Browse Source

Merge branch 'master' of github.com:v2ray/v2ray-core

Shelikhoo 5 years ago
parent
commit
4448d37c2b

+ 18 - 25
app/dns/dohdns.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"net/http"
 	"net/http"
+	"net/url"
 	"sync"
 	"sync"
 	"sync/atomic"
 	"sync/atomic"
 	"time"
 	"time"
@@ -41,25 +42,25 @@ type DoHNameServer struct {
 }
 }
 
 
 // NewDoHNameServer creates DOH client object for remote resolving
 // NewDoHNameServer creates DOH client object for remote resolving
-func NewDoHNameServer(dohHost string, dohPort uint32, dispatcher routing.Dispatcher, clientIP net.IP) (*DoHNameServer, error) {
+func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, clientIP net.IP) (*DoHNameServer, error) {
 
 
-	dohAddr := net.ParseAddress(dohHost)
-	var dests []net.Destination
-
-	if dohPort == 0 {
-		dohPort = 443
+	dohAddr := net.ParseAddress(url.Hostname())
+	dohPort := "443"
+	if url.Port() != "" {
+		dohPort = url.Port()
 	}
 	}
 
 
-	parseIPDest := func(ip net.IP, port uint32) net.Destination {
+	parseIPDest := func(ip net.IP, port string) net.Destination {
 		strIP := ip.String()
 		strIP := ip.String()
 		if len(ip) == net.IPv6len {
 		if len(ip) == net.IPv6len {
 			strIP = fmt.Sprintf("[%s]", strIP)
 			strIP = fmt.Sprintf("[%s]", strIP)
 		}
 		}
-		dest, err := net.ParseDestination(fmt.Sprintf("tcp:%s:%d", strIP, port))
+		dest, err := net.ParseDestination(fmt.Sprintf("tcp:%s:%s", strIP, port))
 		common.Must(err)
 		common.Must(err)
 		return dest
 		return dest
 	}
 	}
 
 
+	var dests []net.Destination
 	if dohAddr.Family().IsDomain() {
 	if dohAddr.Family().IsDomain() {
 		// resolve DOH server in advance
 		// resolve DOH server in advance
 		ips, err := net.LookupIP(dohAddr.Domain())
 		ips, err := net.LookupIP(dohAddr.Domain())
@@ -74,8 +75,8 @@ func NewDoHNameServer(dohHost string, dohPort uint32, dispatcher routing.Dispatc
 		dests = append(dests, parseIPDest(ip, dohPort))
 		dests = append(dests, parseIPDest(ip, dohPort))
 	}
 	}
 
 
-	newError("DNS: created remote DOH client for https://", dohHost, ":", dohPort).AtInfo().WriteToLog()
-	s := baseDOHNameServer(dohHost, dohPort, "DOH", clientIP)
+	newError("DNS: created Remote DOH client for ", url.String(), ", preresolved Dests: ", dests).AtInfo().WriteToLog()
+	s := baseDOHNameServer(url, "DOH", clientIP)
 	s.dispatcher = dispatcher
 	s.dispatcher = dispatcher
 	s.dohDests = dests
 	s.dohDests = dests
 
 
@@ -102,32 +103,24 @@ func NewDoHNameServer(dohHost string, dohPort uint32, dispatcher routing.Dispatc
 }
 }
 
 
 // NewDoHLocalNameServer creates DOH client object for local resolving
 // NewDoHLocalNameServer creates DOH client object for local resolving
-func NewDoHLocalNameServer(dohHost string, dohPort uint32, clientIP net.IP) *DoHNameServer {
-
-	if dohPort == 0 {
-		dohPort = 443
-	}
-
-	s := baseDOHNameServer(dohHost, dohPort, "DOHL", clientIP)
+func NewDoHLocalNameServer(url *url.URL, clientIP net.IP) *DoHNameServer {
+	url.Scheme = "https"
+	s := baseDOHNameServer(url, "DOHL", clientIP)
 	s.httpClient = &http.Client{
 	s.httpClient = &http.Client{
 		Timeout: time.Second * 180,
 		Timeout: time.Second * 180,
 	}
 	}
-	newError("DNS: created local DOH client for https://", dohHost, ":", dohPort).AtInfo().WriteToLog()
+	newError("DNS: created Local DOH client for ", url.String()).AtInfo().WriteToLog()
 	return s
 	return s
 }
 }
 
 
-func baseDOHNameServer(dohHost string, dohPort uint32, prefix string, clientIP net.IP) *DoHNameServer {
-
-	if dohPort == 0 {
-		dohPort = 443
-	}
+func baseDOHNameServer(url *url.URL, prefix string, clientIP net.IP) *DoHNameServer {
 
 
 	s := &DoHNameServer{
 	s := &DoHNameServer{
 		ips:      make(map[string]record),
 		ips:      make(map[string]record),
 		clientIP: clientIP,
 		clientIP: clientIP,
 		pub:      pubsub.NewService(),
 		pub:      pubsub.NewService(),
-		name:     fmt.Sprintf("%s:%s:%d", prefix, dohHost, dohPort),
-		dohURL:   fmt.Sprintf("https://%s:%d/dns-query", dohHost, dohPort),
+		name:     fmt.Sprintf("%s//%s", prefix, url.Host),
+		dohURL:   url.String(),
 	}
 	}
 	s.cleanup = &task.Periodic{
 	s.cleanup = &task.Periodic{
 		Interval: time.Minute,
 		Interval: time.Minute,

+ 18 - 7
app/dns/server.go

@@ -7,6 +7,7 @@ package dns
 import (
 import (
 	"context"
 	"context"
 	"log"
 	"log"
+	"net/url"
 	"strings"
 	"strings"
 	"sync"
 	"sync"
 	"time"
 	"time"
@@ -89,24 +90,34 @@ func New(ctx context.Context, config *Config) (*Server, error) {
 		address := endpoint.Address.AsAddress()
 		address := endpoint.Address.AsAddress()
 		if address.Family().IsDomain() && address.Domain() == "localhost" {
 		if address.Family().IsDomain() && address.Domain() == "localhost" {
 			server.clients = append(server.clients, NewLocalNameServer())
 			server.clients = append(server.clients, NewLocalNameServer())
-		} else if address.Family().IsDomain() && strings.HasPrefix(address.Domain(), "DOHL_") {
-			dohHost := address.Domain()[5:]
-			server.clients = append(server.clients, NewDoHLocalNameServer(dohHost, endpoint.Port, server.clientIP))
-		} else if address.Family().IsDomain() && strings.HasPrefix(address.Domain(), "DOH_") {
-			// DOH_ prefix makes net.Address think it's a domain
-			dohHost := address.Domain()[4:]
+		} else if address.Family().IsDomain() && strings.HasPrefix(address.Domain(), "https+local://") {
+			// URI schemed string treated as domain
+			// DOH Local mode
+			u, err := url.Parse(address.Domain())
+			if err != nil {
+				log.Fatalln(newError("DNS config error").Base(err))
+			}
+			server.clients = append(server.clients, NewDoHLocalNameServer(u, server.clientIP))
+		} else if address.Family().IsDomain() &&
+			strings.HasPrefix(address.Domain(), "https://") {
+			// DOH Remote mode
+			u, err := url.Parse(address.Domain())
+			if err != nil {
+				log.Fatalln(newError("DNS config error").Base(err))
+			}
 			idx := len(server.clients)
 			idx := len(server.clients)
 			server.clients = append(server.clients, nil)
 			server.clients = append(server.clients, nil)
 
 
 			// need the core dispatcher, register DOHClient at callback
 			// need the core dispatcher, register DOHClient at callback
 			common.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) {
 			common.Must(core.RequireFeatures(ctx, func(d routing.Dispatcher) {
-				c, err := NewDoHNameServer(dohHost, endpoint.Port, d, server.clientIP)
+				c, err := NewDoHNameServer(u, d, server.clientIP)
 				if err != nil {
 				if err != nil {
 					log.Fatalln(newError("DNS config error").Base(err))
 					log.Fatalln(newError("DNS config error").Base(err))
 				}
 				}
 				server.clients[idx] = c
 				server.clients[idx] = c
 			}))
 			}))
 		} else {
 		} else {
+			// UDP classic DNS mode
 			dest := endpoint.AsDestination()
 			dest := endpoint.AsDestination()
 			if dest.Network == net.Network_Unknown {
 			if dest.Network == net.Network_Unknown {
 				dest.Network = net.Network_UDP
 				dest.Network = net.Network_UDP

+ 0 - 0
common/buf/data/test_ReadBuffer.dat → common/buf/data/test_MultiBufferReadAllToByte.dat


+ 4 - 8
common/buf/io.go

@@ -3,6 +3,7 @@ package buf
 import (
 import (
 	"io"
 	"io"
 	"net"
 	"net"
+	"os"
 	"syscall"
 	"syscall"
 	"time"
 	"time"
 )
 )
@@ -57,19 +58,14 @@ func NewReader(reader io.Reader) Reader {
 		}
 		}
 	}
 	}
 
 
-	if useReadv {
+	_, isFile := reader.(*os.File)
+	if !isFile && useReadv {
 		if sc, ok := reader.(syscall.Conn); ok {
 		if sc, ok := reader.(syscall.Conn); ok {
 			rawConn, err := sc.SyscallConn()
 			rawConn, err := sc.SyscallConn()
 			if err != nil {
 			if err != nil {
 				newError("failed to get sysconn").Base(err).WriteToLog()
 				newError("failed to get sysconn").Base(err).WriteToLog()
 			} else {
 			} else {
-				/*
-					Check if ReadVReader Can be used on this reader first
-					Fix https://github.com/v2ray/v2ray-core/issues/1666
-				*/
-				if ok, _ := checkReadVConstraint(rawConn); ok {
-					return NewReadVReader(reader, rawConn)
-				}
+				return NewReadVReader(reader, rawConn)
 			}
 			}
 		}
 		}
 	}
 	}

+ 28 - 7
common/buf/multi_buffer_test.go

@@ -7,6 +7,8 @@ import (
 	"testing"
 	"testing"
 
 
 	"github.com/google/go-cmp/cmp"
 	"github.com/google/go-cmp/cmp"
+	"io/ioutil"
+	"os"
 
 
 	"v2ray.com/core/common"
 	"v2ray.com/core/common"
 	. "v2ray.com/core/common/buf"
 	. "v2ray.com/core/common/buf"
@@ -98,14 +100,33 @@ func TestMultiBufferSplitFirst(t *testing.T) {
 }
 }
 
 
 func TestMultiBufferReadAllToByte(t *testing.T) {
 func TestMultiBufferReadAllToByte(t *testing.T) {
-	lb := make([]byte, 8*1024)
-	common.Must2(io.ReadFull(rand.Reader, lb))
-	rd := bytes.NewBuffer(lb)
-	b, err := ReadAllToBytes(rd)
-	common.Must(err)
+	{
+		lb := make([]byte, 8*1024)
+		common.Must2(io.ReadFull(rand.Reader, lb))
+		rd := bytes.NewBuffer(lb)
+		b, err := ReadAllToBytes(rd)
+		common.Must(err)
+
+		if l := len(b); l != 8*1024 {
+			t.Error("unexpceted length from ReadAllToBytes", l)
+		}
+
+	}
+	{
+		const dat = "data/test_MultiBufferReadAllToByte.dat"
+		f, err := os.Open(dat)
+		common.Must(err)
+
+		buf2, err := ReadAllToBytes(f)
+		common.Must(err)
+		f.Close()
+
+		cnt, err := ioutil.ReadFile(dat)
+		common.Must(err)
 
 
-	if l := len(b); l != 8*1024 {
-		t.Error("unexpceted length from ReadAllToBytes", l)
+		if d := cmp.Diff(buf2, cnt); d != "" {
+			t.Error("fail to read from file: ", d)
+		}
 	}
 	}
 }
 }
 
 

+ 0 - 20
common/buf/reader_test.go

@@ -3,12 +3,9 @@ package buf_test
 import (
 import (
 	"bytes"
 	"bytes"
 	"io"
 	"io"
-	"io/ioutil"
-	"os"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
-	"github.com/google/go-cmp/cmp"
 	"v2ray.com/core/common"
 	"v2ray.com/core/common"
 	. "v2ray.com/core/common/buf"
 	. "v2ray.com/core/common/buf"
 	"v2ray.com/core/transport/pipe"
 	"v2ray.com/core/transport/pipe"
@@ -92,23 +89,6 @@ func TestReadBuffer(t *testing.T) {
 		buf.Release()
 		buf.Release()
 	}
 	}
 
 
-	{
-		const dat = "data/test_ReadBuffer.dat"
-		f, err := os.Open(dat)
-		common.Must(err)
-		defer f.Close()
-
-		buf2, err := ReadBuffer(f)
-		common.Must(err)
-
-		cnt, err := ioutil.ReadFile(dat)
-		common.Must(err)
-
-		if cmp.Diff(buf2.Bytes(), cnt) != "" {
-			t.Error("fail to read from file")
-		}
-		buf2.Release()
-	}
 }
 }
 
 
 func TestReadAtMost(t *testing.T) {
 func TestReadAtMost(t *testing.T) {

+ 0 - 9
common/buf/readv_constraint_other.go

@@ -1,9 +0,0 @@
-// +build !windows
-
-package buf
-
-import "syscall"
-
-func checkReadVConstraint(conn syscall.RawConn) (bool, error) {
-	return true, nil
-}

+ 0 - 37
common/buf/readv_constraint_windows.go

@@ -1,37 +0,0 @@
-// +build windows
-package buf
-
-import (
-	"syscall"
-)
-
-func checkReadVConstraint(conn syscall.RawConn) (bool, error) {
-	var isSocketReady = false
-	var reason error
-	/*
-		In Windows, WSARecv system call only support socket connection.
-
-		It it required to check if the given fd is of a socket type
-
-		Fix https://github.com/v2ray/v2ray-core/issues/1666
-
-		Additional Information:
-		https://docs.microsoft.com/en-us/windows/desktop/api/winsock2/nf-winsock2-wsarecv
-		https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-getsockopt
-		https://docs.microsoft.com/en-us/windows/desktop/WinSock/sol-socket-socket-options
-
-	*/
-	err := conn.Control(func(fd uintptr) {
-		var val [4]byte
-		var le = int32(len(val))
-		err := syscall.Getsockopt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, &val[0], &le)
-		if err != nil {
-			isSocketReady = false
-		} else {
-			isSocketReady = true
-		}
-		reason = err
-	})
-
-	return isSocketReady, err
-}

+ 19 - 0
infra/conf/common_test.go

@@ -51,6 +51,25 @@ func TestDomainParsing(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestURLParsing(t *testing.T) {
+	{
+		rawJson := "\"https://dns.google/dns-query\""
+		var address Address
+		common.Must(json.Unmarshal([]byte(rawJson), &address))
+		if address.Domain() != "https://dns.google/dns-query" {
+			t.Error("URL: ", address.Domain())
+		}
+	}
+	{
+		rawJson := "\"https+local://dns.google/dns-query\""
+		var address Address
+		common.Must(json.Unmarshal([]byte(rawJson), &address))
+		if address.Domain() != "https+local://dns.google/dns-query" {
+			t.Error("URL: ", address.Domain())
+		}
+	}
+}
+
 func TestInvalidAddressJson(t *testing.T) {
 func TestInvalidAddressJson(t *testing.T) {
 	rawJson := "1234"
 	rawJson := "1234"
 	var address Address
 	var address Address

+ 1 - 0
proxy/dns/dns_test.go

@@ -162,6 +162,7 @@ func TestUDPDNSTunnel(t *testing.T) {
 		m1.Question[0] = dns.Question{"ipv4only.google.com.", dns.TypeAAAA, dns.ClassINET}
 		m1.Question[0] = dns.Question{"ipv4only.google.com.", dns.TypeAAAA, dns.ClassINET}
 
 
 		c := new(dns.Client)
 		c := new(dns.Client)
+		c.Timeout = 10 * time.Second
 		in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
 		in, _, err := c.Exchange(m1, "127.0.0.1:"+strconv.Itoa(int(serverPort)))
 		common.Must(err)
 		common.Must(err)
 
 

+ 4 - 4
testing/scenarios/vmess_test.go

@@ -810,10 +810,10 @@ func TestVMessKCPLarge(t *testing.T) {
 								Protocol: internet.TransportProtocol_MKCP,
 								Protocol: internet.TransportProtocol_MKCP,
 								Settings: serial.ToTypedMessage(&kcp.Config{
 								Settings: serial.ToTypedMessage(&kcp.Config{
 									ReadBuffer: &kcp.ReadBuffer{
 									ReadBuffer: &kcp.ReadBuffer{
-										Size: 4096,
+										Size: 512 * 1024,
 									},
 									},
 									WriteBuffer: &kcp.WriteBuffer{
 									WriteBuffer: &kcp.WriteBuffer{
-										Size: 4096,
+										Size: 512 * 1024,
 									},
 									},
 									UplinkCapacity: &kcp.UplinkCapacity{
 									UplinkCapacity: &kcp.UplinkCapacity{
 										Value: 20,
 										Value: 20,
@@ -897,10 +897,10 @@ func TestVMessKCPLarge(t *testing.T) {
 								Protocol: internet.TransportProtocol_MKCP,
 								Protocol: internet.TransportProtocol_MKCP,
 								Settings: serial.ToTypedMessage(&kcp.Config{
 								Settings: serial.ToTypedMessage(&kcp.Config{
 									ReadBuffer: &kcp.ReadBuffer{
 									ReadBuffer: &kcp.ReadBuffer{
-										Size: 4096,
+										Size: 512 * 1024,
 									},
 									},
 									WriteBuffer: &kcp.WriteBuffer{
 									WriteBuffer: &kcp.WriteBuffer{
-										Size: 4096,
+										Size: 512 * 1024,
 									},
 									},
 									UplinkCapacity: &kcp.UplinkCapacity{
 									UplinkCapacity: &kcp.UplinkCapacity{
 										Value: 20,
 										Value: 20,