Changes from v2ray-core (#93)

This commit is contained in:
Arthur Morgan 2020-12-25 03:45:35 +08:00 committed by GitHub
parent 85619b5a29
commit 6f25191822
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 85 additions and 39 deletions

View file

@ -36,19 +36,23 @@ func (m *AccessMessage) String() string {
builder.WriteString(string(m.Status))
builder.WriteByte(' ')
builder.WriteString(serial.ToString(m.To))
builder.WriteByte(' ')
if len(m.Detour) > 0 {
builder.WriteByte('[')
builder.WriteString(" [")
builder.WriteString(m.Detour)
builder.WriteString("] ")
builder.WriteByte(']')
}
if reason := serial.ToString(m.Reason); len(reason) > 0 {
builder.WriteString(" ")
builder.WriteString(reason)
}
builder.WriteString(serial.ToString(m.Reason))
if len(m.Email) > 0 {
builder.WriteString("email:")
builder.WriteString(" email: ")
builder.WriteString(m.Email)
builder.WriteByte(' ')
}
return builder.String()
}

View file

@ -8,7 +8,7 @@ import (
// ToString serialize an arbitrary value into string.
func ToString(v interface{}) string {
if v == nil {
return " "
return ""
}
switch value := v.(type) {

View file

@ -84,7 +84,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
geoipList, err := toCidrList(c.ExpectIPs)
if err != nil {
return nil, newError("invalid ip rule: ", c.ExpectIPs).Base(err)
return nil, newError("invalid IP rule: ", c.ExpectIPs).Base(err)
}
return &dns.NameServer{
@ -142,7 +142,7 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
for _, server := range c.Servers {
ns, err := server.Build()
if err != nil {
return nil, newError("failed to build name server").Base(err)
return nil, newError("failed to build nameserver").Base(err)
}
config.NameServer = append(config.NameServer, ns)
}
@ -159,15 +159,23 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
var mappings []*dns.Config_HostMapping
switch {
case strings.HasPrefix(domain, "domain:"):
domainName := domain[7:]
if len(domainName) == 0 {
return nil, newError("empty domain type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Subdomain
mapping.Domain = domain[7:]
mapping.Domain = domainName
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "geosite:"):
domains, err := loadGeositeWithAttr("geosite.dat", strings.ToUpper(domain[8:]))
listName := domain[8:]
if len(listName) == 0 {
return nil, newError("empty geosite rule: ", domain)
}
domains, err := loadGeositeWithAttr("geosite.dat", listName)
if err != nil {
return nil, newError("invalid geosite settings: ", domain).Base(err)
return nil, newError("failed to load geosite: ", listName).Base(err)
}
for _, d := range domains {
mapping := getHostMapping(addr)
@ -177,21 +185,33 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
}
case strings.HasPrefix(domain, "regexp:"):
regexpVal := domain[7:]
if len(regexpVal) == 0 {
return nil, newError("empty regexp type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Regex
mapping.Domain = domain[7:]
mapping.Domain = regexpVal
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "keyword:"):
keywordVal := domain[8:]
if len(keywordVal) == 0 {
return nil, newError("empty keyword type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Keyword
mapping.Domain = domain[8:]
mapping.Domain = keywordVal
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "full:"):
fullVal := domain[5:]
if len(fullVal) == 0 {
return nil, newError("empty full domain type of rule: ", domain)
}
mapping := getHostMapping(addr)
mapping.Type = dns.DomainMatchingType_Full
mapping.Domain = domain[5:]
mapping.Domain = fullVal
mappings = append(mappings, mapping)
case strings.HasPrefix(domain, "dotless:"):
@ -213,10 +233,10 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
return nil, newError("invalid external resource: ", domain)
}
filename := kv[0]
country := kv[1]
domains, err := loadGeositeWithAttr(filename, country)
list := kv[1]
domains, err := loadGeositeWithAttr(filename, list)
if err != nil {
return nil, newError("failed to load domains: ", country, " from ", filename).Base(err)
return nil, newError("failed to load domain list: ", list, " from ", filename).Base(err)
}
for _, d := range domains {
mapping := getHostMapping(addr)

View file

@ -167,7 +167,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
switch fb.Dest[0] {
case '@', '/':
fb.Type = "unix"
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == "linux" {
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, fb.Dest[1:])
fb.Dest = string(fullAddr)

View file

@ -101,7 +101,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
switch fb.Dest[0] {
case '@', '/':
fb.Type = "unix"
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && runtime.GOOS == "linux" {
if fb.Dest[0] == '@' && len(fb.Dest) > 1 && fb.Dest[1] == '@' && (runtime.GOOS == "linux" || runtime.GOOS == "android") {
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
copy(fullAddr, fb.Dest[1:])
fb.Dest = string(fullAddr)

View file

@ -168,6 +168,7 @@ func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, u
rawConn.Close()
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
rawConn.Close()

View file

@ -293,6 +293,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
response.Close = true
result = nil
}
defer response.Body.Close()
} else {
newError("failed to read response from ", request.Host).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
response = &http.Response{

View file

@ -51,14 +51,19 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
if outbound == nil || !outbound.Target.IsValid() {
return newError("target not specified.")
}
// Destination of the inner request.
destination := outbound.Target
// Outbound server.
var server *protocol.ServerSpec
// Outbound server's destination.
var dest net.Destination
// Connection to the outbound server.
var conn internet.Connection
if err := retry.ExponentialBackoff(5, 100).On(func() error {
server = c.serverPicker.PickServer()
dest := server.Destination()
dest = server.Destination()
rawConn, err := dialer.Dial(ctx, dest)
if err != nil {
return err
@ -101,6 +106,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
if err != nil {
return newError("failed to establish connection to server").AtWarning().Base(err)
}
if udpRequest != nil {
if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
udpRequest.Address = dest.Address
}
}
if err := conn.SetDeadline(time.Time{}); err != nil {
newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))

View file

@ -16,7 +16,7 @@ const (
cmdTCPConnect = 0x01
cmdTCPBind = 0x02
cmdUDPPort = 0x03
cmdUDPAssociate = 0x03
cmdTorResolve = 0xF0
cmdTorResolvePTR = 0xF1
@ -39,8 +39,10 @@ var addrParser = protocol.NewAddressParser(
)
type ServerSession struct {
config *ServerConfig
port net.Port
config *ServerConfig
address net.Address
port net.Port
clientAddress net.Address
}
func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
@ -162,7 +164,7 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR:
// We don't have a solution for Tor case now. Simply treat it as connect command.
request.Command = protocol.RequestCommandTCP
case cmdUDPPort:
case cmdUDPAssociate:
if !s.config.UdpEnabled {
writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
return nil, newError("UDP is not enabled.")
@ -185,15 +187,20 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
request.Address = addr
request.Port = port
responseAddress := net.AnyIP
responsePort := net.Port(1717)
responseAddress := s.address
responsePort := s.port
//nolint:gocritic // Use if else chain for clarity
if request.Command == protocol.RequestCommandUDP {
addr := s.config.Address.AsAddress()
if addr == nil {
addr = net.LocalHostIP
if s.config.Address != nil {
// Use configured IP as remote address in the response to UdpAssociate
responseAddress = s.config.Address.AsAddress()
} else if s.clientAddress == net.LocalHostIP || s.clientAddress == net.LocalHostIPv6 {
// For localhost clients use loopback IP
responseAddress = s.clientAddress
} else {
// For non-localhost clients use inbound listening address
responseAddress = s.address
}
responseAddress = addr
responsePort = s.port
}
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {
return nil, err
@ -446,7 +453,7 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
command := byte(cmdTCPConnect)
if request.Command == protocol.RequestCommandUDP {
command = byte(cmdUDPPort)
command = byte(cmdUDPAssociate)
}
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {

View file

@ -89,8 +89,10 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
}
svrSession := &ServerSession{
config: s.config,
port: inbound.Gateway.Port,
config: s.config,
address: inbound.Gateway.Address,
port: inbound.Gateway.Port,
clientAddress: inbound.Source.Address,
}
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}

View file

@ -136,8 +136,8 @@ func TestHTTPConnectionHeader(t *testing.T) {
}
func TestDomainSocket(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("Not supported on windows")
if runtime.GOOS == "windows" || runtime.GOOS == "android" {
t.Skip("Not supported on windows and android")
return
}
tcpServer := tcp.Server{

View file

@ -1,4 +1,5 @@
// +build !windows
// +build !android
package domainsocket_test

View file

@ -54,7 +54,7 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
lc.Control = nil
network = addr.Network()
address = addr.Name
if runtime.GOOS == "linux" && address[0] == '@' {
if (runtime.GOOS == "linux" || runtime.GOOS == "android") && address[0] == '@' {
// linux abstract unix domain socket is lockfree
if len(address) > 1 && address[1] == '@' {
// but may need padding to work with haproxy

View file

@ -48,7 +48,7 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
Net: "unix",
}, streamSettings.SocketSettings)
if err != nil {
return nil, newError("failed to listen Unix Doman Socket on ", address).Base(err)
return nil, newError("failed to listen Unix Domain Socket on ", address).Base(err)
}
newError("listening Unix Domain Socket on ", address).WriteToLog(session.ExportIDToError(ctx))
locker := ctx.Value(address.Domain())