mirror of
https://github.com/XTLS/Xray-core.git
synced 2024-11-22 08:31:28 +00:00
Changes from v2ray-core (#93)
This commit is contained in:
parent
85619b5a29
commit
6f25191822
|
@ -36,19 +36,23 @@ func (m *AccessMessage) String() string {
|
||||||
builder.WriteString(string(m.Status))
|
builder.WriteString(string(m.Status))
|
||||||
builder.WriteByte(' ')
|
builder.WriteByte(' ')
|
||||||
builder.WriteString(serial.ToString(m.To))
|
builder.WriteString(serial.ToString(m.To))
|
||||||
builder.WriteByte(' ')
|
|
||||||
if len(m.Detour) > 0 {
|
if len(m.Detour) > 0 {
|
||||||
builder.WriteByte('[')
|
builder.WriteString(" [")
|
||||||
builder.WriteString(m.Detour)
|
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 {
|
if len(m.Email) > 0 {
|
||||||
builder.WriteString("email:")
|
builder.WriteString(" email: ")
|
||||||
builder.WriteString(m.Email)
|
builder.WriteString(m.Email)
|
||||||
builder.WriteByte(' ')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
// ToString serialize an arbitrary value into string.
|
// ToString serialize an arbitrary value into string.
|
||||||
func ToString(v interface{}) string {
|
func ToString(v interface{}) string {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return " "
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch value := v.(type) {
|
switch value := v.(type) {
|
||||||
|
|
|
@ -84,7 +84,7 @@ func (c *NameServerConfig) Build() (*dns.NameServer, error) {
|
||||||
|
|
||||||
geoipList, err := toCidrList(c.ExpectIPs)
|
geoipList, err := toCidrList(c.ExpectIPs)
|
||||||
if err != nil {
|
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{
|
return &dns.NameServer{
|
||||||
|
@ -142,7 +142,7 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||||
for _, server := range c.Servers {
|
for _, server := range c.Servers {
|
||||||
ns, err := server.Build()
|
ns, err := server.Build()
|
||||||
if err != nil {
|
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)
|
config.NameServer = append(config.NameServer, ns)
|
||||||
}
|
}
|
||||||
|
@ -159,15 +159,23 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||||
var mappings []*dns.Config_HostMapping
|
var mappings []*dns.Config_HostMapping
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(domain, "domain:"):
|
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 := getHostMapping(addr)
|
||||||
mapping.Type = dns.DomainMatchingType_Subdomain
|
mapping.Type = dns.DomainMatchingType_Subdomain
|
||||||
mapping.Domain = domain[7:]
|
mapping.Domain = domainName
|
||||||
mappings = append(mappings, mapping)
|
mappings = append(mappings, mapping)
|
||||||
|
|
||||||
case strings.HasPrefix(domain, "geosite:"):
|
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 {
|
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 {
|
for _, d := range domains {
|
||||||
mapping := getHostMapping(addr)
|
mapping := getHostMapping(addr)
|
||||||
|
@ -177,21 +185,33 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case strings.HasPrefix(domain, "regexp:"):
|
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 := getHostMapping(addr)
|
||||||
mapping.Type = dns.DomainMatchingType_Regex
|
mapping.Type = dns.DomainMatchingType_Regex
|
||||||
mapping.Domain = domain[7:]
|
mapping.Domain = regexpVal
|
||||||
mappings = append(mappings, mapping)
|
mappings = append(mappings, mapping)
|
||||||
|
|
||||||
case strings.HasPrefix(domain, "keyword:"):
|
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 := getHostMapping(addr)
|
||||||
mapping.Type = dns.DomainMatchingType_Keyword
|
mapping.Type = dns.DomainMatchingType_Keyword
|
||||||
mapping.Domain = domain[8:]
|
mapping.Domain = keywordVal
|
||||||
mappings = append(mappings, mapping)
|
mappings = append(mappings, mapping)
|
||||||
|
|
||||||
case strings.HasPrefix(domain, "full:"):
|
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 := getHostMapping(addr)
|
||||||
mapping.Type = dns.DomainMatchingType_Full
|
mapping.Type = dns.DomainMatchingType_Full
|
||||||
mapping.Domain = domain[5:]
|
mapping.Domain = fullVal
|
||||||
mappings = append(mappings, mapping)
|
mappings = append(mappings, mapping)
|
||||||
|
|
||||||
case strings.HasPrefix(domain, "dotless:"):
|
case strings.HasPrefix(domain, "dotless:"):
|
||||||
|
@ -213,10 +233,10 @@ func (c *DNSConfig) Build() (*dns.Config, error) {
|
||||||
return nil, newError("invalid external resource: ", domain)
|
return nil, newError("invalid external resource: ", domain)
|
||||||
}
|
}
|
||||||
filename := kv[0]
|
filename := kv[0]
|
||||||
country := kv[1]
|
list := kv[1]
|
||||||
domains, err := loadGeositeWithAttr(filename, country)
|
domains, err := loadGeositeWithAttr(filename, list)
|
||||||
if err != nil {
|
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 {
|
for _, d := range domains {
|
||||||
mapping := getHostMapping(addr)
|
mapping := getHostMapping(addr)
|
||||||
|
|
|
@ -167,7 +167,7 @@ func (c *TrojanServerConfig) Build() (proto.Message, error) {
|
||||||
switch fb.Dest[0] {
|
switch fb.Dest[0] {
|
||||||
case '@', '/':
|
case '@', '/':
|
||||||
fb.Type = "unix"
|
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
|
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
|
||||||
copy(fullAddr, fb.Dest[1:])
|
copy(fullAddr, fb.Dest[1:])
|
||||||
fb.Dest = string(fullAddr)
|
fb.Dest = string(fullAddr)
|
||||||
|
|
|
@ -101,7 +101,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
|
||||||
switch fb.Dest[0] {
|
switch fb.Dest[0] {
|
||||||
case '@', '/':
|
case '@', '/':
|
||||||
fb.Type = "unix"
|
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
|
fullAddr := make([]byte, len(syscall.RawSockaddrUnix{}.Path)) // may need padding to work with haproxy
|
||||||
copy(fullAddr, fb.Dest[1:])
|
copy(fullAddr, fb.Dest[1:])
|
||||||
fb.Dest = string(fullAddr)
|
fb.Dest = string(fullAddr)
|
||||||
|
|
|
@ -168,6 +168,7 @@ func setUpHTTPTunnel(ctx context.Context, dest net.Destination, target string, u
|
||||||
rawConn.Close()
|
rawConn.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
rawConn.Close()
|
rawConn.Close()
|
||||||
|
|
|
@ -293,6 +293,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
|
||||||
response.Close = true
|
response.Close = true
|
||||||
result = nil
|
result = nil
|
||||||
}
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
} else {
|
} else {
|
||||||
newError("failed to read response from ", request.Host).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
newError("failed to read response from ", request.Host).Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
|
||||||
response = &http.Response{
|
response = &http.Response{
|
||||||
|
|
|
@ -51,14 +51,19 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
||||||
if outbound == nil || !outbound.Target.IsValid() {
|
if outbound == nil || !outbound.Target.IsValid() {
|
||||||
return newError("target not specified.")
|
return newError("target not specified.")
|
||||||
}
|
}
|
||||||
|
// Destination of the inner request.
|
||||||
destination := outbound.Target
|
destination := outbound.Target
|
||||||
|
|
||||||
|
// Outbound server.
|
||||||
var server *protocol.ServerSpec
|
var server *protocol.ServerSpec
|
||||||
|
// Outbound server's destination.
|
||||||
|
var dest net.Destination
|
||||||
|
// Connection to the outbound server.
|
||||||
var conn internet.Connection
|
var conn internet.Connection
|
||||||
|
|
||||||
if err := retry.ExponentialBackoff(5, 100).On(func() error {
|
if err := retry.ExponentialBackoff(5, 100).On(func() error {
|
||||||
server = c.serverPicker.PickServer()
|
server = c.serverPicker.PickServer()
|
||||||
dest := server.Destination()
|
dest = server.Destination()
|
||||||
rawConn, err := dialer.Dial(ctx, dest)
|
rawConn, err := dialer.Dial(ctx, dest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -101,6 +106,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return newError("failed to establish connection to server").AtWarning().Base(err)
|
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 {
|
if err := conn.SetDeadline(time.Time{}); err != nil {
|
||||||
newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
newError("failed to clear deadline after handshake").Base(err).WriteToLog(session.ExportIDToError(ctx))
|
||||||
|
|
|
@ -16,7 +16,7 @@ const (
|
||||||
|
|
||||||
cmdTCPConnect = 0x01
|
cmdTCPConnect = 0x01
|
||||||
cmdTCPBind = 0x02
|
cmdTCPBind = 0x02
|
||||||
cmdUDPPort = 0x03
|
cmdUDPAssociate = 0x03
|
||||||
cmdTorResolve = 0xF0
|
cmdTorResolve = 0xF0
|
||||||
cmdTorResolvePTR = 0xF1
|
cmdTorResolvePTR = 0xF1
|
||||||
|
|
||||||
|
@ -40,7 +40,9 @@ var addrParser = protocol.NewAddressParser(
|
||||||
|
|
||||||
type ServerSession struct {
|
type ServerSession struct {
|
||||||
config *ServerConfig
|
config *ServerConfig
|
||||||
|
address net.Address
|
||||||
port net.Port
|
port net.Port
|
||||||
|
clientAddress net.Address
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
|
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:
|
case cmdTCPConnect, cmdTorResolve, cmdTorResolvePTR:
|
||||||
// We don't have a solution for Tor case now. Simply treat it as connect command.
|
// We don't have a solution for Tor case now. Simply treat it as connect command.
|
||||||
request.Command = protocol.RequestCommandTCP
|
request.Command = protocol.RequestCommandTCP
|
||||||
case cmdUDPPort:
|
case cmdUDPAssociate:
|
||||||
if !s.config.UdpEnabled {
|
if !s.config.UdpEnabled {
|
||||||
writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
|
writeSocks5Response(writer, statusCmdNotSupport, net.AnyIP, net.Port(0))
|
||||||
return nil, newError("UDP is not enabled.")
|
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.Address = addr
|
||||||
request.Port = port
|
request.Port = port
|
||||||
|
|
||||||
responseAddress := net.AnyIP
|
responseAddress := s.address
|
||||||
responsePort := net.Port(1717)
|
responsePort := s.port
|
||||||
|
//nolint:gocritic // Use if else chain for clarity
|
||||||
if request.Command == protocol.RequestCommandUDP {
|
if request.Command == protocol.RequestCommandUDP {
|
||||||
addr := s.config.Address.AsAddress()
|
if s.config.Address != nil {
|
||||||
if addr == nil {
|
// Use configured IP as remote address in the response to UdpAssociate
|
||||||
addr = net.LocalHostIP
|
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 {
|
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -446,7 +453,7 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
|
||||||
|
|
||||||
command := byte(cmdTCPConnect)
|
command := byte(cmdTCPConnect)
|
||||||
if request.Command == protocol.RequestCommandUDP {
|
if request.Command == protocol.RequestCommandUDP {
|
||||||
command = byte(cmdUDPPort)
|
command = byte(cmdUDPAssociate)
|
||||||
}
|
}
|
||||||
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
|
common.Must2(b.Write([]byte{socks5Version, command, 0x00 /* reserved */}))
|
||||||
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
|
if err := addrParser.WriteAddressPort(b, request.Address, request.Port); err != nil {
|
||||||
|
|
|
@ -90,7 +90,9 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
|
||||||
|
|
||||||
svrSession := &ServerSession{
|
svrSession := &ServerSession{
|
||||||
config: s.config,
|
config: s.config,
|
||||||
|
address: inbound.Gateway.Address,
|
||||||
port: inbound.Gateway.Port,
|
port: inbound.Gateway.Port,
|
||||||
|
clientAddress: inbound.Source.Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}
|
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}
|
||||||
|
|
|
@ -136,8 +136,8 @@ func TestHTTPConnectionHeader(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDomainSocket(t *testing.T) {
|
func TestDomainSocket(t *testing.T) {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" || runtime.GOOS == "android" {
|
||||||
t.Skip("Not supported on windows")
|
t.Skip("Not supported on windows and android")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
tcpServer := tcp.Server{
|
tcpServer := tcp.Server{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// +build !windows
|
// +build !windows
|
||||||
|
// +build !android
|
||||||
|
|
||||||
package domainsocket_test
|
package domainsocket_test
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ func (dl *DefaultListener) Listen(ctx context.Context, addr net.Addr, sockopt *S
|
||||||
lc.Control = nil
|
lc.Control = nil
|
||||||
network = addr.Network()
|
network = addr.Network()
|
||||||
address = addr.Name
|
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
|
// linux abstract unix domain socket is lockfree
|
||||||
if len(address) > 1 && address[1] == '@' {
|
if len(address) > 1 && address[1] == '@' {
|
||||||
// but may need padding to work with haproxy
|
// but may need padding to work with haproxy
|
||||||
|
|
|
@ -48,7 +48,7 @@ func ListenTCP(ctx context.Context, address net.Address, port net.Port, streamSe
|
||||||
Net: "unix",
|
Net: "unix",
|
||||||
}, streamSettings.SocketSettings)
|
}, streamSettings.SocketSettings)
|
||||||
if err != nil {
|
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))
|
newError("listening Unix Domain Socket on ", address).WriteToLog(session.ExportIDToError(ctx))
|
||||||
locker := ctx.Value(address.Domain())
|
locker := ctx.Value(address.Domain())
|
||||||
|
|
Loading…
Reference in a new issue