Compare commits

..

20 Commits

Author SHA1 Message Date
RPRX
8eed8a0824 v1.2.2 2021-01-15 13:18:37 +00:00
RPRX
88f6537540 Make necessary maps in non-empty names before copy 2021-01-15 11:36:31 +00:00
RPRX
f0efc0cfde As substring to match in VLESS fallbacks SNI shunt 2021-01-15 09:43:39 +00:00
RPRX
f13ac3cb55 Fix VLESS fallbacks SNI shunt 2021-01-14 21:55:52 +00:00
eMeab
638e8384b6 Optimized log (#167) 2021-01-14 14:45:23 +00:00
eMeab
d85162ea44 Add SNI shunt support for VLESS (#141) 2021-01-13 15:13:51 +00:00
Arthur Morgan
11a851f957 Fix non-local DoH requests & Apply routing (#147) 2021-01-13 07:53:08 +00:00
RPRX
822afb0cc8 Improve UUID generator
https://github.com/XTLS/Xray-core/issues/158
2021-01-12 18:23:54 +00:00
RPRX
157918859f Add pre-checking conversion for VLESS & VMess UUID
https://github.com/XTLS/Xray-core/issues/158
2021-01-12 11:31:02 +00:00
RPRX
40271c09a0 Support for VLESS & VMess UUID v5 mapping standard
https://github.com/XTLS/Xray-core/issues/158
2021-01-11 17:56:33 +00:00
maskedeken
96adf3fbca Trojan: Do not panic when UDP dispatcher failed to write response (#153) 2021-01-11 09:30:57 +00:00
RPRX
e254424c43 v1.2.1 2021-01-10 07:58:53 +00:00
RPRX
ee15cc253f Improve configuration detector (cone or symmetric) 2021-01-10 07:50:21 +00:00
RPRX
43eb5d1b25 16 -> 60, 8 -> 300
https://github.com/XTLS/Xray-core/issues/129#issuecomment-757355137

十分感谢 @GleenJi 等协助测试
2021-01-10 04:50:26 +00:00
RPRX
700966508f Improve the response to UDP Associate in Socks5 2021-01-09 16:36:20 +00:00
RPRX
7427a55ef1 Adjust Trojan Outbound postRequest 2021-01-08 12:00:46 +00:00
RPRX
fb0e517158 Adjust Trojan & Socks handleUDPPayload 2021-01-08 06:00:51 +00:00
maskedeken
d5aeb6c545 Refine Trojan packet reader & writer (#142) 2021-01-08 03:55:25 +00:00
RPRX
161e18299c Fix TPROXY UDP/IPv6
https://github.com/XTLS/Xray-core/issues/137#issuecomment-756064627

十分感谢 @Ninedyz @changyp6
2021-01-07 12:21:27 +00:00
eMeab
be9421fedf Optimized log (#121) 2021-01-04 05:05:38 +00:00
28 changed files with 412 additions and 261 deletions

View File

@@ -263,14 +263,18 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
skipRoutePick = content.SkipRoutePick
}
routingLink := routing_session.AsRoutingContext(ctx)
inTag := routingLink.GetInboundTag()
isPickRoute := false
if d.router != nil && !skipRoutePick {
if route, err := d.router.PickRoute(routing_session.AsRoutingContext(ctx)); err == nil {
tag := route.GetOutboundTag()
if h := d.ohm.GetHandler(tag); h != nil {
newError("taking detour [", tag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
if route, err := d.router.PickRoute(routingLink); err == nil {
outTag := route.GetOutboundTag()
isPickRoute = true
if h := d.ohm.GetHandler(outTag); h != nil {
newError("taking detour [", outTag, "] for [", destination, "]").WriteToLog(session.ExportIDToError(ctx))
handler = h
} else {
newError("non existing tag: ", tag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
newError("non existing outTag: ", outTag).AtWarning().WriteToLog(session.ExportIDToError(ctx))
}
} else {
newError("default route for ", destination).WriteToLog(session.ExportIDToError(ctx))
@@ -290,7 +294,19 @@ func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *transport.
if accessMessage := log.AccessMessageFromContext(ctx); accessMessage != nil {
if tag := handler.Tag(); tag != "" {
accessMessage.Detour = tag
if isPickRoute {
if inTag != "" {
accessMessage.Detour = inTag + " -> " + tag
} else {
accessMessage.Detour = tag
}
} else {
if inTag != "" {
accessMessage.Detour = inTag + " >> " + tag
} else {
accessMessage.Detour = tag
}
}
}
log.Record(accessMessage)
}

View File

@@ -29,6 +29,7 @@ import (
// which is compatible with traditional dns over udp(RFC1035),
// thus most of the DOH implementation is copied from udpns.go
type DoHNameServer struct {
dispatcher routing.Dispatcher
sync.RWMutex
ips map[string]record
pub *pubsub.Service
@@ -45,40 +46,8 @@ func NewDoHNameServer(url *url.URL, dispatcher routing.Dispatcher, clientIP net.
newError("DNS: created Remote DOH client for ", url.String()).AtInfo().WriteToLog()
s := baseDOHNameServer(url, "DOH", clientIP)
// Dispatched connection will be closed (interrupted) after each request
// This makes DOH inefficient without a keep-alived connection
// See: core/app/proxyman/outbound/handler.go:113
// Using mux (https request wrapped in a stream layer) improves the situation.
// Recommend to use NewDoHLocalNameServer (DOHL:) if xray instance is running on
// a normal network eg. the server side of xray
tr := &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
s.dispatcher = dispatcher
link, err := dispatcher.Dispatch(ctx, dest)
if err != nil {
return nil, err
}
return cnc.NewConnection(
cnc.ConnectionInputMulti(link.Writer),
cnc.ConnectionOutputMulti(link.Reader),
), nil
},
}
dispatchedClient := &http.Client{
Transport: tr,
Timeout: 60 * time.Second,
}
s.httpClient = dispatchedClient
return s, nil
}
@@ -211,6 +180,11 @@ func (s *DoHNameServer) newReqID() uint16 {
func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPOption) {
newError(s.name, " querying: ", domain).AtInfo().WriteToLog(session.ExportIDToError(ctx))
if s.name+"." == "DOH//"+domain {
newError(s.name, " tries to resolve itself! Use IP or set \"hosts\" instead.").AtError().WriteToLog(session.ExportIDToError(ctx))
return
}
reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(s.clientIP))
var deadline time.Time
@@ -232,12 +206,12 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPO
}
dnsCtx = session.ContextWithContent(dnsCtx, &session.Content{
Protocol: "https",
SkipRoutePick: true,
Protocol: "https",
//SkipRoutePick: true,
})
// forced to use mux for DOH
dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)
// dnsCtx = session.ContextWithMuxPrefered(dnsCtx, true)
var cancel context.CancelFunc
dnsCtx, cancel = context.WithDeadline(dnsCtx, deadline)
@@ -245,17 +219,17 @@ func (s *DoHNameServer) sendQuery(ctx context.Context, domain string, option IPO
b, err := dns.PackMessage(r.msg)
if err != nil {
newError("failed to pack dns query").Base(err).AtError().WriteToLog()
newError("failed to pack dns query for ", domain).Base(err).AtError().WriteToLog()
return
}
resp, err := s.dohHTTPSContext(dnsCtx, b.Bytes())
if err != nil {
newError("failed to retrieve response").Base(err).AtError().WriteToLog()
newError("failed to retrieve response for ", domain).Base(err).AtError().WriteToLog()
return
}
rec, err := parseResponse(resp)
if err != nil {
newError("failed to handle DOH response").Base(err).AtError().WriteToLog()
newError("failed to handle DOH response for ", domain).Base(err).AtError().WriteToLog()
return
}
s.updateIP(r, rec)
@@ -273,7 +247,44 @@ func (s *DoHNameServer) dohHTTPSContext(ctx context.Context, b []byte) ([]byte,
req.Header.Add("Accept", "application/dns-message")
req.Header.Add("Content-Type", "application/dns-message")
resp, err := s.httpClient.Do(req.WithContext(ctx))
hc := s.httpClient
// Dispatched connection will be closed (interrupted) after each request
// This makes DOH inefficient without a keep-alived connection
// See: core/app/proxyman/outbound/handler.go:113
// Using mux (https request wrapped in a stream layer) improves the situation.
// Recommend to use NewDoHLocalNameServer (DOHL:) if xray instance is running on
// a normal network eg. the server side of xray
if s.dispatcher != nil {
tr := &http.Transport{
MaxIdleConns: 30,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 30 * time.Second,
ForceAttemptHTTP2: true,
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
dest, err := net.ParseDestination(network + ":" + addr)
if err != nil {
return nil, err
}
link, err := s.dispatcher.Dispatch(ctx, dest)
if err != nil {
return nil, err
}
return cnc.NewConnection(
cnc.ConnectionInputMulti(link.Writer),
cnc.ConnectionOutputMulti(link.Reader),
), nil
},
}
hc = &http.Client{
Timeout: time.Second * 180,
Transport: tr,
}
}
resp, err := hc.Do(req.WithContext(ctx))
if err != nil {
return nil, err
}

View File

@@ -136,6 +136,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
stream: mss,
ctx: ctx,
}
h.workers = append(h.workers, worker)
}

View File

@@ -156,6 +156,7 @@ func (h *DynamicInboundHandler) refresh() error {
uplinkCounter: uplinkCounter,
downlinkCounter: downlinkCounter,
stream: h.streamSettings,
ctx: h.ctx,
}
if err := worker.Start(); err != nil {
newError("failed to create UDP worker").Base(err).AtWarning().WriteToLog()

View File

@@ -239,6 +239,9 @@ type udpWorker struct {
checker *task.Periodic
activeConn map[connID]*udpConn
ctx context.Context
cone bool
}
func (w *udpWorker) getConnection(id connID) (*udpConn, bool) {
@@ -279,7 +282,7 @@ func (w *udpWorker) callback(b *buf.Buffer, source net.Destination, originalDest
src: source,
}
if originalDest.IsValid() {
if !buf.Cone {
if !w.cone {
id.dest = originalDest
}
b.UDP = &originalDest
@@ -339,7 +342,7 @@ func (w *udpWorker) clean() error {
}
for addr, conn := range w.activeConn {
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 8 { // TODO Timeout too small
if nowSec-atomic.LoadInt64(&conn.lastActivityTime) > 300 {
delete(w.activeConn, addr)
conn.Close()
}
@@ -360,8 +363,10 @@ func (w *udpWorker) Start() error {
return err
}
w.cone = w.ctx.Value("cone").(bool)
w.checker = &task.Periodic{
Interval: time.Second * 16,
Interval: time.Minute,
Execute: w.clean,
}

View File

@@ -14,8 +14,6 @@ const (
var pool = bytespool.GetPool(Size)
var Cone = true
// Buffer is a recyclable allocation of a byte array. Buffer.Release() recycles
// the buffer into an internal buffer pool, in order to recreate a buffer more
// quickly.

View File

@@ -3,6 +3,7 @@ package uuid // import "github.com/xtls/xray-core/common/uuid"
import (
"bytes"
"crypto/rand"
"crypto/sha1"
"encoding/hex"
"github.com/xtls/xray-core/common"
@@ -49,6 +50,8 @@ func (u *UUID) Equals(another *UUID) bool {
func New() UUID {
var uuid UUID
common.Must2(rand.Read(uuid.Bytes()))
uuid[6] = (uuid[6] & 0x0f) | (4 << 4)
uuid[8] = (uuid[8]&(0xff>>2) | (0x02 << 6))
return uuid
}
@@ -67,8 +70,18 @@ func ParseString(str string) (UUID, error) {
var uuid UUID
text := []byte(str)
if len(text) < 32 {
return uuid, errors.New("invalid UUID: ", str)
if l := len(text); l < 32 || l > 36 {
if l == 0 || l > 30 {
return uuid, errors.New("invalid UUID: ", str)
}
h := sha1.New()
h.Write(uuid[:])
h.Write(text)
u := h.Sum(nil)[:16]
u[6] = (u[6] & 0x0f) | (5 << 4)
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
copy(uuid[:], u)
return uuid, nil
}
b := uuid.Bytes()

View File

@@ -35,9 +35,10 @@ func TestParseString(t *testing.T) {
t.Fatal(r)
}
_, err = ParseString("2418d087")
if err == nil {
t.Fatal("Expect error but nil")
u0, _ := ParseString("example")
u5, _ := ParseString("feb54431-301b-52bb-a6dd-e1e93e81bb9e")
if r := cmp.Diff(u0, u5); r != "" {
t.Fatal(r)
}
_, err = ParseString("2418d087-648k-4990-86e8-19dca1d006d3")

View File

@@ -18,7 +18,7 @@ import (
)
var (
version = "1.2.0"
version = "1.2.2"
build = "Custom"
codename = "Xray, Penetrates Everything."
intro = "A unified platform for anti-censorship."

View File

@@ -3,8 +3,13 @@ package core
import (
"context"
"reflect"
"runtime/debug"
"strings"
"sync"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/features"
@@ -179,6 +184,31 @@ func NewWithContext(ctx context.Context, config *Config) (*Instance, error) {
}
func initInstanceWithConfig(config *Config, server *Instance) (bool, error) {
cone := true
v, t := false, false
for _, outbound := range config.Outbound {
s := strings.ToLower(outbound.ProxySettings.Type)
l := len(s)
if l >= 16 && s[11:16] == "vless" || l >= 16 && s[11:16] == "vmess" {
v = true
continue
}
if l >= 17 && s[11:17] == "trojan" || l >= 22 && s[11:22] == "shadowsocks" {
t = true
var m proxyman.SenderConfig
proto.Unmarshal(outbound.SenderSettings.Value, &m)
if m.MultiplexSettings != nil && m.MultiplexSettings.Enabled {
cone = false
break
}
}
}
if v && !t {
cone = false
}
server.ctx = context.WithValue(server.ctx, "cone", cone)
defer debug.FreeOSMemory()
if config.Transport != nil {
features.PrintDeprecatedFeatureWarning("global transport settings")
}

8
go.mod
View File

@@ -13,14 +13,14 @@ require (
github.com/pelletier/go-toml v1.8.1
github.com/pires/go-proxyproto v0.3.3
github.com/seiflotfy/cuckoofilter v0.0.0-20201222105146-bc6005554a0c
github.com/stretchr/testify v1.6.1
github.com/stretchr/testify v1.7.0
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5
go.starlark.net v0.0.0-20210114021256-8756d3ec1770
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/net v0.0.0-20201224014010-6772e930b67b
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014
google.golang.org/grpc v1.34.0
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78
google.golang.org/grpc v1.35.0
google.golang.org/protobuf v1.25.0
h12.io/socks v1.0.2
)

18
go.sum
View File

@@ -19,7 +19,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -29,7 +29,7 @@ github.com/dgryski/go-metro v0.0.0-20200812162917-85c65e2d0165/go.mod h1:c9O8+fp
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
@@ -171,6 +171,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU=
github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM=
@@ -178,8 +180,8 @@ github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499 h1:QHESTXtfgc1ABV+ArlbPVqU
github.com/xtls/go v0.0.0-20201118062508-3632bf3b7499/go.mod h1:5TB2+k58gx4A4g2Nf5miSHNDF6CuAzHKpWBooLAshTs=
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5 h1:F1LaLz0cvAJWMa5r3bogEYXD7/5fgA9a9jOX4DAobN8=
go.starlark.net v0.0.0-20201210151846-e81fc95f7bd5/go.mod h1:vxxlMsgCAPH7BR2LtxjJC4WhhZhCGd/b01+CIpj8H4k=
go.starlark.net v0.0.0-20210114021256-8756d3ec1770 h1:S8VZYGh3JOUhV0QWJcoZDIXBLoArFNkMbqsL23SzaSE=
go.starlark.net v0.0.0-20210114021256-8756d3ec1770/go.mod h1:vxxlMsgCAPH7BR2LtxjJC4WhhZhCGd/b01+CIpj8H4k=
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -242,8 +244,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014 h1:joucsQqXmyBVxViHCPFjG3hx8JzIFSaym3l3MM/Jsdg=
golang.org/x/sys v0.0.0-20201231184435-2d18734c6014/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY=
golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -290,8 +292,8 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.34.0 h1:raiipEjMOIC/TO2AvyTxP25XFdLxNIBwzDh3FM3XztI=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0 h1:TwIQcH3es+MojMVojxxfQ3l3OF2KzlRxML2xZq0kRo8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View File

@@ -11,12 +11,14 @@ import (
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/proxy/vless"
"github.com/xtls/xray-core/proxy/vless/inbound"
"github.com/xtls/xray-core/proxy/vless/outbound"
)
type VLessInboundFallback struct {
Name string `json:"name"`
Alpn string `json:"alpn"`
Path string `json:"path"`
Type string `json:"type"`
@@ -45,6 +47,12 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
return nil, newError(`VLESS clients: invalid user`).Base(err)
}
u, err := uuid.ParseString(account.Id)
if err != nil {
return nil, err
}
account.Id = u.String()
switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-direct":
case "xtls-rprx-splice":
@@ -78,6 +86,7 @@ func (c *VLessInboundConfig) Build() (proto.Message, error) {
_ = json.Unmarshal(fb.Dest, &s)
}
config.Fallbacks = append(config.Fallbacks, &inbound.Fallback{
Name: fb.Name,
Alpn: fb.Alpn,
Path: fb.Path,
Type: fb.Type,
@@ -167,6 +176,12 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
return nil, newError(`VLESS users: invalid user`).Base(err)
}
u, err := uuid.ParseString(account.Id)
if err != nil {
return nil, err
}
account.Id = u.String()
switch account.Flow {
case "", "xtls-rprx-origin", "xtls-rprx-origin-udp443", "xtls-rprx-direct", "xtls-rprx-direct-udp443":
case "xtls-rprx-splice", "xtls-rprx-splice-udp443":

View File

@@ -8,6 +8,7 @@ import (
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/common/uuid"
"github.com/xtls/xray-core/proxy/vmess"
"github.com/xtls/xray-core/proxy/vmess/inbound"
"github.com/xtls/xray-core/proxy/vmess/outbound"
@@ -105,6 +106,13 @@ func (c *VMessInboundConfig) Build() (proto.Message, error) {
if err := json.Unmarshal(rawData, account); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
u, err := uuid.ParseString(account.ID)
if err != nil {
return nil, err
}
account.ID = u.String()
user.Account = serial.ToTypedMessage(account.Build())
config.User[idx] = user
}
@@ -149,6 +157,13 @@ func (c *VMessOutboundConfig) Build() (proto.Message, error) {
if err := json.Unmarshal(rawUser, account); err != nil {
return nil, newError("invalid VMess user").Base(err)
}
u, err := uuid.ParseString(account.ID)
if err != nil {
return nil, err
}
account.ID = u.String()
user.Account = serial.ToTypedMessage(account.Build())
spec.User = append(spec.User, user)
}

View File

@@ -8,15 +8,33 @@ import (
)
var cmdUUID = &base.Command{
UsageLine: "{{.Exec}} uuid",
Short: "Generate new UUIDs",
UsageLine: `{{.Exec}} uuid [-i "example"]`,
Short: `Generate UUIDv4 or UUIDv5`,
Long: `
Generate new UUIDs.
`,
Run: executeUUID,
Generate UUIDv4 or UUIDv5.
UUIDv4 (random): {{.Exec}} uuid
UUIDv5 (from input): {{.Exec}} uuid -i "example"
`,
}
func executeUUID(cmd *base.Command, args []string) {
u := uuid.New()
fmt.Println(u.String())
func init() {
cmdUUID.Run = executeUUID // break init loop
}
var input = cmdUUID.Flag.String("i", "", "")
func executeUUID(cmd *base.Command, args []string) {
var output string
if l := len(*input); l == 0 {
u := uuid.New()
output = u.String()
} else if l <= 30 {
u, _ := uuid.ParseString(*input)
output = u.String()
} else {
output = "Input must be within 30 bytes."
}
fmt.Println(output)
}

View File

@@ -14,10 +14,6 @@ import (
"strings"
"syscall"
"github.com/golang/protobuf/proto"
"github.com/xtls/xray-core/app/proxyman"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/cmdarg"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/core"
@@ -185,26 +181,6 @@ func startXray() (core.Server, error) {
return nil, newError("failed to load config files: [", configFiles.String(), "]").Base(err)
}
v, t := false, false
for _, outbound := range config.Outbound {
s := strings.ToLower(outbound.ProxySettings.Type)
l := len(s)
if l >= 16 && s[11:16] == "vless" || l >= 16 && s[11:16] == "vmess" {
v = true
continue
}
if l >= 17 && s[11:17] == "trojan" || l >= 22 && s[11:22] == "shadowsocks" {
var m proxyman.SenderConfig
proto.Unmarshal(outbound.SenderSettings.Value, &m)
if m.MultiplexSettings == nil || !m.MultiplexSettings.Enabled {
t = true
}
}
}
if v && !t {
buf.Cone = false
}
server, err := core.New(config)
if err != nil {
return nil, newError("failed to create server").Base(err)

View File

@@ -163,14 +163,19 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
if !destinationOverridden {
writer = &buf.SequentialWriter{Writer: conn}
} else {
var addr *net.UDPAddr
var mark int
if dest.Address.Family().IsIP() {
addr = &net.UDPAddr{
IP: dest.Address.IP(),
Port: int(dest.Port),
back := conn.RemoteAddr().(*net.UDPAddr)
if !dest.Address.Family().IsIP() {
if len(back.IP) == 4 {
dest.Address = net.AnyIP
} else {
dest.Address = net.AnyIPv6
}
}
addr := &net.UDPAddr{
IP: dest.Address.IP(),
Port: int(dest.Port),
}
var mark int
if d.sockopt != nil {
mark = int(d.sockopt.Mark)
}
@@ -178,8 +183,7 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
if err != nil {
return err
}
back := net.DestinationFromAddr(conn.RemoteAddr())
writer = NewPacketWriter(pConn, &dest, mark, &back)
writer = NewPacketWriter(pConn, &dest, mark, back)
defer writer.(*PacketWriter).Close()
/*
sockopt := &internet.SocketConfig{
@@ -236,15 +240,12 @@ func (d *DokodemoDoor) Process(ctx context.Context, network net.Network, conn in
return nil
}
func NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.Destination) buf.Writer {
func NewPacketWriter(conn net.PacketConn, d *net.Destination, mark int, back *net.UDPAddr) buf.Writer {
writer := &PacketWriter{
conn: conn,
conns: make(map[net.Destination]net.PacketConn),
mark: mark,
back: &net.UDPAddr{
IP: back.Address.IP(),
Port: int(back.Port),
},
back: back,
}
writer.conns[*d] = conn
return writer

View File

@@ -6,19 +6,11 @@ import (
"fmt"
"net"
"os"
"strconv"
"syscall"
)
func FakeUDP(addr *net.UDPAddr, mark int) (net.PacketConn, error) {
if addr == nil {
addr = &net.UDPAddr{
IP: []byte{0, 0, 0, 0},
Port: 0,
}
}
localSocketAddress, af, err := udpAddrToSocketAddr(addr)
if err != nil {
return nil, &net.OpError{Op: "fake", Err: fmt.Errorf("build local socket address: %s", err)}
@@ -75,11 +67,6 @@ func udpAddrToSocketAddr(addr *net.UDPAddr) (syscall.Sockaddr, int, error) {
ip := [16]byte{}
copy(ip[:], addr.IP.To16())
zoneID, err := strconv.ParseUint(addr.Zone, 10, 32)
if err != nil {
return nil, 0, err
}
return &syscall.SockaddrInet6{Addr: ip, Port: addr.Port, ZoneId: uint32(zoneID)}, syscall.AF_INET6, nil
return &syscall.SockaddrInet6{Addr: ip, Port: addr.Port, ZoneId: 0}, syscall.AF_INET6, nil
}
}

View File

@@ -24,6 +24,7 @@ type Server struct {
config *ServerConfig
user *protocol.MemoryUser
policyManager policy.Manager
cone bool
}
// NewServer create a new Shadowsocks server.
@@ -42,6 +43,7 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
config: config,
user: mUser,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
return s, nil
@@ -144,7 +146,7 @@ func (s *Server) handlerUDPPayload(ctx context.Context, conn internet.Connection
data.UDP = &destination
if !buf.Cone || dest == nil {
if !s.cone || dest == nil {
dest = &destination
}

View File

@@ -39,10 +39,10 @@ var addrParser = protocol.NewAddressParser(
)
type ServerSession struct {
config *ServerConfig
address net.Address
port net.Port
clientAddress net.Address
config *ServerConfig
address net.Address
port net.Port
localAddress net.Address
}
func (s *ServerSession) handshake4(cmd byte, reader io.Reader, writer io.Writer) (*protocol.RequestHeader, error) {
@@ -192,14 +192,11 @@ func (s *ServerSession) handshake5(nMethod byte, reader io.Reader, writer io.Wri
//nolint:gocritic // Use if else chain for clarity
if request.Command == protocol.RequestCommandUDP {
if s.config.Address != nil {
// Use configured IP as remote address in the response to UdpAssociate
// Use configured IP as remote address in the response to UDP Associate
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
// Use conn.LocalAddr() IP as remote address in the response by default
responseAddress = s.localAddress
}
}
if err := writeSocks5Response(writer, statusSuccess, responseAddress, responsePort); err != nil {

View File

@@ -26,6 +26,7 @@ import (
type Server struct {
config *ServerConfig
policyManager policy.Manager
cone bool
}
// NewServer creates a new Server object.
@@ -34,6 +35,7 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
s := &Server{
config: config,
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
cone: ctx.Value("cone").(bool),
}
return s, nil
}
@@ -89,10 +91,10 @@ func (s *Server) processTCP(ctx context.Context, conn internet.Connection, dispa
}
svrSession := &ServerSession{
config: s.config,
address: inbound.Gateway.Address,
port: inbound.Gateway.Port,
clientAddress: inbound.Source.Address,
config: s.config,
address: inbound.Gateway.Address,
port: inbound.Gateway.Port,
localAddress: net.IPAddress(conn.LocalAddr().(*net.TCPAddr).IP),
}
reader := &buf.BufferedReader{Reader: buf.NewReader(conn)}
@@ -218,7 +220,8 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
conn.Write(udpMessage.Bytes())
})
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
inbound := session.InboundFromContext(ctx)
if inbound != nil && inbound.Source.IsValid() {
newError("client UDP connection from ", inbound.Source).WriteToLog(session.ExportIDToError(ctx))
}
@@ -249,7 +252,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
currentPacketCtx := ctx
newError("send packet to ", destination, " with ", payload.Len(), " bytes").AtDebug().WriteToLog(session.ExportIDToError(ctx))
if inbound := session.InboundFromContext(ctx); inbound != nil && inbound.Source.IsValid() {
if inbound != nil && inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: destination,
@@ -260,7 +263,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn internet.Connection,
payload.UDP = &destination
if !buf.Cone || dest == nil {
if !s.cone || dest == nil {
dest = &destination
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/xtls/xray-core/common"
"github.com/xtls/xray-core/common/buf"
"github.com/xtls/xray-core/common/errors"
"github.com/xtls/xray-core/common/net"
"github.com/xtls/xray-core/common/platform"
"github.com/xtls/xray-core/common/protocol"
@@ -145,12 +146,13 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
postRequest := func() error {
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
var bodyWriter buf.Writer
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
connWriter.Writer = bufferWriter
connWriter.Target = destination
connWriter.Account = account
var bodyWriter buf.Writer
if destination.Network == net.Network_UDP {
bodyWriter = &PacketWriter{Writer: connWriter, Target: destination}
} else {
@@ -167,6 +169,11 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
return newError("failed to flush payload").Base(err).AtWarning()
}
// Send header if not sent yet
if _, err = connWriter.Write([]byte{}); err != nil {
return err.(*errors.Error).AtWarning()
}
if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
return newError("failed to transfer request payload").Base(err).AtInfo()
}

View File

@@ -146,26 +146,6 @@ func (w *PacketWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
return nil
}
// WriteMultiBufferWithMetadata writes udp packet with destination specified
func (w *PacketWriter) WriteMultiBufferWithMetadata(mb buf.MultiBuffer, dest net.Destination) error {
for {
mb2, b := buf.SplitFirst(mb)
mb = mb2
if b == nil {
break
}
source := &dest
if b.UDP != nil {
source = b.UDP
}
if _, err := w.writePacket(b.Bytes(), *source); err != nil {
buf.ReleaseMulti(mb)
return err
}
}
return nil
}
func (w *PacketWriter) writePacket(payload []byte, dest net.Destination) (int, error) {
buffer := buf.StackNew()
defer buffer.Release()
@@ -259,12 +239,6 @@ func (c *ConnReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
return buf.MultiBuffer{b}, err
}
// PacketPayload combines udp payload and destination
type PacketPayload struct {
Target net.Destination
Buffer buf.MultiBuffer
}
// PacketReader is UDP Connection Reader Wrapper for trojan protocol
type PacketReader struct {
io.Reader
@@ -272,15 +246,6 @@ type PacketReader struct {
// ReadMultiBuffer implements buf.Reader
func (r *PacketReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
p, err := r.ReadMultiBufferWithMetadata()
if p != nil {
return p.Buffer, err
}
return nil, err
}
// ReadMultiBufferWithMetadata reads udp packet with destination
func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
addr, port, err := addrParser.ReadAddressPort(nil, r)
if err != nil {
return nil, newError("failed to read address and port").Base(err)
@@ -321,7 +286,7 @@ func (r *PacketReader) ReadMultiBufferWithMetadata() (*PacketPayload, error) {
remain -= int(n)
}
return &PacketPayload{Target: dest, Buffer: mb}, nil
return mb, nil
}
func ReadV(reader buf.Reader, writer buf.Writer, timer signal.ActivityUpdater, conn *xtls.Conn, rawConn syscall.RawConn, counter stats.Counter, sctx context.Context) error {

View File

@@ -71,21 +71,22 @@ func TestUDPRequest(t *testing.T) {
common.Must(connReader.ParseHeader())
packetReader := &PacketReader{Reader: connReader}
p, err := packetReader.ReadMultiBufferWithMetadata()
mb, err := packetReader.ReadMultiBuffer()
common.Must(err)
if p.Buffer.IsEmpty() {
if mb.IsEmpty() {
t.Error("no request data")
}
if r := cmp.Diff(p.Target, destination); r != "" {
mb2, b := buf.SplitFirst(mb)
defer buf.ReleaseMulti(mb2)
dest := *b.UDP
if r := cmp.Diff(dest, destination); r != "" {
t.Error("destination: ", r)
}
mb, decoded := buf.SplitFirst(p.Buffer)
buf.ReleaseMulti(mb)
if r := cmp.Diff(decoded.Bytes(), payload); r != "" {
if r := cmp.Diff(b.Bytes(), payload); r != "" {
t.Error("data: ", r)
}
}

View File

@@ -47,6 +47,7 @@ type Server struct {
policyManager policy.Manager
validator *Validator
fallbacks map[string]map[string]*Fallback // or nil
cone bool
}
// NewServer creates a new trojan inbound handler.
@@ -67,6 +68,7 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
server := &Server{
policyManager: v.GetFeature(policy.ManagerType()).(policy.Manager),
validator: validator,
cone: ctx.Value("cone").(bool),
}
if config.Fallbacks != nil {
@@ -250,7 +252,14 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn internet
func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReader, clientWriter *PacketWriter, dispatcher routing.Dispatcher) error {
udpServer := udp.NewDispatcher(dispatcher, func(ctx context.Context, packet *udp_proto.Packet) {
common.Must(clientWriter.WriteMultiBufferWithMetadata(buf.MultiBuffer{packet.Payload}, packet.Source))
udpPayload := packet.Payload
if udpPayload.UDP == nil {
udpPayload.UDP = &packet.Source
}
if err := clientWriter.WriteMultiBuffer(buf.MultiBuffer{udpPayload}); err != nil {
newError("failed to write response").Base(err).AtWarning().WriteToLog(session.ExportIDToError(ctx))
}
})
inbound := session.InboundFromContext(ctx)
@@ -263,7 +272,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
case <-ctx.Done():
return nil
default:
p, err := clientReader.ReadMultiBufferWithMetadata()
mb, err := clientReader.ReadMultiBuffer()
if err != nil {
if errors.Cause(err) != io.EOF {
return newError("unexpected EOF").Base(err)
@@ -271,21 +280,31 @@ func (s *Server) handleUDPPayload(ctx context.Context, clientReader *PacketReade
return nil
}
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: p.Target,
Status: log.AccessAccepted,
Reason: "",
Email: user.Email,
})
newError("tunnelling request to ", p.Target).WriteToLog(session.ExportIDToError(ctx))
mb2, b := buf.SplitFirst(mb)
if b == nil {
continue
}
destination := *b.UDP
if !buf.Cone || dest == nil {
dest = &p.Target
currentPacketCtx := ctx
if inbound.Source.IsValid() {
currentPacketCtx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
From: inbound.Source,
To: destination,
Status: log.AccessAccepted,
Reason: "",
Email: user.Email,
})
}
newError("tunnelling request to ", destination).WriteToLog(session.ExportIDToError(ctx))
if !s.cone || dest == nil {
dest = &destination
}
for _, b := range p.Buffer {
udpServer.Dispatch(ctx, *dest, b)
udpServer.Dispatch(currentPacketCtx, *dest, b) // first packet
for _, payload := range mb2 {
udpServer.Dispatch(currentPacketCtx, *dest, payload)
}
}
}

View File

@@ -31,11 +31,12 @@ type Fallback struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Alpn string `protobuf:"bytes,1,opt,name=alpn,proto3" json:"alpn,omitempty"`
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
Type string `protobuf:"bytes,3,opt,name=type,proto3" json:"type,omitempty"`
Dest string `protobuf:"bytes,4,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,5,opt,name=xver,proto3" json:"xver,omitempty"`
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Alpn string `protobuf:"bytes,2,opt,name=alpn,proto3" json:"alpn,omitempty"`
Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"`
Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"`
Dest string `protobuf:"bytes,5,opt,name=dest,proto3" json:"dest,omitempty"`
Xver uint64 `protobuf:"varint,6,opt,name=xver,proto3" json:"xver,omitempty"`
}
func (x *Fallback) Reset() {
@@ -70,6 +71,13 @@ func (*Fallback) Descriptor() ([]byte, []int) {
return file_proxy_vless_inbound_config_proto_rawDescGZIP(), []int{0}
}
func (x *Fallback) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *Fallback) GetAlpn() string {
if x != nil {
return x.Alpn
@@ -178,31 +186,33 @@ var file_proxy_vless_inbound_config_proto_rawDesc = []byte{
0x74, 0x6f, 0x12, 0x18, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x1a, 0x1a, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x75, 0x73,
0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x6e, 0x0a, 0x08, 0x46, 0x61, 0x6c, 0x6c,
0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04,
0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01,
0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xa0, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x55, 0x73, 0x65, 0x72,
0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x63,
0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64,
0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x09, 0x66, 0x61, 0x6c,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x78,
0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e,
0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b,
0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x42, 0x6a, 0x0a, 0x1c, 0x63,
0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76, 0x6c,
0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x50, 0x01, 0x5a, 0x2d, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78,
0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2f, 0x76,
0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0xaa, 0x02, 0x18, 0x58,
0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56, 0x6c, 0x65, 0x73, 0x73, 0x2e,
0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x82, 0x01, 0x0a, 0x08, 0x46, 0x61, 0x6c,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x6c, 0x70,
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x12, 0x12, 0x0a,
0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74,
0x68, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x78, 0x76, 0x65,
0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x78, 0x76, 0x65, 0x72, 0x22, 0xa0, 0x01,
0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x6c, 0x69, 0x65,
0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x78, 0x72, 0x61, 0x79,
0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c,
0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x07, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x1e,
0x0a, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40,
0x0a, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x22, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x76,
0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x2e, 0x46, 0x61, 0x6c,
0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x66, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x73,
0x42, 0x6a, 0x0a, 0x1c, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x70, 0x72, 0x6f,
0x78, 0x79, 0x2e, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2e, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64,
0x50, 0x01, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78,
0x74, 0x6c, 0x73, 0x2f, 0x78, 0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x78, 0x79, 0x2f, 0x76, 0x6c, 0x65, 0x73, 0x73, 0x2f, 0x69, 0x6e, 0x62, 0x6f, 0x75, 0x6e,
0x64, 0xaa, 0x02, 0x18, 0x58, 0x72, 0x61, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x56,
0x6c, 0x65, 0x73, 0x73, 0x2e, 0x49, 0x6e, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -9,11 +9,12 @@ option java_multiple_files = true;
import "common/protocol/user.proto";
message Fallback {
string alpn = 1;
string path = 2;
string type = 3;
string dest = 4;
uint64 xver = 5;
string name = 1;
string alpn = 2;
string path = 3;
string type = 4;
string dest = 5;
uint64 xver = 6;
}
message Config {

View File

@@ -6,6 +6,7 @@ import (
"context"
"io"
"strconv"
"strings"
"syscall"
"time"
@@ -63,7 +64,7 @@ type Handler struct {
policyManager policy.Manager
validator *vless.Validator
dns dns.Client
fallbacks map[string]map[string]*Fallback // or nil
fallbacks map[string]map[string]map[string]*Fallback // or nil
// regexps map[string]*regexp.Regexp // or nil
}
@@ -88,13 +89,16 @@ func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
}
if config.Fallbacks != nil {
handler.fallbacks = make(map[string]map[string]*Fallback)
handler.fallbacks = make(map[string]map[string]map[string]*Fallback)
// handler.regexps = make(map[string]*regexp.Regexp)
for _, fb := range config.Fallbacks {
if handler.fallbacks[fb.Alpn] == nil {
handler.fallbacks[fb.Alpn] = make(map[string]*Fallback)
if handler.fallbacks[fb.Name] == nil {
handler.fallbacks[fb.Name] = make(map[string]map[string]*Fallback)
}
handler.fallbacks[fb.Alpn][fb.Path] = fb
if handler.fallbacks[fb.Name][fb.Alpn] == nil {
handler.fallbacks[fb.Name][fb.Alpn] = make(map[string]*Fallback)
}
handler.fallbacks[fb.Name][fb.Alpn][fb.Path] = fb
/*
if fb.Path != "" {
if r, err := regexp.Compile(fb.Path); err != nil {
@@ -106,11 +110,37 @@ func New(ctx context.Context, config *Config, dc dns.Client) (*Handler, error) {
*/
}
if handler.fallbacks[""] != nil {
for alpn, pfb := range handler.fallbacks {
if alpn != "" { // && alpn != "h2" {
for path, fb := range handler.fallbacks[""] {
if pfb[path] == nil {
pfb[path] = fb
for name, apfb := range handler.fallbacks {
if name != "" {
for alpn := range handler.fallbacks[""] {
if apfb[alpn] == nil {
apfb[alpn] = make(map[string]*Fallback)
}
}
}
}
}
for _, apfb := range handler.fallbacks {
if apfb[""] != nil {
for alpn, pfb := range apfb {
if alpn != "" { // && alpn != "h2" {
for path, fb := range apfb[""] {
if pfb[path] == nil {
pfb[path] = fb
}
}
}
}
}
}
if handler.fallbacks[""] != nil {
for name, apfb := range handler.fallbacks {
if name != "" {
for alpn, pfb := range handler.fallbacks[""] {
for path, fb := range pfb {
if apfb[alpn][path] == nil {
apfb[alpn][path] = fb
}
}
}
}
@@ -171,8 +201,8 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
var requestAddons *encoding.Addons
var err error
apfb := h.fallbacks
isfb := apfb != nil
napfb := h.fallbacks
isfb := napfb != nil
if isfb && firstLen < 18 {
err = newError("fallback directly")
@@ -187,19 +217,45 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection i
}
newError("fallback starts").Base(err).AtInfo().WriteToLog(sid)
name := ""
alpn := ""
if len(apfb) > 1 || apfb[""] == nil {
if tlsConn, ok := iConn.(*tls.Conn); ok {
alpn = tlsConn.ConnectionState().NegotiatedProtocol
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
alpn = xtlsConn.ConnectionState().NegotiatedProtocol
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
if apfb[alpn] == nil {
alpn = ""
if tlsConn, ok := iConn.(*tls.Conn); ok {
cs := tlsConn.ConnectionState()
name = cs.ServerName
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
} else if xtlsConn, ok := iConn.(*xtls.Conn); ok {
cs := xtlsConn.ConnectionState()
name = cs.ServerName
alpn = cs.NegotiatedProtocol
newError("realName = " + name).AtInfo().WriteToLog(sid)
newError("realAlpn = " + alpn).AtInfo().WriteToLog(sid)
}
if len(napfb) > 1 || napfb[""] == nil {
if name != "" && napfb[name] == nil {
match := ""
for n := range napfb {
if n != "" && strings.Contains(name, n) && len(n) > len(match) {
match = n
}
}
name = match
}
}
if napfb[name] == nil {
name = ""
}
apfb := napfb[name]
if apfb == nil {
return newError(`failed to find the default "name" config`).AtWarning()
}
if apfb[alpn] == nil {
alpn = ""
}
pfb := apfb[alpn]
if pfb == nil {
return newError(`failed to find the default "alpn" config`).AtWarning()