mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-09-27 01:10:28 +03:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
813f3810ef |
@@ -67,7 +67,9 @@ jobs:
|
|||||||
check-latest: true
|
check-latest: true
|
||||||
cache: false
|
cache: false
|
||||||
- name: Check Format
|
- name: Check Format
|
||||||
run: go run ./infra/vformat/main.go -mode check -pwd ./
|
run: |
|
||||||
|
go install -v mvdan.cc/gofumpt@latest
|
||||||
|
go run ./infra/vformat/main.go -mode check -pwd ./
|
||||||
|
|
||||||
test:
|
test:
|
||||||
needs: check-assets
|
needs: check-assets
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func newFakeDNSSniffer(ctx context.Context) (protocolSnifferWithMetadata, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if fakeDNSEngine == nil {
|
if fakeDNSEngine == nil {
|
||||||
errNotInit := errors.New("FakeDNSEngine is not initialized, but such a sniffer is used")
|
errNotInit := errors.New("FakeDNSEngine is not initialized, but such a sniffer is used").AtError()
|
||||||
return protocolSnifferWithMetadata{}, errNotInit
|
return protocolSnifferWithMetadata{}, errNotInit
|
||||||
}
|
}
|
||||||
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
return protocolSnifferWithMetadata{protocolSniffer: func(ctx context.Context, bytes []byte) (SniffResult, error) {
|
||||||
|
|||||||
+1
-1
@@ -28,7 +28,7 @@ func toNetIP(addrs []net.Address) ([]net.IP, error) {
|
|||||||
if addr.Family().IsIP() {
|
if addr.Family().IsIP() {
|
||||||
ips = append(ips, addr.IP())
|
ips = append(ips, addr.IP())
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Failed to convert address", addr, "to Net IP.")
|
return nil, errors.New("Failed to convert address", addr, "to Net IP.").AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ips, nil
|
return ips, nil
|
||||||
|
|||||||
@@ -188,10 +188,10 @@ func parseResponse(payload []byte) (*IPRecord, error) {
|
|||||||
var parser dnsmessage.Parser
|
var parser dnsmessage.Parser
|
||||||
h, err := parser.Start(payload)
|
h, err := parser.Start(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse DNS response").Base(err)
|
return nil, errors.New("failed to parse DNS response").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
if err := parser.SkipAllQuestions(); err != nil {
|
if err := parser.SkipAllQuestions(); err != nil {
|
||||||
return nil, errors.New("failed to skip questions in DNS response").Base(err)
|
return nil, errors.New("failed to skip questions in DNS response").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func NewFakeDNSHolder() (*Holder, error) {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
if fkdns, err = NewFakeDNSHolderConfigOnly(nil); err != nil {
|
||||||
return nil, errors.New("Unable to create Fake Dns Engine").Base(err)
|
return nil, errors.New("Unable to create Fake Dns Engine").Base(err).AtError()
|
||||||
}
|
}
|
||||||
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
err = fkdns.initialize(dns.FakeIPv4Pool, 65535)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -80,13 +80,13 @@ func (fkdns *Holder) initialize(ipPoolCidr string, lruSize int) error {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
if _, ipRange, err = net.ParseCIDR(ipPoolCidr); err != nil {
|
if _, ipRange, err = net.ParseCIDR(ipPoolCidr); err != nil {
|
||||||
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err)
|
return errors.New("Unable to parse CIDR for Fake DNS IP assignment").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
ones, bits := ipRange.Mask.Size()
|
ones, bits := ipRange.Mask.Size()
|
||||||
rooms := bits - ones
|
rooms := bits - ones
|
||||||
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
if math.Log2(float64(lruSize)) >= float64(rooms) {
|
||||||
return errors.New("LRU size is bigger than subnet size")
|
return errors.New("LRU size is bigger than subnet size").AtError()
|
||||||
}
|
}
|
||||||
fkdns.domainToIP = cache.NewLru(lruSize)
|
fkdns.domainToIP = cache.NewLru(lruSize)
|
||||||
fkdns.ipRange = ipRange
|
fkdns.ipRange = ipRange
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ func NewServer(ctx context.Context, dest net.Destination, dispatcher routing.Dis
|
|||||||
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
if dest.Network == net.Network_UDP { // UDP classic DNS mode
|
||||||
return NewClassicNameServer(dest, dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
return NewClassicNameServer(dest, dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP), nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("No available name server could be created from ", dest)
|
return nil, errors.New("No available name server could be created from ", dest).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
|
// NewClient creates a DNS client managing a name server with client IP, domain rules and expected IPs.
|
||||||
@@ -102,7 +102,7 @@ func NewClient(
|
|||||||
// Create a new server for each client for now
|
// Create a new server for each client for now
|
||||||
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
|
server, err := NewServer(ctx, ns.Address.AsDestination(), dispatcher, disableCache, serveStale, serveExpiredTTL, clientIP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create nameserver").Base(err)
|
return errors.New("failed to create nameserver").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
_, isLocalDNS := server.(*LocalNameServer)
|
_, isLocalDNS := server.(*LocalNameServer)
|
||||||
@@ -113,7 +113,7 @@ func NewClient(
|
|||||||
if len(ns.ExpectedIp) > 0 {
|
if len(ns.ExpectedIp) > 0 {
|
||||||
expectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.ExpectedIp)
|
expectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.ExpectedIp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create expected ip matcher").Base(err)
|
return errors.New("failed to create expected ip matcher").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ func NewClient(
|
|||||||
if len(ns.UnexpectedIp) > 0 {
|
if len(ns.UnexpectedIp) > 0 {
|
||||||
unexpectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.UnexpectedIp)
|
unexpectedMatcher, err = geodata.IPReg.BuildIPMatcher(ns.UnexpectedIp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create unexpected ip matcher").Base(err)
|
return errors.New("failed to create unexpected ip matcher").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func (s *FakeDNSServer) IsDisableCache() bool {
|
|||||||
|
|
||||||
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOption) ([]net.IP, uint32, error) {
|
||||||
if f.fakeDNSEngine == nil {
|
if f.fakeDNSEngine == nil {
|
||||||
return nil, 0, errors.New("Unable to locate a fake DNS Engine")
|
return nil, 0, errors.New("Unable to locate a fake DNS Engine").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
var ips []net.Address
|
var ips []net.Address
|
||||||
@@ -39,7 +39,7 @@ func (f *FakeDNSServer) QueryIP(ctx context.Context, domain string, opt dns.IPOp
|
|||||||
|
|
||||||
netIP, err := toNetIP(ips)
|
netIP, err := toNetIP(ips)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, errors.New("Unable to convert IP to net ip").Base(err)
|
return nil, 0, errors.New("Unable to convert IP to net ip").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
errors.LogInfo(ctx, f.Name(), " got answer: ", domain, " -> ", ips)
|
||||||
|
|||||||
+2
-6
@@ -89,10 +89,10 @@ func (g *Instance) startInternal() error {
|
|||||||
g.active = true
|
g.active = true
|
||||||
|
|
||||||
if err := g.initAccessLogger(); err != nil {
|
if err := g.initAccessLogger(); err != nil {
|
||||||
return errors.New("failed to initialize access logger").Base(err)
|
return errors.New("failed to initialize access logger").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
if err := g.initErrorLogger(); err != nil {
|
if err := g.initErrorLogger(); err != nil {
|
||||||
return errors.New("failed to initialize error logger").Base(err)
|
return errors.New("failed to initialize error logger").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -141,10 +141,6 @@ func (g *Instance) Handle(msg log.Message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Instance) Severity() log.Severity {
|
|
||||||
return g.config.ErrorLogLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close implements common.Closable.Close().
|
// Close implements common.Closable.Close().
|
||||||
func (g *Instance) Close() error {
|
func (g *Instance) Close() error {
|
||||||
errors.LogDebug(context.Background(), "Logger closing")
|
errors.LogDebug(context.Background(), "Logger closing")
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ func NewAlwaysOnInboundHandler(ctx context.Context, tag string, receiverConfig *
|
|||||||
}
|
}
|
||||||
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
mss, err := internet.ToMemoryStreamConfig(receiverConfig.StreamSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse stream config").Base(err)
|
return nil, errors.New("failed to parse stream config").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
newCtx := session.ContextWithInbound(ctx, &session.Inbound{Tag: tag, Source: src})
|
newCtx := session.ContextWithInbound(ctx, &session.Inbound{Tag: tag, Source: src})
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ func NewHandler(ctx context.Context, config *core.InboundHandlerConfig) (inbound
|
|||||||
|
|
||||||
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
|
receiverSettings, ok := rawReceiverSettings.(*proxyman.ReceiverConfig)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not a ReceiverConfig")
|
return nil, errors.New("not a ReceiverConfig").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
streamSettings := receiverSettings.StreamSettings
|
streamSettings := receiverSettings.StreamSettings
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ func (w *tcpWorker) Start() error {
|
|||||||
go w.callback(conn)
|
go w.callback(conn)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to listen TCP on ", w.port).Base(err)
|
return errors.New("failed to listen TCP on ", w.port).AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
w.hub = hub
|
w.hub = hub
|
||||||
return nil
|
return nil
|
||||||
@@ -528,7 +528,7 @@ func (w *dsWorker) Start() error {
|
|||||||
go w.callback(conn)
|
go w.callback(conn)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to listen Unix Domain Socket on ", w.address).Base(err)
|
return errors.New("failed to listen Unix Domain Socket on ", w.address).AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
w.hub = hub
|
w.hub = hub
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ func NewHandler(ctx context.Context, config *core.OutboundHandlerConfig) (outbou
|
|||||||
h.senderSettings = s
|
h.senderSettings = s
|
||||||
mss, err := internet.ToMemoryStreamConfig(s.StreamSettings)
|
mss, err := internet.ToMemoryStreamConfig(s.StreamSettings)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse stream settings").Base(err)
|
return nil, errors.New("failed to parse stream settings").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
h.streamSettings = mss
|
h.streamSettings = mss
|
||||||
default:
|
default:
|
||||||
@@ -217,7 +217,7 @@ func (h *Handler) Dispatch(ctx context.Context, link *transport.Link) {
|
|||||||
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
if ob.Target.Network == net.Network_UDP && ob.Target.Port == 443 {
|
||||||
switch h.udp443 {
|
switch h.udp443 {
|
||||||
case "reject":
|
case "reject":
|
||||||
test(errors.New("XUDP rejected UDP/443 traffic"))
|
test(errors.New("XUDP rejected UDP/443 traffic").AtInfo())
|
||||||
return
|
return
|
||||||
case "skip":
|
case "skip":
|
||||||
goto out
|
goto out
|
||||||
|
|||||||
@@ -68,13 +68,13 @@ func (p *Portal) HandleConnection(ctx context.Context, link *transport.Link) err
|
|||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
if ob == nil {
|
if ob == nil {
|
||||||
return errors.New("outbound metadata not found")
|
return errors.New("outbound metadata not found").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if isDomain(ob.Target, p.domain) {
|
if isDomain(ob.Target, p.domain) {
|
||||||
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create mux client worker").Base(err)
|
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
worker, err := NewPortalWorker(muxClient)
|
worker, err := NewPortalWorker(muxClient)
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ func (rr *RoutingRule) BuildCondition() (Condition, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if conds.Len() == 0 {
|
if conds.Len() == 0 {
|
||||||
return nil, errors.New("this rule has no effective fields")
|
return nil, errors.New("this rule has no effective fields").AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
return conds, nil
|
return conds, nil
|
||||||
@@ -145,7 +145,7 @@ func (br *BalancingRule) Build(ohm outbound.Manager, dispatcher routing.Dispatch
|
|||||||
}
|
}
|
||||||
s, ok := i.(*StrategyLeastLoadConfig)
|
s, ok := i.(*StrategyLeastLoadConfig)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("not a StrategyLeastLoadConfig")
|
return nil, errors.New("not a StrategyLeastLoadConfig").AtError()
|
||||||
}
|
}
|
||||||
leastLoadStrategy := NewLeastLoadStrategy(s)
|
leastLoadStrategy := NewLeastLoadStrategy(s)
|
||||||
return &Balancer{
|
return &Balancer{
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type windowsReader struct {
|
type windowsReader struct {
|
||||||
bufs []syscall.WSABuf
|
bufs []syscall.WSABuf
|
||||||
ready bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *windowsReader) Init(bs []*Buffer) {
|
func (r *windowsReader) Init(bs []*Buffer) {
|
||||||
@@ -16,7 +15,6 @@ func (r *windowsReader) Init(bs []*Buffer) {
|
|||||||
for _, b := range bs {
|
for _, b := range bs {
|
||||||
r.bufs = append(r.bufs, syscall.WSABuf{Len: uint32(Size), Buf: &b.v[0]})
|
r.bufs = append(r.bufs, syscall.WSABuf{Len: uint32(Size), Buf: &b.v[0]})
|
||||||
}
|
}
|
||||||
r.ready = false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *windowsReader) Clear() {
|
func (r *windowsReader) Clear() {
|
||||||
@@ -27,14 +25,6 @@ func (r *windowsReader) Clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *windowsReader) Read(fd uintptr) int32 {
|
func (r *windowsReader) Read(fd uintptr) int32 {
|
||||||
// On the first invocation, we return -1 to indicate "not ready"
|
|
||||||
// to make rawConn.Read wait for readability using the runtime's own mechanism
|
|
||||||
// because syscall.WSARecv() is a blocking call when used with nil OVERLAPPED
|
|
||||||
if !r.ready {
|
|
||||||
r.ready = true
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
var nBytes uint32
|
var nBytes uint32
|
||||||
var flags uint32
|
var flags uint32
|
||||||
err := syscall.WSARecv(syscall.Handle(fd), &r.bufs[0], uint32(len(r.bufs)), &nBytes, &flags, nil, nil)
|
err := syscall.WSARecv(syscall.Handle(fd), &r.bufs[0], uint32(len(r.bufs)), &nBytes, &flags, nil, nil)
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ import (
|
|||||||
|
|
||||||
// [,)
|
// [,)
|
||||||
func RandBetween(from int64, to int64) int64 {
|
func RandBetween(from int64, to int64) int64 {
|
||||||
|
if from == to {
|
||||||
|
return from
|
||||||
|
}
|
||||||
if from > to {
|
if from > to {
|
||||||
from, to = to, from
|
from, to = to, from
|
||||||
}
|
}
|
||||||
if d := to - from; d == 0 || d == 1 {
|
|
||||||
return from
|
|
||||||
}
|
|
||||||
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
|
||||||
return from + bigInt.Int64()
|
return from + bigInt.Int64()
|
||||||
}
|
}
|
||||||
|
|||||||
+65
-13
@@ -18,12 +18,17 @@ type hasInnerError interface {
|
|||||||
Unwrap() error
|
Unwrap() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type hasSeverity interface {
|
||||||
|
Severity() log.Severity
|
||||||
|
}
|
||||||
|
|
||||||
// Error is an error object with underlying error.
|
// Error is an error object with underlying error.
|
||||||
type Error struct {
|
type Error struct {
|
||||||
prefix []interface{}
|
prefix []interface{}
|
||||||
message []interface{}
|
message []interface{}
|
||||||
caller string
|
caller string
|
||||||
inner error
|
inner error
|
||||||
|
severity log.Severity
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error implements error.Error().
|
// Error implements error.Error().
|
||||||
@@ -64,6 +69,46 @@ func (err *Error) Base(e error) *Error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (err *Error) atSeverity(s log.Severity) *Error {
|
||||||
|
err.severity = s
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err *Error) Severity() log.Severity {
|
||||||
|
if err.inner == nil {
|
||||||
|
return err.severity
|
||||||
|
}
|
||||||
|
|
||||||
|
if s, ok := err.inner.(hasSeverity); ok {
|
||||||
|
as := s.Severity()
|
||||||
|
if as < err.severity {
|
||||||
|
return as
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err.severity
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtDebug sets the severity to debug.
|
||||||
|
func (err *Error) AtDebug() *Error {
|
||||||
|
return err.atSeverity(log.Severity_Debug)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtInfo sets the severity to info.
|
||||||
|
func (err *Error) AtInfo() *Error {
|
||||||
|
return err.atSeverity(log.Severity_Info)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtWarning sets the severity to warning.
|
||||||
|
func (err *Error) AtWarning() *Error {
|
||||||
|
return err.atSeverity(log.Severity_Warning)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AtError sets the severity to error.
|
||||||
|
func (err *Error) AtError() *Error {
|
||||||
|
return err.atSeverity(log.Severity_Error)
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the string representation of this error.
|
// String returns the string representation of this error.
|
||||||
func (err *Error) String() string {
|
func (err *Error) String() string {
|
||||||
return err.Error()
|
return err.Error()
|
||||||
@@ -87,8 +132,9 @@ func New(msg ...interface{}) *Error {
|
|||||||
details = details[:i]
|
details = details[:i]
|
||||||
}
|
}
|
||||||
return &Error{
|
return &Error{
|
||||||
message: msg,
|
message: msg,
|
||||||
caller: details,
|
severity: log.Severity_Info,
|
||||||
|
caller: details,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,9 +171,6 @@ func LogErrorInner(ctx context.Context, inner error, msg ...interface{}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func doLog(ctx context.Context, inner error, severity log.Severity, msg ...interface{}) {
|
func doLog(ctx context.Context, inner error, severity log.Severity, msg ...interface{}) {
|
||||||
if log.GetSeverity() < severity {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pc, _, _, _ := runtime.Caller(2)
|
pc, _, _, _ := runtime.Caller(2)
|
||||||
details := runtime.FuncForPC(pc).Name()
|
details := runtime.FuncForPC(pc).Name()
|
||||||
if len(details) >= trim {
|
if len(details) >= trim {
|
||||||
@@ -138,9 +181,10 @@ func doLog(ctx context.Context, inner error, severity log.Severity, msg ...inter
|
|||||||
details = details[:i]
|
details = details[:i]
|
||||||
}
|
}
|
||||||
err := &Error{
|
err := &Error{
|
||||||
message: msg,
|
message: msg,
|
||||||
caller: details,
|
severity: severity,
|
||||||
inner: inner,
|
caller: details,
|
||||||
|
inner: inner,
|
||||||
}
|
}
|
||||||
if ctx != nil && ctx != context.Background() {
|
if ctx != nil && ctx != context.Background() {
|
||||||
id := uint32(c.IDFromContext(ctx))
|
id := uint32(c.IDFromContext(ctx))
|
||||||
@@ -149,7 +193,7 @@ func doLog(ctx context.Context, inner error, severity log.Severity, msg ...inter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Record(&log.GeneralMessage{
|
log.Record(&log.GeneralMessage{
|
||||||
Severity: severity,
|
Severity: GetSeverity(err),
|
||||||
Content: err,
|
Content: err,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -173,3 +217,11 @@ L:
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSeverity returns the actual severity of the error, including inner errors.
|
||||||
|
func GetSeverity(err error) log.Severity {
|
||||||
|
if s, ok := err.(hasSeverity); ok {
|
||||||
|
return s.Severity()
|
||||||
|
}
|
||||||
|
return log.Severity_Info
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,21 +7,30 @@ import (
|
|||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
. "github.com/xtls/xray-core/common/errors"
|
. "github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/common/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestError(t *testing.T) {
|
func TestError(t *testing.T) {
|
||||||
err := New("TestError")
|
err := New("TestError")
|
||||||
if v := err.Error(); !strings.Contains(v, "TestError") {
|
if v := GetSeverity(err); v != log.Severity_Info {
|
||||||
t.Error("error: ", v)
|
t.Error("severity: ", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = New("TestError2").Base(io.EOF)
|
err = New("TestError2").Base(io.EOF)
|
||||||
if v := err.Error(); !strings.Contains(v, "EOF") {
|
if v := GetSeverity(err); v != log.Severity_Info {
|
||||||
t.Error("error: ", v)
|
t.Error("severity: ", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = New("TestError3").Base(io.EOF)
|
err = New("TestError3").Base(io.EOF).AtWarning()
|
||||||
err = New("TestError4").Base(err)
|
if v := GetSeverity(err); v != log.Severity_Warning {
|
||||||
|
t.Error("severity: ", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = New("TestError4").Base(io.EOF).AtWarning()
|
||||||
|
err = New("TestError5").Base(err)
|
||||||
|
if v := GetSeverity(err); v != log.Severity_Warning {
|
||||||
|
t.Error("severity: ", v)
|
||||||
|
}
|
||||||
if v := err.Error(); !strings.Contains(v, "EOF") {
|
if v := err.Error(); !strings.Contains(v, "EOF") {
|
||||||
t.Error("error: ", v)
|
t.Error("error: ", v)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package strmatcher_test
|
package strmatcher_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"regexp"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@@ -73,64 +72,6 @@ func BenchmarkSubstrMatcher(b *testing.B) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func BenchmarkRegexMatcher(b *testing.B) {
|
|
||||||
patterns := []string{ // taken from geosite
|
|
||||||
`(^|\.)91porn\.(best|com|cool|fun|group|party|plus|site|tw|work)$`,
|
|
||||||
`(^|\.)91porn[0-9]{3}\.me$`,
|
|
||||||
`(^|\.)apiproxy-device-prod-nlb-.+\.amazonaws\.com$`,
|
|
||||||
`(^|\.)dualstack\.apiproxy-.+\.amazonaws\.com$`,
|
|
||||||
`(^|\.)aqdk[0-9]{3}\.com$`,
|
|
||||||
`(^|\.)bilibili3(0[1-9]|1[0-2])\.xyz$`,
|
|
||||||
`(^|\.)byyum([3589]|2[235689]|3[34]|4[1-9]|5[1-79]|6[0134679])?\.com$`,
|
|
||||||
`(^|\.)fiftymvapi\..+$`,
|
|
||||||
`(^|\.)gossipfuli[0-9]{3,4}\.xyz$`,
|
|
||||||
`(^|\.)kpkuang\.(bond|fun|info|one|us)$`,
|
|
||||||
`(^|\.)rule34\.(asia|us|world|xxx|xyz)$`,
|
|
||||||
`(^|\.)[a-z][1-9][0-9][a-z]\.com$`,
|
|
||||||
`.+\.awsdns-[0-9][0-9]\.(co\.uk|com|net|org)$`,
|
|
||||||
`.+\.dkr\.ecr\.[^\.]+\.amazonaws\.com$`,
|
|
||||||
`^(.+\.)*zh\.okaapps\.com$`,
|
|
||||||
`^cdn\d-epicgames-\d+\.file\.myqcloud\.com$`,
|
|
||||||
`^chatgpt-async-webps-prod-\S+-\d+\.webpubsub\.azure\.com$`,
|
|
||||||
`^r+[0-9]+(---|\.)sn-(2x3|ni5|j5o)\w{5}\.googlevideo\.com$`,
|
|
||||||
`^speed\.(coe|open)\.ad\.[a-z]{2,6}\.prod\.hosts\.ooklaserver\.net$`,
|
|
||||||
`javdb\d+\.com$`,
|
|
||||||
}
|
|
||||||
domains := []string{
|
|
||||||
"www.google.com", "rr3---sn-4g5edndy.googlevideo.com", "r1---sn-2x3abcde.googlevideo.com", "i.ytimg.com",
|
|
||||||
"graph.facebook.com", "api.twitter.com", "www.baidu.com", "github.com", "objects.githubusercontent.com",
|
|
||||||
"login.microsoftonline.com", "e1234.dscb.akamaiedge.net", "d1a2b3c4d5e6f7.cloudfront.net",
|
|
||||||
"s3.us-east-1.amazonaws.com", "123456789012.dkr.ecr.us-east-1.amazonaws.com", "www.wikipedia.org",
|
|
||||||
"discord.com", "telegram.org", "store.steampowered.com", "www.91porn.com", "ns-1234.awsdns-12.org",
|
|
||||||
}
|
|
||||||
bench := func(b *testing.B, ctor func(pattern string) func(string) bool) {
|
|
||||||
var matchers []func(string) bool
|
|
||||||
for _, p := range patterns {
|
|
||||||
matchers = append(matchers, ctor(p))
|
|
||||||
}
|
|
||||||
b.ResetTimer()
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
for _, d := range domains {
|
|
||||||
for _, match := range matchers {
|
|
||||||
_ = match(d)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b.Run("regexp", func(b *testing.B) {
|
|
||||||
bench(b, func(pattern string) func(string) bool {
|
|
||||||
return regexp.MustCompile(pattern).MatchString
|
|
||||||
})
|
|
||||||
})
|
|
||||||
b.Run("prefilter", func(b *testing.B) {
|
|
||||||
bench(b, func(pattern string) func(string) bool {
|
|
||||||
m, err := Regex.New(pattern)
|
|
||||||
common.Must(err)
|
|
||||||
return m.Match
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility functions for benchmark
|
// Utility functions for benchmark
|
||||||
|
|
||||||
func benchmarkMatcherType(b *testing.B, t Type, ctor func() MatcherGroup) {
|
func benchmarkMatcherType(b *testing.B, t Type, ctor func() MatcherGroup) {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package strmatcher
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
"regexp/syntax"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
@@ -74,43 +73,7 @@ func (m SubstrMatcher) Match(s string) bool {
|
|||||||
|
|
||||||
// RegexMatcher is an implementation of Matcher.
|
// RegexMatcher is an implementation of Matcher.
|
||||||
type RegexMatcher struct {
|
type RegexMatcher struct {
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
literals []string // every match contains all of them, longest first
|
|
||||||
}
|
|
||||||
|
|
||||||
func newRegexMatcher(pattern string) (Matcher, error) {
|
|
||||||
regex, err := regexp.Compile(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
m := &RegexMatcher{pattern: regex}
|
|
||||||
if re, err := syntax.Parse(pattern, syntax.Perl); err == nil { // same flags as regexp.Compile
|
|
||||||
m.literals = requiredLiterals(re, nil)
|
|
||||||
slices.SortStableFunc(m.literals, func(a, b string) int { return len(b) - len(a) })
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// requiredLiterals appends to dst the case-sensitive strings that every match of re contains.
|
|
||||||
func requiredLiterals(re *syntax.Regexp, dst []string) []string {
|
|
||||||
switch re.Op {
|
|
||||||
case syntax.OpLiteral:
|
|
||||||
// regexp matches U+FFFD against invalid UTF-8 bytes, strings.Contains does not
|
|
||||||
if re.Flags&syntax.FoldCase == 0 && !slices.Contains(re.Rune, utf8.RuneError) {
|
|
||||||
dst = append(dst, string(re.Rune))
|
|
||||||
}
|
|
||||||
case syntax.OpCapture, syntax.OpPlus:
|
|
||||||
dst = requiredLiterals(re.Sub[0], dst)
|
|
||||||
case syntax.OpRepeat:
|
|
||||||
if re.Min > 0 {
|
|
||||||
dst = requiredLiterals(re.Sub[0], dst)
|
|
||||||
}
|
|
||||||
case syntax.OpConcat:
|
|
||||||
for _, sub := range re.Sub {
|
|
||||||
dst = requiredLiterals(sub, dst)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dst
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*RegexMatcher) Type() Type {
|
func (*RegexMatcher) Type() Type {
|
||||||
@@ -126,11 +89,6 @@ func (m *RegexMatcher) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *RegexMatcher) Match(s string) bool {
|
func (m *RegexMatcher) Match(s string) bool {
|
||||||
for _, l := range m.literals {
|
|
||||||
if !strings.Contains(s, l) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m.pattern.MatchString(s)
|
return m.pattern.MatchString(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,7 +102,11 @@ func (t Type) New(pattern string) (Matcher, error) {
|
|||||||
case Domain:
|
case Domain:
|
||||||
return DomainMatcher(pattern), nil
|
return DomainMatcher(pattern), nil
|
||||||
case Regex: // 1. regex matching is case-sensitive
|
case Regex: // 1. regex matching is case-sensitive
|
||||||
return newRegexMatcher(pattern)
|
regex, err := regexp.Compile(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RegexMatcher{pattern: regex}, nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unknown matcher type")
|
return nil, errors.New("unknown matcher type")
|
||||||
}
|
}
|
||||||
@@ -173,7 +135,11 @@ func (t Type) NewDomainPattern(pattern string) (Matcher, error) {
|
|||||||
}
|
}
|
||||||
return DomainMatcher(pattern), nil
|
return DomainMatcher(pattern), nil
|
||||||
case Regex: // Regex's charset not in LDH subset
|
case Regex: // Regex's charset not in LDH subset
|
||||||
return newRegexMatcher(pattern)
|
regex, err := regexp.Compile(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &RegexMatcher{pattern: regex}, nil
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unknown matcher type")
|
return nil, errors.New("unknown matcher type")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
package strmatcher
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"slices"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
var regexLiteralCases = []struct {
|
|
||||||
pattern string
|
|
||||||
literals []string
|
|
||||||
}{
|
|
||||||
{`(^|\.)91porn\.(best|com)$`, []string{"91porn."}},
|
|
||||||
{`.+\.awsdns-cn-[0-9][0-9]\.(biz|com|net|top)$`, []string{".awsdns-cn-", "."}},
|
|
||||||
{`^r+[0-9]+(---|\.)sn-(2x3|ni5|j5o)\w{5}\.googlevideo\.com$`, []string{".googlevideo.com", "sn-", "r"}},
|
|
||||||
{`(?i)abc`, nil},
|
|
||||||
{`ab(?i:CD)ef`, []string{"ab", "ef"}},
|
|
||||||
{`(abc)?x`, []string{"x"}},
|
|
||||||
{`(abc)*x`, []string{"x"}},
|
|
||||||
{`x{0,3}yy`, []string{"yy"}},
|
|
||||||
{`(ab)+c{2}`, []string{"ab", "c"}},
|
|
||||||
{`abc|abd`, []string{"ab"}},
|
|
||||||
{`\Qa.b\E`, []string{"a.b"}},
|
|
||||||
{`a\x{FFFD}b`, nil},
|
|
||||||
{`^[^.]+$`, nil},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRegexRequiredLiterals(t *testing.T) {
|
|
||||||
for _, test := range regexLiteralCases {
|
|
||||||
m, err := newRegexMatcher(test.pattern)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if got := m.(*RegexMatcher).literals; !slices.Equal(got, test.literals) {
|
|
||||||
t.Errorf("%s: got %q, want %q", test.pattern, got, test.literals)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func FuzzRegexMatcher(f *testing.F) {
|
|
||||||
inputs := []string{
|
|
||||||
"", "x", "yy", "abd", "ccc", "ABC", "abCDef", "abcdef", "abababcc", "a.b", "a\xffb", "a\uFFFDb",
|
|
||||||
"www.91porn.com", "ns1.awsdns-cn-01.top", "r1---sn-2x3abcde.googlevideo.com",
|
|
||||||
}
|
|
||||||
for _, test := range regexLiteralCases {
|
|
||||||
for _, s := range inputs {
|
|
||||||
f.Add(test.pattern, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Fuzz(func(t *testing.T, pattern, s string) {
|
|
||||||
re, err := regexp.Compile(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
m, _ := newRegexMatcher(pattern)
|
|
||||||
if got, want := m.Match(s), re.MatchString(s); got != want {
|
|
||||||
t.Errorf("pattern %q, input %q: got %v, want %v", pattern, s, got, want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
+25
-21
@@ -1,7 +1,7 @@
|
|||||||
package log // import "github.com/xtls/xray-core/common/log"
|
package log // import "github.com/xtls/xray-core/common/log"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync/atomic"
|
"sync"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
)
|
)
|
||||||
@@ -29,32 +29,36 @@ func (m *GeneralMessage) String() string {
|
|||||||
|
|
||||||
// Record writes a message into log stream.
|
// Record writes a message into log stream.
|
||||||
func Record(msg Message) {
|
func Record(msg Message) {
|
||||||
if h := logHandler.Load(); h != nil {
|
logHandler.Handle(msg)
|
||||||
(*h).Handle(msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SeverityLogger interface {
|
var logHandler syncHandler
|
||||||
Handler
|
|
||||||
Severity() Severity
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetSeverity() Severity {
|
|
||||||
if h := logHandler.Load(); h != nil {
|
|
||||||
if sh, ok := (*h).(SeverityLogger); ok {
|
|
||||||
return sh.Severity()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// log everything by default
|
|
||||||
return Severity_Debug
|
|
||||||
}
|
|
||||||
|
|
||||||
var logHandler atomic.Pointer[Handler]
|
|
||||||
|
|
||||||
// RegisterHandler registers a new handler as current log handler. Previous registered handler will be discarded.
|
// RegisterHandler registers a new handler as current log handler. Previous registered handler will be discarded.
|
||||||
func RegisterHandler(handler Handler) {
|
func RegisterHandler(handler Handler) {
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
panic("Log handler is nil")
|
panic("Log handler is nil")
|
||||||
}
|
}
|
||||||
logHandler.Store(&handler)
|
logHandler.Set(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
type syncHandler struct {
|
||||||
|
sync.RWMutex
|
||||||
|
Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *syncHandler) Handle(msg Message) {
|
||||||
|
h.RLock()
|
||||||
|
defer h.RUnlock()
|
||||||
|
|
||||||
|
if h.Handler != nil {
|
||||||
|
h.Handler.Handle(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *syncHandler) Set(handler Handler) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
|
h.Handler = handler
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,10 +68,6 @@ func (l *serverityLogger) Handle(msg Message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *serverityLogger) Severity() Severity {
|
|
||||||
return l.logLevel
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *generalLogger) run() {
|
func (l *generalLogger) run() {
|
||||||
defer l.access.Signal()
|
defer l.access.Signal()
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func (m *ClientManager) Dispatch(ctx context.Context, link *transport.Link) erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New("unable to find an available mux client")
|
return errors.New("unable to find an available mux client").AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkerPicker interface {
|
type WorkerPicker interface {
|
||||||
|
|||||||
+1
-1
@@ -117,7 +117,7 @@ func (f *FrameMetadata) Unmarshal(reader io.Reader, readSourceAndLocal bool) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if metaLen > 512 {
|
if metaLen > 512 {
|
||||||
return errors.New("invalid metalen ", metaLen)
|
return errors.New("invalid metalen ", metaLen).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
b := buf.New()
|
b := buf.New()
|
||||||
|
|||||||
@@ -351,7 +351,7 @@ func (w *ServerWorker) handleFrame(ctx context.Context, reader *buf.BufferedRead
|
|||||||
err = w.handleStatusKeep(&meta, reader)
|
err = w.handleStatusKeep(&meta, reader)
|
||||||
default:
|
default:
|
||||||
status := meta.SessionStatus
|
status := meta.SessionStatus
|
||||||
return errors.New("unknown status: ", status)
|
return errors.New("unknown status: ", status).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
|
|
||||||
func (u *User) GetTypedAccount() (Account, error) {
|
func (u *User) GetTypedAccount() (Account, error) {
|
||||||
if u.GetAccount() == nil {
|
if u.GetAccount() == nil {
|
||||||
return nil, errors.New("Account is missing")
|
return nil, errors.New("Account is missing").AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
rawAccount, err := u.Account.GetInstance()
|
rawAccount, err := u.Account.GetInstance()
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@ var typeCreatorRegistry = make(map[reflect.Type]ConfigCreator)
|
|||||||
func RegisterConfig(config interface{}, configCreator ConfigCreator) error {
|
func RegisterConfig(config interface{}, configCreator ConfigCreator) error {
|
||||||
configType := reflect.TypeOf(config)
|
configType := reflect.TypeOf(config)
|
||||||
if _, found := typeCreatorRegistry[configType]; found {
|
if _, found := typeCreatorRegistry[configType]; found {
|
||||||
return errors.New(configType.Name() + " is already registered")
|
return errors.New(configType.Name() + " is already registered").AtError()
|
||||||
}
|
}
|
||||||
typeCreatorRegistry[configType] = configCreator
|
typeCreatorRegistry[configType] = configCreator
|
||||||
return nil
|
return nil
|
||||||
@@ -27,7 +27,7 @@ func CreateObject(ctx context.Context, config interface{}) (interface{}, error)
|
|||||||
configType := reflect.TypeOf(config)
|
configType := reflect.TypeOf(config)
|
||||||
creator, found := typeCreatorRegistry[configType]
|
creator, found := typeCreatorRegistry[configType]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, errors.New(configType.String() + " is not registered")
|
return nil, errors.New(configType.String() + " is not registered").AtError()
|
||||||
}
|
}
|
||||||
return creator(ctx, config)
|
return creator(ctx, config)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -125,7 +125,7 @@ func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f == "" {
|
if f == "" {
|
||||||
return nil, errors.New("Failed to get format of ", file)
|
return nil, errors.New("Failed to get format of ", file).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if f == "protobuf" {
|
if f == "protobuf" {
|
||||||
@@ -142,7 +142,7 @@ func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
|||||||
if len(v) == 1 {
|
if len(v) == 1 {
|
||||||
return configLoaderByName["protobuf"].Loader(v)
|
return configLoaderByName["protobuf"].Loader(v)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Only one protobuf config file is allowed")
|
return nil, errors.New("Only one protobuf config file is allowed").AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,11 +152,11 @@ func LoadConfig(formatName string, input interface{}) (*Config, error) {
|
|||||||
if f, found := configLoaderByName[formatName]; found {
|
if f, found := configLoaderByName[formatName]; found {
|
||||||
return f.Loader(v)
|
return f.Loader(v)
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("Unable to load config in", formatName)
|
return nil, errors.New("Unable to load config in", formatName).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("Unable to load config")
|
return nil, errors.New("Unable to load config").AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadProtobufConfig(data []byte) (*Config, error) {
|
func loadProtobufConfig(data []byte) (*Config, error) {
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
Version_x byte = 26
|
Version_x byte = 26
|
||||||
Version_y byte = 9
|
Version_y byte = 9
|
||||||
Version_z byte = 9
|
Version_z byte = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type FakeDNSEngine interface {
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
FakeIPv4Pool = "198.18.0.0/15"
|
FakeIPv4Pool = "198.18.0.0/15"
|
||||||
FakeIPv6Pool = "2001:2::/48"
|
FakeIPv6Pool = "fc00::/18"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FakeDNSEngineRev0 interface {
|
type FakeDNSEngineRev0 interface {
|
||||||
|
|||||||
@@ -24,20 +24,19 @@ require (
|
|||||||
github.com/vishvananda/netlink v1.3.1
|
github.com/vishvananda/netlink v1.3.1
|
||||||
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0
|
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0
|
||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba
|
||||||
golang.org/x/crypto v0.57.0
|
golang.org/x/crypto v0.55.0
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
|
||||||
golang.org/x/net v0.59.0
|
golang.org/x/net v0.58.0
|
||||||
golang.org/x/sync v0.23.0
|
golang.org/x/sync v0.22.0
|
||||||
golang.org/x/sys v0.48.0
|
golang.org/x/sys v0.47.0
|
||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||||
golang.zx2c4.com/wireguard/windows v1.1.1
|
golang.zx2c4.com/wireguard/windows v1.0.1
|
||||||
google.golang.org/grpc v1.84.0
|
google.golang.org/grpc v1.83.2
|
||||||
google.golang.org/protobuf v1.36.12
|
google.golang.org/protobuf v1.36.12
|
||||||
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
gvisor.dev/gvisor v0.0.0-20260122175437-89a5d21be8f0
|
||||||
h12.io/socks v1.0.3
|
h12.io/socks v1.0.3
|
||||||
lukechampine.com/blake3 v1.4.1
|
lukechampine.com/blake3 v1.4.1
|
||||||
mvdan.cc/gofumpt v0.12.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -49,6 +48,7 @@ require (
|
|||||||
github.com/juju/ratelimit v1.0.2 // indirect
|
github.com/juju/ratelimit v1.0.2 // indirect
|
||||||
github.com/klauspost/compress v1.17.4 // indirect
|
github.com/klauspost/compress v1.17.4 // indirect
|
||||||
github.com/koron/go-ssdp v0.0.4 // indirect
|
github.com/koron/go-ssdp v0.0.4 // indirect
|
||||||
|
github.com/kr/text v0.2.0 // indirect
|
||||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||||
github.com/pion/dtls/v3 v3.1.5 // indirect
|
github.com/pion/dtls/v3 v3.1.5 // indirect
|
||||||
github.com/pion/logging v0.2.4 // indirect
|
github.com/pion/logging v0.2.4 // indirect
|
||||||
@@ -57,9 +57,8 @@ require (
|
|||||||
github.com/vishvananda/netns v0.0.5 // indirect
|
github.com/vishvananda/netns v0.0.5 // indirect
|
||||||
github.com/wlynxg/anet v0.0.5 // indirect
|
github.com/wlynxg/anet v0.0.5 // indirect
|
||||||
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
go.yaml.in/yaml/v3 v3.0.5 // indirect
|
||||||
golang.org/x/text v0.42.0 // indirect
|
golang.org/x/text v0.41.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.49.0 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sx
|
|||||||
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e h1:5mgtR5gwIgBKMiGI1QdXldZZ+SNor06Nbu1wCBulQBg=
|
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e h1:5mgtR5gwIgBKMiGI1QdXldZZ+SNor06Nbu1wCBulQBg=
|
||||||
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e/go.mod h1:x7qxEvX6MCVtDuBKHj3E+88+BtrbEMuAL5qGUKItjW8=
|
github.com/apernet/quic-go v0.61.1-0.20260806010916-184d081eef3e/go.mod h1:x7qxEvX6MCVtDuBKHj3E+88+BtrbEMuAL5qGUKItjW8=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cloudflare/circl v1.6.5 h1:O64F26HEqNhznd/hrC5KZXVKYuKM2rx4deZDTc4ihQA=
|
github.com/cloudflare/circl v1.6.5 h1:O64F26HEqNhznd/hrC5KZXVKYuKM2rx4deZDTc4ihQA=
|
||||||
github.com/cloudflare/circl v1.6.5/go.mod h1:h5LNyxAc5nTue9DS5jT+48en2PSDYt3zdGnz5OstK6c=
|
github.com/cloudflare/circl v1.6.5/go.mod h1:h5LNyxAc5nTue9DS5jT+48en2PSDYt3zdGnz5OstK6c=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344 h1:Arcl6UOIS/kgO2nW3A65HN+7CMjSDP/gofXL4CZt1V4=
|
||||||
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
github.com/ghodss/yaml v1.0.1-0.20220118164431-d8423dcdf344/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I=
|
||||||
github.com/go-quicktest/qt v1.102.0 h1:HSQxCeh5YZH3EL3W39ixjtyaEhcWSXQHtHnMBzSs474=
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
github.com/go-quicktest/qt v1.102.0/go.mod h1:p4lGIVX+8Wa6ZPNDvqcxq36XpUDLh42FLetFU7odllI=
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
github.com/golang/mock v1.7.0-rc.1 h1:YojYx61/OLFsiv6Rw1Z96LpldJIy31o+UHmwAUMJ6/U=
|
||||||
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
github.com/golang/mock v1.7.0-rc.1/go.mod h1:s42URUywIqd+OcERslBJvOjepvNymP31m3q8d/GkuRs=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
@@ -68,8 +73,8 @@ github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af h1:er
|
|||||||
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
github.com/refraction-networking/utls v1.8.3-0.20260301010127-aa6edf4b11af/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM=
|
||||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||||
github.com/rogpeppe/go-internal v1.16.0 h1:O9DK+vNMDVGLr2BeZqmpLeMjiMNkuXfcqntWbZV6S5g=
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/rogpeppe/go-internal v1.16.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs=
|
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||||
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
github.com/sagernet/sing v0.5.1 h1:mhL/MZVq0TjuvHcpYcFtmSD1BFOxZ/+8ofbNZcg1k1Y=
|
||||||
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
github.com/sagernet/sing v0.5.1/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
|
||||||
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8=
|
||||||
@@ -85,6 +90,18 @@ github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguH
|
|||||||
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0 h1:rb+fKQFhz+5I2PPuQsNYxI5mUU840XWYtRF0ZBjvkws=
|
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0 h1:rb+fKQFhz+5I2PPuQsNYxI5mUU840XWYtRF0ZBjvkws=
|
||||||
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
|
github.com/xtls/reality v0.0.0-20260908062103-8cdf7bf9c7f0/go.mod h1:DsJblcWDGt76+FVqBVwbwRhxyyNJsGV48gJLch0OOWI=
|
||||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||||
|
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||||
|
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||||
|
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||||
|
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||||
|
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||||
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
|
||||||
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
|
||||||
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
|
||||||
@@ -93,8 +110,8 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs
|
|||||||
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M=
|
golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M=
|
||||||
golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA=
|
golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
|
||||||
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||||
@@ -103,12 +120,12 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
|||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues=
|
golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To=
|
||||||
golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg=
|
golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
|
golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek=
|
||||||
golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
|
golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -116,22 +133,20 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI=
|
golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8=
|
||||||
golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E=
|
golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M=
|
||||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||||
golang.org/x/tools v0.49.0 h1:3NI7VXzL9+1WZD52Dx2ttoPwD5DWrFGpl9mFZDlmisI=
|
|
||||||
golang.org/x/tools v0.49.0/go.mod h1:SJNXV9DBKT0UbdttsQjbfJlAE/q+y36++zo3uL3N0Oo=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -139,14 +154,14 @@ golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 h1:B82qJJgjvYKsXS9jeu
|
|||||||
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+ZbWg+4sHnLp52d5yiIPUxMBSt4X9A=
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb h1:whnFRlWMcXI9d+ZbWg+4sHnLp52d5yiIPUxMBSt4X9A=
|
||||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
|
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb/go.mod h1:rpwXGsirqLqN2L0JDJQlwOboGHmptD5ZD6T2VmcqhTw=
|
||||||
golang.zx2c4.com/wireguard/windows v1.1.1 h1:8/H97U1v1PNDNcBsMZgU3KFuND9MQdTsU2NOwmCXArE=
|
golang.zx2c4.com/wireguard/windows v1.0.1 h1:eOxiDVbywPC+ZQqvdCK7x+ZwWXKbYv50TtH8ysFIbw8=
|
||||||
golang.zx2c4.com/wireguard/windows v1.1.1/go.mod h1:+fbT3FFdX4zzYDLwJh5+HPEcNN/3HyNdzhNSVsQM+zs=
|
golang.zx2c4.com/wireguard/windows v1.0.1/go.mod h1:+fbT3FFdX4zzYDLwJh5+HPEcNN/3HyNdzhNSVsQM+zs=
|
||||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800 h1:qEHAMpSaUhtD0p3NbEEI83HwNGFxEwaSJ1G9PLnCBZE=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260706201446-f0a921348800/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0=
|
google.golang.org/grpc v1.83.2 h1:EManeRomTObA0BU7I8vXgg/78uE5MJ9M8B39EX2WscU=
|
||||||
google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0=
|
google.golang.org/grpc v1.83.2/go.mod h1:YPI1hK3kDked6iHvgX3tR0y+nX/qpMFKhPgFsokw1S8=
|
||||||
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
|
||||||
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -161,5 +176,3 @@ h12.io/socks v1.0.3 h1:Ka3qaQewws4j4/eDQnOdpr4wXsC//dXtWvftlIcCQUo=
|
|||||||
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
h12.io/socks v1.0.3/go.mod h1:AIhxy1jOId/XCz9BO+EIgNL2rQiPTBNnOfnVnQ+3Eck=
|
||||||
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg=
|
||||||
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo=
|
||||||
mvdan.cc/gofumpt v0.12.0 h1:1Lbudkz2kpM9Cjz2pL4M19u7q+GaEhCTNf7N9mfpcho=
|
|
||||||
mvdan.cc/gofumpt v0.12.0/go.mod h1:SmBHHrljiZu/uoypeKup3rFzP6eoC9UwCp2iH5E3jZA=
|
|
||||||
|
|||||||
+2
-2
@@ -97,7 +97,7 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
|||||||
user.Email = v.Email
|
user.Email = v.Email
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||||
return nil, errors.New("failed to parse HTTP user").Base(err)
|
return nil, errors.New("failed to parse HTTP user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account := new(HTTPAccount)
|
account := new(HTTPAccount)
|
||||||
@@ -106,7 +106,7 @@ func (v *HTTPClientConfig) Build() (proto.Message, error) {
|
|||||||
account.Password = v.Password
|
account.Password = v.Password
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New("failed to parse HTTP account").Base(err)
|
return nil, errors.New("failed to parse HTTP account").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ func RegisterConfigureFilePostProcessingStage(name string, stage ConfigureFilePo
|
|||||||
func PostProcessConfigureFile(conf *Config) error {
|
func PostProcessConfigureFile(conf *Config) error {
|
||||||
for k, v := range configureFilePostProcessingStages {
|
for k, v := range configureFilePostProcessingStages {
|
||||||
if err := v.Process(conf); err != nil {
|
if err := v.Process(conf); err != nil {
|
||||||
return errors.New("Rejected by Postprocessing Stage ", k).Base(err)
|
return errors.New("Rejected by Postprocessing Stage ", k).AtError().Base(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type ConfigCreatorCache map[string]ConfigCreator
|
|||||||
|
|
||||||
func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
|
func (v ConfigCreatorCache) RegisterCreator(id string, creator ConfigCreator) error {
|
||||||
if _, found := v[id]; found {
|
if _, found := v[id]; found {
|
||||||
return errors.New(id, " already registered.")
|
return errors.New(id, " already registered.").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
v[id] = creator
|
v[id] = creator
|
||||||
@@ -61,7 +61,7 @@ func (v *JSONConfigLoader) Load(raw []byte) (interface{}, string, error) {
|
|||||||
}
|
}
|
||||||
rawID, found := obj[v.idKey]
|
rawID, found := obj[v.idKey]
|
||||||
if !found {
|
if !found {
|
||||||
return nil, "", errors.New(v.idKey, " not found in JSON context")
|
return nil, "", errors.New(v.idKey, " not found in JSON context").AtError()
|
||||||
}
|
}
|
||||||
var id string
|
var id string
|
||||||
if err := json.Unmarshal(rawID, &id); err != nil {
|
if err := json.Unmarshal(rawID, &id); err != nil {
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
package conf
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/netip"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
|
||||||
"github.com/xtls/xray-core/proxy/masque"
|
|
||||||
"google.golang.org/protobuf/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MasqueClientConfig struct {
|
|
||||||
Address *Address `json:"address"`
|
|
||||||
Port uint16 `json:"port"`
|
|
||||||
RemoteDNS []string `json:"remoteDNS"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MasqueClientConfig) Build() (proto.Message, error) {
|
|
||||||
if c.Address == nil {
|
|
||||||
return nil, errors.New(`MASQUE: "address" is not set`)
|
|
||||||
}
|
|
||||||
if c.Port == 0 {
|
|
||||||
return nil, errors.New(`MASQUE: "port" is not set`)
|
|
||||||
}
|
|
||||||
for _, s := range c.RemoteDNS {
|
|
||||||
if _, err := netip.ParseAddr(s); err != nil {
|
|
||||||
return nil, errors.New(`MASQUE: invalid "remoteDNS" `, s).Base(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &masque.ClientConfig{
|
|
||||||
Server: &protocol.ServerEndpoint{
|
|
||||||
Address: c.Address.Build(),
|
|
||||||
Port: uint32(c.Port),
|
|
||||||
},
|
|
||||||
RemoteDns: c.RemoteDNS,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
package conf_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
. "github.com/xtls/xray-core/infra/conf"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/masque"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMasqueConfig(t *testing.T) {
|
|
||||||
creator := func() Buildable {
|
|
||||||
return new(MasqueConfig)
|
|
||||||
}
|
|
||||||
|
|
||||||
runMultiTestCase(t, []TestCase{
|
|
||||||
{
|
|
||||||
Input: `{}`,
|
|
||||||
Parser: loadJSON(creator),
|
|
||||||
Output: &masque.Config{Path: "/.well-known/masque/ip/*/*/"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Input: `{
|
|
||||||
"host": "example.com:8443",
|
|
||||||
"path": "/.well-known/masque/ip/{target}/{ipproto}/",
|
|
||||||
"headers": {"Authorization": "Basic dTpw"}
|
|
||||||
}`,
|
|
||||||
Parser: loadJSON(creator),
|
|
||||||
Output: &masque.Config{
|
|
||||||
Host: "example.com:8443",
|
|
||||||
Path: "/.well-known/masque/ip/*/*/",
|
|
||||||
Headers: map[string]string{"Authorization": "Basic dTpw"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Input: `{"path": "/masque/ip{?target,ipproto}"}`,
|
|
||||||
Parser: loadJSON(creator),
|
|
||||||
Output: &masque.Config{Path: "/masque/ip?target=*&ipproto=*"},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, input := range []string{
|
|
||||||
`{"path": "/masque/{target}/{ipproto}/{dns}"}`,
|
|
||||||
`{"path": "masque"}`,
|
|
||||||
`{"host": "example.com/path"}`,
|
|
||||||
`{"headers": {"host": "example.com"}}`,
|
|
||||||
`{"headers": {"Capsule-Protocol": "?0"}}`,
|
|
||||||
`{"headers": {"X Token": "a"}}`,
|
|
||||||
`{"headers": {"X-Token": "a\r\nb"}}`,
|
|
||||||
} {
|
|
||||||
if _, err := loadJSON(creator)(input); err == nil {
|
|
||||||
t.Errorf("expected an error for %s", input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMasqueOutboundConfig(t *testing.T) {
|
|
||||||
build := func(s string) error {
|
|
||||||
c := new(OutboundDetourConfig)
|
|
||||||
if err := json.Unmarshal([]byte(s), c); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
_, err := c.Build()
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := build(`{
|
|
||||||
"protocol": "masque",
|
|
||||||
"settings": {"address": "example.com", "port": 443},
|
|
||||||
"streamSettings": {"network": "masque", "security": "tls"},
|
|
||||||
"mux": {"enabled": false, "concurrency": -1}
|
|
||||||
}`); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
for _, input := range []string{
|
|
||||||
`{"protocol": "masque", "settings": {"address": "example.com"}, "streamSettings": {"network": "masque", "security": "tls"}}`,
|
|
||||||
`{"protocol": "masque", "settings": {"address": "example.com", "port": 443}, "streamSettings": {"network": "masque", "security": "tls"}, "mux": {"enabled": true}}`,
|
|
||||||
`{"protocol": "masque", "settings": {"address": "example.com", "port": 443}, "streamSettings": {"network": "masque", "security": "tls"}, "mux": {"enabled": true, "concurrency": -1}}`,
|
|
||||||
`{"protocol": "freedom", "streamSettings": {"network": "masque", "security": "tls"}}`,
|
|
||||||
} {
|
|
||||||
if err := build(input); err == nil {
|
|
||||||
t.Errorf("expected an error for %s", input)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -30,7 +30,7 @@ func MergeConfigFromFiles(files []*core.ConfigSource) (string, error) {
|
|||||||
if j, ok := creflect.MarshalToJson(c, true); ok {
|
if j, ok := creflect.MarshalToJson(c, true); ok {
|
||||||
return j, nil
|
return j, nil
|
||||||
}
|
}
|
||||||
return "", errors.New("marshal to json failed.")
|
return "", errors.New("marshal to json failed.").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
func mergeConfigs(files []*core.ConfigSource) (*conf.Config, error) {
|
func mergeConfigs(files []*core.ConfigSource) (*conf.Config, error) {
|
||||||
|
|||||||
+3
-2
@@ -44,6 +44,7 @@ func (v *SocksServerConfig) Build() (proto.Message, error) {
|
|||||||
case AuthMethodUserPass:
|
case AuthMethodUserPass:
|
||||||
config.AuthType = socks.AuthType_PASSWORD
|
config.AuthType = socks.AuthType_PASSWORD
|
||||||
default:
|
default:
|
||||||
|
// errors.New("unknown socks auth method: ", v.AuthMethod, ". Default to noauth.").AtWarning().WriteToLog()
|
||||||
config.AuthType = socks.AuthType_NO_AUTH
|
config.AuthType = socks.AuthType_NO_AUTH
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +115,7 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
|
|||||||
user.Email = v.Email
|
user.Email = v.Email
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, user); err != nil {
|
if err := json.Unmarshal(rawUser, user); err != nil {
|
||||||
return nil, errors.New("failed to parse Socks user").Base(err)
|
return nil, errors.New("failed to parse Socks user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
account := new(SocksAccount)
|
account := new(SocksAccount)
|
||||||
@@ -123,7 +124,7 @@ func (v *SocksClientConfig) Build() (proto.Message, error) {
|
|||||||
account.Password = v.Password
|
account.Password = v.Password
|
||||||
} else {
|
} else {
|
||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New("failed to parse socks account").Base(err)
|
return nil, errors.New("failed to parse socks account").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
user.Account = serial.ToTypedMessage(account.Build())
|
user.Account = serial.ToTypedMessage(account.Build())
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet/finalmask/realm"
|
"github.com/xtls/xray-core/transport/internet/finalmask/realm"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
|
"github.com/xtls/xray-core/transport/internet/finalmask/salamander"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/sudoku"
|
"github.com/xtls/xray-core/transport/internet/finalmask/sudoku"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/udphop"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/xdns"
|
"github.com/xtls/xray-core/transport/internet/finalmask/xdns"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/xicmp"
|
"github.com/xtls/xray-core/transport/internet/finalmask/xicmp"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/xmc"
|
"github.com/xtls/xray-core/transport/internet/finalmask/xmc"
|
||||||
@@ -84,7 +83,6 @@ var (
|
|||||||
"xdns": func() interface{} { return new(Xdns) },
|
"xdns": func() interface{} { return new(Xdns) },
|
||||||
"xicmp": func() interface{} { return new(Xicmp) },
|
"xicmp": func() interface{} { return new(Xicmp) },
|
||||||
"realm": func() interface{} { return new(Realm) },
|
"realm": func() interface{} { return new(Realm) },
|
||||||
"udphop": func() interface{} { return new(UDPHop) },
|
|
||||||
}, "type", "settings")
|
}, "type", "settings")
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -907,52 +905,6 @@ func (c *Realm) Build() (proto.Message, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UDPHop struct {
|
|
||||||
Mode string `json:"mode"`
|
|
||||||
Interval Int32Range `json:"interval"`
|
|
||||||
RemoteIPs []string `json:"remoteIPs"`
|
|
||||||
RemotePorts PortList `json:"remotePorts"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *UDPHop) Build() (proto.Message, error) {
|
|
||||||
var local, remote, remoteOnce bool
|
|
||||||
for _, mode := range strings.Split(c.Mode, ",") {
|
|
||||||
switch strings.ToLower(mode) {
|
|
||||||
case "intervallocal":
|
|
||||||
local = true
|
|
||||||
case "intervalremote":
|
|
||||||
remote = true
|
|
||||||
case "perconnremote":
|
|
||||||
remoteOnce = true
|
|
||||||
default:
|
|
||||||
return nil, errors.New("invalid mode ", mode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var remoteIPs []string
|
|
||||||
for _, ip := range c.RemoteIPs {
|
|
||||||
prefix, err := netip.ParsePrefix(ip)
|
|
||||||
if err == nil {
|
|
||||||
remoteIPs = append(remoteIPs, prefix.String())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
addr, err := netip.ParseAddr(ip)
|
|
||||||
if err == nil {
|
|
||||||
remoteIPs = append(remoteIPs, netip.PrefixFrom(addr, addr.BitLen()).String())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return nil, errors.New("invalid ip ", ip)
|
|
||||||
}
|
|
||||||
return &udphop.Config{
|
|
||||||
Local: local,
|
|
||||||
Remote: remote,
|
|
||||||
RemoteOnce: remoteOnce,
|
|
||||||
IntervalMin: int64(c.Interval.From),
|
|
||||||
IntervalMax: int64(c.Interval.To),
|
|
||||||
RemoteIPs: remoteIPs,
|
|
||||||
RemotePorts: c.RemotePorts.Build().Ports(),
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Mask struct {
|
type Mask struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Settings *json.RawMessage `json:"settings"`
|
Settings *json.RawMessage `json:"settings"`
|
||||||
@@ -986,6 +938,7 @@ type QuicParamsConfig struct {
|
|||||||
BrutalUp Bandwidth `json:"brutalUp"`
|
BrutalUp Bandwidth `json:"brutalUp"`
|
||||||
BrutalDown Bandwidth `json:"brutalDown"`
|
BrutalDown Bandwidth `json:"brutalDown"`
|
||||||
BrutalDisableLossCompensation bool `json:"brutalDisableLossCompensation"`
|
BrutalDisableLossCompensation bool `json:"brutalDisableLossCompensation"`
|
||||||
|
UdpHop UdpHop `json:"udpHop"`
|
||||||
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
|
InitStreamReceiveWindow uint64 `json:"initStreamReceiveWindow"`
|
||||||
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
|
MaxStreamReceiveWindow uint64 `json:"maxStreamReceiveWindow"`
|
||||||
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"`
|
InitConnectionReceiveWindow uint64 `json:"initConnectionReceiveWindow"`
|
||||||
|
|||||||
@@ -36,10 +36,6 @@ func (p TransportProtocol) Build() (string, error) {
|
|||||||
return "", errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
|
return "", errors.PrintRemovedFeatureError("QUIC transport (without web service, etc.)", "XHTTP stream-one H3")
|
||||||
case "hysteria":
|
case "hysteria":
|
||||||
return "hysteria", nil
|
return "hysteria", nil
|
||||||
case "masque":
|
|
||||||
return "masque", nil
|
|
||||||
case "xdrive":
|
|
||||||
return "xdrive", nil
|
|
||||||
default:
|
default:
|
||||||
return "", errors.New("Config: unknown transport protocol: ", p)
|
return "", errors.New("Config: unknown transport protocol: ", p)
|
||||||
}
|
}
|
||||||
@@ -63,8 +59,6 @@ type StreamConfig struct {
|
|||||||
WSSettings *WebSocketConfig `json:"wsSettings"`
|
WSSettings *WebSocketConfig `json:"wsSettings"`
|
||||||
HTTPUPGRADESettings *HttpUpgradeConfig `json:"httpupgradeSettings"`
|
HTTPUPGRADESettings *HttpUpgradeConfig `json:"httpupgradeSettings"`
|
||||||
HysteriaSettings *HysteriaConfig `json:"hysteriaSettings"`
|
HysteriaSettings *HysteriaConfig `json:"hysteriaSettings"`
|
||||||
MASQUESettings *MasqueConfig `json:"masqueSettings"`
|
|
||||||
XDRIVESettings *XDriveConfig `json:"xdriveSettings"`
|
|
||||||
SocketSettings *SocketConfig `json:"sockopt"`
|
SocketSettings *SocketConfig `json:"sockopt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,26 +192,6 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
Settings: serial.ToTypedMessage(hs),
|
Settings: serial.ToTypedMessage(hs),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if c.MASQUESettings != nil {
|
|
||||||
ms, err := c.MASQUESettings.Build()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Failed to build MASQUE config.").Base(err)
|
|
||||||
}
|
|
||||||
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
||||||
ProtocolName: "masque",
|
|
||||||
Settings: serial.ToTypedMessage(ms),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if c.XDRIVESettings != nil {
|
|
||||||
xs, err := c.XDRIVESettings.Build()
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("Failed to build XDRIVE config.").Base(err)
|
|
||||||
}
|
|
||||||
config.TransportSettings = append(config.TransportSettings, &internet.TransportConfig{
|
|
||||||
ProtocolName: "xdrive",
|
|
||||||
Settings: serial.ToTypedMessage(xs),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if c.SocketSettings != nil {
|
if c.SocketSettings != nil {
|
||||||
ss, err := c.SocketSettings.Build()
|
ss, err := c.SocketSettings.Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -279,6 +253,10 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
return nil, errors.New("unknown congestion control: ", c.FinalMask.QuicParams.Congestion, ", valid values: reno, bbr, brutal, force-brutal")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c.FinalMask.QuicParams.UdpHop.Interval.From != 0 && c.FinalMask.QuicParams.UdpHop.Interval.From < 5) || (c.FinalMask.QuicParams.UdpHop.Interval.To != 0 && c.FinalMask.QuicParams.UdpHop.Interval.To < 5) {
|
||||||
|
return nil, errors.New("Interval must be at least 5")
|
||||||
|
}
|
||||||
|
|
||||||
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
|
if c.FinalMask.QuicParams.InitStreamReceiveWindow > 0 && c.FinalMask.QuicParams.InitStreamReceiveWindow < 16384 {
|
||||||
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
|
return nil, errors.New("InitStreamReceiveWindow must be at least 16384")
|
||||||
}
|
}
|
||||||
@@ -312,17 +290,22 @@ func (c *StreamConfig) Build() (*internet.StreamConfig, error) {
|
|||||||
BrutalUp: up,
|
BrutalUp: up,
|
||||||
BrutalDown: down,
|
BrutalDown: down,
|
||||||
BrutalDisableLossCompensation: c.FinalMask.QuicParams.BrutalDisableLossCompensation,
|
BrutalDisableLossCompensation: c.FinalMask.QuicParams.BrutalDisableLossCompensation,
|
||||||
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
UdpHop: &internet.UdpHop{
|
||||||
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
Ports: c.FinalMask.QuicParams.UdpHop.PortList.Build().Ports(),
|
||||||
InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow,
|
IntervalMin: int64(c.FinalMask.QuicParams.UdpHop.Interval.From),
|
||||||
MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow,
|
IntervalMax: int64(c.FinalMask.QuicParams.UdpHop.Interval.To),
|
||||||
MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout,
|
},
|
||||||
KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod,
|
InitStreamReceiveWindow: c.FinalMask.QuicParams.InitStreamReceiveWindow,
|
||||||
DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
|
MaxStreamReceiveWindow: c.FinalMask.QuicParams.MaxStreamReceiveWindow,
|
||||||
DisableChromeParrot: c.FinalMask.QuicParams.DisableChromeParrot,
|
InitConnReceiveWindow: c.FinalMask.QuicParams.InitConnectionReceiveWindow,
|
||||||
DisableGSO: c.FinalMask.QuicParams.DisableGSO,
|
MaxConnReceiveWindow: c.FinalMask.QuicParams.MaxConnectionReceiveWindow,
|
||||||
MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
|
MaxIdleTimeout: c.FinalMask.QuicParams.MaxIdleTimeout,
|
||||||
DisableStatelessReset: c.FinalMask.QuicParams.DisableStatelessReset,
|
KeepAlivePeriod: c.FinalMask.QuicParams.KeepAlivePeriod,
|
||||||
|
DisablePathMtuDiscovery: c.FinalMask.QuicParams.DisablePathMTUDiscovery,
|
||||||
|
DisableChromeParrot: c.FinalMask.QuicParams.DisableChromeParrot,
|
||||||
|
DisableGSO: c.FinalMask.QuicParams.DisableGSO,
|
||||||
|
MaxIncomingStreams: c.FinalMask.QuicParams.MaxIncomingStreams,
|
||||||
|
DisableStatelessReset: c.FinalMask.QuicParams.DisableStatelessReset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-100
@@ -1,6 +1,7 @@
|
|||||||
package conf
|
package conf
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -20,12 +21,9 @@ import (
|
|||||||
"github.com/xtls/xray-core/transport/internet/httpupgrade"
|
"github.com/xtls/xray-core/transport/internet/httpupgrade"
|
||||||
"github.com/xtls/xray-core/transport/internet/hysteria"
|
"github.com/xtls/xray-core/transport/internet/hysteria"
|
||||||
"github.com/xtls/xray-core/transport/internet/kcp"
|
"github.com/xtls/xray-core/transport/internet/kcp"
|
||||||
"github.com/xtls/xray-core/transport/internet/masque"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/splithttp"
|
"github.com/xtls/xray-core/transport/internet/splithttp"
|
||||||
"github.com/xtls/xray-core/transport/internet/tcp"
|
"github.com/xtls/xray-core/transport/internet/tcp"
|
||||||
"github.com/xtls/xray-core/transport/internet/websocket"
|
"github.com/xtls/xray-core/transport/internet/websocket"
|
||||||
"github.com/xtls/xray-core/transport/internet/xdrive"
|
|
||||||
"golang.org/x/net/http/httpguts"
|
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -124,7 +122,7 @@ func (v *AuthenticatorRequest) Build() (*http.RequestConfig, error) {
|
|||||||
for _, key := range headerNames {
|
for _, key := range headerNames {
|
||||||
value := v.Headers[key]
|
value := v.Headers[key]
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return nil, errors.New("empty HTTP header value: " + key)
|
return nil, errors.New("empty HTTP header value: " + key).AtError()
|
||||||
}
|
}
|
||||||
config.Header = append(config.Header, &http.Header{
|
config.Header = append(config.Header, &http.Header{
|
||||||
Name: key,
|
Name: key,
|
||||||
@@ -192,7 +190,7 @@ func (v *AuthenticatorResponse) Build() (*http.ResponseConfig, error) {
|
|||||||
for _, key := range headerNames {
|
for _, key := range headerNames {
|
||||||
value := v.Headers[key]
|
value := v.Headers[key]
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return nil, errors.New("empty HTTP header value: " + key)
|
return nil, errors.New("empty HTTP header value: " + key).AtError()
|
||||||
}
|
}
|
||||||
config.Header = append(config.Header, &http.Header{
|
config.Header = append(config.Header, &http.Header{
|
||||||
Name: key,
|
Name: key,
|
||||||
@@ -242,11 +240,11 @@ func (c *TCPConfig) Build() (proto.Message, error) {
|
|||||||
if len(c.HeaderConfig) > 0 {
|
if len(c.HeaderConfig) > 0 {
|
||||||
headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
|
headerConfig, _, err := tcpHeaderLoader.Load(c.HeaderConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("invalid TCP header config").Base(err)
|
return nil, errors.New("invalid TCP header config").Base(err).AtError()
|
||||||
}
|
}
|
||||||
ts, err := headerConfig.(Buildable).Build()
|
ts, err := headerConfig.(Buildable).Build()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("invalid TCP header config").Base(err)
|
return nil, errors.New("invalid TCP header config").Base(err).AtError()
|
||||||
}
|
}
|
||||||
config.HeaderSettings = serial.ToTypedMessage(ts)
|
config.HeaderSettings = serial.ToTypedMessage(ts)
|
||||||
}
|
}
|
||||||
@@ -536,6 +534,10 @@ type KCPConfig struct {
|
|||||||
|
|
||||||
// Build implements Buildable.
|
// Build implements Buildable.
|
||||||
func (c *KCPConfig) Build() (proto.Message, error) {
|
func (c *KCPConfig) Build() (proto.Message, error) {
|
||||||
|
if c.HeaderConfig != nil || c.Seed != nil {
|
||||||
|
return nil, errors.PrintRemovedFeatureError("mkcp header & seed", "finalmask/udp header-* & mkcp-original & mkcp-aes128gcm")
|
||||||
|
}
|
||||||
|
|
||||||
config := common.Must2(internet.CreateTransportConfig(kcp.ProtocolName)).(*kcp.Config)
|
config := common.Must2(internet.CreateTransportConfig(kcp.ProtocolName)).(*kcp.Config)
|
||||||
|
|
||||||
if c.Mtu != nil {
|
if c.Mtu != nil {
|
||||||
@@ -558,16 +560,16 @@ func (c *KCPConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if config.Mtu < 21 {
|
if config.Mtu < 21 {
|
||||||
return nil, errors.New("MTU must be at least 21")
|
return nil, errors.New("Mtu must be at least 21").AtError()
|
||||||
}
|
}
|
||||||
if config.Tti < 10 || config.Tti > 1000 {
|
if config.Tti < 10 || config.Tti > 1000 {
|
||||||
return nil, errors.New("TTI must be between 10 and 1000")
|
return nil, errors.New("invalid mKCP TTI: ", c.Tti).AtError()
|
||||||
}
|
}
|
||||||
if config.CwndMultiplier < 1 {
|
if config.CwndMultiplier < 1 {
|
||||||
return nil, errors.New("CwndMultiplier must be at least 1")
|
return nil, errors.New("CwndMultiplier must be at least 1").AtError()
|
||||||
}
|
}
|
||||||
if config.GetSendingBufferSize() == 0 {
|
if config.GetSendingBufferSize() == 0 {
|
||||||
return nil, errors.New("MaxSendingWindow must be at least ", config.Mtu)
|
return nil, errors.New("MaxSendingWindow must be >= Mtu").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
return config, nil
|
return config, nil
|
||||||
@@ -737,6 +739,11 @@ func (b Bandwidth) Bps() (uint64, error) {
|
|||||||
return uint64(val*float64(mul)) / 8, nil
|
return uint64(val*float64(mul)) / 8, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UdpHop struct {
|
||||||
|
PortList PortList `json:"ports"`
|
||||||
|
Interval Int32Range `json:"interval"`
|
||||||
|
}
|
||||||
|
|
||||||
type Masquerade struct {
|
type Masquerade struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
||||||
@@ -753,8 +760,14 @@ type Masquerade struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HysteriaConfig struct {
|
type HysteriaConfig struct {
|
||||||
Version int32 `json:"version"`
|
Version int32 `json:"version"`
|
||||||
Auth string `json:"auth"`
|
Auth string `json:"auth"`
|
||||||
|
|
||||||
|
Congestion *string `json:"congestion"`
|
||||||
|
Up *Bandwidth `json:"up"`
|
||||||
|
Down *Bandwidth `json:"down"`
|
||||||
|
UdpHop *UdpHop `json:"udphop"`
|
||||||
|
|
||||||
UdpIdleTimeout int64 `json:"udpIdleTimeout"`
|
UdpIdleTimeout int64 `json:"udpIdleTimeout"`
|
||||||
Masquerade Masquerade `json:"masquerade"`
|
Masquerade Masquerade `json:"masquerade"`
|
||||||
}
|
}
|
||||||
@@ -764,6 +777,10 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
|||||||
return nil, errors.New("version != 2")
|
return nil, errors.New("version != 2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Congestion != nil || c.Up != nil || c.Down != nil || c.UdpHop != nil {
|
||||||
|
errors.LogWarning(context.Background(), "congestion & up & down & udphop move to finalmask/quicParams")
|
||||||
|
}
|
||||||
|
|
||||||
if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) {
|
if c.UdpIdleTimeout != 0 && (c.UdpIdleTimeout < 2 || c.UdpIdleTimeout > 600) {
|
||||||
return nil, errors.New("UdpIdleTimeout must be between 2 and 600")
|
return nil, errors.New("UdpIdleTimeout must be between 2 and 600")
|
||||||
}
|
}
|
||||||
@@ -788,46 +805,6 @@ func (c *HysteriaConfig) Build() (proto.Message, error) {
|
|||||||
return config, nil
|
return config, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type MasqueConfig struct {
|
|
||||||
Host string `json:"host"`
|
|
||||||
Path string `json:"path"`
|
|
||||||
Headers map[string]string `json:"headers"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *MasqueConfig) Build() (proto.Message, error) {
|
|
||||||
path := c.Path
|
|
||||||
if path == "" {
|
|
||||||
path = masque.DefaultPath
|
|
||||||
}
|
|
||||||
path = strings.NewReplacer(
|
|
||||||
"{target}", "*", "{ipproto}", "*",
|
|
||||||
"{?target,ipproto}", "?target=*&ipproto=*", "{?ipproto,target}", "?ipproto=*&target=*",
|
|
||||||
"{&target,ipproto}", "&target=*&ipproto=*", "{&ipproto,target}", "&ipproto=*&target=*",
|
|
||||||
).Replace(path)
|
|
||||||
if !strings.HasPrefix(path, "/") || strings.ContainsAny(path, "{}") {
|
|
||||||
return nil, errors.New(`invalid "path": `, path, `, only the variables {target} and {ipproto} are supported`)
|
|
||||||
}
|
|
||||||
if c.Host != "" {
|
|
||||||
if u, err := url.Parse("https://" + c.Host); err != nil || u.Host != c.Host {
|
|
||||||
return nil, errors.New(`invalid "host": `, c.Host)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for k, v := range c.Headers {
|
|
||||||
if !httpguts.ValidHeaderFieldName(k) || !httpguts.ValidHeaderFieldValue(v) {
|
|
||||||
return nil, errors.New(`invalid header in "headers": `, strconv.Quote(k))
|
|
||||||
}
|
|
||||||
switch strings.ToLower(k) {
|
|
||||||
case "host", "capsule-protocol":
|
|
||||||
return nil, errors.New(`"headers" can't contain "`, k, `"`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &masque.Config{
|
|
||||||
Host: c.Host,
|
|
||||||
Path: path,
|
|
||||||
Headers: c.Headers,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFileOrString(f string, s []string) ([]byte, error) {
|
func readFileOrString(f string, s []string) ([]byte, error) {
|
||||||
if len(f) > 0 {
|
if len(f) > 0 {
|
||||||
return filesystem.ReadCert(f)
|
return filesystem.ReadCert(f)
|
||||||
@@ -837,50 +814,3 @@ func readFileOrString(f string, s []string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
return nil, errors.New("both file and bytes are empty.")
|
return nil, errors.New("both file and bytes are empty.")
|
||||||
}
|
}
|
||||||
|
|
||||||
type XDriveConfig struct {
|
|
||||||
RemoteFolder string `json:"remoteFolder"`
|
|
||||||
Service string `json:"service"`
|
|
||||||
Secrets []string `json:"secrets"`
|
|
||||||
SegmentBytes uint32 `json:"segmentBytes"`
|
|
||||||
FlushIntervalMs uint32 `json:"flushIntervalMs"`
|
|
||||||
PollIntervalMs uint32 `json:"pollIntervalMs"`
|
|
||||||
MaxPollIntervalMs uint32 `json:"maxPollIntervalMs"`
|
|
||||||
SessionTTLSeconds uint32 `json:"sessionTtlSeconds"`
|
|
||||||
Concurrency uint32 `json:"concurrency"`
|
|
||||||
EagerWindowMs uint32 `json:"eagerWindowMs"`
|
|
||||||
HoleTimeoutMs uint32 `json:"holeTimeoutMs"`
|
|
||||||
Template json.RawMessage `json:"template"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build implements Buildable.
|
|
||||||
func (c *XDriveConfig) Build() (proto.Message, error) {
|
|
||||||
switch c.Service {
|
|
||||||
case "local":
|
|
||||||
case "Google Drive":
|
|
||||||
if len(c.Secrets) != 3 {
|
|
||||||
return nil, errors.New("Google Drive needs 3 secrets in order of ClientID, ClientSecret, RefreshToken")
|
|
||||||
}
|
|
||||||
case "template":
|
|
||||||
if len(c.Template) == 0 {
|
|
||||||
return nil, errors.New(`service "template" needs a "template" object`)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, errors.New("unsupported service")
|
|
||||||
}
|
|
||||||
config := &xdrive.Config{
|
|
||||||
RemoteFolder: c.RemoteFolder,
|
|
||||||
Service: c.Service,
|
|
||||||
Secrets: c.Secrets,
|
|
||||||
SegmentBytes: c.SegmentBytes,
|
|
||||||
FlushIntervalMs: c.FlushIntervalMs,
|
|
||||||
PollIntervalMs: c.PollIntervalMs,
|
|
||||||
MaxPollIntervalMs: c.MaxPollIntervalMs,
|
|
||||||
SessionTtlSeconds: c.SessionTTLSeconds,
|
|
||||||
Concurrency: c.Concurrency,
|
|
||||||
EagerWindowMs: c.EagerWindowMs,
|
|
||||||
HoleTimeoutMs: c.HoleTimeoutMs,
|
|
||||||
Template: string(c.Template),
|
|
||||||
}
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -291,76 +291,3 @@ func TestHeaderCustomUDPBuildRejectsExprWithoutArgs(t *testing.T) {
|
|||||||
t.Fatalf("expected transform arg rejection, got %v", err)
|
t.Fatalf("expected transform arg rejection, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestXDriveStreamConfig(t *testing.T) {
|
|
||||||
config := new(StreamConfig)
|
|
||||||
if err := json.Unmarshal([]byte(`{
|
|
||||||
"method": "xdrive",
|
|
||||||
"xdriveSettings": {
|
|
||||||
"remoteFolder": "/tmp/xdrive",
|
|
||||||
"service": "local"
|
|
||||||
}
|
|
||||||
}`), config); err != nil {
|
|
||||||
t.Fatalf("Unmarshal: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
built, err := config.Build()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Build: %v", err)
|
|
||||||
}
|
|
||||||
if built.ProtocolName != "xdrive" {
|
|
||||||
t.Fatalf("ProtocolName is %q, want %q", built.ProtocolName, "xdrive")
|
|
||||||
}
|
|
||||||
if len(built.TransportSettings) != 1 || built.TransportSettings[0].ProtocolName != "xdrive" {
|
|
||||||
t.Fatalf("TransportSettings is %v, want a single xdrive entry", built.TransportSettings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestXDriveRejectsUnknownService(t *testing.T) {
|
|
||||||
config := new(XDriveConfig)
|
|
||||||
if err := json.Unmarshal([]byte(`{"remoteFolder": "/tmp/xdrive", "service": "Dropbox"}`), config); err != nil {
|
|
||||||
t.Fatalf("Unmarshal: %v", err)
|
|
||||||
}
|
|
||||||
if _, err := config.Build(); err == nil {
|
|
||||||
t.Fatal("Build accepted an unsupported service")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestXDriveTemplateStreamConfig(t *testing.T) {
|
|
||||||
config := new(StreamConfig)
|
|
||||||
if err := json.Unmarshal([]byte(`{
|
|
||||||
"method": "xdrive",
|
|
||||||
"xdriveSettings": {
|
|
||||||
"remoteFolder": "folder",
|
|
||||||
"service": "template",
|
|
||||||
"secrets": ["user", "pass"],
|
|
||||||
"template": {
|
|
||||||
"flatten": true,
|
|
||||||
"auth": {"type": "basic", "username": "{secret0}", "password": "{secret1}"},
|
|
||||||
"put": {"method": "PUT", "url": "https://dav.example/{folder}/{name}"},
|
|
||||||
"get": {"method": "GET", "url": "https://dav.example/{folder}/{name}"},
|
|
||||||
"delete": {"method": "DELETE", "url": "https://dav.example/{folder}/{name}"},
|
|
||||||
"list": {"method": "PROPFIND", "url": "https://dav.example/{folder}/", "namesRegex": "<d:href>/folder/([^<]+)</d:href>"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}`), config); err != nil {
|
|
||||||
t.Fatalf("Unmarshal: %v", err)
|
|
||||||
}
|
|
||||||
built, err := config.Build()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Build: %v", err)
|
|
||||||
}
|
|
||||||
if built.ProtocolName != "xdrive" {
|
|
||||||
t.Fatalf("ProtocolName is %q, want xdrive", built.ProtocolName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestXDriveTemplateNeedsTemplate(t *testing.T) {
|
|
||||||
config := new(XDriveConfig)
|
|
||||||
if err := json.Unmarshal([]byte(`{"remoteFolder": "f", "service": "template"}`), config); err != nil {
|
|
||||||
t.Fatalf("Unmarshal: %v", err)
|
|
||||||
}
|
|
||||||
if _, err := config.Build(); err == nil {
|
|
||||||
t.Fatal("Build accepted a template service without a template")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -312,9 +312,6 @@ func (c *VLessOutboundConfig) Build() (proto.Message, error) {
|
|||||||
if err := json.Unmarshal(rawUser, account); err != nil {
|
if err := json.Unmarshal(rawUser, account); err != nil {
|
||||||
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
return nil, errors.New(`VLESS users: invalid user`).Base(err)
|
||||||
}
|
}
|
||||||
// validateOutboundTransportSecurity needs to see these
|
|
||||||
c.Encryption = account.Encryption
|
|
||||||
c.Address = rec.Address
|
|
||||||
if account.Reverse != nil { // may not be reached: error json unmarshal
|
if account.Reverse != nil { // may not be reached: error json unmarshal
|
||||||
return nil, errors.New(`VLESS users: please use simplified outbound's config style to use "reverse"`)
|
return nil, errors.New(`VLESS users: please use simplified outbound's config style to use "reverse"`)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-7
@@ -59,13 +59,14 @@ func (c *WireGuardPeerConfig) Build() (*wireguard.PeerConfig, error) {
|
|||||||
type WireGuardConfig struct {
|
type WireGuardConfig struct {
|
||||||
IsClient bool `json:""`
|
IsClient bool `json:""`
|
||||||
|
|
||||||
NoKernelTun bool `json:"noKernelTun"`
|
NoKernelTun bool `json:"noKernelTun"`
|
||||||
SecretKey string `json:"secretKey"`
|
SecretKey string `json:"secretKey"`
|
||||||
Address []string `json:"address"`
|
Address []string `json:"address"`
|
||||||
Peers []*WireGuardPeerConfig `json:"peers"`
|
Peers []*WireGuardPeerConfig `json:"peers"`
|
||||||
MTU int32 `json:"mtu"`
|
MTU int32 `json:"mtu"`
|
||||||
Reserved []byte `json:"reserved"`
|
Reserved []byte `json:"reserved"`
|
||||||
DNS []string `json:"remoteDNS"`
|
DomainStrategy string `json:"domainStrategy"`
|
||||||
|
DNS []string `json:"remoteDNS"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *WireGuardConfig) Build() (proto.Message, error) {
|
func (c *WireGuardConfig) Build() (proto.Message, error) {
|
||||||
@@ -124,6 +125,21 @@ func (c *WireGuardConfig) Build() (proto.Message, error) {
|
|||||||
}
|
}
|
||||||
config.Reserved = c.Reserved
|
config.Reserved = c.Reserved
|
||||||
|
|
||||||
|
switch strings.ToLower(c.DomainStrategy) {
|
||||||
|
case "forceip", "":
|
||||||
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP
|
||||||
|
case "forceipv4":
|
||||||
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP4
|
||||||
|
case "forceipv6":
|
||||||
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP6
|
||||||
|
case "forceipv4v6":
|
||||||
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP46
|
||||||
|
case "forceipv6v4":
|
||||||
|
config.DomainStrategy = wireguard.DeviceConfig_FORCE_IP64
|
||||||
|
default:
|
||||||
|
return nil, errors.New("unsupported domain strategy: ", c.DomainStrategy)
|
||||||
|
}
|
||||||
|
|
||||||
config.IsClient = c.IsClient
|
config.IsClient = c.IsClient
|
||||||
config.NoKernelTun = c.NoKernelTun
|
config.NoKernelTun = c.NoKernelTun
|
||||||
config.DNS = c.DNS
|
config.DNS = c.DNS
|
||||||
|
|||||||
+1
-11
@@ -16,7 +16,6 @@ import (
|
|||||||
"github.com/xtls/xray-core/common/serial"
|
"github.com/xtls/xray-core/common/serial"
|
||||||
core "github.com/xtls/xray-core/core"
|
core "github.com/xtls/xray-core/core"
|
||||||
"github.com/xtls/xray-core/proxy/freedom"
|
"github.com/xtls/xray-core/proxy/freedom"
|
||||||
"github.com/xtls/xray-core/proxy/masque"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,7 +48,6 @@ var (
|
|||||||
"vmess": func() interface{} { return new(VMessOutboundConfig) },
|
"vmess": func() interface{} { return new(VMessOutboundConfig) },
|
||||||
"trojan": func() interface{} { return new(TrojanClientConfig) },
|
"trojan": func() interface{} { return new(TrojanClientConfig) },
|
||||||
"hysteria": func() interface{} { return new(HysteriaClientConfig) },
|
"hysteria": func() interface{} { return new(HysteriaClientConfig) },
|
||||||
"masque": func() interface{} { return new(MasqueClientConfig) },
|
|
||||||
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
"dns": func() interface{} { return new(DNSOutboundConfig) },
|
||||||
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: true} },
|
"wireguard": func() interface{} { return &WireGuardConfig{IsClient: true} },
|
||||||
}, "protocol", "settings")
|
}, "protocol", "settings")
|
||||||
@@ -244,7 +242,7 @@ func validateOutboundTransportSecurity(rawConfig interface{}, senderSettings *pr
|
|||||||
if vlessCfg.Encryption != "" && vlessCfg.Encryption != "none" {
|
if vlessCfg.Encryption != "" && vlessCfg.Encryption != "none" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if requiresTransportSecurity(vlessCfg.Address) {
|
if requiresTransportSecurity(vlessCfg.Vnext[0].Address) {
|
||||||
return errors.New("vless without TLS or other encryption is prohibited unless the server address is a private IP or domain")
|
return errors.New("vless without TLS or other encryption is prohibited unless the server address is a private IP or domain")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,14 +338,6 @@ func (c *OutboundDetourConfig) Build() (*core.OutboundHandlerConfig, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := ts.(*masque.ClientConfig); ok {
|
|
||||||
if ms := senderSettings.MultiplexSettings; ms != nil && ms.Enabled {
|
|
||||||
return nil, errors.New(`masque outbound does not support "mux"`)
|
|
||||||
}
|
|
||||||
} else if senderSettings.StreamSettings != nil && senderSettings.StreamSettings.ProtocolName == "masque" {
|
|
||||||
return nil, errors.New("the masque transport can only be used by the masque outbound")
|
|
||||||
}
|
|
||||||
|
|
||||||
if fc, ok := ts.(*freedom.Config); ok {
|
if fc, ok := ts.(*freedom.Config); ok {
|
||||||
if senderSettings.StreamSettings != nil &&
|
if senderSettings.StreamSettings != nil &&
|
||||||
senderSettings.StreamSettings.SocketSettings != nil &&
|
senderSettings.StreamSettings.SocketSettings != nil &&
|
||||||
|
|||||||
+138
-272
@@ -1,18 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/build"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
"mvdan.cc/gofumpt/format"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -26,27 +23,101 @@ var (
|
|||||||
isFormat bool
|
isFormat bool
|
||||||
)
|
)
|
||||||
|
|
||||||
func getModuleInfo(pwd string) (modPath, langVersion string, err error) {
|
// envFile returns the name of the Go environment configuration file.
|
||||||
data, err := os.ReadFile(filepath.Join(pwd, "go.mod"))
|
// Copy from https://github.com/golang/go/blob/c4f2a9788a7be04daf931ac54382fbe2cb754938/src/cmd/go/internal/cfg/cfg.go#L150-L166
|
||||||
if err != nil {
|
func envFile() (string, error) {
|
||||||
return "", "", err
|
if file := os.Getenv("GOENV"); file != "" {
|
||||||
}
|
if file == "off" {
|
||||||
for _, line := range strings.Split(string(data), "\n") {
|
return "", errors.New("GOENV=off")
|
||||||
fields := strings.Fields(line)
|
|
||||||
if len(fields) >= 2 {
|
|
||||||
switch fields[0] {
|
|
||||||
case "module":
|
|
||||||
modPath = fields[1]
|
|
||||||
case "go":
|
|
||||||
langVersion = "go" + strings.TrimPrefix(fields[1], "go")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return file, nil
|
||||||
}
|
}
|
||||||
return modPath, langVersion, nil
|
dir, err := os.UserConfigDir()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if dir == "" {
|
||||||
|
return "", errors.New("missing user-config dir")
|
||||||
|
}
|
||||||
|
return filepath.Join(dir, "go", "env"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatGoSource(src []byte, opts format.Options) ([]byte, error) {
|
// GetRuntimeEnv returns the value of runtime environment variable,
|
||||||
return format.Source(src, opts)
|
// that is set by running following command: `go env -w key=value`.
|
||||||
|
func GetRuntimeEnv(key string) (string, error) {
|
||||||
|
file, err := envFile()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if file == "" {
|
||||||
|
return "", errors.New("missing runtime env file")
|
||||||
|
}
|
||||||
|
var data []byte
|
||||||
|
var runtimeEnv string
|
||||||
|
data, readErr := os.ReadFile(file)
|
||||||
|
if readErr != nil {
|
||||||
|
return "", readErr
|
||||||
|
}
|
||||||
|
envStrings := strings.Split(string(data), "\n")
|
||||||
|
for _, envItem := range envStrings {
|
||||||
|
envItem = strings.TrimSuffix(envItem, "\r")
|
||||||
|
envKeyValue := strings.Split(envItem, "=")
|
||||||
|
if len(envKeyValue) == 2 && strings.TrimSpace(envKeyValue[0]) == key {
|
||||||
|
runtimeEnv = strings.TrimSpace(envKeyValue[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return runtimeEnv, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGOBIN returns GOBIN environment variable as a string. It will NOT be empty.
|
||||||
|
func GetGOBIN() string {
|
||||||
|
// The one set by user explicitly by `export GOBIN=/path` or `env GOBIN=/path command`
|
||||||
|
GOBIN := os.Getenv("GOBIN")
|
||||||
|
if GOBIN == "" {
|
||||||
|
var err error
|
||||||
|
// The one set by user by running `go env -w GOBIN=/path`
|
||||||
|
GOBIN, err = GetRuntimeEnv("GOBIN")
|
||||||
|
if err != nil {
|
||||||
|
// The default one that Golang uses
|
||||||
|
return filepath.Join(build.Default.GOPATH, "bin")
|
||||||
|
}
|
||||||
|
if GOBIN == "" {
|
||||||
|
return filepath.Join(build.Default.GOPATH, "bin")
|
||||||
|
}
|
||||||
|
return GOBIN
|
||||||
|
}
|
||||||
|
return GOBIN
|
||||||
|
}
|
||||||
|
|
||||||
|
func Run(binary string, args []string) ([]byte, error) {
|
||||||
|
cmd := exec.Command(binary, args...)
|
||||||
|
cmd.Env = append(cmd.Env, os.Environ()...)
|
||||||
|
output, cmdErr := cmd.CombinedOutput()
|
||||||
|
if cmdErr != nil {
|
||||||
|
return nil, cmdErr
|
||||||
|
}
|
||||||
|
return output, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunMany(binary string, args, files []string) bool {
|
||||||
|
fmt.Println("Processing with", binary, args, "...")
|
||||||
|
|
||||||
|
formatRequired := false
|
||||||
|
maxTasks := make(chan struct{}, runtime.NumCPU())
|
||||||
|
for _, file := range files {
|
||||||
|
maxTasks <- struct{}{}
|
||||||
|
go func(file string) {
|
||||||
|
output, err := Run(binary, append(args, file))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
} else if len(output) > 0 {
|
||||||
|
fmt.Println(string(output))
|
||||||
|
formatRequired = true
|
||||||
|
}
|
||||||
|
<-maxTasks
|
||||||
|
}(file)
|
||||||
|
}
|
||||||
|
return formatRequired
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -79,76 +150,26 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pwd := *directory
|
pwd := *directory
|
||||||
modPath, langVersion, modErr := getModuleInfo(pwd)
|
GOBIN := GetGOBIN()
|
||||||
if modErr != nil {
|
binPath := os.Getenv("PATH")
|
||||||
fmt.Println("Error reading go.mod:", modErr)
|
pathSlice := []string{pwd, GOBIN, binPath}
|
||||||
|
binPath = strings.Join(pathSlice, string(os.PathListSeparator))
|
||||||
|
os.Setenv("PATH", binPath)
|
||||||
|
|
||||||
|
suffix := ""
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
suffix = ".exe"
|
||||||
|
}
|
||||||
|
gofmt := "gofumpt" + suffix
|
||||||
|
|
||||||
|
if gofmtPath, err := exec.LookPath(gofmt); err != nil {
|
||||||
|
fmt.Println("Can not find", gofmt, "in system path or current working directory.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
} else {
|
||||||
opts := format.Options{
|
gofmt = gofmtPath
|
||||||
LangVersion: langVersion,
|
|
||||||
ModulePath: modPath,
|
|
||||||
}
|
|
||||||
|
|
||||||
if isFormat {
|
|
||||||
fmt.Println("Formatting Go source files...")
|
|
||||||
} else if isCheck {
|
|
||||||
fmt.Println("Checking files thar are not properly formatted...")
|
|
||||||
}
|
|
||||||
|
|
||||||
jobs := make(chan string, runtime.NumCPU())
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
var formatRequired atomic.Bool
|
|
||||||
var hasErrors atomic.Bool
|
|
||||||
|
|
||||||
for i := 0; i < runtime.NumCPU(); i++ {
|
|
||||||
wg.Go(func() {
|
|
||||||
for path := range jobs {
|
|
||||||
src, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error reading %s: %v\n", path, err)
|
|
||||||
hasErrors.Store(true)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
formatted, err := formatGoSource(src, opts)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error formatting %s: %v\n", path, err)
|
|
||||||
hasErrors.Store(true)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if !bytes.Equal(src, formatted) {
|
|
||||||
var diffText []byte
|
|
||||||
if isDryrun {
|
|
||||||
newName := filepath.ToSlash(path)
|
|
||||||
oldName := newName + ".orig"
|
|
||||||
diffText = diff(oldName, src, newName, formatted)
|
|
||||||
}
|
|
||||||
if isFormat {
|
|
||||||
info, statErr := os.Stat(path)
|
|
||||||
if statErr != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error stating %s: %v\n", path, statErr)
|
|
||||||
hasErrors.Store(true)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if writeErr := os.WriteFile(path, formatted, info.Mode().Perm()); writeErr != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error writing %s: %v\n", path, writeErr)
|
|
||||||
hasErrors.Store(true)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formatRequired.Store(true)
|
|
||||||
if isDryrun && len(diffText) > 0 {
|
|
||||||
fmt.Printf("%s\n%s", path, diffText)
|
|
||||||
} else {
|
|
||||||
fmt.Println(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rawFilesSlice := make([]string, 0, 1000)
|
||||||
walkErr := filepath.Walk(pwd, func(path string, info os.FileInfo, err error) error {
|
walkErr := filepath.Walk(pwd, func(path string, info os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
@@ -165,206 +186,51 @@ func main() {
|
|||||||
!strings.HasSuffix(filename, ".pb.go") &&
|
!strings.HasSuffix(filename, ".pb.go") &&
|
||||||
!strings.Contains(dir, filepath.Join("testing", "mocks")) &&
|
!strings.Contains(dir, filepath.Join("testing", "mocks")) &&
|
||||||
!strings.Contains(path, filepath.Join("main", "distro", "all", "all.go")) {
|
!strings.Contains(path, filepath.Join("main", "distro", "all", "all.go")) {
|
||||||
jobs <- path
|
rawFilesSlice = append(rawFilesSlice, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
close(jobs)
|
|
||||||
wg.Wait()
|
|
||||||
|
|
||||||
if walkErr != nil {
|
if walkErr != nil {
|
||||||
fmt.Println(walkErr)
|
fmt.Println(walkErr)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasErrors.Load() {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if isFormat {
|
if isFormat {
|
||||||
if formatRequired.Load() {
|
gofmtArgs := []string{
|
||||||
fmt.Println("Do NOT forget to commit file changes.")
|
"-l", "-e", "-w",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("Formatting Go source files...")
|
||||||
|
RunMany(gofmt, gofmtArgs, rawFilesSlice)
|
||||||
|
fmt.Println("Do NOT forget to commit file changes.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if isCheck {
|
if isCheck {
|
||||||
if formatRequired.Load() {
|
gofmtListArgs := []string{
|
||||||
|
"-l", "-e",
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Checking files thar are not properly formatted...")
|
||||||
|
formatRequired := RunMany(gofmt, gofmtListArgs, rawFilesSlice)
|
||||||
|
if formatRequired {
|
||||||
fmt.Println("Format problem(s) found.")
|
fmt.Println("Format problem(s) found.")
|
||||||
fmt.Println("Please run 'go run ./infra/vformat/main.go' to format the Go source files.")
|
}
|
||||||
|
|
||||||
|
if isDryrun {
|
||||||
|
if formatRequired {
|
||||||
|
gofmtShowArgs := []string{
|
||||||
|
"-d", "-e",
|
||||||
|
}
|
||||||
|
RunMany(gofmt, gofmtShowArgs, rawFilesSlice)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if formatRequired {
|
||||||
|
fmt.Println("Please run 'go install -v mvdan.cc/gofumpt@latest', then run 'go run ./infra/vformat/main.go' to format the Go source files.")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("All Go source file format check has been passed.")
|
fmt.Println("All Go source file format check has been passed.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff algorithm copied from mvdan.cc/gofumpt/internal/govendor/diff
|
|
||||||
type pair struct{ x, y int }
|
|
||||||
|
|
||||||
func diff(oldName string, old []byte, newName string, new []byte) []byte {
|
|
||||||
if bytes.Equal(old, new) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
x := diffLines(old)
|
|
||||||
y := diffLines(new)
|
|
||||||
|
|
||||||
var out bytes.Buffer
|
|
||||||
fmt.Fprintf(&out, "diff %s %s\n", oldName, newName)
|
|
||||||
fmt.Fprintf(&out, "--- %s\n", oldName)
|
|
||||||
fmt.Fprintf(&out, "+++ %s\n", newName)
|
|
||||||
|
|
||||||
var (
|
|
||||||
done pair
|
|
||||||
chunk pair
|
|
||||||
count pair
|
|
||||||
ctext []string
|
|
||||||
)
|
|
||||||
for _, m := range diffTgs(x, y) {
|
|
||||||
if m.x < done.x {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
start := m
|
|
||||||
for start.x > done.x && start.y > done.y && x[start.x-1] == y[start.y-1] {
|
|
||||||
start.x--
|
|
||||||
start.y--
|
|
||||||
}
|
|
||||||
end := m
|
|
||||||
for end.x < len(x) && end.y < len(y) && x[end.x] == y[end.y] {
|
|
||||||
end.x++
|
|
||||||
end.y++
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range x[done.x:start.x] {
|
|
||||||
ctext = append(ctext, "-"+s)
|
|
||||||
count.x++
|
|
||||||
}
|
|
||||||
for _, s := range y[done.y:start.y] {
|
|
||||||
ctext = append(ctext, "+"+s)
|
|
||||||
count.y++
|
|
||||||
}
|
|
||||||
|
|
||||||
const C = 3
|
|
||||||
if (end.x < len(x) || end.y < len(y)) &&
|
|
||||||
(end.x-start.x < C || (len(ctext) > 0 && end.x-start.x < 2*C)) {
|
|
||||||
for _, s := range x[start.x:end.x] {
|
|
||||||
ctext = append(ctext, " "+s)
|
|
||||||
count.x++
|
|
||||||
count.y++
|
|
||||||
}
|
|
||||||
done = end
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ctext) > 0 {
|
|
||||||
n := end.x - start.x
|
|
||||||
if n > C {
|
|
||||||
n = C
|
|
||||||
}
|
|
||||||
for _, s := range x[start.x : start.x+n] {
|
|
||||||
ctext = append(ctext, " "+s)
|
|
||||||
count.x++
|
|
||||||
count.y++
|
|
||||||
}
|
|
||||||
done = pair{start.x + n, start.y + n}
|
|
||||||
|
|
||||||
if count.x > 0 {
|
|
||||||
chunk.x++
|
|
||||||
}
|
|
||||||
if count.y > 0 {
|
|
||||||
chunk.y++
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&out, "@@ -%d,%d +%d,%d @@\n", chunk.x, count.x, chunk.y, count.y)
|
|
||||||
for _, s := range ctext {
|
|
||||||
out.WriteString(s)
|
|
||||||
}
|
|
||||||
count.x = 0
|
|
||||||
count.y = 0
|
|
||||||
ctext = ctext[:0]
|
|
||||||
}
|
|
||||||
|
|
||||||
if end.x >= len(x) && end.y >= len(y) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
chunk = pair{end.x - C, end.y - C}
|
|
||||||
for _, s := range x[chunk.x:end.x] {
|
|
||||||
ctext = append(ctext, " "+s)
|
|
||||||
count.x++
|
|
||||||
count.y++
|
|
||||||
}
|
|
||||||
done = end
|
|
||||||
}
|
|
||||||
|
|
||||||
return out.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffLines(x []byte) []string {
|
|
||||||
l := strings.SplitAfter(string(x), "\n")
|
|
||||||
if l[len(l)-1] == "" {
|
|
||||||
l = l[:len(l)-1]
|
|
||||||
} else {
|
|
||||||
l[len(l)-1] += "\n\\ No newline at end of file\n"
|
|
||||||
}
|
|
||||||
return l
|
|
||||||
}
|
|
||||||
|
|
||||||
func diffTgs(x, y []string) []pair {
|
|
||||||
m := make(map[string]int)
|
|
||||||
for _, s := range x {
|
|
||||||
if c := m[s]; c > -2 {
|
|
||||||
m[s] = c - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, s := range y {
|
|
||||||
if c := m[s]; c > -8 {
|
|
||||||
m[s] = c - 4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var xi, yi, inv []int
|
|
||||||
for i, s := range y {
|
|
||||||
if m[s] == -5 {
|
|
||||||
m[s] = len(yi)
|
|
||||||
yi = append(yi, i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i, s := range x {
|
|
||||||
if j, ok := m[s]; ok && j >= 0 {
|
|
||||||
xi = append(xi, i)
|
|
||||||
inv = append(inv, j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
J := inv
|
|
||||||
n := len(xi)
|
|
||||||
T := make([]int, n)
|
|
||||||
L := make([]int, n)
|
|
||||||
for i := range T {
|
|
||||||
T[i] = n + 1
|
|
||||||
}
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
k := sort.Search(n, func(k int) bool {
|
|
||||||
return T[k] >= J[i]
|
|
||||||
})
|
|
||||||
T[k] = J[i]
|
|
||||||
L[i] = k + 1
|
|
||||||
}
|
|
||||||
k := 0
|
|
||||||
for _, v := range L {
|
|
||||||
if k < v {
|
|
||||||
k = v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
seq := make([]pair, 2+k)
|
|
||||||
seq[1+k] = pair{len(x), len(y)}
|
|
||||||
lastj := n
|
|
||||||
for i := n - 1; i >= 0; i-- {
|
|
||||||
if L[i] == k && J[i] < lastj {
|
|
||||||
seq[k] = pair{xi[i], yi[J[i]]}
|
|
||||||
k--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
seq[0] = pair{0, 0}
|
|
||||||
return seq
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import (
|
|||||||
_ "github.com/xtls/xray-core/proxy/freedom"
|
_ "github.com/xtls/xray-core/proxy/freedom"
|
||||||
_ "github.com/xtls/xray-core/proxy/http"
|
_ "github.com/xtls/xray-core/proxy/http"
|
||||||
_ "github.com/xtls/xray-core/proxy/loopback"
|
_ "github.com/xtls/xray-core/proxy/loopback"
|
||||||
_ "github.com/xtls/xray-core/proxy/masque"
|
|
||||||
_ "github.com/xtls/xray-core/proxy/shadowsocks"
|
_ "github.com/xtls/xray-core/proxy/shadowsocks"
|
||||||
_ "github.com/xtls/xray-core/proxy/socks"
|
_ "github.com/xtls/xray-core/proxy/socks"
|
||||||
_ "github.com/xtls/xray-core/proxy/trojan"
|
_ "github.com/xtls/xray-core/proxy/trojan"
|
||||||
@@ -55,14 +54,12 @@ import (
|
|||||||
_ "github.com/xtls/xray-core/transport/internet/grpc"
|
_ "github.com/xtls/xray-core/transport/internet/grpc"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/httpupgrade"
|
_ "github.com/xtls/xray-core/transport/internet/httpupgrade"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/kcp"
|
_ "github.com/xtls/xray-core/transport/internet/kcp"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/masque"
|
|
||||||
_ "github.com/xtls/xray-core/transport/internet/reality"
|
_ "github.com/xtls/xray-core/transport/internet/reality"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/splithttp"
|
_ "github.com/xtls/xray-core/transport/internet/splithttp"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/tcp"
|
_ "github.com/xtls/xray-core/transport/internet/tcp"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/tls"
|
_ "github.com/xtls/xray-core/transport/internet/tls"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/udp"
|
_ "github.com/xtls/xray-core/transport/internet/udp"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/websocket"
|
_ "github.com/xtls/xray-core/transport/internet/websocket"
|
||||||
_ "github.com/xtls/xray-core/transport/internet/xdrive"
|
|
||||||
|
|
||||||
// Transport headers
|
// Transport headers
|
||||||
_ "github.com/xtls/xray-core/transport/internet/headers/http"
|
_ "github.com/xtls/xray-core/transport/internet/headers/http"
|
||||||
|
|||||||
@@ -115,7 +115,11 @@ Start:
|
|||||||
|
|
||||||
request, err := http.ReadRequest(reader)
|
request, err := http.ReadRequest(reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to read http request").Base(err)
|
trace := errors.New("failed to read http request").Base(err)
|
||||||
|
if errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {
|
||||||
|
trace.AtWarning()
|
||||||
|
}
|
||||||
|
return trace
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.config.Accounts) > 0 {
|
if len(s.config.Accounts) > 0 {
|
||||||
@@ -143,7 +147,7 @@ Start:
|
|||||||
}
|
}
|
||||||
dest, err := http_proto.ParseHost(host, defaultPort)
|
dest, err := http_proto.ParseHost(host, defaultPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("malformed proxy host: ", host).Base(err)
|
return errors.New("malformed proxy host: ", host).AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
ctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{
|
||||||
From: conn.RemoteAddr(),
|
From: conn.RemoteAddr(),
|
||||||
@@ -258,7 +262,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
|
|||||||
requestWriter := buf.NewBufferedWriter(link.Writer)
|
requestWriter := buf.NewBufferedWriter(link.Writer)
|
||||||
common.Must(requestWriter.SetBuffered(false))
|
common.Must(requestWriter.SetBuffered(false))
|
||||||
if err := request.Write(requestWriter); err != nil {
|
if err := request.Write(requestWriter); err != nil {
|
||||||
return errors.New("failed to write whole request").Base(err)
|
return errors.New("failed to write whole request").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -295,7 +299,7 @@ func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, wri
|
|||||||
response.Header.Set("Proxy-Connection", "close")
|
response.Header.Set("Proxy-Connection", "close")
|
||||||
}
|
}
|
||||||
if err := response.Write(writer); err != nil {
|
if err := response.Write(writer); err != nil {
|
||||||
return errors.New("failed to write response").Base(err)
|
return errors.New("failed to write response").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
|
|
||||||
conn, err := dialer.Dial(hysteria.ContextWithDatagram(ctx, target.Network == net.Network_UDP), c.server.Destination)
|
conn, err := dialer.Dial(hysteria.ContextWithDatagram(ctx, target.Network == net.Network_UDP), c.server.Destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").Base(err)
|
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
errors.LogInfo(ctx, "tunneling request to ", target, " via ", target.Network, ":", c.server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", target, " via ", target.Network, ":", c.server.Destination.NetAddr())
|
||||||
@@ -236,14 +236,14 @@ type UDPReader struct {
|
|||||||
|
|
||||||
func (r *UDPReader) ReadFrom(p []byte) (n int, addr *net.Destination, err error) {
|
func (r *UDPReader) ReadFrom(p []byte) (n int, addr *net.Destination, err error) {
|
||||||
for {
|
for {
|
||||||
var packet [1500]byte
|
var buf [hysteria.MaxDatagramFrameSize]byte
|
||||||
|
|
||||||
n, err := r.reader.Read(packet[:])
|
n, err := r.reader.Read(buf[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
msg, err := ParseUDPMessage(packet[:n])
|
msg, err := ParseUDPMessage(buf[:n])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
|||||||
for _, user := range config.Users {
|
for _, user := range config.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get hysteria user").Base(err)
|
return nil, errors.New("failed to get hysteria user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to add user").Base(err)
|
return nil, errors.New("failed to add user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func (l *Loopback) init(config *Config, dispatcherInstance routing.Dispatcher) e
|
|||||||
if config.Sniffing.GetEnabled() {
|
if config.Sniffing.GetEnabled() {
|
||||||
request, err := proxyman.BuildSniffingRequest(config.Sniffing)
|
request, err := proxyman.BuildSniffingRequest(config.Sniffing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to build loopback sniffing request").Base(err)
|
return errors.New("failed to build loopback sniffing request").Base(err).AtError()
|
||||||
}
|
}
|
||||||
l.sniffingRequest = request
|
l.sniffingRequest = request
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,328 +0,0 @@
|
|||||||
package masque
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
go_errors "errors"
|
|
||||||
"io"
|
|
||||||
"net/netip"
|
|
||||||
"slices"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.zx2c4.com/wireguard/tun"
|
|
||||||
|
|
||||||
"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/protocol"
|
|
||||||
"github.com/xtls/xray-core/common/session"
|
|
||||||
"github.com/xtls/xray-core/common/signal"
|
|
||||||
"github.com/xtls/xray-core/common/task"
|
|
||||||
"github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/features/policy"
|
|
||||||
"github.com/xtls/xray-core/proxy/wireguard"
|
|
||||||
"github.com/xtls/xray-core/transport"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/masque"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/stat"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
establishTimeout = 10 * time.Second
|
|
||||||
retryInterval = time.Second
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
server *protocol.ServerSpec
|
|
||||||
policyManager policy.Manager
|
|
||||||
remoteDNS []netip.Addr
|
|
||||||
|
|
||||||
ctx context.Context
|
|
||||||
cancel context.CancelFunc
|
|
||||||
|
|
||||||
tunnel atomic.Pointer[tunnel]
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
lastErr error
|
|
||||||
lastErrAt time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewClient(ctx context.Context, config *ClientConfig) (*Client, error) {
|
|
||||||
v := core.MustFromContext(ctx)
|
|
||||||
p := v.GetFeature(policy.ManagerType()).(policy.Manager)
|
|
||||||
|
|
||||||
streamSettings := session.StreamSettingsFromContext(ctx).(*internet.MemoryStreamConfig)
|
|
||||||
if _, ok := streamSettings.ProtocolSettings.(*masque.Config); !ok {
|
|
||||||
return nil, errors.New("not masque transport")
|
|
||||||
}
|
|
||||||
if tls.ConfigFromStreamSettings(streamSettings) == nil {
|
|
||||||
return nil, errors.New(`MASQUE requires "security": "tls"`)
|
|
||||||
}
|
|
||||||
if config.Server == nil {
|
|
||||||
return nil, errors.New(`no target server found`)
|
|
||||||
}
|
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Server)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to get server spec").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dns := config.RemoteDns
|
|
||||||
if len(dns) == 0 {
|
|
||||||
dns = []string{"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"}
|
|
||||||
}
|
|
||||||
remoteDNS := make([]netip.Addr, 0, len(dns))
|
|
||||||
for _, s := range dns {
|
|
||||||
addr, err := netip.ParseAddr(s)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("invalid remote DNS server ", s).Base(err)
|
|
||||||
}
|
|
||||||
remoteDNS = append(remoteDNS, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
c := &Client{
|
|
||||||
server: server,
|
|
||||||
policyManager: p,
|
|
||||||
remoteDNS: remoteDNS,
|
|
||||||
}
|
|
||||||
c.ctx, c.cancel = context.WithCancel(context.Background())
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Process(ctx context.Context, link *transport.Link, dialer internet.Dialer) error {
|
|
||||||
outbounds := session.OutboundsFromContext(ctx)
|
|
||||||
ob := outbounds[len(outbounds)-1]
|
|
||||||
if !ob.Target.IsValid() {
|
|
||||||
return errors.New("target not specified")
|
|
||||||
}
|
|
||||||
ob.Name = "masque"
|
|
||||||
ob.CanSpliceCopy = 3
|
|
||||||
|
|
||||||
t, err := c.getTunnel(ctx, dialer)
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to establish CONNECT-IP tunnel").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var newCtx context.Context
|
|
||||||
var newCancel context.CancelFunc
|
|
||||||
if session.TimeoutOnlyFromContext(ctx) {
|
|
||||||
newCtx, newCancel = context.WithCancel(context.Background())
|
|
||||||
}
|
|
||||||
|
|
||||||
sessionPolicy := c.policyManager.ForLevel(0)
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
|
||||||
timer := signal.CancelAfterInactivity(ctx, func() {
|
|
||||||
cancel()
|
|
||||||
if newCancel != nil {
|
|
||||||
newCancel()
|
|
||||||
}
|
|
||||||
}, sessionPolicy.Timeouts.ConnectionIdle)
|
|
||||||
|
|
||||||
if newCtx != nil {
|
|
||||||
ctx = newCtx
|
|
||||||
}
|
|
||||||
|
|
||||||
var reader buf.Reader
|
|
||||||
var writer buf.Writer
|
|
||||||
|
|
||||||
switch ob.Target.Network {
|
|
||||||
case net.Network_TCP:
|
|
||||||
var conn net.Conn
|
|
||||||
var err error
|
|
||||||
if sessionPolicy.Timeouts.Handshake != 0 {
|
|
||||||
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, sessionPolicy.Timeouts.Handshake)
|
|
||||||
conn, err = t.tnet.DialContext(timeoutCtx, "tcp", ob.Target.NetAddr())
|
|
||||||
timeoutCancel()
|
|
||||||
} else {
|
|
||||||
conn, err = t.tnet.Dial("tcp", ob.Target.NetAddr())
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create TCP connection").Base(err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
reader = buf.NewReader(conn)
|
|
||||||
writer = buf.NewWriter(conn)
|
|
||||||
case net.Network_UDP:
|
|
||||||
conn, err := t.tnet.Dial("udp", ob.Target.NetAddr())
|
|
||||||
if err != nil {
|
|
||||||
return errors.New("failed to create UDP connection").Base(err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
uc := &wireguard.UDPConnClient{
|
|
||||||
PacketConn: conn.(*internet.PacketConnWrapper).PacketConn,
|
|
||||||
Dest: conn.RemoteAddr().(*net.UDPAddr),
|
|
||||||
}
|
|
||||||
reader = uc
|
|
||||||
writer = uc
|
|
||||||
default:
|
|
||||||
panic(ob.Target.Network)
|
|
||||||
}
|
|
||||||
|
|
||||||
requestFunc := func() error {
|
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.DownlinkOnly)
|
|
||||||
return buf.Copy(link.Reader, writer, buf.UpdateActivity(timer))
|
|
||||||
}
|
|
||||||
|
|
||||||
responseFunc := func() error {
|
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
|
||||||
return buf.Copy(reader, link.Writer, buf.UpdateActivity(timer))
|
|
||||||
}
|
|
||||||
|
|
||||||
responseDonePost := task.OnSuccess(responseFunc, task.Close(link.Writer))
|
|
||||||
if err := task.Run(ctx, requestFunc, responseDonePost); err != nil {
|
|
||||||
common.Interrupt(link.Reader)
|
|
||||||
common.Interrupt(link.Writer)
|
|
||||||
return errors.New("connection ends").Base(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) getTunnel(ctx context.Context, dialer internet.Dialer) (*tunnel, error) {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
if c.ctx.Err() != nil {
|
|
||||||
return nil, errors.New("closed")
|
|
||||||
}
|
|
||||||
if t := c.tunnel.Load(); t != nil {
|
|
||||||
select {
|
|
||||||
case <-t.done:
|
|
||||||
default:
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := ctx.Err(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if c.lastErr != nil && time.Since(c.lastErrAt) < retryInterval {
|
|
||||||
return nil, c.lastErr
|
|
||||||
}
|
|
||||||
|
|
||||||
t, err := c.establish(ctx, dialer)
|
|
||||||
if err != nil {
|
|
||||||
c.lastErr, c.lastErrAt = err, time.Now()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
c.lastErr = nil
|
|
||||||
c.tunnel.Store(t)
|
|
||||||
if c.ctx.Err() != nil {
|
|
||||||
if c.tunnel.CompareAndSwap(t, nil) {
|
|
||||||
t.close()
|
|
||||||
}
|
|
||||||
return nil, errors.New("closed")
|
|
||||||
}
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) establish(ctx context.Context, dialer internet.Dialer) (*tunnel, error) {
|
|
||||||
ctx, cancel := context.WithTimeout(context.WithoutCancel(ctx), establishTimeout)
|
|
||||||
defer cancel()
|
|
||||||
defer context.AfterFunc(c.ctx, cancel)()
|
|
||||||
conn, err := dialer.Dial(ctx, c.server.Destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
mconn, ok := stat.TryUnwrapStatsConn(conn).(*masque.Conn)
|
|
||||||
if !ok {
|
|
||||||
conn.Close()
|
|
||||||
return nil, errors.New("not a CONNECT-IP connection")
|
|
||||||
}
|
|
||||||
t, err := newTunnel(conn, mconn.LocalAddrs(), c.remoteDNS)
|
|
||||||
if err != nil {
|
|
||||||
conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
errors.LogInfo(ctx, "MASQUE: tunnel established from ", mconn.LocalAddrs())
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) Close() error {
|
|
||||||
c.cancel()
|
|
||||||
if t := c.tunnel.Swap(nil); t != nil {
|
|
||||||
t.close()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type tunnel struct {
|
|
||||||
conn stat.Connection
|
|
||||||
dev tun.Device
|
|
||||||
tnet *wireguard.Net
|
|
||||||
done chan struct{}
|
|
||||||
closeOnce sync.Once
|
|
||||||
}
|
|
||||||
|
|
||||||
func newTunnel(conn stat.Connection, local []netip.Addr, remoteDNS []netip.Addr) (*tunnel, error) {
|
|
||||||
var dns []netip.Addr
|
|
||||||
for _, addr := range remoteDNS {
|
|
||||||
if slices.ContainsFunc(local, func(l netip.Addr) bool { return l.Is4() == addr.Is4() }) {
|
|
||||||
dns = append(dns, addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(dns) == 0 {
|
|
||||||
errors.LogWarning(context.Background(), "MASQUE: no remote DNS server is reachable from the assigned addresses ", local, ", domain names will fail to resolve")
|
|
||||||
dns = remoteDNS
|
|
||||||
}
|
|
||||||
|
|
||||||
dev, tnet, _, err := wireguard.CreateNetTUN(local, dns, masque.MinPacketSize, true)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t := &tunnel{
|
|
||||||
conn: conn,
|
|
||||||
dev: dev,
|
|
||||||
tnet: tnet,
|
|
||||||
done: make(chan struct{}),
|
|
||||||
}
|
|
||||||
go t.readFromTunnel()
|
|
||||||
go t.writeToTunnel()
|
|
||||||
return t, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tunnel) readFromTunnel() {
|
|
||||||
defer t.close()
|
|
||||||
b := make([]byte, buf.Size)
|
|
||||||
for {
|
|
||||||
n, err := t.conn.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
if go_errors.Is(err, io.ErrShortBuffer) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
errors.LogInfoInner(context.Background(), err, "MASQUE: tunnel closed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.dev.Write([][]byte{b[:n]}, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tunnel) writeToTunnel() {
|
|
||||||
bufs := [][]byte{make([]byte, masque.MinPacketSize)}
|
|
||||||
sizes := []int{0}
|
|
||||||
for {
|
|
||||||
if _, err := t.dev.Read(bufs, sizes, 0); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := t.conn.Write(bufs[0][:sizes[0]]); err != nil {
|
|
||||||
var ptb *masque.PacketTooBigError
|
|
||||||
if go_errors.As(err, &ptb) {
|
|
||||||
go t.dev.Write([][]byte{ptb.ICMP}, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *tunnel) close() {
|
|
||||||
t.closeOnce.Do(func() {
|
|
||||||
close(t.done)
|
|
||||||
t.conn.Close()
|
|
||||||
t.dev.Close()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
common.Must(common.RegisterConfig((*ClientConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
|
|
||||||
return NewClient(ctx, config.(*ClientConfig))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
@@ -1,136 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.36.11
|
|
||||||
// protoc v6.33.5
|
|
||||||
// source: proxy/masque/config.proto
|
|
||||||
|
|
||||||
package masque
|
|
||||||
|
|
||||||
import (
|
|
||||||
protocol "github.com/xtls/xray-core/common/protocol"
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type ClientConfig struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Server *protocol.ServerEndpoint `protobuf:"bytes,1,opt,name=server,proto3" json:"server,omitempty"`
|
|
||||||
RemoteDns []string `protobuf:"bytes,2,rep,name=remote_dns,json=remoteDns,proto3" json:"remote_dns,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ClientConfig) Reset() {
|
|
||||||
*x = ClientConfig{}
|
|
||||||
mi := &file_proxy_masque_config_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ClientConfig) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*ClientConfig) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *ClientConfig) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_proxy_masque_config_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use ClientConfig.ProtoReflect.Descriptor instead.
|
|
||||||
func (*ClientConfig) Descriptor() ([]byte, []int) {
|
|
||||||
return file_proxy_masque_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ClientConfig) GetServer() *protocol.ServerEndpoint {
|
|
||||||
if x != nil {
|
|
||||||
return x.Server
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *ClientConfig) GetRemoteDns() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.RemoteDns
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_proxy_masque_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
const file_proxy_masque_config_proto_rawDesc = "" +
|
|
||||||
"\n" +
|
|
||||||
"\x19proxy/masque/config.proto\x12\x11xray.proxy.masque\x1a!common/protocol/server_spec.proto\"k\n" +
|
|
||||||
"\fClientConfig\x12<\n" +
|
|
||||||
"\x06server\x18\x01 \x01(\v2$.xray.common.protocol.ServerEndpointR\x06server\x12\x1d\n" +
|
|
||||||
"\n" +
|
|
||||||
"remote_dns\x18\x02 \x03(\tR\tremoteDnsBU\n" +
|
|
||||||
"\x15com.xray.proxy.masqueP\x01Z&github.com/xtls/xray-core/proxy/masque\xaa\x02\x11Xray.Proxy.Masqueb\x06proto3"
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_proxy_masque_config_proto_rawDescOnce sync.Once
|
|
||||||
file_proxy_masque_config_proto_rawDescData []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_proxy_masque_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_proxy_masque_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_proxy_masque_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proxy_masque_config_proto_rawDesc), len(file_proxy_masque_config_proto_rawDesc)))
|
|
||||||
})
|
|
||||||
return file_proxy_masque_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_proxy_masque_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_proxy_masque_config_proto_goTypes = []any{
|
|
||||||
(*ClientConfig)(nil), // 0: xray.proxy.masque.ClientConfig
|
|
||||||
(*protocol.ServerEndpoint)(nil), // 1: xray.common.protocol.ServerEndpoint
|
|
||||||
}
|
|
||||||
var file_proxy_masque_config_proto_depIdxs = []int32{
|
|
||||||
1, // 0: xray.proxy.masque.ClientConfig.server:type_name -> xray.common.protocol.ServerEndpoint
|
|
||||||
1, // [1:1] is the sub-list for method output_type
|
|
||||||
1, // [1:1] is the sub-list for method input_type
|
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
|
||||||
0, // [0:1] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_proxy_masque_config_proto_init() }
|
|
||||||
func file_proxy_masque_config_proto_init() {
|
|
||||||
if File_proxy_masque_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_masque_config_proto_rawDesc), len(file_proxy_masque_config_proto_rawDesc)),
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_proxy_masque_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_proxy_masque_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_proxy_masque_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_proxy_masque_config_proto = out.File
|
|
||||||
file_proxy_masque_config_proto_goTypes = nil
|
|
||||||
file_proxy_masque_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package xray.proxy.masque;
|
|
||||||
option csharp_namespace = "Xray.Proxy.Masque";
|
|
||||||
option go_package = "github.com/xtls/xray-core/proxy/masque";
|
|
||||||
option java_package = "com.xray.proxy.masque";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
|
|
||||||
import "common/protocol/server_spec.proto";
|
|
||||||
|
|
||||||
message ClientConfig {
|
|
||||||
xray.common.protocol.ServerEndpoint server = 1;
|
|
||||||
repeated string remote_dns = 2;
|
|
||||||
}
|
|
||||||
@@ -71,7 +71,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").Base(err)
|
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", network, ":", server.Destination.NetAddr())
|
||||||
|
|
||||||
@@ -124,7 +124,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
||||||
return errors.New("failed to write A request payload").Base(err)
|
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bufferedWriter.SetBuffered(false); err != nil {
|
if err := bufferedWriter.SetBuffered(false); err != nil {
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHe
|
|||||||
iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
|
iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
|
||||||
r, err = account.Cipher.NewDecryptionReader(account.Key, iv, reader)
|
r, err = account.Cipher.NewDecryptionReader(account.Key, iv, reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, drain.WithError(drainer, reader, errors.New("failed to initialize decoding stream").Base(err))
|
return nil, nil, drain.WithError(drainer, reader, errors.New("failed to initialize decoding stream").Base(err).AtError())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ func WriteTCPRequest(request *protocol.RequestHeader, writer io.Writer) (buf.Wri
|
|||||||
|
|
||||||
w, err := account.Cipher.NewEncryptionWriter(account.Key, iv, writer)
|
w, err := account.Cipher.NewEncryptionWriter(account.Key, iv, writer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to create encoding stream").Base(err)
|
return nil, errors.New("failed to create encoding stream").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
header := buf.New()
|
header := buf.New()
|
||||||
|
|||||||
@@ -34,11 +34,11 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
|||||||
for _, user := range config.Users {
|
for _, user := range config.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get shadowsocks user").Base(err)
|
return nil, errors.New("failed to get shadowsocks user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to add user").Base(err)
|
return nil, errors.New("failed to add user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
|
|||||||
func (s *Server) handleConnection(ctx context.Context, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
func (s *Server) handleConnection(ctx context.Context, conn stat.Connection, dispatcher routing.Dispatcher) error {
|
||||||
sessionPolicy := s.policyManager.ForLevel(0)
|
sessionPolicy := s.policyManager.ForLevel(0)
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err)
|
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
|
bufferedReader := buf.BufferedReader{Reader: buf.NewReader(conn)}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func NewMultiServer(ctx context.Context, config *MultiUserServerConfig) (*MultiU
|
|||||||
}
|
}
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get shadowsocks user").Base(err)
|
return nil, errors.New("failed to get shadowsocks user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
memUsers = append(memUsers, u)
|
memUsers = append(memUsers, u)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
}
|
}
|
||||||
udpRequest, err := ClientHandshake(request, conn, conn)
|
udpRequest, err := ClientHandshake(request, conn, conn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to establish connection to server").Base(err)
|
return errors.New("failed to establish connection to server").AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
if udpRequest != nil {
|
if udpRequest != nil {
|
||||||
if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
|
if udpRequest.Address == net.AnyIP || udpRequest.Address == net.AnyIPv6 {
|
||||||
|
|||||||
@@ -458,10 +458,10 @@ func ClientHandshake(request *protocol.RequestHeader, reader io.Reader, writer i
|
|||||||
}
|
}
|
||||||
|
|
||||||
if b.Byte(0) != socks5Version {
|
if b.Byte(0) != socks5Version {
|
||||||
return nil, errors.New("unexpected server version: ", b.Byte(0))
|
return nil, errors.New("unexpected server version: ", b.Byte(0)).AtWarning()
|
||||||
}
|
}
|
||||||
if b.Byte(1) != authByte {
|
if b.Byte(1) != authByte {
|
||||||
return nil, errors.New("auth method not supported.")
|
return nil, errors.New("auth method not supported.").AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if authByte == authPassword {
|
if authByte == authPassword {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").Base(err)
|
return errors.New("failed to find an available destination").AtWarning().Base(err)
|
||||||
}
|
}
|
||||||
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination.NetAddr())
|
errors.LogInfo(ctx, "tunneling request to ", destination, " via ", server.Destination.NetAddr())
|
||||||
|
|
||||||
@@ -116,21 +116,21 @@ func (c *Client) Process(ctx context.Context, link *transport.Link, dialer inter
|
|||||||
|
|
||||||
// write some request payload to buffer
|
// write some request payload to buffer
|
||||||
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
if err = buf.CopyOnceTimeout(link.Reader, bodyWriter, time.Millisecond*100); err != nil && err != buf.ErrNotTimeoutReader && err != buf.ErrReadTimeout {
|
||||||
return errors.New("failed to write A request payload").Base(err)
|
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
||||||
if err = bufferWriter.SetBuffered(false); err != nil {
|
if err = bufferWriter.SetBuffered(false); err != nil {
|
||||||
return errors.New("failed to flush payload").Base(err)
|
return errors.New("failed to flush payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send header if not sent yet
|
// Send header if not sent yet
|
||||||
if _, err = connWriter.Write([]byte{}); err != nil {
|
if _, err = connWriter.Write([]byte{}); err != nil {
|
||||||
return err
|
return err.(*errors.Error).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
|
if err = buf.Copy(link.Reader, bodyWriter, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to transfer request payload").Base(err)
|
return errors.New("failed to transfer request payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+12
-12
@@ -47,11 +47,11 @@ func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
|
|||||||
for _, user := range config.Users {
|
for _, user := range config.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get trojan user").Base(err)
|
return nil, errors.New("failed to get trojan user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to add user").Base(err)
|
return nil, errors.New("failed to add user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||||||
|
|
||||||
sessionPolicy := s.policyManager.ForLevel(0)
|
sessionPolicy := s.policyManager.ForLevel(0)
|
||||||
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := conn.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err)
|
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
first := buf.FromBytes(make([]byte, buf.Size))
|
first := buf.FromBytes(make([]byte, buf.Size))
|
||||||
@@ -219,7 +219,7 @@ func (s *Server) Process(ctx context.Context, network net.Network, conn stat.Con
|
|||||||
|
|
||||||
destination := clientReader.Target
|
destination := clientReader.Target
|
||||||
if err := conn.SetReadDeadline(time.Time{}); err != nil {
|
if err := conn.SetReadDeadline(time.Time{}); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err)
|
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
inbound := session.InboundFromContext(ctx)
|
inbound := session.InboundFromContext(ctx)
|
||||||
@@ -402,7 +402,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
apfb := napfb[name]
|
apfb := napfb[name]
|
||||||
if apfb == nil {
|
if apfb == nil {
|
||||||
return errors.New(`failed to find the default "name" config`)
|
return errors.New(`failed to find the default "name" config`).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if apfb[alpn] == nil {
|
if apfb[alpn] == nil {
|
||||||
@@ -410,7 +410,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
pfb := apfb[alpn]
|
pfb := apfb[alpn]
|
||||||
if pfb == nil {
|
if pfb == nil {
|
||||||
return errors.New(`failed to find the default "alpn" config`)
|
return errors.New(`failed to find the default "alpn" config`).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
path := ""
|
path := ""
|
||||||
@@ -444,7 +444,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
fb := pfb[path]
|
fb := pfb[path]
|
||||||
if fb == nil {
|
if fb == nil {
|
||||||
return errors.New(`failed to find the default "path" config`)
|
return errors.New(`failed to find the default "path" config`).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
@@ -460,7 +460,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errors.New("failed to dial to " + fb.Dest).Base(err)
|
return errors.New("failed to dial to " + fb.Dest).Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -520,11 +520,11 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
common.Must2(pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)}))
|
common.Must2(pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)}))
|
||||||
}
|
}
|
||||||
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
||||||
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err)
|
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to fallback request payload").Base(err)
|
return errors.New("failed to fallback request payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -534,7 +534,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
getResponse := func() error {
|
getResponse := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to deliver response payload").Base(err)
|
return errors.New("failed to deliver response payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -542,7 +542,7 @@ func (s *Server) fallback(ctx context.Context, err error, sessionPolicy policy.S
|
|||||||
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
||||||
common.Must(common.Interrupt(serverReader))
|
common.Must(common.Interrupt(serverReader))
|
||||||
common.Must(common.Interrupt(serverWriter))
|
common.Must(common.Interrupt(serverWriter))
|
||||||
return errors.New("fallback ends").Base(err)
|
return errors.New("fallback ends").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+4
-33
@@ -37,25 +37,6 @@ type Handler struct {
|
|||||||
downlinkCounter stats.Counter
|
downlinkCounter stats.Counter
|
||||||
}
|
}
|
||||||
|
|
||||||
type tunUDPStatsWriter struct {
|
|
||||||
writer buf.Writer
|
|
||||||
counter stats.Counter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *tunUDPStatsWriter) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|
||||||
for len(mb) > 0 {
|
|
||||||
remaining, packet := buf.SplitFirst(mb)
|
|
||||||
packetSize := packet.Len()
|
|
||||||
if err := w.writer.WriteMultiBuffer(buf.MultiBuffer{packet}); err != nil {
|
|
||||||
buf.ReleaseMulti(remaining)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.counter.Add(int64(packetSize))
|
|
||||||
mb = remaining
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ConnectionHandler interface with the only method that stack is going to push new connections to
|
// ConnectionHandler interface with the only method that stack is going to push new connections to
|
||||||
type ConnectionHandler interface {
|
type ConnectionHandler interface {
|
||||||
HandleConnection(conn net.Conn, destination net.Destination)
|
HandleConnection(conn net.Conn, destination net.Destination)
|
||||||
@@ -123,7 +104,7 @@ func (t *Handler) Start() error {
|
|||||||
iface := updater.Get()
|
iface := updater.Get()
|
||||||
if iface == nil {
|
if iface == nil {
|
||||||
errors.LogInfo(context.Background(), "[tun] falied to set interface > iface == nil")
|
errors.LogInfo(context.Background(), "[tun] falied to set interface > iface == nil")
|
||||||
return errors.New("iface not found")
|
return nil
|
||||||
}
|
}
|
||||||
return c.Control(func(fd uintptr) {
|
return c.Control(func(fd uintptr) {
|
||||||
addrPort, _ := netip.ParseAddrPort(address)
|
addrPort, _ := netip.ParseAddrPort(address)
|
||||||
@@ -190,8 +171,7 @@ func (t *Handler) HandleConnection(conn net.Conn, destination net.Destination) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
source := net.DestinationFromAddr(remote)
|
source := net.DestinationFromAddr(remote)
|
||||||
isUDP := destination.Network == net.Network_UDP
|
if t.uplinkCounter != nil || t.downlinkCounter != nil {
|
||||||
if !isUDP && (t.uplinkCounter != nil || t.downlinkCounter != nil) {
|
|
||||||
conn = &stat.CounterConnection{
|
conn = &stat.CounterConnection{
|
||||||
Connection: conn,
|
Connection: conn,
|
||||||
ReadCounter: t.uplinkCounter,
|
ReadCounter: t.uplinkCounter,
|
||||||
@@ -223,18 +203,9 @@ func (t *Handler) HandleConnection(conn net.Conn, destination net.Destination) {
|
|||||||
})
|
})
|
||||||
errors.LogInfo(ctx, "processing from ", source, " to ", destination)
|
errors.LogInfo(ctx, "processing from ", source, " to ", destination)
|
||||||
|
|
||||||
reader := &buf.TimeoutWrapperReader{Reader: buf.NewReader(conn)}
|
|
||||||
writer := buf.NewWriter(conn)
|
|
||||||
if isUDP {
|
|
||||||
reader.Counter = t.uplinkCounter
|
|
||||||
if t.downlinkCounter != nil {
|
|
||||||
writer = &tunUDPStatsWriter{writer: writer, counter: t.downlinkCounter}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
link := &transport.Link{
|
link := &transport.Link{
|
||||||
Reader: reader,
|
Reader: &buf.TimeoutWrapperReader{Reader: buf.NewReader(conn)},
|
||||||
Writer: writer,
|
Writer: buf.NewWriter(conn),
|
||||||
}
|
}
|
||||||
if err := t.dispatcher.DispatchLink(ctx, destination, link); err != nil {
|
if err := t.dispatcher.DispatchLink(ctx, destination, link); err != nil {
|
||||||
errors.LogError(ctx, errors.New("connection closed").Base(err))
|
errors.LogError(ctx, errors.New("connection closed").Base(err))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
func (a *Account) AsAccount() (protocol.Account, error) {
|
func (a *Account) AsAccount() (protocol.Account, error) {
|
||||||
id, err := uuid.ParseString(a.Id)
|
id, err := uuid.ParseString(a.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse ID").Base(err)
|
return nil, errors.New("failed to parse ID").Base(err).AtError()
|
||||||
}
|
}
|
||||||
return &MemoryAccount{
|
return &MemoryAccount{
|
||||||
ID: protocol.NewID(id),
|
ID: protocol.NewID(id),
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ func init() {
|
|||||||
for _, user := range c.Users {
|
for _, user := range c.Users {
|
||||||
u, err := user.ToMemoryUser()
|
u, err := user.ToMemoryUser()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get VLESS user").Base(err)
|
return nil, errors.New("failed to get VLESS user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
if err := validator.Add(u); err != nil {
|
if err := validator.Add(u); err != nil {
|
||||||
return nil, errors.New("failed to initiate user").Base(err)
|
return nil, errors.New("failed to initiate user").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Val
|
|||||||
}
|
}
|
||||||
handler.decryption = &encryption.ServerInstance{}
|
handler.decryption = &encryption.ServerInstance{}
|
||||||
if err := handler.decryption.Init(nfsSKeysBytes, config.XorMode, config.SecondsFrom, config.SecondsTo, config.Padding); err != nil {
|
if err := handler.decryption.Init(nfsSKeysBytes, config.XorMode, config.SecondsFrom, config.SecondsTo, config.Padding); err != nil {
|
||||||
return nil, errors.New("failed to use decryption").Base(err)
|
return nil, errors.New("failed to use decryption").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ func New(ctx context.Context, config *Config, dc dns.Client, validator vless.Val
|
|||||||
/*
|
/*
|
||||||
if fb.Path != "" {
|
if fb.Path != "" {
|
||||||
if r, err := regexp.Compile(fb.Path); err != nil {
|
if r, err := regexp.Compile(fb.Path); err != nil {
|
||||||
return nil, errors.New("invalid path regexp").Base(err)
|
return nil, errors.New("invalid path regexp").Base(err).AtError()
|
||||||
} else {
|
} else {
|
||||||
handler.regexps[fb.Path] = r
|
handler.regexps[fb.Path] = r
|
||||||
}
|
}
|
||||||
@@ -274,13 +274,13 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
if h.decryption != nil {
|
if h.decryption != nil {
|
||||||
var err error
|
var err error
|
||||||
if connection, err = h.decryption.Handshake(connection, nil); err != nil {
|
if connection, err = h.decryption.Handshake(connection, nil); err != nil {
|
||||||
return errors.New("ML-KEM-768 handshake failed").Base(err)
|
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sessionPolicy := h.policyManager.ForLevel(0)
|
sessionPolicy := h.policyManager.ForLevel(0)
|
||||||
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err)
|
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
first := buf.FromBytes(make([]byte, buf.Size))
|
first := buf.FromBytes(make([]byte, buf.Size))
|
||||||
@@ -352,7 +352,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
apfb := napfb[name]
|
apfb := napfb[name]
|
||||||
if apfb == nil {
|
if apfb == nil {
|
||||||
return errors.New(`failed to find the default "name" config`)
|
return errors.New(`failed to find the default "name" config`).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if apfb[alpn] == nil {
|
if apfb[alpn] == nil {
|
||||||
@@ -360,7 +360,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
pfb := apfb[alpn]
|
pfb := apfb[alpn]
|
||||||
if pfb == nil {
|
if pfb == nil {
|
||||||
return errors.New(`failed to find the default "alpn" config`)
|
return errors.New(`failed to find the default "alpn" config`).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
path := ""
|
path := ""
|
||||||
@@ -369,7 +369,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
if lines := bytes.Split(firstBytes, []byte{'\r', '\n'}); len(lines) > 1 {
|
if lines := bytes.Split(firstBytes, []byte{'\r', '\n'}); len(lines) > 1 {
|
||||||
if s := bytes.Split(lines[0], []byte{' '}); len(s) == 3 {
|
if s := bytes.Split(lines[0], []byte{' '}); len(s) == 3 {
|
||||||
if len(s[0]) < 8 && len(s[1]) > 0 && len(s[2]) == 8 {
|
if len(s[0]) < 8 && len(s[1]) > 0 && len(s[2]) == 8 {
|
||||||
errors.New("realPath = " + string(s[1])).WriteToLog(sid)
|
errors.New("realPath = " + string(s[1])).AtInfo().WriteToLog(sid)
|
||||||
for _, fb := range pfb {
|
for _, fb := range pfb {
|
||||||
if fb.Path != "" && h.regexps[fb.Path].Match(s[1]) {
|
if fb.Path != "" && h.regexps[fb.Path].Match(s[1]) {
|
||||||
path = fb.Path
|
path = fb.Path
|
||||||
@@ -409,7 +409,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
fb := pfb[path]
|
fb := pfb[path]
|
||||||
if fb == nil {
|
if fb == nil {
|
||||||
return errors.New(`failed to find the default "path" config`)
|
return errors.New(`failed to find the default "path" config`).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
@@ -425,7 +425,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errors.New("failed to dial to " + fb.Dest).Base(err)
|
return errors.New("failed to dial to " + fb.Dest).Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -485,11 +485,11 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)})
|
pro.Write([]byte{byte(p1 >> 8), byte(p1), byte(p2 >> 8), byte(p2)})
|
||||||
}
|
}
|
||||||
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
if err := serverWriter.WriteMultiBuffer(buf.MultiBuffer{pro}); err != nil {
|
||||||
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err)
|
return errors.New("failed to set PROXY protocol v", fb.Xver).Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(reader, serverWriter, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to fallback request payload").Base(err)
|
return errors.New("failed to fallback request payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -499,7 +499,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
getResponse := func() error {
|
getResponse := func() error {
|
||||||
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
defer timer.SetTimeout(sessionPolicy.Timeouts.UplinkOnly)
|
||||||
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
if err := buf.Copy(serverReader, writer, buf.UpdateActivity(timer)); err != nil {
|
||||||
return errors.New("failed to deliver response payload").Base(err)
|
return errors.New("failed to deliver response payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -507,7 +507,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
if err := task.Run(ctx, task.OnSuccess(postRequest, task.Close(serverWriter)), task.OnSuccess(getResponse, task.Close(writer))); err != nil {
|
||||||
common.Interrupt(serverReader)
|
common.Interrupt(serverReader)
|
||||||
common.Interrupt(serverWriter)
|
common.Interrupt(serverWriter)
|
||||||
return errors.New("fallback ends").Base(err)
|
return errors.New("fallback ends").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -519,7 +519,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
Status: log.AccessRejected,
|
Status: log.AccessRejected,
|
||||||
Reason: err,
|
Reason: err,
|
||||||
})
|
})
|
||||||
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err)
|
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -555,7 +555,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
inbound.CanSpliceCopy = 2
|
inbound.CanSpliceCopy = 2
|
||||||
switch request.Command {
|
switch request.Command {
|
||||||
case protocol.RequestCommandUDP:
|
case protocol.RequestCommandUDP:
|
||||||
return errors.New(requestAddons.Flow + " doesn't support UDP")
|
return errors.New(requestAddons.Flow + " doesn't support UDP").AtWarning()
|
||||||
case protocol.RequestCommandMux, protocol.RequestCommandRvs:
|
case protocol.RequestCommandMux, protocol.RequestCommandRvs:
|
||||||
inbound.CanSpliceCopy = 3
|
inbound.CanSpliceCopy = 3
|
||||||
fallthrough // we will break Mux connections that contain TCP requests
|
fallthrough // we will break Mux connections that contain TCP requests
|
||||||
@@ -570,7 +570,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
p = uintptr(unsafe.Pointer(commonConn))
|
p = uintptr(unsafe.Pointer(commonConn))
|
||||||
} else if tlsConn, ok := iConn.(*tls.Conn); ok {
|
} else if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||||
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version)
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
|
||||||
}
|
}
|
||||||
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
t = reflect.TypeOf(tlsConn.Conn).Elem()
|
||||||
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
p = uintptr(unsafe.Pointer(tlsConn.Conn))
|
||||||
@@ -578,7 +578,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
t = reflect.TypeOf(realityConn.Conn).Elem()
|
t = reflect.TypeOf(realityConn.Conn).Elem()
|
||||||
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
||||||
} else {
|
} else {
|
||||||
return errors.New("XTLS only supports TLS and REALITY directly for now.")
|
return errors.New("XTLS only supports TLS and REALITY directly for now.").AtWarning()
|
||||||
}
|
}
|
||||||
i, _ := t.FieldByName("input")
|
i, _ := t.FieldByName("input")
|
||||||
r, _ := t.FieldByName("rawInput")
|
r, _ := t.FieldByName("rawInput")
|
||||||
@@ -586,15 +586,15 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
|
rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return errors.New("account " + account.ID.String() + " is not able to use the flow " + requestAddons.Flow)
|
return errors.New("account " + account.ID.String() + " is not able to use the flow " + requestAddons.Flow).AtWarning()
|
||||||
}
|
}
|
||||||
case "":
|
case "":
|
||||||
inbound.CanSpliceCopy = 3
|
inbound.CanSpliceCopy = 3
|
||||||
if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
|
if account.Flow == vless.XRV && (request.Command == protocol.RequestCommandTCP || isMuxAndNotXUDP(request, first)) {
|
||||||
return errors.New("account " + account.ID.String() + " is rejected since the client flow is empty. Note that the pure TLS proxy has certain TLS in TLS characters.")
|
return errors.New("account " + account.ID.String() + " is rejected since the client flow is empty. Note that the pure TLS proxy has certain TLS in TLS characters.").AtWarning()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown request flow " + requestAddons.Flow)
|
return errors.New("unknown request flow " + requestAddons.Flow).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.Command != protocol.RequestCommandMux {
|
if request.Command != protocol.RequestCommandMux {
|
||||||
@@ -617,7 +617,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
|
|
||||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(connection))
|
||||||
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
if err := encoding.EncodeResponseHeader(bufferWriter, request, responseAddons); err != nil {
|
||||||
return errors.New("failed to encode response header").Base(err)
|
return errors.New("failed to encode response header").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil)
|
clientWriter := encoding.EncodeBodyAddons(bufferWriter, request, requestAddons, trafficState, false, ctx, connection, nil)
|
||||||
bufferWriter.SetFlushNext()
|
bufferWriter.SetFlushNext()
|
||||||
@@ -654,11 +654,11 @@ func (r *Reverse) Tag() string {
|
|||||||
func (r *Reverse) NewMux(ctx context.Context, link *transport.Link, observer features.Feature) error {
|
func (r *Reverse) NewMux(ctx context.Context, link *transport.Link, observer features.Feature) error {
|
||||||
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
muxClient, err := mux.NewClientWorker(*link, mux.ClientStrategy{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create mux client worker").Base(err)
|
return errors.New("failed to create mux client worker").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
worker, err := reverse.NewPortalWorker(muxClient)
|
worker, err := reverse.NewPortalWorker(muxClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create portal worker").Base(err)
|
return errors.New("failed to create portal worker").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
r.picker.AddWorker(worker)
|
r.picker.AddWorker(worker)
|
||||||
if burstObs, ok := observer.(extension.BurstObservatory); ok {
|
if burstObs, ok := observer.(extension.BurstObservatory); ok {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
}
|
}
|
||||||
server, err := protocol.NewServerSpecFromPB(config.Vnext)
|
server, err := protocol.NewServerSpecFromPB(config.Vnext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to get server spec").Base(err)
|
return nil, errors.New("failed to get server spec").Base(err).AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
v := core.MustFromContext(ctx)
|
v := core.MustFromContext(ctx)
|
||||||
@@ -93,7 +93,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
}
|
}
|
||||||
handler.encryption = &encryption.ClientInstance{}
|
handler.encryption = &encryption.ClientInstance{}
|
||||||
if err := handler.encryption.Init(nfsPKeysBytes, a.XorMode, a.Seconds, a.Padding); err != nil {
|
if err := handler.encryption.Init(nfsPKeysBytes, a.XorMode, a.Seconds, a.Padding); err != nil {
|
||||||
return nil, errors.New("failed to use encryption").Base(err)
|
return nil, errors.New("failed to use encryption").Base(err).AtError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ func New(ctx context.Context, config *Config) (*Handler, error) {
|
|||||||
if sc := a.Reverse.Sniffing; sc != nil && sc.Enabled {
|
if sc := a.Reverse.Sniffing; sc != nil && sc.Enabled {
|
||||||
request, err := proxymanConfig.BuildSniffingRequest(sc)
|
request, err := proxymanConfig.BuildSniffingRequest(sc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to build reverse sniffing request").Base(err)
|
return nil, errors.New("failed to build reverse sniffing request").Base(err).AtError()
|
||||||
}
|
}
|
||||||
rvsCtx = session.ContextWithContent(rvsCtx, &session.Content{
|
rvsCtx = session.ContextWithContent(rvsCtx, &session.Content{
|
||||||
SniffingRequest: request,
|
SniffingRequest: request,
|
||||||
@@ -149,7 +149,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
if !ob.Target.IsValid() && ob.Target.Address.String() != "v1.rvs.cool" {
|
if !ob.Target.IsValid() && ob.Target.Address.String() != "v1.rvs.cool" {
|
||||||
return errors.New("target not specified")
|
return errors.New("target not specified").AtError()
|
||||||
}
|
}
|
||||||
ob.Name = "vless"
|
ob.Name = "vless"
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
for {
|
for {
|
||||||
connTime := <-h.preConns
|
connTime := <-h.preConns
|
||||||
if connTime == nil {
|
if connTime == nil {
|
||||||
return errors.New("closed handler")
|
return errors.New("closed handler").AtWarning()
|
||||||
}
|
}
|
||||||
if time.Now().Before(connTime.Expire) {
|
if time.Now().Before(connTime.Expire) {
|
||||||
conn = connTime.Conn
|
conn = connTime.Conn
|
||||||
@@ -197,7 +197,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return errors.New("failed to find an available destination").Base(err)
|
return errors.New("failed to find an available destination").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
@@ -209,7 +209,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
if h.encryption != nil {
|
if h.encryption != nil {
|
||||||
var err error
|
var err error
|
||||||
if conn, err = h.encryption.Handshake(conn); err != nil {
|
if conn, err = h.encryption.Handshake(conn); err != nil {
|
||||||
return errors.New("ML-KEM-768 handshake failed").Base(err)
|
return errors.New("ML-KEM-768 handshake failed").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
command = protocol.RequestCommandMux
|
command = protocol.RequestCommandMux
|
||||||
case "v1.rvs.cool":
|
case "v1.rvs.cool":
|
||||||
if target.Network != net.Network_Unknown {
|
if target.Network != net.Network_Unknown {
|
||||||
return errors.New("nice try baby")
|
return errors.New("nice try baby").AtError()
|
||||||
}
|
}
|
||||||
command = protocol.RequestCommandRvs
|
command = protocol.RequestCommandRvs
|
||||||
}
|
}
|
||||||
@@ -256,7 +256,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
switch request.Command {
|
switch request.Command {
|
||||||
case protocol.RequestCommandUDP:
|
case protocol.RequestCommandUDP:
|
||||||
if !allowUDP443 && request.Port == 443 {
|
if !allowUDP443 && request.Port == 443 {
|
||||||
return errors.New("XTLS rejected UDP/443 traffic")
|
return errors.New("XTLS rejected UDP/443 traffic").AtInfo()
|
||||||
}
|
}
|
||||||
case protocol.RequestCommandMux:
|
case protocol.RequestCommandMux:
|
||||||
fallthrough // let server break Mux connections that contain TCP requests
|
fallthrough // let server break Mux connections that contain TCP requests
|
||||||
@@ -279,7 +279,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
t = reflect.TypeOf(realityConn.Conn).Elem()
|
t = reflect.TypeOf(realityConn.Conn).Elem()
|
||||||
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
p = uintptr(unsafe.Pointer(realityConn.Conn))
|
||||||
} else {
|
} else {
|
||||||
return errors.New("XTLS only supports TLS and REALITY directly for now.")
|
return errors.New("XTLS only supports TLS and REALITY directly for now.").AtWarning()
|
||||||
}
|
}
|
||||||
i, _ := t.FieldByName("input")
|
i, _ := t.FieldByName("input")
|
||||||
r, _ := t.FieldByName("rawInput")
|
r, _ := t.FieldByName("rawInput")
|
||||||
@@ -321,7 +321,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
|
bufferWriter := buf.NewBufferedWriter(buf.NewWriter(conn))
|
||||||
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
|
if err := encoding.EncodeRequestHeader(bufferWriter, request, requestAddons); err != nil {
|
||||||
return errors.New("failed to encode request header").Base(err)
|
return errors.New("failed to encode request header").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
// default: serverWriter := bufferWriter
|
// default: serverWriter := bufferWriter
|
||||||
@@ -350,23 +350,23 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
// Flush; bufferWriter.WriteMultiBuffer now is bufferWriter.writer.WriteMultiBuffer
|
||||||
if err := bufferWriter.SetBuffered(false); err != nil {
|
if err := bufferWriter.SetBuffered(false); err != nil {
|
||||||
return errors.New("failed to write A request payload").Base(err)
|
return errors.New("failed to write A request payload").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if requestAddons.Flow == vless.XRV {
|
if requestAddons.Flow == vless.XRV {
|
||||||
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
if tlsConn, ok := iConn.(*tls.Conn); ok {
|
||||||
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
if tlsConn.ConnectionState().Version != gotls.VersionTLS13 {
|
||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version)
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, tlsConn.ConnectionState().Version).AtWarning()
|
||||||
}
|
}
|
||||||
} else if utlsConn, ok := iConn.(*tls.UConn); ok {
|
} else if utlsConn, ok := iConn.(*tls.UConn); ok {
|
||||||
if utlsConn.ConnectionState().Version != utls.VersionTLS13 {
|
if utlsConn.ConnectionState().Version != utls.VersionTLS13 {
|
||||||
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version)
|
return errors.New(`failed to use `+requestAddons.Flow+`, found outer tls version `, utlsConn.ConnectionState().Version).AtWarning()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
err := buf.Copy(clientReader, serverWriter, buf.UpdateActivity(timer))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to transfer request payload").Base(err)
|
return errors.New("failed to transfer request payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicates the end of request payload.
|
// Indicates the end of request payload.
|
||||||
@@ -381,7 +381,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
responseAddons, err := encoding.DecodeResponseHeader(conn, request)
|
responseAddons, err := encoding.DecodeResponseHeader(conn, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to decode response header").Base(err)
|
return errors.New("failed to decode response header").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
// default: serverReader := buf.NewReader(conn)
|
// default: serverReader := buf.NewReader(conn)
|
||||||
@@ -405,7 +405,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to transfer response payload").Base(err)
|
return errors.New("failed to transfer response payload").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -416,7 +416,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
|
if err := task.Run(ctx, postRequest, task.OnSuccess(getResponse, task.Close(clientWriter))); err != nil {
|
||||||
return errors.New("connection ends").Base(err)
|
return errors.New("connection ends").Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (a *MemoryAccount) ToProto() proto.Message {
|
|||||||
func (a *Account) AsAccount() (protocol.Account, error) {
|
func (a *Account) AsAccount() (protocol.Account, error) {
|
||||||
id, err := uuid.ParseString(a.Id)
|
id, err := uuid.ParseString(a.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to parse ID").Base(err)
|
return nil, errors.New("failed to parse ID").Base(err).AtError()
|
||||||
}
|
}
|
||||||
protoID := protocol.NewID(id)
|
protoID := protocol.NewID(id)
|
||||||
var AuthenticatedLength, NoTerminationSignal bool
|
var AuthenticatedLength, NoTerminationSignal bool
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ func (c *ClientSession) DecodeResponseHeader(reader io.Reader) (*protocol.Respon
|
|||||||
defer buffer.Release()
|
defer buffer.Release()
|
||||||
|
|
||||||
if _, err := buffer.ReadFullFrom(c.responseReader, 4); err != nil {
|
if _, err := buffer.ReadFullFrom(c.responseReader, 4); err != nil {
|
||||||
return nil, errors.New("failed to read response header").Base(err)
|
return nil, errors.New("failed to read response header").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
if buffer.Byte(0) != c.responseHeader {
|
if buffer.Byte(0) != c.responseHeader {
|
||||||
|
|||||||
@@ -227,7 +227,7 @@ func transferResponse(timer signal.ActivityUpdater, session *encoding.ServerSess
|
|||||||
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
func (h *Handler) Process(ctx context.Context, network net.Network, connection stat.Connection, dispatcher routing.Dispatcher) error {
|
||||||
sessionPolicy := h.policyManager.ForLevel(0)
|
sessionPolicy := h.policyManager.ForLevel(0)
|
||||||
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
if err := connection.SetReadDeadline(time.Now().Add(sessionPolicy.Timeouts.Handshake)); err != nil {
|
||||||
return errors.New("unable to set read deadline").Base(err)
|
return errors.New("unable to set read deadline").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
iConn := stat.TryUnwrapStatsConn(connection)
|
iConn := stat.TryUnwrapStatsConn(connection)
|
||||||
@@ -247,7 +247,7 @@ func (h *Handler) Process(ctx context.Context, network net.Network, connection s
|
|||||||
Status: log.AccessRejected,
|
Status: log.AccessRejected,
|
||||||
Reason: err,
|
Reason: err,
|
||||||
})
|
})
|
||||||
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err)
|
err = errors.New("invalid request from ", connection.RemoteAddr()).Base(err).AtInfo()
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
outbounds := session.OutboundsFromContext(ctx)
|
outbounds := session.OutboundsFromContext(ctx)
|
||||||
ob := outbounds[len(outbounds)-1]
|
ob := outbounds[len(outbounds)-1]
|
||||||
if !ob.Target.IsValid() {
|
if !ob.Target.IsValid() {
|
||||||
return errors.New("target not specified")
|
return errors.New("target not specified").AtError()
|
||||||
}
|
}
|
||||||
ob.Name = "vmess"
|
ob.Name = "vmess"
|
||||||
ob.CanSpliceCopy = 3
|
ob.CanSpliceCopy = 3
|
||||||
@@ -78,7 +78,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to find an available destination").Base(err)
|
return errors.New("failed to find an available destination").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
|
|
||||||
writer := buf.NewBufferedWriter(buf.NewWriter(conn))
|
writer := buf.NewBufferedWriter(buf.NewWriter(conn))
|
||||||
if err := session.EncodeRequestHeader(request, writer); err != nil {
|
if err := session.EncodeRequestHeader(request, writer); err != nil {
|
||||||
return errors.New("failed to encode request").Base(err)
|
return errors.New("failed to encode request").Base(err).AtWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
bodyWriter, err := session.EncodeRequestBody(request, writer)
|
bodyWriter, err := session.EncodeRequestBody(request, writer)
|
||||||
|
|||||||
+140
-125
@@ -3,6 +3,7 @@ package wireguard
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
gonet "net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -27,10 +28,14 @@ import (
|
|||||||
"github.com/xtls/xray-core/features/stats"
|
"github.com/xtls/xray-core/features/stats"
|
||||||
"github.com/xtls/xray-core/transport"
|
"github.com/xtls/xray-core/transport"
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
"golang.zx2c4.com/wireguard/device"
|
"golang.zx2c4.com/wireguard/device"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type entry struct {
|
||||||
|
got []net.IP
|
||||||
|
time time.Time
|
||||||
|
}
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
conf *DeviceConfig
|
conf *DeviceConfig
|
||||||
policyManager policy.Manager
|
policyManager policy.Manager
|
||||||
@@ -44,6 +49,11 @@ type Handler struct {
|
|||||||
tnet *Net
|
tnet *Net
|
||||||
dev *device.Device
|
dev *device.Device
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
|
// TODO: cache cleanup loop
|
||||||
|
local bool
|
||||||
|
cache map[string]entry
|
||||||
|
cacheMu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClient(ctx context.Context, conf *DeviceConfig) (*Handler, error) {
|
func NewClient(ctx context.Context, conf *DeviceConfig) (*Handler, error) {
|
||||||
@@ -99,10 +109,15 @@ func NewClient(ctx context.Context, conf *DeviceConfig) (*Handler, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local := false
|
||||||
dns := conf.DNS
|
dns := conf.DNS
|
||||||
if len(dns) == 0 {
|
if len(dns) == 0 {
|
||||||
dns = []string{"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"}
|
dns = []string{"1.1.1.1", "1.0.0.1", "2606:4700:4700::1111", "2606:4700:4700::1001"}
|
||||||
}
|
}
|
||||||
|
if len(dns) == 1 && dns[0] == "local" {
|
||||||
|
local = true
|
||||||
|
dns = nil
|
||||||
|
}
|
||||||
dnses := make([]netip.Addr, 0, len(dns))
|
dnses := make([]netip.Addr, 0, len(dns))
|
||||||
for _, dns := range dns {
|
for _, dns := range dns {
|
||||||
dnses = append(dnses, netip.MustParseAddr(dns))
|
dnses = append(dnses, netip.MustParseAddr(dns))
|
||||||
@@ -136,6 +151,9 @@ func NewClient(ctx context.Context, conf *DeviceConfig) (*Handler, error) {
|
|||||||
|
|
||||||
tun: tun,
|
tun: tun,
|
||||||
tnet: tnet,
|
tnet: tnet,
|
||||||
|
|
||||||
|
local: local,
|
||||||
|
cache: make(map[string]entry),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +172,22 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var addr netip.Addr
|
||||||
|
if ob.Target.Address.Family().IsDomain() {
|
||||||
|
ip, err := h.resolveRemote(ob.Target.Address.String())
|
||||||
|
if err != nil {
|
||||||
|
return errors.New("failed to resolve domain").Base(err)
|
||||||
|
}
|
||||||
|
addr, _ = netip.AddrFromSlice(ip)
|
||||||
|
} else {
|
||||||
|
addr, _ = netip.AddrFromSlice(ob.Target.Address.IP())
|
||||||
|
}
|
||||||
|
|
||||||
|
addrPort := netip.AddrPortFrom(addr, ob.Target.Port.Value())
|
||||||
|
if !addrPort.IsValid() {
|
||||||
|
return errors.New("invalid target ", ob.Target)
|
||||||
|
}
|
||||||
|
|
||||||
var newCtx context.Context
|
var newCtx context.Context
|
||||||
var newCancel context.CancelFunc
|
var newCancel context.CancelFunc
|
||||||
if session.TimeoutOnlyFromContext(ctx) {
|
if session.TimeoutOnlyFromContext(ctx) {
|
||||||
@@ -182,10 +216,10 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
var err error
|
var err error
|
||||||
if sessionPolicy.Timeouts.Handshake != 0 {
|
if sessionPolicy.Timeouts.Handshake != 0 {
|
||||||
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, sessionPolicy.Timeouts.Handshake)
|
timeoutCtx, timeoutCancel := context.WithTimeout(ctx, sessionPolicy.Timeouts.Handshake)
|
||||||
conn, err = h.tnet.DialContext(timeoutCtx, "tcp", ob.Target.NetAddr())
|
conn, err = h.tnet.DialContextTCPAddrPort(timeoutCtx, addrPort)
|
||||||
timeoutCancel()
|
timeoutCancel()
|
||||||
} else {
|
} else {
|
||||||
conn, err = h.tnet.Dial("tcp", ob.Target.NetAddr())
|
conn, err = h.tnet.DialContextTCPAddrPort(ctx, addrPort)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create TCP connection").Base(err)
|
return errors.New("failed to create TCP connection").Base(err)
|
||||||
@@ -194,14 +228,15 @@ func (h *Handler) Process(ctx context.Context, link *transport.Link, dialer inte
|
|||||||
reader = buf.NewReader(conn)
|
reader = buf.NewReader(conn)
|
||||||
writer = buf.NewWriter(conn)
|
writer = buf.NewWriter(conn)
|
||||||
case net.Network_UDP:
|
case net.Network_UDP:
|
||||||
conn, err := h.tnet.Dial("udp", ob.Target.NetAddr())
|
conn, err := h.tnet.DialUDPAddrPort(netip.AddrPort{}, addrPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.New("failed to create UDP connection").Base(err)
|
return errors.New("failed to create UDP connection").Base(err)
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
c := &UDPConnClient{
|
c := &udpConnClient{
|
||||||
PacketConn: conn.(*internet.PacketConnWrapper).PacketConn,
|
PacketConn: conn.(*internet.PacketConnWrapper).PacketConn,
|
||||||
Dest: conn.RemoteAddr().(*net.UDPAddr),
|
resolveFunc: h.resolveRemote,
|
||||||
|
dest: gonet.UDPAddrFromAddrPort(addrPort),
|
||||||
}
|
}
|
||||||
reader = c
|
reader = c
|
||||||
writer = c
|
writer = c
|
||||||
@@ -258,26 +293,26 @@ func (h *Handler) init(ctx context.Context) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
conn, err := internet.DialSystem(ctx, dest, h.streamSettings.SocketSettings)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
var pktConn net.PacketConn
|
var pktConn net.PacketConn
|
||||||
if h.streamSettings.FinalMask != nil {
|
switch c := conn.(type) {
|
||||||
conn, err := h.streamSettings.FinalMask.DialUDP(ctx, dest)
|
case *internet.PacketConnWrapper:
|
||||||
|
pktConn = c.PacketConn
|
||||||
|
case *cnc.Connection:
|
||||||
|
pktConn = &internet.FakePacketConn{Conn: c}
|
||||||
|
default:
|
||||||
|
panic(reflect.TypeOf(c))
|
||||||
|
}
|
||||||
|
if h.streamSettings.UdpmaskManager != nil {
|
||||||
|
newConn, err := h.streamSettings.UdpmaskManager.WrapPacketConnClient(pktConn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New("failed to dial to dest").Base(err)
|
pktConn.Close()
|
||||||
}
|
return nil, errors.New("mask err").Base(err)
|
||||||
pktConn = conn.(*finalmask.PacketConnWrapper).PacketConn
|
|
||||||
} else {
|
|
||||||
conn, err := internet.DialSystem(ctx, dest, h.streamSettings.SocketSettings)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to dial to dest").Base(err)
|
|
||||||
}
|
|
||||||
switch c := conn.(type) {
|
|
||||||
case *internet.PacketConnWrapper:
|
|
||||||
pktConn = c.PacketConn
|
|
||||||
case *cnc.Connection:
|
|
||||||
pktConn = &internet.FakePacketConn{Conn: c}
|
|
||||||
default:
|
|
||||||
panic(reflect.TypeOf(c))
|
|
||||||
}
|
}
|
||||||
|
pktConn = newConn
|
||||||
}
|
}
|
||||||
if h.uplinkCounter != nil || h.downlinkCounter != nil {
|
if h.uplinkCounter != nil || h.downlinkCounter != nil {
|
||||||
pktConn = &PacketCounterConnection{
|
pktConn = &PacketCounterConnection{
|
||||||
@@ -336,54 +371,90 @@ func (h *Handler) init(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) resolveLocal(host string) (net.IP, error) {
|
func (h *Handler) resolveLocal(host string) (net.IP, error) {
|
||||||
|
return h.resolveDomain(host, h.conf.DomainStrategy, func(host string) ([]net.IP, uint32, error) {
|
||||||
|
return h.dns.LookupIP(host, dns.IPOption{IPv4Enable: true, IPv6Enable: true})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) resolveRemote(host string) (net.IP, error) {
|
||||||
|
return h.resolveDomain(host, h.conf.DomainStrategy, func(host string) ([]net.IP, uint32, error) {
|
||||||
|
if h.local {
|
||||||
|
return h.dns.LookupIP(host, dns.IPOption{IPv4Enable: true, IPv6Enable: true})
|
||||||
|
}
|
||||||
|
return h.tnet.LookupHost(host)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) resolveDomain(host string, strategy DeviceConfig_DomainStrategy, lookupIP func(host string) ([]net.IP, uint32, error)) (net.IP, error) {
|
||||||
if ip := net.ParseIP(host); ip != nil {
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
return ip, nil
|
return ip, nil
|
||||||
}
|
}
|
||||||
ips, _, err := h.dns.LookupIP(host, dns.IPOption{IPv4Enable: true, IPv6Enable: true})
|
h.cacheMu.Lock()
|
||||||
|
if entry, ok := h.cache[host]; ok {
|
||||||
|
if time.Now().Before(entry.time) {
|
||||||
|
h.cacheMu.Unlock()
|
||||||
|
return entry.got[dice.Roll(len(entry.got))], nil
|
||||||
|
}
|
||||||
|
delete(h.cache, host)
|
||||||
|
}
|
||||||
|
h.cacheMu.Unlock()
|
||||||
|
ips, ttl, err := lookupIP(host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
got := ips
|
if len(ips) == 0 {
|
||||||
if h.streamSettings.SocketSettings != nil {
|
return nil, dns.ErrEmptyResponse
|
||||||
var got4, got6 []net.IP
|
}
|
||||||
for _, ip := range ips {
|
var got4, got6 []net.IP
|
||||||
if ip.To4() != nil {
|
for _, ip := range ips {
|
||||||
got4 = append(got4, ip)
|
if ip.To4() != nil {
|
||||||
} else {
|
got4 = append(got4, ip)
|
||||||
got6 = append(got6, ip)
|
} else {
|
||||||
}
|
got6 = append(got6, ip)
|
||||||
}
|
|
||||||
switch h.streamSettings.SocketSettings.DomainStrategy {
|
|
||||||
case internet.DomainStrategy_AS_IS, internet.DomainStrategy_USE_IP, internet.DomainStrategy_FORCE_IP:
|
|
||||||
got = ips
|
|
||||||
case internet.DomainStrategy_USE_IP4, internet.DomainStrategy_FORCE_IP4:
|
|
||||||
got = got4
|
|
||||||
case internet.DomainStrategy_USE_IP6, internet.DomainStrategy_FORCE_IP6:
|
|
||||||
got = got6
|
|
||||||
case internet.DomainStrategy_USE_IP46, internet.DomainStrategy_FORCE_IP46:
|
|
||||||
got = got4
|
|
||||||
if len(got) == 0 {
|
|
||||||
got = got6
|
|
||||||
}
|
|
||||||
case internet.DomainStrategy_USE_IP64, internet.DomainStrategy_FORCE_IP64:
|
|
||||||
got = got6
|
|
||||||
if len(got) == 0 {
|
|
||||||
got = got4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(got) == 0 {
|
|
||||||
return nil, dns.ErrEmptyResponse
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var got []net.IP
|
||||||
|
switch strategy {
|
||||||
|
case DeviceConfig_FORCE_IP:
|
||||||
|
got = ips
|
||||||
|
return ips[dice.Roll(len(ips))], nil
|
||||||
|
case DeviceConfig_FORCE_IP4:
|
||||||
|
got = got4
|
||||||
|
case DeviceConfig_FORCE_IP6:
|
||||||
|
got = got6
|
||||||
|
case DeviceConfig_FORCE_IP46:
|
||||||
|
got = got4
|
||||||
|
if len(got) == 0 {
|
||||||
|
got = got6
|
||||||
|
}
|
||||||
|
case DeviceConfig_FORCE_IP64:
|
||||||
|
got = got6
|
||||||
|
if len(got) == 0 {
|
||||||
|
got = got4
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic(strategy)
|
||||||
|
}
|
||||||
|
if len(got) == 0 {
|
||||||
|
return nil, dns.ErrEmptyResponse
|
||||||
|
}
|
||||||
|
entry := entry{
|
||||||
|
got: got,
|
||||||
|
time: time.Now().Add(time.Duration(ttl) * time.Second),
|
||||||
|
}
|
||||||
|
h.cacheMu.Lock()
|
||||||
|
h.cache[host] = entry
|
||||||
|
h.cacheMu.Unlock()
|
||||||
return got[dice.Roll(len(got))], nil
|
return got[dice.Roll(len(got))], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type UDPConnClient struct {
|
type udpConnClient struct {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
Dest *net.UDPAddr
|
resolveFunc func(host string) (net.IP, error)
|
||||||
|
dest *net.UDPAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPConnClient) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
func (c *udpConnClient) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
||||||
b := buf.New()
|
b := buf.New()
|
||||||
b.Resize(0, buf.Size)
|
b.Resize(0, buf.Size)
|
||||||
n, addr, err := c.PacketConn.ReadFrom(b.Bytes())
|
n, addr, err := c.PacketConn.ReadFrom(b.Bytes())
|
||||||
@@ -402,13 +473,20 @@ func (c *UDPConnClient) ReadMultiBuffer() (buf.MultiBuffer, error) {
|
|||||||
return buf.MultiBuffer{b}, nil
|
return buf.MultiBuffer{b}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPConnClient) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
func (c *udpConnClient) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
||||||
for i, b := range mb {
|
for i, b := range mb {
|
||||||
dst := c.Dest
|
dst := c.dest
|
||||||
if b.UDP != nil {
|
if b.UDP != nil {
|
||||||
if b.UDP.Address.Family().IsDomain() {
|
if b.UDP.Address.Family().IsDomain() {
|
||||||
if b.UDP.Port != net.Port(dst.Port) {
|
ip, err := c.resolveFunc(b.UDP.Address.String())
|
||||||
dst = &net.UDPAddr{IP: dst.IP, Port: int(b.UDP.Port)}
|
if err != nil {
|
||||||
|
errors.LogErrorInner(context.Background(), err, "drop packet to ", b.UDP, " with size ", len(b.Bytes()))
|
||||||
|
b.Release()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
dst = &net.UDPAddr{
|
||||||
|
IP: ip,
|
||||||
|
Port: int(b.UDP.Port),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dst = b.UDP.RawNetAddr().(*net.UDPAddr)
|
dst = b.UDP.RawNetAddr().(*net.UDPAddr)
|
||||||
@@ -445,66 +523,3 @@ func (c *PacketCounterConnection) WriteTo(p []byte, addr net.Addr) (n int, err e
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
type entry struct {
|
|
||||||
saddr []string
|
|
||||||
deadline time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type cache struct {
|
|
||||||
running bool
|
|
||||||
m map[string]entry
|
|
||||||
mu sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) run() {
|
|
||||||
if c.running {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.running = true
|
|
||||||
if c.m == nil {
|
|
||||||
c.m = make(map[string]entry)
|
|
||||||
}
|
|
||||||
go c.gc()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) gc() {
|
|
||||||
ticker := time.NewTicker(time.Minute)
|
|
||||||
defer ticker.Stop()
|
|
||||||
for now := range ticker.C {
|
|
||||||
c.mu.Lock()
|
|
||||||
for key, entry := range c.m {
|
|
||||||
if now.After(entry.deadline) {
|
|
||||||
delete(c.m, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(c.m) == 0 {
|
|
||||||
c.running = false
|
|
||||||
c.mu.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.mu.Unlock()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) LookupHost(host string) []string {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.run()
|
|
||||||
if entry, ok := c.m[host]; ok {
|
|
||||||
if time.Now().Before(entry.deadline) {
|
|
||||||
return entry.saddr
|
|
||||||
}
|
|
||||||
delete(c.m, host)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *cache) Cache(host string, saddr []string, ttl uint32) {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.m[host] = entry{
|
|
||||||
saddr: saddr,
|
|
||||||
deadline: time.Now().Add(time.Second * time.Duration(ttl)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+102
-26
@@ -22,6 +22,61 @@ const (
|
|||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DeviceConfig_DomainStrategy int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
DeviceConfig_FORCE_IP DeviceConfig_DomainStrategy = 0
|
||||||
|
DeviceConfig_FORCE_IP4 DeviceConfig_DomainStrategy = 1
|
||||||
|
DeviceConfig_FORCE_IP6 DeviceConfig_DomainStrategy = 2
|
||||||
|
DeviceConfig_FORCE_IP46 DeviceConfig_DomainStrategy = 3
|
||||||
|
DeviceConfig_FORCE_IP64 DeviceConfig_DomainStrategy = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
// Enum value maps for DeviceConfig_DomainStrategy.
|
||||||
|
var (
|
||||||
|
DeviceConfig_DomainStrategy_name = map[int32]string{
|
||||||
|
0: "FORCE_IP",
|
||||||
|
1: "FORCE_IP4",
|
||||||
|
2: "FORCE_IP6",
|
||||||
|
3: "FORCE_IP46",
|
||||||
|
4: "FORCE_IP64",
|
||||||
|
}
|
||||||
|
DeviceConfig_DomainStrategy_value = map[string]int32{
|
||||||
|
"FORCE_IP": 0,
|
||||||
|
"FORCE_IP4": 1,
|
||||||
|
"FORCE_IP6": 2,
|
||||||
|
"FORCE_IP46": 3,
|
||||||
|
"FORCE_IP64": 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func (x DeviceConfig_DomainStrategy) Enum() *DeviceConfig_DomainStrategy {
|
||||||
|
p := new(DeviceConfig_DomainStrategy)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DeviceConfig_DomainStrategy) String() string {
|
||||||
|
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DeviceConfig_DomainStrategy) Descriptor() protoreflect.EnumDescriptor {
|
||||||
|
return file_proxy_wireguard_config_proto_enumTypes[0].Descriptor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (DeviceConfig_DomainStrategy) Type() protoreflect.EnumType {
|
||||||
|
return &file_proxy_wireguard_config_proto_enumTypes[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x DeviceConfig_DomainStrategy) Number() protoreflect.EnumNumber {
|
||||||
|
return protoreflect.EnumNumber(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use DeviceConfig_DomainStrategy.Descriptor instead.
|
||||||
|
func (DeviceConfig_DomainStrategy) EnumDescriptor() ([]byte, []int) {
|
||||||
|
return file_proxy_wireguard_config_proto_rawDescGZIP(), []int{1, 0}
|
||||||
|
}
|
||||||
|
|
||||||
type PeerConfig struct {
|
type PeerConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
PublicKey string `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
|
PublicKey string `protobuf:"bytes,1,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
|
||||||
@@ -99,18 +154,19 @@ func (x *PeerConfig) GetAllowedIps() []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DeviceConfig struct {
|
type DeviceConfig struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
SecretKey string `protobuf:"bytes,1,opt,name=secret_key,json=secretKey,proto3" json:"secret_key,omitempty"`
|
SecretKey string `protobuf:"bytes,1,opt,name=secret_key,json=secretKey,proto3" json:"secret_key,omitempty"`
|
||||||
Endpoint []string `protobuf:"bytes,2,rep,name=endpoint,proto3" json:"endpoint,omitempty"`
|
Endpoint []string `protobuf:"bytes,2,rep,name=endpoint,proto3" json:"endpoint,omitempty"`
|
||||||
Peers []*PeerConfig `protobuf:"bytes,3,rep,name=peers,proto3" json:"peers,omitempty"`
|
Peers []*PeerConfig `protobuf:"bytes,3,rep,name=peers,proto3" json:"peers,omitempty"`
|
||||||
Users []*protocol.User `protobuf:"bytes,5,rep,name=users,proto3" json:"users,omitempty"`
|
Users []*protocol.User `protobuf:"bytes,5,rep,name=users,proto3" json:"users,omitempty"`
|
||||||
Mtu int32 `protobuf:"varint,4,opt,name=mtu,proto3" json:"mtu,omitempty"`
|
Mtu int32 `protobuf:"varint,4,opt,name=mtu,proto3" json:"mtu,omitempty"`
|
||||||
Reserved []byte `protobuf:"bytes,6,opt,name=reserved,proto3" json:"reserved,omitempty"`
|
Reserved []byte `protobuf:"bytes,6,opt,name=reserved,proto3" json:"reserved,omitempty"`
|
||||||
IsClient bool `protobuf:"varint,8,opt,name=is_client,json=isClient,proto3" json:"is_client,omitempty"`
|
DomainStrategy DeviceConfig_DomainStrategy `protobuf:"varint,7,opt,name=domain_strategy,json=domainStrategy,proto3,enum=xray.proxy.wireguard.DeviceConfig_DomainStrategy" json:"domain_strategy,omitempty"`
|
||||||
NoKernelTun bool `protobuf:"varint,9,opt,name=no_kernel_tun,json=noKernelTun,proto3" json:"no_kernel_tun,omitempty"`
|
IsClient bool `protobuf:"varint,8,opt,name=is_client,json=isClient,proto3" json:"is_client,omitempty"`
|
||||||
DNS []string `protobuf:"bytes,10,rep,name=DNS,proto3" json:"DNS,omitempty"`
|
NoKernelTun bool `protobuf:"varint,9,opt,name=no_kernel_tun,json=noKernelTun,proto3" json:"no_kernel_tun,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
DNS []string `protobuf:"bytes,10,rep,name=DNS,proto3" json:"DNS,omitempty"`
|
||||||
sizeCache protoimpl.SizeCache
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *DeviceConfig) Reset() {
|
func (x *DeviceConfig) Reset() {
|
||||||
@@ -185,6 +241,13 @@ func (x *DeviceConfig) GetReserved() []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *DeviceConfig) GetDomainStrategy() DeviceConfig_DomainStrategy {
|
||||||
|
if x != nil {
|
||||||
|
return x.DomainStrategy
|
||||||
|
}
|
||||||
|
return DeviceConfig_FORCE_IP
|
||||||
|
}
|
||||||
|
|
||||||
func (x *DeviceConfig) GetIsClient() bool {
|
func (x *DeviceConfig) GetIsClient() bool {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.IsClient
|
return x.IsClient
|
||||||
@@ -220,7 +283,7 @@ const file_proxy_wireguard_config_proto_rawDesc = "" +
|
|||||||
"\n" +
|
"\n" +
|
||||||
"keep_alive\x18\x04 \x01(\tR\tkeepAlive\x12\x1f\n" +
|
"keep_alive\x18\x04 \x01(\tR\tkeepAlive\x12\x1f\n" +
|
||||||
"\vallowed_ips\x18\x05 \x03(\tR\n" +
|
"\vallowed_ips\x18\x05 \x03(\tR\n" +
|
||||||
"allowedIps\"\xb4\x02\n" +
|
"allowedIps\"\xee\x03\n" +
|
||||||
"\fDeviceConfig\x12\x1d\n" +
|
"\fDeviceConfig\x12\x1d\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"secret_key\x18\x01 \x01(\tR\tsecretKey\x12\x1a\n" +
|
"secret_key\x18\x01 \x01(\tR\tsecretKey\x12\x1a\n" +
|
||||||
@@ -228,11 +291,20 @@ const file_proxy_wireguard_config_proto_rawDesc = "" +
|
|||||||
"\x05peers\x18\x03 \x03(\v2 .xray.proxy.wireguard.PeerConfigR\x05peers\x120\n" +
|
"\x05peers\x18\x03 \x03(\v2 .xray.proxy.wireguard.PeerConfigR\x05peers\x120\n" +
|
||||||
"\x05users\x18\x05 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\x12\x10\n" +
|
"\x05users\x18\x05 \x03(\v2\x1a.xray.common.protocol.UserR\x05users\x12\x10\n" +
|
||||||
"\x03mtu\x18\x04 \x01(\x05R\x03mtu\x12\x1a\n" +
|
"\x03mtu\x18\x04 \x01(\x05R\x03mtu\x12\x1a\n" +
|
||||||
"\breserved\x18\x06 \x01(\fR\breserved\x12\x1b\n" +
|
"\breserved\x18\x06 \x01(\fR\breserved\x12Z\n" +
|
||||||
|
"\x0fdomain_strategy\x18\a \x01(\x0e21.xray.proxy.wireguard.DeviceConfig.DomainStrategyR\x0edomainStrategy\x12\x1b\n" +
|
||||||
"\tis_client\x18\b \x01(\bR\bisClient\x12\"\n" +
|
"\tis_client\x18\b \x01(\bR\bisClient\x12\"\n" +
|
||||||
"\rno_kernel_tun\x18\t \x01(\bR\vnoKernelTun\x12\x10\n" +
|
"\rno_kernel_tun\x18\t \x01(\bR\vnoKernelTun\x12\x10\n" +
|
||||||
"\x03DNS\x18\n" +
|
"\x03DNS\x18\n" +
|
||||||
" \x03(\tR\x03DNSB^\n" +
|
" \x03(\tR\x03DNS\"\\\n" +
|
||||||
|
"\x0eDomainStrategy\x12\f\n" +
|
||||||
|
"\bFORCE_IP\x10\x00\x12\r\n" +
|
||||||
|
"\tFORCE_IP4\x10\x01\x12\r\n" +
|
||||||
|
"\tFORCE_IP6\x10\x02\x12\x0e\n" +
|
||||||
|
"\n" +
|
||||||
|
"FORCE_IP46\x10\x03\x12\x0e\n" +
|
||||||
|
"\n" +
|
||||||
|
"FORCE_IP64\x10\x04B^\n" +
|
||||||
"\x18com.xray.proxy.wireguardP\x01Z)github.com/xtls/xray-core/proxy/wireguard\xaa\x02\x14Xray.Proxy.WireGuardb\x06proto3"
|
"\x18com.xray.proxy.wireguardP\x01Z)github.com/xtls/xray-core/proxy/wireguard\xaa\x02\x14Xray.Proxy.WireGuardb\x06proto3"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -247,20 +319,23 @@ func file_proxy_wireguard_config_proto_rawDescGZIP() []byte {
|
|||||||
return file_proxy_wireguard_config_proto_rawDescData
|
return file_proxy_wireguard_config_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var file_proxy_wireguard_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||||
var file_proxy_wireguard_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
var file_proxy_wireguard_config_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
var file_proxy_wireguard_config_proto_goTypes = []any{
|
var file_proxy_wireguard_config_proto_goTypes = []any{
|
||||||
(*PeerConfig)(nil), // 0: xray.proxy.wireguard.PeerConfig
|
(DeviceConfig_DomainStrategy)(0), // 0: xray.proxy.wireguard.DeviceConfig.DomainStrategy
|
||||||
(*DeviceConfig)(nil), // 1: xray.proxy.wireguard.DeviceConfig
|
(*PeerConfig)(nil), // 1: xray.proxy.wireguard.PeerConfig
|
||||||
(*protocol.User)(nil), // 2: xray.common.protocol.User
|
(*DeviceConfig)(nil), // 2: xray.proxy.wireguard.DeviceConfig
|
||||||
|
(*protocol.User)(nil), // 3: xray.common.protocol.User
|
||||||
}
|
}
|
||||||
var file_proxy_wireguard_config_proto_depIdxs = []int32{
|
var file_proxy_wireguard_config_proto_depIdxs = []int32{
|
||||||
0, // 0: xray.proxy.wireguard.DeviceConfig.peers:type_name -> xray.proxy.wireguard.PeerConfig
|
1, // 0: xray.proxy.wireguard.DeviceConfig.peers:type_name -> xray.proxy.wireguard.PeerConfig
|
||||||
2, // 1: xray.proxy.wireguard.DeviceConfig.users:type_name -> xray.common.protocol.User
|
3, // 1: xray.proxy.wireguard.DeviceConfig.users:type_name -> xray.common.protocol.User
|
||||||
2, // [2:2] is the sub-list for method output_type
|
0, // 2: xray.proxy.wireguard.DeviceConfig.domain_strategy:type_name -> xray.proxy.wireguard.DeviceConfig.DomainStrategy
|
||||||
2, // [2:2] is the sub-list for method input_type
|
3, // [3:3] is the sub-list for method output_type
|
||||||
2, // [2:2] is the sub-list for extension type_name
|
3, // [3:3] is the sub-list for method input_type
|
||||||
2, // [2:2] is the sub-list for extension extendee
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
0, // [0:2] is the sub-list for field type_name
|
3, // [3:3] is the sub-list for extension extendee
|
||||||
|
0, // [0:3] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proxy_wireguard_config_proto_init() }
|
func init() { file_proxy_wireguard_config_proto_init() }
|
||||||
@@ -273,13 +348,14 @@ func file_proxy_wireguard_config_proto_init() {
|
|||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_wireguard_config_proto_rawDesc), len(file_proxy_wireguard_config_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proxy_wireguard_config_proto_rawDesc), len(file_proxy_wireguard_config_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 1,
|
||||||
NumMessages: 2,
|
NumMessages: 2,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
GoTypes: file_proxy_wireguard_config_proto_goTypes,
|
GoTypes: file_proxy_wireguard_config_proto_goTypes,
|
||||||
DependencyIndexes: file_proxy_wireguard_config_proto_depIdxs,
|
DependencyIndexes: file_proxy_wireguard_config_proto_depIdxs,
|
||||||
|
EnumInfos: file_proxy_wireguard_config_proto_enumTypes,
|
||||||
MessageInfos: file_proxy_wireguard_config_proto_msgTypes,
|
MessageInfos: file_proxy_wireguard_config_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_proxy_wireguard_config_proto = out.File
|
File_proxy_wireguard_config_proto = out.File
|
||||||
|
|||||||
@@ -17,6 +17,13 @@ message PeerConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message DeviceConfig {
|
message DeviceConfig {
|
||||||
|
enum DomainStrategy {
|
||||||
|
FORCE_IP = 0;
|
||||||
|
FORCE_IP4 = 1;
|
||||||
|
FORCE_IP6 = 2;
|
||||||
|
FORCE_IP46 = 3;
|
||||||
|
FORCE_IP64 = 4;
|
||||||
|
}
|
||||||
string secret_key = 1;
|
string secret_key = 1;
|
||||||
repeated string endpoint = 2;
|
repeated string endpoint = 2;
|
||||||
repeated PeerConfig peers = 3;
|
repeated PeerConfig peers = 3;
|
||||||
@@ -24,6 +31,7 @@ message DeviceConfig {
|
|||||||
int32 mtu = 4;
|
int32 mtu = 4;
|
||||||
|
|
||||||
bytes reserved = 6;
|
bytes reserved = 6;
|
||||||
|
DomainStrategy domain_strategy = 7;
|
||||||
bool is_client = 8;
|
bool is_client = 8;
|
||||||
bool no_kernel_tun = 9;
|
bool no_kernel_tun = 9;
|
||||||
repeated string DNS = 10;
|
repeated string DNS = 10;
|
||||||
|
|||||||
+14
-159
@@ -15,8 +15,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
@@ -44,7 +42,6 @@ type netTun struct {
|
|||||||
events chan tun.Event
|
events chan tun.Event
|
||||||
notifyHandle *channel.NotificationHandle
|
notifyHandle *channel.NotificationHandle
|
||||||
incomingPacket chan *buffer.View
|
incomingPacket chan *buffer.View
|
||||||
closed chan struct{}
|
|
||||||
mtu int
|
mtu int
|
||||||
dnsServers []netip.Addr
|
dnsServers []netip.Addr
|
||||||
hasV4, hasV6 bool
|
hasV4, hasV6 bool
|
||||||
@@ -61,7 +58,6 @@ func CreateNetTUN(localAddresses, dnsServers []netip.Addr, mtu int, handleLocal
|
|||||||
stack: stack.New(opts),
|
stack: stack.New(opts),
|
||||||
events: make(chan tun.Event, 10),
|
events: make(chan tun.Event, 10),
|
||||||
incomingPacket: make(chan *buffer.View),
|
incomingPacket: make(chan *buffer.View),
|
||||||
closed: make(chan struct{}),
|
|
||||||
dnsServers: dnsServers,
|
dnsServers: dnsServers,
|
||||||
mtu: mtu,
|
mtu: mtu,
|
||||||
}
|
}
|
||||||
@@ -128,15 +124,12 @@ func (tun *netTun) Events() <-chan tun.Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tun *netTun) Read(buf [][]byte, sizes []int, offset int) (int, error) {
|
func (tun *netTun) Read(buf [][]byte, sizes []int, offset int) (int, error) {
|
||||||
var view *buffer.View
|
view, ok := <-tun.incomingPacket
|
||||||
select {
|
if !ok {
|
||||||
case view = <-tun.incomingPacket:
|
|
||||||
case <-tun.closed:
|
|
||||||
return 0, os.ErrClosed
|
return 0, os.ErrClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := view.Read(buf[0][offset:])
|
n, err := view.Read(buf[0][offset:])
|
||||||
view.Release()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@@ -173,11 +166,7 @@ func (tun *netTun) WriteNotify() {
|
|||||||
view := pkt.ToView()
|
view := pkt.ToView()
|
||||||
pkt.DecRef()
|
pkt.DecRef()
|
||||||
|
|
||||||
select {
|
tun.incomingPacket <- view
|
||||||
case tun.incomingPacket <- view:
|
|
||||||
case <-tun.closed:
|
|
||||||
view.Release()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tun *netTun) Close() error {
|
func (tun *netTun) Close() error {
|
||||||
@@ -190,9 +179,8 @@ func (tun *netTun) Close() error {
|
|||||||
close(tun.events)
|
close(tun.events)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we don't close incomingPacket, because WriteNotify may be mid-send on it (DNS lookup) and would panic.
|
if tun.incomingPacket != nil {
|
||||||
if tun.closed != nil {
|
close(tun.incomingPacket)
|
||||||
close(tun.closed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -231,7 +219,6 @@ type Net struct {
|
|||||||
DialUDPAddrPort func(laddr, raddr netip.AddrPort) (net.Conn, error)
|
DialUDPAddrPort func(laddr, raddr netip.AddrPort) (net.Conn, error)
|
||||||
dnsServers []netip.Addr
|
dnsServers []netip.Addr
|
||||||
hasV4, hasV6 bool
|
hasV4, hasV6 bool
|
||||||
cache cache
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertToFullAddr(endpoint netip.AddrPort) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) {
|
func convertToFullAddr(endpoint netip.AddrPort) (tcpip.FullAddress, tcpip.NetworkProtocolNumber) {
|
||||||
@@ -259,12 +246,9 @@ var (
|
|||||||
errServerTemporarilyMisbehaving = errors.New("server misbehaving")
|
errServerTemporarilyMisbehaving = errors.New("server misbehaving")
|
||||||
errCanceled = errors.New("operation was canceled")
|
errCanceled = errors.New("operation was canceled")
|
||||||
errTimeout = errors.New("i/o timeout")
|
errTimeout = errors.New("i/o timeout")
|
||||||
errNumericPort = errors.New("port must be numeric")
|
|
||||||
errNoSuitableAddress = errors.New("no suitable address found")
|
|
||||||
errMissingAddress = errors.New("missing address")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (net *Net) LookupHost(host string) (addrs []string, err error) {
|
func (net *Net) LookupHost(host string) (addrs []net.IP, ttl uint32, err error) {
|
||||||
return net.LookupContextHost(context.Background(), host)
|
return net.LookupContextHost(context.Background(), host)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -583,12 +567,9 @@ func (tnet *Net) tryOneName(ctx context.Context, name string, qtype dnsmessage.T
|
|||||||
return dnsmessage.Parser{}, "", lastErr
|
return dnsmessage.Parser{}, "", lastErr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string, error) {
|
func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]net.IP, uint32, error) {
|
||||||
if saddr := tnet.cache.LookupHost(host); saddr != nil {
|
|
||||||
return saddr, nil
|
|
||||||
}
|
|
||||||
if host == "" || (!tnet.hasV6 && !tnet.hasV4) {
|
if host == "" || (!tnet.hasV6 && !tnet.hasV4) {
|
||||||
return nil, &net.DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
|
return nil, 0, &net.DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
|
||||||
}
|
}
|
||||||
zlen := len(host)
|
zlen := len(host)
|
||||||
if strings.IndexByte(host, ':') != -1 {
|
if strings.IndexByte(host, ':') != -1 {
|
||||||
@@ -597,11 +578,11 @@ func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ip, err := netip.ParseAddr(host[:zlen]); err == nil {
|
if ip, err := netip.ParseAddr(host[:zlen]); err == nil {
|
||||||
return []string{ip.String()}, nil
|
return []net.IP{ip.AsSlice()}, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isDomainName(host) {
|
if !isDomainName(host) {
|
||||||
return nil, &net.DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
|
return nil, 0, &net.DNSError{Err: errNoSuchHost.Error(), Name: host, IsNotFound: true}
|
||||||
}
|
}
|
||||||
type result struct {
|
type result struct {
|
||||||
p dnsmessage.Parser
|
p dnsmessage.Parser
|
||||||
@@ -702,137 +683,11 @@ func (tnet *Net) LookupContextHost(ctx context.Context, host string) ([]string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(addrs) == 0 && lastErr != nil {
|
if len(addrs) == 0 && lastErr != nil {
|
||||||
return nil, lastErr
|
return nil, 0, lastErr
|
||||||
}
|
}
|
||||||
saddrs := make([]string, 0, len(addrs))
|
ips := make([]net.IP, 0, len(addrs))
|
||||||
for _, ip := range addrs {
|
for _, ip := range addrs {
|
||||||
saddrs = append(saddrs, ip.String())
|
ips = append(ips, ip.AsSlice())
|
||||||
}
|
}
|
||||||
tnet.cache.Cache(host, saddrs, ttl)
|
return ips, ttl, nil
|
||||||
return saddrs, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) {
|
|
||||||
if deadline.IsZero() {
|
|
||||||
return deadline, nil
|
|
||||||
}
|
|
||||||
timeRemaining := deadline.Sub(now)
|
|
||||||
if timeRemaining <= 0 {
|
|
||||||
return time.Time{}, errTimeout
|
|
||||||
}
|
|
||||||
timeout := timeRemaining / time.Duration(addrsRemaining)
|
|
||||||
const saneMinimum = 2 * time.Second
|
|
||||||
if timeout < saneMinimum {
|
|
||||||
if timeRemaining < saneMinimum {
|
|
||||||
timeout = timeRemaining
|
|
||||||
} else {
|
|
||||||
timeout = saneMinimum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return now.Add(timeout), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var protoSplitter = regexp.MustCompile(`^(tcp|udp|ping)(4|6)?$`)
|
|
||||||
|
|
||||||
func (tnet *Net) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
|
|
||||||
if ctx == nil {
|
|
||||||
panic("nil context")
|
|
||||||
}
|
|
||||||
var acceptV4, acceptV6 bool
|
|
||||||
matches := protoSplitter.FindStringSubmatch(network)
|
|
||||||
if matches == nil {
|
|
||||||
return nil, &net.OpError{Op: "dial", Err: net.UnknownNetworkError(network)}
|
|
||||||
} else if len(matches[2]) == 0 {
|
|
||||||
acceptV4 = true
|
|
||||||
acceptV6 = true
|
|
||||||
} else {
|
|
||||||
acceptV4 = matches[2][0] == '4'
|
|
||||||
acceptV6 = !acceptV4
|
|
||||||
}
|
|
||||||
var host string
|
|
||||||
var port int
|
|
||||||
if matches[1] == "ping" {
|
|
||||||
host = address
|
|
||||||
} else {
|
|
||||||
var sport string
|
|
||||||
var err error
|
|
||||||
host, sport, err = net.SplitHostPort(address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &net.OpError{Op: "dial", Err: err}
|
|
||||||
}
|
|
||||||
port, err = strconv.Atoi(sport)
|
|
||||||
if err != nil || port < 0 || port > 65535 {
|
|
||||||
return nil, &net.OpError{Op: "dial", Err: errNumericPort}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
allAddr, err := tnet.LookupContextHost(ctx, host)
|
|
||||||
if err != nil {
|
|
||||||
return nil, &net.OpError{Op: "dial", Err: err}
|
|
||||||
}
|
|
||||||
var addrs []netip.AddrPort
|
|
||||||
for _, addr := range allAddr {
|
|
||||||
ip, err := netip.ParseAddr(addr)
|
|
||||||
if err == nil && ((ip.Is4() && acceptV4) || (ip.Is6() && acceptV6)) {
|
|
||||||
addrs = append(addrs, netip.AddrPortFrom(ip, uint16(port)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(addrs) == 0 && len(allAddr) != 0 {
|
|
||||||
return nil, &net.OpError{Op: "dial", Err: errNoSuitableAddress}
|
|
||||||
}
|
|
||||||
|
|
||||||
var firstErr error
|
|
||||||
for i, addr := range addrs {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
err := ctx.Err()
|
|
||||||
if err == context.Canceled {
|
|
||||||
err = errCanceled
|
|
||||||
} else if err == context.DeadlineExceeded {
|
|
||||||
err = errTimeout
|
|
||||||
}
|
|
||||||
return nil, &net.OpError{Op: "dial", Err: err}
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
dialCtx := ctx
|
|
||||||
if deadline, hasDeadline := ctx.Deadline(); hasDeadline {
|
|
||||||
partialDeadline, err := partialDeadline(time.Now(), deadline, len(addrs)-i)
|
|
||||||
if err != nil {
|
|
||||||
if firstErr == nil {
|
|
||||||
firstErr = &net.OpError{Op: "dial", Err: err}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if partialDeadline.Before(deadline) {
|
|
||||||
var cancel context.CancelFunc
|
|
||||||
dialCtx, cancel = context.WithDeadline(ctx, partialDeadline)
|
|
||||||
defer cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var c net.Conn
|
|
||||||
switch matches[1] {
|
|
||||||
case "tcp":
|
|
||||||
c, err = tnet.DialContextTCPAddrPort(dialCtx, addr)
|
|
||||||
case "udp":
|
|
||||||
c, err = tnet.DialUDPAddrPort(netip.AddrPort{}, addr)
|
|
||||||
case "ping":
|
|
||||||
err = errors.New("not support")
|
|
||||||
// c, err = tnet.DialPingAddr(netip.Addr{}, addr.Addr())
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
return c, nil
|
|
||||||
}
|
|
||||||
if firstErr == nil {
|
|
||||||
firstErr = err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if firstErr == nil {
|
|
||||||
firstErr = &net.OpError{Op: "dial", Err: errMissingAddress}
|
|
||||||
}
|
|
||||||
return nil, firstErr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tnet *Net) Dial(network, address string) (net.Conn, error) {
|
|
||||||
return tnet.DialContext(context.Background(), network, address)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,16 +258,18 @@ func (s *Server) Start() error {
|
|||||||
return errors.New("address is domain")
|
return errors.New("address is domain")
|
||||||
}
|
}
|
||||||
listenFunc := func() (net.PacketConn, error) {
|
listenFunc := func() (net.PacketConn, error) {
|
||||||
var pktConn net.PacketConn
|
pktConn, err := internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: s.src.Address.IP(), Port: int(s.src.Port)}, s.streamSettings.SocketSettings)
|
||||||
var err error
|
|
||||||
if s.streamSettings.FinalMask != nil {
|
|
||||||
pktConn, err = s.streamSettings.FinalMask.ListenPacket(context.Background(), &net.UDPAddr{IP: s.src.Address.IP(), Port: int(s.src.Port)})
|
|
||||||
} else {
|
|
||||||
pktConn, err = internet.ListenSystemPacket(context.Background(), &net.UDPAddr{IP: s.src.Address.IP(), Port: int(s.src.Port)}, s.streamSettings.SocketSettings)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if s.streamSettings.UdpmaskManager != nil {
|
||||||
|
newConn, err := s.streamSettings.UdpmaskManager.WrapPacketConnServer(pktConn)
|
||||||
|
if err != nil {
|
||||||
|
pktConn.Close()
|
||||||
|
return nil, errors.New("mask err").Base(err)
|
||||||
|
}
|
||||||
|
pktConn = newConn
|
||||||
|
}
|
||||||
if s.uplinkCounter != nil || s.downlinkCounter != nil {
|
if s.uplinkCounter != nil || s.downlinkCounter != nil {
|
||||||
pktConn = &PacketCounterConnection{
|
pktConn = &PacketCounterConnection{
|
||||||
PacketConn: pktConn,
|
PacketConn: pktConn,
|
||||||
|
|||||||
@@ -1,468 +0,0 @@
|
|||||||
package scenarios
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
gotls "crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
go_errors "errors"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"net/netip"
|
|
||||||
"net/url"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"sync/atomic"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/apernet/quic-go"
|
|
||||||
"github.com/apernet/quic-go/http3"
|
|
||||||
"golang.org/x/net/http2"
|
|
||||||
"golang.org/x/net/http2/hpack"
|
|
||||||
"golang.org/x/sync/errgroup"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv4"
|
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/network/ipv6"
|
|
||||||
|
|
||||||
"github.com/xtls/xray-core/app/log"
|
|
||||||
"github.com/xtls/xray-core/app/proxyman"
|
|
||||||
"github.com/xtls/xray-core/common"
|
|
||||||
clog "github.com/xtls/xray-core/common/log"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/common/protocol"
|
|
||||||
"github.com/xtls/xray-core/common/protocol/tls/cert"
|
|
||||||
"github.com/xtls/xray-core/common/serial"
|
|
||||||
core "github.com/xtls/xray-core/core"
|
|
||||||
"github.com/xtls/xray-core/proxy/dokodemo"
|
|
||||||
"github.com/xtls/xray-core/proxy/masque"
|
|
||||||
"github.com/xtls/xray-core/proxy/wireguard"
|
|
||||||
"github.com/xtls/xray-core/testing/servers/tcp"
|
|
||||||
"github.com/xtls/xray-core/testing/servers/udp"
|
|
||||||
"github.com/xtls/xray-core/transport/internet"
|
|
||||||
transmasque "github.com/xtls/xray-core/transport/internet/masque"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/masque/connectip"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/tls"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
masqueServerV4 = netip.MustParseAddr("10.13.0.1")
|
|
||||||
masqueServerV6 = netip.MustParseAddr("fd13::1")
|
|
||||||
masqueClientV4 = netip.MustParsePrefix("10.13.0.2/32")
|
|
||||||
masqueClientV6 = netip.MustParsePrefix("fd13::2/128")
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
masqueEchoPort = 7
|
|
||||||
masqueAuthorization = "Basic dTpw"
|
|
||||||
)
|
|
||||||
|
|
||||||
func startMasqueServer(t *testing.T, h2 bool) (net.Port, [32]byte) {
|
|
||||||
dev, _, gstack, err := wireguard.CreateNetTUN([]netip.Addr{masqueServerV4, masqueServerV6}, nil, transmasque.MinPacketSize, false)
|
|
||||||
common.Must(err)
|
|
||||||
t.Cleanup(func() { dev.Close() })
|
|
||||||
|
|
||||||
for _, addr := range []netip.Addr{masqueServerV4, masqueServerV6} {
|
|
||||||
proto := ipv4.ProtocolNumber
|
|
||||||
if addr.Is6() {
|
|
||||||
proto = ipv6.ProtocolNumber
|
|
||||||
}
|
|
||||||
local := tcpip.FullAddress{NIC: 1, Addr: tcpip.AddrFromSlice(addr.AsSlice()), Port: masqueEchoPort}
|
|
||||||
l, err := gonet.ListenTCP(gstack, local, proto)
|
|
||||||
common.Must(err)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
c, err := l.Accept()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go func() {
|
|
||||||
defer c.Close()
|
|
||||||
b := make([]byte, 2048)
|
|
||||||
for {
|
|
||||||
n, err := c.Read(b)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := c.Write(xor(b[:n])); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
u, err := gonet.DialUDP(gstack, &local, nil, proto)
|
|
||||||
common.Must(err)
|
|
||||||
go func() {
|
|
||||||
b := make([]byte, 2048)
|
|
||||||
for {
|
|
||||||
n, addr, err := u.ReadFrom(b)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
u.WriteTo(xor(b[:n]), addr)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
var current atomic.Pointer[connectip.Conn]
|
|
||||||
go func() {
|
|
||||||
bufs := [][]byte{make([]byte, transmasque.MinPacketSize)}
|
|
||||||
sizes := []int{0}
|
|
||||||
for {
|
|
||||||
if _, err := dev.Read(bufs, sizes, 0); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if conn := current.Load(); conn != nil {
|
|
||||||
if icmp, _ := conn.WritePacket(bufs[0][:sizes[0]]); len(icmp) > 0 {
|
|
||||||
go dev.Write([][]byte{icmp}, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
handler := func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if r.URL.Path != transmasque.DefaultPath {
|
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if r.Header.Get("Authorization") != masqueAuthorization {
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req, err := connectip.ParseProxyRequest(r)
|
|
||||||
if err != nil {
|
|
||||||
var perr *connectip.ProxyRequestParseError
|
|
||||||
if go_errors.As(err, &perr) {
|
|
||||||
w.WriteHeader(perr.HTTPStatus)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
conn, err := (&connectip.Proxy{}).Proxy(w, req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
common.Must(conn.AssignAddresses([]netip.Prefix{masqueClientV4, masqueClientV6}))
|
|
||||||
common.Must(conn.AdvertiseRoute([]connectip.IPRoute{
|
|
||||||
{StartIP: netip.IPv4Unspecified(), EndIP: netip.AddrFrom4([4]byte{255, 255, 255, 255})},
|
|
||||||
{StartIP: netip.IPv6Unspecified(), EndIP: netip.AddrFrom16([16]byte{0: 0xff, 1: 0xff, 2: 0xff, 3: 0xff, 4: 0xff, 5: 0xff, 6: 0xff, 7: 0xff, 8: 0xff, 9: 0xff, 10: 0xff, 11: 0xff, 12: 0xff, 13: 0xff, 14: 0xff, 15: 0xff})},
|
|
||||||
}))
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
ar, err := conn.ReceiveAddressRequest(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
assigned := make([]netip.Prefix, len(ar.Prefixes))
|
|
||||||
for i, p := range ar.Prefixes {
|
|
||||||
if p.Addr().Is4() {
|
|
||||||
assigned[i] = masqueClientV4
|
|
||||||
} else {
|
|
||||||
assigned[i] = masqueClientV6
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ar.Respond(assigned, nil)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
current.Store(conn)
|
|
||||||
b := make([]byte, 2048)
|
|
||||||
for {
|
|
||||||
n, err := conn.ReadPacket(b)
|
|
||||||
if err != nil {
|
|
||||||
if go_errors.Is(err, io.ErrShortBuffer) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
dev.Write([][]byte{b[:n]}, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
certificate, certHash := cert.MustGenerate(nil, cert.CommonName("localhost"))
|
|
||||||
key := common.Must2(x509.ParsePKCS8PrivateKey(certificate.PrivateKey))
|
|
||||||
tlsConfig := &gotls.Config{
|
|
||||||
Certificates: []gotls.Certificate{{Certificate: [][]byte{certificate.Certificate}, PrivateKey: key}},
|
|
||||||
NextProtos: []string{http3.NextProtoH3},
|
|
||||||
}
|
|
||||||
if h2 {
|
|
||||||
tlsConfig.NextProtos = []string{http2.NextProtoTLS}
|
|
||||||
ln := common.Must2(gotls.Listen("tcp", "127.0.0.1:0", tlsConfig))
|
|
||||||
t.Cleanup(func() { ln.Close() })
|
|
||||||
go serveHTTP2(ln, http.HandlerFunc(handler))
|
|
||||||
return net.Port(ln.Addr().(*net.TCPAddr).Port), certHash
|
|
||||||
}
|
|
||||||
pktConn := common.Must2(net.ListenUDP("udp", &net.UDPAddr{IP: net.LocalHostIP.IP()}))
|
|
||||||
tr := &quic.Transport{Conn: pktConn}
|
|
||||||
ln := common.Must2(tr.ListenEarly(tlsConfig, &quic.Config{EnableDatagrams: true, InitialPacketSize: 1350}))
|
|
||||||
server := &http3.Server{Handler: http.HandlerFunc(handler), EnableDatagrams: true}
|
|
||||||
go server.ServeListener(ln)
|
|
||||||
t.Cleanup(func() {
|
|
||||||
server.Close()
|
|
||||||
ln.Close()
|
|
||||||
tr.Close()
|
|
||||||
pktConn.Close()
|
|
||||||
})
|
|
||||||
|
|
||||||
return net.Port(pktConn.LocalAddr().(*net.UDPAddr).Port), certHash
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveHTTP2(ln net.Listener, handler http.Handler) {
|
|
||||||
for {
|
|
||||||
conn, err := ln.Accept()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
go serveHTTP2Conn(conn, handler)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type http2ServerConn struct {
|
|
||||||
mu sync.Mutex
|
|
||||||
fr *http2.Framer
|
|
||||||
hbuf bytes.Buffer
|
|
||||||
henc *hpack.Encoder
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *http2ServerConn) write(f func(*http2.Framer) error) error {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
return f(c.fr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *http2ServerConn) writeHeaders(streamID uint32, status int, header http.Header) error {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
c.hbuf.Reset()
|
|
||||||
c.henc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(status)})
|
|
||||||
for k, vv := range header {
|
|
||||||
for _, v := range vv {
|
|
||||||
c.henc.WriteField(hpack.HeaderField{Name: strings.ToLower(k), Value: v})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return c.fr.WriteHeaders(http2.HeadersFrameParam{StreamID: streamID, BlockFragment: c.hbuf.Bytes(), EndHeaders: true})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *http2ServerConn) writeData(streamID uint32, endStream bool, data []byte) error {
|
|
||||||
c.mu.Lock()
|
|
||||||
defer c.mu.Unlock()
|
|
||||||
for {
|
|
||||||
n := min(len(data), 16384)
|
|
||||||
if err := c.fr.WriteData(streamID, endStream && n == len(data), data[:n]); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if data = data[n:]; len(data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func serveHTTP2Conn(conn net.Conn, handler http.Handler) {
|
|
||||||
defer conn.Close()
|
|
||||||
br := bufio.NewReader(conn)
|
|
||||||
preface := make([]byte, len(http2.ClientPreface))
|
|
||||||
if _, err := io.ReadFull(br, preface); err != nil || string(preface) != http2.ClientPreface {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sc := &http2ServerConn{fr: http2.NewFramer(conn, br)}
|
|
||||||
sc.henc = hpack.NewEncoder(&sc.hbuf)
|
|
||||||
sc.fr.ReadMetaHeaders = hpack.NewDecoder(4096, nil)
|
|
||||||
if err := sc.write(func(fr *http2.Framer) error {
|
|
||||||
if err := fr.WriteSettings(
|
|
||||||
http2.Setting{ID: http2.SettingEnableConnectProtocol, Val: 1},
|
|
||||||
http2.Setting{ID: http2.SettingInitialWindowSize, Val: 1 << 30},
|
|
||||||
); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return fr.WriteWindowUpdate(0, 1<<30)
|
|
||||||
}); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bodies := make(map[uint32]*io.PipeWriter)
|
|
||||||
defer func() {
|
|
||||||
for _, body := range bodies {
|
|
||||||
body.Close()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
for {
|
|
||||||
f, err := sc.fr.ReadFrame()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch f := f.(type) {
|
|
||||||
case *http2.SettingsFrame:
|
|
||||||
if !f.IsAck() {
|
|
||||||
err = sc.write((*http2.Framer).WriteSettingsAck)
|
|
||||||
}
|
|
||||||
case *http2.PingFrame:
|
|
||||||
if !f.IsAck() {
|
|
||||||
err = sc.write(func(fr *http2.Framer) error { return fr.WritePing(true, f.Data) })
|
|
||||||
}
|
|
||||||
case *http2.MetaHeadersFrame:
|
|
||||||
u, err := url.ParseRequestURI(f.PseudoValue("path"))
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pr, pw := io.Pipe()
|
|
||||||
bodies[f.StreamID] = pw
|
|
||||||
req := &http.Request{
|
|
||||||
Method: f.PseudoValue("method"),
|
|
||||||
URL: u,
|
|
||||||
Proto: "HTTP/2.0",
|
|
||||||
ProtoMajor: 2,
|
|
||||||
Header: http.Header{},
|
|
||||||
Host: f.PseudoValue("authority"),
|
|
||||||
Body: pr,
|
|
||||||
}
|
|
||||||
for _, hf := range f.RegularFields() {
|
|
||||||
req.Header.Add(hf.Name, hf.Value)
|
|
||||||
}
|
|
||||||
if protocol := f.PseudoValue("protocol"); protocol != "" {
|
|
||||||
req.Header.Set(":protocol", protocol)
|
|
||||||
}
|
|
||||||
streamID := f.StreamID
|
|
||||||
w := &http2ResponseWriter{conn: sc, streamID: streamID, header: http.Header{}}
|
|
||||||
go func() {
|
|
||||||
handler.ServeHTTP(w, req)
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
sc.writeData(streamID, true, nil)
|
|
||||||
}()
|
|
||||||
case *http2.DataFrame:
|
|
||||||
if body := bodies[f.StreamID]; body != nil {
|
|
||||||
if _, err := body.Write(f.Data()); err != nil || f.StreamEnded() {
|
|
||||||
body.Close()
|
|
||||||
delete(bodies, f.StreamID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *http2.RSTStreamFrame:
|
|
||||||
if body := bodies[f.StreamID]; body != nil {
|
|
||||||
body.CloseWithError(http2.StreamError{StreamID: f.StreamID, Code: f.ErrCode})
|
|
||||||
delete(bodies, f.StreamID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type http2ResponseWriter struct {
|
|
||||||
conn *http2ServerConn
|
|
||||||
streamID uint32
|
|
||||||
header http.Header
|
|
||||||
wroteHeader bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *http2ResponseWriter) Header() http.Header { return w.header }
|
|
||||||
|
|
||||||
func (w *http2ResponseWriter) WriteHeader(code int) {
|
|
||||||
if !w.wroteHeader {
|
|
||||||
w.wroteHeader = true
|
|
||||||
w.conn.writeHeaders(w.streamID, code, w.header)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *http2ResponseWriter) Write(b []byte) (int, error) {
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
if err := w.conn.writeData(w.streamID, false, b); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return len(b), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *http2ResponseWriter) Flush() {}
|
|
||||||
|
|
||||||
func TestMasque(t *testing.T) {
|
|
||||||
testMasque(t, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMasqueHTTP2(t *testing.T) {
|
|
||||||
testMasque(t, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testMasque(t *testing.T, h2 bool) {
|
|
||||||
serverPort, certHash := startMasqueServer(t, h2)
|
|
||||||
|
|
||||||
tcpPort := tcp.PickPort()
|
|
||||||
tcp6Port := tcp.PickPort()
|
|
||||||
udpPort := udp.PickPort()
|
|
||||||
dokodemoTo := func(port net.Port, addr netip.Addr, network net.Network) *core.InboundHandlerConfig {
|
|
||||||
return &core.InboundHandlerConfig{
|
|
||||||
ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
|
|
||||||
PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(port)}},
|
|
||||||
Listen: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
}),
|
|
||||||
ProxySettings: serial.ToTypedMessage(&dokodemo.Config{
|
|
||||||
RewriteAddress: net.NewIPOrDomain(net.IPAddress(addr.AsSlice())),
|
|
||||||
RewritePort: masqueEchoPort,
|
|
||||||
AllowedNetworks: []net.Network{network},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tlsConfig := &tls.Config{
|
|
||||||
ServerName: "localhost",
|
|
||||||
PinnedPeerCertSha256: [][]byte{certHash[:]},
|
|
||||||
}
|
|
||||||
if h2 {
|
|
||||||
tlsConfig.NextProtocol = []string{http2.NextProtoTLS}
|
|
||||||
}
|
|
||||||
clientConfig := &core.Config{
|
|
||||||
App: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(&log.Config{
|
|
||||||
ErrorLogLevel: clog.Severity_Debug,
|
|
||||||
ErrorLogType: log.LogType_Console,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
Inbound: []*core.InboundHandlerConfig{
|
|
||||||
dokodemoTo(tcpPort, masqueServerV4, net.Network_TCP),
|
|
||||||
dokodemoTo(tcp6Port, masqueServerV6, net.Network_TCP),
|
|
||||||
dokodemoTo(udpPort, masqueServerV4, net.Network_UDP),
|
|
||||||
},
|
|
||||||
Outbound: []*core.OutboundHandlerConfig{
|
|
||||||
{
|
|
||||||
ProxySettings: serial.ToTypedMessage(&masque.ClientConfig{
|
|
||||||
Server: &protocol.ServerEndpoint{
|
|
||||||
Address: net.NewIPOrDomain(net.LocalHostIP),
|
|
||||||
Port: uint32(serverPort),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{
|
|
||||||
StreamSettings: &internet.StreamConfig{
|
|
||||||
ProtocolName: "masque",
|
|
||||||
TransportSettings: []*internet.TransportConfig{
|
|
||||||
{
|
|
||||||
ProtocolName: "masque",
|
|
||||||
Settings: serial.ToTypedMessage(&transmasque.Config{
|
|
||||||
Path: transmasque.DefaultPath,
|
|
||||||
Headers: map[string]string{"Authorization": masqueAuthorization},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SecurityType: serial.GetMessageType(&tls.Config{}),
|
|
||||||
SecuritySettings: []*serial.TypedMessage{
|
|
||||||
serial.ToTypedMessage(tlsConfig),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
servers, err := InitializeServerConfigs(clientConfig)
|
|
||||||
common.Must(err)
|
|
||||||
defer CloseAllServers(servers)
|
|
||||||
|
|
||||||
var errg errgroup.Group
|
|
||||||
for range 3 {
|
|
||||||
errg.Go(testTCPConn(tcpPort, 1024*1024, time.Second*20))
|
|
||||||
}
|
|
||||||
errg.Go(testTCPConn(tcp6Port, 1024*1024, time.Second*20))
|
|
||||||
errg.Go(testUDPConn(udpPort, 1024, time.Second*5))
|
|
||||||
if err := errg.Wait(); err != nil {
|
|
||||||
t.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -65,7 +65,6 @@ func TestWireguard(t *testing.T) {
|
|||||||
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
ProxySettings: serial.ToTypedMessage(&freedom.Config{
|
||||||
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
FinalRules: []*freedom.FinalRuleConfig{{Action: freedom.RuleAction_Allow}},
|
||||||
}),
|
}),
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -105,7 +104,6 @@ func TestWireguard(t *testing.T) {
|
|||||||
AllowedIps: []string{"0.0.0.0/0", "::0/0"},
|
AllowedIps: []string{"0.0.0.0/0", "::0/0"},
|
||||||
}},
|
}},
|
||||||
}),
|
}),
|
||||||
SenderSettings: serial.ToTypedMessage(&proxyman.SenderConfig{}),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ var strategy = [11][3]byte{
|
|||||||
|
|
||||||
func RegisterProtocolConfigCreator(name string, creator ConfigCreator) error {
|
func RegisterProtocolConfigCreator(name string, creator ConfigCreator) error {
|
||||||
if _, found := globalTransportConfigCreatorCache[name]; found {
|
if _, found := globalTransportConfigCreatorCache[name]; found {
|
||||||
return errors.New("protocol ", name, " is already registered")
|
return errors.New("protocol ", name, " is already registered").AtError()
|
||||||
}
|
}
|
||||||
globalTransportConfigCreatorCache[name] = creator
|
globalTransportConfigCreatorCache[name] = creator
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+138
-63
@@ -206,7 +206,7 @@ func (x SocketConfig_TProxyMode) Number() protoreflect.EnumNumber {
|
|||||||
|
|
||||||
// Deprecated: Use SocketConfig_TProxyMode.Descriptor instead.
|
// Deprecated: Use SocketConfig_TProxyMode.Descriptor instead.
|
||||||
func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) {
|
func (SocketConfig_TProxyMode) EnumDescriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{4, 0}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{5, 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
type TransportConfig struct {
|
type TransportConfig struct {
|
||||||
@@ -382,6 +382,66 @@ func (x *StreamConfig) GetSocketSettings() *SocketConfig {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UdpHop struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
Ports []uint32 `protobuf:"varint,1,rep,packed,name=ports,proto3" json:"ports,omitempty"`
|
||||||
|
IntervalMin int64 `protobuf:"varint,2,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
|
||||||
|
IntervalMax int64 `protobuf:"varint,3,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *UdpHop) Reset() {
|
||||||
|
*x = UdpHop{}
|
||||||
|
mi := &file_transport_internet_config_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *UdpHop) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*UdpHop) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *UdpHop) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_transport_internet_config_proto_msgTypes[2]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use UdpHop.ProtoReflect.Descriptor instead.
|
||||||
|
func (*UdpHop) Descriptor() ([]byte, []int) {
|
||||||
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *UdpHop) GetPorts() []uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Ports
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *UdpHop) GetIntervalMin() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.IntervalMin
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *UdpHop) GetIntervalMax() int64 {
|
||||||
|
if x != nil {
|
||||||
|
return x.IntervalMax
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
type QuicParams struct {
|
type QuicParams struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"`
|
Congestion string `protobuf:"bytes,1,opt,name=congestion,proto3" json:"congestion,omitempty"`
|
||||||
@@ -389,24 +449,25 @@ type QuicParams struct {
|
|||||||
BrutalUp uint64 `protobuf:"varint,3,opt,name=brutal_up,json=brutalUp,proto3" json:"brutal_up,omitempty"`
|
BrutalUp uint64 `protobuf:"varint,3,opt,name=brutal_up,json=brutalUp,proto3" json:"brutal_up,omitempty"`
|
||||||
BrutalDown uint64 `protobuf:"varint,4,opt,name=brutal_down,json=brutalDown,proto3" json:"brutal_down,omitempty"`
|
BrutalDown uint64 `protobuf:"varint,4,opt,name=brutal_down,json=brutalDown,proto3" json:"brutal_down,omitempty"`
|
||||||
BrutalDisableLossCompensation bool `protobuf:"varint,5,opt,name=brutal_disable_loss_compensation,json=brutalDisableLossCompensation,proto3" json:"brutal_disable_loss_compensation,omitempty"`
|
BrutalDisableLossCompensation bool `protobuf:"varint,5,opt,name=brutal_disable_loss_compensation,json=brutalDisableLossCompensation,proto3" json:"brutal_disable_loss_compensation,omitempty"`
|
||||||
InitStreamReceiveWindow uint64 `protobuf:"varint,6,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
|
UdpHop *UdpHop `protobuf:"bytes,6,opt,name=udp_hop,json=udpHop,proto3" json:"udp_hop,omitempty"`
|
||||||
MaxStreamReceiveWindow uint64 `protobuf:"varint,7,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
|
InitStreamReceiveWindow uint64 `protobuf:"varint,7,opt,name=init_stream_receive_window,json=initStreamReceiveWindow,proto3" json:"init_stream_receive_window,omitempty"`
|
||||||
InitConnReceiveWindow uint64 `protobuf:"varint,8,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
|
MaxStreamReceiveWindow uint64 `protobuf:"varint,8,opt,name=max_stream_receive_window,json=maxStreamReceiveWindow,proto3" json:"max_stream_receive_window,omitempty"`
|
||||||
MaxConnReceiveWindow uint64 `protobuf:"varint,9,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
|
InitConnReceiveWindow uint64 `protobuf:"varint,9,opt,name=init_conn_receive_window,json=initConnReceiveWindow,proto3" json:"init_conn_receive_window,omitempty"`
|
||||||
MaxIdleTimeout int64 `protobuf:"varint,10,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
|
MaxConnReceiveWindow uint64 `protobuf:"varint,10,opt,name=max_conn_receive_window,json=maxConnReceiveWindow,proto3" json:"max_conn_receive_window,omitempty"`
|
||||||
KeepAlivePeriod int64 `protobuf:"varint,11,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
|
MaxIdleTimeout int64 `protobuf:"varint,11,opt,name=max_idle_timeout,json=maxIdleTimeout,proto3" json:"max_idle_timeout,omitempty"`
|
||||||
DisablePathMtuDiscovery bool `protobuf:"varint,12,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
|
KeepAlivePeriod int64 `protobuf:"varint,12,opt,name=keep_alive_period,json=keepAlivePeriod,proto3" json:"keep_alive_period,omitempty"`
|
||||||
DisableChromeParrot bool `protobuf:"varint,13,opt,name=disable_chrome_parrot,json=disableChromeParrot,proto3" json:"disable_chrome_parrot,omitempty"`
|
DisablePathMtuDiscovery bool `protobuf:"varint,13,opt,name=disable_path_mtu_discovery,json=disablePathMtuDiscovery,proto3" json:"disable_path_mtu_discovery,omitempty"`
|
||||||
DisableGSO bool `protobuf:"varint,14,opt,name=disableGSO,proto3" json:"disableGSO,omitempty"`
|
DisableChromeParrot bool `protobuf:"varint,14,opt,name=disable_chrome_parrot,json=disableChromeParrot,proto3" json:"disable_chrome_parrot,omitempty"`
|
||||||
MaxIncomingStreams int64 `protobuf:"varint,15,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"`
|
DisableGSO bool `protobuf:"varint,15,opt,name=disableGSO,proto3" json:"disableGSO,omitempty"`
|
||||||
DisableStatelessReset bool `protobuf:"varint,16,opt,name=disable_stateless_reset,json=disableStatelessReset,proto3" json:"disable_stateless_reset,omitempty"`
|
MaxIncomingStreams int64 `protobuf:"varint,16,opt,name=max_incoming_streams,json=maxIncomingStreams,proto3" json:"max_incoming_streams,omitempty"`
|
||||||
|
DisableStatelessReset bool `protobuf:"varint,17,opt,name=disable_stateless_reset,json=disableStatelessReset,proto3" json:"disable_stateless_reset,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QuicParams) Reset() {
|
func (x *QuicParams) Reset() {
|
||||||
*x = QuicParams{}
|
*x = QuicParams{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[2]
|
mi := &file_transport_internet_config_proto_msgTypes[3]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -418,7 +479,7 @@ func (x *QuicParams) String() string {
|
|||||||
func (*QuicParams) ProtoMessage() {}
|
func (*QuicParams) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *QuicParams) ProtoReflect() protoreflect.Message {
|
func (x *QuicParams) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[2]
|
mi := &file_transport_internet_config_proto_msgTypes[3]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -431,7 +492,7 @@ func (x *QuicParams) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use QuicParams.ProtoReflect.Descriptor instead.
|
// Deprecated: Use QuicParams.ProtoReflect.Descriptor instead.
|
||||||
func (*QuicParams) Descriptor() ([]byte, []int) {
|
func (*QuicParams) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{2}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{3}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *QuicParams) GetCongestion() string {
|
func (x *QuicParams) GetCongestion() string {
|
||||||
@@ -469,6 +530,13 @@ func (x *QuicParams) GetBrutalDisableLossCompensation() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *QuicParams) GetUdpHop() *UdpHop {
|
||||||
|
if x != nil {
|
||||||
|
return x.UdpHop
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (x *QuicParams) GetInitStreamReceiveWindow() uint64 {
|
func (x *QuicParams) GetInitStreamReceiveWindow() uint64 {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.InitStreamReceiveWindow
|
return x.InitStreamReceiveWindow
|
||||||
@@ -560,7 +628,7 @@ type CustomSockopt struct {
|
|||||||
|
|
||||||
func (x *CustomSockopt) Reset() {
|
func (x *CustomSockopt) Reset() {
|
||||||
*x = CustomSockopt{}
|
*x = CustomSockopt{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[3]
|
mi := &file_transport_internet_config_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -572,7 +640,7 @@ func (x *CustomSockopt) String() string {
|
|||||||
func (*CustomSockopt) ProtoMessage() {}
|
func (*CustomSockopt) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
|
func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[3]
|
mi := &file_transport_internet_config_proto_msgTypes[4]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -585,7 +653,7 @@ func (x *CustomSockopt) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead.
|
// Deprecated: Use CustomSockopt.ProtoReflect.Descriptor instead.
|
||||||
func (*CustomSockopt) Descriptor() ([]byte, []int) {
|
func (*CustomSockopt) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{3}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *CustomSockopt) GetSystem() string {
|
func (x *CustomSockopt) GetSystem() string {
|
||||||
@@ -665,7 +733,7 @@ type SocketConfig struct {
|
|||||||
|
|
||||||
func (x *SocketConfig) Reset() {
|
func (x *SocketConfig) Reset() {
|
||||||
*x = SocketConfig{}
|
*x = SocketConfig{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[4]
|
mi := &file_transport_internet_config_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -677,7 +745,7 @@ func (x *SocketConfig) String() string {
|
|||||||
func (*SocketConfig) ProtoMessage() {}
|
func (*SocketConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *SocketConfig) ProtoReflect() protoreflect.Message {
|
func (x *SocketConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[4]
|
mi := &file_transport_internet_config_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -690,7 +758,7 @@ func (x *SocketConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use SocketConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*SocketConfig) Descriptor() ([]byte, []int) {
|
func (*SocketConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{4}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *SocketConfig) GetMark() int32 {
|
func (x *SocketConfig) GetMark() int32 {
|
||||||
@@ -852,7 +920,7 @@ type HappyEyeballsConfig struct {
|
|||||||
|
|
||||||
func (x *HappyEyeballsConfig) Reset() {
|
func (x *HappyEyeballsConfig) Reset() {
|
||||||
*x = HappyEyeballsConfig{}
|
*x = HappyEyeballsConfig{}
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[5]
|
mi := &file_transport_internet_config_proto_msgTypes[6]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@@ -864,7 +932,7 @@ func (x *HappyEyeballsConfig) String() string {
|
|||||||
func (*HappyEyeballsConfig) ProtoMessage() {}
|
func (*HappyEyeballsConfig) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
|
func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_transport_internet_config_proto_msgTypes[5]
|
mi := &file_transport_internet_config_proto_msgTypes[6]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@@ -877,7 +945,7 @@ func (x *HappyEyeballsConfig) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead.
|
// Deprecated: Use HappyEyeballsConfig.ProtoReflect.Descriptor instead.
|
||||||
func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) {
|
func (*HappyEyeballsConfig) Descriptor() ([]byte, []int) {
|
||||||
return file_transport_internet_config_proto_rawDescGZIP(), []int{5}
|
return file_transport_internet_config_proto_rawDescGZIP(), []int{6}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool {
|
func (x *HappyEyeballsConfig) GetPrioritizeIpv6() bool {
|
||||||
@@ -928,7 +996,11 @@ const file_transport_internet_config_proto_rawDesc = "" +
|
|||||||
"\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" +
|
"\btcpmasks\x18\v \x03(\v2 .xray.common.serial.TypedMessageR\btcpmasks\x12D\n" +
|
||||||
"\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" +
|
"\vquic_params\x18\f \x01(\v2#.xray.transport.internet.QuicParamsR\n" +
|
||||||
"quicParams\x12N\n" +
|
"quicParams\x12N\n" +
|
||||||
"\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"\x8d\x06\n" +
|
"\x0fsocket_settings\x18\x06 \x01(\v2%.xray.transport.internet.SocketConfigR\x0esocketSettings\"d\n" +
|
||||||
|
"\x06UdpHop\x12\x14\n" +
|
||||||
|
"\x05ports\x18\x01 \x03(\rR\x05ports\x12!\n" +
|
||||||
|
"\finterval_min\x18\x02 \x01(\x03R\vintervalMin\x12!\n" +
|
||||||
|
"\finterval_max\x18\x03 \x01(\x03R\vintervalMax\"\xc7\x06\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"QuicParams\x12\x1e\n" +
|
"QuicParams\x12\x1e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
@@ -939,21 +1011,22 @@ const file_transport_internet_config_proto_rawDesc = "" +
|
|||||||
"\tbrutal_up\x18\x03 \x01(\x04R\bbrutalUp\x12\x1f\n" +
|
"\tbrutal_up\x18\x03 \x01(\x04R\bbrutalUp\x12\x1f\n" +
|
||||||
"\vbrutal_down\x18\x04 \x01(\x04R\n" +
|
"\vbrutal_down\x18\x04 \x01(\x04R\n" +
|
||||||
"brutalDown\x12G\n" +
|
"brutalDown\x12G\n" +
|
||||||
" brutal_disable_loss_compensation\x18\x05 \x01(\bR\x1dbrutalDisableLossCompensation\x12;\n" +
|
" brutal_disable_loss_compensation\x18\x05 \x01(\bR\x1dbrutalDisableLossCompensation\x128\n" +
|
||||||
"\x1ainit_stream_receive_window\x18\x06 \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
|
"\audp_hop\x18\x06 \x01(\v2\x1f.xray.transport.internet.UdpHopR\x06udpHop\x12;\n" +
|
||||||
"\x19max_stream_receive_window\x18\a \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
|
"\x1ainit_stream_receive_window\x18\a \x01(\x04R\x17initStreamReceiveWindow\x129\n" +
|
||||||
"\x18init_conn_receive_window\x18\b \x01(\x04R\x15initConnReceiveWindow\x125\n" +
|
"\x19max_stream_receive_window\x18\b \x01(\x04R\x16maxStreamReceiveWindow\x127\n" +
|
||||||
"\x17max_conn_receive_window\x18\t \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
|
"\x18init_conn_receive_window\x18\t \x01(\x04R\x15initConnReceiveWindow\x125\n" +
|
||||||
"\x10max_idle_timeout\x18\n" +
|
"\x17max_conn_receive_window\x18\n" +
|
||||||
" \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
|
" \x01(\x04R\x14maxConnReceiveWindow\x12(\n" +
|
||||||
"\x11keep_alive_period\x18\v \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
|
"\x10max_idle_timeout\x18\v \x01(\x03R\x0emaxIdleTimeout\x12*\n" +
|
||||||
"\x1adisable_path_mtu_discovery\x18\f \x01(\bR\x17disablePathMtuDiscovery\x122\n" +
|
"\x11keep_alive_period\x18\f \x01(\x03R\x0fkeepAlivePeriod\x12;\n" +
|
||||||
"\x15disable_chrome_parrot\x18\r \x01(\bR\x13disableChromeParrot\x12\x1e\n" +
|
"\x1adisable_path_mtu_discovery\x18\r \x01(\bR\x17disablePathMtuDiscovery\x122\n" +
|
||||||
|
"\x15disable_chrome_parrot\x18\x0e \x01(\bR\x13disableChromeParrot\x12\x1e\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"disableGSO\x18\x0e \x01(\bR\n" +
|
"disableGSO\x18\x0f \x01(\bR\n" +
|
||||||
"disableGSO\x120\n" +
|
"disableGSO\x120\n" +
|
||||||
"\x14max_incoming_streams\x18\x0f \x01(\x03R\x12maxIncomingStreams\x126\n" +
|
"\x14max_incoming_streams\x18\x10 \x01(\x03R\x12maxIncomingStreams\x126\n" +
|
||||||
"\x17disable_stateless_reset\x18\x10 \x01(\bR\x15disableStatelessReset\"\x93\x01\n" +
|
"\x17disable_stateless_reset\x18\x11 \x01(\bR\x15disableStatelessReset\"\x93\x01\n" +
|
||||||
"\rCustomSockopt\x12\x16\n" +
|
"\rCustomSockopt\x12\x16\n" +
|
||||||
"\x06system\x18\x01 \x01(\tR\x06system\x12\x18\n" +
|
"\x06system\x18\x01 \x01(\tR\x06system\x12\x18\n" +
|
||||||
"\anetwork\x18\x02 \x01(\tR\anetwork\x12\x14\n" +
|
"\anetwork\x18\x02 \x01(\tR\anetwork\x12\x14\n" +
|
||||||
@@ -1037,39 +1110,41 @@ func file_transport_internet_config_proto_rawDescGZIP() []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
var file_transport_internet_config_proto_enumTypes = make([]protoimpl.EnumInfo, 3)
|
||||||
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
var file_transport_internet_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||||
var file_transport_internet_config_proto_goTypes = []any{
|
var file_transport_internet_config_proto_goTypes = []any{
|
||||||
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
|
(DomainStrategy)(0), // 0: xray.transport.internet.DomainStrategy
|
||||||
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy
|
(AddressPortStrategy)(0), // 1: xray.transport.internet.AddressPortStrategy
|
||||||
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode
|
(SocketConfig_TProxyMode)(0), // 2: xray.transport.internet.SocketConfig.TProxyMode
|
||||||
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig
|
(*TransportConfig)(nil), // 3: xray.transport.internet.TransportConfig
|
||||||
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig
|
(*StreamConfig)(nil), // 4: xray.transport.internet.StreamConfig
|
||||||
(*QuicParams)(nil), // 5: xray.transport.internet.QuicParams
|
(*UdpHop)(nil), // 5: xray.transport.internet.UdpHop
|
||||||
(*CustomSockopt)(nil), // 6: xray.transport.internet.CustomSockopt
|
(*QuicParams)(nil), // 6: xray.transport.internet.QuicParams
|
||||||
(*SocketConfig)(nil), // 7: xray.transport.internet.SocketConfig
|
(*CustomSockopt)(nil), // 7: xray.transport.internet.CustomSockopt
|
||||||
(*HappyEyeballsConfig)(nil), // 8: xray.transport.internet.HappyEyeballsConfig
|
(*SocketConfig)(nil), // 8: xray.transport.internet.SocketConfig
|
||||||
(*serial.TypedMessage)(nil), // 9: xray.common.serial.TypedMessage
|
(*HappyEyeballsConfig)(nil), // 9: xray.transport.internet.HappyEyeballsConfig
|
||||||
(*net.IPOrDomain)(nil), // 10: xray.common.net.IPOrDomain
|
(*serial.TypedMessage)(nil), // 10: xray.common.serial.TypedMessage
|
||||||
|
(*net.IPOrDomain)(nil), // 11: xray.common.net.IPOrDomain
|
||||||
}
|
}
|
||||||
var file_transport_internet_config_proto_depIdxs = []int32{
|
var file_transport_internet_config_proto_depIdxs = []int32{
|
||||||
9, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
|
10, // 0: xray.transport.internet.TransportConfig.settings:type_name -> xray.common.serial.TypedMessage
|
||||||
10, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
|
11, // 1: xray.transport.internet.StreamConfig.address:type_name -> xray.common.net.IPOrDomain
|
||||||
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
|
3, // 2: xray.transport.internet.StreamConfig.transport_settings:type_name -> xray.transport.internet.TransportConfig
|
||||||
9, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
|
10, // 3: xray.transport.internet.StreamConfig.security_settings:type_name -> xray.common.serial.TypedMessage
|
||||||
9, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage
|
10, // 4: xray.transport.internet.StreamConfig.udpmasks:type_name -> xray.common.serial.TypedMessage
|
||||||
9, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage
|
10, // 5: xray.transport.internet.StreamConfig.tcpmasks:type_name -> xray.common.serial.TypedMessage
|
||||||
5, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams
|
6, // 6: xray.transport.internet.StreamConfig.quic_params:type_name -> xray.transport.internet.QuicParams
|
||||||
7, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
|
8, // 7: xray.transport.internet.StreamConfig.socket_settings:type_name -> xray.transport.internet.SocketConfig
|
||||||
2, // 8: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
|
5, // 8: xray.transport.internet.QuicParams.udp_hop:type_name -> xray.transport.internet.UdpHop
|
||||||
0, // 9: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
2, // 9: xray.transport.internet.SocketConfig.tproxy:type_name -> xray.transport.internet.SocketConfig.TProxyMode
|
||||||
6, // 10: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
|
0, // 10: xray.transport.internet.SocketConfig.domain_strategy:type_name -> xray.transport.internet.DomainStrategy
|
||||||
1, // 11: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy
|
7, // 11: xray.transport.internet.SocketConfig.customSockopt:type_name -> xray.transport.internet.CustomSockopt
|
||||||
8, // 12: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig
|
1, // 12: xray.transport.internet.SocketConfig.address_port_strategy:type_name -> xray.transport.internet.AddressPortStrategy
|
||||||
13, // [13:13] is the sub-list for method output_type
|
9, // 13: xray.transport.internet.SocketConfig.happy_eyeballs:type_name -> xray.transport.internet.HappyEyeballsConfig
|
||||||
13, // [13:13] is the sub-list for method input_type
|
14, // [14:14] is the sub-list for method output_type
|
||||||
13, // [13:13] is the sub-list for extension type_name
|
14, // [14:14] is the sub-list for method input_type
|
||||||
13, // [13:13] is the sub-list for extension extendee
|
14, // [14:14] is the sub-list for extension type_name
|
||||||
0, // [0:13] is the sub-list for field type_name
|
14, // [14:14] is the sub-list for extension extendee
|
||||||
|
0, // [0:14] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_transport_internet_config_proto_init() }
|
func init() { file_transport_internet_config_proto_init() }
|
||||||
@@ -1083,7 +1158,7 @@ func file_transport_internet_config_proto_init() {
|
|||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_config_proto_rawDesc), len(file_transport_internet_config_proto_rawDesc)),
|
||||||
NumEnums: 3,
|
NumEnums: 3,
|
||||||
NumMessages: 6,
|
NumMessages: 7,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 0,
|
NumServices: 0,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -64,23 +64,30 @@ message StreamConfig {
|
|||||||
SocketConfig socket_settings = 6;
|
SocketConfig socket_settings = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message UdpHop {
|
||||||
|
repeated uint32 ports = 1;
|
||||||
|
int64 interval_min = 2;
|
||||||
|
int64 interval_max = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message QuicParams {
|
message QuicParams {
|
||||||
string congestion = 1;
|
string congestion = 1;
|
||||||
string bbr_profile = 2;
|
string bbr_profile = 2;
|
||||||
uint64 brutal_up = 3;
|
uint64 brutal_up = 3;
|
||||||
uint64 brutal_down = 4;
|
uint64 brutal_down = 4;
|
||||||
bool brutal_disable_loss_compensation = 5;
|
bool brutal_disable_loss_compensation = 5;
|
||||||
uint64 init_stream_receive_window = 6;
|
UdpHop udp_hop = 6;
|
||||||
uint64 max_stream_receive_window = 7;
|
uint64 init_stream_receive_window = 7;
|
||||||
uint64 init_conn_receive_window = 8;
|
uint64 max_stream_receive_window = 8;
|
||||||
uint64 max_conn_receive_window = 9;
|
uint64 init_conn_receive_window = 9;
|
||||||
int64 max_idle_timeout = 10;
|
uint64 max_conn_receive_window = 10;
|
||||||
int64 keep_alive_period = 11;
|
int64 max_idle_timeout = 11;
|
||||||
bool disable_path_mtu_discovery = 12;
|
int64 keep_alive_period = 12;
|
||||||
bool disable_chrome_parrot = 13;
|
bool disable_path_mtu_discovery = 13;
|
||||||
bool disableGSO = 14;
|
bool disable_chrome_parrot = 14;
|
||||||
int64 max_incoming_streams = 15;
|
bool disableGSO = 15;
|
||||||
bool disable_stateless_reset = 16;
|
int64 max_incoming_streams = 16;
|
||||||
|
bool disable_stateless_reset = 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CustomSockopt {
|
message CustomSockopt {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var transportDialerCache = make(map[string]dialFunc)
|
|||||||
// RegisterTransportDialer registers a Dialer with given name.
|
// RegisterTransportDialer registers a Dialer with given name.
|
||||||
func RegisterTransportDialer(protocol string, dialer dialFunc) error {
|
func RegisterTransportDialer(protocol string, dialer dialFunc) error {
|
||||||
if _, found := transportDialerCache[protocol]; found {
|
if _, found := transportDialerCache[protocol]; found {
|
||||||
return errors.New(protocol, " dialer already registered")
|
return errors.New(protocol, " dialer already registered").AtError()
|
||||||
}
|
}
|
||||||
transportDialerCache[protocol] = dialer
|
transportDialerCache[protocol] = dialer
|
||||||
return nil
|
return nil
|
||||||
@@ -58,7 +58,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStrea
|
|||||||
protocol := streamSettings.ProtocolName
|
protocol := streamSettings.ProtocolName
|
||||||
dialer := transportDialerCache[protocol]
|
dialer := transportDialerCache[protocol]
|
||||||
if dialer == nil {
|
if dialer == nil {
|
||||||
return nil, errors.New(protocol, " dialer not registered")
|
return nil, errors.New(protocol, " dialer not registered").AtError()
|
||||||
}
|
}
|
||||||
return dialer(ctx, dest, streamSettings)
|
return dialer(ctx, dest, streamSettings)
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ func Dial(ctx context.Context, dest net.Destination, streamSettings *MemoryStrea
|
|||||||
if dest.Network == net.Network_UDP {
|
if dest.Network == net.Network_UDP {
|
||||||
udpDialer := transportDialerCache["udp"]
|
udpDialer := transportDialerCache["udp"]
|
||||||
if udpDialer == nil {
|
if udpDialer == nil {
|
||||||
return nil, errors.New("UDP dialer not registered")
|
return nil, errors.New("UDP dialer not registered").AtError()
|
||||||
}
|
}
|
||||||
return udpDialer(ctx, dest, streamSettings)
|
return udpDialer(ctx, dest, streamSettings)
|
||||||
}
|
}
|
||||||
@@ -86,7 +86,7 @@ var (
|
|||||||
|
|
||||||
func LookupForIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
|
func LookupForIP(domain string, strategy DomainStrategy, localAddr net.Address) ([]net.IP, error) {
|
||||||
if dnsClient == nil {
|
if dnsClient == nil {
|
||||||
return nil, errors.New("DNS client not initialized")
|
return nil, errors.New("DNS client not initialized").AtError()
|
||||||
}
|
}
|
||||||
|
|
||||||
ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{
|
ips, _, err := dnsClient.LookupIP(domain, dns.IPOption{
|
||||||
@@ -269,11 +269,11 @@ func DialSystem(ctx context.Context, dest net.Destination, sockopt *SocketConfig
|
|||||||
|
|
||||||
if len(sockopt.DialerProxy) > 0 {
|
if len(sockopt.DialerProxy) > 0 {
|
||||||
if obm == nil {
|
if obm == nil {
|
||||||
return nil, errors.New("there is no outbound manager for dialerProxy")
|
return nil, errors.New("there is no outbound manager for dialerProxy").AtError()
|
||||||
}
|
}
|
||||||
h := obm.GetHandler(sockopt.DialerProxy)
|
h := obm.GetHandler(sockopt.DialerProxy)
|
||||||
if h == nil {
|
if h == nil {
|
||||||
return nil, errors.New("there is no outbound handler for dialerProxy")
|
return nil, errors.New("there is no outbound handler for dialerProxy").AtError()
|
||||||
}
|
}
|
||||||
return redirect(ctx, dest, sockopt.DialerProxy, h), nil
|
return redirect(ctx, dest, sockopt.DialerProxy, h), nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,291 +2,106 @@ package finalmask
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"net"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/buf"
|
"github.com/xtls/xray-core/common/buf"
|
||||||
"github.com/xtls/xray-core/common/errors"
|
"github.com/xtls/xray-core/common/errors"
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Dialer struct {
|
type Udpmask interface {
|
||||||
DialTCP func(net.Destination) (net.Conn, error)
|
UDP()
|
||||||
DialUDP func(net.Destination) (net.Conn, error)
|
|
||||||
|
WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
|
||||||
|
WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ListenConfig struct {
|
type UdpmaskManager struct {
|
||||||
Listen func(net.Addr) (net.Listener, error)
|
udpmasks []Udpmask
|
||||||
ListenPacket func(net.Addr) (net.PacketConn, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type TCPMask interface {
|
func NewUdpmaskManager(udpmasks []Udpmask) *UdpmaskManager {
|
||||||
WrapConnClient(net.Conn, *net.Destination, *Dialer) (net.Conn, error)
|
return &UdpmaskManager{
|
||||||
WrapConnServer(net.Conn) (net.Conn, error)
|
udpmasks: udpmasks,
|
||||||
// Listen(net.Listener) (net.Listener, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type UDPMask interface {
|
|
||||||
WrapPacketConnClient(net.PacketConn, *net.Destination, *Dialer) (net.PacketConn, error)
|
|
||||||
WrapPacketConnServer(net.PacketConn, net.Addr, *ListenConfig) (net.PacketConn, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type FinalMask struct {
|
|
||||||
tcpMasks []TCPMask
|
|
||||||
udpMasks []UDPMask
|
|
||||||
dialTCP func(context.Context, net.Destination) (net.Conn, error)
|
|
||||||
listen func(context.Context, net.Addr) (net.Listener, error)
|
|
||||||
dialUDP func(context.Context, net.Destination) (net.PacketConn, net.Addr, error)
|
|
||||||
listenPacket func(context.Context, net.Addr) (net.PacketConn, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFinalMask(tcpMasks []TCPMask, udpMasks []UDPMask, dialTCP func(context.Context, net.Destination) (net.Conn, error), listen func(context.Context, net.Addr) (net.Listener, error), dialUDP func(context.Context, net.Destination) (net.PacketConn, net.Addr, error), listenPacket func(context.Context, net.Addr) (net.PacketConn, error)) *FinalMask {
|
|
||||||
slices.Reverse(tcpMasks)
|
|
||||||
slices.Reverse(udpMasks)
|
|
||||||
return &FinalMask{
|
|
||||||
tcpMasks: tcpMasks,
|
|
||||||
udpMasks: udpMasks,
|
|
||||||
dialTCP: dialTCP,
|
|
||||||
dialUDP: dialUDP,
|
|
||||||
listen: listen,
|
|
||||||
listenPacket: listenPacket,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fm *FinalMask) DialTCP(ctx context.Context, dest net.Destination) (net.Conn, error) {
|
func (m *UdpmaskManager) WrapPacketConnClient(raw net.PacketConn) (net.PacketConn, error) {
|
||||||
if len(fm.tcpMasks) == 0 {
|
|
||||||
return fm.dialTCP(ctx, dest)
|
|
||||||
}
|
|
||||||
for i := range fm.tcpMasks {
|
|
||||||
if i > 0 {
|
|
||||||
if _, ok := fm.tcpMasks[i].(interface{ HandleDial() }); ok {
|
|
||||||
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.tcpMasks[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var conn net.Conn
|
|
||||||
var err error
|
|
||||||
if _, ok := fm.tcpMasks[0].(interface{ HandleDial() }); !ok {
|
|
||||||
conn, err = fm.dialTCP(ctx, dest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dialer := &Dialer{
|
|
||||||
DialTCP: func(dest net.Destination) (net.Conn, error) {
|
|
||||||
return fm.dialTCP(ctx, dest)
|
|
||||||
},
|
|
||||||
DialUDP: func(dest net.Destination) (net.Conn, error) {
|
|
||||||
conn, addr, err := fm.dialUDP(ctx, dest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, err
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i := range fm.tcpMasks {
|
|
||||||
var newConn net.Conn
|
|
||||||
newConn, err = fm.tcpMasks[i].WrapConnClient(conn, &dest, dialer)
|
|
||||||
if err != nil {
|
|
||||||
_ = conn.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn = newConn
|
|
||||||
}
|
|
||||||
return conn, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fm *FinalMask) Listen(ctx context.Context, addr net.Addr) (net.Listener, error) {
|
|
||||||
if len(fm.tcpMasks) == 0 {
|
|
||||||
return fm.listen(ctx, addr)
|
|
||||||
}
|
|
||||||
off := 0
|
|
||||||
listener, err := fm.listen(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
for i := range fm.tcpMasks {
|
|
||||||
if _, ok := fm.tcpMasks[i].(interface {
|
|
||||||
Listen(net.Listener) (net.Listener, error)
|
|
||||||
}); ok {
|
|
||||||
if i-off == 0 {
|
|
||||||
l, err := fm.tcpMasks[i].(interface {
|
|
||||||
Listen(net.Listener) (net.Listener, error)
|
|
||||||
}).Listen(listener)
|
|
||||||
if err != nil {
|
|
||||||
listener.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
listener = l
|
|
||||||
} else {
|
|
||||||
l, err := fm.tcpMasks[i].(interface {
|
|
||||||
Listen(net.Listener) (net.Listener, error)
|
|
||||||
}).Listen(&TCPListener{Listener: listener, tcpMasks: fm.tcpMasks[off:i]})
|
|
||||||
if err != nil {
|
|
||||||
listener.Close()
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
listener = l
|
|
||||||
}
|
|
||||||
off = i + 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if off < len(fm.tcpMasks) {
|
|
||||||
return &TCPListener{Listener: listener, tcpMasks: fm.tcpMasks[off:]}, nil
|
|
||||||
}
|
|
||||||
return listener, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fm *FinalMask) DialUDP(ctx context.Context, dest net.Destination) (net.Conn, error) {
|
|
||||||
if len(fm.udpMasks) == 0 {
|
|
||||||
conn, addr, err := fm.dialUDP(ctx, dest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, nil
|
|
||||||
}
|
|
||||||
for i := range fm.udpMasks {
|
|
||||||
if i > 0 {
|
|
||||||
if _, ok := fm.udpMasks[i].(interface{ HandleDial() }); ok {
|
|
||||||
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.udpMasks[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var conn net.PacketConn
|
|
||||||
var addr net.Addr
|
|
||||||
var err error
|
|
||||||
if _, ok := fm.udpMasks[0].(interface{ HandleDial() }); !ok {
|
|
||||||
conn, addr, err = fm.dialUDP(ctx, dest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dialer := &Dialer{
|
|
||||||
DialTCP: func(dest net.Destination) (net.Conn, error) {
|
|
||||||
return fm.dialTCP(ctx, dest)
|
|
||||||
},
|
|
||||||
DialUDP: func(dest net.Destination) (net.Conn, error) {
|
|
||||||
conn, addr, err := fm.dialUDP(ctx, dest)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, err
|
|
||||||
},
|
|
||||||
}
|
|
||||||
var sizes []int
|
var sizes []int
|
||||||
var conns []net.PacketConn
|
var conns []net.PacketConn
|
||||||
for i := range fm.udpMasks {
|
for i, mask := range slices.Backward(m.udpmasks) {
|
||||||
var newConn net.PacketConn
|
if _, ok := mask.(headerConn); ok {
|
||||||
if _, ok := fm.udpMasks[i].(interface{ HeaderConn() }); ok {
|
conn, err := mask.WrapPacketConnClient(nil, i, len(m.udpmasks)-1)
|
||||||
newConn, err = fm.udpMasks[i].WrapPacketConnClient(nil, nil, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = conn.Close()
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sizes = append(sizes, newConn.(interface{ Size() int }).Size())
|
sizes = append(sizes, conn.(headerSize).Size())
|
||||||
conns = append(conns, newConn)
|
conns = append(conns, conn)
|
||||||
} else {
|
} else {
|
||||||
if len(conns) > 0 {
|
if len(conns) > 0 {
|
||||||
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
|
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw}
|
||||||
sizes = nil
|
sizes = nil
|
||||||
conns = nil
|
conns = nil
|
||||||
}
|
}
|
||||||
newConn, err = fm.udpMasks[i].WrapPacketConnClient(conn, &dest, dialer)
|
var err error
|
||||||
|
raw, err = mask.WrapPacketConnClient(raw, i, len(m.udpmasks)-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = conn.Close()
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conn = newConn
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(conns) > 0 {
|
if len(conns) > 0 {
|
||||||
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
|
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw}
|
||||||
sizes = nil
|
sizes = nil
|
||||||
conns = nil
|
conns = nil
|
||||||
}
|
}
|
||||||
if addr == nil {
|
return raw, nil
|
||||||
addr = &net.UDPAddr{IP: []byte{0, 0, 0, 0}}
|
|
||||||
}
|
|
||||||
return &PacketConnWrapper{PacketConn: conn, udpAddr: addr}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fm *FinalMask) ListenPacket(ctx context.Context, addr net.Addr) (net.PacketConn, error) {
|
func (m *UdpmaskManager) WrapPacketConnServer(raw net.PacketConn) (net.PacketConn, error) {
|
||||||
if len(fm.udpMasks) == 0 {
|
|
||||||
return fm.listenPacket(ctx, addr)
|
|
||||||
}
|
|
||||||
for i := range fm.udpMasks {
|
|
||||||
if i > 0 {
|
|
||||||
if _, ok := fm.udpMasks[i].(interface{ HandleListen() }); ok {
|
|
||||||
return nil, fmt.Errorf("incorrect index: %d %T", i, fm.udpMasks[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var conn net.PacketConn
|
|
||||||
var err error
|
|
||||||
if _, ok := fm.udpMasks[0].(interface{ HandleListen() }); !ok {
|
|
||||||
conn, err = fm.listenPacket(ctx, addr)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lc := &ListenConfig{
|
|
||||||
Listen: func(addr net.Addr) (net.Listener, error) { return fm.listen(ctx, addr) },
|
|
||||||
ListenPacket: func(addr net.Addr) (net.PacketConn, error) { return fm.listenPacket(ctx, addr) },
|
|
||||||
}
|
|
||||||
var sizes []int
|
var sizes []int
|
||||||
var conns []net.PacketConn
|
var conns []net.PacketConn
|
||||||
for i := range fm.udpMasks {
|
for i, mask := range slices.Backward(m.udpmasks) {
|
||||||
var newConn net.PacketConn
|
if _, ok := mask.(headerConn); ok {
|
||||||
if _, ok := fm.udpMasks[i].(interface{ HeaderConn() }); ok {
|
conn, err := mask.WrapPacketConnServer(nil, i, len(m.udpmasks)-1)
|
||||||
newConn, err = fm.udpMasks[i].WrapPacketConnServer(nil, nil, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = conn.Close()
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sizes = append(sizes, newConn.(interface{ Size() int }).Size())
|
sizes = append(sizes, conn.(headerSize).Size())
|
||||||
conns = append(conns, newConn)
|
conns = append(conns, conn)
|
||||||
} else {
|
} else {
|
||||||
if len(conns) > 0 {
|
if len(conns) > 0 {
|
||||||
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
|
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw}
|
||||||
sizes = nil
|
sizes = nil
|
||||||
conns = nil
|
conns = nil
|
||||||
}
|
}
|
||||||
newConn, err = fm.udpMasks[i].WrapPacketConnServer(conn, addr, lc)
|
var err error
|
||||||
|
raw, err = mask.WrapPacketConnServer(raw, i, len(m.udpmasks)-1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = conn.Close()
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
conn = newConn
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(conns) > 0 {
|
if len(conns) > 0 {
|
||||||
conn = &headerManagerConn{PacketConn: conn, sizes: sizes, conns: conns}
|
raw = &headerManagerConn{sizes: sizes, conns: conns, PacketConn: raw}
|
||||||
sizes = nil
|
sizes = nil
|
||||||
conns = nil
|
conns = nil
|
||||||
}
|
}
|
||||||
return conn, nil
|
return raw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
UDPSize = 4096
|
UDPSize = 4096
|
||||||
)
|
)
|
||||||
|
|
||||||
type PacketConnWrapper struct {
|
type headerConn interface {
|
||||||
net.PacketConn
|
HeaderConn()
|
||||||
udpAddr net.Addr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PacketConnWrapper) RemoteAddr() net.Addr {
|
type headerSize interface {
|
||||||
return c.udpAddr
|
Size() int
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PacketConnWrapper) Read(b []byte) (n int, err error) {
|
|
||||||
n, _, err = c.PacketConn.ReadFrom(b)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *PacketConnWrapper) Write(b []byte) (n int, err error) {
|
|
||||||
return c.PacketConn.WriteTo(b, c.udpAddr)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type headerManagerConn struct {
|
type headerManagerConn struct {
|
||||||
@@ -379,27 +194,75 @@ func (c *headerManagerConn) WriteTo(p []byte, addr net.Addr) (n int, err error)
|
|||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type TCPListener struct {
|
type Tcpmask interface {
|
||||||
net.Listener
|
TCP()
|
||||||
tcpMasks []TCPMask
|
|
||||||
|
WrapConnClient(net.Conn) (net.Conn, error)
|
||||||
|
WrapConnServer(net.Conn) (net.Conn, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *TCPListener) Accept() (net.Conn, error) {
|
type TcpmaskManager struct {
|
||||||
|
tcpmasks []Tcpmask
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpmaskManager(tcpmasks []Tcpmask) *TcpmaskManager {
|
||||||
|
return &TcpmaskManager{
|
||||||
|
tcpmasks: tcpmasks,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TcpmaskManager) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
|
var err error
|
||||||
|
for _, mask := range slices.Backward(m.tcpmasks) {
|
||||||
|
raw, err = mask.WrapConnClient(raw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return raw, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TcpmaskManager) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||||
|
var err error
|
||||||
|
for _, mask := range slices.Backward(m.tcpmasks) {
|
||||||
|
raw, err = mask.WrapConnServer(raw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return raw, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *TcpmaskManager) WrapListener(l net.Listener) (net.Listener, error) {
|
||||||
|
return NewTcpListener(m, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
type tcpListener struct {
|
||||||
|
m *TcpmaskManager
|
||||||
|
net.Listener
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcpListener(m *TcpmaskManager, l net.Listener) (net.Listener, error) {
|
||||||
|
return &tcpListener{
|
||||||
|
m: m,
|
||||||
|
Listener: l,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *tcpListener) Accept() (net.Conn, error) {
|
||||||
conn, err := l.Listener.Accept()
|
conn, err := l.Listener.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return conn, err
|
return conn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := range l.tcpMasks {
|
newConn, err := l.m.WrapConnServer(conn)
|
||||||
var newConn net.Conn
|
if err != nil {
|
||||||
newConn, err = l.tcpMasks[i].WrapConnServer(conn)
|
errors.LogDebugInner(context.Background(), err, "mask err")
|
||||||
if err != nil {
|
_ = conn.Close()
|
||||||
_ = conn.Close()
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
conn = newConn
|
|
||||||
}
|
}
|
||||||
return conn, nil
|
|
||||||
|
return newConn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type TcpMaskConn interface {
|
type TcpMaskConn interface {
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package fragment
|
package fragment
|
||||||
|
|
||||||
import (
|
import "net"
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Config) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
|
func (c *Config) TCP() {
|
||||||
return NewConnClient(c, conn, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapConnServer(conn net.Conn) (net.Conn, error) {
|
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
return NewConnServer(c, conn, true)
|
return NewConnClient(c, raw, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||||
|
return NewConnServer(c, raw, true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,35 @@
|
|||||||
package custom
|
package custom
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"net"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *TCPConfig) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
|
func (c *TCPConfig) TCP() {}
|
||||||
return NewConnClientTCP(c, conn)
|
|
||||||
|
func (c *TCPConfig) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
|
return NewConnClientTCP(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TCPConfig) WrapConnServer(conn net.Conn) (net.Conn, error) {
|
func (c *TCPConfig) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||||
return NewConnServerTCP(c, conn)
|
return NewConnServerTCP(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPConfig) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *UDPConfig) UDP() {}
|
||||||
return NewConnClientUDP(c, conn)
|
|
||||||
|
func (c *UDPConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
return NewConnClientUDP(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPConfig) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *UDPConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnServerUDP(c, conn)
|
return NewConnServerUDP(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPStandaloneConfig) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *UDPStandaloneConfig) UDP() {}
|
||||||
return NewConnClientUDPStandalone(c, conn)
|
|
||||||
|
func (c *UDPStandaloneConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
return NewConnClientUDPStandalone(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *UDPStandaloneConfig) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *UDPStandaloneConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnServerUDPStandalone(c, conn)
|
return NewConnServerUDPStandalone(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMetadataEvaluatorRejectsUnknownName(t *testing.T) {
|
func TestMetadataEvaluatorRejectsUnknownName(t *testing.T) {
|
||||||
@@ -154,7 +156,7 @@ func TestMetadataUDPStandaloneWriteUsesRemotePort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
|
client, err := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg}).WrapPacketConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -299,7 +301,7 @@ func TestMetadataTCPHandshakeUsesEndpointPorts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := clientCfg.WrapConnClient(clientRaw, nil, nil)
|
client, err := clientCfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mustSendRecvUDP(t *testing.T, from net.PacketConn, to net.PacketConn, msg []byte) {
|
func mustSendRecvUDP(t *testing.T, from net.PacketConn, to net.PacketConn, msg []byte) {
|
||||||
@@ -46,6 +48,7 @@ func TestStateUDPResponseReusesPriorCapturedValues(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg})
|
||||||
|
|
||||||
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -59,11 +62,11 @@ func TestStateUDPResponseReusesPriorCapturedValues(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
|
client, err := maskManager.WrapPacketConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
server, err := cfg.WrapPacketConnServer(serverRaw, nil, nil)
|
server, err := maskManager.WrapPacketConnServer(serverRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func TestDSLTCPHandshakeReusesCapturedValue(t *testing.T) {
|
|||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
client, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ func TestDSLTCPClientRejectsMismatchedResponseSequence(t *testing.T) {
|
|||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := clientCfg.WrapConnClient(clientRaw, nil, nil)
|
client, err := clientCfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package aes128gcm
|
package aes128gcm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"net"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *Config) UDP() {}
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnClient(c, conn)
|
return NewConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnServer(c, conn)
|
return NewConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package header
|
package header
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"net"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *Config) UDP() {}
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnClient(c, conn)
|
return NewConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnServer(c, conn)
|
return NewConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
package original
|
package original
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"net"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *Config) UDP() {}
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnClient(c, conn)
|
return NewConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnServer(c, conn)
|
return NewConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package noise
|
package noise
|
||||||
|
|
||||||
import (
|
import "net"
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *Config) UDP() {
|
||||||
return NewConnClient(c, conn)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnServer(c, conn)
|
return NewConnClient(c, raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
return NewConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,27 @@
|
|||||||
package realm
|
package realm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"net"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
|
"github.com/xtls/xray-core/transport/internet"
|
||||||
|
"github.com/xtls/xray-core/transport/internet/hysteria/udphop"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *Config) UDP() {}
|
||||||
return NewConnClient(c, conn)
|
|
||||||
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
_, ok1 := raw.(*internet.FakePacketConn)
|
||||||
|
_, ok2 := raw.(*udphop.UdpHopPacketConn)
|
||||||
|
if level != 0 || ok1 || ok2 {
|
||||||
|
return nil, errors.New("realm requires being at the outermost level")
|
||||||
|
}
|
||||||
|
return NewConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewConnServer(c, conn)
|
if level != 0 {
|
||||||
|
return nil, errors.New("realm requires being at the outermost level")
|
||||||
|
}
|
||||||
|
return NewConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,27 @@
|
|||||||
package salamander
|
package salamander
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"net"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *Config) UDP() {}
|
||||||
|
|
||||||
func (c *Config) HeaderConn() {}
|
func (c *Config) HeaderConn() {}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewSalamanderConnClient(c, conn)
|
return NewSalamanderConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewSalamanderConnServer(c, conn)
|
return NewSalamanderConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GeckoConfig) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *GeckoConfig) UDP() {}
|
||||||
return NewGeckoConnClient(c, conn)
|
|
||||||
|
func (c *GeckoConfig) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
|
return NewGeckoConnClient(c, raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *GeckoConfig) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *GeckoConfig) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewGeckoConnServer(c, conn)
|
return NewGeckoConnServer(c, raw)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
package sudoku
|
package sudoku
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xtls/xray-core/common/net"
|
"net"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
|
"github.com/xtls/xray-core/common/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c *Config) TCP() {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) UDP() {
|
||||||
|
}
|
||||||
|
|
||||||
// Sudoku in finalmask mode is a pure appearance transform with no standalone handshake.
|
// Sudoku in finalmask mode is a pure appearance transform with no standalone handshake.
|
||||||
// TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes.
|
// TCP always keeps classic sudoku on uplink and uses packed downlink optimization on server writes.
|
||||||
func (c *Config) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
|
func (c *Config) WrapConnClient(raw net.Conn) (net.Conn, error) {
|
||||||
return newPackedDirectionalConn(conn, c, true)
|
return newPackedDirectionalConn(raw, c, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapConnServer(conn net.Conn) (net.Conn, error) {
|
func (c *Config) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||||
return newPackedDirectionalConn(conn, c, false)
|
return newPackedDirectionalConn(raw, c, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPackedDirectionalConn(raw net.Conn, config *Config, readPacked bool) (net.Conn, error) {
|
func newPackedDirectionalConn(raw net.Conn, config *Config, readPacked bool) (net.Conn, error) {
|
||||||
@@ -35,10 +42,16 @@ func newPackedDirectionalConn(raw net.Conn, config *Config, readPacked bool) (ne
|
|||||||
return newWrappedConn(raw, reader, writer), nil
|
return newWrappedConn(raw, reader, writer), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnClient(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewUDPConn(conn, c)
|
if level != levelCount {
|
||||||
|
return nil, errors.New("sudoku udp mask must be the innermost mask in chain")
|
||||||
|
}
|
||||||
|
return NewUDPConn(raw, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
func (c *Config) WrapPacketConnServer(raw net.PacketConn, level int, levelCount int) (net.PacketConn, error) {
|
||||||
return NewUDPConn(conn, c)
|
if level != levelCount {
|
||||||
|
return nil, errors.New("sudoku udp mask must be the innermost mask in chain")
|
||||||
|
}
|
||||||
|
return NewUDPConn(raw, c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ package finalmask_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"io"
|
"io"
|
||||||
gonet "net"
|
"net"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
|
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
|
||||||
)
|
)
|
||||||
@@ -22,14 +20,11 @@ func mustSendRecvTcp(
|
|||||||
) {
|
) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
waitCh := make(chan error)
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
_, err := from.Write(msg)
|
_, err := from.Write(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
close(waitCh)
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
buf := make([]byte, 1024)
|
buf := make([]byte, 1024)
|
||||||
@@ -45,23 +40,18 @@ func mustSendRecvTcp(
|
|||||||
if !bytes.Equal(buf[:n], msg) {
|
if !bytes.Equal(buf[:n], msg) {
|
||||||
t.Fatalf("unexpected data %q", buf[:n])
|
t.Fatalf("unexpected data %q", buf[:n])
|
||||||
}
|
}
|
||||||
|
|
||||||
<-waitCh
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type layerMaskTcp struct {
|
type layerMaskTcp struct {
|
||||||
name string
|
name string
|
||||||
mask finalmask.TCPMask
|
mask finalmask.Tcpmask
|
||||||
}
|
}
|
||||||
|
|
||||||
type failingWrapMask struct{}
|
type failingWrapMask struct{}
|
||||||
|
|
||||||
func (failingWrapMask) TCP() {}
|
func (failingWrapMask) TCP() {}
|
||||||
func (f failingWrapMask) WrapConnClient(conn net.Conn, dest *net.Destination, dialer *finalmask.Dialer) (net.Conn, error) {
|
func (f failingWrapMask) WrapConnClient(raw net.Conn) (net.Conn, error) { return raw, nil }
|
||||||
return conn, nil
|
func (f failingWrapMask) WrapConnServer(raw net.Conn) (net.Conn, error) {
|
||||||
}
|
|
||||||
|
|
||||||
func (f failingWrapMask) WrapConnServer(conn net.Conn) (net.Conn, error) {
|
|
||||||
return nil, io.ErrClosedPipe
|
return nil, io.ErrClosedPipe
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,31 +92,32 @@ func TestConnReadWrite(t *testing.T) {
|
|||||||
t.Run(c.name, func(t *testing.T) {
|
t.Run(c.name, func(t *testing.T) {
|
||||||
mask := c.mask
|
mask := c.mask
|
||||||
|
|
||||||
dialTCP := func(ctx context.Context, dest net.Destination) (net.Conn, error) {
|
maskManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{mask})
|
||||||
return net.Dial("tcp", dest.NetAddr())
|
|
||||||
}
|
|
||||||
listen := func(ctx context.Context, addr net.Addr) (net.Listener, error) {
|
|
||||||
return net.Listen("tcp", addr.String())
|
|
||||||
}
|
|
||||||
finalMask := finalmask.NewFinalMask([]finalmask.TCPMask{mask}, nil, dialTCP, listen, nil, nil)
|
|
||||||
|
|
||||||
listener, err := finalMask.Listen(context.Background(), &net.TCPAddr{IP: net.LocalHostIP.IP()})
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { listener.Close() })
|
|
||||||
|
|
||||||
client, err := finalMask.DialTCP(context.Background(), net.TCPDestination(net.IPAddress(listener.Addr().(*net.TCPAddr).IP), net.Port(listener.Addr().(*net.TCPAddr).Port)))
|
client, err := net.Dial("tcp", ln.Addr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { client.Close() })
|
|
||||||
|
|
||||||
server, err := listener.Accept()
|
client, err = maskManager.WrapConnClient(client)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err = maskManager.WrapConnServer(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { server.Close() })
|
|
||||||
|
|
||||||
_ = client.SetDeadline(time.Now().Add(time.Second))
|
_ = client.SetDeadline(time.Now().Add(time.Second))
|
||||||
_ = server.SetDeadline(time.Now().Add(time.Second))
|
_ = server.SetDeadline(time.Now().Add(time.Second))
|
||||||
@@ -159,32 +150,34 @@ func TestTCPcustomStaticHandshakeRoundTrip(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
maskManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{cfg})
|
||||||
|
|
||||||
dialTCP := func(ctx context.Context, dest net.Destination) (net.Conn, error) {
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
return net.Dial("tcp", dest.NetAddr())
|
|
||||||
}
|
|
||||||
listen := func(ctx context.Context, addr net.Addr) (net.Listener, error) {
|
|
||||||
return net.Listen("tcp", addr.String())
|
|
||||||
}
|
|
||||||
finalMask := finalmask.NewFinalMask([]finalmask.TCPMask{cfg}, nil, dialTCP, listen, nil, nil)
|
|
||||||
|
|
||||||
listener, err := finalMask.Listen(context.Background(), &net.TCPAddr{IP: net.LocalHostIP.IP()})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer listener.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
client, err := finalMask.DialTCP(context.Background(), net.TCPDestination(net.IPAddress(listener.Addr().(*net.TCPAddr).IP), net.Port(listener.Addr().(*net.TCPAddr).Port)))
|
clientRaw, err := net.Dial("tcp", ln.Addr().String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer client.Close()
|
defer clientRaw.Close()
|
||||||
|
|
||||||
server, err := listener.Accept()
|
serverRaw, err := ln.Accept()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer serverRaw.Close()
|
||||||
|
|
||||||
|
client, err := maskManager.WrapConnClient(clientRaw)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
server, err := maskManager.WrapConnServer(serverRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer server.Close()
|
|
||||||
|
|
||||||
_ = client.SetDeadline(time.Now().Add(time.Second))
|
_ = client.SetDeadline(time.Now().Add(time.Second))
|
||||||
_ = server.SetDeadline(time.Now().Add(time.Second))
|
_ = server.SetDeadline(time.Now().Add(time.Second))
|
||||||
@@ -227,11 +220,11 @@ func TestTCPcustomClientRejectsMismatchedServerSequence(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := clientCfg.WrapConnClient(clientRaw, nil, nil)
|
client, err := clientCfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -264,37 +257,42 @@ func TestTCPcustomClientRejectsMismatchedServerSequence(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTCPWrapListenerRejectsImmediateWrapErrors(t *testing.T) {
|
func TestTCPWrapListenerRejectsImmediateWrapErrors(t *testing.T) {
|
||||||
dialTCP := func(ctx context.Context, dest net.Destination) (net.Conn, error) {
|
clientManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{failingWrapMask{}})
|
||||||
return net.Dial("tcp", dest.NetAddr())
|
serverManager := finalmask.NewTcpmaskManager([]finalmask.Tcpmask{failingWrapMask{}})
|
||||||
}
|
|
||||||
listen := func(ctx context.Context, addr net.Addr) (net.Listener, error) {
|
|
||||||
return net.Listen("tcp", addr.String())
|
|
||||||
}
|
|
||||||
finalMask := finalmask.NewFinalMask([]finalmask.TCPMask{failingWrapMask{}}, nil, dialTCP, listen, nil, nil)
|
|
||||||
|
|
||||||
listener, err := finalMask.Listen(context.Background(), &net.TCPAddr{IP: net.LocalHostIP.IP()})
|
rawLn, err := net.Listen("tcp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer rawLn.Close()
|
||||||
|
|
||||||
|
ln, err := serverManager.WrapListener(rawLn)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer listener.Close()
|
|
||||||
|
|
||||||
accepted := make(chan struct {
|
accepted := make(chan struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
err error
|
err error
|
||||||
}, 1)
|
}, 1)
|
||||||
go func() {
|
go func() {
|
||||||
conn, err := listener.Accept()
|
conn, err := ln.Accept()
|
||||||
accepted <- struct {
|
accepted <- struct {
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
err error
|
err error
|
||||||
}{conn: conn, err: err}
|
}{conn: conn, err: err}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
client, err := finalMask.DialTCP(context.Background(), net.TCPDestination(net.IPAddress(listener.Addr().(*net.TCPAddr).IP), net.Port(listener.Addr().(*net.TCPAddr).Port)))
|
clientRaw, err := net.Dial("tcp", rawLn.Addr().String())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer clientRaw.Close()
|
||||||
|
|
||||||
|
client, err := clientManager.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer client.Close()
|
|
||||||
|
|
||||||
_ = client.SetDeadline(time.Now().Add(time.Second))
|
_ = client.SetDeadline(time.Now().Add(time.Second))
|
||||||
|
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ package finalmask_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"io"
|
"io"
|
||||||
gonet "net"
|
"net"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/proxy"
|
"github.com/xtls/xray-core/proxy"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
"github.com/xtls/xray-core/transport/internet/finalmask"
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
|
"github.com/xtls/xray-core/transport/internet/finalmask/header/custom"
|
||||||
@@ -53,7 +51,7 @@ func mustSendRecv(
|
|||||||
|
|
||||||
type layerMask struct {
|
type layerMask struct {
|
||||||
name string
|
name string
|
||||||
mask finalmask.UDPMask
|
mask finalmask.Udpmask
|
||||||
layers int
|
layers int
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,23 +213,25 @@ func newStandaloneStunLikeUDPServerConfig() *custom.UDPStandaloneConfig {
|
|||||||
func newUDPClientServerPair(t *testing.T, cfg *custom.UDPStandaloneConfig) (net.PacketConn, net.PacketConn, net.PacketConn, net.PacketConn) {
|
func newUDPClientServerPair(t *testing.T, cfg *custom.UDPStandaloneConfig) (net.PacketConn, net.PacketConn, net.PacketConn, net.PacketConn) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
clientRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
|
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { _ = clientRaw.Close() })
|
t.Cleanup(func() { _ = clientRaw.Close() })
|
||||||
|
|
||||||
serverRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
|
serverRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { _ = serverRaw.Close() })
|
t.Cleanup(func() { _ = serverRaw.Close() })
|
||||||
|
|
||||||
client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
|
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg})
|
||||||
|
|
||||||
|
client, err := maskManager.WrapPacketConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
server, err := cfg.WrapPacketConnServer(serverRaw, nil, nil)
|
server, err := maskManager.WrapPacketConnServer(serverRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -348,39 +348,31 @@ func TestPacketConnReadWrite(t *testing.T) {
|
|||||||
if layers <= 0 {
|
if layers <= 0 {
|
||||||
layers = 1
|
layers = 1
|
||||||
}
|
}
|
||||||
masks := make([]finalmask.UDPMask, 0, layers)
|
masks := make([]finalmask.Udpmask, 0, layers)
|
||||||
for i := 0; i < layers; i++ {
|
for i := 0; i < layers; i++ {
|
||||||
masks = append(masks, mask)
|
masks = append(masks, mask)
|
||||||
}
|
}
|
||||||
|
maskManager := finalmask.NewUdpmaskManager(masks)
|
||||||
|
|
||||||
dialUDP := func(ctx context.Context, dest net.Destination) (net.PacketConn, net.Addr, error) {
|
client, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
udpAddr, err := net.ResolveUDPAddr("udp", dest.NetAddr())
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
conn, err := gonet.ListenPacket("udp", "127.0.0.1:0")
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
return conn, udpAddr, nil
|
|
||||||
}
|
|
||||||
listenPacket := func(ctx context.Context, addr net.Addr) (net.PacketConn, error) {
|
|
||||||
return gonet.ListenPacket(addr.Network(), addr.String())
|
|
||||||
}
|
|
||||||
finalMask := finalmask.NewFinalMask(nil, masks, nil, nil, dialUDP, listenPacket)
|
|
||||||
|
|
||||||
server, err := finalMask.ListenPacket(context.Background(), &net.UDPAddr{IP: net.LocalHostIP.IP()})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { server.Close() })
|
|
||||||
|
|
||||||
clientConn, err := finalMask.DialUDP(context.Background(), net.UDPDestination(net.IPAddress(server.LocalAddr().(*net.UDPAddr).IP), net.Port(server.LocalAddr().(*net.UDPAddr).Port)))
|
client, err = maskManager.WrapPacketConnClient(client)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
server, err = maskManager.WrapPacketConnServer(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(func() { clientConn.Close() })
|
|
||||||
client := clientConn.(*finalmask.PacketConnWrapper).PacketConn
|
|
||||||
|
|
||||||
_ = client.SetDeadline(time.Now().Add(time.Second))
|
_ = client.SetDeadline(time.Now().Add(time.Second))
|
||||||
_ = server.SetDeadline(time.Now().Add(time.Second))
|
_ = server.SetDeadline(time.Now().Add(time.Second))
|
||||||
@@ -405,20 +397,21 @@ func TestUDPcustomStaticHeaderWireShape(t *testing.T) {
|
|||||||
{Rand: 1, RandMin: 0x30, RandMax: 0x40},
|
{Rand: 1, RandMin: 0x30, RandMax: 0x40},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg})
|
||||||
|
|
||||||
clientRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
|
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
|
|
||||||
serverRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
|
serverRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
|
client, err := maskManager.WrapPacketConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -649,11 +642,11 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
Ascii: "prefer_ascii",
|
Ascii: "prefer_ascii",
|
||||||
}
|
}
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -690,11 +683,11 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
PaddingMax: 0,
|
PaddingMax: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -745,10 +738,10 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
countWireBytes := func(wrapServer func(net.Conn, *sudoku.Config) (net.Conn, error), cfg *sudoku.Config) int64 {
|
countWireBytes := func(wrapServer func(net.Conn, *sudoku.Config) (net.Conn, error), cfg *sudoku.Config) int64 {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
watchedServerRaw := &countingConn{Conn: serverRaw}
|
watchedServerRaw := &countingConn{Conn: serverRaw}
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -800,11 +793,11 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
CustomTables: []string{"xpxvvpvv", "vxpvxvvp"},
|
CustomTables: []string{"xpxvvpvv", "vxpvxvvp"},
|
||||||
}
|
}
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -842,11 +835,11 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
PaddingMax: 0,
|
PaddingMax: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -875,6 +868,19 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("GivenSudokuUDPMask_WhenNotInnermost_ThenWrapFails", func(t *testing.T) {
|
||||||
|
cfg := &sudoku.Config{Password: "sudoku-udp"}
|
||||||
|
raw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer raw.Close()
|
||||||
|
|
||||||
|
if _, err := cfg.WrapPacketConnClient(raw, 0, 1); err == nil {
|
||||||
|
t.Fatal("expected innermost check failure")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("GivenSudokuMultiTableUDPMask_WhenClientSendsMultipleDatagrams_ThenPayloadMatches", func(t *testing.T) {
|
t.Run("GivenSudokuMultiTableUDPMask_WhenClientSendsMultipleDatagrams_ThenPayloadMatches", func(t *testing.T) {
|
||||||
cfg := &sudoku.Config{
|
cfg := &sudoku.Config{
|
||||||
Password: "sudoku-udp-multi",
|
Password: "sudoku-udp-multi",
|
||||||
@@ -883,24 +889,25 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
PaddingMin: 0,
|
PaddingMin: 0,
|
||||||
PaddingMax: 0,
|
PaddingMax: 0,
|
||||||
}
|
}
|
||||||
|
maskManager := finalmask.NewUdpmaskManager([]finalmask.Udpmask{cfg})
|
||||||
|
|
||||||
clientRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
|
clientRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
|
|
||||||
serverRaw, err := gonet.ListenPacket("udp", "127.0.0.1:0")
|
serverRaw, err := net.ListenPacket("udp", "127.0.0.1:0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
client, err := cfg.WrapPacketConnClient(clientRaw, nil, nil)
|
client, err := maskManager.WrapPacketConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
server, err := cfg.WrapPacketConnServer(serverRaw, nil, nil)
|
server, err := maskManager.WrapPacketConnServer(serverRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -954,7 +961,7 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
}
|
}
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1001,11 +1008,11 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
Ascii: "prefer_entropy",
|
Ascii: "prefer_entropy",
|
||||||
}
|
}
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -1025,11 +1032,11 @@ func TestSudokuBDD(t *testing.T) {
|
|||||||
Ascii: "prefer_entropy",
|
Ascii: "prefer_entropy",
|
||||||
}
|
}
|
||||||
|
|
||||||
clientRaw, serverRaw := gonet.Pipe()
|
clientRaw, serverRaw := net.Pipe()
|
||||||
defer clientRaw.Close()
|
defer clientRaw.Close()
|
||||||
defer serverRaw.Close()
|
defer serverRaw.Close()
|
||||||
|
|
||||||
clientConn, err := cfg.WrapConnClient(clientRaw, nil, nil)
|
clientConn, err := cfg.WrapConnClient(clientRaw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
package udphop
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/xtls/xray-core/common/errors"
|
|
||||||
"github.com/xtls/xray-core/common/net"
|
|
||||||
"github.com/xtls/xray-core/transport/internet/finalmask"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *Config) HandleDial() {}
|
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnClient(conn net.PacketConn, dest *net.Destination, dialer *finalmask.Dialer) (net.PacketConn, error) {
|
|
||||||
return NewUDPHopConn(c, dest, dialer)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) WrapPacketConnServer(conn net.PacketConn, addr net.Addr, lc *finalmask.ListenConfig) (net.PacketConn, error) {
|
|
||||||
return nil, errors.New("udphop: client only")
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.36.11
|
|
||||||
// protoc v6.33.5
|
|
||||||
// source: transport/internet/finalmask/udphop/config.proto
|
|
||||||
|
|
||||||
package udphop
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Local bool `protobuf:"varint,2,opt,name=local,proto3" json:"local,omitempty"`
|
|
||||||
Remote bool `protobuf:"varint,3,opt,name=remote,proto3" json:"remote,omitempty"`
|
|
||||||
RemoteOnce bool `protobuf:"varint,4,opt,name=remote_once,json=remoteOnce,proto3" json:"remote_once,omitempty"`
|
|
||||||
IntervalMin int64 `protobuf:"varint,5,opt,name=interval_min,json=intervalMin,proto3" json:"interval_min,omitempty"`
|
|
||||||
IntervalMax int64 `protobuf:"varint,6,opt,name=interval_max,json=intervalMax,proto3" json:"interval_max,omitempty"`
|
|
||||||
RemoteIPs []string `protobuf:"bytes,7,rep,name=remoteIPs,proto3" json:"remoteIPs,omitempty"`
|
|
||||||
RemotePorts []uint32 `protobuf:"varint,8,rep,packed,name=remote_ports,json=remotePorts,proto3" json:"remote_ports,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) Reset() {
|
|
||||||
*x = Config{}
|
|
||||||
mi := &file_transport_internet_finalmask_udphop_config_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*Config) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *Config) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_transport_internet_finalmask_udphop_config_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use Config.ProtoReflect.Descriptor instead.
|
|
||||||
func (*Config) Descriptor() ([]byte, []int) {
|
|
||||||
return file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetLocal() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Local
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetRemote() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.Remote
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetRemoteOnce() bool {
|
|
||||||
if x != nil {
|
|
||||||
return x.RemoteOnce
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetIntervalMin() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.IntervalMin
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetIntervalMax() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.IntervalMax
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetRemoteIPs() []string {
|
|
||||||
if x != nil {
|
|
||||||
return x.RemoteIPs
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *Config) GetRemotePorts() []uint32 {
|
|
||||||
if x != nil {
|
|
||||||
return x.RemotePorts
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_transport_internet_finalmask_udphop_config_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
const file_transport_internet_finalmask_udphop_config_proto_rawDesc = "" +
|
|
||||||
"\n" +
|
|
||||||
"0transport/internet/finalmask/udphop/config.proto\x12(xray.transport.internet.finalmask.udphop\"\xe4\x01\n" +
|
|
||||||
"\x06Config\x12\x14\n" +
|
|
||||||
"\x05local\x18\x02 \x01(\bR\x05local\x12\x16\n" +
|
|
||||||
"\x06remote\x18\x03 \x01(\bR\x06remote\x12\x1f\n" +
|
|
||||||
"\vremote_once\x18\x04 \x01(\bR\n" +
|
|
||||||
"remoteOnce\x12!\n" +
|
|
||||||
"\finterval_min\x18\x05 \x01(\x03R\vintervalMin\x12!\n" +
|
|
||||||
"\finterval_max\x18\x06 \x01(\x03R\vintervalMax\x12\x1c\n" +
|
|
||||||
"\tremoteIPs\x18\a \x03(\tR\tremoteIPs\x12!\n" +
|
|
||||||
"\fremote_ports\x18\b \x03(\rR\vremotePortsJ\x04\b\x01\x10\x02B\x9a\x01\n" +
|
|
||||||
",com.xray.transport.internet.finalmask.udphopP\x01Z=github.com/xtls/xray-core/transport/internet/finalmask/udphop\xaa\x02(Xray.Transport.Internet.Finalmask.Udphopb\x06proto3"
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_transport_internet_finalmask_udphop_config_proto_rawDescOnce sync.Once
|
|
||||||
file_transport_internet_finalmask_udphop_config_proto_rawDescData []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_transport_internet_finalmask_udphop_config_proto_rawDescGZIP() []byte {
|
|
||||||
file_transport_internet_finalmask_udphop_config_proto_rawDescOnce.Do(func() {
|
|
||||||
file_transport_internet_finalmask_udphop_config_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_udphop_config_proto_rawDesc), len(file_transport_internet_finalmask_udphop_config_proto_rawDesc)))
|
|
||||||
})
|
|
||||||
return file_transport_internet_finalmask_udphop_config_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_transport_internet_finalmask_udphop_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
|
||||||
var file_transport_internet_finalmask_udphop_config_proto_goTypes = []any{
|
|
||||||
(*Config)(nil), // 0: xray.transport.internet.finalmask.udphop.Config
|
|
||||||
}
|
|
||||||
var file_transport_internet_finalmask_udphop_config_proto_depIdxs = []int32{
|
|
||||||
0, // [0:0] is the sub-list for method output_type
|
|
||||||
0, // [0:0] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_transport_internet_finalmask_udphop_config_proto_init() }
|
|
||||||
func file_transport_internet_finalmask_udphop_config_proto_init() {
|
|
||||||
if File_transport_internet_finalmask_udphop_config_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_transport_internet_finalmask_udphop_config_proto_rawDesc), len(file_transport_internet_finalmask_udphop_config_proto_rawDesc)),
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 1,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 0,
|
|
||||||
},
|
|
||||||
GoTypes: file_transport_internet_finalmask_udphop_config_proto_goTypes,
|
|
||||||
DependencyIndexes: file_transport_internet_finalmask_udphop_config_proto_depIdxs,
|
|
||||||
MessageInfos: file_transport_internet_finalmask_udphop_config_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_transport_internet_finalmask_udphop_config_proto = out.File
|
|
||||||
file_transport_internet_finalmask_udphop_config_proto_goTypes = nil
|
|
||||||
file_transport_internet_finalmask_udphop_config_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user