Browse Source

Fix tls.WithDestination ignoring IP address (#3177)

dyhkwong 1 year ago
parent
commit
5ffbc0296c
3 changed files with 241 additions and 2 deletions
  1. 7 0
      common/protocol/tls/cert/cert.go
  2. 227 0
      testing/scenarios/tls_test.go
  3. 7 2
      transport/internet/tls/config.go

+ 7 - 0
common/protocol/tls/cert/cert.go

@@ -13,6 +13,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/v2fly/v2ray-core/v5/common"
 	"github.com/v2fly/v2ray-core/v5/common"
+	"github.com/v2fly/v2ray-core/v5/common/net"
 )
 )
 
 
 //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
 //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen
@@ -76,6 +77,12 @@ func CommonName(name string) Option {
 	}
 	}
 }
 }
 
 
+func IPAddresses(ip ...net.IP) Option {
+	return func(c *x509.Certificate) {
+		c.IPAddresses = ip
+	}
+}
+
 func KeyUsage(usage x509.KeyUsage) Option {
 func KeyUsage(usage x509.KeyUsage) Option {
 	return func(c *x509.Certificate) {
 	return func(c *x509.Certificate) {
 		c.KeyUsage = usage
 		c.KeyUsage = usage

+ 227 - 0
testing/scenarios/tls_test.go

@@ -253,6 +253,233 @@ func TestAutoIssuingCertificate(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestIPAddressesCertificate(t *testing.T) {
+	tcpServer := tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	common.Must(err)
+	defer tcpServer.Close()
+
+	caCert, err := cert.Generate(nil, cert.IPAddresses(net.LocalHostIP.IP()), cert.Authority(true), cert.KeyUsage(x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment|x509.KeyUsageCertSign))
+	common.Must(err)
+	certPEM, keyPEM := caCert.ToPEM()
+
+	userID := protocol.NewID(uuid.New())
+	serverPort := tcp.PickPort()
+	serverConfig := &core.Config{
+		Inbound: []*core.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: net.SinglePortRange(serverPort),
+					Listen:    net.NewIPOrDomain(net.LocalHostIP),
+					StreamSettings: &internet.StreamConfig{
+						SecurityType: serial.GetMessageType(&tls.Config{}),
+						SecuritySettings: []*anypb.Any{
+							serial.ToTypedMessage(&tls.Config{
+								Certificate: []*tls.Certificate{{
+									Certificate: certPEM,
+									Key:         keyPEM,
+								}},
+							}),
+						},
+					},
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{
+					User: []*protocol.User{
+						{
+							Account: serial.ToTypedMessage(&vmess.Account{
+								Id: userID.String(),
+							}),
+						},
+					},
+				}),
+			},
+		},
+		Outbound: []*core.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+	}
+
+	clientPort := tcp.PickPort()
+	clientConfig := &core.Config{
+		Inbound: []*core.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: net.SinglePortRange(clientPort),
+					Listen:    net.NewIPOrDomain(net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
+					Address: net.NewIPOrDomain(dest.Address),
+					Port:    uint32(dest.Port),
+					NetworkList: &net.NetworkList{
+						Network: []net.Network{net.Network_TCP},
+					},
+				}),
+			},
+		},
+		Outbound: []*core.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&outbound.Config{
+					Receiver: []*protocol.ServerEndpoint{
+						{
+							Address: net.NewIPOrDomain(net.LocalHostIP),
+							Port:    uint32(serverPort),
+							User: []*protocol.User{
+								{
+									Account: serial.ToTypedMessage(&vmess.Account{
+										Id: userID.String(),
+									}),
+								},
+							},
+						},
+					},
+				}),
+				SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
+					StreamSettings: &internet.StreamConfig{
+						SecurityType: serial.GetMessageType(&tls.Config{}),
+						SecuritySettings: []*anypb.Any{
+							serial.ToTypedMessage(&tls.Config{
+								DisableSystemRoot: true,
+								Certificate: []*tls.Certificate{{
+									Certificate: certPEM,
+									Usage:       tls.Certificate_AUTHORITY_VERIFY,
+								}},
+							}),
+						},
+					},
+				}),
+			},
+		},
+	}
+
+	servers, err := InitializeServerConfigs(serverConfig, clientConfig)
+	common.Must(err)
+	defer CloseAllServers(servers)
+
+	for i := 0; i < 10; i++ {
+		if err := testTCPConn(clientPort, 1024, time.Second*20)(); err != nil {
+			t.Error(err)
+		}
+	}
+}
+
+func TestDNSNamesCertificate(t *testing.T) {
+	tcpServer := tcp.Server{
+		MsgProcessor: xor,
+	}
+	dest, err := tcpServer.Start()
+	common.Must(err)
+	defer tcpServer.Close()
+
+	caCert, err := cert.Generate(nil, cert.DNSNames("v2fly.org"), cert.Authority(true), cert.KeyUsage(x509.KeyUsageDigitalSignature|x509.KeyUsageKeyEncipherment|x509.KeyUsageCertSign))
+	common.Must(err)
+	certPEM, keyPEM := caCert.ToPEM()
+
+	userID := protocol.NewID(uuid.New())
+	serverPort := tcp.PickPort()
+	serverConfig := &core.Config{
+		Inbound: []*core.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: net.SinglePortRange(serverPort),
+					Listen:    net.NewIPOrDomain(net.LocalHostIP),
+					StreamSettings: &internet.StreamConfig{
+						SecurityType: serial.GetMessageType(&tls.Config{}),
+						SecuritySettings: []*anypb.Any{
+							serial.ToTypedMessage(&tls.Config{
+								Certificate: []*tls.Certificate{{
+									Certificate: certPEM,
+									Key:         keyPEM,
+								}},
+							}),
+						},
+					},
+				}),
+				ProxySettings: serial.ToTypedMessage(&inbound.Config{
+					User: []*protocol.User{
+						{
+							Account: serial.ToTypedMessage(&vmess.Account{
+								Id: userID.String(),
+							}),
+						},
+					},
+				}),
+			},
+		},
+		Outbound: []*core.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
+			},
+		},
+	}
+
+	clientPort := tcp.PickPort()
+	clientConfig := &core.Config{
+		Inbound: []*core.InboundHandlerConfig{
+			{
+				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
+					PortRange: net.SinglePortRange(clientPort),
+					Listen:    net.NewIPOrDomain(net.LocalHostIP),
+				}),
+				ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
+					Address: net.NewIPOrDomain(dest.Address),
+					Port:    uint32(dest.Port),
+					NetworkList: &net.NetworkList{
+						Network: []net.Network{net.Network_TCP},
+					},
+				}),
+			},
+		},
+		Outbound: []*core.OutboundHandlerConfig{
+			{
+				ProxySettings: serial.ToTypedMessage(&outbound.Config{
+					Receiver: []*protocol.ServerEndpoint{
+						{
+							Address: net.NewIPOrDomain(net.LocalHostIP),
+							Port:    uint32(serverPort),
+							User: []*protocol.User{
+								{
+									Account: serial.ToTypedMessage(&vmess.Account{
+										Id: userID.String(),
+									}),
+								},
+							},
+						},
+					},
+				}),
+				SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
+					StreamSettings: &internet.StreamConfig{
+						SecurityType: serial.GetMessageType(&tls.Config{}),
+						SecuritySettings: []*anypb.Any{
+							serial.ToTypedMessage(&tls.Config{
+								DisableSystemRoot: true,
+								ServerName:        "v2fly.org",
+								Certificate: []*tls.Certificate{{
+									Certificate: certPEM,
+									Usage:       tls.Certificate_AUTHORITY_VERIFY,
+								}},
+							}),
+						},
+					},
+				}),
+			},
+		},
+	}
+
+	servers, err := InitializeServerConfigs(serverConfig, clientConfig)
+	common.Must(err)
+	defer CloseAllServers(servers)
+
+	for i := 0; i < 10; i++ {
+		if err := testTCPConn(clientPort, 1024, time.Second*20)(); err != nil {
+			t.Error(err)
+		}
+	}
+}
+
 func TestTLSOverKCP(t *testing.T) {
 func TestTLSOverKCP(t *testing.T) {
 	tcpServer := tcp.Server{
 	tcpServer := tcp.Server{
 		MsgProcessor: xor,
 		MsgProcessor: xor,

+ 7 - 2
transport/internet/tls/config.go

@@ -303,8 +303,13 @@ type Option func(*tls.Config)
 // WithDestination sets the server name in TLS config.
 // WithDestination sets the server name in TLS config.
 func WithDestination(dest net.Destination) Option {
 func WithDestination(dest net.Destination) Option {
 	return func(config *tls.Config) {
 	return func(config *tls.Config) {
-		if dest.Address.Family().IsDomain() && config.ServerName == "" {
-			config.ServerName = dest.Address.Domain()
+		if config.ServerName == "" {
+			switch dest.Address.Family() {
+			case net.AddressFamilyDomain:
+				config.ServerName = dest.Address.Domain()
+			case net.AddressFamilyIPv4, net.AddressFamilyIPv6:
+				config.ServerName = dest.Address.IP().String()
+			}
 		}
 		}
 	}
 	}
 }
 }