From fb99412193de303ceea52e30fc1c762f576651f3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 26 Sep 2023 08:51:25 +0800 Subject: [PATCH 001/192] chore: update quic-go to 0.39.0 --- go.mod | 8 ++--- go.sum | 30 +++++-------------- transport/hysteria/congestion/brutal.go | 2 +- transport/tuic/common/congestion.go | 2 -- .../tuic/congestion/bandwidth_sampler.go | 4 +-- transport/tuic/congestion/bbr_sender.go | 4 +-- transport/tuic/congestion/cubic_sender.go | 27 +---------------- 7 files changed, 18 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index 6c67a38a..74f5d0a7 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf - github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 + github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731 + github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.12 @@ -69,7 +69,6 @@ require ( github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/golang/mock v1.6.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect @@ -85,7 +84,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.3 // indirect + github.com/quic-go/qtls-go1-20 v0.3.4 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect @@ -99,6 +98,7 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect + go.uber.org/mock v0.3.0 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index 0105d57d..d251a6b7 100644 --- a/go.sum +++ b/go.sum @@ -51,8 +51,6 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -95,12 +93,12 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= -github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= +github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731 h1:F+xz1KCwUfCud5eWHKZr0QsWOeA+mqIFvn90r8hq+R8= +github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 h1:qiTekhMDwY2vXARJx1D9EIEdtllbL7+ZBzHX9DQpWs4= github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 h1:6g+ohVa8FQLXz/ATmped/4kWuK0HKvhy1hwzQXyF0EI= -github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= @@ -139,8 +137,8 @@ github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErp github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= -github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= +github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= @@ -197,7 +195,6 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= @@ -208,6 +205,8 @@ go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= 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.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= @@ -216,16 +215,13 @@ golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjs golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -235,10 +231,7 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -248,23 +241,16 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 9992f6a0..88bf6f34 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -85,7 +85,7 @@ func (b *BrutalSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes b.updateAckRate(currentTimestamp) } -func (b *BrutalSender) OnPacketLost(number congestion.PacketNumber, lostBytes congestion.ByteCount, +func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { currentTimestamp := time.Now().Unix() slot := currentTimestamp % pktInfoSlotCount diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 36ee01a1..158f22d6 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -23,7 +23,6 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { congestion.DefaultClock{}, congestion.GetInitialPacketSize(quicConn.RemoteAddr()), false, - nil, ), ) case "new_reno": @@ -32,7 +31,6 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { congestion.DefaultClock{}, congestion.GetInitialPacketSize(quicConn.RemoteAddr()), true, - nil, ), ) case "bbr": diff --git a/transport/tuic/congestion/bandwidth_sampler.go b/transport/tuic/congestion/bandwidth_sampler.go index b82d391f..e415fe7a 100644 --- a/transport/tuic/congestion/bandwidth_sampler.go +++ b/transport/tuic/congestion/bandwidth_sampler.go @@ -296,9 +296,9 @@ func (s *BandwidthSampler) onPacketAckedInner(ackTime time.Time, lastAckedPacket return sample } -// OnPacketLost Informs the sampler that a packet is considered lost and it should no +// OnCongestionEvent Informs the sampler that a packet is considered lost and it should no // longer keep track of it. -func (s *BandwidthSampler) OnPacketLost(packetNumber congestion.PacketNumber) SendTimeState { +func (s *BandwidthSampler) OnCongestionEvent(packetNumber congestion.PacketNumber) SendTimeState { ok, sentPacket := s.connectionStats.Remove(packetNumber) sendTimeState := SendTimeState{ isValid: ok, diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index e78819c7..2c842300 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -374,7 +374,7 @@ func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes con } -func (b *bbrSender) OnPacketLost(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { +func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { eventTime := time.Now() totalBytesAckedBefore := b.sampler.totalBytesAcked isRoundStart, minRttExpired := false, false @@ -620,7 +620,7 @@ func (b *bbrSender) ShouldExtendMinRttExpiry() bool { } func (b *bbrSender) DiscardLostPackets(number congestion.PacketNumber, lostBytes congestion.ByteCount) { - b.sampler.OnPacketLost(number) + b.sampler.OnCongestionEvent(number) if b.mode == STARTUP { // if b.rttStats != nil { // TODO: slow start. diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index ca20b420..e058ac7d 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -5,7 +5,6 @@ import ( "time" "github.com/metacubex/quic-go/congestion" - "github.com/metacubex/quic-go/logging" ) const ( @@ -54,9 +53,6 @@ type cubicSender struct { initialMaxCongestionWindow congestion.ByteCount maxDatagramSize congestion.ByteCount - - lastState logging.CongestionState - tracer logging.ConnectionTracer } var ( @@ -68,7 +64,6 @@ func NewCubicSender( clock Clock, initialMaxDatagramSize congestion.ByteCount, reno bool, - tracer logging.ConnectionTracer, ) *cubicSender { return newCubicSender( clock, @@ -76,7 +71,6 @@ func NewCubicSender( initialMaxDatagramSize, initialCongestionWindow*initialMaxDatagramSize, MaxCongestionWindowPackets*initialMaxDatagramSize, - tracer, ) } @@ -86,7 +80,6 @@ func newCubicSender( initialMaxDatagramSize, initialCongestionWindow, initialMaxCongestionWindow congestion.ByteCount, - tracer logging.ConnectionTracer, ) *cubicSender { c := &cubicSender{ largestSentPacketNumber: InvalidPacketNumber, @@ -99,14 +92,9 @@ func newCubicSender( cubic: NewCubic(clock), clock: clock, reno: reno, - tracer: tracer, maxDatagramSize: initialMaxDatagramSize, } c.pacer = newPacer(c.BandwidthEstimate) - if c.tracer != nil { - c.lastState = logging.CongestionStateSlowStart - c.tracer.UpdatedCongestionState(logging.CongestionStateSlowStart) - } return c } @@ -167,7 +155,6 @@ func (c *cubicSender) MaybeExitSlowStart() { c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) { // exit slow start c.slowStartThreshold = c.congestionWindow - c.maybeTraceStateChange(logging.CongestionStateCongestionAvoidance) } } @@ -187,14 +174,13 @@ func (c *cubicSender) OnPacketAcked( } } -func (c *cubicSender) OnPacketLost(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { +func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets // already sent should be treated as a single loss event, since it's expected. if packetNumber <= c.largestSentAtLastCutback { return } c.lastCutbackExitedSlowstart = c.InSlowStart() - c.maybeTraceStateChange(logging.CongestionStateRecovery) if c.reno { c.congestionWindow = congestion.ByteCount(float64(c.congestionWindow) * renoBeta) @@ -223,7 +209,6 @@ func (c *cubicSender) maybeIncreaseCwnd( // the current window. if !c.isCwndLimited(priorInFlight) { c.cubic.OnApplicationLimited() - c.maybeTraceStateChange(logging.CongestionStateApplicationLimited) return } if c.congestionWindow >= c.maxCongestionWindow() { @@ -232,11 +217,9 @@ func (c *cubicSender) maybeIncreaseCwnd( if c.InSlowStart() { // TCP slow start, exponential growth, increase by one for each ACK. c.congestionWindow += c.maxDatagramSize - c.maybeTraceStateChange(logging.CongestionStateSlowStart) return } // Congestion avoidance - c.maybeTraceStateChange(logging.CongestionStateCongestionAvoidance) if c.reno { // Classic Reno congestion avoidance. c.numAckedPackets++ @@ -297,14 +280,6 @@ func (c *cubicSender) OnConnectionMigration() { c.slowStartThreshold = c.initialMaxCongestionWindow } -func (c *cubicSender) maybeTraceStateChange(new logging.CongestionState) { - if c.tracer == nil || new == c.lastState { - return - } - c.tracer.UpdatedCongestionState(new) - c.lastState = new -} - func (c *cubicSender) SetMaxDatagramSize(s congestion.ByteCount) { if s < c.maxDatagramSize { panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s)) From 21fb5f75b8f383b343601402722130a90cb95d44 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 26 Sep 2023 09:06:00 +0800 Subject: [PATCH 002/192] fix: gvisor panic --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 74f5d0a7..3c26f0ae 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.12 + github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 github.com/miekg/dns v1.1.56 @@ -105,4 +105,4 @@ require ( golang.org/x/tools v0.13.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 diff --git a/go.sum b/go.sum index d251a6b7..584a797f 100644 --- a/go.sum +++ b/go.sum @@ -95,16 +95,16 @@ github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggF github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731 h1:F+xz1KCwUfCud5eWHKZr0QsWOeA+mqIFvn90r8hq+R8= github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 h1:qiTekhMDwY2vXARJx1D9EIEdtllbL7+ZBzHX9DQpWs4= -github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 h1:MkYAvDyhb7cwuqL4ZLKU3Oi6tYjFnz1sz5LS82JmtDo= +github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.12 h1:Jgmz0k3ddRiJ8zfS4X7j6B/iSy6GnOdDEU0nhqiZcK4= -github.com/metacubex/sing-tun v0.1.12/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M= +github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee h1:hbbq181N4ZaDbhk/iJ0iA+3xfI/6v+j3nWeN5Who1xQ= +github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= From e0458a8fdef6c0d722c5c2c383f62ae6ffe96da9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 28 Sep 2023 18:59:31 +0800 Subject: [PATCH 003/192] chore: decrease goroutine used in core tunnel --- adapter/inbound/addition.go | 11 +++++ constant/listener.go | 2 +- constant/tunnel.go | 10 +++++ hub/executor/executor.go | 30 ++++++-------- hub/route/configs.go | 22 ++++------ listener/autoredir/tcp.go | 8 ++-- listener/http/client.go | 4 +- listener/http/proxy.go | 8 ++-- listener/http/server.go | 8 ++-- listener/http/upgrade.go | 4 +- listener/inbound/base.go | 2 +- listener/inbound/http.go | 4 +- listener/inbound/hysteria2.go | 4 +- listener/inbound/mixed.go | 6 +-- listener/inbound/redir.go | 4 +- listener/inbound/shadowsocks.go | 4 +- listener/inbound/socks.go | 6 +-- listener/inbound/tproxy.go | 6 +-- listener/inbound/tuic.go | 4 +- listener/inbound/tun.go | 4 +- listener/inbound/tunnel.go | 12 +++--- listener/inbound/vmess.go | 4 +- listener/inner/tcp.go | 10 ++--- listener/listener.go | 64 ++++++++++++++--------------- listener/mixed/mixed.go | 12 +++--- listener/redir/tcp.go | 9 ++-- listener/shadowsocks/tcp.go | 14 +++---- listener/shadowsocks/udp.go | 11 ++--- listener/sing/sing.go | 47 ++++----------------- listener/sing_hysteria2/server.go | 5 +-- listener/sing_shadowsocks/server.go | 17 ++++---- listener/sing_tun/server.go | 5 +-- listener/sing_vmess/server.go | 13 +++--- listener/socks/tcp.go | 18 ++++---- listener/socks/udp.go | 11 ++--- listener/tproxy/packet.go | 20 ++++----- listener/tproxy/tproxy.go | 8 ++-- listener/tproxy/udp.go | 20 ++++----- listener/tuic/server.go | 12 ++---- listener/tunnel/tcp.go | 8 ++-- listener/tunnel/udp.go | 11 ++--- tunnel/tunnel.go | 39 ++++++++++++++---- 42 files changed, 252 insertions(+), 269 deletions(-) create mode 100644 constant/tunnel.go diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 47307ed7..327d00e9 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -1,6 +1,8 @@ package inbound import ( + "net" + C "github.com/Dreamacro/clash/constant" ) @@ -33,3 +35,12 @@ func WithSpecialProxy(specialProxy string) Addition { metadata.SpecialProxy = specialProxy } } + +func WithSrcAddr(addr net.Addr) Addition { + return func(metadata *C.Metadata) { + if ip, port, err := parseAddr(addr); err == nil { + metadata.SrcIP = ip + metadata.SrcPort = port + } + } +} diff --git a/constant/listener.go b/constant/listener.go index 6f9f169b..f69b4a9b 100644 --- a/constant/listener.go +++ b/constant/listener.go @@ -16,7 +16,7 @@ type MultiAddrListener interface { type InboundListener interface { Name() string - Listen(tcpIn chan<- ConnContext, udpIn chan<- PacketAdapter, natTable NatTable) error + Listen(tunnel Tunnel) error Close() error Address() string RawAddress() string diff --git a/constant/tunnel.go b/constant/tunnel.go new file mode 100644 index 00000000..39f8936a --- /dev/null +++ b/constant/tunnel.go @@ -0,0 +1,10 @@ +package constant + +type Tunnel interface { + // HandleTCPConn will handle a tcp connection blocking + HandleTCPConn(connCtx ConnContext) + // HandleUDPPacket will handle a udp packet nonblocking + HandleUDPPacket(packet PacketAdapter) + // NatTable return nat table + NatTable() NatTable +} diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 1831584f..a50d3539 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -118,7 +118,7 @@ func ApplyConfig(cfg *config.Config, force bool) { } func initInnerTcp() { - inner.New(tunnel.TCPIn()) + inner.New(tunnel.Tunnel) } func GetGeneral() *config.General { @@ -157,11 +157,7 @@ func GetGeneral() *config.General { } func updateListeners(general *config.General, listeners map[string]C.InboundListener, force bool) { - tcpIn := tunnel.TCPIn() - udpIn := tunnel.UDPIn() - natTable := tunnel.NatTable() - - listener.PatchInboundListeners(listeners, tcpIn, udpIn, natTable, true) + listener.PatchInboundListeners(listeners, tunnel.Tunnel, true) if !force { return } @@ -171,15 +167,15 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList bindAddress := general.BindAddress listener.SetBindAddress(bindAddress) - listener.ReCreateHTTP(general.Port, tcpIn) - listener.ReCreateSocks(general.SocksPort, tcpIn, udpIn) - listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn, natTable) - listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tcpIn, udpIn) - listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn, natTable) - listener.ReCreateMixed(general.MixedPort, tcpIn, udpIn) - listener.ReCreateShadowSocks(general.ShadowSocksConfig, tcpIn, udpIn) - listener.ReCreateVmess(general.VmessConfig, tcpIn, udpIn) - listener.ReCreateTuic(LC.TuicServer(general.TuicServer), tcpIn, udpIn) + listener.ReCreateHTTP(general.Port, tunnel.Tunnel) + listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) + listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) + listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) + listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) + listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel) + listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) + listener.ReCreateVmess(general.VmessConfig, tunnel.Tunnel) + listener.ReCreateTuic(general.TuicServer, tunnel.Tunnel) } func updateExperimental(c *config.Config) { @@ -339,7 +335,7 @@ func updateTun(general *config.General) { if general == nil { return } - listener.ReCreateTun(LC.Tun(general.Tun), tunnel.TCPIn(), tunnel.UDPIn()) + listener.ReCreateTun(general.Tun, tunnel.Tunnel) listener.ReCreateRedirToTun(general.Tun.RedirectToTun) } @@ -367,7 +363,7 @@ func updateSniffer(sniffer *config.Sniffer) { } func updateTunnels(tunnels []LC.Tunnel) { - listener.PatchTunnel(tunnels, tunnel.TCPIn(), tunnel.UDPIn()) + listener.PatchTunnel(tunnels, tunnel.Tunnel) } func updateGeneral(general *config.General) { diff --git a/hub/route/configs.go b/hub/route/configs.go index cb7c93f6..1f29de0c 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -249,19 +249,15 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { ports := P.GetPorts() - tcpIn := tunnel.TCPIn() - udpIn := tunnel.UDPIn() - natTable := tunnel.NatTable() - - P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tcpIn) - P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tcpIn, udpIn) - P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn, natTable) - P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn, natTable) - P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn) - P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tcpIn, udpIn) - P.ReCreateShadowSocks(pointerOrDefaultString(general.ShadowSocksConfig, ports.ShadowSocksConfig), tcpIn, udpIn) - P.ReCreateVmess(pointerOrDefaultString(general.VmessConfig, ports.VmessConfig), tcpIn, udpIn) - P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tcpIn, udpIn) + P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tunnel.Tunnel) + P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tunnel.Tunnel) + P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tunnel.Tunnel) + P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel) + P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel) + P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tunnel.Tunnel) + P.ReCreateShadowSocks(pointerOrDefaultString(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel) + P.ReCreateVmess(pointerOrDefaultString(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel) + P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tunnel.Tunnel) if general.Mode != nil { tunnel.SetMode(*general.Mode) diff --git a/listener/autoredir/tcp.go b/listener/autoredir/tcp.go index c390d89a..57df45f3 100644 --- a/listener/autoredir/tcp.go +++ b/listener/autoredir/tcp.go @@ -43,7 +43,7 @@ func (l *Listener) SetLookupFunc(lookupFunc func(netip.AddrPort) (socks5.Addr, e l.lookupFunc = lookupFunc } -func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) { +func (l *Listener) handleRedir(conn net.Conn, tunnel C.Tunnel) { if l.lookupFunc == nil { log.Errorln("[Auto Redirect] lookup function is nil") return @@ -58,10 +58,10 @@ func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) { N.TCPKeepAlive(conn) - in <- inbound.NewSocket(target, conn, C.REDIR, l.additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.REDIR, l.additions...)) } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-REDIR"), @@ -87,7 +87,7 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go rl.handleRedir(c, in) + go rl.handleRedir(c, tunnel) } }() diff --git a/listener/http/client.go b/listener/http/client.go index 15c21f91..76c7c8eb 100644 --- a/listener/http/client.go +++ b/listener/http/client.go @@ -12,7 +12,7 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -func newClient(source net.Addr, in chan<- C.ConnContext, additions ...inbound.Addition) *http.Client { +func newClient(source net.Addr, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { return &http.Client{ Transport: &http.Transport{ // from http.DefaultTransport @@ -32,7 +32,7 @@ func newClient(source net.Addr, in chan<- C.ConnContext, additions ...inbound.Ad left, right := net.Pipe() - in <- inbound.NewHTTP(dstAddr, source, right, additions...) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, source, right, additions...)) return left, nil }, diff --git a/listener/http/proxy.go b/listener/http/proxy.go index a95f7195..a267fbad 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -14,8 +14,8 @@ import ( "github.com/Dreamacro/clash/log" ) -func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { - client := newClient(c.RemoteAddr(), in, additions...) +func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { + client := newClient(c.RemoteAddr(), tunnel, additions...) defer client.CloseIdleConnections() conn := N.NewBufferedConn(c) @@ -48,7 +48,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[strin break // close connection } - in <- inbound.NewHTTPS(request, conn, additions...) + tunnel.HandleTCPConn(inbound.NewHTTPS(request, conn, additions...)) return // hijack connection } @@ -61,7 +61,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[strin request.RequestURI = "" if isUpgradeRequest(request) { - handleUpgrade(conn, request, in, additions...) + handleUpgrade(conn, request, tunnel, additions...) return // hijack connection } diff --git a/listener/http/server.go b/listener/http/server.go index 8819af11..0377d3b6 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -30,11 +30,11 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { - return NewWithAuthenticate(addr, in, true, additions...) +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { + return NewWithAuthenticate(addr, tunnel, true, additions...) } -func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool, additions ...inbound.Addition) (*Listener, error) { +func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-HTTP"), @@ -65,7 +65,7 @@ func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool } continue } - go HandleConn(conn, in, c, additions...) + go HandleConn(conn, tunnel, c, additions...) } }() diff --git a/listener/http/upgrade.go b/listener/http/upgrade.go index 90e28f0a..e67928ce 100644 --- a/listener/http/upgrade.go +++ b/listener/http/upgrade.go @@ -25,7 +25,7 @@ func isUpgradeRequest(req *http.Request) bool { return false } -func handleUpgrade(conn net.Conn, request *http.Request, in chan<- C.ConnContext, additions ...inbound.Addition) { +func handleUpgrade(conn net.Conn, request *http.Request, tunnel C.Tunnel, additions ...inbound.Addition) { defer conn.Close() removeProxyHeaders(request.Header) @@ -43,7 +43,7 @@ func handleUpgrade(conn net.Conn, request *http.Request, in chan<- C.ConnContext left, right := net.Pipe() - in <- inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right, additions...) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right, additions...)) var bufferedLeft *N.BufferedConn if request.TLS != nil { diff --git a/listener/inbound/base.go b/listener/inbound/base.go index b132ac6c..83695bb1 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -61,7 +61,7 @@ func (b *Base) RawAddress() string { } // Listen implements constant.InboundListener -func (*Base) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (*Base) Listen(tunnel C.Tunnel) error { return nil } diff --git a/listener/inbound/http.go b/listener/inbound/http.go index a93f9684..99577177 100644 --- a/listener/inbound/http.go +++ b/listener/inbound/http.go @@ -42,9 +42,9 @@ func (h *HTTP) Address() string { } // Listen implements constant.InboundListener -func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (h *HTTP) Listen(tunnel C.Tunnel) error { var err error - h.l, err = http.New(h.RawAddress(), tcpIn, h.Additions()...) + h.l, err = http.New(h.RawAddress(), tunnel, h.Additions()...) if err != nil { return err } diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index 430d0e68..df537a41 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -77,9 +77,9 @@ func (t *Hysteria2) Address() string { } // Listen implements constant.InboundListener -func (t *Hysteria2) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Hysteria2) Listen(tunnel C.Tunnel) error { var err error - t.l, err = sing_hysteria2.New(t.ts, tcpIn, udpIn, t.Additions()...) + t.l, err = sing_hysteria2.New(t.ts, tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/mixed.go b/listener/inbound/mixed.go index dbba264c..ce445bda 100644 --- a/listener/inbound/mixed.go +++ b/listener/inbound/mixed.go @@ -50,14 +50,14 @@ func (m *Mixed) Address() string { } // Listen implements constant.InboundListener -func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (m *Mixed) Listen(tunnel C.Tunnel) error { var err error - m.l, err = mixed.New(m.RawAddress(), tcpIn, m.Additions()...) + m.l, err = mixed.New(m.RawAddress(), tunnel, m.Additions()...) if err != nil { return err } if m.udp { - m.lUDP, err = socks.NewUDP(m.RawAddress(), udpIn, m.Additions()...) + m.lUDP, err = socks.NewUDP(m.RawAddress(), tunnel, m.Additions()...) if err != nil { return err } diff --git a/listener/inbound/redir.go b/listener/inbound/redir.go index 4b88d895..085bf3a8 100644 --- a/listener/inbound/redir.go +++ b/listener/inbound/redir.go @@ -42,9 +42,9 @@ func (r *Redir) Address() string { } // Listen implements constant.InboundListener -func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (r *Redir) Listen(tunnel C.Tunnel) error { var err error - r.l, err = redir.New(r.RawAddress(), tcpIn, r.Additions()...) + r.l, err = redir.New(r.RawAddress(), tunnel, r.Additions()...) if err != nil { return err } diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index 4659f4d7..fa5b3082 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -59,9 +59,9 @@ func (s *ShadowSocks) Address() string { } // Listen implements constant.InboundListener -func (s *ShadowSocks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (s *ShadowSocks) Listen(tunnel C.Tunnel) error { var err error - s.l, err = sing_shadowsocks.New(s.ss, tcpIn, udpIn, s.Additions()...) + s.l, err = sing_shadowsocks.New(s.ss, tunnel, s.Additions()...) if err != nil { return err } diff --git a/listener/inbound/socks.go b/listener/inbound/socks.go index aac2ee23..09580a57 100644 --- a/listener/inbound/socks.go +++ b/listener/inbound/socks.go @@ -68,13 +68,13 @@ func (s *Socks) Address() string { } // Listen implements constant.InboundListener -func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (s *Socks) Listen(tunnel C.Tunnel) error { var err error - if s.stl, err = socks.New(s.RawAddress(), tcpIn, s.Additions()...); err != nil { + if s.stl, err = socks.New(s.RawAddress(), tunnel, s.Additions()...); err != nil { return err } if s.udp { - if s.sul, err = socks.NewUDP(s.RawAddress(), udpIn, s.Additions()...); err != nil { + if s.sul, err = socks.NewUDP(s.RawAddress(), tunnel, s.Additions()...); err != nil { return err } } diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index 00cd0849..682188f5 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -49,14 +49,14 @@ func (t *TProxy) Address() string { } // Listen implements constant.InboundListener -func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *TProxy) Listen(tunnel C.Tunnel) error { var err error - t.lTCP, err = tproxy.New(t.RawAddress(), tcpIn, t.Additions()...) + t.lTCP, err = tproxy.New(t.RawAddress(), tunnel, t.Additions()...) if err != nil { return err } if t.udp { - t.lUDP, err = tproxy.NewUDP(t.RawAddress(), udpIn, natTable, t.Additions()...) + t.lUDP, err = tproxy.NewUDP(t.RawAddress(), tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index bf448d31..e7b51392 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -73,9 +73,9 @@ func (t *Tuic) Address() string { } // Listen implements constant.InboundListener -func (t *Tuic) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Tuic) Listen(tunnel C.Tunnel) error { var err error - t.l, err = tuic.New(t.ts, tcpIn, udpIn, t.Additions()...) + t.l, err = tuic.New(t.ts, tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index eb16d2dd..3151e6b0 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -113,9 +113,9 @@ func (t *Tun) Address() string { } // Listen implements constant.InboundListener -func (t *Tun) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Tun) Listen(tunnel C.Tunnel) error { var err error - t.l, err = sing_tun.New(t.tun, tcpIn, udpIn, t.Additions()...) + t.l, err = sing_tun.New(t.tun, tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/tunnel.go b/listener/inbound/tunnel.go index 41d024ef..2af663a5 100644 --- a/listener/inbound/tunnel.go +++ b/listener/inbound/tunnel.go @@ -4,7 +4,7 @@ import ( "fmt" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/tunnel" + LT "github.com/Dreamacro/clash/listener/tunnel" "github.com/Dreamacro/clash/log" ) @@ -21,8 +21,8 @@ func (o TunnelOption) Equal(config C.InboundConfig) bool { type Tunnel struct { *Base config *TunnelOption - ttl *tunnel.Listener - tul *tunnel.PacketConn + ttl *LT.Listener + tul *LT.PacketConn } func NewTunnel(options *TunnelOption) (*Tunnel, error) { @@ -74,16 +74,16 @@ func (t *Tunnel) Address() string { } // Listen implements constant.InboundListener -func (t *Tunnel) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Tunnel) Listen(tunnel C.Tunnel) error { var err error for _, network := range t.config.Network { switch network { case "tcp": - if t.ttl, err = tunnel.New(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tcpIn, t.Additions()...); err != nil { + if t.ttl, err = LT.New(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { return err } case "udp": - if t.tul, err = tunnel.NewUDP(t.RawAddress(), t.config.Target, t.config.SpecialProxy, udpIn, t.Additions()...); err != nil { + if t.tul, err = LT.NewUDP(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { return err } default: diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 70e840a5..fa2c30f1 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -69,7 +69,7 @@ func (v *Vmess) Address() string { } // Listen implements constant.InboundListener -func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (v *Vmess) Listen(tunnel C.Tunnel) error { var err error users := make([]LC.VmessUser, len(v.config.Users)) for i, v := range v.config.Users { @@ -79,7 +79,7 @@ func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, AlterID: v.AlterID, } } - v.l, err = sing_vmess.New(v.vs, tcpIn, udpIn, v.Additions()...) + v.l, err = sing_vmess.New(v.vs, tunnel, v.Additions()...) if err != nil { return err } diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index 9ba87e2f..4a54a82f 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -8,19 +8,19 @@ import ( C "github.com/Dreamacro/clash/constant" ) -var tcpIn chan<- C.ConnContext +var tunnel C.Tunnel -func New(in chan<- C.ConnContext) { - tcpIn = in +func New(t C.Tunnel) { + tunnel = t } func HandleTcp(address string) (conn net.Conn, err error) { - if tcpIn == nil { + if tunnel == nil { return nil, errors.New("tcp uninitialized") } // executor Parsed conn1, conn2 := net.Pipe() context := inbound.NewInner(conn2, address) - tcpIn <- context + go tunnel.HandleTCPConn(context) return conn1, nil } diff --git a/listener/listener.go b/listener/listener.go index b1d59d49..afbcf14c 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -23,7 +23,7 @@ import ( "github.com/Dreamacro/clash/listener/socks" "github.com/Dreamacro/clash/listener/tproxy" "github.com/Dreamacro/clash/listener/tuic" - "github.com/Dreamacro/clash/listener/tunnel" + LT "github.com/Dreamacro/clash/listener/tunnel" "github.com/Dreamacro/clash/log" "github.com/samber/lo" @@ -42,8 +42,8 @@ var ( tproxyUDPListener *tproxy.UDPListener mixedListener *mixed.Listener mixedUDPLister *socks.UDPListener - tunnelTCPListeners = map[string]*tunnel.Listener{} - tunnelUDPListeners = map[string]*tunnel.PacketConn{} + tunnelTCPListeners = map[string]*LT.Listener{} + tunnelUDPListeners = map[string]*LT.PacketConn{} inboundListeners = map[string]C.InboundListener{} tunLister *sing_tun.Listener shadowSocksListener C.MultiAddrListener @@ -112,7 +112,7 @@ func SetBindAddress(host string) { bindAddress = host } -func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) { +func ReCreateHTTP(port int, tunnel C.Tunnel) { httpMux.Lock() defer httpMux.Unlock() @@ -137,7 +137,7 @@ func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) { return } - httpListener, err = http.New(addr, tcpIn) + httpListener, err = http.New(addr, tunnel) if err != nil { log.Errorln("Start HTTP server error: %s", err.Error()) return @@ -146,7 +146,7 @@ func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) { log.Infoln("HTTP proxy listening at: %s", httpListener.Address()) } -func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateSocks(port int, tunnel C.Tunnel) { socksMux.Lock() defer socksMux.Unlock() @@ -188,12 +188,12 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd return } - tcpListener, err := socks.New(addr, tcpIn) + tcpListener, err := socks.New(addr, tunnel) if err != nil { return } - udpListener, err := socks.NewUDP(addr, udpIn) + udpListener, err := socks.NewUDP(addr, tunnel) if err != nil { tcpListener.Close() return @@ -205,7 +205,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd log.Infoln("SOCKS proxy listening at: %s", socksListener.Address()) } -func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) { +func ReCreateRedir(port int, tunnel C.Tunnel) { redirMux.Lock() defer redirMux.Unlock() @@ -238,12 +238,12 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd return } - redirListener, err = redir.New(addr, tcpIn) + redirListener, err = redir.New(addr, tunnel) if err != nil { return } - redirUDPListener, err = tproxy.NewUDP(addr, udpIn, natTable) + redirUDPListener, err = tproxy.NewUDP(addr, tunnel) if err != nil { log.Warnln("Failed to start Redir UDP Listener: %s", err) } @@ -251,7 +251,7 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd log.Infoln("Redirect proxy listening at: %s", redirListener.Address()) } -func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateShadowSocks(shadowSocksConfig string, tunnel C.Tunnel) { ssMux.Lock() defer ssMux.Unlock() @@ -292,7 +292,7 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u return } - listener, err := sing_shadowsocks.New(ssConfig, tcpIn, udpIn) + listener, err := sing_shadowsocks.New(ssConfig, tunnel) if err != nil { return } @@ -305,7 +305,7 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u return } -func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateVmess(vmessConfig string, tunnel C.Tunnel) { vmessMux.Lock() defer vmessMux.Unlock() @@ -344,7 +344,7 @@ func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- return } - listener, err := sing_vmess.New(vsConfig, tcpIn, udpIn) + listener, err := sing_vmess.New(vsConfig, tunnel) if err != nil { return } @@ -357,7 +357,7 @@ func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- return } -func ReCreateTuic(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateTuic(config LC.TuicServer, tunnel C.Tunnel) { tuicMux.Lock() defer func() { LastTuicConf = config @@ -389,7 +389,7 @@ func ReCreateTuic(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- return } - listener, err := tuic.New(config, tcpIn, udpIn) + listener, err := tuic.New(config, tunnel) if err != nil { return } @@ -402,7 +402,7 @@ func ReCreateTuic(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- return } -func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) { +func ReCreateTProxy(port int, tunnel C.Tunnel) { tproxyMux.Lock() defer tproxyMux.Unlock() @@ -435,12 +435,12 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketA return } - tproxyListener, err = tproxy.New(addr, tcpIn) + tproxyListener, err = tproxy.New(addr, tunnel) if err != nil { return } - tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn, natTable) + tproxyUDPListener, err = tproxy.NewUDP(addr, tunnel) if err != nil { log.Warnln("Failed to start TProxy UDP Listener: %s", err) } @@ -448,7 +448,7 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketA log.Infoln("TProxy server listening at: %s", tproxyListener.Address()) } -func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateMixed(port int, tunnel C.Tunnel) { mixedMux.Lock() defer mixedMux.Unlock() @@ -489,12 +489,12 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd return } - mixedListener, err = mixed.New(addr, tcpIn) + mixedListener, err = mixed.New(addr, tunnel) if err != nil { return } - mixedUDPLister, err = socks.NewUDP(addr, udpIn) + mixedUDPLister, err = socks.NewUDP(addr, tunnel) if err != nil { mixedListener.Close() return @@ -503,7 +503,7 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address()) } -func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateTun(tunConf LC.Tun, tunnel C.Tunnel) { tunMux.Lock() defer func() { LastTunConf = tunConf @@ -531,7 +531,7 @@ func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.Pack return } - lister, err := sing_tun.New(tunConf, tcpIn, udpIn) + lister, err := sing_tun.New(tunConf, tunnel) if err != nil { return } @@ -573,7 +573,7 @@ func ReCreateRedirToTun(ifaceNames []string) { log.Infoln("Attached tc ebpf program to interfaces %v", tcProgram.RawNICs()) } -func ReCreateAutoRedir(ifaceNames []string, tcpIn chan<- C.ConnContext, _ chan<- C.PacketAdapter) { +func ReCreateAutoRedir(ifaceNames []string, tunnel C.Tunnel) { autoRedirMux.Lock() defer autoRedirMux.Unlock() @@ -614,7 +614,7 @@ func ReCreateAutoRedir(ifaceNames []string, tcpIn chan<- C.ConnContext, _ chan<- addr := genAddr("*", C.TcpAutoRedirPort, true) - autoRedirListener, err = autoredir.New(addr, tcpIn) + autoRedirListener, err = autoredir.New(addr, tunnel) if err != nil { return } @@ -629,7 +629,7 @@ func ReCreateAutoRedir(ifaceNames []string, tcpIn chan<- C.ConnContext, _ chan<- log.Infoln("Auto redirect proxy listening at: %s, attached tc ebpf program to interfaces %v", autoRedirListener.Address(), autoRedirProgram.RawNICs()) } -func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func PatchTunnel(tunnels []LC.Tunnel, tunnel C.Tunnel) { tunnelMux.Lock() defer tunnelMux.Unlock() @@ -699,7 +699,7 @@ func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C for _, elm := range needCreate { key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy) if elm.network == "tcp" { - l, err := tunnel.New(elm.addr, elm.target, elm.proxy, tcpIn) + l, err := LT.New(elm.addr, elm.target, elm.proxy, tunnel) if err != nil { log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) continue @@ -707,7 +707,7 @@ func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C tunnelTCPListeners[key] = l log.Infoln("Tunnel(tcp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelTCPListeners[key].Address()) } else { - l, err := tunnel.NewUDP(elm.addr, elm.target, elm.proxy, udpIn) + l, err := LT.NewUDP(elm.addr, elm.target, elm.proxy, tunnel) if err != nil { log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) continue @@ -718,7 +718,7 @@ func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C } } -func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable, dropOld bool) { +func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tunnel C.Tunnel, dropOld bool) { inboundMux.Lock() defer inboundMux.Unlock() @@ -730,7 +730,7 @@ func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn ch continue } } - if err := newListener.Listen(tcpIn, udpIn, natTable); err != nil { + if err := newListener.Listen(tunnel); err != nil { log.Errorln("Listener %s listen err: %s", name, err.Error()) continue } diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index 7241927d..d2ede096 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -36,7 +36,7 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-MIXED"), @@ -62,14 +62,14 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go handleConn(c, in, ml.cache, additions...) + go handleConn(c, tunnel, ml.cache, additions...) } }() return ml, nil } -func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { +func handleConn(conn net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { N.TCPKeepAlive(conn) bufConn := N.NewBufferedConn(conn) @@ -80,10 +80,10 @@ func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[st switch head[0] { case socks4.Version: - socks.HandleSocks4(bufConn, in, additions...) + socks.HandleSocks4(bufConn, tunnel, additions...) case socks5.Version: - socks.HandleSocks5(bufConn, in, additions...) + socks.HandleSocks5(bufConn, tunnel, additions...) default: - http.HandleConn(bufConn, in, cache, additions...) + http.HandleConn(bufConn, tunnel, cache, additions...) } } diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go index 9a843af8..6419760f 100644 --- a/listener/redir/tcp.go +++ b/listener/redir/tcp.go @@ -30,7 +30,7 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-REDIR"), @@ -55,18 +55,19 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go handleRedir(c, in, additions...) + go handleRedir(c, tunnel, additions...) } }() return rl, nil } -func handleRedir(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { + +func handleRedir(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { target, err := parserPacket(conn) if err != nil { conn.Close() return } N.TCPKeepAlive(conn) - in <- inbound.NewSocket(target, conn, C.REDIR, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.REDIR, additions...)) } diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 2d0958a0..8959e6ba 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -22,7 +22,7 @@ type Listener struct { var _listener *Listener -func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) { +func New(config LC.ShadowsocksServer, tunnel C.Tunnel) (*Listener, error) { pickCipher, err := core.PickCipher(config.Cipher, nil, config.Password) if err != nil { return nil, err @@ -36,7 +36,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C if config.Udp { //UDP - ul, err := NewUDP(addr, pickCipher, udpIn) + ul, err := NewUDP(addr, pickCipher, tunnel) if err != nil { return nil, err } @@ -60,7 +60,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C continue } N.TCPKeepAlive(c) - go sl.HandleConn(c, tcpIn) + go sl.HandleConn(c, tunnel) } }() } @@ -99,7 +99,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { conn = l.pickCipher.StreamConn(conn) conn = N.NewDeadlineConn(conn) // embed ss can't handle readDeadline correctly @@ -108,12 +108,12 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions _ = conn.Close() return } - in <- inbound.NewSocket(target, conn, C.SHADOWSOCKS, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.SHADOWSOCKS, additions...)) } -func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { +func HandleShadowSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool { if _listener != nil && _listener.pickCipher != nil { - go _listener.HandleConn(conn, in, additions...) + go _listener.HandleConn(conn, tunnel, additions...) return true } return false diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index af610431..cc055853 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -17,7 +17,7 @@ type UDPListener struct { closed bool } -func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UDPListener, error) { +func NewUDP(addr string, pickCipher core.Cipher, tunnel C.Tunnel) (*UDPListener, error) { l, err := net.ListenPacket("udp", addr) if err != nil { return nil, err @@ -42,7 +42,7 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD } continue } - handleSocksUDP(conn, in, data, put, remoteAddr) + handleSocksUDP(conn, tunnel, data, put, remoteAddr) } }() @@ -58,7 +58,7 @@ func (l *UDPListener) LocalAddr() net.Addr { return l.packetConn.LocalAddr() } -func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr, additions ...inbound.Addition) { +func handleSocksUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, put func(), addr net.Addr, additions ...inbound.Addition) { tgtAddr := socks5.SplitAddr(buf) if tgtAddr == nil { // Unresolved UDP packet, return buffer to the pool @@ -76,8 +76,5 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, pu payload: payload, put: put, } - select { - case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS, additions...): - default: - } + tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, C.SHADOWSOCKS, additions...)) } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index d5731bbf..a9bee564 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -28,43 +28,12 @@ import ( const UDPTimeout = 5 * time.Minute type ListenerHandler struct { - TcpIn chan<- C.ConnContext - UdpIn chan<- C.PacketAdapter + Tunnel C.Tunnel Type C.Type Additions []inbound.Addition UDPTimeout time.Duration } -type waitCloseConn struct { - N.ExtendedConn - wg *sync.WaitGroup - close sync.Once - rAddr net.Addr -} - -func (c *waitCloseConn) Close() error { // call from handleTCPConn(connCtx C.ConnContext) - c.close.Do(func() { - c.wg.Done() - }) - return c.ExtendedConn.Close() -} - -func (c *waitCloseConn) RemoteAddr() net.Addr { - return c.rAddr -} - -func (c *waitCloseConn) Upstream() any { - return c.ExtendedConn -} - -func (c *waitCloseConn) ReaderReplaceable() bool { - return true -} - -func (c *waitCloseConn) WriterReplaceable() bool { - return true -} - func UpstreamMetadata(metadata M.Metadata) M.Metadata { return M.Metadata{ Source: metadata.Source, @@ -117,14 +86,14 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta return h.ParseSpecialFqdn(ctx, conn, metadata) } target := socks5.ParseAddr(metadata.Destination.String()) - wg := &sync.WaitGroup{} - defer wg.Wait() // this goroutine must exit after conn.Close() - wg.Add(1) if deadline.NeedAdditionalReadDeadline(conn) { conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline } - h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, combineAdditions(ctx, h.Additions)...) + connCtx := inbound.NewSocket(target, conn, h.Type, combineAdditions(ctx, h.Additions)...) + inbound.WithSrcAddr(metadata.Source.TCPAddr()).Apply(connCtx.Metadata()) // set srcAddr from sing's metadata + + h.Tunnel.HandleTCPConn(connCtx) // this goroutine must exit after conn unused return nil } @@ -177,10 +146,8 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. lAddr: conn.LocalAddr(), buff: buff, } - select { - case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...): - default: - } + + h.Tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...)) } return nil } diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 4e0a7c07..3628a2ce 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -32,7 +32,7 @@ type Listener struct { services []*hysteria2.Service[string] } -func New(config LC.Hysteria2Server, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { +func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { var sl *Listener var err error if len(additions) == 0 { @@ -43,8 +43,7 @@ func New(config LC.Hysteria2Server, tcpIn chan<- C.ConnContext, udpIn chan<- C.P } h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.HYSTERIA2, Additions: additions, } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index d0e137a7..51baeaa1 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -35,7 +35,7 @@ type Listener struct { var _listener *Listener -func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (C.MultiAddrListener, error) { +func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addition) (C.MultiAddrListener, error) { var sl *Listener var err error if len(additions) == 0 { @@ -51,8 +51,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C udpTimeout := int64(sing.UDPTimeout.Seconds()) h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.SHADOWSOCKS, Additions: additions, } @@ -68,7 +67,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h, ntp.Now) default: err = fmt.Errorf("shadowsocks: unsupported method: %s", config.Cipher) - return embedSS.New(config, tcpIn, udpIn) + return embedSS.New(config, tunnel) } if err != nil { return nil, err @@ -148,7 +147,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C } N.TCPKeepAlive(c) - go sl.HandleConn(c, tcpIn) + go sl.HandleConn(c, tunnel) } }() } @@ -188,7 +187,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { ctx := sing.WithAdditions(context.TODO(), additions...) err := l.service.NewConnection(ctx, conn, M.Metadata{ Protocol: "shadowsocks", @@ -200,10 +199,10 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions } } -func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { +func HandleShadowSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool { if _listener != nil && _listener.service != nil { - go _listener.HandleConn(conn, in, additions...) + go _listener.HandleConn(conn, tunnel, additions...) return true } - return embedSS.HandleShadowSocks(conn, in, additions...) + return embedSS.HandleShadowSocks(conn, tunnel, additions...) } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 66fe8cd5..4ca6fc30 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -88,7 +88,7 @@ func checkTunName(tunName string) (ok bool) { return true } -func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (l *Listener, err error) { +func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Listener, err error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TUN"), @@ -152,8 +152,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte handler := &ListenerHandler{ ListenerHandler: sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.TUN, Additions: additions, UDPTimeout: time.Second * time.Duration(udpTimeout), diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 06f3e051..d28213c8 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -27,7 +27,7 @@ type Listener struct { var _listener *Listener -func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (sl *Listener, err error) { +func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) (sl *Listener, err error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-VMESS"), @@ -38,8 +38,7 @@ func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packe }() } h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.VMESS, Additions: additions, } @@ -87,7 +86,7 @@ func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packe } N.TCPKeepAlive(c) - go sl.HandleConn(c, tcpIn) + go sl.HandleConn(c, tunnel) } }() } @@ -122,7 +121,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { ctx := sing.WithAdditions(context.TODO(), additions...) err := l.service.NewConnection(ctx, conn, metadata.Metadata{ Protocol: "vmess", @@ -134,9 +133,9 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions } } -func HandleVmess(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { +func HandleVmess(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool { if _listener != nil && _listener.service != nil { - go _listener.HandleConn(conn, in, additions...) + go _listener.HandleConn(conn, tunnel, additions...) return true } return false diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index 2fd252a3..89b23562 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -34,7 +34,7 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-SOCKS"), @@ -59,14 +59,14 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go handleSocks(c, in, additions...) + go handleSocks(c, tunnel, additions...) } }() return sl, nil } -func handleSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func handleSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) bufConn := N.NewBufferedConn(conn) head, err := bufConn.Peek(1) @@ -77,24 +77,24 @@ func handleSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Ad switch head[0] { case socks4.Version: - HandleSocks4(bufConn, in, additions...) + HandleSocks4(bufConn, tunnel, additions...) case socks5.Version: - HandleSocks5(bufConn, in, additions...) + HandleSocks5(bufConn, tunnel, additions...) default: conn.Close() } } -func HandleSocks4(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { addr, _, err := socks4.ServerHandshake(conn, authStore.Authenticator()) if err != nil { conn.Close() return } - in <- inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4, additions...)) } -func HandleSocks5(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func HandleSocks5(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator()) if err != nil { conn.Close() @@ -105,5 +105,5 @@ func HandleSocks5(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.A io.Copy(io.Discard, conn) return } - in <- inbound.NewSocket(target, conn, C.SOCKS5, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.SOCKS5, additions...)) } diff --git a/listener/socks/udp.go b/listener/socks/udp.go index 31858f74..2f786e95 100644 --- a/listener/socks/udp.go +++ b/listener/socks/udp.go @@ -33,7 +33,7 @@ func (l *UDPListener) Close() error { return l.packetConn.Close() } -func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) { +func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPListener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-SOCKS"), @@ -66,14 +66,14 @@ func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Additio } continue } - handleSocksUDP(l, in, data, put, remoteAddr, additions...) + handleSocksUDP(l, tunnel, data, put, remoteAddr, additions...) } }() return sl, nil } -func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr, additions ...inbound.Addition) { +func handleSocksUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, put func(), addr net.Addr, additions ...inbound.Addition) { target, payload, err := socks5.DecodeUDPPacket(buf) if err != nil { // Unresolved UDP packet, return buffer to the pool @@ -88,8 +88,5 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, pu payload: payload, put: put, } - select { - case in <- inbound.NewPacket(target, packet, C.SOCKS5, additions...): - default: - } + tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, C.SOCKS5, additions...)) } diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index b73339a1..24fff09a 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -13,11 +13,10 @@ import ( ) type packet struct { - pc net.PacketConn - lAddr netip.AddrPort - buf []byte - in chan<- C.PacketAdapter - natTable C.NatTable + pc net.PacketConn + lAddr netip.AddrPort + buf []byte + tunnel C.Tunnel } func (c *packet) Data() []byte { @@ -26,7 +25,7 @@ func (c *packet) Data() []byte { // WriteBack opens a new socket binding `addr` to write UDP packet back func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { - tc, err := createOrGetLocalConn(addr, c.LocalAddr(), c.in, c.natTable) + tc, err := createOrGetLocalConn(addr, c.LocalAddr(), c.tunnel) if err != nil { n = 0 return @@ -52,9 +51,10 @@ func (c *packet) InAddr() net.Addr { // this function listen at rAddr and write to lAddr // for here, rAddr is the ip/port client want to access // lAddr is the ip/port client opened -func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable C.NatTable) (*net.UDPConn, error) { +func createOrGetLocalConn(rAddr, lAddr net.Addr, tunnel C.Tunnel) (*net.UDPConn, error) { remote := rAddr.String() local := lAddr.String() + natTable := tunnel.NatTable() localConn := natTable.GetForLocalConn(local, remote) // localConn not exist if localConn == nil { @@ -76,7 +76,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT natTable.DeleteLockForLocalConn(local, remote) cond.Broadcast() }() - conn, err := listenLocalConn(rAddr, lAddr, in, natTable) + conn, err := listenLocalConn(rAddr, lAddr, tunnel) if err != nil { log.Errorln("listenLocalConn failed with error: %s, packet loss (rAddr[%T]=%s lAddr[%T]=%s)", err.Error(), rAddr, remote, lAddr, local) return nil, err @@ -90,7 +90,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT // this function listen at rAddr // and send what received to program itself, then send to real remote -func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable C.NatTable) (*net.UDPConn, error) { +func listenLocalConn(rAddr, lAddr net.Addr, tunnel C.Tunnel) (*net.UDPConn, error) { additions := []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), inbound.WithSpecialRules(""), @@ -113,7 +113,7 @@ func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable } // since following localPackets are pass through this socket which listen rAddr // I choose current listener as packet's packet conn - handlePacketConn(lc, in, natTable, buf[:br], lAddr.(*net.UDPAddr).AddrPort(), rAddr.(*net.UDPAddr).AddrPort(), additions...) + handlePacketConn(lc, tunnel, buf[:br], lAddr.(*net.UDPAddr).AddrPort(), rAddr.(*net.UDPAddr).AddrPort(), additions...) } }() return lc, nil diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go index 8c868609..319d5c30 100644 --- a/listener/tproxy/tproxy.go +++ b/listener/tproxy/tproxy.go @@ -31,13 +31,13 @@ func (l *Listener) Close() error { return l.listener.Close() } -func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) handleTProxy(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { target := socks5.ParseAddrToSocksAddr(conn.LocalAddr()) N.TCPKeepAlive(conn) - in <- inbound.NewSocket(target, conn, C.TPROXY, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.TPROXY, additions...)) } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), @@ -74,7 +74,7 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go rl.handleTProxy(c, in, additions...) + go rl.handleTProxy(c, tunnel, additions...) } }() diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go index d3727180..c8460def 100644 --- a/listener/tproxy/udp.go +++ b/listener/tproxy/udp.go @@ -32,7 +32,7 @@ func (l *UDPListener) Close() error { return l.packetConn.Close() } -func NewUDP(addr string, in chan<- C.PacketAdapter, natTable C.NatTable, additions ...inbound.Addition) (*UDPListener, error) { +func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPListener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), @@ -83,24 +83,20 @@ func NewUDP(addr string, in chan<- C.PacketAdapter, natTable C.NatTable, additio // try to unmap 4in6 address lAddr = netip.AddrPortFrom(lAddr.Addr().Unmap(), lAddr.Port()) } - handlePacketConn(l, in, natTable, buf[:n], lAddr, rAddr, additions...) + handlePacketConn(l, tunnel, buf[:n], lAddr, rAddr, additions...) } }() return rl, nil } -func handlePacketConn(pc net.PacketConn, in chan<- C.PacketAdapter, natTable C.NatTable, buf []byte, lAddr, rAddr netip.AddrPort, additions ...inbound.Addition) { +func handlePacketConn(pc net.PacketConn, tunnel C.Tunnel, buf []byte, lAddr, rAddr netip.AddrPort, additions ...inbound.Addition) { target := socks5.AddrFromStdAddrPort(rAddr) pkt := &packet{ - pc: pc, - lAddr: lAddr, - buf: buf, - in: in, - natTable: natTable, - } - select { - case in <- inbound.NewPacket(target, pkt, C.TPROXY, additions...): - default: + pc: pc, + lAddr: lAddr, + buf: buf, + tunnel: tunnel, } + tunnel.HandleUDPPacket(inbound.NewPacket(target, pkt, C.TPROXY, additions...)) } diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 125c53e1..bfead7f3 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -31,7 +31,7 @@ type Listener struct { servers []*tuic.Server } -func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { +func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TUIC"), @@ -39,8 +39,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet } } h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.TUIC, Additions: additions, } @@ -106,7 +105,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet }() return nil } - tcpIn <- connCtx + go tunnel.HandleTCPConn(connCtx) return nil } handleUdpFn := func(addr socks5.Addr, packet C.UDPPacket, _additions ...inbound.Addition) error { @@ -115,10 +114,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet newAdditions = slices.Clone(additions) newAdditions = append(newAdditions, _additions...) } - select { - case udpIn <- inbound.NewPacket(addr, packet, C.TUIC, newAdditions...): - default: - } + tunnel.HandleUDPPacket(inbound.NewPacket(addr, packet, C.TUIC, newAdditions...)) return nil } diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index d660d2b8..8cc527fb 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -34,14 +34,14 @@ func (l *Listener) Close() error { return l.listener.Close() } -func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) handleTCP(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) ctx := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) ctx.Metadata().SpecialProxy = l.proxy - in <- ctx + tunnel.HandleTCPConn(ctx) } -func New(addr, target, proxy string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { l, err := inbound.Listen("tcp", addr) if err != nil { return nil, err @@ -68,7 +68,7 @@ func New(addr, target, proxy string, in chan<- C.ConnContext, additions ...inbou } continue } - go rl.handleTCP(c, in, additions...) + go rl.handleTCP(c, tunnel, additions...) } }() diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index 0795084c..c2f1dcc3 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -34,7 +34,7 @@ func (l *PacketConn) Close() error { return l.conn.Close() } -func NewUDP(addr, target, proxy string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*PacketConn, error) { +func NewUDP(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*PacketConn, error) { l, err := net.ListenPacket("udp", addr) if err != nil { return nil, err @@ -62,14 +62,14 @@ func NewUDP(addr, target, proxy string, in chan<- C.PacketAdapter, additions ... } continue } - sl.handleUDP(l, in, buf[:n], remoteAddr, additions...) + sl.handleUDP(l, tunnel, buf[:n], remoteAddr, additions...) } }() return sl, nil } -func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr, additions ...inbound.Addition) { +func (l *PacketConn) handleUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, addr net.Addr, additions ...inbound.Addition) { packet := &packet{ pc: pc, rAddr: addr, @@ -78,8 +78,5 @@ func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf ctx := inbound.NewPacket(l.target, packet, C.TUNNEL, additions...) ctx.Metadata().SpecialProxy = l.proxy - select { - case in <- ctx: - default: - } + tunnel.HandleUDPPacket(ctx) } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index ff64915a..1e73a833 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -49,6 +49,25 @@ var ( fakeIPRange netip.Prefix ) +type tunnel struct{} + +var Tunnel C.Tunnel = tunnel{} + +func (t tunnel) HandleTCPConn(connCtx C.ConnContext) { + handleTCPConn(connCtx) +} + +func (t tunnel) HandleUDPPacket(packet C.PacketAdapter) { + select { + case udpQueue <- packet: + default: + } +} + +func (t tunnel) NatTable() C.NatTable { + return natTable +} + func OnSuspend() { status.Store(Suspend) } @@ -90,11 +109,13 @@ func init() { } // TCPIn return fan-in queue +// Deprecated: using Tunnel instead func TCPIn() chan<- C.ConnContext { return tcpQueue } // UDPIn return fan-in udp queue +// Deprecated: using Tunnel instead func UDPIn() chan<- C.PacketAdapter { return udpQueue } @@ -197,10 +218,6 @@ func isHandle(t C.Type) bool { func processUDP() { queue := udpQueue for conn := range queue { - if !isHandle(conn.Metadata().Type) { - conn.Drop() - continue - } handleUDPConn(conn) } } @@ -216,10 +233,6 @@ func process() { queue := tcpQueue for conn := range queue { - if !isHandle(conn.Metadata().Type) { - _ = conn.Conn().Close() - continue - } go handleTCPConn(conn) } } @@ -284,6 +297,11 @@ func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, r } func handleUDPConn(packet C.PacketAdapter) { + if !isHandle(packet.Metadata().Type) { + packet.Drop() + return + } + metadata := packet.Metadata() if !metadata.Valid() { packet.Drop() @@ -409,6 +427,11 @@ func handleUDPConn(packet C.PacketAdapter) { } func handleTCPConn(connCtx C.ConnContext) { + if !isHandle(connCtx.Metadata().Type) { + _ = connCtx.Conn().Close() + return + } + defer func(conn net.Conn) { _ = conn.Close() }(connCtx.Conn()) From c2b06a02bf8884b572955aed59303ec8e9cd821e Mon Sep 17 00:00:00 2001 From: Andrei Shevchuk Date: Fri, 29 Sep 2023 00:36:25 +0000 Subject: [PATCH 004/192] feat: add reload signal support (#780) Backport Clash feature by @septs, see Dreamacro/clash#2908 --- main.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index e13b8dc8..e9f66058 100644 --- a/main.go +++ b/main.go @@ -115,7 +115,20 @@ func main() { defer executor.Shutdown() - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - <-sigCh + termSign := make(chan os.Signal, 1) + hupSign := make(chan os.Signal, 1) + signal.Notify(termSign, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(hupSign, syscall.SIGHUP) + for { + select { + case <-termSign: + return + case <-hupSign: + if cfg, err := executor.ParseWithPath(C.Path.Config()); err == nil { + executor.ApplyConfig(cfg, true) + } else { + log.Errorln("Parse config error: %s", err.Error()) + } + } + } } From 0ed3c5a5ec7df9319a797c057b5420b578e9467d Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 29 Sep 2023 08:42:57 +0800 Subject: [PATCH 005/192] chore: improve subscription userinfo parsing (#781) do not use regex parsing for `Subscription-UserInfo` header field --- adapter/provider/subscription_info.go | 54 ++++++++------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/adapter/provider/subscription_info.go b/adapter/provider/subscription_info.go index fc6992e2..8b90601c 100644 --- a/adapter/provider/subscription_info.go +++ b/adapter/provider/subscription_info.go @@ -1,7 +1,6 @@ package provider import ( - "github.com/dlclark/regexp2" "strconv" "strings" ) @@ -13,45 +12,24 @@ type SubscriptionInfo struct { Expire int64 } -func NewSubscriptionInfo(str string) (si *SubscriptionInfo, err error) { - si = &SubscriptionInfo{} - str = strings.ToLower(str) - reTraffic := regexp2.MustCompile("upload=(\\d+); download=(\\d+); total=(\\d+)", 0) - reExpire := regexp2.MustCompile("expire=(\\d+)", 0) - - match, err := reTraffic.FindStringMatch(str) - if err != nil || match == nil { - return nil, err - } - group := match.Groups() - si.Upload, err = str2uint64(group[1].String()) - if err != nil { - return nil, err - } - - si.Download, err = str2uint64(group[2].String()) - if err != nil { - return nil, err - } - - si.Total, err = str2uint64(group[3].String()) - if err != nil { - return nil, err - } - - match, _ = reExpire.FindStringMatch(str) - if match != nil { - group = match.Groups() - si.Expire, err = str2uint64(group[1].String()) +func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo, err error) { + userinfo = strings.ToLower(userinfo) + userinfo = strings.ReplaceAll(userinfo, " ", "") + si = new(SubscriptionInfo) + for _, field := range strings.Split(userinfo, ";") { + switch name, value, _ := strings.Cut(field, "="); name { + case "upload": + si.Upload, err = strconv.ParseInt(value, 10, 64) + case "download": + si.Download, err = strconv.ParseInt(value, 10, 64) + case "total": + si.Total, err = strconv.ParseInt(value, 10, 64) + case "expire": + si.Expire, err = strconv.ParseInt(value, 10, 64) + } if err != nil { - return nil, err + return } } - return } - -func str2uint64(str string) (int64, error) { - i, err := strconv.ParseInt(str, 10, 64) - return i, err -} From 10e7c533d72665a352cd065250ffb4a97ef58f0d Mon Sep 17 00:00:00 2001 From: NyaMisty Date: Fri, 29 Sep 2023 08:50:50 +0800 Subject: [PATCH 006/192] feat: support clash premium's structured log stream (#735) * feat: support clash premium's structured log stream New version of Clash for Windows uses `ws://external-controller/logs?token=&level=info&format=structured` to get real time log. When Clash Premium Core reveices `format=structured`, it returns a different form of JSON log entry. Supporting this feature will allow better Clash for Windows integration Signed-off-by: Misty --- hub/route/server.go | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/hub/route/server.go b/hub/route/server.go index d2fecd05..3d0df95e 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -293,6 +293,16 @@ type Log struct { Type string `json:"type"` Payload string `json:"payload"` } +type LogStructuredField struct { + Key string `json:"key"` + Value string `json:"value"` +} +type LogStructured struct { + Time string `json:"time"` + Level string `json:"level"` + Message string `json:"message"` + Fields []LogStructuredField `json:"fields"` +} func getLogs(w http.ResponseWriter, r *http.Request) { levelText := r.URL.Query().Get("level") @@ -300,6 +310,12 @@ func getLogs(w http.ResponseWriter, r *http.Request) { levelText = "info" } + formatText := r.URL.Query().Get("format") + isStructured := false + if formatText == "structured" { + isStructured = true + } + level, ok := log.LogLevelMapping[levelText] if !ok { render.Status(r, http.StatusBadRequest) @@ -342,11 +358,26 @@ func getLogs(w http.ResponseWriter, r *http.Request) { } buf.Reset() - if err := json.NewEncoder(buf).Encode(Log{ - Type: logM.Type(), - Payload: logM.Payload, - }); err != nil { - break + if !isStructured { + if err := json.NewEncoder(buf).Encode(Log{ + Type: logM.Type(), + Payload: logM.Payload, + }); err != nil { + break + } + } else { + newLevel := logM.Type() + if newLevel == "warning" { + newLevel = "warn" + } + if err := json.NewEncoder(buf).Encode(LogStructured{ + Time: time.Now().Format(time.TimeOnly), + Level: newLevel, + Message: logM.Payload, + Fields: []LogStructuredField{}, + }); err != nil { + break + } } var err error From 265a6b9b685ec01073fb63951efaea4f5a153b21 Mon Sep 17 00:00:00 2001 From: Kiva Date: Fri, 29 Sep 2023 08:51:13 +0800 Subject: [PATCH 007/192] chore: reduce string split immediately after string concat (#773) --- adapter/outbound/hysteria.go | 2 +- adapter/outbound/hysteria2.go | 2 +- adapter/outbound/shadowsocks.go | 4 ++-- adapter/outbound/singmux.go | 2 +- adapter/outbound/vmess.go | 6 +++--- transport/hysteria/core/client.go | 6 +----- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 8a9d6258..5a41274c 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -46,7 +46,7 @@ type Hysteria struct { } func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { - tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), h.genHdc(ctx, opts...)) + tcpConn, err := h.client.DialTCP(metadata.String(), metadata.DstPort, h.genHdc(ctx, opts...)) if err != nil { return nil, err } diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 57c15a12..6ed4cd8c 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -55,7 +55,7 @@ type Hysteria2Option struct { func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { options := h.Base.DialOptions(opts...) h.dialer.SetDialer(dialer.NewDialer(options...)) - c, err := h.client.DialConn(ctx, M.ParseSocksaddr(metadata.RemoteAddress())) + c, err := h.client.DialConn(ctx, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) if err != nil { return nil, err } diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index f744ec53..40868d04 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -123,9 +123,9 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada } } if useEarly { - return ss.method.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + return ss.method.DialEarlyConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)), nil } else { - return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + return ss.method.DialConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) } } diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index c9f50ce9..fb6b1c29 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -42,7 +42,7 @@ type ProxyBase interface { func (s *SingMux) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { options := s.base.DialOptions(opts...) s.dialer.SetDialer(dialer.NewDialer(options...)) - c, err := s.client.DialContext(ctx, "tcp", M.ParseSocksaddr(metadata.RemoteAddress())) + c, err := s.client.DialContext(ctx, "tcp", M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) if err != nil { return nil, err } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index db654580..326f0c6f 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -260,10 +260,10 @@ func (v *Vmess) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err } else { if N.NeedHandshake(c) { conn = v.client.DialEarlyConn(c, - M.ParseSocksaddr(metadata.RemoteAddress())) + M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) } else { conn, err = v.client.DialConn(c, - M.ParseSocksaddr(metadata.RemoteAddress())) + M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) } } if err != nil { @@ -284,7 +284,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d safeConnClose(c, err) }(c) - c, err = v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + c, err = v.client.DialConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) if err != nil { return nil, err } diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index a219e76c..ecc8a6f1 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -194,11 +194,7 @@ func (c *Client) openStreamWithReconnect(dialer utils.PacketDialer) (quic.Connec return c.quicSession, &wrappedQUICStream{stream}, err } -func (c *Client) DialTCP(addr string, dialer utils.PacketDialer) (net.Conn, error) { - host, port, err := utils.SplitHostPort(addr) - if err != nil { - return nil, err - } +func (c *Client) DialTCP(host string, port uint16, dialer utils.PacketDialer) (net.Conn, error) { session, stream, err := c.openStreamWithReconnect(dialer) if err != nil { return nil, err From 02397868fc065fe881920959ddf02a0ffcf5c532 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 29 Sep 2023 13:26:59 +0800 Subject: [PATCH 008/192] docs: support reload in service --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 51cecc2d..bbf5cf43 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,7 @@ AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE Restart=always ExecStartPre=/usr/bin/sleep 1s ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta +ExecReload=/bin/kill -HUP $MAINPID [Install] WantedBy=multi-user.target From 5f6de610e10b818d87ea98d756213db2a3262d74 Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Sat, 2 Sep 2023 20:56:42 +0800 Subject: [PATCH 009/192] Fix: should check all ips need to fallback (#2915) --- dns/resolver.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dns/resolver.go b/dns/resolver.go index 89e36214..3a530918 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -18,6 +18,7 @@ import ( "github.com/Dreamacro/clash/log" D "github.com/miekg/dns" + "github.com/samber/lo" "golang.org/x/sync/singleflight" ) @@ -200,7 +201,7 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M isIPReq := isIPRequest(q) if isIPReq { - cache=true + cache = true return r.ipExchange(ctx, m) } @@ -332,7 +333,10 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er res := <-msgCh if res.Error == nil { if ips := msgToIP(res.Msg); len(ips) != 0 { - if !r.shouldIPFallback(ips[0]) { + shouldNotFallback := lo.EveryBy(ips, func(ip netip.Addr) bool { + return !r.shouldIPFallback(ip) + }) + if shouldNotFallback { msg, err = res.Msg, res.Error // no need to wait for fallback result return } From a526bb70ea27a401419acc4b2942577705229f99 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 30 Sep 2023 13:39:50 +0800 Subject: [PATCH 010/192] chore: fix bbr bugs --- go.mod | 4 +- go.sum | 8 +- transport/hysteria/congestion/brutal.go | 4 + transport/tuic/congestion/bbr_sender.go | 178 ++++++++-------------- transport/tuic/congestion/cubic_sender.go | 4 + 5 files changed, 79 insertions(+), 119 deletions(-) diff --git a/go.mod b/go.mod index 3c26f0ae..826eb0ba 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731 - github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 + github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55 + github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee diff --git a/go.sum b/go.sum index 584a797f..d6c96aaa 100644 --- a/go.sum +++ b/go.sum @@ -93,12 +93,12 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731 h1:F+xz1KCwUfCud5eWHKZr0QsWOeA+mqIFvn90r8hq+R8= -github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55 h1:cAqp0BFOTr/1TpFicH1dA1q/6fp7E/JkqHBORfohqr4= +github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 h1:MkYAvDyhb7cwuqL4ZLKU3Oi6tYjFnz1sz5LS82JmtDo= github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= +github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c h1:j7PKIUUhOAxJaLf/NmUKuIs9R06xNoYizwYgqf5HSrA= +github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c/go.mod h1:TPAXFCHCtzW9Dm+wq1l1R/p0v/S/xmuRU0qfPR7WlOA= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 88bf6f34..67067917 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -100,6 +100,10 @@ func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostByt b.updateAckRate(currentTimestamp) } +func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + // Stub +} + func (b *BrutalSender) SetMaxDatagramSize(size congestion.ByteCount) { b.maxDatagramSize = size b.pacer.SetMaxDatagramSize(size) diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 2c842300..8c18c616 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -347,15 +347,36 @@ func (b *bbrSender) MaybeExitSlowStart() { } func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, eventTime time.Time) { + // Stub +} + +func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { + // Stub +} + +func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { totalBytesAckedBefore := b.sampler.totalBytesAcked isRoundStart, minRttExpired := false, false - lastAckedPacket := number - isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket) - minRttExpired = b.UpdateBandwidthAndMinRtt(eventTime, number, ackedBytes) - b.UpdateRecoveryState(false, isRoundStart) - bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore - excessAcked := b.UpdateAckAggregationBytes(eventTime, bytesAcked) + if lostPackets != nil { + b.DiscardLostPackets(lostPackets) + } + + // Input the new data into the BBR model of the connection. + var excessAcked congestion.ByteCount + if len(ackedPackets) > 0 { + lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber + isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket) + minRttExpired = b.UpdateBandwidthAndMinRtt(eventTime, ackedPackets) + b.UpdateRecoveryState(len(lostPackets) > 0, isRoundStart) + bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore + excessAcked = b.UpdateAckAggregationBytes(eventTime, bytesAcked) + } + + // Handle logic specific to PROBE_BW mode. + if b.mode == PROBE_BW { + b.UpdateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) > 0) + } // Handle logic specific to STARTUP and DRAIN modes. if isRoundStart && !b.isAtFullBandwidth { @@ -366,38 +387,12 @@ func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes con // Handle logic specific to PROBE_RTT. b.MaybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) - // After the model is updated, recalculate the pacing rate and congestion - // window. - b.CalculatePacingRate() - b.CalculateCongestionWindow(bytesAcked, excessAcked) - b.CalculateRecoveryWindow(bytesAcked, congestion.ByteCount(0)) - -} - -func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { - eventTime := time.Now() - totalBytesAckedBefore := b.sampler.totalBytesAcked - isRoundStart, minRttExpired := false, false - - b.DiscardLostPackets(number, lostBytes) - - // Input the new data into the BBR model of the connection. - var excessAcked congestion.ByteCount - - // Handle logic specific to PROBE_BW mode. - if b.mode == PROBE_BW { - b.UpdateGainCyclePhase(time.Now(), priorInFlight, true) - } - - // Handle logic specific to STARTUP and DRAIN modes. - b.MaybeExitStartupOrDrain(eventTime) - - // Handle logic specific to PROBE_RTT. - b.MaybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) - // Calculate number of packets acked and lost. bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore - bytesLost := lostBytes + bytesLost := congestion.ByteCount(0) + for _, packet := range lostPackets { + bytesLost += packet.BytesLost + } // After the model is updated, recalculate the pacing rate and congestion // window. @@ -406,53 +401,6 @@ func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes b.CalculateRecoveryWindow(bytesAcked, bytesLost) } -//func (b *bbrSender) OnCongestionEvent(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets, lostPackets []*congestion.Packet) { -// totalBytesAckedBefore := b.sampler.totalBytesAcked -// isRoundStart, minRttExpired := false, false -// -// if lostPackets != nil { -// b.DiscardLostPackets(lostPackets) -// } -// -// // Input the new data into the BBR model of the connection. -// var excessAcked congestion.ByteCount -// if len(ackedPackets) > 0 { -// lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber -// isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket) -// minRttExpired = b.UpdateBandwidthAndMinRtt(eventTime, ackedPackets) -// b.UpdateRecoveryState(lastAckedPacket, len(lostPackets) > 0, isRoundStart) -// bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore -// excessAcked = b.UpdateAckAggregationBytes(eventTime, bytesAcked) -// } -// -// // Handle logic specific to PROBE_BW mode. -// if b.mode == PROBE_BW { -// b.UpdateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) > 0) -// } -// -// // Handle logic specific to STARTUP and DRAIN modes. -// if isRoundStart && !b.isAtFullBandwidth { -// b.CheckIfFullBandwidthReached() -// } -// b.MaybeExitStartupOrDrain(eventTime) -// -// // Handle logic specific to PROBE_RTT. -// b.MaybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) -// -// // Calculate number of packets acked and lost. -// bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore -// bytesLost := congestion.ByteCount(0) -// for _, packet := range lostPackets { -// bytesLost += packet.Length -// } -// -// // After the model is updated, recalculate the pacing rate and congestion -// // window. -// b.CalculatePacingRate() -// b.CalculateCongestionWindow(bytesAcked, excessAcked) -// b.CalculateRecoveryWindow(bytesAcked, bytesLost) -//} - //func (b *bbrSender) SetNumEmulatedConnections(n int) { // //} @@ -553,30 +501,32 @@ func (b *bbrSender) UpdateRoundTripCounter(lastAckedPacket congestion.PacketNumb return false } -func (b *bbrSender) UpdateBandwidthAndMinRtt(now time.Time, number congestion.PacketNumber, ackedBytes congestion.ByteCount) bool { +func (b *bbrSender) UpdateBandwidthAndMinRtt(now time.Time, ackedPackets []congestion.AckedPacketInfo) bool { sampleMinRtt := InfiniteRTT - if !b.alwaysGetBwSampleWhenAcked && ackedBytes == 0 { - // Skip acked packets with 0 in flight bytes when updating bandwidth. - return false - } - bandwidthSample := b.sampler.OnPacketAcked(now, number) - if b.alwaysGetBwSampleWhenAcked && !bandwidthSample.stateAtSend.isValid { - // From the sampler's perspective, the packet has never been sent, or the - // packet has been acked or marked as lost previously. - return false - } - b.lastSampleIsAppLimited = bandwidthSample.stateAtSend.isAppLimited - // has_non_app_limited_sample_ |= - // !bandwidth_sample.state_at_send.is_app_limited; - if !bandwidthSample.stateAtSend.isAppLimited { - b.hasNoAppLimitedSample = true - } - if bandwidthSample.rtt > 0 { - sampleMinRtt = minRtt(sampleMinRtt, bandwidthSample.rtt) - } - if !bandwidthSample.stateAtSend.isAppLimited || bandwidthSample.bandwidth > b.BandwidthEstimate() { - b.maxBandwidth.Update(int64(bandwidthSample.bandwidth), b.roundTripCount) + for _, packet := range ackedPackets { + if !b.alwaysGetBwSampleWhenAcked && packet.BytesAcked == 0 { + // Skip acked packets with 0 in flight bytes when updating bandwidth. + return false + } + bandwidthSample := b.sampler.OnPacketAcked(now, packet.PacketNumber) + if b.alwaysGetBwSampleWhenAcked && !bandwidthSample.stateAtSend.isValid { + // From the sampler's perspective, the packet has never been sent, or the + // packet has been acked or marked as lost previously. + return false + } + b.lastSampleIsAppLimited = bandwidthSample.stateAtSend.isAppLimited + // has_non_app_limited_sample_ |= + // !bandwidth_sample.state_at_send.is_app_limited; + if !bandwidthSample.stateAtSend.isAppLimited { + b.hasNoAppLimitedSample = true + } + if bandwidthSample.rtt > 0 { + sampleMinRtt = minRtt(sampleMinRtt, bandwidthSample.rtt) + } + if !bandwidthSample.stateAtSend.isAppLimited || bandwidthSample.bandwidth > b.BandwidthEstimate() { + b.maxBandwidth.Update(int64(bandwidthSample.bandwidth), b.roundTripCount) + } } // If none of the RTT samples are valid, return immediately. @@ -619,14 +569,16 @@ func (b *bbrSender) ShouldExtendMinRttExpiry() bool { return false } -func (b *bbrSender) DiscardLostPackets(number congestion.PacketNumber, lostBytes congestion.ByteCount) { - b.sampler.OnCongestionEvent(number) - if b.mode == STARTUP { - // if b.rttStats != nil { - // TODO: slow start. - // } - if b.startupRateReductionMultiplier != 0 { - b.startupBytesLost += lostBytes +func (b *bbrSender) DiscardLostPackets(lostPackets []congestion.LostPacketInfo) { + for _, packet := range lostPackets { + b.sampler.OnCongestionEvent(packet.PacketNumber) + if b.mode == STARTUP { + // if b.rttStats != nil { + // TODO: slow start. + // } + if b.startupRateReductionMultiplier != 0 { + b.startupBytesLost += packet.BytesLost + } } } } diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index e058ac7d..f544cd74 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -197,6 +197,10 @@ func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lo c.numAckedPackets = 0 } +func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + // Stub +} + // Called when we receive an ack. Normal TCP tracks how many packets one ack // represents, but quic has a separate ack for each packet. func (c *cubicSender) maybeIncreaseCwnd( From fedad26c136adb09929c6ab807b77f7ff42efded Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:26:39 +0800 Subject: [PATCH 011/192] chore: support relative path for hy2/tuic inbound cert --- listener/sing_hysteria2/server.go | 3 +++ listener/tuic/server.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 3628a2ce..7897bd84 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -50,6 +50,9 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi sl = &Listener{false, config, nil, nil} + config.Certificate = C.Path.Resolve(config.Certificate) + config.PrivateKey = C.Path.Resolve(config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) if err != nil { return nil, err diff --git a/listener/tuic/server.go b/listener/tuic/server.go index bfead7f3..12a6ac6d 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -43,6 +43,10 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( Type: C.TUIC, Additions: additions, } + + config.Certificate = C.Path.Resolve(config.Certificate) + config.PrivateKey = C.Path.Resolve(config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) if err != nil { return nil, err From 828b5ad8bb8b33cc8fc256e2a7e29d350570840e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 30 Sep 2023 23:55:56 +0800 Subject: [PATCH 012/192] chore: add new bbr implementation --- transport/tuic/common/congestion.go | 29 +- transport/tuic/congestion/cubic.go | 213 ---- transport/tuic/congestion/cubic_sender.go | 297 ------ .../tuic/congestion/hybrid_slow_start.go | 112 --- transport/tuic/congestion/minmax.go | 56 -- transport/tuic/congestion_v2/bandwidth.go | 27 + .../tuic/congestion_v2/bandwidth_sampler.go | 874 +++++++++++++++++ transport/tuic/congestion_v2/bbr_sender.go | 927 ++++++++++++++++++ transport/tuic/congestion_v2/clock.go | 18 + transport/tuic/congestion_v2/minmax_go120.go | 19 + transport/tuic/congestion_v2/minmax_go121.go | 13 + transport/tuic/congestion_v2/pacer.go | 71 ++ .../packet_number_indexed_queue.go | 199 ++++ transport/tuic/congestion_v2/ringbuffer.go | 118 +++ .../tuic/congestion_v2/windowed_filter.go | 162 +++ 15 files changed, 2440 insertions(+), 695 deletions(-) delete mode 100644 transport/tuic/congestion/cubic.go delete mode 100644 transport/tuic/congestion/cubic_sender.go delete mode 100644 transport/tuic/congestion/hybrid_slow_start.go delete mode 100644 transport/tuic/congestion/minmax.go create mode 100644 transport/tuic/congestion_v2/bandwidth.go create mode 100644 transport/tuic/congestion_v2/bandwidth_sampler.go create mode 100644 transport/tuic/congestion_v2/bbr_sender.go create mode 100644 transport/tuic/congestion_v2/clock.go create mode 100644 transport/tuic/congestion_v2/minmax_go120.go create mode 100644 transport/tuic/congestion_v2/minmax_go121.go create mode 100644 transport/tuic/congestion_v2/pacer.go create mode 100644 transport/tuic/congestion_v2/packet_number_indexed_queue.go create mode 100644 transport/tuic/congestion_v2/ringbuffer.go create mode 100644 transport/tuic/congestion_v2/windowed_filter.go diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 158f22d6..1176ebd6 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -2,6 +2,7 @@ package common import ( "github.com/Dreamacro/clash/transport/tuic/congestion" + congestionv2 "github.com/Dreamacro/clash/transport/tuic/congestion_v2" "github.com/metacubex/quic-go" c "github.com/metacubex/quic-go/congestion" @@ -17,23 +18,7 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { cwnd = 32 } switch cc { - case "cubic": - quicConn.SetCongestionControl( - congestion.NewCubicSender( - congestion.DefaultClock{}, - congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - false, - ), - ) - case "new_reno": - quicConn.SetCongestionControl( - congestion.NewCubicSender( - congestion.DefaultClock{}, - congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - true, - ), - ) - case "bbr": + case "bbr_meta_v1": quicConn.SetCongestionControl( congestion.NewBBRSender( congestion.DefaultClock{}, @@ -42,5 +27,15 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize, ), ) + case "bbr_meta_v2": + fallthrough + case "bbr": + quicConn.SetCongestionControl( + congestionv2.NewBbrSender( + congestionv2.DefaultClock{}, + congestionv2.GetInitialPacketSize(quicConn.RemoteAddr()), + c.ByteCount(cwnd), + ), + ) } } diff --git a/transport/tuic/congestion/cubic.go b/transport/tuic/congestion/cubic.go deleted file mode 100644 index dd491a32..00000000 --- a/transport/tuic/congestion/cubic.go +++ /dev/null @@ -1,213 +0,0 @@ -package congestion - -import ( - "math" - "time" - - "github.com/metacubex/quic-go/congestion" -) - -// This cubic implementation is based on the one found in Chromiums's QUIC -// implementation, in the files net/quic/congestion_control/cubic.{hh,cc}. - -// Constants based on TCP defaults. -// The following constants are in 2^10 fractions of a second instead of ms to -// allow a 10 shift right to divide. - -// 1024*1024^3 (first 1024 is from 0.100^3) -// where 0.100 is 100 ms which is the scaling round trip time. -const ( - cubeScale = 40 - cubeCongestionWindowScale = 410 - cubeFactor congestion.ByteCount = 1 << cubeScale / cubeCongestionWindowScale / maxDatagramSize - // TODO: when re-enabling cubic, make sure to use the actual packet size here - maxDatagramSize = congestion.ByteCount(InitialPacketSizeIPv4) -) - -const defaultNumConnections = 1 - -// Default Cubic backoff factor -const beta float32 = 0.7 - -// Additional backoff factor when loss occurs in the concave part of the Cubic -// curve. This additional backoff factor is expected to give up bandwidth to -// new concurrent flows and speed up convergence. -const betaLastMax float32 = 0.85 - -// Cubic implements the cubic algorithm from TCP -type Cubic struct { - clock Clock - - // Number of connections to simulate. - numConnections int - - // Time when this cycle started, after last loss event. - epoch time.Time - - // Max congestion window used just before last loss event. - // Note: to improve fairness to other streams an additional back off is - // applied to this value if the new value is below our latest value. - lastMaxCongestionWindow congestion.ByteCount - - // Number of acked bytes since the cycle started (epoch). - ackedBytesCount congestion.ByteCount - - // TCP Reno equivalent congestion window in packets. - estimatedTCPcongestionWindow congestion.ByteCount - - // Origin point of cubic function. - originPointCongestionWindow congestion.ByteCount - - // Time to origin point of cubic function in 2^10 fractions of a second. - timeToOriginPoint uint32 - - // Last congestion window in packets computed by cubic function. - lastTargetCongestionWindow congestion.ByteCount -} - -// NewCubic returns a new Cubic instance -func NewCubic(clock Clock) *Cubic { - c := &Cubic{ - clock: clock, - numConnections: defaultNumConnections, - } - c.Reset() - return c -} - -// Reset is called after a timeout to reset the cubic state -func (c *Cubic) Reset() { - c.epoch = time.Time{} - c.lastMaxCongestionWindow = 0 - c.ackedBytesCount = 0 - c.estimatedTCPcongestionWindow = 0 - c.originPointCongestionWindow = 0 - c.timeToOriginPoint = 0 - c.lastTargetCongestionWindow = 0 -} - -func (c *Cubic) alpha() float32 { - // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that - // beta here is a cwnd multiplier, and is equal to 1-beta from the paper. - // We derive the equivalent alpha for an N-connection emulation as: - b := c.beta() - return 3 * float32(c.numConnections) * float32(c.numConnections) * (1 - b) / (1 + b) -} - -func (c *Cubic) beta() float32 { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (float32(c.numConnections) - 1 + beta) / float32(c.numConnections) -} - -func (c *Cubic) betaLastMax() float32 { - // betaLastMax is the additional backoff factor after loss for our - // N-connection emulation, which emulates the additional backoff of - // an ensemble of N TCP-Reno connections on a single loss event. The - // effective multiplier is computed as: - return (float32(c.numConnections) - 1 + betaLastMax) / float32(c.numConnections) -} - -// OnApplicationLimited is called on ack arrival when sender is unable to use -// the available congestion window. Resets Cubic state during quiescence. -func (c *Cubic) OnApplicationLimited() { - // When sender is not using the available congestion window, the window does - // not grow. But to be RTT-independent, Cubic assumes that the sender has been - // using the entire window during the time since the beginning of the current - // "epoch" (the end of the last loss recovery period). Since - // application-limited periods break this assumption, we reset the epoch when - // in such a period. This reset effectively freezes congestion window growth - // through application-limited periods and allows Cubic growth to continue - // when the entire window is being used. - c.epoch = time.Time{} -} - -// CongestionWindowAfterPacketLoss computes a new congestion window to use after -// a loss event. Returns the new congestion window in packets. The new -// congestion window is a multiplicative decrease of our current window. -func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow congestion.ByteCount) congestion.ByteCount { - if currentCongestionWindow+maxDatagramSize < c.lastMaxCongestionWindow { - // We never reached the old max, so assume we are competing with another - // flow. Use our extra back off factor to allow the other flow to go up. - c.lastMaxCongestionWindow = congestion.ByteCount(c.betaLastMax() * float32(currentCongestionWindow)) - } else { - c.lastMaxCongestionWindow = currentCongestionWindow - } - c.epoch = time.Time{} // Reset time. - return congestion.ByteCount(float32(currentCongestionWindow) * c.beta()) -} - -// CongestionWindowAfterAck computes a new congestion window to use after a received ACK. -// Returns the new congestion window in packets. The new congestion window -// follows a cubic function that depends on the time passed since last -// packet loss. -func (c *Cubic) CongestionWindowAfterAck( - ackedBytes congestion.ByteCount, - currentCongestionWindow congestion.ByteCount, - delayMin time.Duration, - eventTime time.Time, -) congestion.ByteCount { - c.ackedBytesCount += ackedBytes - - if c.epoch.IsZero() { - // First ACK after a loss event. - c.epoch = eventTime // Start of epoch. - c.ackedBytesCount = ackedBytes // Reset count. - // Reset estimated_tcp_congestion_window_ to be in sync with cubic. - c.estimatedTCPcongestionWindow = currentCongestionWindow - if c.lastMaxCongestionWindow <= currentCongestionWindow { - c.timeToOriginPoint = 0 - c.originPointCongestionWindow = currentCongestionWindow - } else { - c.timeToOriginPoint = uint32(math.Cbrt(float64(cubeFactor * (c.lastMaxCongestionWindow - currentCongestionWindow)))) - c.originPointCongestionWindow = c.lastMaxCongestionWindow - } - } - - // Change the time unit from microseconds to 2^10 fractions per second. Take - // the round trip time in account. This is done to allow us to use shift as a - // divide operator. - elapsedTime := int64(eventTime.Add(delayMin).Sub(c.epoch)/time.Microsecond) << 10 / (1000 * 1000) - - // Right-shifts of negative, signed numbers have implementation-dependent - // behavior, so force the offset to be positive, as is done in the kernel. - offset := int64(c.timeToOriginPoint) - elapsedTime - if offset < 0 { - offset = -offset - } - - deltaCongestionWindow := congestion.ByteCount(cubeCongestionWindowScale*offset*offset*offset) * maxDatagramSize >> cubeScale - var targetCongestionWindow congestion.ByteCount - if elapsedTime > int64(c.timeToOriginPoint) { - targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow - } else { - targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow - } - // Limit the CWND increase to half the acked bytes. - targetCongestionWindow = Min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) - - // Increase the window by approximately Alpha * 1 MSS of bytes every - // time we ack an estimated tcp window of bytes. For small - // congestion windows (less than 25), the formula below will - // increase slightly slower than linearly per estimated tcp window - // of bytes. - c.estimatedTCPcongestionWindow += congestion.ByteCount(float32(c.ackedBytesCount) * c.alpha() * float32(maxDatagramSize) / float32(c.estimatedTCPcongestionWindow)) - c.ackedBytesCount = 0 - - // We have a new cubic congestion window. - c.lastTargetCongestionWindow = targetCongestionWindow - - // Compute target congestion_window based on cubic target and estimated TCP - // congestion_window, use highest (fastest). - if targetCongestionWindow < c.estimatedTCPcongestionWindow { - targetCongestionWindow = c.estimatedTCPcongestionWindow - } - return targetCongestionWindow -} - -// SetNumConnections sets the number of emulated connections -func (c *Cubic) SetNumConnections(n int) { - c.numConnections = n -} diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go deleted file mode 100644 index f544cd74..00000000 --- a/transport/tuic/congestion/cubic_sender.go +++ /dev/null @@ -1,297 +0,0 @@ -package congestion - -import ( - "fmt" - "time" - - "github.com/metacubex/quic-go/congestion" -) - -const ( - maxBurstPackets = 3 - renoBeta = 0.7 // Reno backoff factor. - minCongestionWindowPackets = 2 - initialCongestionWindow = 32 -) - -const InvalidPacketNumber congestion.PacketNumber = -1 -const MaxCongestionWindowPackets = 20000 -const MaxByteCount = congestion.ByteCount(1<<62 - 1) - -type cubicSender struct { - hybridSlowStart HybridSlowStart - rttStats congestion.RTTStatsProvider - cubic *Cubic - pacer *pacer - clock Clock - - reno bool - - // Track the largest packet that has been sent. - largestSentPacketNumber congestion.PacketNumber - - // Track the largest packet that has been acked. - largestAckedPacketNumber congestion.PacketNumber - - // Track the largest packet number outstanding when a CWND cutback occurs. - largestSentAtLastCutback congestion.PacketNumber - - // Whether the last loss event caused us to exit slowstart. - // Used for stats collection of slowstartPacketsLost - lastCutbackExitedSlowstart bool - - // Congestion window in bytes. - congestionWindow congestion.ByteCount - - // Slow start congestion window in bytes, aka ssthresh. - slowStartThreshold congestion.ByteCount - - // ACK counter for the Reno implementation. - numAckedPackets uint64 - - initialCongestionWindow congestion.ByteCount - initialMaxCongestionWindow congestion.ByteCount - - maxDatagramSize congestion.ByteCount -} - -var ( - _ congestion.CongestionControl = &cubicSender{} -) - -// NewCubicSender makes a new cubic sender -func NewCubicSender( - clock Clock, - initialMaxDatagramSize congestion.ByteCount, - reno bool, -) *cubicSender { - return newCubicSender( - clock, - reno, - initialMaxDatagramSize, - initialCongestionWindow*initialMaxDatagramSize, - MaxCongestionWindowPackets*initialMaxDatagramSize, - ) -} - -func newCubicSender( - clock Clock, - reno bool, - initialMaxDatagramSize, - initialCongestionWindow, - initialMaxCongestionWindow congestion.ByteCount, -) *cubicSender { - c := &cubicSender{ - largestSentPacketNumber: InvalidPacketNumber, - largestAckedPacketNumber: InvalidPacketNumber, - largestSentAtLastCutback: InvalidPacketNumber, - initialCongestionWindow: initialCongestionWindow, - initialMaxCongestionWindow: initialMaxCongestionWindow, - congestionWindow: initialCongestionWindow, - slowStartThreshold: MaxByteCount, - cubic: NewCubic(clock), - clock: clock, - reno: reno, - maxDatagramSize: initialMaxDatagramSize, - } - c.pacer = newPacer(c.BandwidthEstimate) - return c -} - -func (c *cubicSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { - c.rttStats = provider -} - -// TimeUntilSend returns when the next packet should be sent. -func (c *cubicSender) TimeUntilSend(_ congestion.ByteCount) time.Time { - return c.pacer.TimeUntilSend() -} - -func (c *cubicSender) HasPacingBudget(now time.Time) bool { - return c.pacer.Budget(now) >= c.maxDatagramSize -} - -func (c *cubicSender) maxCongestionWindow() congestion.ByteCount { - return c.maxDatagramSize * MaxCongestionWindowPackets -} - -func (c *cubicSender) minCongestionWindow() congestion.ByteCount { - return c.maxDatagramSize * minCongestionWindowPackets -} - -func (c *cubicSender) OnPacketSent( - sentTime time.Time, - _ congestion.ByteCount, - packetNumber congestion.PacketNumber, - bytes congestion.ByteCount, - isRetransmittable bool, -) { - c.pacer.SentPacket(sentTime, bytes) - if !isRetransmittable { - return - } - c.largestSentPacketNumber = packetNumber - c.hybridSlowStart.OnPacketSent(packetNumber) -} - -func (c *cubicSender) CanSend(bytesInFlight congestion.ByteCount) bool { - return bytesInFlight < c.GetCongestionWindow() -} - -func (c *cubicSender) InRecovery() bool { - return c.largestAckedPacketNumber != InvalidPacketNumber && c.largestAckedPacketNumber <= c.largestSentAtLastCutback -} - -func (c *cubicSender) InSlowStart() bool { - return c.GetCongestionWindow() < c.slowStartThreshold -} - -func (c *cubicSender) GetCongestionWindow() congestion.ByteCount { - return c.congestionWindow -} - -func (c *cubicSender) MaybeExitSlowStart() { - if c.InSlowStart() && - c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) { - // exit slow start - c.slowStartThreshold = c.congestionWindow - } -} - -func (c *cubicSender) OnPacketAcked( - ackedPacketNumber congestion.PacketNumber, - ackedBytes congestion.ByteCount, - priorInFlight congestion.ByteCount, - eventTime time.Time, -) { - c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber) - if c.InRecovery() { - return - } - c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime) - if c.InSlowStart() { - c.hybridSlowStart.OnPacketAcked(ackedPacketNumber) - } -} - -func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { - // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets - // already sent should be treated as a single loss event, since it's expected. - if packetNumber <= c.largestSentAtLastCutback { - return - } - c.lastCutbackExitedSlowstart = c.InSlowStart() - - if c.reno { - c.congestionWindow = congestion.ByteCount(float64(c.congestionWindow) * renoBeta) - } else { - c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow) - } - if minCwnd := c.minCongestionWindow(); c.congestionWindow < minCwnd { - c.congestionWindow = minCwnd - } - c.slowStartThreshold = c.congestionWindow - c.largestSentAtLastCutback = c.largestSentPacketNumber - // reset packet count from congestion avoidance mode. We start - // counting again when we're out of recovery. - c.numAckedPackets = 0 -} - -func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { - // Stub -} - -// Called when we receive an ack. Normal TCP tracks how many packets one ack -// represents, but quic has a separate ack for each packet. -func (c *cubicSender) maybeIncreaseCwnd( - _ congestion.PacketNumber, - ackedBytes congestion.ByteCount, - priorInFlight congestion.ByteCount, - eventTime time.Time, -) { - // Do not increase the congestion window unless the sender is close to using - // the current window. - if !c.isCwndLimited(priorInFlight) { - c.cubic.OnApplicationLimited() - return - } - if c.congestionWindow >= c.maxCongestionWindow() { - return - } - if c.InSlowStart() { - // TCP slow start, exponential growth, increase by one for each ACK. - c.congestionWindow += c.maxDatagramSize - return - } - // Congestion avoidance - if c.reno { - // Classic Reno congestion avoidance. - c.numAckedPackets++ - if c.numAckedPackets >= uint64(c.congestionWindow/c.maxDatagramSize) { - c.congestionWindow += c.maxDatagramSize - c.numAckedPackets = 0 - } - } else { - c.congestionWindow = Min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) - } -} - -func (c *cubicSender) isCwndLimited(bytesInFlight congestion.ByteCount) bool { - congestionWindow := c.GetCongestionWindow() - if bytesInFlight >= congestionWindow { - return true - } - availableBytes := congestionWindow - bytesInFlight - slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2 - return slowStartLimited || availableBytes <= maxBurstPackets*c.maxDatagramSize -} - -// BandwidthEstimate returns the current bandwidth estimate -func (c *cubicSender) BandwidthEstimate() Bandwidth { - if c.rttStats == nil { - return infBandwidth - } - srtt := c.rttStats.SmoothedRTT() - if srtt == 0 { - // If we haven't measured an rtt, the bandwidth estimate is unknown. - return infBandwidth - } - return BandwidthFromDelta(c.GetCongestionWindow(), srtt) -} - -// OnRetransmissionTimeout is called on an retransmission timeout -func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { - c.largestSentAtLastCutback = InvalidPacketNumber - if !packetsRetransmitted { - return - } - c.hybridSlowStart.Restart() - c.cubic.Reset() - c.slowStartThreshold = c.congestionWindow / 2 - c.congestionWindow = c.minCongestionWindow() -} - -// OnConnectionMigration is called when the connection is migrated (?) -func (c *cubicSender) OnConnectionMigration() { - c.hybridSlowStart.Restart() - c.largestSentPacketNumber = InvalidPacketNumber - c.largestAckedPacketNumber = InvalidPacketNumber - c.largestSentAtLastCutback = InvalidPacketNumber - c.lastCutbackExitedSlowstart = false - c.cubic.Reset() - c.numAckedPackets = 0 - c.congestionWindow = c.initialCongestionWindow - c.slowStartThreshold = c.initialMaxCongestionWindow -} - -func (c *cubicSender) SetMaxDatagramSize(s congestion.ByteCount) { - if s < c.maxDatagramSize { - panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s)) - } - cwndIsMinCwnd := c.congestionWindow == c.minCongestionWindow() - c.maxDatagramSize = s - if cwndIsMinCwnd { - c.congestionWindow = c.minCongestionWindow() - } - c.pacer.SetMaxDatagramSize(s) -} diff --git a/transport/tuic/congestion/hybrid_slow_start.go b/transport/tuic/congestion/hybrid_slow_start.go deleted file mode 100644 index 7586774e..00000000 --- a/transport/tuic/congestion/hybrid_slow_start.go +++ /dev/null @@ -1,112 +0,0 @@ -package congestion - -import ( - "time" - - "github.com/metacubex/quic-go/congestion" -) - -// Note(pwestin): the magic clamping numbers come from the original code in -// tcp_cubic.c. -const hybridStartLowWindow = congestion.ByteCount(16) - -// Number of delay samples for detecting the increase of delay. -const hybridStartMinSamples = uint32(8) - -// Exit slow start if the min rtt has increased by more than 1/8th. -const hybridStartDelayFactorExp = 3 // 2^3 = 8 -// The original paper specifies 2 and 8ms, but those have changed over time. -const ( - hybridStartDelayMinThresholdUs = int64(4000) - hybridStartDelayMaxThresholdUs = int64(16000) -) - -// HybridSlowStart implements the TCP hybrid slow start algorithm -type HybridSlowStart struct { - endPacketNumber congestion.PacketNumber - lastSentPacketNumber congestion.PacketNumber - started bool - currentMinRTT time.Duration - rttSampleCount uint32 - hystartFound bool -} - -// StartReceiveRound is called for the start of each receive round (burst) in the slow start phase. -func (s *HybridSlowStart) StartReceiveRound(lastSent congestion.PacketNumber) { - s.endPacketNumber = lastSent - s.currentMinRTT = 0 - s.rttSampleCount = 0 - s.started = true -} - -// IsEndOfRound returns true if this ack is the last packet number of our current slow start round. -func (s *HybridSlowStart) IsEndOfRound(ack congestion.PacketNumber) bool { - return s.endPacketNumber < ack -} - -// ShouldExitSlowStart should be called on every new ack frame, since a new -// RTT measurement can be made then. -// rtt: the RTT for this ack packet. -// minRTT: is the lowest delay (RTT) we have seen during the session. -// congestionWindow: the congestion window in packets. -func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT time.Duration, congestionWindow congestion.ByteCount) bool { - if !s.started { - // Time to start the hybrid slow start. - s.StartReceiveRound(s.lastSentPacketNumber) - } - if s.hystartFound { - return true - } - // Second detection parameter - delay increase detection. - // Compare the minimum delay (s.currentMinRTT) of the current - // burst of packets relative to the minimum delay during the session. - // Note: we only look at the first few(8) packets in each burst, since we - // only want to compare the lowest RTT of the burst relative to previous - // bursts. - s.rttSampleCount++ - if s.rttSampleCount <= hybridStartMinSamples { - if s.currentMinRTT == 0 || s.currentMinRTT > latestRTT { - s.currentMinRTT = latestRTT - } - } - // We only need to check this once per round. - if s.rttSampleCount == hybridStartMinSamples { - // Divide minRTT by 8 to get a rtt increase threshold for exiting. - minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) - // Ensure the rtt threshold is never less than 2ms or more than 16ms. - minRTTincreaseThresholdUs = Min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) - minRTTincreaseThreshold := time.Duration(Max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond - - if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { - s.hystartFound = true - } - } - // Exit from slow start if the cwnd is greater than 16 and - // increasing delay is found. - return congestionWindow >= hybridStartLowWindow && s.hystartFound -} - -// OnPacketSent is called when a packet was sent -func (s *HybridSlowStart) OnPacketSent(packetNumber congestion.PacketNumber) { - s.lastSentPacketNumber = packetNumber -} - -// OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end -// the round when the final packet of the burst is received and start it on -// the next incoming ack. -func (s *HybridSlowStart) OnPacketAcked(ackedPacketNumber congestion.PacketNumber) { - if s.IsEndOfRound(ackedPacketNumber) { - s.started = false - } -} - -// Started returns true if started -func (s *HybridSlowStart) Started() bool { - return s.started -} - -// Restart the slow start phase -func (s *HybridSlowStart) Restart() { - s.started = false - s.hystartFound = false -} diff --git a/transport/tuic/congestion/minmax.go b/transport/tuic/congestion/minmax.go deleted file mode 100644 index 0a8f4ad4..00000000 --- a/transport/tuic/congestion/minmax.go +++ /dev/null @@ -1,56 +0,0 @@ -package congestion - -import ( - "math" - "time" -) - -// InfDuration is a duration of infinite length -const InfDuration = time.Duration(math.MaxInt64) - -// MinNonZeroDuration return the minimum duration that's not zero. -func MinNonZeroDuration(a, b time.Duration) time.Duration { - if a == 0 { - return b - } - if b == 0 { - return a - } - return Min(a, b) -} - -// AbsDuration returns the absolute value of a time duration -func AbsDuration(d time.Duration) time.Duration { - if d >= 0 { - return d - } - return -d -} - -// MinTime returns the earlier time -func MinTime(a, b time.Time) time.Time { - if a.After(b) { - return b - } - return a -} - -// MinNonZeroTime returns the earlist time that is not time.Time{} -// If both a and b are time.Time{}, it returns time.Time{} -func MinNonZeroTime(a, b time.Time) time.Time { - if a.IsZero() { - return b - } - if b.IsZero() { - return a - } - return MinTime(a, b) -} - -// MaxTime returns the later time -func MaxTime(a, b time.Time) time.Time { - if a.After(b) { - return a - } - return b -} diff --git a/transport/tuic/congestion_v2/bandwidth.go b/transport/tuic/congestion_v2/bandwidth.go new file mode 100644 index 00000000..df39a077 --- /dev/null +++ b/transport/tuic/congestion_v2/bandwidth.go @@ -0,0 +1,27 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + infBandwidth = Bandwidth(math.MaxUint64) +) + +// Bandwidth of a connection +type Bandwidth uint64 + +const ( + // BitsPerSecond is 1 bit per second + BitsPerSecond Bandwidth = 1 + // BytesPerSecond is 1 byte per second + BytesPerSecond = 8 * BitsPerSecond +) + +// BandwidthFromDelta calculates the bandwidth from a number of bytes and a time delta +func BandwidthFromDelta(bytes congestion.ByteCount, delta time.Duration) Bandwidth { + return Bandwidth(bytes) * Bandwidth(time.Second) / Bandwidth(delta) * BytesPerSecond +} diff --git a/transport/tuic/congestion_v2/bandwidth_sampler.go b/transport/tuic/congestion_v2/bandwidth_sampler.go new file mode 100644 index 00000000..9028df64 --- /dev/null +++ b/transport/tuic/congestion_v2/bandwidth_sampler.go @@ -0,0 +1,874 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + infRTT = time.Duration(math.MaxInt64) + defaultConnectionStateMapQueueSize = 256 + defaultCandidatesBufferSize = 256 +) + +type roundTripCount uint64 + +// SendTimeState is a subset of ConnectionStateOnSentPacket which is returned +// to the caller when the packet is acked or lost. +type sendTimeState struct { + // Whether other states in this object is valid. + isValid bool + // Whether the sender is app limited at the time the packet was sent. + // App limited bandwidth sample might be artificially low because the sender + // did not have enough data to send in order to saturate the link. + isAppLimited bool + // Total number of sent bytes at the time the packet was sent. + // Includes the packet itself. + totalBytesSent congestion.ByteCount + // Total number of acked bytes at the time the packet was sent. + totalBytesAcked congestion.ByteCount + // Total number of lost bytes at the time the packet was sent. + totalBytesLost congestion.ByteCount + // Total number of inflight bytes at the time the packet was sent. + // Includes the packet itself. + // It should be equal to |total_bytes_sent| minus the sum of + // |total_bytes_acked|, |total_bytes_lost| and total neutered bytes. + bytesInFlight congestion.ByteCount +} + +func newSendTimeState( + isAppLimited bool, + totalBytesSent congestion.ByteCount, + totalBytesAcked congestion.ByteCount, + totalBytesLost congestion.ByteCount, + bytesInFlight congestion.ByteCount, +) *sendTimeState { + return &sendTimeState{ + isValid: true, + isAppLimited: isAppLimited, + totalBytesSent: totalBytesSent, + totalBytesAcked: totalBytesAcked, + totalBytesLost: totalBytesLost, + bytesInFlight: bytesInFlight, + } +} + +type extraAckedEvent struct { + // The excess bytes acknowlwedged in the time delta for this event. + extraAcked congestion.ByteCount + + // The bytes acknowledged and time delta from the event. + bytesAcked congestion.ByteCount + timeDelta time.Duration + // The round trip of the event. + round roundTripCount +} + +func maxExtraAckedEventFunc(a, b extraAckedEvent) int { + if a.extraAcked > b.extraAcked { + return 1 + } else if a.extraAcked < b.extraAcked { + return -1 + } + return 0 +} + +// BandwidthSample +type bandwidthSample struct { + // The bandwidth at that particular sample. Zero if no valid bandwidth sample + // is available. + bandwidth Bandwidth + // The RTT measurement at this particular sample. Zero if no RTT sample is + // available. Does not correct for delayed ack time. + rtt time.Duration + // |send_rate| is computed from the current packet being acked('P') and an + // earlier packet that is acked before P was sent. + sendRate Bandwidth + // States captured when the packet was sent. + stateAtSend sendTimeState +} + +func newBandwidthSample() *bandwidthSample { + return &bandwidthSample{ + sendRate: infBandwidth, + } +} + +// MaxAckHeightTracker is part of the BandwidthSampler. It is called after every +// ack event to keep track the degree of ack aggregation(a.k.a "ack height"). +type maxAckHeightTracker struct { + // Tracks the maximum number of bytes acked faster than the estimated + // bandwidth. + maxAckHeightFilter *WindowedFilter[extraAckedEvent, roundTripCount] + // The time this aggregation started and the number of bytes acked during it. + aggregationEpochStartTime time.Time + aggregationEpochBytes congestion.ByteCount + // The last sent packet number before the current aggregation epoch started. + lastSentPacketNumberBeforeEpoch congestion.PacketNumber + // The number of ack aggregation epochs ever started, including the ongoing + // one. Stats only. + numAckAggregationEpochs uint64 + ackAggregationBandwidthThreshold float64 + startNewAggregationEpochAfterFullRound bool + reduceExtraAckedOnBandwidthIncrease bool +} + +func newMaxAckHeightTracker(windowLength roundTripCount) *maxAckHeightTracker { + return &maxAckHeightTracker{ + maxAckHeightFilter: NewWindowedFilter(windowLength, maxExtraAckedEventFunc), + lastSentPacketNumberBeforeEpoch: invalidPacketNumber, + ackAggregationBandwidthThreshold: 1.0, + } +} + +func (m *maxAckHeightTracker) Get() congestion.ByteCount { + return m.maxAckHeightFilter.GetBest().extraAcked +} + +func (m *maxAckHeightTracker) Update( + bandwidthEstimate Bandwidth, + isNewMaxBandwidth bool, + roundTripCount roundTripCount, + lastSentPacketNumber congestion.PacketNumber, + lastAckedPacketNumber congestion.PacketNumber, + ackTime time.Time, + bytesAcked congestion.ByteCount, +) congestion.ByteCount { + forceNewEpoch := false + + if m.reduceExtraAckedOnBandwidthIncrease && isNewMaxBandwidth { + // Save and clear existing entries. + best := m.maxAckHeightFilter.GetBest() + secondBest := m.maxAckHeightFilter.GetSecondBest() + thirdBest := m.maxAckHeightFilter.GetThirdBest() + m.maxAckHeightFilter.Clear() + + // Reinsert the heights into the filter after recalculating. + expectedBytesAcked := bytesFromBandwidthAndTimeDelta(bandwidthEstimate, best.timeDelta) + if expectedBytesAcked < best.bytesAcked { + best.extraAcked = best.bytesAcked - expectedBytesAcked + m.maxAckHeightFilter.Update(best, best.round) + } + expectedBytesAcked = bytesFromBandwidthAndTimeDelta(bandwidthEstimate, secondBest.timeDelta) + if expectedBytesAcked < secondBest.bytesAcked { + secondBest.extraAcked = secondBest.bytesAcked - expectedBytesAcked + m.maxAckHeightFilter.Update(secondBest, secondBest.round) + } + expectedBytesAcked = bytesFromBandwidthAndTimeDelta(bandwidthEstimate, thirdBest.timeDelta) + if expectedBytesAcked < thirdBest.bytesAcked { + thirdBest.extraAcked = thirdBest.bytesAcked - expectedBytesAcked + m.maxAckHeightFilter.Update(thirdBest, thirdBest.round) + } + } + + // If any packet sent after the start of the epoch has been acked, start a new + // epoch. + if m.startNewAggregationEpochAfterFullRound && + m.lastSentPacketNumberBeforeEpoch != invalidPacketNumber && + lastAckedPacketNumber != invalidPacketNumber && + lastAckedPacketNumber > m.lastSentPacketNumberBeforeEpoch { + forceNewEpoch = true + } + if m.aggregationEpochStartTime.IsZero() || forceNewEpoch { + m.aggregationEpochBytes = bytesAcked + m.aggregationEpochStartTime = ackTime + m.lastSentPacketNumberBeforeEpoch = lastSentPacketNumber + m.numAckAggregationEpochs++ + return 0 + } + + // Compute how many bytes are expected to be delivered, assuming max bandwidth + // is correct. + aggregationDelta := ackTime.Sub(m.aggregationEpochStartTime) + expectedBytesAcked := bytesFromBandwidthAndTimeDelta(bandwidthEstimate, aggregationDelta) + // Reset the current aggregation epoch as soon as the ack arrival rate is less + // than or equal to the max bandwidth. + if m.aggregationEpochBytes <= congestion.ByteCount(m.ackAggregationBandwidthThreshold*float64(expectedBytesAcked)) { + // Reset to start measuring a new aggregation epoch. + m.aggregationEpochBytes = bytesAcked + m.aggregationEpochStartTime = ackTime + m.lastSentPacketNumberBeforeEpoch = lastSentPacketNumber + m.numAckAggregationEpochs++ + return 0 + } + + m.aggregationEpochBytes += bytesAcked + + // Compute how many extra bytes were delivered vs max bandwidth. + extraBytesAcked := m.aggregationEpochBytes - expectedBytesAcked + newEvent := extraAckedEvent{ + extraAcked: expectedBytesAcked, + bytesAcked: m.aggregationEpochBytes, + timeDelta: aggregationDelta, + } + m.maxAckHeightFilter.Update(newEvent, roundTripCount) + return extraBytesAcked +} + +func (m *maxAckHeightTracker) SetFilterWindowLength(length roundTripCount) { + m.maxAckHeightFilter.SetWindowLength(length) +} + +func (m *maxAckHeightTracker) Reset(newHeight congestion.ByteCount, newTime roundTripCount) { + newEvent := extraAckedEvent{ + extraAcked: newHeight, + round: newTime, + } + m.maxAckHeightFilter.Reset(newEvent, newTime) +} + +func (m *maxAckHeightTracker) SetAckAggregationBandwidthThreshold(threshold float64) { + m.ackAggregationBandwidthThreshold = threshold +} + +func (m *maxAckHeightTracker) SetStartNewAggregationEpochAfterFullRound(value bool) { + m.startNewAggregationEpochAfterFullRound = value +} + +func (m *maxAckHeightTracker) SetReduceExtraAckedOnBandwidthIncrease(value bool) { + m.reduceExtraAckedOnBandwidthIncrease = value +} + +func (m *maxAckHeightTracker) AckAggregationBandwidthThreshold() float64 { + return m.ackAggregationBandwidthThreshold +} + +func (m *maxAckHeightTracker) NumAckAggregationEpochs() uint64 { + return m.numAckAggregationEpochs +} + +// AckPoint represents a point on the ack line. +type ackPoint struct { + ackTime time.Time + totalBytesAcked congestion.ByteCount +} + +// RecentAckPoints maintains the most recent 2 ack points at distinct times. +type recentAckPoints struct { + ackPoints [2]ackPoint +} + +func (r *recentAckPoints) Update(ackTime time.Time, totalBytesAcked congestion.ByteCount) { + if ackTime.Before(r.ackPoints[1].ackTime) { + r.ackPoints[1].ackTime = ackTime + } else if ackTime.After(r.ackPoints[1].ackTime) { + r.ackPoints[0] = r.ackPoints[1] + r.ackPoints[1].ackTime = ackTime + } + + r.ackPoints[1].totalBytesAcked = totalBytesAcked +} + +func (r *recentAckPoints) Clear() { + r.ackPoints[0] = ackPoint{} + r.ackPoints[1] = ackPoint{} +} + +func (r *recentAckPoints) MostRecentPoint() *ackPoint { + return &r.ackPoints[1] +} + +func (r *recentAckPoints) LessRecentPoint() *ackPoint { + if r.ackPoints[0].totalBytesAcked != 0 { + return &r.ackPoints[0] + } + + return &r.ackPoints[1] +} + +// ConnectionStateOnSentPacket represents the information about a sent packet +// and the state of the connection at the moment the packet was sent, +// specifically the information about the most recently acknowledged packet at +// that moment. +type connectionStateOnSentPacket struct { + // Time at which the packet is sent. + sentTime time.Time + // Size of the packet. + size congestion.ByteCount + // The value of |totalBytesSentAtLastAckedPacket| at the time the + // packet was sent. + totalBytesSentAtLastAckedPacket congestion.ByteCount + // The value of |lastAckedPacketSentTime| at the time the packet was + // sent. + lastAckedPacketSentTime time.Time + // The value of |lastAckedPacketAckTime| at the time the packet was + // sent. + lastAckedPacketAckTime time.Time + // Send time states that are returned to the congestion controller when the + // packet is acked or lost. + sendTimeState sendTimeState +} + +// Snapshot constructor. Records the current state of the bandwidth +// sampler. +// |bytes_in_flight| is the bytes in flight right after the packet is sent. +func newConnectionStateOnSentPacket( + sentTime time.Time, + size congestion.ByteCount, + bytesInFlight congestion.ByteCount, + sampler *bandwidthSampler, +) *connectionStateOnSentPacket { + return &connectionStateOnSentPacket{ + sentTime: sentTime, + size: size, + totalBytesSentAtLastAckedPacket: sampler.totalBytesSentAtLastAckedPacket, + lastAckedPacketSentTime: sampler.lastAckedPacketSentTime, + lastAckedPacketAckTime: sampler.lastAckedPacketAckTime, + sendTimeState: *newSendTimeState( + sampler.isAppLimited, + sampler.totalBytesSent, + sampler.totalBytesAcked, + sampler.totalBytesLost, + bytesInFlight, + ), + } +} + +// BandwidthSampler keeps track of sent and acknowledged packets and outputs a +// bandwidth sample for every packet acknowledged. The samples are taken for +// individual packets, and are not filtered; the consumer has to filter the +// bandwidth samples itself. In certain cases, the sampler will locally severely +// underestimate the bandwidth, hence a maximum filter with a size of at least +// one RTT is recommended. +// +// This class bases its samples on the slope of two curves: the number of bytes +// sent over time, and the number of bytes acknowledged as received over time. +// It produces a sample of both slopes for every packet that gets acknowledged, +// based on a slope between two points on each of the corresponding curves. Note +// that due to the packet loss, the number of bytes on each curve might get +// further and further away from each other, meaning that it is not feasible to +// compare byte values coming from different curves with each other. +// +// The obvious points for measuring slope sample are the ones corresponding to +// the packet that was just acknowledged. Let us denote them as S_1 (point at +// which the current packet was sent) and A_1 (point at which the current packet +// was acknowledged). However, taking a slope requires two points on each line, +// so estimating bandwidth requires picking a packet in the past with respect to +// which the slope is measured. +// +// For that purpose, BandwidthSampler always keeps track of the most recently +// acknowledged packet, and records it together with every outgoing packet. +// When a packet gets acknowledged (A_1), it has not only information about when +// it itself was sent (S_1), but also the information about the latest +// acknowledged packet right before it was sent (S_0 and A_0). +// +// Based on that data, send and ack rate are estimated as: +// +// send_rate = (bytes(S_1) - bytes(S_0)) / (time(S_1) - time(S_0)) +// ack_rate = (bytes(A_1) - bytes(A_0)) / (time(A_1) - time(A_0)) +// +// Here, the ack rate is intuitively the rate we want to treat as bandwidth. +// However, in certain cases (e.g. ack compression) the ack rate at a point may +// end up higher than the rate at which the data was originally sent, which is +// not indicative of the real bandwidth. Hence, we use the send rate as an upper +// bound, and the sample value is +// +// rate_sample = Min(send_rate, ack_rate) +// +// An important edge case handled by the sampler is tracking the app-limited +// samples. There are multiple meaning of "app-limited" used interchangeably, +// hence it is important to understand and to be able to distinguish between +// them. +// +// Meaning 1: connection state. The connection is said to be app-limited when +// there is no outstanding data to send. This means that certain bandwidth +// samples in the future would not be an accurate indication of the link +// capacity, and it is important to inform consumer about that. Whenever +// connection becomes app-limited, the sampler is notified via OnAppLimited() +// method. +// +// Meaning 2: a phase in the bandwidth sampler. As soon as the bandwidth +// sampler becomes notified about the connection being app-limited, it enters +// app-limited phase. In that phase, all *sent* packets are marked as +// app-limited. Note that the connection itself does not have to be +// app-limited during the app-limited phase, and in fact it will not be +// (otherwise how would it send packets?). The boolean flag below indicates +// whether the sampler is in that phase. +// +// Meaning 3: a flag on the sent packet and on the sample. If a sent packet is +// sent during the app-limited phase, the resulting sample related to the +// packet will be marked as app-limited. +// +// With the terminology issue out of the way, let us consider the question of +// what kind of situation it addresses. +// +// Consider a scenario where we first send packets 1 to 20 at a regular +// bandwidth, and then immediately run out of data. After a few seconds, we send +// packets 21 to 60, and only receive ack for 21 between sending packets 40 and +// 41. In this case, when we sample bandwidth for packets 21 to 40, the S_0/A_0 +// we use to compute the slope is going to be packet 20, a few seconds apart +// from the current packet, hence the resulting estimate would be extremely low +// and not indicative of anything. Only at packet 41 the S_0/A_0 will become 21, +// meaning that the bandwidth sample would exclude the quiescence. +// +// Based on the analysis of that scenario, we implement the following rule: once +// OnAppLimited() is called, all sent packets will produce app-limited samples +// up until an ack for a packet that was sent after OnAppLimited() was called. +// Note that while the scenario above is not the only scenario when the +// connection is app-limited, the approach works in other cases too. + +type congestionEventSample struct { + // The maximum bandwidth sample from all acked packets. + // QuicBandwidth::Zero() if no samples are available. + sampleMaxBandwidth Bandwidth + // Whether |sample_max_bandwidth| is from a app-limited sample. + sampleIsAppLimited bool + // The minimum rtt sample from all acked packets. + // QuicTime::Delta::Infinite() if no samples are available. + sampleRtt time.Duration + // For each packet p in acked packets, this is the max value of INFLIGHT(p), + // where INFLIGHT(p) is the number of bytes acked while p is inflight. + sampleMaxInflight congestion.ByteCount + // The send state of the largest packet in acked_packets, unless it is + // empty. If acked_packets is empty, it's the send state of the largest + // packet in lost_packets. + lastPacketSendState sendTimeState + // The number of extra bytes acked from this ack event, compared to what is + // expected from the flow's bandwidth. Larger value means more ack + // aggregation. + extraAcked congestion.ByteCount +} + +func newCongestionEventSample() *congestionEventSample { + return &congestionEventSample{ + sampleRtt: infRTT, + } +} + +type bandwidthSampler struct { + // The total number of congestion controlled bytes sent during the connection. + totalBytesSent congestion.ByteCount + + // The total number of congestion controlled bytes which were acknowledged. + totalBytesAcked congestion.ByteCount + + // The total number of congestion controlled bytes which were lost. + totalBytesLost congestion.ByteCount + + // The total number of congestion controlled bytes which have been neutered. + totalBytesNeutered congestion.ByteCount + + // The value of |total_bytes_sent_| at the time the last acknowledged packet + // was sent. Valid only when |last_acked_packet_sent_time_| is valid. + totalBytesSentAtLastAckedPacket congestion.ByteCount + + // The time at which the last acknowledged packet was sent. Set to + // QuicTime::Zero() if no valid timestamp is available. + lastAckedPacketSentTime time.Time + + // The time at which the most recent packet was acknowledged. + lastAckedPacketAckTime time.Time + + // The most recently sent packet. + lastSentPacket congestion.PacketNumber + + // The most recently acked packet. + lastAckedPacket congestion.PacketNumber + + // Indicates whether the bandwidth sampler is currently in an app-limited + // phase. + isAppLimited bool + + // The packet that will be acknowledged after this one will cause the sampler + // to exit the app-limited phase. + endOfAppLimitedPhase congestion.PacketNumber + + // Record of the connection state at the point where each packet in flight was + // sent, indexed by the packet number. + connectionStateMap *packetNumberIndexedQueue[connectionStateOnSentPacket] + + recentAckPoints recentAckPoints + a0Candidates RingBuffer[ackPoint] + + // Maximum number of tracked packets. + maxTrackedPackets congestion.ByteCount + + maxAckHeightTracker *maxAckHeightTracker + totalBytesAckedAfterLastAckEvent congestion.ByteCount + + // True if connection option 'BSAO' is set. + overestimateAvoidance bool + + // True if connection option 'BBRB' is set. + limitMaxAckHeightTrackerBySendRate bool +} + +func newBandwidthSampler(maxAckHeightTrackerWindowLength roundTripCount) *bandwidthSampler { + b := &bandwidthSampler{ + maxAckHeightTracker: newMaxAckHeightTracker(maxAckHeightTrackerWindowLength), + connectionStateMap: newPacketNumberIndexedQueue[connectionStateOnSentPacket](defaultConnectionStateMapQueueSize), + lastSentPacket: invalidPacketNumber, + lastAckedPacket: invalidPacketNumber, + endOfAppLimitedPhase: invalidPacketNumber, + } + + b.a0Candidates.Init(defaultCandidatesBufferSize) + + return b +} + +func (b *bandwidthSampler) MaxAckHeight() congestion.ByteCount { + return b.maxAckHeightTracker.Get() +} + +func (b *bandwidthSampler) NumAckAggregationEpochs() uint64 { + return b.maxAckHeightTracker.NumAckAggregationEpochs() +} + +func (b *bandwidthSampler) SetMaxAckHeightTrackerWindowLength(length roundTripCount) { + b.maxAckHeightTracker.SetFilterWindowLength(length) +} + +func (b *bandwidthSampler) ResetMaxAckHeightTracker(newHeight congestion.ByteCount, newTime roundTripCount) { + b.maxAckHeightTracker.Reset(newHeight, newTime) +} + +func (b *bandwidthSampler) SetStartNewAggregationEpochAfterFullRound(value bool) { + b.maxAckHeightTracker.SetStartNewAggregationEpochAfterFullRound(value) +} + +func (b *bandwidthSampler) SetLimitMaxAckHeightTrackerBySendRate(value bool) { + b.limitMaxAckHeightTrackerBySendRate = value +} + +func (b *bandwidthSampler) SetReduceExtraAckedOnBandwidthIncrease(value bool) { + b.maxAckHeightTracker.SetReduceExtraAckedOnBandwidthIncrease(value) +} + +func (b *bandwidthSampler) EnableOverestimateAvoidance() { + if b.overestimateAvoidance { + return + } + + b.overestimateAvoidance = true + b.maxAckHeightTracker.SetAckAggregationBandwidthThreshold(2.0) +} + +func (b *bandwidthSampler) IsOverestimateAvoidanceEnabled() bool { + return b.overestimateAvoidance +} + +func (b *bandwidthSampler) OnPacketSent( + sentTime time.Time, + packetNumber congestion.PacketNumber, + bytes congestion.ByteCount, + bytesInFlight congestion.ByteCount, + isRetransmittable bool, +) { + b.lastSentPacket = packetNumber + + if !isRetransmittable { + return + } + + b.totalBytesSent += bytes + + // If there are no packets in flight, the time at which the new transmission + // opens can be treated as the A_0 point for the purpose of bandwidth + // sampling. This underestimates bandwidth to some extent, and produces some + // artificially low samples for most packets in flight, but it provides with + // samples at important points where we would not have them otherwise, most + // importantly at the beginning of the connection. + if bytesInFlight == 0 { + b.lastAckedPacketAckTime = sentTime + if b.overestimateAvoidance { + b.recentAckPoints.Clear() + b.recentAckPoints.Update(sentTime, b.totalBytesAcked) + b.a0Candidates.Clear() + b.a0Candidates.PushBack(*b.recentAckPoints.MostRecentPoint()) + } + b.totalBytesSentAtLastAckedPacket = b.totalBytesSent + + // In this situation ack compression is not a concern, set send rate to + // effectively infinite. + b.lastAckedPacketSentTime = sentTime + } + + b.connectionStateMap.Emplace(packetNumber, newConnectionStateOnSentPacket( + sentTime, + bytes, + bytesInFlight+bytes, + b, + )) +} + +func (b *bandwidthSampler) OnCongestionEvent( + ackTime time.Time, + ackedPackets []congestion.AckedPacketInfo, + lostPackets []congestion.LostPacketInfo, + maxBandwidth Bandwidth, + estBandwidthUpperBound Bandwidth, + roundTripCount roundTripCount, +) congestionEventSample { + eventSample := newCongestionEventSample() + + var lastLostPacketSendState sendTimeState + + for _, p := range lostPackets { + sendState := b.OnPacketLost(p.PacketNumber, p.BytesLost) + if sendState.isValid { + lastLostPacketSendState = sendState + } + } + + if len(ackedPackets) == 0 { + // Only populate send state for a loss-only event. + eventSample.lastPacketSendState = lastLostPacketSendState + return *eventSample + } + + var lastAckedPacketSendState sendTimeState + var maxSendRate Bandwidth + + for _, p := range ackedPackets { + sample := b.onPacketAcknowledged(ackTime, p.PacketNumber) + if !sample.stateAtSend.isValid { + continue + } + + lastAckedPacketSendState = sample.stateAtSend + + if sample.rtt != 0 { + eventSample.sampleRtt = Min(eventSample.sampleRtt, sample.rtt) + } + if sample.bandwidth > eventSample.sampleMaxBandwidth { + eventSample.sampleMaxBandwidth = sample.bandwidth + eventSample.sampleIsAppLimited = sample.stateAtSend.isAppLimited + } + if sample.sendRate != infBandwidth { + maxSendRate = Max(maxSendRate, sample.sendRate) + } + inflightSample := b.totalBytesAcked - lastAckedPacketSendState.totalBytesAcked + if inflightSample > eventSample.sampleMaxInflight { + eventSample.sampleMaxInflight = inflightSample + } + } + + if !lastLostPacketSendState.isValid { + eventSample.lastPacketSendState = lastAckedPacketSendState + } else if !lastAckedPacketSendState.isValid { + eventSample.lastPacketSendState = lastLostPacketSendState + } else { + // If two packets are inflight and an alarm is armed to lose a packet and it + // wakes up late, then the first of two in flight packets could have been + // acknowledged before the wakeup, which re-evaluates loss detection, and + // could declare the later of the two lost. + if lostPackets[len(lostPackets)-1].PacketNumber > ackedPackets[len(ackedPackets)-1].PacketNumber { + eventSample.lastPacketSendState = lastLostPacketSendState + } else { + eventSample.lastPacketSendState = lastAckedPacketSendState + } + } + + isNewMaxBandwidth := eventSample.sampleMaxBandwidth > maxBandwidth + maxBandwidth = Max(maxBandwidth, eventSample.sampleMaxBandwidth) + if b.limitMaxAckHeightTrackerBySendRate { + maxBandwidth = Max(maxBandwidth, maxSendRate) + } + + eventSample.extraAcked = b.onAckEventEnd(Min(estBandwidthUpperBound, maxBandwidth), isNewMaxBandwidth, roundTripCount) + + return *eventSample +} + +func (b *bandwidthSampler) OnPacketLost(packetNumber congestion.PacketNumber, bytesLost congestion.ByteCount) (s sendTimeState) { + b.totalBytesLost += bytesLost + if sentPacketPointer := b.connectionStateMap.GetEntry(packetNumber); sentPacketPointer != nil { + sentPacketToSendTimeState(sentPacketPointer, &s) + } + return s +} + +func (b *bandwidthSampler) OnPacketNeutered(packetNumber congestion.PacketNumber) { + b.connectionStateMap.Remove(packetNumber, func(sentPacket connectionStateOnSentPacket) { + b.totalBytesNeutered += sentPacket.size + }) +} + +func (b *bandwidthSampler) OnAppLimited() { + b.isAppLimited = true + b.endOfAppLimitedPhase = b.lastSentPacket +} + +func (b *bandwidthSampler) RemoveObsoletePackets(leastUnacked congestion.PacketNumber) { + // A packet can become obsolete when it is removed from QuicUnackedPacketMap's + // view of inflight before it is acked or marked as lost. For example, when + // QuicSentPacketManager::RetransmitCryptoPackets retransmits a crypto packet, + // the packet is removed from QuicUnackedPacketMap's inflight, but is not + // marked as acked or lost in the BandwidthSampler. + b.connectionStateMap.RemoveUpTo(leastUnacked) +} + +func (b *bandwidthSampler) TotalBytesSent() congestion.ByteCount { + return b.totalBytesSent +} + +func (b *bandwidthSampler) TotalBytesLost() congestion.ByteCount { + return b.totalBytesLost +} + +func (b *bandwidthSampler) TotalBytesAcked() congestion.ByteCount { + return b.totalBytesAcked +} + +func (b *bandwidthSampler) TotalBytesNeutered() congestion.ByteCount { + return b.totalBytesNeutered +} + +func (b *bandwidthSampler) IsAppLimited() bool { + return b.isAppLimited +} + +func (b *bandwidthSampler) EndOfAppLimitedPhase() congestion.PacketNumber { + return b.endOfAppLimitedPhase +} + +func (b *bandwidthSampler) max_ack_height() congestion.ByteCount { + return b.maxAckHeightTracker.Get() +} + +func (b *bandwidthSampler) chooseA0Point(totalBytesAcked congestion.ByteCount, a0 *ackPoint) bool { + if b.a0Candidates.Empty() { + return false + } + + if b.a0Candidates.Len() == 1 { + *a0 = *b.a0Candidates.Front() + return true + } + + for i := 1; i < b.a0Candidates.Len(); i++ { + if b.a0Candidates.Offset(i).totalBytesAcked > totalBytesAcked { + *a0 = *b.a0Candidates.Offset(i - 1) + if i > 1 { + for j := 0; j < i-1; j++ { + b.a0Candidates.PopFront() + } + } + return true + } + } + + *a0 = *b.a0Candidates.Back() + for k := 0; k < b.a0Candidates.Len()-1; k++ { + b.a0Candidates.PopFront() + } + return true +} + +func (b *bandwidthSampler) onPacketAcknowledged(ackTime time.Time, packetNumber congestion.PacketNumber) bandwidthSample { + sample := newBandwidthSample() + b.lastAckedPacket = packetNumber + sentPacketPointer := b.connectionStateMap.GetEntry(packetNumber) + if sentPacketPointer == nil { + return *sample + } + + // OnPacketAcknowledgedInner + b.totalBytesAcked += sentPacketPointer.size + b.totalBytesSentAtLastAckedPacket = sentPacketPointer.sendTimeState.totalBytesSent + b.lastAckedPacketSentTime = sentPacketPointer.sentTime + b.lastAckedPacketAckTime = ackTime + if b.overestimateAvoidance { + b.recentAckPoints.Update(ackTime, b.totalBytesAcked) + } + + if b.isAppLimited { + // Exit app-limited phase in two cases: + // (1) end_of_app_limited_phase_ is not initialized, i.e., so far all + // packets are sent while there are buffered packets or pending data. + // (2) The current acked packet is after the sent packet marked as the end + // of the app limit phase. + if b.endOfAppLimitedPhase == invalidPacketNumber || + packetNumber > b.endOfAppLimitedPhase { + b.isAppLimited = false + } + } + + // There might have been no packets acknowledged at the moment when the + // current packet was sent. In that case, there is no bandwidth sample to + // make. + if sentPacketPointer.lastAckedPacketSentTime.IsZero() { + return *sample + } + + // Infinite rate indicates that the sampler is supposed to discard the + // current send rate sample and use only the ack rate. + sendRate := infBandwidth + if sentPacketPointer.sentTime.After(sentPacketPointer.lastAckedPacketSentTime) { + sendRate = BandwidthFromDelta( + sentPacketPointer.sendTimeState.totalBytesSent-sentPacketPointer.totalBytesSentAtLastAckedPacket, + sentPacketPointer.sentTime.Sub(sentPacketPointer.lastAckedPacketSentTime)) + } + + var a0 ackPoint + if b.overestimateAvoidance && b.chooseA0Point(sentPacketPointer.sendTimeState.totalBytesAcked, &a0) { + } else { + a0.ackTime = sentPacketPointer.lastAckedPacketAckTime + a0.totalBytesAcked = sentPacketPointer.sendTimeState.totalBytesAcked + } + + // During the slope calculation, ensure that ack time of the current packet is + // always larger than the time of the previous packet, otherwise division by + // zero or integer underflow can occur. + if ackTime.Sub(a0.ackTime) <= 0 { + return *sample + } + + ackRate := BandwidthFromDelta(b.totalBytesAcked-a0.totalBytesAcked, ackTime.Sub(a0.ackTime)) + + sample.bandwidth = Min(sendRate, ackRate) + // Note: this sample does not account for delayed acknowledgement time. This + // means that the RTT measurements here can be artificially high, especially + // on low bandwidth connections. + sample.rtt = ackTime.Sub(sentPacketPointer.sentTime) + sample.sendRate = sendRate + sentPacketToSendTimeState(sentPacketPointer, &sample.stateAtSend) + + return *sample +} + +func (b *bandwidthSampler) onAckEventEnd( + bandwidthEstimate Bandwidth, + isNewMaxBandwidth bool, + roundTripCount roundTripCount, +) congestion.ByteCount { + newlyAckedBytes := b.totalBytesAcked - b.totalBytesAckedAfterLastAckEvent + if newlyAckedBytes == 0 { + return 0 + } + b.totalBytesAckedAfterLastAckEvent = b.totalBytesAcked + extraAcked := b.maxAckHeightTracker.Update( + bandwidthEstimate, + isNewMaxBandwidth, + roundTripCount, + b.lastSentPacket, + b.lastAckedPacket, + b.lastAckedPacketAckTime, + newlyAckedBytes) + // If |extra_acked| is zero, i.e. this ack event marks the start of a new ack + // aggregation epoch, save LessRecentPoint, which is the last ack point of the + // previous epoch, as a A0 candidate. + if b.overestimateAvoidance && extraAcked == 0 { + b.a0Candidates.PushBack(*b.recentAckPoints.LessRecentPoint()) + } + return extraAcked +} + +func sentPacketToSendTimeState(sentPacket *connectionStateOnSentPacket, sendTimeState *sendTimeState) { + *sendTimeState = sentPacket.sendTimeState + sendTimeState.isValid = true +} + +// BytesFromBandwidthAndTimeDelta calculates the bytes +// from a bandwidth(bits per second) and a time delta +func bytesFromBandwidthAndTimeDelta(bandwidth Bandwidth, delta time.Duration) congestion.ByteCount { + return (congestion.ByteCount(bandwidth) * congestion.ByteCount(delta)) / + (congestion.ByteCount(time.Second) * 8) +} + +func timeDeltaFromBytesAndBandwidth(bytes congestion.ByteCount, bandwidth Bandwidth) time.Duration { + return time.Duration(bytes*8) * time.Second / time.Duration(bandwidth) +} diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go new file mode 100644 index 00000000..a7700fa1 --- /dev/null +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -0,0 +1,927 @@ +package congestion + +// src from https://github.com/google/quiche/blob/e7872fc9e12bb1d46a118949c3d4da36de58aa44/quiche/quic/core/congestion_control/bbr_sender.cc + +import ( + "fmt" + "net" + "time" + + "github.com/metacubex/quic-go/congestion" + + "github.com/zhangyunhao116/fastrand" +) + +// BbrSender implements BBR congestion control algorithm. BBR aims to estimate +// the current available Bottleneck Bandwidth and RTT (hence the name), and +// regulates the pacing rate and the size of the congestion window based on +// those signals. +// +// BBR relies on pacing in order to function properly. Do not use BBR when +// pacing is disabled. +// + +const ( + invalidPacketNumber = -1 + initialCongestionWindowPackets = 32 + + // Constants based on TCP defaults. + // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. + // Does not inflate the pacing rate. + defaultMinimumCongestionWindow = 4 * congestion.ByteCount(congestion.InitialPacketSizeIPv4) + + // The gain used for the STARTUP, equal to 2/ln(2). + defaultHighGain = 2.885 + // The newly derived gain for STARTUP, equal to 4 * ln(2) + derivedHighGain = 2.773 + // The newly derived CWND gain for STARTUP, 2. + derivedHighCWNDGain = 2.0 +) + +// The cycle of gains used during the PROBE_BW stage. +var pacingGain = [...]float64{1.25, 0.75, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0} + +const ( + // The length of the gain cycle. + gainCycleLength = len(pacingGain) + // The size of the bandwidth filter window, in round-trips. + bandwidthWindowSize = gainCycleLength + 2 + + // The time after which the current min_rtt value expires. + minRttExpiry = 10 * time.Second + // The minimum time the connection can spend in PROBE_RTT mode. + probeRttTime = 200 * time.Millisecond + // If the bandwidth does not increase by the factor of |kStartupGrowthTarget| + // within |kRoundTripsWithoutGrowthBeforeExitingStartup| rounds, the connection + // will exit the STARTUP mode. + startupGrowthTarget = 1.25 + roundTripsWithoutGrowthBeforeExitingStartup = int64(3) + + // Flag. + defaultStartupFullLossCount = 8 + quicBbr2DefaultLossThreshold = 0.02 + maxBbrBurstPackets = 3 +) + +type bbrMode int + +const ( + // Startup phase of the connection. + bbrModeStartup = iota + // After achieving the highest possible bandwidth during the startup, lower + // the pacing rate in order to drain the queue. + bbrModeDrain + // Cruising mode. + bbrModeProbeBw + // Temporarily slow down sending in order to empty the buffer and measure + // the real minimum RTT. + bbrModeProbeRtt +) + +// Indicates how the congestion control limits the amount of bytes in flight. +type bbrRecoveryState int + +const ( + // Do not limit. + bbrRecoveryStateNotInRecovery = iota + // Allow an extra outstanding byte for each byte acknowledged. + bbrRecoveryStateConservation + // Allow two extra outstanding bytes for each byte acknowledged (slow + // start). + bbrRecoveryStateGrowth +) + +type bbrSender struct { + rttStats congestion.RTTStatsProvider + clock Clock + pacer *Pacer + + mode bbrMode + + // Bandwidth sampler provides BBR with the bandwidth measurements at + // individual points. + sampler *bandwidthSampler + + // The number of the round trips that have occurred during the connection. + roundTripCount roundTripCount + + // The packet number of the most recently sent packet. + lastSentPacket congestion.PacketNumber + // Acknowledgement of any packet after |current_round_trip_end_| will cause + // the round trip counter to advance. + currentRoundTripEnd congestion.PacketNumber + + // Number of congestion events with some losses, in the current round. + numLossEventsInRound uint64 + + // Number of total bytes lost in the current round. + bytesLostInRound congestion.ByteCount + + // The filter that tracks the maximum bandwidth over the multiple recent + // round-trips. + maxBandwidth *WindowedFilter[Bandwidth, roundTripCount] + + // Minimum RTT estimate. Automatically expires within 10 seconds (and + // triggers PROBE_RTT mode) if no new value is sampled during that period. + minRtt time.Duration + // The time at which the current value of |min_rtt_| was assigned. + minRttTimestamp time.Time + + // The maximum allowed number of bytes in flight. + congestionWindow congestion.ByteCount + + // The initial value of the |congestion_window_|. + initialCongestionWindow congestion.ByteCount + + // The largest value the |congestion_window_| can achieve. + maxCongestionWindow congestion.ByteCount + + // The smallest value the |congestion_window_| can achieve. + minCongestionWindow congestion.ByteCount + + // The pacing gain applied during the STARTUP phase. + highGain float64 + + // The CWND gain applied during the STARTUP phase. + highCwndGain float64 + + // The pacing gain applied during the DRAIN phase. + drainGain float64 + + // The current pacing rate of the connection. + pacingRate Bandwidth + + // The gain currently applied to the pacing rate. + pacingGain float64 + // The gain currently applied to the congestion window. + congestionWindowGain float64 + + // The gain used for the congestion window during PROBE_BW. Latched from + // quic_bbr_cwnd_gain flag. + congestionWindowGainConstant float64 + // The number of RTTs to stay in STARTUP mode. Defaults to 3. + numStartupRtts int64 + + // Number of round-trips in PROBE_BW mode, used for determining the current + // pacing gain cycle. + cycleCurrentOffset int + // The time at which the last pacing gain cycle was started. + lastCycleStart time.Time + + // Indicates whether the connection has reached the full bandwidth mode. + isAtFullBandwidth bool + // Number of rounds during which there was no significant bandwidth increase. + roundsWithoutBandwidthGain int64 + // The bandwidth compared to which the increase is measured. + bandwidthAtLastRound Bandwidth + + // Set to true upon exiting quiescence. + exitingQuiescence bool + + // Time at which PROBE_RTT has to be exited. Setting it to zero indicates + // that the time is yet unknown as the number of packets in flight has not + // reached the required value. + exitProbeRttAt time.Time + // Indicates whether a round-trip has passed since PROBE_RTT became active. + probeRttRoundPassed bool + + // Indicates whether the most recent bandwidth sample was marked as + // app-limited. + lastSampleIsAppLimited bool + // Indicates whether any non app-limited samples have been recorded. + hasNoAppLimitedSample bool + + // Current state of recovery. + recoveryState bbrRecoveryState + // Receiving acknowledgement of a packet after |end_recovery_at_| will cause + // BBR to exit the recovery mode. A value above zero indicates at least one + // loss has been detected, so it must not be set back to zero. + endRecoveryAt congestion.PacketNumber + // A window used to limit the number of bytes in flight during loss recovery. + recoveryWindow congestion.ByteCount + // If true, consider all samples in recovery app-limited. + isAppLimitedRecovery bool // not used + + // When true, pace at 1.5x and disable packet conservation in STARTUP. + slowerStartup bool // not used + // When true, disables packet conservation in STARTUP. + rateBasedStartup bool // not used + + // When true, add the most recent ack aggregation measurement during STARTUP. + enableAckAggregationDuringStartup bool + // When true, expire the windowed ack aggregation values in STARTUP when + // bandwidth increases more than 25%. + expireAckAggregationInStartup bool + + // If true, will not exit low gain mode until bytes_in_flight drops below BDP + // or it's time for high gain mode. + drainToTarget bool + + // If true, slow down pacing rate in STARTUP when overshooting is detected. + detectOvershooting bool + // Bytes lost while detect_overshooting_ is true. + bytesLostWhileDetectingOvershooting congestion.ByteCount + // Slow down pacing rate if + // bytes_lost_while_detecting_overshooting_ * + // bytes_lost_multiplier_while_detecting_overshooting_ > IW. + bytesLostMultiplierWhileDetectingOvershooting uint8 + // When overshooting is detected, do not drop pacing_rate_ below this value / + // min_rtt. + cwndToCalculateMinPacingRate congestion.ByteCount + + // Max congestion window when adjusting network parameters. + maxCongestionWindowWithNetworkParametersAdjusted congestion.ByteCount // not used + + // Params. + maxDatagramSize congestion.ByteCount + // Recorded on packet sent. equivalent |unacked_packets_->bytes_in_flight()| + bytesInFlight congestion.ByteCount +} + +var _ congestion.CongestionControl = &bbrSender{} + +func NewBbrSender( + clock Clock, + initialMaxDatagramSize congestion.ByteCount, + initialCongestionWindowPackets congestion.ByteCount, +) *bbrSender { + return newBbrSender( + clock, + initialMaxDatagramSize, + initialCongestionWindowPackets*initialMaxDatagramSize, + congestion.MaxCongestionWindowPackets*initialMaxDatagramSize, + ) +} + +func newBbrSender( + clock Clock, + initialMaxDatagramSize, + initialCongestionWindow, + initialMaxCongestionWindow congestion.ByteCount, +) *bbrSender { + b := &bbrSender{ + clock: clock, + mode: bbrModeStartup, + sampler: newBandwidthSampler(roundTripCount(bandwidthWindowSize)), + lastSentPacket: invalidPacketNumber, + currentRoundTripEnd: invalidPacketNumber, + maxBandwidth: NewWindowedFilter(roundTripCount(bandwidthWindowSize), MaxFilter[Bandwidth]), + congestionWindow: initialCongestionWindow, + initialCongestionWindow: initialCongestionWindow, + maxCongestionWindow: initialMaxCongestionWindow, + minCongestionWindow: defaultMinimumCongestionWindow, + highGain: defaultHighGain, + highCwndGain: defaultHighGain, + drainGain: 1.0 / defaultHighGain, + pacingGain: 1.0, + congestionWindowGain: 1.0, + congestionWindowGainConstant: 2.0, + numStartupRtts: roundTripsWithoutGrowthBeforeExitingStartup, + recoveryState: bbrRecoveryStateNotInRecovery, + endRecoveryAt: invalidPacketNumber, + recoveryWindow: initialMaxCongestionWindow, + bytesLostMultiplierWhileDetectingOvershooting: 2, + cwndToCalculateMinPacingRate: initialCongestionWindow, + maxCongestionWindowWithNetworkParametersAdjusted: initialMaxCongestionWindow, + maxDatagramSize: initialMaxDatagramSize, + } + b.pacer = NewPacer(func() congestion.ByteCount { + // Pacer wants bytes per second, but Bandwidth is in bits per second. + return congestion.ByteCount(float64(b.bandwidthEstimate()) * b.congestionWindowGain / float64(BytesPerSecond)) + }) + + /* + if b.tracer != nil { + b.lastState = logging.CongestionStateStartup + b.tracer.UpdatedCongestionState(logging.CongestionStateStartup) + } + */ + + b.enterStartupMode(b.clock.Now()) + b.setHighCwndGain(derivedHighCWNDGain) + + return b +} + +func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { + b.rttStats = provider +} + +// TimeUntilSend implements the SendAlgorithm interface. +func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time { + return b.pacer.TimeUntilSend() +} + +// HasPacingBudget implements the SendAlgorithm interface. +func (b *bbrSender) HasPacingBudget(now time.Time) bool { + return b.pacer.Budget(now) >= b.maxDatagramSize +} + +// OnPacketSent implements the SendAlgorithm interface. +func (b *bbrSender) OnPacketSent( + sentTime time.Time, + bytesInFlight congestion.ByteCount, + packetNumber congestion.PacketNumber, + bytes congestion.ByteCount, + isRetransmittable bool, +) { + b.pacer.SentPacket(sentTime, bytes) + + b.lastSentPacket = packetNumber + b.bytesInFlight = bytesInFlight + + if bytesInFlight == 0 { + b.exitingQuiescence = true + } + + b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, isRetransmittable) +} + +// CanSend implements the SendAlgorithm interface. +func (b *bbrSender) CanSend(bytesInFlight congestion.ByteCount) bool { + return bytesInFlight < b.GetCongestionWindow() +} + +// MaybeExitSlowStart implements the SendAlgorithm interface. +func (b *bbrSender) MaybeExitSlowStart() { + // Do nothing +} + +// OnPacketAcked implements the SendAlgorithm interface. +func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes, priorInFlight congestion.ByteCount, eventTime time.Time) { + // Do nothing. +} + +// OnPacketLost implements the SendAlgorithm interface. +func (b *bbrSender) OnPacketLost(number congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { + // Do nothing. +} + +// OnRetransmissionTimeout implements the SendAlgorithm interface. +func (b *bbrSender) OnRetransmissionTimeout(packetsRetransmitted bool) { + // Do nothing. +} + +// SetMaxDatagramSize implements the SendAlgorithm interface. +func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) { + if s < b.maxDatagramSize { + panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", b.maxDatagramSize, s)) + } + cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow + b.maxDatagramSize = s + if cwndIsMinCwnd { + b.congestionWindow = b.minCongestionWindow + } + b.pacer.SetMaxDatagramSize(s) +} + +// InSlowStart implements the SendAlgorithmWithDebugInfos interface. +func (b *bbrSender) InSlowStart() bool { + return b.mode == bbrModeStartup +} + +// InRecovery implements the SendAlgorithmWithDebugInfos interface. +func (b *bbrSender) InRecovery() bool { + return b.recoveryState != bbrRecoveryStateNotInRecovery +} + +// GetCongestionWindow implements the SendAlgorithmWithDebugInfos interface. +func (b *bbrSender) GetCongestionWindow() congestion.ByteCount { + if b.mode == bbrModeProbeRtt { + return b.probeRttCongestionWindow() + } + + if b.InRecovery() { + return Min(b.congestionWindow, b.recoveryWindow) + } + + return b.congestionWindow +} + +func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { + // Do nothing. +} + +func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + totalBytesAckedBefore := b.sampler.TotalBytesAcked() + totalBytesLostBefore := b.sampler.TotalBytesLost() + + var isRoundStart, minRttExpired bool + var excessAcked, bytesLost congestion.ByteCount + + // The send state of the largest packet in acked_packets, unless it is + // empty. If acked_packets is empty, it's the send state of the largest + // packet in lost_packets. + var lastPacketSendState sendTimeState + + b.maybeApplimited(priorInFlight) + + // Update bytesInFlight + b.bytesInFlight = priorInFlight + for _, p := range ackedPackets { + b.bytesInFlight -= p.BytesAcked + } + for _, p := range lostPackets { + b.bytesInFlight -= p.BytesLost + } + + if len(ackedPackets) != 0 { + lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber + isRoundStart = b.updateRoundTripCounter(lastAckedPacket) + b.updateRecoveryState(lastAckedPacket, len(lostPackets) != 0, isRoundStart) + } + + sample := b.sampler.OnCongestionEvent(eventTime, + ackedPackets, lostPackets, b.maxBandwidth.GetBest(), infBandwidth, b.roundTripCount) + if sample.lastPacketSendState.isValid { + b.lastSampleIsAppLimited = sample.lastPacketSendState.isAppLimited + b.hasNoAppLimitedSample = b.hasNoAppLimitedSample || !b.lastSampleIsAppLimited + } + // Avoid updating |max_bandwidth_| if a) this is a loss-only event, or b) all + // packets in |acked_packets| did not generate valid samples. (e.g. ack of + // ack-only packets). In both cases, sampler_.total_bytes_acked() will not + // change. + if totalBytesAckedBefore != b.sampler.TotalBytesAcked() { + if !sample.sampleIsAppLimited || sample.sampleMaxBandwidth > b.maxBandwidth.GetBest() { + b.maxBandwidth.Update(sample.sampleMaxBandwidth, b.roundTripCount) + } + } + + if sample.sampleRtt != infRTT { + minRttExpired = b.maybeUpdateMinRtt(eventTime, sample.sampleRtt) + } + bytesLost = b.sampler.TotalBytesLost() - totalBytesLostBefore + + excessAcked = sample.extraAcked + lastPacketSendState = sample.lastPacketSendState + + if len(lostPackets) != 0 { + b.numLossEventsInRound++ + b.bytesLostInRound += bytesLost + } + + // Handle logic specific to PROBE_BW mode. + if b.mode == bbrModeProbeBw { + b.updateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) != 0) + } + + // Handle logic specific to STARTUP and DRAIN modes. + if isRoundStart && !b.isAtFullBandwidth { + b.checkIfFullBandwidthReached(&lastPacketSendState) + } + + b.maybeExitStartupOrDrain(eventTime) + + // Handle logic specific to PROBE_RTT. + b.maybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) + + // Calculate number of packets acked and lost. + bytesAcked := b.sampler.TotalBytesAcked() - totalBytesAckedBefore + + // After the model is updated, recalculate the pacing rate and congestion + // window. + b.calculatePacingRate(bytesLost) + b.calculateCongestionWindow(bytesAcked, excessAcked) + b.calculateRecoveryWindow(bytesAcked, bytesLost) + + // Cleanup internal state. + if len(lostPackets) != 0 { + lastLostPacket := lostPackets[len(lostPackets)-1].PacketNumber + b.sampler.RemoveObsoletePackets(lastLostPacket) + } + if isRoundStart { + b.numLossEventsInRound = 0 + b.bytesLostInRound = 0 + } +} + +func (b *bbrSender) PacingRate() Bandwidth { + if b.pacingRate == 0 { + return Bandwidth(b.highGain * float64( + BandwidthFromDelta(b.initialCongestionWindow, b.getMinRtt()))) + } + + return b.pacingRate +} + +func (b *bbrSender) hasGoodBandwidthEstimateForResumption() bool { + return b.hasNonAppLimitedSample() +} + +func (b *bbrSender) hasNonAppLimitedSample() bool { + return b.hasNoAppLimitedSample +} + +// Sets the pacing gain used in STARTUP. Must be greater than 1. +func (b *bbrSender) setHighGain(highGain float64) { + b.highGain = highGain + if b.mode == bbrModeStartup { + b.pacingGain = highGain + } +} + +// Sets the CWND gain used in STARTUP. Must be greater than 1. +func (b *bbrSender) setHighCwndGain(highCwndGain float64) { + b.highCwndGain = highCwndGain + if b.mode == bbrModeStartup { + b.congestionWindowGain = highCwndGain + } +} + +// Sets the gain used in DRAIN. Must be less than 1. +func (b *bbrSender) setDrainGain(drainGain float64) { + b.drainGain = drainGain +} + +// What's the current estimated bandwidth in bytes per second. +func (b *bbrSender) bandwidthEstimate() Bandwidth { + return b.maxBandwidth.GetBest() +} + +// Returns the current estimate of the RTT of the connection. Outside of the +// edge cases, this is minimum RTT. +func (b *bbrSender) getMinRtt() time.Duration { + if b.minRtt != 0 { + return b.minRtt + } + // min_rtt could be available if the handshake packet gets neutered then + // gets acknowledged. This could only happen for QUIC crypto where we do not + // drop keys. + minRtt := b.rttStats.MinRTT() + if minRtt == 0 { + return 100 * time.Millisecond + } else { + return minRtt + } +} + +// Computes the target congestion window using the specified gain. +func (b *bbrSender) getTargetCongestionWindow(gain float64) congestion.ByteCount { + bdp := bdpFromRttAndBandwidth(b.getMinRtt(), b.bandwidthEstimate()) + congestionWindow := congestion.ByteCount(gain * float64(bdp)) + + // BDP estimate will be zero if no bandwidth samples are available yet. + if congestionWindow == 0 { + congestionWindow = congestion.ByteCount(gain * float64(b.initialCongestionWindow)) + } + + return Max(congestionWindow, b.minCongestionWindow) +} + +// The target congestion window during PROBE_RTT. +func (b *bbrSender) probeRttCongestionWindow() congestion.ByteCount { + return b.minCongestionWindow +} + +func (b *bbrSender) maybeUpdateMinRtt(now time.Time, sampleMinRtt time.Duration) bool { + // Do not expire min_rtt if none was ever available. + minRttExpired := b.minRtt != 0 && now.After(b.minRttTimestamp.Add(minRttExpiry)) + if minRttExpired || sampleMinRtt < b.minRtt || b.minRtt == 0 { + b.minRtt = sampleMinRtt + b.minRttTimestamp = now + } + + return minRttExpired +} + +// Enters the STARTUP mode. +func (b *bbrSender) enterStartupMode(now time.Time) { + b.mode = bbrModeStartup + // b.maybeTraceStateChange(logging.CongestionStateStartup) + b.pacingGain = b.highGain + b.congestionWindowGain = b.highCwndGain +} + +// Enters the PROBE_BW mode. +func (b *bbrSender) enterProbeBandwidthMode(now time.Time) { + b.mode = bbrModeProbeBw + // b.maybeTraceStateChange(logging.CongestionStateProbeBw) + b.congestionWindowGain = b.congestionWindowGainConstant + + // Pick a random offset for the gain cycle out of {0, 2..7} range. 1 is + // excluded because in that case increased gain and decreased gain would not + // follow each other. + b.cycleCurrentOffset = int(fastrand.Int31n(congestion.PacketsPerConnectionID)) % (gainCycleLength - 1) + if b.cycleCurrentOffset >= 1 { + b.cycleCurrentOffset += 1 + } + + b.lastCycleStart = now + b.pacingGain = pacingGain[b.cycleCurrentOffset] +} + +// Updates the round-trip counter if a round-trip has passed. Returns true if +// the counter has been advanced. +func (b *bbrSender) updateRoundTripCounter(lastAckedPacket congestion.PacketNumber) bool { + if b.currentRoundTripEnd == invalidPacketNumber || lastAckedPacket > b.currentRoundTripEnd { + b.roundTripCount++ + b.currentRoundTripEnd = b.lastSentPacket + return true + } + return false +} + +// Updates the current gain used in PROBE_BW mode. +func (b *bbrSender) updateGainCyclePhase(now time.Time, priorInFlight congestion.ByteCount, hasLosses bool) { + // In most cases, the cycle is advanced after an RTT passes. + shouldAdvanceGainCycling := now.After(b.lastCycleStart.Add(b.getMinRtt())) + // If the pacing gain is above 1.0, the connection is trying to probe the + // bandwidth by increasing the number of bytes in flight to at least + // pacing_gain * BDP. Make sure that it actually reaches the target, as long + // as there are no losses suggesting that the buffers are not able to hold + // that much. + if b.pacingGain > 1.0 && !hasLosses && priorInFlight < b.getTargetCongestionWindow(b.pacingGain) { + shouldAdvanceGainCycling = false + } + + // If pacing gain is below 1.0, the connection is trying to drain the extra + // queue which could have been incurred by probing prior to it. If the number + // of bytes in flight falls down to the estimated BDP value earlier, conclude + // that the queue has been successfully drained and exit this cycle early. + if b.pacingGain < 1.0 && b.bytesInFlight <= b.getTargetCongestionWindow(1) { + shouldAdvanceGainCycling = true + } + + if shouldAdvanceGainCycling { + b.cycleCurrentOffset = (b.cycleCurrentOffset + 1) % gainCycleLength + b.lastCycleStart = now + // Stay in low gain mode until the target BDP is hit. + // Low gain mode will be exited immediately when the target BDP is achieved. + if b.drainToTarget && b.pacingGain < 1 && + pacingGain[b.cycleCurrentOffset] == 1 && + b.bytesInFlight > b.getTargetCongestionWindow(1) { + return + } + b.pacingGain = pacingGain[b.cycleCurrentOffset] + } +} + +// Tracks for how many round-trips the bandwidth has not increased +// significantly. +func (b *bbrSender) checkIfFullBandwidthReached(lastPacketSendState *sendTimeState) { + if b.lastSampleIsAppLimited { + return + } + + target := Bandwidth(float64(b.bandwidthAtLastRound) * startupGrowthTarget) + if b.bandwidthEstimate() >= target { + b.bandwidthAtLastRound = b.bandwidthEstimate() + b.roundsWithoutBandwidthGain = 0 + if b.expireAckAggregationInStartup { + // Expire old excess delivery measurements now that bandwidth increased. + b.sampler.ResetMaxAckHeightTracker(0, b.roundTripCount) + } + return + } + + b.roundsWithoutBandwidthGain++ + if b.roundsWithoutBandwidthGain >= b.numStartupRtts || + b.shouldExitStartupDueToLoss(lastPacketSendState) { + b.isAtFullBandwidth = true + } +} + +func (b *bbrSender) maybeApplimited(bytesInFlight congestion.ByteCount) { + congestionWindow := b.GetCongestionWindow() + if bytesInFlight >= congestionWindow { + return + } + availableBytes := congestionWindow - bytesInFlight + drainLimited := b.mode == bbrModeDrain && bytesInFlight > congestionWindow/2 + if !drainLimited || availableBytes > maxBbrBurstPackets*b.maxDatagramSize { + b.sampler.OnAppLimited() + } +} + +// Transitions from STARTUP to DRAIN and from DRAIN to PROBE_BW if +// appropriate. +func (b *bbrSender) maybeExitStartupOrDrain(now time.Time) { + if b.mode == bbrModeStartup && b.isAtFullBandwidth { + b.mode = bbrModeDrain + // b.maybeTraceStateChange(logging.CongestionStateDrain) + b.pacingGain = b.drainGain + b.congestionWindowGain = b.highCwndGain + } + if b.mode == bbrModeDrain && b.bytesInFlight <= b.getTargetCongestionWindow(1) { + b.enterProbeBandwidthMode(now) + } +} + +// Decides whether to enter or exit PROBE_RTT. +func (b *bbrSender) maybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRttExpired bool) { + if minRttExpired && !b.exitingQuiescence && b.mode != bbrModeProbeRtt { + b.mode = bbrModeProbeRtt + // b.maybeTraceStateChange(logging.CongestionStateProbRtt) + b.pacingGain = 1.0 + // Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight| + // is at the target small value. + b.exitProbeRttAt = time.Time{} + } + + if b.mode == bbrModeProbeRtt { + b.sampler.OnAppLimited() + // b.maybeTraceStateChange(logging.CongestionStateApplicationLimited) + + if b.exitProbeRttAt.IsZero() { + // If the window has reached the appropriate size, schedule exiting + // PROBE_RTT. The CWND during PROBE_RTT is kMinimumCongestionWindow, but + // we allow an extra packet since QUIC checks CWND before sending a + // packet. + if b.bytesInFlight < b.probeRttCongestionWindow()+congestion.MaxPacketBufferSize { + b.exitProbeRttAt = now.Add(probeRttTime) + b.probeRttRoundPassed = false + } + } else { + if isRoundStart { + b.probeRttRoundPassed = true + } + if now.Sub(b.exitProbeRttAt) >= 0 && b.probeRttRoundPassed { + b.minRttTimestamp = now + if !b.isAtFullBandwidth { + b.enterStartupMode(now) + } else { + b.enterProbeBandwidthMode(now) + } + } + } + } + + b.exitingQuiescence = false +} + +// Determines whether BBR needs to enter, exit or advance state of the +// recovery. +func (b *bbrSender) updateRecoveryState(lastAckedPacket congestion.PacketNumber, hasLosses, isRoundStart bool) { + // Disable recovery in startup, if loss-based exit is enabled. + if !b.isAtFullBandwidth { + return + } + + // Exit recovery when there are no losses for a round. + if hasLosses { + b.endRecoveryAt = b.lastSentPacket + } + + switch b.recoveryState { + case bbrRecoveryStateNotInRecovery: + if hasLosses { + b.recoveryState = bbrRecoveryStateConservation + // This will cause the |recovery_window_| to be set to the correct + // value in CalculateRecoveryWindow(). + b.recoveryWindow = 0 + // Since the conservation phase is meant to be lasting for a whole + // round, extend the current round as if it were started right now. + b.currentRoundTripEnd = b.lastSentPacket + } + case bbrRecoveryStateConservation: + if isRoundStart { + b.recoveryState = bbrRecoveryStateGrowth + } + fallthrough + case bbrRecoveryStateGrowth: + // Exit recovery if appropriate. + if !hasLosses && lastAckedPacket > b.endRecoveryAt { + b.recoveryState = bbrRecoveryStateNotInRecovery + } + } +} + +// Determines the appropriate pacing rate for the connection. +func (b *bbrSender) calculatePacingRate(bytesLost congestion.ByteCount) { + if b.bandwidthEstimate() == 0 { + return + } + + targetRate := Bandwidth(b.pacingGain * float64(b.bandwidthEstimate())) + if b.isAtFullBandwidth { + b.pacingRate = targetRate + return + } + + // Pace at the rate of initial_window / RTT as soon as RTT measurements are + // available. + if b.pacingRate == 0 && b.rttStats.MinRTT() != 0 { + b.pacingRate = BandwidthFromDelta(b.initialCongestionWindow, b.rttStats.MinRTT()) + return + } + + if b.detectOvershooting { + b.bytesLostWhileDetectingOvershooting += bytesLost + // Check for overshooting with network parameters adjusted when pacing rate + // > target_rate and loss has been detected. + if b.pacingRate > targetRate && b.bytesLostWhileDetectingOvershooting > 0 { + if b.hasNoAppLimitedSample || + b.bytesLostWhileDetectingOvershooting*congestion.ByteCount(b.bytesLostMultiplierWhileDetectingOvershooting) > b.initialCongestionWindow { + // We are fairly sure overshoot happens if 1) there is at least one + // non app-limited bw sample or 2) half of IW gets lost. Slow pacing + // rate. + b.pacingRate = Max(targetRate, BandwidthFromDelta(b.cwndToCalculateMinPacingRate, b.rttStats.MinRTT())) + b.bytesLostWhileDetectingOvershooting = 0 + b.detectOvershooting = false + } + } + } + + // Do not decrease the pacing rate during startup. + b.pacingRate = Max(b.pacingRate, targetRate) +} + +// Determines the appropriate congestion window for the connection. +func (b *bbrSender) calculateCongestionWindow(bytesAcked, excessAcked congestion.ByteCount) { + if b.mode == bbrModeProbeRtt { + return + } + + targetWindow := b.getTargetCongestionWindow(b.congestionWindowGain) + if b.isAtFullBandwidth { + // Add the max recently measured ack aggregation to CWND. + targetWindow += b.sampler.MaxAckHeight() + } else if b.enableAckAggregationDuringStartup { + // Add the most recent excess acked. Because CWND never decreases in + // STARTUP, this will automatically create a very localized max filter. + targetWindow += excessAcked + } + + // Instead of immediately setting the target CWND as the new one, BBR grows + // the CWND towards |target_window| by only increasing it |bytes_acked| at a + // time. + if b.isAtFullBandwidth { + b.congestionWindow = Min(targetWindow, b.congestionWindow+bytesAcked) + } else if b.congestionWindow < targetWindow || + b.sampler.TotalBytesAcked() < b.initialCongestionWindow { + // If the connection is not yet out of startup phase, do not decrease the + // window. + b.congestionWindow += bytesAcked + } + + // Enforce the limits on the congestion window. + b.congestionWindow = Max(b.congestionWindow, b.minCongestionWindow) + b.congestionWindow = Min(b.congestionWindow, b.maxCongestionWindow) +} + +// Determines the appropriate window that constrains the in-flight during recovery. +func (b *bbrSender) calculateRecoveryWindow(bytesAcked, bytesLost congestion.ByteCount) { + if b.recoveryState == bbrRecoveryStateNotInRecovery { + return + } + + // Set up the initial recovery window. + if b.recoveryWindow == 0 { + b.recoveryWindow = b.bytesInFlight + bytesAcked + b.recoveryWindow = Max(b.minCongestionWindow, b.recoveryWindow) + return + } + + // Remove losses from the recovery window, while accounting for a potential + // integer underflow. + if b.recoveryWindow >= bytesLost { + b.recoveryWindow = b.recoveryWindow - bytesLost + } else { + b.recoveryWindow = b.maxDatagramSize + } + + // In CONSERVATION mode, just subtracting losses is sufficient. In GROWTH, + // release additional |bytes_acked| to achieve a slow-start-like behavior. + if b.recoveryState == bbrRecoveryStateGrowth { + b.recoveryWindow += bytesAcked + } + + // Always allow sending at least |bytes_acked| in response. + b.recoveryWindow = Max(b.recoveryWindow, b.bytesInFlight+bytesAcked) + b.recoveryWindow = Max(b.minCongestionWindow, b.recoveryWindow) +} + +// Return whether we should exit STARTUP due to excessive loss. +func (b *bbrSender) shouldExitStartupDueToLoss(lastPacketSendState *sendTimeState) bool { + if b.numLossEventsInRound < defaultStartupFullLossCount || !lastPacketSendState.isValid { + return false + } + + inflightAtSend := lastPacketSendState.bytesInFlight + + if inflightAtSend > 0 && b.bytesLostInRound > 0 { + if b.bytesLostInRound > congestion.ByteCount(float64(inflightAtSend)*quicBbr2DefaultLossThreshold) { + return true + } + return false + } + return false +} + +func bdpFromRttAndBandwidth(rtt time.Duration, bandwidth Bandwidth) congestion.ByteCount { + return congestion.ByteCount(rtt) * congestion.ByteCount(bandwidth) / congestion.ByteCount(BytesPerSecond) / congestion.ByteCount(time.Second) +} + +func GetInitialPacketSize(addr net.Addr) congestion.ByteCount { + // If this is not a UDP address, we don't know anything about the MTU. + // Use the minimum size of an Initial packet as the max packet size. + if udpAddr, ok := addr.(*net.UDPAddr); ok { + if udpAddr.IP.To4() != nil { + return congestion.InitialPacketSizeIPv4 + } else { + return congestion.InitialPacketSizeIPv6 + } + } else { + return congestion.MinInitialPacketSize + } +} diff --git a/transport/tuic/congestion_v2/clock.go b/transport/tuic/congestion_v2/clock.go new file mode 100644 index 00000000..405fae70 --- /dev/null +++ b/transport/tuic/congestion_v2/clock.go @@ -0,0 +1,18 @@ +package congestion + +import "time" + +// A Clock returns the current time +type Clock interface { + Now() time.Time +} + +// DefaultClock implements the Clock interface using the Go stdlib clock. +type DefaultClock struct{} + +var _ Clock = DefaultClock{} + +// Now gets the current time +func (DefaultClock) Now() time.Time { + return time.Now() +} diff --git a/transport/tuic/congestion_v2/minmax_go120.go b/transport/tuic/congestion_v2/minmax_go120.go new file mode 100644 index 00000000..1266edbc --- /dev/null +++ b/transport/tuic/congestion_v2/minmax_go120.go @@ -0,0 +1,19 @@ +//go:build !go1.21 + +package congestion + +import "golang.org/x/exp/constraints" + +func Max[T constraints.Ordered](a, b T) T { + if a < b { + return b + } + return a +} + +func Min[T constraints.Ordered](a, b T) T { + if a < b { + return a + } + return b +} diff --git a/transport/tuic/congestion_v2/minmax_go121.go b/transport/tuic/congestion_v2/minmax_go121.go new file mode 100644 index 00000000..65b06726 --- /dev/null +++ b/transport/tuic/congestion_v2/minmax_go121.go @@ -0,0 +1,13 @@ +//go:build go1.21 + +package congestion + +import "cmp" + +func Max[T cmp.Ordered](a, b T) T { + return max(a, b) +} + +func Min[T cmp.Ordered](a, b T) T { + return min(a, b) +} diff --git a/transport/tuic/congestion_v2/pacer.go b/transport/tuic/congestion_v2/pacer.go new file mode 100644 index 00000000..ba4ca138 --- /dev/null +++ b/transport/tuic/congestion_v2/pacer.go @@ -0,0 +1,71 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + maxBurstPackets = 10 +) + +// Pacer implements a token bucket pacing algorithm. +type Pacer struct { + budgetAtLastSent congestion.ByteCount + maxDatagramSize congestion.ByteCount + lastSentTime time.Time + getBandwidth func() congestion.ByteCount // in bytes/s +} + +func NewPacer(getBandwidth func() congestion.ByteCount) *Pacer { + p := &Pacer{ + budgetAtLastSent: maxBurstPackets * congestion.InitialPacketSizeIPv4, + maxDatagramSize: congestion.InitialPacketSizeIPv4, + getBandwidth: getBandwidth, + } + return p +} + +func (p *Pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { + budget := p.Budget(sendTime) + if size > budget { + p.budgetAtLastSent = 0 + } else { + p.budgetAtLastSent = budget - size + } + p.lastSentTime = sendTime +} + +func (p *Pacer) Budget(now time.Time) congestion.ByteCount { + if p.lastSentTime.IsZero() { + return p.maxBurstSize() + } + budget := p.budgetAtLastSent + (p.getBandwidth()*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9 + return Min(p.maxBurstSize(), budget) +} + +func (p *Pacer) maxBurstSize() congestion.ByteCount { + return Max( + congestion.ByteCount((congestion.MinPacingDelay+time.Millisecond).Nanoseconds())*p.getBandwidth()/1e9, + maxBurstPackets*p.maxDatagramSize, + ) +} + +// TimeUntilSend returns when the next packet should be sent. +// It returns the zero value of time.Time if a packet can be sent immediately. +func (p *Pacer) TimeUntilSend() time.Time { + if p.budgetAtLastSent >= p.maxDatagramSize { + return time.Time{} + } + return p.lastSentTime.Add(Max( + congestion.MinPacingDelay, + time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/ + float64(p.getBandwidth())))*time.Nanosecond, + )) +} + +func (p *Pacer) SetMaxDatagramSize(s congestion.ByteCount) { + p.maxDatagramSize = s +} diff --git a/transport/tuic/congestion_v2/packet_number_indexed_queue.go b/transport/tuic/congestion_v2/packet_number_indexed_queue.go new file mode 100644 index 00000000..119d36f6 --- /dev/null +++ b/transport/tuic/congestion_v2/packet_number_indexed_queue.go @@ -0,0 +1,199 @@ +package congestion + +import ( + "github.com/metacubex/quic-go/congestion" +) + +// packetNumberIndexedQueue is a queue of mostly continuous numbered entries +// which supports the following operations: +// - adding elements to the end of the queue, or at some point past the end +// - removing elements in any order +// - retrieving elements +// If all elements are inserted in order, all of the operations above are +// amortized O(1) time. +// +// Internally, the data structure is a deque where each element is marked as +// present or not. The deque starts at the lowest present index. Whenever an +// element is removed, it's marked as not present, and the front of the deque is +// cleared of elements that are not present. +// +// The tail of the queue is not cleared due to the assumption of entries being +// inserted in order, though removing all elements of the queue will return it +// to its initial state. +// +// Note that this data structure is inherently hazardous, since an addition of +// just two entries will cause it to consume all of the memory available. +// Because of that, it is not a general-purpose container and should not be used +// as one. + +type entryWrapper[T any] struct { + present bool + entry T +} + +type packetNumberIndexedQueue[T any] struct { + entries RingBuffer[entryWrapper[T]] + numberOfPresentEntries int + firstPacket congestion.PacketNumber +} + +func newPacketNumberIndexedQueue[T any](size int) *packetNumberIndexedQueue[T] { + q := &packetNumberIndexedQueue[T]{ + firstPacket: invalidPacketNumber, + } + + q.entries.Init(size) + + return q +} + +// Emplace inserts data associated |packet_number| into (or past) the end of the +// queue, filling up the missing intermediate entries as necessary. Returns +// true if the element has been inserted successfully, false if it was already +// in the queue or inserted out of order. +func (p *packetNumberIndexedQueue[T]) Emplace(packetNumber congestion.PacketNumber, entry *T) bool { + if packetNumber == invalidPacketNumber || entry == nil { + return false + } + + if p.IsEmpty() { + p.entries.PushBack(entryWrapper[T]{ + present: true, + entry: *entry, + }) + p.numberOfPresentEntries = 1 + p.firstPacket = packetNumber + return true + } + + // Do not allow insertion out-of-order. + if packetNumber <= p.LastPacket() { + return false + } + + // Handle potentially missing elements. + offset := int(packetNumber - p.FirstPacket()) + if gap := offset - p.entries.Len(); gap > 0 { + for i := 0; i < gap; i++ { + p.entries.PushBack(entryWrapper[T]{}) + } + } + + p.entries.PushBack(entryWrapper[T]{ + present: true, + entry: *entry, + }) + p.numberOfPresentEntries++ + return true +} + +// GetEntry Retrieve the entry associated with the packet number. Returns the pointer +// to the entry in case of success, or nullptr if the entry does not exist. +func (p *packetNumberIndexedQueue[T]) GetEntry(packetNumber congestion.PacketNumber) *T { + ew := p.getEntryWraper(packetNumber) + if ew == nil { + return nil + } + + return &ew.entry +} + +// Remove, Same as above, but if an entry is present in the queue, also call f(entry) +// before removing it. +func (p *packetNumberIndexedQueue[T]) Remove(packetNumber congestion.PacketNumber, f func(T)) bool { + ew := p.getEntryWraper(packetNumber) + if ew == nil { + return false + } + if f != nil { + f(ew.entry) + } + ew.present = false + p.numberOfPresentEntries-- + + if packetNumber == p.FirstPacket() { + p.clearup() + } + + return true +} + +// RemoveUpTo, but not including |packet_number|. +// Unused slots in the front are also removed, which means when the function +// returns, |first_packet()| can be larger than |packet_number|. +func (p *packetNumberIndexedQueue[T]) RemoveUpTo(packetNumber congestion.PacketNumber) { + for !p.entries.Empty() && + p.firstPacket != invalidPacketNumber && + p.firstPacket < packetNumber { + if p.entries.Front().present { + p.numberOfPresentEntries-- + } + p.entries.PopFront() + p.firstPacket++ + } + p.clearup() + + return +} + +// IsEmpty return if queue is empty. +func (p *packetNumberIndexedQueue[T]) IsEmpty() bool { + return p.numberOfPresentEntries == 0 +} + +// NumberOfPresentEntries returns the number of entries in the queue. +func (p *packetNumberIndexedQueue[T]) NumberOfPresentEntries() int { + return p.numberOfPresentEntries +} + +// EntrySlotsUsed returns the number of entries allocated in the underlying deque. This is +// proportional to the memory usage of the queue. +func (p *packetNumberIndexedQueue[T]) EntrySlotsUsed() int { + return p.entries.Len() +} + +// LastPacket returns packet number of the first entry in the queue. +func (p *packetNumberIndexedQueue[T]) FirstPacket() (packetNumber congestion.PacketNumber) { + return p.firstPacket +} + +// LastPacket returns packet number of the last entry ever inserted in the queue. Note that the +// entry in question may have already been removed. Zero if the queue is +// empty. +func (p *packetNumberIndexedQueue[T]) LastPacket() (packetNumber congestion.PacketNumber) { + if p.IsEmpty() { + return invalidPacketNumber + } + + return p.firstPacket + congestion.PacketNumber(p.entries.Len()-1) +} + +func (p *packetNumberIndexedQueue[T]) clearup() { + for !p.entries.Empty() && !p.entries.Front().present { + p.entries.PopFront() + p.firstPacket++ + } + if p.entries.Empty() { + p.firstPacket = invalidPacketNumber + } +} + +func (p *packetNumberIndexedQueue[T]) getEntryWraper(packetNumber congestion.PacketNumber) *entryWrapper[T] { + if packetNumber == invalidPacketNumber || + p.IsEmpty() || + packetNumber < p.firstPacket { + return nil + } + + offset := int(packetNumber - p.firstPacket) + if offset >= p.entries.Len() { + return nil + } + + ew := p.entries.Offset(offset) + if ew == nil || !ew.present { + return nil + } + + return ew +} diff --git a/transport/tuic/congestion_v2/ringbuffer.go b/transport/tuic/congestion_v2/ringbuffer.go new file mode 100644 index 00000000..e110c00f --- /dev/null +++ b/transport/tuic/congestion_v2/ringbuffer.go @@ -0,0 +1,118 @@ +package congestion + +// A RingBuffer is a ring buffer. +// It acts as a heap that doesn't cause any allocations. +type RingBuffer[T any] struct { + ring []T + headPos, tailPos int + full bool +} + +// Init preallocs a buffer with a certain size. +func (r *RingBuffer[T]) Init(size int) { + r.ring = make([]T, size) +} + +// Len returns the number of elements in the ring buffer. +func (r *RingBuffer[T]) Len() int { + if r.full { + return len(r.ring) + } + if r.tailPos >= r.headPos { + return r.tailPos - r.headPos + } + return r.tailPos - r.headPos + len(r.ring) +} + +// Empty says if the ring buffer is empty. +func (r *RingBuffer[T]) Empty() bool { + return !r.full && r.headPos == r.tailPos +} + +// PushBack adds a new element. +// If the ring buffer is full, its capacity is increased first. +func (r *RingBuffer[T]) PushBack(t T) { + if r.full || len(r.ring) == 0 { + r.grow() + } + r.ring[r.tailPos] = t + r.tailPos++ + if r.tailPos == len(r.ring) { + r.tailPos = 0 + } + if r.tailPos == r.headPos { + r.full = true + } +} + +// PopFront returns the next element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first. +func (r *RingBuffer[T]) PopFront() T { + if r.Empty() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: pop from an empty queue") + } + r.full = false + t := r.ring[r.headPos] + r.ring[r.headPos] = *new(T) + r.headPos++ + if r.headPos == len(r.ring) { + r.headPos = 0 + } + return t +} + +// Offset returns the offset element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first +// and check if the index larger than buffer length. +func (r *RingBuffer[T]) Offset(index int) *T { + if r.Empty() || index >= r.Len() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: offset from invalid index") + } + offset := (r.headPos + index) % len(r.ring) + return &r.ring[offset] +} + +// Front returns the front element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first. +func (r *RingBuffer[T]) Front() *T { + if r.Empty() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: front from an empty queue") + } + return &r.ring[r.headPos] +} + +// Back returns the back element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first. +func (r *RingBuffer[T]) Back() *T { + if r.Empty() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: back from an empty queue") + } + return r.Offset(r.Len() - 1) +} + +// Grow the maximum size of the queue. +// This method assume the queue is full. +func (r *RingBuffer[T]) grow() { + oldRing := r.ring + newSize := len(oldRing) * 2 + if newSize == 0 { + newSize = 1 + } + r.ring = make([]T, newSize) + headLen := copy(r.ring, oldRing[r.headPos:]) + copy(r.ring[headLen:], oldRing[:r.headPos]) + r.headPos, r.tailPos, r.full = 0, len(oldRing), false +} + +// Clear removes all elements. +func (r *RingBuffer[T]) Clear() { + var zeroValue T + for i := range r.ring { + r.ring[i] = zeroValue + } + r.headPos, r.tailPos, r.full = 0, 0, false +} diff --git a/transport/tuic/congestion_v2/windowed_filter.go b/transport/tuic/congestion_v2/windowed_filter.go new file mode 100644 index 00000000..2421b48b --- /dev/null +++ b/transport/tuic/congestion_v2/windowed_filter.go @@ -0,0 +1,162 @@ +package congestion + +import ( + "golang.org/x/exp/constraints" +) + +// Implements Kathleen Nichols' algorithm for tracking the minimum (or maximum) +// estimate of a stream of samples over some fixed time interval. (E.g., +// the minimum RTT over the past five minutes.) The algorithm keeps track of +// the best, second best, and third best min (or max) estimates, maintaining an +// invariant that the measurement time of the n'th best >= n-1'th best. + +// The algorithm works as follows. On a reset, all three estimates are set to +// the same sample. The second best estimate is then recorded in the second +// quarter of the window, and a third best estimate is recorded in the second +// half of the window, bounding the worst case error when the true min is +// monotonically increasing (or true max is monotonically decreasing) over the +// window. +// +// A new best sample replaces all three estimates, since the new best is lower +// (or higher) than everything else in the window and it is the most recent. +// The window thus effectively gets reset on every new min. The same property +// holds true for second best and third best estimates. Specifically, when a +// sample arrives that is better than the second best but not better than the +// best, it replaces the second and third best estimates but not the best +// estimate. Similarly, a sample that is better than the third best estimate +// but not the other estimates replaces only the third best estimate. +// +// Finally, when the best expires, it is replaced by the second best, which in +// turn is replaced by the third best. The newest sample replaces the third +// best. + +type WindowedFilterValue interface { + any +} + +type WindowedFilterTime interface { + constraints.Integer | constraints.Float +} + +type WindowedFilter[V WindowedFilterValue, T WindowedFilterTime] struct { + // Time length of window. + windowLength T + estimates []entry[V, T] + comparator func(V, V) int +} + +type entry[V WindowedFilterValue, T WindowedFilterTime] struct { + sample V + time T +} + +// Compares two values and returns true if the first is greater than or equal +// to the second. +func MaxFilter[O constraints.Ordered](a, b O) int { + if a > b { + return 1 + } else if a < b { + return -1 + } + return 0 +} + +// Compares two values and returns true if the first is less than or equal +// to the second. +func MinFilter[O constraints.Ordered](a, b O) int { + if a < b { + return 1 + } else if a > b { + return -1 + } + return 0 +} + +func NewWindowedFilter[V WindowedFilterValue, T WindowedFilterTime](windowLength T, comparator func(V, V) int) *WindowedFilter[V, T] { + return &WindowedFilter[V, T]{ + windowLength: windowLength, + estimates: make([]entry[V, T], 3, 3), + comparator: comparator, + } +} + +// Changes the window length. Does not update any current samples. +func (f *WindowedFilter[V, T]) SetWindowLength(windowLength T) { + f.windowLength = windowLength +} + +func (f *WindowedFilter[V, T]) GetBest() V { + return f.estimates[0].sample +} + +func (f *WindowedFilter[V, T]) GetSecondBest() V { + return f.estimates[1].sample +} + +func (f *WindowedFilter[V, T]) GetThirdBest() V { + return f.estimates[2].sample +} + +// Updates best estimates with |sample|, and expires and updates best +// estimates as necessary. +func (f *WindowedFilter[V, T]) Update(newSample V, newTime T) { + // Reset all estimates if they have not yet been initialized, if new sample + // is a new best, or if the newest recorded estimate is too old. + if f.comparator(f.estimates[0].sample, *new(V)) == 0 || + f.comparator(newSample, f.estimates[0].sample) >= 0 || + newTime-f.estimates[2].time > f.windowLength { + f.Reset(newSample, newTime) + return + } + + if f.comparator(newSample, f.estimates[1].sample) >= 0 { + f.estimates[1] = entry[V, T]{newSample, newTime} + f.estimates[2] = f.estimates[1] + } else if f.comparator(newSample, f.estimates[2].sample) >= 0 { + f.estimates[2] = entry[V, T]{newSample, newTime} + } + + // Expire and update estimates as necessary. + if newTime-f.estimates[0].time > f.windowLength { + // The best estimate hasn't been updated for an entire window, so promote + // second and third best estimates. + f.estimates[0] = f.estimates[1] + f.estimates[1] = f.estimates[2] + f.estimates[2] = entry[V, T]{newSample, newTime} + // Need to iterate one more time. Check if the new best estimate is + // outside the window as well, since it may also have been recorded a + // long time ago. Don't need to iterate once more since we cover that + // case at the beginning of the method. + if newTime-f.estimates[0].time > f.windowLength { + f.estimates[0] = f.estimates[1] + f.estimates[1] = f.estimates[2] + } + return + } + if f.comparator(f.estimates[1].sample, f.estimates[0].sample) == 0 && + newTime-f.estimates[1].time > f.windowLength/4 { + // A quarter of the window has passed without a better sample, so the + // second-best estimate is taken from the second quarter of the window. + f.estimates[1] = entry[V, T]{newSample, newTime} + f.estimates[2] = f.estimates[1] + return + } + + if f.comparator(f.estimates[2].sample, f.estimates[1].sample) == 0 && + newTime-f.estimates[2].time > f.windowLength/2 { + // We've passed a half of the window without a better estimate, so take + // a third-best estimate from the second half of the window. + f.estimates[2] = entry[V, T]{newSample, newTime} + } +} + +// Resets all estimates to new sample. +func (f *WindowedFilter[V, T]) Reset(newSample V, newTime T) { + f.estimates[2] = entry[V, T]{newSample, newTime} + f.estimates[1] = f.estimates[2] + f.estimates[0] = f.estimates[1] +} + +func (f *WindowedFilter[V, T]) Clear() { + f.estimates = make([]entry[V, T], 3, 3) +} From 8253bfe2e00c22a5b81de866b0ae757e18efe15b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 1 Oct 2023 09:10:11 +0800 Subject: [PATCH 013/192] add `quic-go-disable-ecn` to experimental --- config/config.go | 1 + hub/executor/executor.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index e240f9b9..5ea45a39 100644 --- a/config/config.go +++ b/config/config.go @@ -159,6 +159,7 @@ type Sniffer struct { type Experimental struct { Fingerprints []string `yaml:"fingerprints"` QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` + QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` } // Config is clash config manager diff --git a/hub/executor/executor.go b/hub/executor/executor.go index a50d3539..ebcbac91 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -180,7 +180,10 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList func updateExperimental(c *config.Config) { if c.Experimental.QUICGoDisableGSO { - _ = os.Setenv("QUIC_GO_DISABLE_GSO", "1") + _ = os.Setenv("QUIC_GO_DISABLE_GSO", strconv.FormatBool(true)) + } + if c.Experimental.QUICGoDisableECN { + _ = os.Setenv("QUIC_GO_DISABLE_ECN", strconv.FormatBool(true)) } } From dbaee284e4310aea71344f5154b174bd0333b657 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:04:34 +0800 Subject: [PATCH 014/192] fix: hy2/tuic inbound cert isn't path Co-authored-by: wwqgtxx --- common/net/tls.go | 8 +++++++- hub/route/server.go | 2 +- listener/sing_hysteria2/server.go | 5 +---- listener/tuic/server.go | 5 +---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/net/tls.go b/common/net/tls.go index e51324f7..b2865503 100644 --- a/common/net/tls.go +++ b/common/net/tls.go @@ -10,7 +10,11 @@ import ( "math/big" ) -func ParseCert(certificate, privateKey string) (tls.Certificate, error) { +type Path interface { + Resolve(path string) string +} + +func ParseCert(certificate, privateKey string, path Path) (tls.Certificate, error) { if certificate == "" && privateKey == "" { return newRandomTLSKeyPair() } @@ -19,6 +23,8 @@ func ParseCert(certificate, privateKey string) (tls.Certificate, error) { return cert, nil } + certificate = path.Resolve(certificate) + privateKey = path.Resolve(privateKey) cert, loadErr := tls.LoadX509KeyPair(certificate, privateKey) if loadErr != nil { return tls.Certificate{}, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error()) diff --git a/hub/route/server.go b/hub/route/server.go index 3d0df95e..aa2d03b8 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -112,7 +112,7 @@ func Start(addr string, tlsAddr string, secret string, if len(tlsAddr) > 0 { go func() { - c, err := CN.ParseCert(certificat, privateKey) + c, err := CN.ParseCert(certificat, privateKey, C.Path) if err != nil { log.Errorln("External controller tls listen error: %s", err) return diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 7897bd84..bc25ec2a 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -50,10 +50,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi sl = &Listener{false, config, nil, nil} - config.Certificate = C.Path.Resolve(config.Certificate) - config.PrivateKey = C.Path.Resolve(config.PrivateKey) - - cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey, C.Path) if err != nil { return nil, err } diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 12a6ac6d..70cf4a01 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -44,10 +44,7 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( Additions: additions, } - config.Certificate = C.Path.Resolve(config.Certificate) - config.PrivateKey = C.Path.Resolve(config.PrivateKey) - - cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey, C.Path) if err != nil { return nil, err } From 4e3cd01aadff90adcd2ee5f68c007d53b3bcc31d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 1 Oct 2023 13:44:56 +0800 Subject: [PATCH 015/192] chore: merge some quic-go fix --- go.mod | 8 +- go.sum | 12 +- transport/hysteria/congestion/brutal.go | 4 - transport/tuic/common/congestion.go | 16 + transport/tuic/congestion/cubic.go | 213 +++++++++++++ transport/tuic/congestion/cubic_sender.go | 297 ++++++++++++++++++ .../tuic/congestion/hybrid_slow_start.go | 112 +++++++ transport/tuic/congestion/minmax.go | 56 ++++ 8 files changed, 704 insertions(+), 14 deletions(-) create mode 100644 transport/tuic/congestion/cubic.go create mode 100644 transport/tuic/congestion/cubic_sender.go create mode 100644 transport/tuic/congestion/hybrid_slow_start.go create mode 100644 transport/tuic/congestion/minmax.go diff --git a/go.mod b/go.mod index 826eb0ba..d1503b48 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55 - github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c + github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 + github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee @@ -32,7 +32,7 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.11 + github.com/sagernet/sing v0.2.12 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -105,4 +105,4 @@ require ( golang.org/x/tools v0.13.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 diff --git a/go.sum b/go.sum index d6c96aaa..3aa28a7f 100644 --- a/go.sum +++ b/go.sum @@ -93,12 +93,12 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55 h1:cAqp0BFOTr/1TpFicH1dA1q/6fp7E/JkqHBORfohqr4= -github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 h1:MkYAvDyhb7cwuqL4ZLKU3Oi6tYjFnz1sz5LS82JmtDo= -github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c h1:j7PKIUUhOAxJaLf/NmUKuIs9R06xNoYizwYgqf5HSrA= -github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c/go.mod h1:TPAXFCHCtzW9Dm+wq1l1R/p0v/S/xmuRU0qfPR7WlOA= +github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 h1:lxXUXdS2GB4Ktn3ocnzQ53v1lqd6LYYfYIKICugTaJM= +github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= +github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 67067917..88bf6f34 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -100,10 +100,6 @@ func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostByt b.updateAckRate(currentTimestamp) } -func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { - // Stub -} - func (b *BrutalSender) SetMaxDatagramSize(size congestion.ByteCount) { b.maxDatagramSize = size b.pacer.SetMaxDatagramSize(size) diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 1176ebd6..13c1300f 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -18,6 +18,22 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { cwnd = 32 } switch cc { + case "cubic": + quicConn.SetCongestionControl( + congestion.NewCubicSender( + congestion.DefaultClock{}, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + false, + ), + ) + case "new_reno": + quicConn.SetCongestionControl( + congestion.NewCubicSender( + congestion.DefaultClock{}, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + true, + ), + ) case "bbr_meta_v1": quicConn.SetCongestionControl( congestion.NewBBRSender( diff --git a/transport/tuic/congestion/cubic.go b/transport/tuic/congestion/cubic.go new file mode 100644 index 00000000..dd491a32 --- /dev/null +++ b/transport/tuic/congestion/cubic.go @@ -0,0 +1,213 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +// This cubic implementation is based on the one found in Chromiums's QUIC +// implementation, in the files net/quic/congestion_control/cubic.{hh,cc}. + +// Constants based on TCP defaults. +// The following constants are in 2^10 fractions of a second instead of ms to +// allow a 10 shift right to divide. + +// 1024*1024^3 (first 1024 is from 0.100^3) +// where 0.100 is 100 ms which is the scaling round trip time. +const ( + cubeScale = 40 + cubeCongestionWindowScale = 410 + cubeFactor congestion.ByteCount = 1 << cubeScale / cubeCongestionWindowScale / maxDatagramSize + // TODO: when re-enabling cubic, make sure to use the actual packet size here + maxDatagramSize = congestion.ByteCount(InitialPacketSizeIPv4) +) + +const defaultNumConnections = 1 + +// Default Cubic backoff factor +const beta float32 = 0.7 + +// Additional backoff factor when loss occurs in the concave part of the Cubic +// curve. This additional backoff factor is expected to give up bandwidth to +// new concurrent flows and speed up convergence. +const betaLastMax float32 = 0.85 + +// Cubic implements the cubic algorithm from TCP +type Cubic struct { + clock Clock + + // Number of connections to simulate. + numConnections int + + // Time when this cycle started, after last loss event. + epoch time.Time + + // Max congestion window used just before last loss event. + // Note: to improve fairness to other streams an additional back off is + // applied to this value if the new value is below our latest value. + lastMaxCongestionWindow congestion.ByteCount + + // Number of acked bytes since the cycle started (epoch). + ackedBytesCount congestion.ByteCount + + // TCP Reno equivalent congestion window in packets. + estimatedTCPcongestionWindow congestion.ByteCount + + // Origin point of cubic function. + originPointCongestionWindow congestion.ByteCount + + // Time to origin point of cubic function in 2^10 fractions of a second. + timeToOriginPoint uint32 + + // Last congestion window in packets computed by cubic function. + lastTargetCongestionWindow congestion.ByteCount +} + +// NewCubic returns a new Cubic instance +func NewCubic(clock Clock) *Cubic { + c := &Cubic{ + clock: clock, + numConnections: defaultNumConnections, + } + c.Reset() + return c +} + +// Reset is called after a timeout to reset the cubic state +func (c *Cubic) Reset() { + c.epoch = time.Time{} + c.lastMaxCongestionWindow = 0 + c.ackedBytesCount = 0 + c.estimatedTCPcongestionWindow = 0 + c.originPointCongestionWindow = 0 + c.timeToOriginPoint = 0 + c.lastTargetCongestionWindow = 0 +} + +func (c *Cubic) alpha() float32 { + // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that + // beta here is a cwnd multiplier, and is equal to 1-beta from the paper. + // We derive the equivalent alpha for an N-connection emulation as: + b := c.beta() + return 3 * float32(c.numConnections) * float32(c.numConnections) * (1 - b) / (1 + b) +} + +func (c *Cubic) beta() float32 { + // kNConnectionBeta is the backoff factor after loss for our N-connection + // emulation, which emulates the effective backoff of an ensemble of N + // TCP-Reno connections on a single loss event. The effective multiplier is + // computed as: + return (float32(c.numConnections) - 1 + beta) / float32(c.numConnections) +} + +func (c *Cubic) betaLastMax() float32 { + // betaLastMax is the additional backoff factor after loss for our + // N-connection emulation, which emulates the additional backoff of + // an ensemble of N TCP-Reno connections on a single loss event. The + // effective multiplier is computed as: + return (float32(c.numConnections) - 1 + betaLastMax) / float32(c.numConnections) +} + +// OnApplicationLimited is called on ack arrival when sender is unable to use +// the available congestion window. Resets Cubic state during quiescence. +func (c *Cubic) OnApplicationLimited() { + // When sender is not using the available congestion window, the window does + // not grow. But to be RTT-independent, Cubic assumes that the sender has been + // using the entire window during the time since the beginning of the current + // "epoch" (the end of the last loss recovery period). Since + // application-limited periods break this assumption, we reset the epoch when + // in such a period. This reset effectively freezes congestion window growth + // through application-limited periods and allows Cubic growth to continue + // when the entire window is being used. + c.epoch = time.Time{} +} + +// CongestionWindowAfterPacketLoss computes a new congestion window to use after +// a loss event. Returns the new congestion window in packets. The new +// congestion window is a multiplicative decrease of our current window. +func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow congestion.ByteCount) congestion.ByteCount { + if currentCongestionWindow+maxDatagramSize < c.lastMaxCongestionWindow { + // We never reached the old max, so assume we are competing with another + // flow. Use our extra back off factor to allow the other flow to go up. + c.lastMaxCongestionWindow = congestion.ByteCount(c.betaLastMax() * float32(currentCongestionWindow)) + } else { + c.lastMaxCongestionWindow = currentCongestionWindow + } + c.epoch = time.Time{} // Reset time. + return congestion.ByteCount(float32(currentCongestionWindow) * c.beta()) +} + +// CongestionWindowAfterAck computes a new congestion window to use after a received ACK. +// Returns the new congestion window in packets. The new congestion window +// follows a cubic function that depends on the time passed since last +// packet loss. +func (c *Cubic) CongestionWindowAfterAck( + ackedBytes congestion.ByteCount, + currentCongestionWindow congestion.ByteCount, + delayMin time.Duration, + eventTime time.Time, +) congestion.ByteCount { + c.ackedBytesCount += ackedBytes + + if c.epoch.IsZero() { + // First ACK after a loss event. + c.epoch = eventTime // Start of epoch. + c.ackedBytesCount = ackedBytes // Reset count. + // Reset estimated_tcp_congestion_window_ to be in sync with cubic. + c.estimatedTCPcongestionWindow = currentCongestionWindow + if c.lastMaxCongestionWindow <= currentCongestionWindow { + c.timeToOriginPoint = 0 + c.originPointCongestionWindow = currentCongestionWindow + } else { + c.timeToOriginPoint = uint32(math.Cbrt(float64(cubeFactor * (c.lastMaxCongestionWindow - currentCongestionWindow)))) + c.originPointCongestionWindow = c.lastMaxCongestionWindow + } + } + + // Change the time unit from microseconds to 2^10 fractions per second. Take + // the round trip time in account. This is done to allow us to use shift as a + // divide operator. + elapsedTime := int64(eventTime.Add(delayMin).Sub(c.epoch)/time.Microsecond) << 10 / (1000 * 1000) + + // Right-shifts of negative, signed numbers have implementation-dependent + // behavior, so force the offset to be positive, as is done in the kernel. + offset := int64(c.timeToOriginPoint) - elapsedTime + if offset < 0 { + offset = -offset + } + + deltaCongestionWindow := congestion.ByteCount(cubeCongestionWindowScale*offset*offset*offset) * maxDatagramSize >> cubeScale + var targetCongestionWindow congestion.ByteCount + if elapsedTime > int64(c.timeToOriginPoint) { + targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow + } else { + targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow + } + // Limit the CWND increase to half the acked bytes. + targetCongestionWindow = Min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) + + // Increase the window by approximately Alpha * 1 MSS of bytes every + // time we ack an estimated tcp window of bytes. For small + // congestion windows (less than 25), the formula below will + // increase slightly slower than linearly per estimated tcp window + // of bytes. + c.estimatedTCPcongestionWindow += congestion.ByteCount(float32(c.ackedBytesCount) * c.alpha() * float32(maxDatagramSize) / float32(c.estimatedTCPcongestionWindow)) + c.ackedBytesCount = 0 + + // We have a new cubic congestion window. + c.lastTargetCongestionWindow = targetCongestionWindow + + // Compute target congestion_window based on cubic target and estimated TCP + // congestion_window, use highest (fastest). + if targetCongestionWindow < c.estimatedTCPcongestionWindow { + targetCongestionWindow = c.estimatedTCPcongestionWindow + } + return targetCongestionWindow +} + +// SetNumConnections sets the number of emulated connections +func (c *Cubic) SetNumConnections(n int) { + c.numConnections = n +} diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go new file mode 100644 index 00000000..f544cd74 --- /dev/null +++ b/transport/tuic/congestion/cubic_sender.go @@ -0,0 +1,297 @@ +package congestion + +import ( + "fmt" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + maxBurstPackets = 3 + renoBeta = 0.7 // Reno backoff factor. + minCongestionWindowPackets = 2 + initialCongestionWindow = 32 +) + +const InvalidPacketNumber congestion.PacketNumber = -1 +const MaxCongestionWindowPackets = 20000 +const MaxByteCount = congestion.ByteCount(1<<62 - 1) + +type cubicSender struct { + hybridSlowStart HybridSlowStart + rttStats congestion.RTTStatsProvider + cubic *Cubic + pacer *pacer + clock Clock + + reno bool + + // Track the largest packet that has been sent. + largestSentPacketNumber congestion.PacketNumber + + // Track the largest packet that has been acked. + largestAckedPacketNumber congestion.PacketNumber + + // Track the largest packet number outstanding when a CWND cutback occurs. + largestSentAtLastCutback congestion.PacketNumber + + // Whether the last loss event caused us to exit slowstart. + // Used for stats collection of slowstartPacketsLost + lastCutbackExitedSlowstart bool + + // Congestion window in bytes. + congestionWindow congestion.ByteCount + + // Slow start congestion window in bytes, aka ssthresh. + slowStartThreshold congestion.ByteCount + + // ACK counter for the Reno implementation. + numAckedPackets uint64 + + initialCongestionWindow congestion.ByteCount + initialMaxCongestionWindow congestion.ByteCount + + maxDatagramSize congestion.ByteCount +} + +var ( + _ congestion.CongestionControl = &cubicSender{} +) + +// NewCubicSender makes a new cubic sender +func NewCubicSender( + clock Clock, + initialMaxDatagramSize congestion.ByteCount, + reno bool, +) *cubicSender { + return newCubicSender( + clock, + reno, + initialMaxDatagramSize, + initialCongestionWindow*initialMaxDatagramSize, + MaxCongestionWindowPackets*initialMaxDatagramSize, + ) +} + +func newCubicSender( + clock Clock, + reno bool, + initialMaxDatagramSize, + initialCongestionWindow, + initialMaxCongestionWindow congestion.ByteCount, +) *cubicSender { + c := &cubicSender{ + largestSentPacketNumber: InvalidPacketNumber, + largestAckedPacketNumber: InvalidPacketNumber, + largestSentAtLastCutback: InvalidPacketNumber, + initialCongestionWindow: initialCongestionWindow, + initialMaxCongestionWindow: initialMaxCongestionWindow, + congestionWindow: initialCongestionWindow, + slowStartThreshold: MaxByteCount, + cubic: NewCubic(clock), + clock: clock, + reno: reno, + maxDatagramSize: initialMaxDatagramSize, + } + c.pacer = newPacer(c.BandwidthEstimate) + return c +} + +func (c *cubicSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { + c.rttStats = provider +} + +// TimeUntilSend returns when the next packet should be sent. +func (c *cubicSender) TimeUntilSend(_ congestion.ByteCount) time.Time { + return c.pacer.TimeUntilSend() +} + +func (c *cubicSender) HasPacingBudget(now time.Time) bool { + return c.pacer.Budget(now) >= c.maxDatagramSize +} + +func (c *cubicSender) maxCongestionWindow() congestion.ByteCount { + return c.maxDatagramSize * MaxCongestionWindowPackets +} + +func (c *cubicSender) minCongestionWindow() congestion.ByteCount { + return c.maxDatagramSize * minCongestionWindowPackets +} + +func (c *cubicSender) OnPacketSent( + sentTime time.Time, + _ congestion.ByteCount, + packetNumber congestion.PacketNumber, + bytes congestion.ByteCount, + isRetransmittable bool, +) { + c.pacer.SentPacket(sentTime, bytes) + if !isRetransmittable { + return + } + c.largestSentPacketNumber = packetNumber + c.hybridSlowStart.OnPacketSent(packetNumber) +} + +func (c *cubicSender) CanSend(bytesInFlight congestion.ByteCount) bool { + return bytesInFlight < c.GetCongestionWindow() +} + +func (c *cubicSender) InRecovery() bool { + return c.largestAckedPacketNumber != InvalidPacketNumber && c.largestAckedPacketNumber <= c.largestSentAtLastCutback +} + +func (c *cubicSender) InSlowStart() bool { + return c.GetCongestionWindow() < c.slowStartThreshold +} + +func (c *cubicSender) GetCongestionWindow() congestion.ByteCount { + return c.congestionWindow +} + +func (c *cubicSender) MaybeExitSlowStart() { + if c.InSlowStart() && + c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) { + // exit slow start + c.slowStartThreshold = c.congestionWindow + } +} + +func (c *cubicSender) OnPacketAcked( + ackedPacketNumber congestion.PacketNumber, + ackedBytes congestion.ByteCount, + priorInFlight congestion.ByteCount, + eventTime time.Time, +) { + c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber) + if c.InRecovery() { + return + } + c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime) + if c.InSlowStart() { + c.hybridSlowStart.OnPacketAcked(ackedPacketNumber) + } +} + +func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { + // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets + // already sent should be treated as a single loss event, since it's expected. + if packetNumber <= c.largestSentAtLastCutback { + return + } + c.lastCutbackExitedSlowstart = c.InSlowStart() + + if c.reno { + c.congestionWindow = congestion.ByteCount(float64(c.congestionWindow) * renoBeta) + } else { + c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow) + } + if minCwnd := c.minCongestionWindow(); c.congestionWindow < minCwnd { + c.congestionWindow = minCwnd + } + c.slowStartThreshold = c.congestionWindow + c.largestSentAtLastCutback = c.largestSentPacketNumber + // reset packet count from congestion avoidance mode. We start + // counting again when we're out of recovery. + c.numAckedPackets = 0 +} + +func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + // Stub +} + +// Called when we receive an ack. Normal TCP tracks how many packets one ack +// represents, but quic has a separate ack for each packet. +func (c *cubicSender) maybeIncreaseCwnd( + _ congestion.PacketNumber, + ackedBytes congestion.ByteCount, + priorInFlight congestion.ByteCount, + eventTime time.Time, +) { + // Do not increase the congestion window unless the sender is close to using + // the current window. + if !c.isCwndLimited(priorInFlight) { + c.cubic.OnApplicationLimited() + return + } + if c.congestionWindow >= c.maxCongestionWindow() { + return + } + if c.InSlowStart() { + // TCP slow start, exponential growth, increase by one for each ACK. + c.congestionWindow += c.maxDatagramSize + return + } + // Congestion avoidance + if c.reno { + // Classic Reno congestion avoidance. + c.numAckedPackets++ + if c.numAckedPackets >= uint64(c.congestionWindow/c.maxDatagramSize) { + c.congestionWindow += c.maxDatagramSize + c.numAckedPackets = 0 + } + } else { + c.congestionWindow = Min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) + } +} + +func (c *cubicSender) isCwndLimited(bytesInFlight congestion.ByteCount) bool { + congestionWindow := c.GetCongestionWindow() + if bytesInFlight >= congestionWindow { + return true + } + availableBytes := congestionWindow - bytesInFlight + slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2 + return slowStartLimited || availableBytes <= maxBurstPackets*c.maxDatagramSize +} + +// BandwidthEstimate returns the current bandwidth estimate +func (c *cubicSender) BandwidthEstimate() Bandwidth { + if c.rttStats == nil { + return infBandwidth + } + srtt := c.rttStats.SmoothedRTT() + if srtt == 0 { + // If we haven't measured an rtt, the bandwidth estimate is unknown. + return infBandwidth + } + return BandwidthFromDelta(c.GetCongestionWindow(), srtt) +} + +// OnRetransmissionTimeout is called on an retransmission timeout +func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { + c.largestSentAtLastCutback = InvalidPacketNumber + if !packetsRetransmitted { + return + } + c.hybridSlowStart.Restart() + c.cubic.Reset() + c.slowStartThreshold = c.congestionWindow / 2 + c.congestionWindow = c.minCongestionWindow() +} + +// OnConnectionMigration is called when the connection is migrated (?) +func (c *cubicSender) OnConnectionMigration() { + c.hybridSlowStart.Restart() + c.largestSentPacketNumber = InvalidPacketNumber + c.largestAckedPacketNumber = InvalidPacketNumber + c.largestSentAtLastCutback = InvalidPacketNumber + c.lastCutbackExitedSlowstart = false + c.cubic.Reset() + c.numAckedPackets = 0 + c.congestionWindow = c.initialCongestionWindow + c.slowStartThreshold = c.initialMaxCongestionWindow +} + +func (c *cubicSender) SetMaxDatagramSize(s congestion.ByteCount) { + if s < c.maxDatagramSize { + panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s)) + } + cwndIsMinCwnd := c.congestionWindow == c.minCongestionWindow() + c.maxDatagramSize = s + if cwndIsMinCwnd { + c.congestionWindow = c.minCongestionWindow() + } + c.pacer.SetMaxDatagramSize(s) +} diff --git a/transport/tuic/congestion/hybrid_slow_start.go b/transport/tuic/congestion/hybrid_slow_start.go new file mode 100644 index 00000000..7586774e --- /dev/null +++ b/transport/tuic/congestion/hybrid_slow_start.go @@ -0,0 +1,112 @@ +package congestion + +import ( + "time" + + "github.com/metacubex/quic-go/congestion" +) + +// Note(pwestin): the magic clamping numbers come from the original code in +// tcp_cubic.c. +const hybridStartLowWindow = congestion.ByteCount(16) + +// Number of delay samples for detecting the increase of delay. +const hybridStartMinSamples = uint32(8) + +// Exit slow start if the min rtt has increased by more than 1/8th. +const hybridStartDelayFactorExp = 3 // 2^3 = 8 +// The original paper specifies 2 and 8ms, but those have changed over time. +const ( + hybridStartDelayMinThresholdUs = int64(4000) + hybridStartDelayMaxThresholdUs = int64(16000) +) + +// HybridSlowStart implements the TCP hybrid slow start algorithm +type HybridSlowStart struct { + endPacketNumber congestion.PacketNumber + lastSentPacketNumber congestion.PacketNumber + started bool + currentMinRTT time.Duration + rttSampleCount uint32 + hystartFound bool +} + +// StartReceiveRound is called for the start of each receive round (burst) in the slow start phase. +func (s *HybridSlowStart) StartReceiveRound(lastSent congestion.PacketNumber) { + s.endPacketNumber = lastSent + s.currentMinRTT = 0 + s.rttSampleCount = 0 + s.started = true +} + +// IsEndOfRound returns true if this ack is the last packet number of our current slow start round. +func (s *HybridSlowStart) IsEndOfRound(ack congestion.PacketNumber) bool { + return s.endPacketNumber < ack +} + +// ShouldExitSlowStart should be called on every new ack frame, since a new +// RTT measurement can be made then. +// rtt: the RTT for this ack packet. +// minRTT: is the lowest delay (RTT) we have seen during the session. +// congestionWindow: the congestion window in packets. +func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT time.Duration, congestionWindow congestion.ByteCount) bool { + if !s.started { + // Time to start the hybrid slow start. + s.StartReceiveRound(s.lastSentPacketNumber) + } + if s.hystartFound { + return true + } + // Second detection parameter - delay increase detection. + // Compare the minimum delay (s.currentMinRTT) of the current + // burst of packets relative to the minimum delay during the session. + // Note: we only look at the first few(8) packets in each burst, since we + // only want to compare the lowest RTT of the burst relative to previous + // bursts. + s.rttSampleCount++ + if s.rttSampleCount <= hybridStartMinSamples { + if s.currentMinRTT == 0 || s.currentMinRTT > latestRTT { + s.currentMinRTT = latestRTT + } + } + // We only need to check this once per round. + if s.rttSampleCount == hybridStartMinSamples { + // Divide minRTT by 8 to get a rtt increase threshold for exiting. + minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) + // Ensure the rtt threshold is never less than 2ms or more than 16ms. + minRTTincreaseThresholdUs = Min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) + minRTTincreaseThreshold := time.Duration(Max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond + + if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { + s.hystartFound = true + } + } + // Exit from slow start if the cwnd is greater than 16 and + // increasing delay is found. + return congestionWindow >= hybridStartLowWindow && s.hystartFound +} + +// OnPacketSent is called when a packet was sent +func (s *HybridSlowStart) OnPacketSent(packetNumber congestion.PacketNumber) { + s.lastSentPacketNumber = packetNumber +} + +// OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end +// the round when the final packet of the burst is received and start it on +// the next incoming ack. +func (s *HybridSlowStart) OnPacketAcked(ackedPacketNumber congestion.PacketNumber) { + if s.IsEndOfRound(ackedPacketNumber) { + s.started = false + } +} + +// Started returns true if started +func (s *HybridSlowStart) Started() bool { + return s.started +} + +// Restart the slow start phase +func (s *HybridSlowStart) Restart() { + s.started = false + s.hystartFound = false +} diff --git a/transport/tuic/congestion/minmax.go b/transport/tuic/congestion/minmax.go new file mode 100644 index 00000000..0a8f4ad4 --- /dev/null +++ b/transport/tuic/congestion/minmax.go @@ -0,0 +1,56 @@ +package congestion + +import ( + "math" + "time" +) + +// InfDuration is a duration of infinite length +const InfDuration = time.Duration(math.MaxInt64) + +// MinNonZeroDuration return the minimum duration that's not zero. +func MinNonZeroDuration(a, b time.Duration) time.Duration { + if a == 0 { + return b + } + if b == 0 { + return a + } + return Min(a, b) +} + +// AbsDuration returns the absolute value of a time duration +func AbsDuration(d time.Duration) time.Duration { + if d >= 0 { + return d + } + return -d +} + +// MinTime returns the earlier time +func MinTime(a, b time.Time) time.Time { + if a.After(b) { + return b + } + return a +} + +// MinNonZeroTime returns the earlist time that is not time.Time{} +// If both a and b are time.Time{}, it returns time.Time{} +func MinNonZeroTime(a, b time.Time) time.Time { + if a.IsZero() { + return b + } + if b.IsZero() { + return a + } + return MinTime(a, b) +} + +// MaxTime returns the later time +func MaxTime(a, b time.Time) time.Time { + if a.After(b) { + return a + } + return b +} From 7eae7756f56034913c36add8e316a629bd31eee5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 1 Oct 2023 19:15:26 +0800 Subject: [PATCH 016/192] chore: update gvisor --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index d1503b48..26075f32 100644 --- a/go.mod +++ b/go.mod @@ -23,9 +23,9 @@ require ( github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee + github.com/metacubex/sing-tun v0.1.14 github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 - github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 + github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 @@ -77,7 +77,7 @@ require ( github.com/klauspost/compress v1.16.7 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect + github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect diff --git a/go.sum b/go.sum index 3aa28a7f..a8de3428 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= -github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= -github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= +github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= +github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 h1:lxXUXdS2GB4Ktn3ocnzQ53v1lqd6LYYfYIKICugTaJM= github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= @@ -103,12 +103,12 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee h1:hbbq181N4ZaDbhk/iJ0iA+3xfI/6v+j3nWeN5Who1xQ= -github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M= +github.com/metacubex/sing-tun v0.1.14 h1:35ermQwWZkHDai9Eg7EXoCjBFaU7IxcgzFOSMIcTR24= +github.com/metacubex/sing-tun v0.1.14/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= -github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= -github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= +github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= +github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= From d1e88a30cb1fe7be8ea938039c22e8f9ab44e50d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 3 Oct 2023 16:00:03 +0800 Subject: [PATCH 017/192] fix: gVisor UDP 6to4 check --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 26075f32..abcf0a2c 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.14 + github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 diff --git a/go.sum b/go.sum index a8de3428..cd1a44a2 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.14 h1:35ermQwWZkHDai9Eg7EXoCjBFaU7IxcgzFOSMIcTR24= -github.com/metacubex/sing-tun v0.1.14/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= +github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c h1:vzueqPO6LCdgE+KpGdZ89PwxcDGQW+lCnc7Leq2s1yY= +github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= From 5ff4473083e95c62614ca1e735fd33e57c917ec4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 6 Oct 2023 17:44:36 +0800 Subject: [PATCH 018/192] chore: migrate from gorilla/websocket to gobwas/ws --- component/tls/utls.go | 9 +- go.mod | 4 +- go.sum | 9 +- hub/route/connections.go | 9 +- hub/route/server.go | 36 +++-- transport/vmess/websocket.go | 263 ++++++++++++++++++++--------------- 6 files changed, 187 insertions(+), 143 deletions(-) diff --git a/component/tls/utls.go b/component/tls/utls.go index 7ea2ad06..e3d101dc 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -99,10 +99,9 @@ func copyConfig(c *tls.Config) *utls.Config { } } -// WebsocketHandshake basically calls UConn.Handshake inside it but it will only send -// http/1.1 in its ALPN. +// BuildWebsocketHandshakeState it will only send http/1.1 in its ALPN. // Copy from https://github.com/XTLS/Xray-core/blob/main/transport/internet/tls/tls.go -func (c *UConn) WebsocketHandshake() error { +func (c *UConn) BuildWebsocketHandshakeState() error { // Build the handshake state. This will apply every variable of the TLS of the // fingerprint in the UConn if err := c.BuildHandshakeState(); err != nil { @@ -120,11 +119,11 @@ func (c *UConn) WebsocketHandshake() error { if !hasALPNExtension { // Append extension if doesn't exists c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}) } - // Rebuild the client hello and do the handshake + // Rebuild the client hello if err := c.BuildHandshakeState(); err != nil { return err } - return c.Handshake() + return nil } func SetGlobalUtlsClient(Client string) { diff --git a/go.mod b/go.mod index abcf0a2c..e14ccda1 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 + github.com/gobwas/ws v1.3.0 github.com/gofrs/uuid/v5 v5.0.0 - github.com/gorilla/websocket v1.5.0 github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a github.com/jpillora/backoff v1.0.0 github.com/klauspost/cpuid/v2 v2.2.5 @@ -69,6 +69,8 @@ require ( github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect diff --git a/go.sum b/go.sum index cd1a44a2..0c6b9e50 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,12 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0= +github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -63,8 +69,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -237,6 +241,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= diff --git a/hub/route/connections.go b/hub/route/connections.go index b123ecae..67d5afa3 100644 --- a/hub/route/connections.go +++ b/hub/route/connections.go @@ -11,7 +11,8 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/render" - "github.com/gorilla/websocket" + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" ) func connectionRouter() http.Handler { @@ -23,13 +24,13 @@ func connectionRouter() http.Handler { } func getConnections(w http.ResponseWriter, r *http.Request) { - if !websocket.IsWebSocketUpgrade(r) { + if !(r.Header.Get("Upgrade") == "websocket") { snapshot := statistic.DefaultManager.Snapshot() render.JSON(w, r, snapshot) return } - conn, err := upgrader.Upgrade(w, r, nil) + conn, _, _, err := ws.UpgradeHTTP(r, w) if err != nil { return } @@ -55,7 +56,7 @@ func getConnections(w http.ResponseWriter, r *http.Request) { return err } - return conn.WriteMessage(websocket.TextMessage, buf.Bytes()) + return wsutil.WriteMessage(conn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err := sendSnapshot(); err != nil { diff --git a/hub/route/server.go b/hub/route/server.go index aa2d03b8..93afd989 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -5,6 +5,7 @@ import ( "crypto/subtle" "crypto/tls" "encoding/json" + "net" "net/http" "runtime/debug" "strings" @@ -21,7 +22,8 @@ import ( "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "github.com/go-chi/render" - "github.com/gorilla/websocket" + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" ) var ( @@ -29,12 +31,6 @@ var ( serverAddr = "" uiPath = "" - - upgrader = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - } ) type Traffic struct { @@ -166,7 +162,7 @@ func authentication(next http.Handler) http.Handler { } // Browser websocket not support custom header - if websocket.IsWebSocketUpgrade(r) && r.URL.Query().Get("token") != "" { + if r.Header.Get("Upgrade") == "websocket" && r.URL.Query().Get("token") != "" { token := r.URL.Query().Get("token") if !safeEuqal(token, serverSecret) { render.Status(r, http.StatusUnauthorized) @@ -197,10 +193,10 @@ func hello(w http.ResponseWriter, r *http.Request) { } func traffic(w http.ResponseWriter, r *http.Request) { - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var wsConn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + wsConn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } @@ -230,7 +226,7 @@ func traffic(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err != nil { @@ -240,10 +236,10 @@ func traffic(w http.ResponseWriter, r *http.Request) { } func memory(w http.ResponseWriter, r *http.Request) { - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var wsConn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + wsConn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } @@ -280,7 +276,7 @@ func memory(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err != nil { @@ -323,10 +319,10 @@ func getLogs(w http.ResponseWriter, r *http.Request) { return } - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var wsConn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + wsConn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } @@ -385,7 +381,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err != nil { diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index a4ce99a9..2b26eb1a 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -1,6 +1,7 @@ package vmess import ( + "bufio" "bytes" "context" "crypto/tls" @@ -14,27 +15,24 @@ import ( "net/url" "strconv" "strings" - "sync" "time" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/gorilla/websocket" + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" "github.com/zhangyunhao116/fastrand" ) type websocketConn struct { - conn *websocket.Conn - reader io.Reader - remoteAddr net.Addr + net.Conn + state ws.State + reader *wsutil.Reader + controlHandler wsutil.FrameHandlerFunc rawWriter N.ExtendedWriter - - // https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency - rMux sync.Mutex - wMux sync.Mutex } type websocketWithEarlyDataConn struct { @@ -61,32 +59,48 @@ type WebsocketConfig struct { } // Read implements net.Conn.Read() -func (wsc *websocketConn) Read(b []byte) (int, error) { - wsc.rMux.Lock() - defer wsc.rMux.Unlock() +// modify from gobwas/ws/wsutil.readData +func (wsc *websocketConn) Read(b []byte) (n int, err error) { + var header ws.Header for { - reader, err := wsc.getReader() - if err != nil { - return 0, err + n, err = wsc.reader.Read(b) + // in gobwas/ws: "The error is io.EOF only if all of message bytes were read." + // but maybe next frame still have data, so drop it + if errors.Is(err, io.EOF) { + err = nil } - - nBytes, err := reader.Read(b) - if err == io.EOF { - wsc.reader = nil + if !errors.Is(err, wsutil.ErrNoFrameAdvance) { + return + } + header, err = wsc.reader.NextFrame() + if err != nil { + return + } + if header.OpCode.IsControl() { + err = wsc.controlHandler(header, wsc.reader) + if err != nil { + return + } + continue + } + if header.OpCode&(ws.OpBinary|ws.OpText) == 0 { + err = wsc.reader.Discard() + if err != nil { + return + } continue } - return nBytes, err } } // Write implements io.Writer. -func (wsc *websocketConn) Write(b []byte) (int, error) { - wsc.wMux.Lock() - defer wsc.wMux.Unlock() - if err := wsc.conn.WriteMessage(websocket.BinaryMessage, b); err != nil { - return 0, err +func (wsc *websocketConn) Write(b []byte) (n int, err error) { + err = wsutil.WriteMessage(wsc.Conn, wsc.state, ws.OpBinary, b) + if err != nil { + return } - return len(b), nil + n = len(b) + return } func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { @@ -108,7 +122,7 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { header := buffer.ExtendHeader(headerLen) _ = header[2] // bounds check hint to compiler - header[0] = websocket.BinaryMessage | 1<<7 + header[0] = byte(ws.OpBinary) | 0x80 header[1] = 1 << 7 if dataLen < 126 { @@ -121,12 +135,12 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { binary.BigEndian.PutUint64(header[2:], uint64(dataLen)) } - maskKey := fastrand.Uint32() - binary.LittleEndian.PutUint32(header[1+payloadBitLength:], maskKey) - N.MaskWebSocket(maskKey, data) + if wsc.state.ClientSide() { + maskKey := fastrand.Uint32() + binary.LittleEndian.PutUint32(header[1+payloadBitLength:], maskKey) + N.MaskWebSocket(maskKey, data) + } - wsc.wMux.Lock() - defer wsc.wMux.Unlock() return wsc.rawWriter.WriteBuffer(buffer) } @@ -135,59 +149,16 @@ func (wsc *websocketConn) FrontHeadroom() int { } func (wsc *websocketConn) Upstream() any { - return wsc.conn.UnderlyingConn() + return wsc.Conn } func (wsc *websocketConn) Close() error { - var e []string - if err := wsc.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5)); err != nil { - e = append(e, err.Error()) - } - if err := wsc.conn.Close(); err != nil { - e = append(e, err.Error()) - } - if len(e) > 0 { - return fmt.Errorf("failed to close connection: %s", strings.Join(e, ",")) - } + _ = wsc.Conn.SetWriteDeadline(time.Now().Add(time.Second * 5)) + _ = wsutil.WriteMessage(wsc.Conn, wsc.state, ws.OpClose, ws.NewCloseFrameBody(ws.StatusNormalClosure, "")) + _ = wsc.Conn.Close() return nil } -func (wsc *websocketConn) getReader() (io.Reader, error) { - if wsc.reader != nil { - return wsc.reader, nil - } - - _, reader, err := wsc.conn.NextReader() - if err != nil { - return nil, err - } - wsc.reader = reader - return reader, nil -} - -func (wsc *websocketConn) LocalAddr() net.Addr { - return wsc.conn.LocalAddr() -} - -func (wsc *websocketConn) RemoteAddr() net.Addr { - return wsc.remoteAddr -} - -func (wsc *websocketConn) SetDeadline(t time.Time) error { - if err := wsc.SetReadDeadline(t); err != nil { - return err - } - return wsc.SetWriteDeadline(t) -} - -func (wsc *websocketConn) SetReadDeadline(t time.Time) error { - return wsc.conn.SetReadDeadline(t) -} - -func (wsc *websocketConn) SetWriteDeadline(t time.Time) error { - return wsc.conn.SetWriteDeadline(t) -} - func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error { base64DataBuf := &bytes.Buffer{} base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, base64DataBuf) @@ -341,29 +312,25 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co } func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { - - dialer := &websocket.Dialer{ - NetDial: func(network, addr string) (net.Conn, error) { + dialer := ws.Dialer{ + NetDial: func(ctx context.Context, network, addr string) (net.Conn, error) { return conn, nil }, - ReadBufferSize: 4 * 1024, - WriteBufferSize: 4 * 1024, - HandshakeTimeout: time.Second * 8, + TLSConfig: c.TLSConfig, } - scheme := "ws" if c.TLS { scheme = "wss" - dialer.TLSClientConfig = c.TLSConfig if len(c.ClientFingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { - dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) { - utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) + utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) - if err := utlsConn.(*tlsC.UConn).WebsocketHandshake(); err != nil { - return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) - } - return utlsConn, nil + if err := utlsConn.(*tlsC.UConn).BuildWebsocketHandshakeState(); err != nil { + return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) + } + + dialer.TLSClient = func(conn net.Conn, hostname string) net.Conn { + return utlsConn } } } @@ -381,38 +348,47 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } - headers := http.Header{} + headers := http.Header{"User-Agent": []string{"Go-http-client/1.1"}} // match golang's net/http if c.Headers != nil { - for k := range c.Headers { - headers.Add(k, c.Headers.Get(k)) + cHeaders := c.Headers + // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` + // if headers has "Host" will send repeatedly + if host := cHeaders.Get("Host"); host != "" { + cHeaders.Del("Host") + uri.Host = host + } + for k := range cHeaders { + headers.Add(k, cHeaders.Get(k)) } } if earlyData != nil { + earlyDataString := earlyData.String() if c.EarlyDataHeaderName == "" { - uri.Path += earlyData.String() + uri.Path += earlyDataString } else { - headers.Set(c.EarlyDataHeaderName, earlyData.String()) + // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer + // if not will cause ws.ErrHandshakeBadSubProtocol + if c.EarlyDataHeaderName == "Sec-WebSocket-Protocol" { + // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols + // to avoid send repeatedly don't set it to headers + dialer.Protocols = []string{earlyDataString} + } else { + headers.Set(c.EarlyDataHeaderName, earlyDataString) + } + } } - wsConn, resp, err := dialer.DialContext(ctx, uri.String(), headers) + dialer.Header = ws.HandshakeHeaderHTTP(headers) + + conn, reader, _, err := dialer.Dial(ctx, uri.String()) if err != nil { - reason := err - if resp != nil { - reason = errors.New(resp.Status) - } - return nil, fmt.Errorf("dial %s error: %w", uri.Host, reason) + return nil, fmt.Errorf("dial %s error: %w", uri.Host, err) } - conn = &websocketConn{ - conn: wsConn, - rawWriter: N.NewExtendedWriter(wsConn.UnderlyingConn()), - remoteAddr: conn.RemoteAddr(), - } + conn = newWebsocketConn(conn, reader, ws.StateClientSide) // websocketConn can't correct handle ReadDeadline - // gorilla/websocket will cache the os.ErrDeadlineExceeded from conn.Read() - // it will cause read fail and event panic in *websocket.Conn.NextReader() // so call N.NewDeadlineConn to add a safe wrapper return N.NewDeadlineConn(conn), nil } @@ -436,3 +412,68 @@ func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) return streamWebsocketConn(ctx, conn, c, nil) } + +func newWebsocketConn(conn net.Conn, br *bufio.Reader, state ws.State) *websocketConn { + controlHandler := wsutil.ControlFrameHandler(conn, state) + var reader io.Reader + if br != nil && br.Buffered() > 0 { + reader = br + } else { + reader = conn + } + return &websocketConn{ + Conn: conn, + state: state, + reader: &wsutil.Reader{ + Source: reader, + State: state, + SkipHeaderCheck: true, + CheckUTF8: false, + OnIntermediate: controlHandler, + }, + controlHandler: controlHandler, + rawWriter: N.NewExtendedWriter(conn), + } +} + +var replacer = strings.NewReplacer("+", "-", "/", "_", "=", "") + +func decodeEd(s string) ([]byte, error) { + return base64.RawURLEncoding.DecodeString(replacer.Replace(s)) +} + +func decodeXray0rtt(requestHeader http.Header) ([]byte, http.Header) { + var edBuf []byte + responseHeader := http.Header{} + // read inHeader's `Sec-WebSocket-Protocol` for Xray's 0rtt ws + if secProtocol := requestHeader.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { + if buf, err := decodeEd(secProtocol); err == nil { // sure could base64 decode + edBuf = buf + } + } + return edBuf, responseHeader +} + +func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { + edBuf, responseHeader := decodeXray0rtt(r.Header) + wsConn, rw, _, err := ws.HTTPUpgrader{ + Header: responseHeader, + }.Upgrade(r, w) + if err != nil { + return nil, err + } + conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) + if len(edBuf) > 0 { + return &websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}, nil + } + return conn, nil +} + +type websocketWithReaderConn struct { + *websocketConn + reader io.Reader +} + +func (ws *websocketWithReaderConn) Read(b []byte) (n int, err error) { + return ws.reader.Read(b) +} From 791ecfbb32219b7b5cf625c3aa74a9f9003eef89 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 7 Oct 2023 16:45:15 +0800 Subject: [PATCH 019/192] feat: add `ws-path` to vmess listener --- docs/config.yaml | 1 + listener/config/vmess.go | 1 + listener/inbound/vmess.go | 4 +++- listener/sing_vmess/server.go | 20 ++++++++++++++++++++ transport/vmess/websocket.go | 19 +++++++++++-------- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index c2bdc263..030328b6 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -936,6 +936,7 @@ listeners: - username: 1 uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 + # ws-path: "/" # 如果不为空则开启websocket传输层 - name: tuic-in-1 type: tuic diff --git a/listener/config/vmess.go b/listener/config/vmess.go index cc49433e..88bde9a4 100644 --- a/listener/config/vmess.go +++ b/listener/config/vmess.go @@ -14,6 +14,7 @@ type VmessServer struct { Enable bool Listen string Users []VmessUser + WsPath string } func (t VmessServer) String() string { diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index fa2c30f1..36bb208b 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -9,7 +9,8 @@ import ( type VmessOption struct { BaseOption - Users []VmessUser `inbound:"users"` + Users []VmessUser `inbound:"users"` + WsPath string `inbound:"ws-path,omitempty"` } type VmessUser struct { @@ -49,6 +50,7 @@ func NewVmess(options *VmessOption) (*Vmess, error) { Enable: true, Listen: base.RawAddress(), Users: users, + WsPath: options.WsPath, }, }, nil } diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index d28213c8..96d713c9 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -3,6 +3,7 @@ package sing_vmess import ( "context" "net" + "net/http" "net/url" "strings" @@ -12,6 +13,7 @@ import ( LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/listener/sing" "github.com/Dreamacro/clash/ntp" + clashVMess "github.com/Dreamacro/clash/transport/vmess" vmess "github.com/metacubex/sing-vmess" "github.com/sagernet/sing/common" @@ -65,6 +67,20 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl = &Listener{false, config, nil, service} + var httpMux *http.ServeMux + + if config.WsPath != "" { + httpMux = http.NewServeMux() + httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { + conn, err := clashVMess.StreamUpgradedWebsocketConn(w, r) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + sl.HandleConn(conn, tunnel) + }) + } + for _, addr := range strings.Split(config.Listen, ",") { addr := addr @@ -76,6 +92,10 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl.listeners = append(sl.listeners, l) go func() { + if httpMux != nil { + _ = http.Serve(l, httpMux) + return + } for { c, err := l.Accept() if err != nil { diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 2b26eb1a..6d679e29 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -118,12 +118,17 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { var headerLen int headerLen += 1 // FIN / RSV / OPCODE headerLen += payloadBitLength - headerLen += 4 // MASK KEY + if wsc.state.ClientSide() { + headerLen += 4 // MASK KEY + } header := buffer.ExtendHeader(headerLen) - _ = header[2] // bounds check hint to compiler header[0] = byte(ws.OpBinary) | 0x80 - header[1] = 1 << 7 + if wsc.state.ClientSide() { + header[1] = 1 << 7 + } else { + header[1] = 0 + } if dataLen < 126 { header[1] |= byte(dataLen) @@ -456,17 +461,15 @@ func decodeXray0rtt(requestHeader http.Header) ([]byte, http.Header) { func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { edBuf, responseHeader := decodeXray0rtt(r.Header) - wsConn, rw, _, err := ws.HTTPUpgrader{ - Header: responseHeader, - }.Upgrade(r, w) + wsConn, rw, _, err := ws.HTTPUpgrader{Header: responseHeader}.Upgrade(r, w) if err != nil { return nil, err } conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) if len(edBuf) > 0 { - return &websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}, nil + return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil } - return conn, nil + return N.NewDeadlineConn(conn), nil } type websocketWithReaderConn struct { From d8fe7a52d685b1edf63395ca7de73a16f8307149 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 7 Oct 2023 17:08:54 +0800 Subject: [PATCH 020/192] feat: add `certificate` and `private-key` to vmess listener --- docs/config.yaml | 3 +++ listener/config/vmess.go | 10 ++++++---- listener/inbound/vmess.go | 16 ++++++++++------ listener/sing_vmess/server.go | 13 +++++++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 030328b6..bfcdc0cd 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -937,6 +937,9 @@ listeners: uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 # ws-path: "/" # 如果不为空则开启websocket传输层 + # 下面两项如果填写则开启tls(需要同时填写) + # certificate: ./server.crt + # private-key: ./server.key - name: tuic-in-1 type: tuic diff --git a/listener/config/vmess.go b/listener/config/vmess.go index 88bde9a4..1cf2d46c 100644 --- a/listener/config/vmess.go +++ b/listener/config/vmess.go @@ -11,10 +11,12 @@ type VmessUser struct { } type VmessServer struct { - Enable bool - Listen string - Users []VmessUser - WsPath string + Enable bool + Listen string + Users []VmessUser + WsPath string + Certificate string + PrivateKey string } func (t VmessServer) String() string { diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 36bb208b..3f516198 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -9,8 +9,10 @@ import ( type VmessOption struct { BaseOption - Users []VmessUser `inbound:"users"` - WsPath string `inbound:"ws-path,omitempty"` + Users []VmessUser `inbound:"users"` + WsPath string `inbound:"ws-path,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` } type VmessUser struct { @@ -47,10 +49,12 @@ func NewVmess(options *VmessOption) (*Vmess, error) { Base: base, config: options, vs: LC.VmessServer{ - Enable: true, - Listen: base.RawAddress(), - Users: users, - WsPath: options.WsPath, + Enable: true, + Listen: base.RawAddress(), + Users: users, + WsPath: options.WsPath, + Certificate: options.Certificate, + PrivateKey: options.PrivateKey, }, }, nil } diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 96d713c9..014e86f9 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -2,6 +2,7 @@ package sing_vmess import ( "context" + "crypto/tls" "net" "net/http" "net/url" @@ -67,8 +68,16 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl = &Listener{false, config, nil, service} + tlsConfig := &tls.Config{} var httpMux *http.ServeMux + if config.Certificate != "" && config.PrivateKey != "" { + cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{cert} + } if config.WsPath != "" { httpMux = http.NewServeMux() httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { @@ -79,6 +88,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) } sl.HandleConn(conn, tunnel) }) + tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1") } for _, addr := range strings.Split(config.Listen, ",") { @@ -89,6 +99,9 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) if err != nil { return nil, err } + if len(tlsConfig.Certificates) > 0 { + l = tls.NewListener(l, tlsConfig) + } sl.listeners = append(sl.listeners, l) go func() { From 5a1800d642a6d928637f55bff2382a81ef1c96ab Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 7 Oct 2023 17:30:03 +0800 Subject: [PATCH 021/192] fix: BBR bandwidth estimation edge case from https://github.com/apernet/hysteria/commit/89429598bf897a34d61027cf7f68f5e35fcfff4b --- go.mod | 2 +- go.sum | 4 ++-- transport/tuic/congestion_v2/bbr_sender.go | 18 ++++++++++++++---- transport/tuic/congestion_v2/pacer.go | 3 +++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index e14ccda1..171fec55 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 + github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838 github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 diff --git a/go.sum b/go.sum index 0c6b9e50..aa6ff01b 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 h1:lxXUXdS2GB4Ktn3ocnzQ53v1lqd6LYYfYIKICugTaJM= -github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838 h1:VqiDBQY+MB7vmUF2AHhbExMoLXu+1zoPgMUsDy43wvs= +github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go index a7700fa1..68c10d20 100644 --- a/transport/tuic/congestion_v2/bbr_sender.go +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -22,6 +22,8 @@ import ( // const ( + minBps = 65536 // 64 kbps + invalidPacketNumber = -1 initialCongestionWindowPackets = 32 @@ -285,10 +287,7 @@ func newBbrSender( maxCongestionWindowWithNetworkParametersAdjusted: initialMaxCongestionWindow, maxDatagramSize: initialMaxDatagramSize, } - b.pacer = NewPacer(func() congestion.ByteCount { - // Pacer wants bytes per second, but Bandwidth is in bits per second. - return congestion.ByteCount(float64(b.bandwidthEstimate()) * b.congestionWindowGain / float64(BytesPerSecond)) - }) + b.pacer = NewPacer(b.bandwidthForPacer) /* if b.tracer != nil { @@ -538,6 +537,17 @@ func (b *bbrSender) bandwidthEstimate() Bandwidth { return b.maxBandwidth.GetBest() } +func (b *bbrSender) bandwidthForPacer() congestion.ByteCount { + bps := congestion.ByteCount(float64(b.bandwidthEstimate()) * b.congestionWindowGain / float64(BytesPerSecond)) + if bps < minBps { + // We need to make sure that the bandwidth value for pacer is never zero, + // otherwise it will go into an edge case where HasPacingBudget = false + // but TimeUntilSend is before, causing the quic-go send loop to go crazy and get stuck. + return minBps + } + return bps +} + // Returns the current estimate of the RTT of the connection. Outside of the // edge cases, this is minimum RTT. func (b *bbrSender) getMinRtt() time.Duration { diff --git a/transport/tuic/congestion_v2/pacer.go b/transport/tuic/congestion_v2/pacer.go index ba4ca138..ecaf3d11 100644 --- a/transport/tuic/congestion_v2/pacer.go +++ b/transport/tuic/congestion_v2/pacer.go @@ -43,6 +43,9 @@ func (p *Pacer) Budget(now time.Time) congestion.ByteCount { return p.maxBurstSize() } budget := p.budgetAtLastSent + (p.getBandwidth()*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9 + if budget < 0 { // protect against overflows + budget = congestion.ByteCount(1<<62 - 1) + } return Min(p.maxBurstSize(), budget) } From ae557c30d3805ca8f58d9c3301e8c9321d5218c4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 8 Oct 2023 13:15:17 +0800 Subject: [PATCH 022/192] fix: quic-go min MTU --- go.mod | 10 ++++---- go.sum | 15 ++++++------ transport/hysteria/congestion/brutal.go | 31 ++++++++++++------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 171fec55..188f00ea 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838 - github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 + github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0 + github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c @@ -32,7 +32,7 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.12 + github.com/sagernet/sing v0.2.13 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -45,11 +45,11 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.3 - golang.org/x/crypto v0.13.0 + golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/net v0.15.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.12.0 + golang.org/x/sys v0.13.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 diff --git a/go.sum b/go.sum index aa6ff01b..84b186c1 100644 --- a/go.sum +++ b/go.sum @@ -97,12 +97,12 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838 h1:VqiDBQY+MB7vmUF2AHhbExMoLXu+1zoPgMUsDy43wvs= -github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0 h1:zUNzLFzYAHti3LCSMyM1PILsGovf1QYdWpzFhrdQovA= +github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= +github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= +github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= @@ -213,8 +213,8 @@ go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= 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.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -244,8 +244,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 88bf6f34..601949de 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -8,11 +8,13 @@ import ( const ( initMaxDatagramSize = 1252 - pktInfoSlotCount = 4 + pktInfoSlotCount = 5 // slot index is based on seconds, so this is basically how many seconds we sample minSampleCount = 50 minAckRate = 0.8 ) +var _ congestion.CongestionControlEx = &BrutalSender{} + type BrutalSender struct { rttStats congestion.RTTStatsProvider bps congestion.ByteCount @@ -72,30 +74,25 @@ func (b *BrutalSender) OnPacketSent(sentTime time.Time, bytesInFlight congestion func (b *BrutalSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, eventTime time.Time) { - currentTimestamp := eventTime.Unix() - slot := currentTimestamp % pktInfoSlotCount - if b.pktInfoSlots[slot].Timestamp == currentTimestamp { - b.pktInfoSlots[slot].AckCount++ - } else { - // uninitialized slot or too old, reset - b.pktInfoSlots[slot].Timestamp = currentTimestamp - b.pktInfoSlots[slot].AckCount = 1 - b.pktInfoSlots[slot].LossCount = 0 - } - b.updateAckRate(currentTimestamp) + // Stub } func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { - currentTimestamp := time.Now().Unix() + // Stub +} + +func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + currentTimestamp := eventTime.Unix() slot := currentTimestamp % pktInfoSlotCount if b.pktInfoSlots[slot].Timestamp == currentTimestamp { - b.pktInfoSlots[slot].LossCount++ + b.pktInfoSlots[slot].LossCount += uint64(len(lostPackets)) + b.pktInfoSlots[slot].AckCount += uint64(len(ackedPackets)) } else { // uninitialized slot or too old, reset b.pktInfoSlots[slot].Timestamp = currentTimestamp - b.pktInfoSlots[slot].AckCount = 0 - b.pktInfoSlots[slot].LossCount = 1 + b.pktInfoSlots[slot].AckCount = uint64(len(ackedPackets)) + b.pktInfoSlots[slot].LossCount = uint64(len(lostPackets)) } b.updateAckRate(currentTimestamp) } @@ -117,10 +114,12 @@ func (b *BrutalSender) updateAckRate(currentTimestamp int64) { } if ackCount+lossCount < minSampleCount { b.ackRate = 1 + return } rate := float64(ackCount) / float64(ackCount+lossCount) if rate < minAckRate { b.ackRate = minAckRate + return } b.ackRate = rate } From 7ed25ddc7494086e00760ef516f658c1b6a4e36d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 10 Oct 2023 16:34:33 +0800 Subject: [PATCH 023/192] chore: better atomic using --- adapter/adapter.go | 4 ++-- adapter/outboundgroup/groupbase.go | 2 +- adapter/provider/healthcheck.go | 21 +++++++++--------- common/atomic/type.go | 35 ++++++++++++------------------ common/atomic/value.go | 5 ++--- dns/client.go | 6 ++--- dns/resolver.go | 2 +- transport/gun/gun.go | 2 +- tunnel/statistic/manager.go | 12 +++++----- tunnel/statistic/tracker.go | 16 +++++++------- 10 files changed, 48 insertions(+), 57 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index e9ce59bb..62941e6d 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -30,13 +30,13 @@ const ( type extraProxyState struct { history *queue.Queue[C.DelayHistory] - alive *atomic.Bool + alive atomic.Bool } type Proxy struct { C.ProxyAdapter history *queue.Queue[C.DelayHistory] - alive *atomic.Bool + alive atomic.Bool url string extra *xsync.MapOf[string, *extraProxyState] } diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 66776bf5..22dd407b 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -28,7 +28,7 @@ type GroupBase struct { failedTestMux sync.Mutex failedTimes int failedTime time.Time - failedTesting *atomic.Bool + failedTesting atomic.Bool proxies [][]C.Proxy versions []atomic.Uint32 } diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 35327b1c..feb972ab 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -34,12 +34,12 @@ type HealthCheck struct { url string extra map[string]*extraOption mu sync.Mutex - started *atomic.Bool + started atomic.Bool proxies []C.Proxy - interval uint + interval time.Duration lazy bool expectedStatus utils.IntRanges[uint16] - lastTouch *atomic.Int64 + lastTouch atomic.TypedValue[time.Time] done chan struct{} singleDo *singledo.Single[struct{}] } @@ -50,13 +50,14 @@ func (hc *HealthCheck) process() { return } - ticker := time.NewTicker(time.Duration(hc.interval) * time.Second) + ticker := time.NewTicker(hc.interval) hc.start() for { select { case <-ticker.C: - now := time.Now().Unix() - if !hc.lazy || now-hc.lastTouch.Load() < int64(hc.interval) { + lastTouch := hc.lastTouch.Load() + since := time.Since(lastTouch) + if !hc.lazy || since < hc.interval { hc.check() } else { log.Debugln("Skip once health check because we are lazy") @@ -85,7 +86,7 @@ func (hc *HealthCheck) registerHealthCheckTask(url string, expectedStatus utils. // if the provider has not set up health checks, then modify it to be the same as the group's interval if hc.interval == 0 { - hc.interval = interval + hc.interval = time.Duration(interval) * time.Second } if hc.extra == nil { @@ -135,7 +136,7 @@ func (hc *HealthCheck) auto() bool { } func (hc *HealthCheck) touch() { - hc.lastTouch.Store(time.Now().Unix()) + hc.lastTouch.Store(time.Now()) } func (hc *HealthCheck) start() { @@ -228,11 +229,9 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, exp proxies: proxies, url: url, extra: map[string]*extraOption{}, - started: atomic.NewBool(false), - interval: interval, + interval: time.Duration(interval) * time.Second, lazy: lazy, expectedStatus: expectedStatus, - lastTouch: atomic.NewInt64(0), done: make(chan struct{}, 1), singleDo: singledo.NewSingle[struct{}](time.Second), } diff --git a/common/atomic/type.go b/common/atomic/type.go index f1549235..71695c63 100644 --- a/common/atomic/type.go +++ b/common/atomic/type.go @@ -11,10 +11,9 @@ type Bool struct { atomic.Bool } -func NewBool(val bool) *Bool { - i := &Bool{} +func NewBool(val bool) (i Bool) { i.Store(val) - return i + return } func (i *Bool) MarshalJSON() ([]byte, error) { @@ -39,12 +38,11 @@ type Pointer[T any] struct { atomic.Pointer[T] } -func NewPointer[T any](v *T) *Pointer[T] { - var p Pointer[T] +func NewPointer[T any](v *T) (p Pointer[T]) { if v != nil { p.Store(v) } - return &p + return } func (p *Pointer[T]) MarshalJSON() ([]byte, error) { @@ -68,10 +66,9 @@ type Int32 struct { atomic.Int32 } -func NewInt32(val int32) *Int32 { - i := &Int32{} +func NewInt32(val int32) (i Int32) { i.Store(val) - return i + return } func (i *Int32) MarshalJSON() ([]byte, error) { @@ -96,10 +93,9 @@ type Int64 struct { atomic.Int64 } -func NewInt64(val int64) *Int64 { - i := &Int64{} +func NewInt64(val int64) (i Int64) { i.Store(val) - return i + return } func (i *Int64) MarshalJSON() ([]byte, error) { @@ -124,10 +120,9 @@ type Uint32 struct { atomic.Uint32 } -func NewUint32(val uint32) *Uint32 { - i := &Uint32{} +func NewUint32(val uint32) (i Uint32) { i.Store(val) - return i + return } func (i *Uint32) MarshalJSON() ([]byte, error) { @@ -152,10 +147,9 @@ type Uint64 struct { atomic.Uint64 } -func NewUint64(val uint64) *Uint64 { - i := &Uint64{} +func NewUint64(val uint64) (i Uint64) { i.Store(val) - return i + return } func (i *Uint64) MarshalJSON() ([]byte, error) { @@ -180,10 +174,9 @@ type Uintptr struct { atomic.Uintptr } -func NewUintptr(val uintptr) *Uintptr { - i := &Uintptr{} +func NewUintptr(val uintptr) (i Uintptr) { i.Store(val) - return i + return } func (i *Uintptr) MarshalJSON() ([]byte, error) { diff --git a/common/atomic/value.go b/common/atomic/value.go index ca0eb631..95733533 100644 --- a/common/atomic/value.go +++ b/common/atomic/value.go @@ -51,8 +51,7 @@ func (t *TypedValue[T]) UnmarshalJSON(b []byte) error { return nil } -func NewTypedValue[T any](t T) *TypedValue[T] { - v := &TypedValue[T]{} +func NewTypedValue[T any](t T) (v TypedValue[T]) { v.Store(t) - return v + return } diff --git a/dns/client.go b/dns/client.go index 56f55668..89f083aa 100644 --- a/dns/client.go +++ b/dns/client.go @@ -23,7 +23,7 @@ type client struct { r *Resolver port string host string - iface *atomic.TypedValue[string] + iface atomic.TypedValue[string] proxyAdapter C.ProxyAdapter proxyName string addr string @@ -77,8 +77,8 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) network = "tcp" } - options := []dialer.Option{} - if c.iface != nil && c.iface.Load() != "" { + var options []dialer.Option + if c.iface.Load() != "" { options = append(options, dialer.WithInterface(c.iface.Load())) } diff --git a/dns/resolver.go b/dns/resolver.go index 3a530918..2c429358 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -398,7 +398,7 @@ func (r *Resolver) Invalid() bool { type NameServer struct { Net string Addr string - Interface *atomic.TypedValue[string] + Interface atomic.TypedValue[string] ProxyAdapter C.ProxyAdapter ProxyName string Params map[string]string diff --git a/transport/gun/gun.go b/transport/gun/gun.go index e98f7fb5..cfe8aa3d 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -43,7 +43,7 @@ type Conn struct { transport *TransportWrap writer *io.PipeWriter once sync.Once - close *atomic.Bool + close atomic.Bool err error remain int br *bufio.Reader diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 19ce58d9..4797829f 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -29,12 +29,12 @@ func init() { type Manager struct { connections *xsync.MapOf[string, Tracker] - uploadTemp *atomic.Int64 - downloadTemp *atomic.Int64 - uploadBlip *atomic.Int64 - downloadBlip *atomic.Int64 - uploadTotal *atomic.Int64 - downloadTotal *atomic.Int64 + uploadTemp atomic.Int64 + downloadTemp atomic.Int64 + uploadBlip atomic.Int64 + downloadBlip atomic.Int64 + uploadTotal atomic.Int64 + downloadTotal atomic.Int64 process *process.Process memory uint64 } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index f0f868de..bc2dbd5c 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -23,14 +23,14 @@ type Tracker interface { } type TrackerInfo struct { - UUID uuid.UUID `json:"id"` - Metadata *C.Metadata `json:"metadata"` - UploadTotal *atomic.Int64 `json:"upload"` - DownloadTotal *atomic.Int64 `json:"download"` - Start time.Time `json:"start"` - Chain C.Chain `json:"chains"` - Rule string `json:"rule"` - RulePayload string `json:"rulePayload"` + UUID uuid.UUID `json:"id"` + Metadata *C.Metadata `json:"metadata"` + UploadTotal atomic.Int64 `json:"upload"` + DownloadTotal atomic.Int64 `json:"download"` + Start time.Time `json:"start"` + Chain C.Chain `json:"chains"` + Rule string `json:"rule"` + RulePayload string `json:"rulePayload"` } type tcpTracker struct { From 6bcd91a801cdc0cfbf29632cb9be43520fbed2e4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 10 Oct 2023 19:43:26 +0800 Subject: [PATCH 024/192] feat: add `skip-auth-prefixes` --- adapter/inbound/addition.go | 24 +++++++++++++++++++++--- adapter/inbound/auth.go | 27 +++++++++++++++++++++++++++ adapter/inbound/http.go | 9 +-------- adapter/inbound/https.go | 9 +-------- adapter/inbound/packet.go | 14 ++++---------- adapter/inbound/socket.go | 10 +--------- adapter/inbound/util.go | 18 +++++++++++------- config/config.go | 31 +++++++++++++++++-------------- docs/config.yaml | 5 +++++ hub/executor/executor.go | 2 ++ hub/route/configs.go | 7 +++++++ listener/http/proxy.go | 3 +++ listener/socks/tcp.go | 12 ++++++++++-- 13 files changed, 110 insertions(+), 61 deletions(-) create mode 100644 adapter/inbound/auth.go diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 327d00e9..14fc303f 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -38,9 +38,27 @@ func WithSpecialProxy(specialProxy string) Addition { func WithSrcAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if ip, port, err := parseAddr(addr); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port + if addrPort, err := parseAddr(addr); err == nil { + metadata.SrcIP = addrPort.Addr() + metadata.SrcPort = addrPort.Port() + } + } +} + +func WithDstAddr(addr net.Addr) Addition { + return func(metadata *C.Metadata) { + if addrPort, err := parseAddr(addr); err == nil { + metadata.DstIP = addrPort.Addr() + metadata.DstPort = addrPort.Port() + } + } +} + +func WithInAddr(addr net.Addr) Addition { + return func(metadata *C.Metadata) { + if addrPort, err := parseAddr(addr); err == nil { + metadata.InIP = addrPort.Addr() + metadata.InPort = addrPort.Port() } } } diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go new file mode 100644 index 00000000..724b5b7a --- /dev/null +++ b/adapter/inbound/auth.go @@ -0,0 +1,27 @@ +package inbound + +import ( + "net" + "net/netip" +) + +var skipAuthPrefixes []netip.Prefix + +func SetSkipAuthPrefixes(prefixes []netip.Prefix) { + skipAuthPrefixes = prefixes +} + +func SkipAuthPrefixes() []netip.Prefix { + return skipAuthPrefixes +} + +func SkipAuthRemoteAddr(addr net.Addr) bool { + if addrPort, err := parseAddr(addr); err == nil { + for _, prefix := range skipAuthPrefixes { + if prefix.Contains(addrPort.Addr()) { + return true + } + } + } + return false +} diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index b1b881ce..93ec2373 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -13,16 +13,9 @@ func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP + additions = append(additions, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(source); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } return context.NewConnContext(conn, metadata) } diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 485e72bb..26f93a45 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -12,16 +12,9 @@ import ( func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) *context.ConnContext { metadata := parseHTTPAddr(request) metadata.Type = C.HTTPS + additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(conn.RemoteAddr()); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } return context.NewConnContext(conn, metadata) } diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index 44e5e1a7..d481ec09 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -21,19 +21,13 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source + additions = append(additions, WithSrcAddr(packet.LocalAddr())) + if p, ok := packet.(C.UDPPacketInAddr); ok { + additions = append(additions, WithInAddr(p.InAddr())) + } for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(packet.LocalAddr()); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if p, ok := packet.(C.UDPPacketInAddr); ok { - if ip, port, err := parseAddr(p.InAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } - } return &PacketAdapter{ packet, diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index d75901f1..5892bebc 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -15,19 +15,11 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = source + additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(conn.RemoteAddr()); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } - return context.NewConnContext(conn, metadata) } diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index 626687c0..32ca9f05 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -63,21 +63,25 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } -func parseAddr(addr net.Addr) (netip.Addr, uint16, error) { +func parseAddr(addr net.Addr) (netip.AddrPort, error) { // Filter when net.Addr interface is nil if addr == nil { - return netip.Addr{}, 0, errors.New("nil addr") + return netip.AddrPort{}, errors.New("nil addr") } if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { - ip, port, err := parseAddr(rawAddr.RawAddr()) - if err == nil { - return ip, port, err + if addrPort, err := parseAddr(rawAddr.RawAddr()); err == nil { + return addrPort, nil + } + } + if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { + if addrPort := addr.AddrPort(); addrPort.IsValid() { + return addrPort, nil } } addrStr := addr.String() host, port, err := net.SplitHostPort(addrStr) if err != nil { - return netip.Addr{}, 0, err + return netip.AddrPort{}, err } var uint16Port uint16 @@ -86,5 +90,5 @@ func parseAddr(addr net.Addr) (netip.Addr, uint16, error) { } ip, err := netip.ParseAddr(host) - return ip, uint16Port, err + return netip.AddrPortFrom(ip, uint16Port), err } diff --git a/config/config.go b/config/config.go index 5ea45a39..dd5ce59a 100644 --- a/config/config.go +++ b/config/config.go @@ -66,20 +66,21 @@ type General struct { // Inbound config type Inbound struct { - Port int `json:"port"` - SocksPort int `json:"socks-port"` - RedirPort int `json:"redir-port"` - TProxyPort int `json:"tproxy-port"` - MixedPort int `json:"mixed-port"` - Tun LC.Tun `json:"tun"` - TuicServer LC.TuicServer `json:"tuic-server"` - ShadowSocksConfig string `json:"ss-config"` - VmessConfig string `json:"vmess-config"` - Authentication []string `json:"authentication"` - AllowLan bool `json:"allow-lan"` - BindAddress string `json:"bind-address"` - InboundTfo bool `json:"inbound-tfo"` - InboundMPTCP bool `json:"inbound-mptcp"` + Port int `json:"port"` + SocksPort int `json:"socks-port"` + RedirPort int `json:"redir-port"` + TProxyPort int `json:"tproxy-port"` + MixedPort int `json:"mixed-port"` + Tun LC.Tun `json:"tun"` + TuicServer LC.TuicServer `json:"tuic-server"` + ShadowSocksConfig string `json:"ss-config"` + VmessConfig string `json:"vmess-config"` + Authentication []string `json:"authentication"` + SkipAuthPrefixes []netip.Prefix `json:"skip-auth-prefixes"` + AllowLan bool `json:"allow-lan"` + BindAddress string `json:"bind-address"` + InboundTfo bool `json:"inbound-tfo"` + InboundMPTCP bool `json:"inbound-mptcp"` } // Controller config @@ -271,6 +272,7 @@ type RawConfig struct { InboundTfo bool `yaml:"inbound-tfo"` InboundMPTCP bool `yaml:"inbound-mptcp"` Authentication []string `yaml:"authentication"` + SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"` AllowLan bool `yaml:"allow-lan"` BindAddress string `yaml:"bind-address"` Mode T.TunnelMode `yaml:"mode"` @@ -620,6 +622,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { ShadowSocksConfig: cfg.ShadowSocksConfig, VmessConfig: cfg.VmessConfig, AllowLan: cfg.AllowLan, + SkipAuthPrefixes: cfg.SkipAuthPrefixes, BindAddress: cfg.BindAddress, InboundTfo: cfg.InboundTfo, InboundMPTCP: cfg.InboundMPTCP, diff --git a/docs/config.yaml b/docs/config.yaml index bfcdc0cd..e829e5db 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -8,6 +8,11 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口 allow-lan: true # 允许局域网连接 bind-address: "*" # 绑定 IP 地址,仅作用于 allow-lan 为 true,'*'表示所有地址 +authentication: # http,socks入口的验证用户名,密码 + - "username:password" +skip-auth-prefixes: # 设置跳过验证的IP段 + - 127.0.0.1/8 + - ::1/128 # find-process-mode has 3 values:always, strict, off # - always, 开启,强制匹配所有进程 diff --git a/hub/executor/executor.go b/hub/executor/executor.go index ebcbac91..87e0e0b1 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -140,6 +140,7 @@ func GetGeneral() *config.General { ShadowSocksConfig: ports.ShadowSocksConfig, VmessConfig: ports.VmessConfig, Authentication: authenticator, + SkipAuthPrefixes: inbound.SkipAuthPrefixes(), AllowLan: listener.AllowLan(), BindAddress: listener.BindAddress(), }, @@ -164,6 +165,7 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList allowLan := general.AllowLan listener.SetAllowLan(allowLan) + inbound.SetSkipAuthPrefixes(general.SkipAuthPrefixes) bindAddress := general.BindAddress listener.SetBindAddress(bindAddress) diff --git a/hub/route/configs.go b/hub/route/configs.go index 1f29de0c..6edbf979 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -2,9 +2,11 @@ package route import ( "net/http" + "net/netip" "path/filepath" "sync" + "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/config" @@ -47,6 +49,7 @@ type configSchema struct { TcptunConfig *string `json:"tcptun-config"` UdptunConfig *string `json:"udptun-config"` AllowLan *bool `json:"allow-lan"` + SkipAuthPrefixes *[]netip.Prefix `json:"skip-auth-prefixes"` BindAddress *string `json:"bind-address"` Mode *tunnel.TunnelMode `json:"mode"` LogLevel *log.LogLevel `json:"log-level"` @@ -231,6 +234,10 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { P.SetAllowLan(*general.AllowLan) } + if general.SkipAuthPrefixes != nil { + inbound.SetSkipAuthPrefixes(*general.SkipAuthPrefixes) + } + if general.BindAddress != nil { P.SetBindAddress(*general.BindAddress) } diff --git a/listener/http/proxy.go b/listener/http/proxy.go index a267fbad..173bb64a 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -100,6 +100,9 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool] func authenticate(request *http.Request, cache *cache.LruCache[string, bool]) *http.Response { authenticator := authStore.Authenticator() + if inbound.SkipAuthRemoteAddr(N.NewCustomAddr("", request.RemoteAddr, nil)) { + authenticator = nil + } if authenticator != nil { credential := parseBasicProxyAuthorization(request) if credential == "" { diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index 89b23562..9448f269 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -86,7 +86,11 @@ func handleSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) } func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { - addr, _, err := socks4.ServerHandshake(conn, authStore.Authenticator()) + authenticator := authStore.Authenticator() + if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) { + authenticator = nil + } + addr, _, err := socks4.ServerHandshake(conn, authenticator) if err != nil { conn.Close() return @@ -95,7 +99,11 @@ func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) } func HandleSocks5(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { - target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator()) + authenticator := authStore.Authenticator() + if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) { + authenticator = nil + } + target, command, err := socks5.ServerHandshake(conn, authenticator) if err != nil { conn.Close() return From 1cf9a55e3ee48e57b4feeb12fc8448b55520fd0c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 10 Oct 2023 19:49:16 +0800 Subject: [PATCH 025/192] chore: code cleanup --- config/config.go | 34 +++++++++---------- hub/route/configs.go | 30 ++++++++--------- listener/config/tun.go | 67 ++++--------------------------------- listener/inbound/tun.go | 8 ++--- listener/listener.go | 8 ++--- listener/sing_tun/server.go | 12 +++---- 6 files changed, 53 insertions(+), 106 deletions(-) diff --git a/config/config.go b/config/config.go index dd5ce59a..97a193a1 100644 --- a/config/config.go +++ b/config/config.go @@ -229,21 +229,21 @@ type RawTun struct { RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` - //Inet4Address []LC.ListenPrefix `yaml:"inet4-address" json:"inet4_address,omitempty"` - Inet6Address []LC.ListenPrefix `yaml:"inet6-address" json:"inet6_address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - Inet4RouteAddress []LC.ListenPrefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []LC.ListenPrefix `yaml:"inet6_route_address" json:"inet6_route_address,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6_route_address" json:"inet6_route_address,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } type RawTuicServer struct { @@ -388,7 +388,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query AutoRoute: true, AutoDetectInterface: true, - Inet6Address: []LC.ListenPrefix{LC.ListenPrefix(netip.MustParsePrefix("fdfe:dcba:9876::1/126"))}, + Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")}, }, TuicServer: RawTuicServer{ Enable: false, @@ -1364,7 +1364,7 @@ func parseTun(rawTun RawTun, general *General) error { RedirectToTun: rawTun.RedirectToTun, MTU: rawTun.MTU, - Inet4Address: []LC.ListenPrefix{LC.ListenPrefix(tunAddressPrefix)}, + Inet4Address: []netip.Prefix{tunAddressPrefix}, Inet6Address: rawTun.Inet6Address, StrictRoute: rawTun.StrictRoute, Inet4RouteAddress: rawTun.Inet4RouteAddress, diff --git a/hub/route/configs.go b/hub/route/configs.go index 6edbf979..cb500157 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -69,21 +69,21 @@ type tunSchema struct { //RedirectToTun []string `yaml:"-" json:"-"` MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` - //Inet4Address *[]config.ListenPrefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address *[]LC.ListenPrefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress *[]LC.ListenPrefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress *[]LC.ListenPrefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` - IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` + //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` + Inet4RouteAddress *[]netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` } type tuicServerSchema struct { diff --git a/listener/config/tun.go b/listener/config/tun.go index 50f5cf7d..06e92188 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -1,72 +1,19 @@ package config import ( - "encoding/json" "net/netip" C "github.com/Dreamacro/clash/constant" - - "gopkg.in/yaml.v3" ) -type ListenPrefix netip.Prefix - -func (p ListenPrefix) MarshalJSON() ([]byte, error) { - prefix := netip.Prefix(p) - if !prefix.IsValid() { - return json.Marshal(nil) - } - return json.Marshal(prefix.String()) -} - -func (p ListenPrefix) MarshalYAML() (interface{}, error) { - prefix := netip.Prefix(p) - if !prefix.IsValid() { - return nil, nil - } - return prefix.String(), nil -} - -func (p *ListenPrefix) UnmarshalJSON(bytes []byte) error { - var value string - err := json.Unmarshal(bytes, &value) - if err != nil { - return err - } - prefix, err := netip.ParsePrefix(value) - if err != nil { - return err - } - *p = ListenPrefix(prefix) - return nil -} - -func (p *ListenPrefix) UnmarshalYAML(node *yaml.Node) error { - var value string - err := node.Decode(&value) - if err != nil { - return err - } - prefix, err := netip.ParsePrefix(value) - if err != nil { - return err - } - *p = ListenPrefix(prefix) - return nil -} - -func (p ListenPrefix) Build() netip.Prefix { - return netip.Prefix(p) -} - -func StringSliceToListenPrefixSlice(ss []string) ([]ListenPrefix, error) { - lps := make([]ListenPrefix, 0, len(ss)) +func StringSliceToNetipPrefixSlice(ss []string) ([]netip.Prefix, error) { + lps := make([]netip.Prefix, 0, len(ss)) for _, s := range ss { prefix, err := netip.ParsePrefix(s) if err != nil { return nil, err } - lps = append(lps, ListenPrefix(prefix)) + lps = append(lps, prefix) } return lps, nil } @@ -81,11 +28,11 @@ type Tun struct { RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` - Inet4Address []ListenPrefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address []ListenPrefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress []ListenPrefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress []ListenPrefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index 3151e6b0..9ba7ae87 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -56,19 +56,19 @@ func NewTun(options *TunOption) (*Tun, error) { if !exist { return nil, errors.New("invalid tun stack") } - inet4Address, err := LC.StringSliceToListenPrefixSlice(options.Inet4Address) + inet4Address, err := LC.StringSliceToNetipPrefixSlice(options.Inet4Address) if err != nil { return nil, err } - inet6Address, err := LC.StringSliceToListenPrefixSlice(options.Inet6Address) + inet6Address, err := LC.StringSliceToNetipPrefixSlice(options.Inet6Address) if err != nil { return nil, err } - inet4RouteAddress, err := LC.StringSliceToListenPrefixSlice(options.Inet4RouteAddress) + inet4RouteAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet4RouteAddress) if err != nil { return nil, err } - inet6RouteAddress, err := LC.StringSliceToListenPrefixSlice(options.Inet6RouteAddress) + inet6RouteAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet6RouteAddress) if err != nil { return nil, err } diff --git a/listener/listener.go b/listener/listener.go index afbcf14c..ad3b2351 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -834,19 +834,19 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { }) sort.Slice(tunConf.Inet4Address, func(i, j int) bool { - return tunConf.Inet4Address[i].Build().String() < tunConf.Inet4Address[j].Build().String() + return tunConf.Inet4Address[i].String() < tunConf.Inet4Address[j].String() }) sort.Slice(tunConf.Inet6Address, func(i, j int) bool { - return tunConf.Inet6Address[i].Build().String() < tunConf.Inet6Address[j].Build().String() + return tunConf.Inet6Address[i].String() < tunConf.Inet6Address[j].String() }) sort.Slice(tunConf.Inet4RouteAddress, func(i, j int) bool { - return tunConf.Inet4RouteAddress[i].Build().String() < tunConf.Inet4RouteAddress[j].Build().String() + return tunConf.Inet4RouteAddress[i].String() < tunConf.Inet4RouteAddress[j].String() }) sort.Slice(tunConf.Inet6RouteAddress, func(i, j int) bool { - return tunConf.Inet6RouteAddress[i].Build().String() < tunConf.Inet6RouteAddress[j].Build().String() + return tunConf.Inet6RouteAddress[i].String() < tunConf.Inet6RouteAddress[j].String() }) sort.Slice(tunConf.IncludeUID, func(i, j int) bool { diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 4ca6fc30..122e9af3 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -142,11 +142,11 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis dnsAdds = append(dnsAdds, addrPort) } for _, a := range options.Inet4Address { - addrPort := netip.AddrPortFrom(a.Build().Addr().Next(), 53) + addrPort := netip.AddrPortFrom(a.Addr().Next(), 53) dnsAdds = append(dnsAdds, addrPort) } for _, a := range options.Inet6Address { - addrPort := netip.AddrPortFrom(a.Build().Addr().Next(), 53) + addrPort := netip.AddrPortFrom(a.Addr().Next(), 53) dnsAdds = append(dnsAdds, addrPort) } @@ -201,12 +201,12 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis tunOptions := tun.Options{ Name: tunName, MTU: tunMTU, - Inet4Address: common.Map(options.Inet4Address, LC.ListenPrefix.Build), - Inet6Address: common.Map(options.Inet6Address, LC.ListenPrefix.Build), + Inet4Address: options.Inet4Address, + Inet6Address: options.Inet6Address, AutoRoute: options.AutoRoute, StrictRoute: options.StrictRoute, - Inet4RouteAddress: common.Map(options.Inet4RouteAddress, LC.ListenPrefix.Build), - Inet6RouteAddress: common.Map(options.Inet6RouteAddress, LC.ListenPrefix.Build), + Inet4RouteAddress: options.Inet4RouteAddress, + Inet6RouteAddress: options.Inet6RouteAddress, IncludeUID: includeUID, ExcludeUID: excludeUID, IncludeAndroidUser: options.IncludeAndroidUser, From 270a080b553cadeb0d9f231f8565acae3be8edc9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 10:55:12 +0800 Subject: [PATCH 026/192] fix: sing listener panic --- adapter/inbound/http.go | 5 ++-- adapter/inbound/https.go | 5 ++-- adapter/inbound/packet.go | 18 ++------------ adapter/inbound/socket.go | 9 ++++--- constant/adapters.go | 17 ++++++++++++++ constant/tunnel.go | 6 +++-- listener/inner/tcp.go | 3 +-- listener/shadowsocks/udp.go | 2 +- listener/sing/context.go | 9 ++++++- listener/sing/sing.go | 47 ++++++++++++++++++++++++------------- listener/tuic/server.go | 9 ++++--- listener/tunnel/tcp.go | 6 ++--- listener/tunnel/udp.go | 8 +++---- tunnel/tunnel.go | 14 ++++++----- 14 files changed, 91 insertions(+), 67 deletions(-) diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 93ec2373..15376606 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -4,12 +4,11 @@ import ( "net" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" "github.com/Dreamacro/clash/transport/socks5" ) // NewHTTP receive normal http request and return HTTPContext -func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Addition) *context.ConnContext { +func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP @@ -17,5 +16,5 @@ func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Ad for _, addition := range additions { addition.Apply(metadata) } - return context.NewConnContext(conn, metadata) + return conn, metadata } diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 26f93a45..7353fe59 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -5,16 +5,15 @@ import ( "net/http" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" ) // NewHTTPS receive CONNECT request and return ConnContext -func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) *context.ConnContext { +func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseHTTPAddr(request) metadata.Type = C.HTTPS additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - return context.NewConnContext(conn, metadata) + return conn, metadata } diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index d481ec09..f211f7a5 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -5,19 +5,8 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -// PacketAdapter is a UDP Packet adapter for socks/redir/tun -type PacketAdapter struct { - C.UDPPacket - metadata *C.Metadata -} - -// Metadata returns destination metadata -func (s *PacketAdapter) Metadata() *C.Metadata { - return s.metadata -} - // NewPacket is PacketAdapter generator -func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions ...Addition) C.PacketAdapter { +func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions ...Addition) (C.UDPPacket, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source @@ -29,8 +18,5 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions addition.Apply(metadata) } - return &PacketAdapter{ - packet, - metadata, - } + return packet, metadata } diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 5892bebc..65dbe0a2 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -6,12 +6,11 @@ import ( "strconv" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" "github.com/Dreamacro/clash/transport/socks5" ) // NewSocket receive TCP inbound and return ConnContext -func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Addition) *context.ConnContext { +func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = source @@ -20,10 +19,10 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad addition.Apply(metadata) } - return context.NewConnContext(conn, metadata) + return conn, metadata } -func NewInner(conn net.Conn, address string) *context.ConnContext { +func NewInner(conn net.Conn, address string) (net.Conn, *C.Metadata) { metadata := &C.Metadata{} metadata.NetWork = C.TCP metadata.Type = C.INNER @@ -40,5 +39,5 @@ func NewInner(conn net.Conn, address string) *context.ConnContext { } } - return context.NewConnContext(conn, metadata) + return conn, metadata } diff --git a/constant/adapters.go b/constant/adapters.go index 33b9a44f..ad50a8ab 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -252,6 +252,23 @@ type PacketAdapter interface { Metadata() *Metadata } +type packetAdapter struct { + UDPPacket + metadata *Metadata +} + +// Metadata returns destination metadata +func (s *packetAdapter) Metadata() *Metadata { + return s.metadata +} + +func NewPacketAdapter(packet UDPPacket, metadata *Metadata) PacketAdapter { + return &packetAdapter{ + packet, + metadata, + } +} + type WriteBack interface { WriteBack(b []byte, addr net.Addr) (n int, err error) } diff --git a/constant/tunnel.go b/constant/tunnel.go index 39f8936a..7c9d08e2 100644 --- a/constant/tunnel.go +++ b/constant/tunnel.go @@ -1,10 +1,12 @@ package constant +import "net" + type Tunnel interface { // HandleTCPConn will handle a tcp connection blocking - HandleTCPConn(connCtx ConnContext) + HandleTCPConn(conn net.Conn, metadata *Metadata) // HandleUDPPacket will handle a udp packet nonblocking - HandleUDPPacket(packet PacketAdapter) + HandleUDPPacket(packet UDPPacket, metadata *Metadata) // NatTable return nat table NatTable() NatTable } diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index 4a54a82f..cbd27cd6 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -20,7 +20,6 @@ func HandleTcp(address string) (conn net.Conn, err error) { } // executor Parsed conn1, conn2 := net.Pipe() - context := inbound.NewInner(conn2, address) - go tunnel.HandleTCPConn(context) + go tunnel.HandleTCPConn(inbound.NewInner(conn2, address)) return conn1, nil } diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index cc055853..53f5549a 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -67,7 +67,7 @@ func handleSocksUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, put func(), } return } - target := socks5.ParseAddr(tgtAddr.String()) + target := tgtAddr payload := buf[len(tgtAddr):] packet := &packet{ diff --git a/listener/sing/context.go b/listener/sing/context.go index a500e4a4..32b2a161 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -26,7 +26,7 @@ func getAdditions(ctx context.Context) []inbound.Addition { return nil } -func combineAdditions(ctx context.Context, additions []inbound.Addition) []inbound.Addition { +func combineAdditions(ctx context.Context, additions []inbound.Addition, extraAdditions ...inbound.Addition) []inbound.Addition { additionsCloned := false if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { additions = slices.Clone(additions) @@ -40,5 +40,12 @@ func combineAdditions(ctx context.Context, additions []inbound.Addition) []inbou } additions = append(additions, inbound.WithInUser(user)) } + if len(extraAdditions) > 0 { + if !additionsCloned { + additions = slices.Clone(additions) + additionsCloned = true + } + additions = append(additions, extraAdditions...) + } return additions } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index a9bee564..301dc783 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -12,7 +12,6 @@ import ( N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" vmess "github.com/metacubex/sing-vmess" mux "github.com/sagernet/sing-mux" @@ -85,15 +84,26 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta if h.IsSpecialFqdn(metadata.Destination.Fqdn) { return h.ParseSpecialFqdn(ctx, conn, metadata) } - target := socks5.ParseAddr(metadata.Destination.String()) if deadline.NeedAdditionalReadDeadline(conn) { conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline } - connCtx := inbound.NewSocket(target, conn, h.Type, combineAdditions(ctx, h.Additions)...) - inbound.WithSrcAddr(metadata.Source.TCPAddr()).Apply(connCtx.Metadata()) // set srcAddr from sing's metadata - h.Tunnel.HandleTCPConn(connCtx) // this goroutine must exit after conn unused + cMetadata := &C.Metadata{ + NetWork: C.TCP, + Type: h.Type, + Host: metadata.Destination.Fqdn, + DstIP: metadata.Destination.Addr, + DstPort: metadata.Destination.Port, + SrcIP: metadata.Source.Addr, + SrcPort: metadata.Source.Port, + } + additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + for _, addition := range additions { + addition.Apply(cMetadata) + } + + h.Tunnel.HandleTCPConn(conn, cMetadata) // this goroutine must exit after conn unused return nil } @@ -138,8 +148,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } return err } - target := socks5.ParseAddr(dest.String()) - packet := &packet{ + cPacket := &packet{ conn: &conn2, mutex: &mutex, rAddr: metadata.Source.UDPAddr(), @@ -147,7 +156,21 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. buff: buff, } - h.Tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...)) + cMetadata := &C.Metadata{ + NetWork: C.UDP, + Type: h.Type, + Host: dest.Fqdn, + DstIP: dest.Addr, + DstPort: dest.Port, + SrcIP: metadata.Source.Addr, + SrcPort: metadata.Source.Port, + } + additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + for _, addition := range additions { + addition.Apply(cMetadata) + } + + h.Tunnel.HandleUDPPacket(cPacket, cMetadata) } return nil } @@ -215,11 +238,3 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.lAddr } - -func (c *packet) SetNatTable(natTable C.NatTable) { - // no need -} - -func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { - // no need -} diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 70cf4a01..544f1328 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -94,19 +94,18 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( newAdditions = slices.Clone(additions) newAdditions = append(newAdditions, _additions...) } - connCtx := inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) - metadata := sing.ConvertMetadata(connCtx.Metadata()) - if h.IsSpecialFqdn(metadata.Destination.Fqdn) { + conn, metadata := inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) + if h.IsSpecialFqdn(metadata.Host) { go func() { // ParseSpecialFqdn will block, so open a new goroutine _ = h.ParseSpecialFqdn( sing.WithAdditions(context.Background(), newAdditions...), conn, - metadata, + sing.ConvertMetadata(metadata), ) }() return nil } - go tunnel.HandleTCPConn(connCtx) + go tunnel.HandleTCPConn(conn, metadata) return nil } handleUdpFn := func(addr socks5.Addr, packet C.UDPPacket, _additions ...inbound.Addition) error { diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index 8cc527fb..dd2059db 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -36,9 +36,9 @@ func (l *Listener) Close() error { func (l *Listener) handleTCP(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) - ctx := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) - ctx.Metadata().SpecialProxy = l.proxy - tunnel.HandleTCPConn(ctx) + conn, metadata := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) + metadata.SpecialProxy = l.proxy + tunnel.HandleTCPConn(conn, metadata) } func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index c2f1dcc3..38b779c4 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -70,13 +70,13 @@ func NewUDP(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Ad } func (l *PacketConn) handleUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, addr net.Addr, additions ...inbound.Addition) { - packet := &packet{ + cPacket := &packet{ pc: pc, rAddr: addr, payload: buf, } - ctx := inbound.NewPacket(l.target, packet, C.TUNNEL, additions...) - ctx.Metadata().SpecialProxy = l.proxy - tunnel.HandleUDPPacket(ctx) + packet, metadata := inbound.NewPacket(l.target, cPacket, C.TUNNEL, additions...) + metadata.SpecialProxy = l.proxy + tunnel.HandleUDPPacket(packet, metadata) } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 1e73a833..13bf6d8c 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -53,13 +53,15 @@ type tunnel struct{} var Tunnel C.Tunnel = tunnel{} -func (t tunnel) HandleTCPConn(connCtx C.ConnContext) { +func (t tunnel) HandleTCPConn(conn net.Conn, metadata *C.Metadata) { + connCtx := icontext.NewConnContext(conn, metadata) handleTCPConn(connCtx) } -func (t tunnel) HandleUDPPacket(packet C.PacketAdapter) { +func (t tunnel) HandleUDPPacket(packet C.UDPPacket, metadata *C.Metadata) { + packetAdapter := C.NewPacketAdapter(packet, metadata) select { - case udpQueue <- packet: + case udpQueue <- packetAdapter: default: } } @@ -274,7 +276,7 @@ func preHandleMetadata(metadata *C.Metadata) error { return nil } -func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) { +func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) { if metadata.SpecialProxy != "" { var exist bool proxy, exist = proxies[metadata.SpecialProxy] @@ -369,7 +371,7 @@ func handleUDPConn(packet C.PacketAdapter) { }() pCtx := icontext.NewPacketConnContext(metadata) - proxy, rule, err := resolveMetadata(pCtx, metadata) + proxy, rule, err := resolveMetadata(metadata) if err != nil { log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) return @@ -477,7 +479,7 @@ func handleTCPConn(connCtx C.ConnContext) { }() } - proxy, rule, err := resolveMetadata(connCtx, metadata) + proxy, rule, err := resolveMetadata(metadata) if err != nil { log.Warnln("[Metadata] parse failed: %s", err.Error()) return From 9a16eb289565406c3b2a4bd6ec933b920da5037e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 11:01:17 +0800 Subject: [PATCH 027/192] fix: BBR memory leak from: https://github.com/apernet/hysteria/commit/7c46e845a6e4d1355c1a4515fb8e94ebec2c89c3 --- transport/tuic/congestion_v2/bbr_sender.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go index 68c10d20..084f85b1 100644 --- a/transport/tuic/congestion_v2/bbr_sender.go +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -484,10 +484,19 @@ func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, even b.calculateRecoveryWindow(bytesAcked, bytesLost) // Cleanup internal state. - if len(lostPackets) != 0 { - lastLostPacket := lostPackets[len(lostPackets)-1].PacketNumber - b.sampler.RemoveObsoletePackets(lastLostPacket) + // This is where we clean up obsolete (acked or lost) packets from the bandwidth sampler. + // The "least unacked" should actually be FirstOutstanding, but since we are not passing + // that through OnCongestionEventEx, we will only do an estimate using acked/lost packets + // for now. Because of fast retransmission, they should differ by no more than 2 packets. + // (this is controlled by packetThreshold in quic-go's sentPacketHandler) + var leastUnacked congestion.PacketNumber + if len(ackedPackets) != 0 { + leastUnacked = ackedPackets[len(ackedPackets)-1].PacketNumber - 2 + } else { + leastUnacked = lostPackets[len(lostPackets)-1].PacketNumber + 1 } + b.sampler.RemoveObsoletePackets(leastUnacked) + if isRoundStart { b.numLossEventsInRound = 0 b.bytesLostInRound = 0 From 4636499439d7d549b4ddeb178f071508d9ff96e2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 13:01:14 +0800 Subject: [PATCH 028/192] chore: support reject proxy type --- adapter/inbound/socket.go | 22 ---------------------- adapter/outbound/reject.go | 14 ++++++++++++++ adapter/parser.go | 7 +++++++ listener/inner/tcp.go | 22 ++++++++++++++++++++-- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 65dbe0a2..dbe1712d 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -2,8 +2,6 @@ package inbound import ( "net" - "net/netip" - "strconv" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" @@ -21,23 +19,3 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad return conn, metadata } - -func NewInner(conn net.Conn, address string) (net.Conn, *C.Metadata) { - metadata := &C.Metadata{} - metadata.NetWork = C.TCP - metadata.Type = C.INNER - metadata.DNSMode = C.DNSNormal - metadata.Process = C.ClashName - if h, port, err := net.SplitHostPort(address); err == nil { - if port, err := strconv.ParseUint(port, 10, 16); err == nil { - metadata.DstPort = uint16(port) - } - if ip, err := netip.ParseAddr(h); err == nil { - metadata.DstIP = ip - } else { - metadata.Host = h - } - } - - return conn, metadata -} diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index a72dc377..f1de3981 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -15,6 +15,10 @@ type Reject struct { *Base } +type RejectOption struct { + Name string `proxy:"name"` +} + // DialContext implements C.ProxyAdapter func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { return NewConn(nopConn{}, r), nil @@ -25,6 +29,16 @@ func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return newPacketConn(nopPacketConn{}, r), nil } +func NewRejectWithOption(option RejectOption) *Reject { + return &Reject{ + Base: &Base{ + name: option.Name, + tp: C.Direct, + udp: true, + }, + } +} + func NewReject() *Reject { return &Reject{ Base: &Base{ diff --git a/adapter/parser.go b/adapter/parser.go index eeb0fd59..43ebfe5f 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -120,6 +120,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { break } proxy = outbound.NewDirectWithOption(*directOption) + case "reject": + rejectOption := &outbound.RejectOption{} + err = decoder.Decode(mapping, rejectOption) + if err != nil { + break + } + proxy = outbound.NewRejectWithOption(*rejectOption) default: return nil, fmt.Errorf("unsupport proxy type: %s", proxyType) } diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index cbd27cd6..8973c431 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -3,8 +3,9 @@ package inner import ( "errors" "net" + "net/netip" + "strconv" - "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" ) @@ -20,6 +21,23 @@ func HandleTcp(address string) (conn net.Conn, err error) { } // executor Parsed conn1, conn2 := net.Pipe() - go tunnel.HandleTCPConn(inbound.NewInner(conn2, address)) + + metadata := &C.Metadata{} + metadata.NetWork = C.TCP + metadata.Type = C.INNER + metadata.DNSMode = C.DNSNormal + metadata.Process = C.ClashName + if h, port, err := net.SplitHostPort(address); err == nil { + if port, err := strconv.ParseUint(port, 10, 16); err == nil { + metadata.DstPort = uint16(port) + } + if ip, err := netip.ParseAddr(h); err == nil { + metadata.DstIP = ip + } else { + metadata.Host = h + } + } + + go tunnel.HandleTCPConn(conn2, metadata) return conn1, nil } From 0dc6a726c1f56f32d690bc5a480e983057d9837f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 18:17:39 +0800 Subject: [PATCH 029/192] fix: unmap 4in6 ip --- adapter/inbound/addition.go | 21 +++++++++------------ adapter/inbound/auth.go | 4 ++-- adapter/inbound/util.go | 21 +++++++++------------ listener/sing/sing.go | 12 ++---------- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 14fc303f..2754ee1e 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -38,27 +38,24 @@ func WithSpecialProxy(specialProxy string) Addition { func WithSrcAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if addrPort, err := parseAddr(addr); err == nil { - metadata.SrcIP = addrPort.Addr() - metadata.SrcPort = addrPort.Port() - } + addrPort := parseAddr(addr) + metadata.SrcIP = addrPort.Addr().Unmap() + metadata.SrcPort = addrPort.Port() } } func WithDstAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if addrPort, err := parseAddr(addr); err == nil { - metadata.DstIP = addrPort.Addr() - metadata.DstPort = addrPort.Port() - } + addrPort := parseAddr(addr) + metadata.DstIP = addrPort.Addr().Unmap() + metadata.DstPort = addrPort.Port() } } func WithInAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if addrPort, err := parseAddr(addr); err == nil { - metadata.InIP = addrPort.Addr() - metadata.InPort = addrPort.Port() - } + addrPort := parseAddr(addr) + metadata.InIP = addrPort.Addr().Unmap() + metadata.InPort = addrPort.Port() } } diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go index 724b5b7a..93c56c99 100644 --- a/adapter/inbound/auth.go +++ b/adapter/inbound/auth.go @@ -16,9 +16,9 @@ func SkipAuthPrefixes() []netip.Prefix { } func SkipAuthRemoteAddr(addr net.Addr) bool { - if addrPort, err := parseAddr(addr); err == nil { + if addrPort := parseAddr(addr); addrPort.IsValid() { for _, prefix := range skipAuthPrefixes { - if prefix.Contains(addrPort.Addr()) { + if prefix.Contains(addrPort.Addr().Unmap()) { return true } } diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index 32ca9f05..e4d2630d 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -1,7 +1,6 @@ package inbound import ( - "errors" "net" "net/http" "net/netip" @@ -63,25 +62,23 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } -func parseAddr(addr net.Addr) (netip.AddrPort, error) { +func parseAddr(addr net.Addr) netip.AddrPort { // Filter when net.Addr interface is nil if addr == nil { - return netip.AddrPort{}, errors.New("nil addr") + return netip.AddrPort{} } - if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { - if addrPort, err := parseAddr(rawAddr.RawAddr()); err == nil { - return addrPort, nil + if addr, ok := addr.(interface{ RawAddr() net.Addr }); ok { + if rawAddr := addr.RawAddr(); rawAddr != nil { + return parseAddr(rawAddr) } } if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { - if addrPort := addr.AddrPort(); addrPort.IsValid() { - return addrPort, nil - } + return addr.AddrPort() } addrStr := addr.String() host, port, err := net.SplitHostPort(addrStr) if err != nil { - return netip.AddrPort{}, err + return netip.AddrPort{} } var uint16Port uint16 @@ -89,6 +86,6 @@ func parseAddr(addr net.Addr) (netip.AddrPort, error) { uint16Port = uint16(port) } - ip, err := netip.ParseAddr(host) - return netip.AddrPortFrom(ip, uint16Port), err + ip, _ := netip.ParseAddr(host) + return netip.AddrPortFrom(ip, uint16Port) } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 301dc783..d03bebb1 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -93,12 +93,8 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta NetWork: C.TCP, Type: h.Type, Host: metadata.Destination.Fqdn, - DstIP: metadata.Destination.Addr, - DstPort: metadata.Destination.Port, - SrcIP: metadata.Source.Addr, - SrcPort: metadata.Source.Port, } - additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(cMetadata) } @@ -160,12 +156,8 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. NetWork: C.UDP, Type: h.Type, Host: dest.Fqdn, - DstIP: dest.Addr, - DstPort: dest.Port, - SrcIP: metadata.Source.Addr, - SrcPort: metadata.Source.Port, } - additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(cMetadata) } From 129283066fbf3bbb217833fff65ff5f9d875ee16 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 22:54:19 +0800 Subject: [PATCH 030/192] chore: code cleanup --- adapter/inbound/addition.go | 30 ++++++++++++++++------------ adapter/inbound/auth.go | 22 ++++++++++++++++++-- adapter/inbound/http.go | 6 ++---- adapter/inbound/https.go | 6 ++---- adapter/inbound/packet.go | 8 +++----- adapter/inbound/socket.go | 7 ++----- adapter/inbound/util.go | 28 -------------------------- component/proxydialer/proxydialer.go | 5 +---- constant/metadata.go | 28 ++++++++++++++++++++++++++ listener/http/proxy.go | 2 +- listener/sing/context.go | 28 ++++---------------------- listener/sing/sing.go | 16 ++++++--------- listener/tunnel/tcp.go | 8 +++++--- listener/tunnel/udp.go | 9 ++++++--- 14 files changed, 97 insertions(+), 106 deletions(-) diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 2754ee1e..df03b84a 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -8,8 +8,10 @@ import ( type Addition func(metadata *C.Metadata) -func (a Addition) Apply(metadata *C.Metadata) { - a(metadata) +func ApplyAdditions(metadata *C.Metadata, additions ...Addition) { + for _, addition := range additions { + addition(metadata) + } } func WithInName(name string) Addition { @@ -36,26 +38,28 @@ func WithSpecialProxy(specialProxy string) Addition { } } -func WithSrcAddr(addr net.Addr) Addition { +func WithDstAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - addrPort := parseAddr(addr) - metadata.SrcIP = addrPort.Addr().Unmap() - metadata.SrcPort = addrPort.Port() + _ = metadata.SetRemoteAddr(addr) } } -func WithDstAddr(addr net.Addr) Addition { +func WithSrcAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - addrPort := parseAddr(addr) - metadata.DstIP = addrPort.Addr().Unmap() - metadata.DstPort = addrPort.Port() + m := C.Metadata{} + if err := m.SetRemoteAddr(addr);err ==nil{ + metadata.SrcIP = m.DstIP + metadata.SrcPort = m.DstPort + } } } func WithInAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - addrPort := parseAddr(addr) - metadata.InIP = addrPort.Addr().Unmap() - metadata.InPort = addrPort.Port() + m := C.Metadata{} + if err := m.SetRemoteAddr(addr);err ==nil{ + metadata.InIP = m.DstIP + metadata.InPort = m.DstPort + } } } diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go index 93c56c99..4022659f 100644 --- a/adapter/inbound/auth.go +++ b/adapter/inbound/auth.go @@ -3,6 +3,8 @@ package inbound import ( "net" "net/netip" + + C "github.com/Dreamacro/clash/constant" ) var skipAuthPrefixes []netip.Prefix @@ -16,9 +18,25 @@ func SkipAuthPrefixes() []netip.Prefix { } func SkipAuthRemoteAddr(addr net.Addr) bool { - if addrPort := parseAddr(addr); addrPort.IsValid() { + m := C.Metadata{} + if err := m.SetRemoteAddr(addr); err != nil { + return false + } + return skipAuth(m.AddrPort().Addr()) +} + +func SkipAuthRemoteAddress(addr string) bool { + m := C.Metadata{} + if err := m.SetRemoteAddress(addr); err != nil { + return false + } + return skipAuth(m.AddrPort().Addr()) +} + +func skipAuth(addr netip.Addr) bool { + if addr.IsValid() { for _, prefix := range skipAuthPrefixes { - if prefix.Contains(addrPort.Addr().Unmap()) { + if prefix.Contains(addr.Unmap()) { return true } } diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 15376606..2a6050e5 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -12,9 +12,7 @@ func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP - additions = append(additions, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(metadata) - } + ApplyAdditions(metadata, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 7353fe59..891ac9e7 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -11,9 +11,7 @@ import ( func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseHTTPAddr(request) metadata.Type = C.HTTPS - additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(metadata) - } + ApplyAdditions(metadata, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index f211f7a5..0e3f6c48 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -10,13 +10,11 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source - additions = append(additions, WithSrcAddr(packet.LocalAddr())) + ApplyAdditions(metadata, WithSrcAddr(packet.LocalAddr())) if p, ok := packet.(C.UDPPacketInAddr); ok { - additions = append(additions, WithInAddr(p.InAddr())) - } - for _, addition := range additions { - addition.Apply(metadata) + ApplyAdditions(metadata, WithInAddr(p.InAddr())) } + ApplyAdditions(metadata, additions...) return packet, metadata } diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index dbe1712d..21cb490b 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -12,10 +12,7 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = source - additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(metadata) - } - + ApplyAdditions(metadata, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index e4d2630d..acae7c3e 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -61,31 +61,3 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } - -func parseAddr(addr net.Addr) netip.AddrPort { - // Filter when net.Addr interface is nil - if addr == nil { - return netip.AddrPort{} - } - if addr, ok := addr.(interface{ RawAddr() net.Addr }); ok { - if rawAddr := addr.RawAddr(); rawAddr != nil { - return parseAddr(rawAddr) - } - } - if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { - return addr.AddrPort() - } - addrStr := addr.String() - host, port, err := net.SplitHostPort(addrStr) - if err != nil { - return netip.AddrPort{} - } - - var uint16Port uint16 - if port, err := strconv.ParseUint(port, 10, 16); err == nil { - uint16Port = uint16(port) - } - - ip, _ := netip.ParseAddr(host) - return netip.AddrPortFrom(ip, uint16Port) -} diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 83010f96..2d14abae 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -70,10 +70,7 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( } func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - currentMeta := &C.Metadata{Type: C.INNER} - if err := currentMeta.SetRemoteAddress(rAddrPort.String()); err != nil { - return nil, err - } + currentMeta := &C.Metadata{Type: C.INNER, DstIP: rAddrPort.Addr(), DstPort: rAddrPort.Port()} return p.listenPacket(ctx, currentMeta) } diff --git a/constant/metadata.go b/constant/metadata.go index 70478911..5f472205 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -240,6 +240,34 @@ func (m *Metadata) Valid() bool { return m.Host != "" || m.DstIP.IsValid() } +func (m *Metadata) SetRemoteAddr(addr net.Addr) error { + if addr == nil { + return nil + } + if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { + if rawAddr := rawAddr.RawAddr(); rawAddr != nil { + if err := m.SetRemoteAddr(rawAddr); err == nil { + return nil + } + } + } + if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { // *net.TCPAddr, *net.UDPAddr, M.Socksaddr + if addrPort := addr.AddrPort(); addrPort.Port() != 0 { + m.DstPort = addrPort.Port() + if addrPort.IsValid() { // sing's M.Socksaddr maybe return an invalid AddrPort if it's a DomainName + m.DstIP = addrPort.Addr().Unmap() + return nil + } else { + if addr, ok := addr.(interface{ AddrString() string }); ok { // must be sing's M.Socksaddr + m.Host = addr.AddrString() // actually is M.Socksaddr.Fqdn + return nil + } + } + } + } + return m.SetRemoteAddress(addr.String()) +} + func (m *Metadata) SetRemoteAddress(rawAddress string) error { host, port, err := net.SplitHostPort(rawAddress) if err != nil { diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 173bb64a..44ff04c7 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -100,7 +100,7 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool] func authenticate(request *http.Request, cache *cache.LruCache[string, bool]) *http.Response { authenticator := authStore.Authenticator() - if inbound.SkipAuthRemoteAddr(N.NewCustomAddr("", request.RemoteAddr, nil)) { + if inbound.SkipAuthRemoteAddress(request.RemoteAddr) { authenticator = nil } if authenticator != nil { diff --git a/listener/sing/context.go b/listener/sing/context.go index 32b2a161..4204757a 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -17,35 +17,15 @@ func WithAdditions(ctx context.Context, additions ...inbound.Addition) context.C return context.WithValue(ctx, ctxKeyAdditions, additions) } -func getAdditions(ctx context.Context) []inbound.Addition { +func getAdditions(ctx context.Context) (additions []inbound.Addition) { if v := ctx.Value(ctxKeyAdditions); v != nil { if a, ok := v.([]inbound.Addition); ok { - return a + additions = a } } - return nil -} - -func combineAdditions(ctx context.Context, additions []inbound.Addition, extraAdditions ...inbound.Addition) []inbound.Addition { - additionsCloned := false - if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { - additions = slices.Clone(additions) - additionsCloned = true - additions = append(additions, ctxAdditions...) - } if user, ok := auth.UserFromContext[string](ctx); ok { - if !additionsCloned { - additions = slices.Clone(additions) - additionsCloned = true - } + additions = slices.Clone(additions) additions = append(additions, inbound.WithInUser(user)) } - if len(extraAdditions) > 0 { - if !additionsCloned { - additions = slices.Clone(additions) - additionsCloned = true - } - additions = append(additions, extraAdditions...) - } - return additions + return } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index d03bebb1..1837951d 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -92,12 +92,10 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta cMetadata := &C.Metadata{ NetWork: C.TCP, Type: h.Type, - Host: metadata.Destination.Fqdn, - } - additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(cMetadata) } + inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) + inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) + inbound.ApplyAdditions(cMetadata, h.Additions...) h.Tunnel.HandleTCPConn(conn, cMetadata) // this goroutine must exit after conn unused return nil @@ -155,12 +153,10 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. cMetadata := &C.Metadata{ NetWork: C.UDP, Type: h.Type, - Host: dest.Fqdn, - } - additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(cMetadata) } + inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) + inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) + inbound.ApplyAdditions(cMetadata, h.Additions...) h.Tunnel.HandleUDPPacket(cPacket, cMetadata) } diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index dd2059db..9fca14dd 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -36,9 +36,7 @@ func (l *Listener) Close() error { func (l *Listener) handleTCP(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) - conn, metadata := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) - metadata.SpecialProxy = l.proxy - tunnel.HandleTCPConn(conn, metadata) + tunnel.HandleTCPConn(inbound.NewSocket(l.target, conn, C.TUNNEL, additions...)) } func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { @@ -59,6 +57,10 @@ func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addit addr: addr, } + if proxy != "" { + additions = append([]inbound.Addition{inbound.WithSpecialProxy(proxy)}, additions...) + } + go func() { for { c, err := l.Accept() diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index 38b779c4..00d61663 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -51,6 +51,11 @@ func NewUDP(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Ad proxy: proxy, addr: addr, } + + if proxy != "" { + additions = append([]inbound.Addition{inbound.WithSpecialProxy(proxy)}, additions...) + } + go func() { for { buf := pool.Get(pool.UDPBufferSize) @@ -76,7 +81,5 @@ func (l *PacketConn) handleUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, a payload: buf, } - packet, metadata := inbound.NewPacket(l.target, cPacket, C.TUNNEL, additions...) - metadata.SpecialProxy = l.proxy - tunnel.HandleUDPPacket(packet, metadata) + tunnel.HandleUDPPacket(inbound.NewPacket(l.target, cPacket, C.TUNNEL, additions...)) } From 9f530525d7fe6812567ee8a1254878f4228af85b Mon Sep 17 00:00:00 2001 From: sduoduo233 <85996970+sduoduo233@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:16:36 +0800 Subject: [PATCH 031/192] fix: method in vmess http-opts is not used --- common/util/manipulation.go | 8 ++++++++ transport/vmess/http.go | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 common/util/manipulation.go diff --git a/common/util/manipulation.go b/common/util/manipulation.go new file mode 100644 index 00000000..d2c861eb --- /dev/null +++ b/common/util/manipulation.go @@ -0,0 +1,8 @@ +package util + +import "github.com/samber/lo" + +func EmptyOr[T comparable](v T, def T) T { + ret, _ := lo.Coalesce(v, def) + return ret +} diff --git a/transport/vmess/http.go b/transport/vmess/http.go index c4f27c4c..d9e73f68 100644 --- a/transport/vmess/http.go +++ b/transport/vmess/http.go @@ -8,6 +8,8 @@ import ( "net/http" "net/textproto" + "github.com/Dreamacro/clash/common/util" + "github.com/zhangyunhao116/fastrand" ) @@ -59,7 +61,7 @@ func (hc *httpConn) Write(b []byte) (int, error) { } u := fmt.Sprintf("http://%s%s", host, path) - req, _ := http.NewRequest("GET", u, bytes.NewBuffer(b)) + req, _ := http.NewRequest(util.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b)) for key, list := range hc.cfg.Headers { req.Header.Set(key, list[fastrand.Intn(len(list))]) } From 81bbbe4eece2ca88a33d813f3935c2ad2cbe8a55 Mon Sep 17 00:00:00 2001 From: Jiahao Lu Date: Mon, 16 Oct 2023 09:21:06 +0800 Subject: [PATCH 032/192] fix: DNS NCACHE TTL and OPT RRs (#2900) * Fix: DNS NCACHE TTL and OPT RRs 1. DNS NCACHE was not correctly implemented. 2. OPT RRs must not be cached or forwarded. Closes #2889. --- dns/resolver.go | 6 +++++- dns/util.go | 47 +++++++++++++++++++++++------------------------ 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/dns/resolver.go b/dns/resolver.go index 2c429358..4696515f 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -195,7 +195,11 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M msg := result.(*D.Msg) if cache { - putMsgToCache(r.lruCache, q.String(), msg) + // OPT RRs MUST NOT be cached, forwarded, or stored in or loaded from master files. + msg.Extra = lo.Filter(msg.Extra, func(rr D.RR, index int) bool { + return rr.Header().Rrtype != D.TypeOPT + }) + putMsgToCache(r.lruCache, q.String(), q, msg) } }() diff --git a/dns/util.go b/dns/util.go index 29de4e2a..433ea9e2 100644 --- a/dns/util.go +++ b/dns/util.go @@ -29,14 +29,16 @@ const ( MaxMsgSize = 65535 ) +const serverFailureCacheTTL uint32 = 5 + func minimalTTL(records []D.RR) uint32 { - minObj := lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool { + rr := lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool { return r1.Header().Ttl < r2.Header().Ttl }) - if minObj != nil { - return minObj.Header().Ttl + if rr == nil { + return 0 } - return 0 + return rr.Header().Ttl } func updateTTL(records []D.RR, ttl uint32) { @@ -49,28 +51,25 @@ func updateTTL(records []D.RR, ttl uint32) { } } -func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg) { - putMsgToCacheWithExpire(c, key, msg, 0) -} - -func putMsgToCacheWithExpire(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg, sec uint32) { - if sec == 0 { - if sec = minimalTTL(msg.Answer); sec == 0 { - if sec = minimalTTL(msg.Ns); sec == 0 { - sec = minimalTTL(msg.Extra) - } - } - if sec == 0 { - return - } - - if sec > 120 { - sec = 120 // at least 2 minutes to cache - } - +func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, q D.Question, msg *D.Msg) { + // skip dns cache for acme challenge + if q.Qtype == D.TypeTXT && strings.HasPrefix(q.Name, "_acme-challenge.") { + log.Debugln("[DNS] dns cache ignored because of acme challenge for: %s", q.Name) + return } - c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Duration(sec)*time.Second)) + var ttl uint32 + if msg.Rcode == D.RcodeServerFailure { + // [...] a resolver MAY cache a server failure response. + // If it does so it MUST NOT cache it for longer than five (5) minutes [...] + ttl = serverFailureCacheTTL + } else { + ttl = minimalTTL(append(append(msg.Answer, msg.Ns...), msg.Extra...)) + } + if ttl == 0 { + return + } + c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Duration(ttl)*time.Second)) } func setMsgTTL(msg *D.Msg, ttl uint32) { From 98df77439c036d0c9d76924854c714e5f41d02be Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 16 Oct 2023 09:22:16 +0800 Subject: [PATCH 033/192] feature: add environs startup option support (#2909) --- main.go | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/main.go b/main.go index e9f66058..d41450b6 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,6 @@ import ( ) var ( - flagset map[string]bool version bool testConfig bool geodataMode bool @@ -33,20 +32,15 @@ var ( ) func init() { - flag.StringVar(&homeDir, "d", "", "set configuration directory") - flag.StringVar(&configFile, "f", "", "specify configuration file") - flag.StringVar(&externalUI, "ext-ui", "", "override external ui directory") - flag.StringVar(&externalController, "ext-ctl", "", "override external controller address") - flag.StringVar(&secret, "secret", "", "override secret for RESTful API") + flag.StringVar(&homeDir, "d", os.Getenv("CLASH_HOME_DIR"), "set configuration directory") + flag.StringVar(&configFile, "f", os.Getenv("CLASH_CONFIG_FILE"), "specify configuration file") + flag.StringVar(&externalUI, "ext-ui", os.Getenv("CLASH_OVERRIDE_EXTERNAL_UI_DIR"), "override external ui directory") + flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), "override external controller address") + flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API") flag.BoolVar(&geodataMode, "m", false, "set geodata mode") flag.BoolVar(&version, "v", false, "show current version of clash") flag.BoolVar(&testConfig, "t", false, "test configuration and exit") flag.Parse() - - flagset = map[string]bool{} - flag.Visit(func(f *flag.Flag) { - flagset[f.Name] = true - }) } func main() { @@ -99,13 +93,13 @@ func main() { } var options []hub.Option - if flagset["ext-ui"] { + if externalUI != "" { options = append(options, hub.WithExternalUI(externalUI)) } - if flagset["ext-ctl"] { + if externalController != "" { options = append(options, hub.WithExternalController(externalController)) } - if flagset["secret"] { + if secret != "" { options = append(options, hub.WithSecret(secret)) } From d2499cd69d5998cd1c64b77397ddaacecc95025c Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 16 Oct 2023 09:23:31 +0800 Subject: [PATCH 034/192] feature: add xdg base support (#2913) --- constant/path.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/constant/path.go b/constant/path.go index d7477e0e..0d82f549 100644 --- a/constant/path.go +++ b/constant/path.go @@ -18,6 +18,9 @@ var ( ) // Path is used to get the configuration path +// +// on Unix systems, `$HOME/.config/clash`. +// on Windows, `%USERPROFILE%/.config/clash`. var Path = func() *path { homeDir, err := os.UserHomeDir() if err != nil { @@ -25,6 +28,13 @@ var Path = func() *path { } allowUnsafePath, _ := strconv.ParseBool(os.Getenv("SKIP_SAFE_PATH_CHECK")) homeDir = P.Join(homeDir, ".config", Name) + + if _, err = os.Stat(homeDir); err != nil { + if configHome, ok := os.LookupEnv("XDG_CONFIG_HOME"); ok { + homeDir = P.Join(configHome, Name) + } + } + return &path{homeDir: homeDir, configFile: "config.yaml", allowUnsafePath: allowUnsafePath} }() From 1faad7338164fee305ea8446c10007198add3597 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+dreamacro@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:27:55 +0800 Subject: [PATCH 035/192] fix: socks5 udp associate --- adapter/outbound/socks5.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 864500c5..43dfe8ef 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net" + "net/netip" "strconv" N "github.com/Dreamacro/clash/common/net" @@ -136,7 +137,8 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, } } - bindAddr, err := socks5.ClientHandshake(c, serializesSocksAddr(metadata), socks5.CmdUDPAssociate, user) + udpAssocateAddr := socks5.AddrFromStdAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), 0)) + bindAddr, err := socks5.ClientHandshake(c, udpAssocateAddr, socks5.CmdUDPAssociate, user) if err != nil { err = fmt.Errorf("client hanshake error: %w", err) return From d75a0e69a090e49219e1f7b7440a5dad0f16456c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Oct 2023 09:56:41 +0800 Subject: [PATCH 036/192] chore: Update dependencies --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 188f00ea..08dd7c25 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/3andne/restls-client-go v0.1.6 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da - github.com/cilium/ebpf v0.11.0 + github.com/cilium/ebpf v0.12.0 github.com/coreos/go-iptables v0.7.0 github.com/dlclark/regexp2 v1.10.0 github.com/go-chi/chi/v5 v5.0.10 @@ -30,7 +30,7 @@ require ( github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 - github.com/puzpuzpuz/xsync/v2 v2.5.0 + github.com/puzpuzpuz/xsync/v2 v2.5.1 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.13 github.com/sagernet/sing-mux v0.1.3 @@ -39,16 +39,16 @@ require ( github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.8 + github.com/shirou/gopsutil/v3 v3.23.9 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.3 golang.org/x/crypto v0.14.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 - golang.org/x/net v0.15.0 - golang.org/x/sync v0.3.0 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/net v0.17.0 + golang.org/x/sync v0.4.0 golang.org/x/sys v0.13.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 @@ -101,10 +101,10 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect - golang.org/x/mod v0.12.0 // indirect + golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect ) replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 diff --git a/go.sum b/go.sum index 84b186c1..3e48dc07 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= -github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= +github.com/cilium/ebpf v0.12.0 h1:oQEuIQIXgYhe1v7sYUG0P9vtJTYZLLdA6tiQmrOB1mo= +github.com/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -137,8 +137,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= -github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= +github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= @@ -164,8 +164,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -215,19 +215,19 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -253,8 +253,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= From 11ed4a56bda6adbfb8583a54519682ccb3f0e7c1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Oct 2023 12:46:41 +0800 Subject: [PATCH 037/192] chore: code cleanup --- transport/vmess/websocket.go | 56 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 6d679e29..83f5e3c2 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -353,17 +353,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } - headers := http.Header{"User-Agent": []string{"Go-http-client/1.1"}} // match golang's net/http + headers := http.Header{} + headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http if c.Headers != nil { - cHeaders := c.Headers - // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` - // if headers has "Host" will send repeatedly - if host := cHeaders.Get("Host"); host != "" { - cHeaders.Del("Host") - uri.Host = host - } - for k := range cHeaders { - headers.Add(k, cHeaders.Get(k)) + for k := range c.Headers { + headers.Add(k, c.Headers.Get(k)) } } @@ -372,19 +366,26 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if c.EarlyDataHeaderName == "" { uri.Path += earlyDataString } else { - // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer - // if not will cause ws.ErrHandshakeBadSubProtocol - if c.EarlyDataHeaderName == "Sec-WebSocket-Protocol" { - // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols - // to avoid send repeatedly don't set it to headers - dialer.Protocols = []string{earlyDataString} - } else { - headers.Set(c.EarlyDataHeaderName, earlyDataString) - } - + headers.Set(c.EarlyDataHeaderName, earlyDataString) } } + // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer + // if not will cause ws.ErrHandshakeBadSubProtocol + if secProtocol := headers.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { + // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols + // to avoid send repeatedly don't set it to headers + headers.Del("Sec-WebSocket-Protocol") + dialer.Protocols = []string{secProtocol} + } + + // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` + // if headers has "Host" will send repeatedly + if host := headers.Get("Host"); host != "" { + headers.Del("Host") + uri.Host = host + } + dialer.Header = ws.HandshakeHeaderHTTP(headers) conn, reader, _, err := dialer.Dial(ctx, uri.String()) @@ -447,26 +448,23 @@ func decodeEd(s string) ([]byte, error) { return base64.RawURLEncoding.DecodeString(replacer.Replace(s)) } -func decodeXray0rtt(requestHeader http.Header) ([]byte, http.Header) { - var edBuf []byte - responseHeader := http.Header{} +func decodeXray0rtt(requestHeader http.Header) []byte { // read inHeader's `Sec-WebSocket-Protocol` for Xray's 0rtt ws if secProtocol := requestHeader.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { - if buf, err := decodeEd(secProtocol); err == nil { // sure could base64 decode - edBuf = buf + if edBuf, err := decodeEd(secProtocol); err == nil { // sure could base64 decode + return edBuf } } - return edBuf, responseHeader + return nil } func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { - edBuf, responseHeader := decodeXray0rtt(r.Header) - wsConn, rw, _, err := ws.HTTPUpgrader{Header: responseHeader}.Upgrade(r, w) + wsConn, rw, _, err := ws.UpgradeHTTP(r, w) if err != nil { return nil, err } conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) - if len(edBuf) > 0 { + if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 { return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil } return N.NewDeadlineConn(conn), nil From 0129a8579f7bea79f82906ff357cb8407fbbbeba Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 19 Oct 2023 11:08:14 +0800 Subject: [PATCH 038/192] chore: merge some quic-go fix --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 08dd7c25..f6e02548 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0 + github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 diff --git a/go.sum b/go.sum index 3e48dc07..f3de8013 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0 h1:zUNzLFzYAHti3LCSMyM1PILsGovf1QYdWpzFhrdQovA= -github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= From de90c276afe434d02e88a9bf0e3fa413c14536f8 Mon Sep 17 00:00:00 2001 From: 5aaee9 <7685264+5aaee9@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:30:20 +0800 Subject: [PATCH 039/192] feat(sniffer): add quic sniffer --- component/sniffer/base_sniffer.go | 4 +- component/sniffer/dispatcher.go | 40 ++++- component/sniffer/http_sniffer.go | 2 +- component/sniffer/quic_sniffer.go | 289 +++++++++++++++++++++++++++++- component/sniffer/sniff_test.go | 28 +++ component/sniffer/tls_sniffer.go | 2 +- constant/sniffer/sniffer.go | 7 +- test/go.mod | 44 ++--- test/go.sum | 23 +++ tunnel/tunnel.go | 4 + 10 files changed, 412 insertions(+), 31 deletions(-) diff --git a/component/sniffer/base_sniffer.go b/component/sniffer/base_sniffer.go index cf7cb940..6d869aa0 100644 --- a/component/sniffer/base_sniffer.go +++ b/component/sniffer/base_sniffer.go @@ -23,8 +23,8 @@ func (*BaseSniffer) Protocol() string { return "unknown" } -// SniffTCP implements sniffer.Sniffer -func (*BaseSniffer) SniffTCP(bytes []byte) (string, error) { +// SniffData implements sniffer.Sniffer +func (*BaseSniffer) SniffData(bytes []byte) (string, error) { return "", errors.New("TODO") } diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index a1c8a93f..8df6313c 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -35,9 +35,43 @@ type SnifferDispatcher struct { parsePureIp bool } +func (sd *SnifferDispatcher) shouldOverride(metadata *C.Metadata) bool { + return (metadata.Host == "" && sd.parsePureIp) || + sd.forceDomain.Has(metadata.Host) || + (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) +} + +func (sd *SnifferDispatcher) UDPSniff(packet C.PacketAdapter) bool { + metadata := packet.Metadata() + + if sd.shouldOverride(packet.Metadata()) { + for sniffer, config := range sd.sniffers { + if sniffer.SupportNetwork() == C.UDP || sniffer.SupportNetwork() == C.ALLNet { + inWhitelist := sniffer.SupportPort(metadata.DstPort) + overrideDest := config.OverrideDest + + if inWhitelist { + var copyBuf = make([]byte, len(packet.Data())) + copy(copyBuf, packet.Data()) + + host, err := sniffer.SniffData(copyBuf) + if err != nil { + continue + } + + sd.replaceDomain(metadata, host, overrideDest) + return true + } + } + } + } + + return false +} + // TCPSniff returns true if the connection is sniffed to have a domain func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool { - if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Has(metadata.Host) || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) { + if sd.shouldOverride(metadata) { inWhitelist := false overrideDest := false for sniffer, config := range sd.sniffers { @@ -125,7 +159,7 @@ func (sd *SnifferDispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metad continue } - host, err := s.SniffTCP(bytes) + host, err := s.SniffData(bytes) if err != nil { //log.Debugln("[Sniffer] [%s] Sniff data failed %s", s.Protocol(), metadata.DstIP) continue @@ -194,6 +228,8 @@ func NewSniffer(name sniffer.Type, snifferConfig SnifferConfig) (sniffer.Sniffer return NewTLSSniffer(snifferConfig) case sniffer.HTTP: return NewHTTPSniffer(snifferConfig) + case sniffer.QUIC: + return NewQuicSniffer(snifferConfig) default: return nil, ErrorUnsupportedSniffer } diff --git a/component/sniffer/http_sniffer.go b/component/sniffer/http_sniffer.go index beb4bd20..ee958a1c 100644 --- a/component/sniffer/http_sniffer.go +++ b/component/sniffer/http_sniffer.go @@ -58,7 +58,7 @@ func (http *HTTPSniffer) SupportNetwork() C.NetWork { return C.TCP } -func (http *HTTPSniffer) SniffTCP(bytes []byte) (string, error) { +func (http *HTTPSniffer) SniffData(bytes []byte) (string, error) { domain, err := SniffHTTP(bytes) if err == nil { return *domain, nil diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index de78cf82..ab721c41 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -1,3 +1,290 @@ package sniffer -//TODO +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/tls" + _ "crypto/tls" + "encoding/binary" + "errors" + "github.com/Dreamacro/clash/common/buf" + "github.com/Dreamacro/clash/common/utils" + C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/quic-go/quicvarint" + "golang.org/x/crypto/hkdf" + "io" + _ "unsafe" +) + +// Modified from https://github.com/v2fly/v2ray-core/blob/master/common/protocol/quic/sniff.go + +const ( + versionDraft29 uint32 = 0xff00001d + version1 uint32 = 0x1 +) + +type cipherSuiteTLS13 struct { + ID uint16 + KeyLen int + AEAD func(key, fixedNonce []byte) cipher.AEAD + Hash crypto.Hash +} + +// github.com/quic-go/quic-go/internal/handshake/cipher_suite.go describes these cipher suite implementations are copied from the standard library crypto/tls package. +// So we can user go:linkname to implement the same feature. + +//go:linkname aeadAESGCMTLS13 crypto/tls.aeadAESGCMTLS13 +func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD + +var ( + quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} + quicSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} + initialSuite = &cipherSuiteTLS13{ + ID: tls.TLS_AES_128_GCM_SHA256, + KeyLen: 16, + AEAD: aeadAESGCMTLS13, + Hash: crypto.SHA256, + } + errNotQuic = errors.New("not QUIC") + errNotQuicInitial = errors.New("not QUIC initial packet") +) + +type QuicSniffer struct { + *BaseSniffer +} + +func NewQuicSniffer(snifferConfig SnifferConfig) (*QuicSniffer, error) { + ports := snifferConfig.Ports + if len(ports) == 0 { + ports = utils.IntRanges[uint16]{utils.NewRange[uint16](443, 443)} + } + return &QuicSniffer{ + BaseSniffer: NewBaseSniffer(ports, C.UDP), + }, nil +} + +func (quic QuicSniffer) Protocol() string { + return "quic" +} + +func (quic QuicSniffer) SupportNetwork() C.NetWork { + return C.UDP +} + +func (quic QuicSniffer) SniffData(b []byte) (string, error) { + buffer := buf.As(b) + typeByte, err := buffer.ReadByte() + if err != nil { + return "", errNotQuic + } + isLongHeader := typeByte&0x80 > 0 + if !isLongHeader || typeByte&0x40 == 0 { + return "", errNotQuicInitial + } + + vb, err := buffer.ReadBytes(4) + if err != nil { + return "", errNotQuic + } + + versionNumber := binary.BigEndian.Uint32(vb) + + if versionNumber != 0 && typeByte&0x40 == 0 { + return "", errNotQuic + } else if versionNumber != versionDraft29 && versionNumber != version1 { + return "", errNotQuic + } + + if (typeByte&0x30)>>4 != 0x0 { + return "", errNotQuicInitial + } + + var destConnID []byte + if l, err := buffer.ReadByte(); err != nil { + return "", errNotQuic + } else if destConnID, err = buffer.ReadBytes(int(l)); err != nil { + return "", errNotQuic + } + + if l, err := buffer.ReadByte(); err != nil { + return "", errNotQuic + } else if _, err := buffer.ReadBytes(int(l)); err != nil { + return "", errNotQuic + } + + tokenLen, err := quicvarint.Read(buffer) + if err != nil || tokenLen > uint64(len(b)) { + return "", errNotQuic + } + + if _, err = buffer.ReadBytes(int(tokenLen)); err != nil { + return "", errNotQuic + } + + packetLen, err := quicvarint.Read(buffer) + if err != nil { + return "", errNotQuic + } + + hdrLen := len(b) - int(buffer.Len()) + + origPNBytes := make([]byte, 4) + copy(origPNBytes, b[hdrLen:hdrLen+4]) + + var salt []byte + if versionNumber == version1 { + salt = quicSalt + } else { + salt = quicSaltOld + } + initialSecret := hkdf.Extract(crypto.SHA256.New, destConnID, salt) + secret := hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size()) + hpKey := hkdfExpandLabel(initialSuite.Hash, secret, []byte{}, "quic hp", initialSuite.KeyLen) + block, err := aes.NewCipher(hpKey) + if err != nil { + return "", err + } + + cache := buf.New() + defer cache.Release() + + mask := cache.Extend(int(block.BlockSize())) + block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16]) + b[0] ^= mask[0] & 0xf + for i := range b[hdrLen : hdrLen+4] { + b[hdrLen+i] ^= mask[i+1] + } + packetNumberLength := b[0]&0x3 + 1 + var packetNumber uint32 + { + n, err := buffer.ReadByte() + if err != nil { + return "", err + } + packetNumber = uint32(n) + } + + if packetNumber != 0 && packetNumber != 1 { + return "", errNotQuicInitial + } + + extHdrLen := hdrLen + int(packetNumberLength) + copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:]) + data := b[extHdrLen : int(packetLen)+hdrLen] + + key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) + iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12) + c := aeadAESGCMTLS13(key, iv) + nonce := cache.Extend(int(c.NonceSize())) + binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber)) + decrypted, err := c.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen]) + if err != nil { + return "", err + } + buffer = buf.As(decrypted) + + cryptoLen := uint(0) + cryptoData := make([]byte, buffer.Len()) + for i := 0; !buffer.IsEmpty(); i++ { + frameType := byte(0x0) // Default to PADDING frame + for frameType == 0x0 && !buffer.IsEmpty() { + frameType, _ = buffer.ReadByte() + } + switch frameType { + case 0x00: // PADDING frame + case 0x01: // PING frame + case 0x02, 0x03: // ACK frame + if _, err = quicvarint.Read(buffer); err != nil { // Field: Largest Acknowledged + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Delay + return "", io.ErrUnexpectedEOF + } + ackRangeCount, err := quicvarint.Read(buffer) // Field: ACK Range Count + if err != nil { + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: First ACK Range + return "", io.ErrUnexpectedEOF + } + for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range + if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> Gap + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> ACK Range Length + return "", io.ErrUnexpectedEOF + } + } + if frameType == 0x03 { + if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT0 Count + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT1 Count + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count + return "", io.ErrUnexpectedEOF + } + } + case 0x06: // CRYPTO frame, we will use this frame + offset, err := quicvarint.Read(buffer) // Field: Offset + if err != nil { + return "", io.ErrUnexpectedEOF + } + length, err := quicvarint.Read(buffer) // Field: Length + if err != nil || length > uint64(buffer.Len()) { + return "", io.ErrUnexpectedEOF + } + if cryptoLen < uint(offset+length) { + cryptoLen = uint(offset + length) + } + if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data + return "", io.ErrUnexpectedEOF + } + case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet + if _, err = quicvarint.Read(buffer); err != nil { // Field: Error Code + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: Frame Type + return "", io.ErrUnexpectedEOF + } + length, err := quicvarint.Read(buffer) // Field: Reason Phrase Length + if err != nil { + return "", io.ErrUnexpectedEOF + } + if _, err := buffer.ReadBytes(int(length)); err != nil { // Field: Reason Phrase + return "", io.ErrUnexpectedEOF + } + default: + // Only above frame types are permitted in initial packet. + // See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8 + return "", errNotQuicInitial + } + } + + domain, err := ReadClientHello(cryptoData[:cryptoLen]) + if err != nil { + return "", err + } + + return *domain, nil +} + +func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte { + b := make([]byte, 3, 3+6+len(label)+1+len(context)) + binary.BigEndian.PutUint16(b, uint16(length)) + b[2] = uint8(6 + len(label)) + b = append(b, []byte("tls13 ")...) + b = append(b, []byte(label)...) + b = b[:3+6+len(label)+1] + b[3+6+len(label)] = uint8(len(context)) + b = append(b, context...) + + out := make([]byte, length) + n, err := hkdf.Expand(hash.New, secret, b).Read(out) + if err != nil || n != length { + panic("quic: HKDF-Expand-Label invocation failed unexpectedly") + } + return out +} diff --git a/component/sniffer/sniff_test.go b/component/sniffer/sniff_test.go index e7ced43c..4c59d432 100644 --- a/component/sniffer/sniff_test.go +++ b/component/sniffer/sniff_test.go @@ -1,9 +1,37 @@ package sniffer import ( + "encoding/hex" + "github.com/stretchr/testify/assert" "testing" ) +func TestQuicHeaders(t *testing.T) { + cases := []struct { + input string + domain string + }{ + { + input: "cd0000000108f1fb7bcc78aa5e7203a8f86400421531fe825b19541876db6c55c38890cd73149d267a084afee6087304095417a3033df6a81bbb71d8512e7a3e16df1e277cae5df3182cb214b8fe982ba3fdffbaa9ffec474547d55945f0fddbeadfb0b5243890b2fa3da45169e2bd34ec04b2e29382f48d612b28432a559757504d158e9e505407a77dd34f4b60b8d3b555ee85aacd6648686802f4de25e7216b19e54c5f78e8a5963380c742d861306db4c16e4f7fc94957aa50b9578a0b61f1e406b2ad5f0cd3cd271c4d99476409797b0c3cb3efec256118912d4b7e4fd79d9cb9016b6e5eaa4f5e57b637b217755daf8968a4092bed0ed5413f5d04904b3a61e4064f9211b2629e5b52a89c7b19f37a713e41e27743ea6dfa736dfa1bb0a4b2bc8c8dc632c6ce963493a20c550e6fdb2475213665e9a85cfc394da9cec0cf41f0c8abed3fc83be5245b2b5aa5e825d29349f721d30774ef5bf965b540f3d8d98febe20956b1fc8fa047e10e7d2f921c9c6622389e02322e80621a1cf5264e245b7276966eb02932584e3f7038bd36aa908766ad3fb98344025dec18670d6db43a1c5daac00937fce7b7c7d61ff4e6efd01a2bdee0ee183108b926393df4f3d74bbcbb015f240e7e346b7d01c41111a401225ce3b095ab4623a5836169bf9599eeca79d1d2e9b2202b5960a09211e978058d6fc0484eff3e91ce4649a5e3ba15b906d334cf66e28d9ff575406e1ae1ac2febafd72870b6f5d58fc5fb949cb1f40feb7c1d9ce5e71b", + domain: "www.google.com", + }, + { + input: "c3000000011266f50524e8d0fe88cbf51e3ad71a13198235000044c82dc5d943fb34cc6d5c5e433610dc7a44f5951935c2c1d14ac641b02472340a892c4492dbfe3f8262109108fc36d96bdc1e9e46b5f1f6ef6104add2aafbfd8e79246eb3b4637541aaed7d195571724e642ab4d31c909f1db86e7d8516117ce8716bd1e3acb664c499086b0f3bc7258595420e7bb969f934457d195e832ffff4ffddf11123eeadacc48190e356c8f0f6abc381deb7e285e3b0613a795b19bddb9f002ffdf6fd70f0ff2072302b33d2421aac6540bb9f0e85c7237af0dd56225b2264d769160febab952e64bd5155f23e58c6113891143f946591032b41816aed3ac54f521f60605f86791de24c5765b664c1348cc53d5d631b4bbefe1915f2b21fefafb47badeb72d8ba1fd5c3cfeb0ba9d0112396f170e94cd33952c4fa87997b870931bf1a300e8e127f530815ff087815b4f9d004cbcd17013ac143847572a1655a5b36e054e8b9951d747c2c6ff25d7b2edb13a2a6b8074062332f2191f6830cf435a4ed9db5d9c4eb43a143bf3edf0c48f6f9435dafad4afb743a5a33990379df953ecd388e848aff0ebba9ccc052b8303c0bd1fee7e7553af1894e81b7772818bb69249540ccb8cfb47b1517abaf71c81c3bd271f1a5f1b66465f850f377c9db682b8e543c3d0c10fcd2dee263630889b7d1d521d1d27e866ea4ab5f43790d6a7f76ceefd5783678ca92cc131fa42fc4a01e2a81cad734ddf17a53e1bda8e0a21afc9e8c1118c9459b13519f5b3c3d9692c92234f01129d47ae8ec70625170847472801190b46d36f73b868f55f5a18a3cb05af6d38610e0829e4fbf13ddcc202341702e43dcf33be76ff4afe327e5783287c137aad075752940b41e7d9f5146e36d908897c6d7a9fdc343fde2d9c9d6e6a6b237669bd3e6abe0a732861a679eadfa29a876c6a646953c9361830811b012b26b31c9e7158f8de9c9a108346ddee3dd3886da6258364c1281bff8e055f6384e3a23e198b5e6b726fa7f811b3338072019d4b5fd05891770d11e3ed6ab5f7ed33db1c6220c5aa8fa1909949ac55d5435b75982e17aa80940fa574f0aba4dc340129cad491fdf1f5e05c4e83e36ad29ff38f15e1c9436c792024442f57f07583d671dd05446c84ea20b471303f6ae4e5e13f244d671e0ebe94d3d5c17d3f3f378cdd51fa8a6d2c977c78a2397dd1e251cd979803d617d45f575e5d9db0a28b3c4c25fe2af24af5bddac09786b6d6d8aa19cfbd5409bdbfed7d518ef5c863f3ee757bd9d37cddc546cc57d2e52b6ae58789f297a300f1d76c3842603eae4b1224de31a939a68875c86e697aeebf7ebc65568f43fc681bacab830ac4a2164d324e90067125bad702192d01cb3cb3d2689ae681967e86fd7ac93a25cf2e905c88ca5ad7d11962f021754cf3f61224517bd3411d5b5a83955bcea79d702466d073a6eaadc1202b3693e555b051a5b19457023a01e7f943742bb7f5f8aeba8d4e363973aebdccfb12479619cfb93e833be702a307e796dc7431a48abd9b755b392c510b98cd20ef778e2ac88d6a04f23ba8a253d7eb7c13e0c88c3a21f7e23857c58704d139703a47e0965bf2dc8810dc36894ac1f3da73c155e271c106a718b2d184e4e5637c820fe909984642960edfc9e62ac50af5dd3feee6bc560ced7bda676d4e290c9c5916fad52180bbc83d3483e95c79bac15c209936f21042dc2b6253eefdac06e7f4745044eaa0acedabf1d1c8cd9402738", + domain: "cloudflare-dns.com", + }, + } + q, err := NewQuicSniffer(SnifferConfig{}) + assert.NoError(t, err) + + for _, test := range cases { + pkt, err := hex.DecodeString(test.input) + assert.NoError(t, err) + domain, err := q.SniffData(pkt) + assert.NoError(t, err) + assert.Equal(t, test.domain, domain) + } +} + func TestTLSHeaders(t *testing.T) { cases := []struct { input []byte diff --git a/component/sniffer/tls_sniffer.go b/component/sniffer/tls_sniffer.go index 58e1e29e..b695c76f 100644 --- a/component/sniffer/tls_sniffer.go +++ b/component/sniffer/tls_sniffer.go @@ -39,7 +39,7 @@ func (tls *TLSSniffer) SupportNetwork() C.NetWork { return C.TCP } -func (tls *TLSSniffer) SniffTCP(bytes []byte) (string, error) { +func (tls *TLSSniffer) SniffData(bytes []byte) (string, error) { domain, err := SniffTLS(bytes) if err == nil { return *domain, nil diff --git a/constant/sniffer/sniffer.go b/constant/sniffer/sniffer.go index 6b20b3f6..d5414b14 100644 --- a/constant/sniffer/sniffer.go +++ b/constant/sniffer/sniffer.go @@ -4,7 +4,7 @@ import "github.com/Dreamacro/clash/constant" type Sniffer interface { SupportNetwork() constant.NetWork - SniffTCP(bytes []byte) (string, error) + SniffData(bytes []byte) (string, error) Protocol() string SupportPort(port uint16) bool } @@ -12,10 +12,11 @@ type Sniffer interface { const ( TLS Type = iota HTTP + QUIC ) var ( - List = []Type{TLS, HTTP} + List = []Type{TLS, HTTP, QUIC} ) type Type int @@ -26,6 +27,8 @@ func (rt Type) String() string { return "TLS" case HTTP: return "HTTP" + case QUIC: + return "QUIC" default: return "Unknown" } diff --git a/test/go.mod b/test/go.mod index 5582dd04..36fa7256 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,9 +6,9 @@ require ( github.com/Dreamacro/clash v0.0.0 github.com/docker/docker v20.10.21+incompatible github.com/docker/go-connections v0.4.0 - github.com/miekg/dns v1.1.55 + github.com/miekg/dns v1.1.56 github.com/stretchr/testify v1.8.4 - golang.org/x/net v0.15.0 + golang.org/x/net v0.17.0 ) replace github.com/Dreamacro/clash => ../ @@ -20,7 +20,7 @@ require ( github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/andybalholm/brotli v1.0.5 // indirect - github.com/cilium/ebpf v0.11.0 // indirect + github.com/cilium/ebpf v0.12.0 // indirect github.com/coreos/go-iptables v0.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect @@ -32,7 +32,7 @@ require ( github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -52,13 +52,13 @@ require ( github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect - github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect - github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf // indirect - github.com/metacubex/sing-shadowsocks v0.2.4 // indirect - github.com/metacubex/sing-shadowsocks2 v0.1.3 // indirect - github.com/metacubex/sing-tun v0.1.11 // indirect - github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 // indirect - github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 // indirect + github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect + github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b // indirect + github.com/metacubex/sing-shadowsocks v0.2.5 // indirect + github.com/metacubex/sing-shadowsocks2 v0.1.4 // indirect + github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c // indirect + github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 // indirect + github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect @@ -72,13 +72,13 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/puzpuzpuz/xsync/v2 v2.5.0 // indirect + github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.3 // indirect + github.com/quic-go/qtls-go1-20 v0.3.4 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a // indirect - github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c // indirect + github.com/sagernet/sing v0.2.13 // indirect + github.com/sagernet/sing-mux v0.1.3 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect @@ -86,7 +86,7 @@ require ( github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // indirect github.com/samber/lo v1.38.1 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect - github.com/shirou/gopsutil/v3 v3.23.8 // indirect + github.com/shirou/gopsutil/v3 v3.23.9 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect @@ -100,14 +100,14 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.etcd.io/bbolt v1.3.7 // indirect - golang.org/x/crypto v0.13.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.12.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect diff --git a/test/go.sum b/test/go.sum index 609d2fcb..10d016c9 100644 --- a/test/go.sum +++ b/test/go.sum @@ -17,6 +17,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= +github.com/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -49,6 +50,7 @@ github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67d github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= @@ -101,20 +103,28 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= +github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= github.com/metacubex/sing-shadowsocks v0.2.4/go.mod h1:w9qoEZSh9aKeXSLXHe0DGbG2UE9/2VlLGwukzQZ7byI= +github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.3 h1:nZvH+4jQXZ92NeNdR9fXaUGTPNJPt6u0nkcuh/NEt5Y= github.com/metacubex/sing-shadowsocks2 v0.1.3/go.mod h1:5Mt93RlmRlIcDmvtapkhQJ8YTRGLFhHciLYopJjs7j8= +github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= github.com/metacubex/sing-tun v0.1.11 h1:B8meDewklvKkeUfjqR2ViuYLam0/m4IgkTi3qcJIOuc= github.com/metacubex/sing-tun v0.1.11/go.mod h1:vbki176Y5sxXC1DWXucrPh3q5j8cKai1D87y8m8rjQc= +github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 h1:AqqZCr9gOeKdO6oIzFh4b2puOUFcw8MdpmGHWRehyX8= github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8/go.mod h1:tyJg7b4s8NrSztl/Y1ajA7X0sJLlIsEJWkgRVocjmgY= +github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= +github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -147,10 +157,12 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= @@ -160,8 +172,10 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4= github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/sagernet/sing v0.2.13/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I= github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= +github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -178,6 +192,7 @@ github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -227,8 +242,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -236,6 +253,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -243,12 +261,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -265,11 +285,13 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -285,6 +307,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 13bf6d8c..fe37d75e 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -323,6 +323,10 @@ func handleUDPConn(packet C.PacketAdapter) { return } + if sniffer.Dispatcher.Enable() && sniffingEnable { + sniffer.Dispatcher.UDPSniff(packet) + } + // local resolve UDP dns if !metadata.Resolved() { ip, err := resolver.ResolveIP(context.Background(), metadata.Host) From 981c69040faff74c893ed2dcaeb765ac8d29f638 Mon Sep 17 00:00:00 2001 From: 5aaee9 <7685264+5aaee9@users.noreply.github.com> Date: Thu, 19 Oct 2023 19:09:13 +0800 Subject: [PATCH 040/192] docs: update about quic sniffer --- docs/config.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index e829e5db..80fc2995 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -142,7 +142,9 @@ sniffer: # 是否使用嗅探结果作为实际访问,默认 true # 全局配置,优先级低于 sniffer.sniff 实际配置 override-destination: false - sniff: # TLS 默认如果不配置 ports 默认嗅探 443 + sniff: # TLS 和 QUIC 默认如果不配置 ports 默认嗅探 443 + QUIC: + # ports: [ 443 ] TLS: # ports: [443, 8443] From 8e637a2ec77a0bf720ee10f7023c57399764335d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 19 Oct 2023 20:44:49 +0800 Subject: [PATCH 041/192] chore: code cleanup --- component/sniffer/quic_sniffer.go | 53 ++++++++++++++----------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index ab721c41..24e1bcc4 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -4,17 +4,16 @@ import ( "crypto" "crypto/aes" "crypto/cipher" - "crypto/tls" - _ "crypto/tls" "encoding/binary" "errors" + "io" + "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/quic-go/quicvarint" "golang.org/x/crypto/hkdf" - "io" - _ "unsafe" ) // Modified from https://github.com/v2fly/v2ray-core/blob/master/common/protocol/quic/sniff.go @@ -24,28 +23,9 @@ const ( version1 uint32 = 0x1 ) -type cipherSuiteTLS13 struct { - ID uint16 - KeyLen int - AEAD func(key, fixedNonce []byte) cipher.AEAD - Hash crypto.Hash -} - -// github.com/quic-go/quic-go/internal/handshake/cipher_suite.go describes these cipher suite implementations are copied from the standard library crypto/tls package. -// So we can user go:linkname to implement the same feature. - -//go:linkname aeadAESGCMTLS13 crypto/tls.aeadAESGCMTLS13 -func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD - var ( - quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} - quicSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} - initialSuite = &cipherSuiteTLS13{ - ID: tls.TLS_AES_128_GCM_SHA256, - KeyLen: 16, - AEAD: aeadAESGCMTLS13, - Hash: crypto.SHA256, - } + quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} + quicSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} errNotQuic = errors.New("not QUIC") errNotQuicInitial = errors.New("not QUIC initial packet") ) @@ -140,7 +120,7 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { } initialSecret := hkdf.Extract(crypto.SHA256.New, destConnID, salt) secret := hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size()) - hpKey := hkdfExpandLabel(initialSuite.Hash, secret, []byte{}, "quic hp", initialSuite.KeyLen) + hpKey := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic hp", 16) block, err := aes.NewCipher(hpKey) if err != nil { return "", err @@ -175,10 +155,25 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12) - c := aeadAESGCMTLS13(key, iv) - nonce := cache.Extend(int(c.NonceSize())) + aesCipher, err := aes.NewCipher(key) + if err != nil { + return "", err + } + aead, err := cipher.NewGCM(aesCipher) + if err != nil { + return "", err + } + nonce := cache.Extend(8) // 64-bit sequence number binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber)) - decrypted, err := c.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen]) + // copy from crypto/tls.aeadAESGCMTLS13 + for i, b := range nonce { + iv[4+i] ^= b + } + decrypted, err := aead.Open(b[extHdrLen:extHdrLen], iv, data, b[:extHdrLen]) + // We only decrypt once, so we do not need to XOR it back. + //for i, b := range nonce { + // iv[4+i] ^= b + //} if err != nil { return "", err } From ea7e15b447299ffa3d742d7b9fee3d44eb830457 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 19 Oct 2023 23:51:37 +0800 Subject: [PATCH 042/192] chore: decrease memory copy in quic sniffer --- common/buf/sing.go | 1 + component/sniffer/dispatcher.go | 5 +-- component/sniffer/quic_sniffer.go | 64 ++++++++++++++++--------------- component/sniffer/sniff_test.go | 5 +++ constant/sniffer/sniffer.go | 1 + 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/common/buf/sing.go b/common/buf/sing.go index d204ba11..0907a95c 100644 --- a/common/buf/sing.go +++ b/common/buf/sing.go @@ -10,6 +10,7 @@ const BufferSize = buf.BufferSize type Buffer = buf.Buffer var New = buf.New +var NewPacket = buf.NewPacket var NewSize = buf.NewSize var With = buf.With var As = buf.As diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 8df6313c..271be8bb 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -51,10 +51,7 @@ func (sd *SnifferDispatcher) UDPSniff(packet C.PacketAdapter) bool { overrideDest := config.OverrideDest if inWhitelist { - var copyBuf = make([]byte, len(packet.Data())) - copy(copyBuf, packet.Data()) - - host, err := sniffer.SniffData(copyBuf) + host, err := sniffer.SniffData(packet.Data()) if err != nil { continue } diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index 24e1bcc4..ef49e5ad 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -107,10 +107,7 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { return "", errNotQuic } - hdrLen := len(b) - int(buffer.Len()) - - origPNBytes := make([]byte, 4) - copy(origPNBytes, b[hdrLen:hdrLen+4]) + hdrLen := len(b) - buffer.Len() var salt []byte if versionNumber == version1 { @@ -126,31 +123,40 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { return "", err } - cache := buf.New() + cache := buf.NewPacket() defer cache.Release() - mask := cache.Extend(int(block.BlockSize())) + mask := cache.Extend(block.BlockSize()) block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16]) - b[0] ^= mask[0] & 0xf - for i := range b[hdrLen : hdrLen+4] { - b[hdrLen+i] ^= mask[i+1] + firstByte := b[0] + // Encrypt/decrypt first byte. + if isLongHeader { + // Long header: 4 bits masked + // High 4 bits are not protected. + firstByte ^= mask[0] & 0x0f + } else { + // Short header: 5 bits masked + // High 3 bits are not protected. + firstByte ^= mask[0] & 0x1f } - packetNumberLength := b[0]&0x3 + 1 - var packetNumber uint32 - { - n, err := buffer.ReadByte() - if err != nil { - return "", err - } - packetNumber = uint32(n) + packetNumberLength := int(firstByte&0x3 + 1) // max = 4 (64-bit sequence number) + extHdrLen := hdrLen + packetNumberLength + + // copy to avoid modify origin data + extHdr := cache.Extend(extHdrLen) + copy(extHdr, b) + extHdr[0] = firstByte + + packetNumber := extHdr[hdrLen:extHdrLen] + // Encrypt/decrypt packet number. + for i := range packetNumber { + packetNumber[i] ^= mask[1+i] } - if packetNumber != 0 && packetNumber != 1 { + if packetNumber[0] != 0 && packetNumber[0] != 1 { return "", errNotQuicInitial } - extHdrLen := hdrLen + int(packetNumberLength) - copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:]) data := b[extHdrLen : int(packetLen)+hdrLen] key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) @@ -163,24 +169,20 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { if err != nil { return "", err } - nonce := cache.Extend(8) // 64-bit sequence number - binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber)) - // copy from crypto/tls.aeadAESGCMTLS13 - for i, b := range nonce { - iv[4+i] ^= b - } - decrypted, err := aead.Open(b[extHdrLen:extHdrLen], iv, data, b[:extHdrLen]) // We only decrypt once, so we do not need to XOR it back. - //for i, b := range nonce { - // iv[4+i] ^= b - //} + // https://github.com/quic-go/qtls-go1-20/blob/e132a0e6cb45e20ac0b705454849a11d09ba5a54/cipher_suites.go#L496 + for i, b := range packetNumber { + iv[len(iv)-len(packetNumber)+i] ^= b + } + dst := cache.Extend(len(data)) + decrypted, err := aead.Open(dst[:0], iv, data, extHdr) if err != nil { return "", err } buffer = buf.As(decrypted) cryptoLen := uint(0) - cryptoData := make([]byte, buffer.Len()) + cryptoData := cache.Extend(buffer.Len()) for i := 0; !buffer.IsEmpty(); i++ { frameType := byte(0x0) // Default to PADDING frame for frameType == 0x0 && !buffer.IsEmpty() { diff --git a/component/sniffer/sniff_test.go b/component/sniffer/sniff_test.go index 4c59d432..18cc9152 100644 --- a/component/sniffer/sniff_test.go +++ b/component/sniffer/sniff_test.go @@ -1,6 +1,7 @@ package sniffer import ( + "bytes" "encoding/hex" "github.com/stretchr/testify/assert" "testing" @@ -26,9 +27,11 @@ func TestQuicHeaders(t *testing.T) { for _, test := range cases { pkt, err := hex.DecodeString(test.input) assert.NoError(t, err) + oriPkt := bytes.Clone(pkt) domain, err := q.SniffData(pkt) assert.NoError(t, err) assert.Equal(t, test.domain, domain) + assert.Equal(t, oriPkt, pkt) // ensure input data not changed } } @@ -170,6 +173,7 @@ func TestTLSHeaders(t *testing.T) { } for _, test := range cases { + input := bytes.Clone(test.input) domain, err := SniffTLS(test.input) if test.err { if err == nil { @@ -183,5 +187,6 @@ func TestTLSHeaders(t *testing.T) { t.Error("expect domain ", test.domain, " but got ", domain) } } + assert.Equal(t, input, test.input) } } diff --git a/constant/sniffer/sniffer.go b/constant/sniffer/sniffer.go index d5414b14..47dbd069 100644 --- a/constant/sniffer/sniffer.go +++ b/constant/sniffer/sniffer.go @@ -4,6 +4,7 @@ import "github.com/Dreamacro/clash/constant" type Sniffer interface { SupportNetwork() constant.NetWork + // SniffData must not change input bytes SniffData(bytes []byte) (string, error) Protocol() string SupportPort(port uint16) bool From 51004b14d98087392d4fa29084823128adeb7acc Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 19 Oct 2023 23:41:43 +0800 Subject: [PATCH 043/192] docs: update readme.md --- README.md | 303 +++--------------------------------------------------- 1 file changed, 16 insertions(+), 287 deletions(-) diff --git a/README.md b/README.md index bbf5cf43..d5022dfb 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ ## Features - Local HTTP/HTTPS/SOCKS server with authentication support -- VMess, Shadowsocks, Trojan, Snell protocol support for remote connections +- VMess, VLESS, Shadowsocks, Trojan, Snell, TUIC, Hysteria protocol support - Built-in DNS server that aims to minimize DNS pollution attack impact, supports DoH/DoT upstream and fake IP. - Rules based off domains, GEOIP, IPCIDR or Process to forward packets to different nodes - Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node @@ -32,259 +32,41 @@ ## Dashboard -We made an official web dashboard providing first class support for this project, check it out -at [metacubexd](https://github.com/MetaCubeX/metacubexd) +A web dashboard with first-class support for this project has been created; it can be checked out at [metacubexd](https://github.com/MetaCubeX/metacubexd). -## Wiki +## Configration example -Configuration examples can be found -at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml), while documentation can be -found [Clash.Meta Wiki](https://clash-meta.wiki). +Configuration example is located at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml). -## Build +## Docs -You should install [golang](https://go.dev) first. +Documentation can be found in [Clash.Meta Docs](https://clash-meta.wiki). -Then get the source code of Clash.Meta: +## For development + +Requirements: +[Go 1.20 or newer](https://go.dev/dl/) + +Build Clash.Meta: ```shell git clone https://github.com/MetaCubeX/Clash.Meta.git cd Clash.Meta && go mod download +go build ``` -If you can't visit GitHub, you should set proxy first: +Set go proxy if a connection to GitHub is not possible: ```shell go env -w GOPROXY=https://goproxy.io,direct ``` -Now you can build it: - -```shell -go build -``` - -If you need gvisor for tun stack, build with: +Build with gvisor tun stack: ```shell go build -tags with_gvisor ``` - - - - ### IPTABLES configuration Work on Linux OS which supported `iptables` @@ -298,62 +80,9 @@ iptables: inbound-interface: eth0 # detect the inbound interface, default is 'lo' ``` -### General installation guide for Linux - -- Create user given name `clash-meta` - -- Download and decompress pre-built binaries from [releases](https://github.com/MetaCubeX/Clash.Meta/releases) - -- Rename executable file to `Clash-Meta` and move to `/usr/local/bin/` - -- Create folder `/etc/Clash-Meta/` as working directory - -Run Meta Kernel by user `clash-meta` as a daemon. - -Create the systemd configuration file at `/etc/systemd/system/Clash-Meta.service`: - -``` -[Unit] -Description=Clash-Meta Daemon, Another Clash Kernel. -After=network.target NetworkManager.service systemd-networkd.service iwd.service - -[Service] -Type=simple -User=clash-meta -Group=clash-meta -LimitNPROC=500 -LimitNOFILE=1000000 -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE -Restart=always -ExecStartPre=/usr/bin/sleep 1s -ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta -ExecReload=/bin/kill -HUP $MAINPID - -[Install] -WantedBy=multi-user.target -``` - -Launch clash-meta daemon on system startup with: - -```shell -$ systemctl enable Clash-Meta -``` - -Launch clash-meta daemon immediately with: - -```shell -$ systemctl start Clash-Meta -``` - -## Development - -If you want to build an application that uses clash as a library, check out -the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library) - ## Debugging -Check [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki/How-to-use-debug-api) to get an instruction on using debug +Check [wiki](https://wiki.metacubex.one/api/#debug) to get an instruction on using debug API. ## Credits From 150bf7fc65c7736d7c56e2ce7866f03a620d9014 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 20 Oct 2023 08:39:04 +0800 Subject: [PATCH 044/192] chore: decrease memory copy in sing listener --- listener/sing/sing.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 1837951d..ff72f67d 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -193,12 +193,6 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { err = errors.New("address is invalid") return } - buff := buf.NewPacket() - defer buff.Release() - n, err = buff.Write(b) - if err != nil { - return - } c.mutex.Lock() defer c.mutex.Unlock() @@ -207,6 +201,14 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { err = errors.New("writeBack to closed connection") return } + + buff := buf.NewPacket() + defer buff.Release() + n, err = buff.Write(b) + if err != nil { + return + } + err = conn.WritePacket(buff, M.SocksaddrFromNet(addr)) if err != nil { return From 0d3197e4371e6e2c81f32c8fb876e06a0b828dc5 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Fri, 20 Oct 2023 22:36:29 +0800 Subject: [PATCH 045/192] chore: fix sniffer log error --- component/sniffer/dispatcher.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 271be8bb..11deb1ed 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -117,7 +117,8 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) { // show log early, since the following code may mutate `metadata.Host` - log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]", + log.Debugln("[Sniffer] Sniff %s [%s]-->[%s] success, replace domain [%s]-->[%s]", + metadata.NetWork, metadata.SourceDetail(), metadata.RemoteAddress(), metadata.Host, host) From f794c090a52f41c78d12a946f21b0d338c9e0299 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 22 Oct 2023 23:38:25 +0800 Subject: [PATCH 046/192] chore: update sing-tun --- go.mod | 6 +++--- go.sum | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index f6e02548..f355a977 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c + github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 @@ -32,7 +32,7 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.1 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.13 + github.com/sagernet/sing v0.2.14 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -65,7 +65,7 @@ require ( github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect diff --git a/go.sum b/go.sum index f3de8013..be89ca4d 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4Rfsap github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= @@ -107,8 +107,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c h1:vzueqPO6LCdgE+KpGdZ89PwxcDGQW+lCnc7Leq2s1yY= -github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= +github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 h1:JToLa8cxHrd6tOUHWCg9YM+o/4MXmjgagG909itmnyE= +github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700/go.mod h1:atkIOs6Y5NeUzstK5SBvnrFo4z1JLuORhEfQECEVUpI= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= @@ -238,7 +238,6 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 6cd0e58fd03f362ff98380f07746653ca9a365c7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 22 Oct 2023 23:39:46 +0800 Subject: [PATCH 047/192] fix: ssr panic --- transport/ssr/protocol/auth_chain_a.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/transport/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go index 23efb390..12345db6 100644 --- a/transport/ssr/protocol/auth_chain_a.go +++ b/transport/ssr/protocol/auth_chain_a.go @@ -7,6 +7,7 @@ import ( "crypto/rc4" "encoding/base64" "encoding/binary" + "errors" "net" "strconv" "strings" @@ -107,6 +108,10 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { dataLength := int(binary.LittleEndian.Uint16(src.Bytes()[:2]) ^ binary.LittleEndian.Uint16(a.lastServerHash[14:16])) randDataLength := a.randDataLength(dataLength, a.lastServerHash, &a.randomServer) length := dataLength + randDataLength + // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + if dataLength < 0 || randDataLength < 0 || length < 0 { + return errors.New("ssr crashing blocked") + } if length >= 4096 { a.rawTrans = true @@ -130,6 +135,11 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { if dataLength > 0 && randDataLength > 0 { pos += getRandStartPos(randDataLength, &a.randomServer) } + // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + if pos < 0 || pos+dataLength < 0 || dataLength < 0 { + return errors.New("ssr crashing blocked") + } + wantedData := src.Bytes()[pos : pos+dataLength] a.decrypter.XORKeyStream(wantedData, wantedData) if a.recvID == 1 { From e987cdaaae202749aadeed0e051bc882cd84c0db Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Mon, 23 Oct 2023 00:27:37 +0800 Subject: [PATCH 048/192] chore: add CMFA auto update-dependencies trigger --- .../workflows/cmfa-update-deps-trigger.yml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/cmfa-update-deps-trigger.yml diff --git a/.github/workflows/cmfa-update-deps-trigger.yml b/.github/workflows/cmfa-update-deps-trigger.yml new file mode 100644 index 00000000..51736644 --- /dev/null +++ b/.github/workflows/cmfa-update-deps-trigger.yml @@ -0,0 +1,28 @@ +name: CMFA auto update-dependencies trigger +on: + workflow_dispatch: + push: + tags: + - "v*" + pull_request_target: + branches: + - Alpha + +jobs: + update-dependencies: + runs-on: ubuntu-latest + steps: + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.MAINTAINER_APPID }} + private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} + + - name: Trigger update-dependencies + run: | + curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ + -H "Accept: application/vnd.github.everest-preview+json" \ + -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ + -d '{"event_type": "core-updated"}' + # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies + \ No newline at end of file From dff54464c635297e3da32dff4e605ea9ca475fbb Mon Sep 17 00:00:00 2001 From: Steve Johnson <144257728+stevejohnson7@users.noreply.github.com> Date: Mon, 23 Oct 2023 07:01:03 +0800 Subject: [PATCH 049/192] Add auto sync Alpha rebase android-open -> android-real (#817) * chore: add android branch auto sync * chore: fix * chore: fix missing * chore: fix actions * chore: write branch auto sync --- .../workflows/android-branch-auto-sync.yml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/android-branch-auto-sync.yml diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml new file mode 100644 index 00000000..f1a5b2d8 --- /dev/null +++ b/.github/workflows/android-branch-auto-sync.yml @@ -0,0 +1,50 @@ +name: Android Branch Auto Sync +on: + workflow_dispatch: + push: + paths-ignore: + - "docs/**" + - "README.md" + - ".github/ISSUE_TEMPLATE/**" + branches: + - Alpha + - android-open + tags: + - "v*" + pull_request_target: + branches: + - Alpha + - android-open + +jobs: + update-dependencies: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config --global user.name 'GitHub Action' + git config --global user.email 'action@github.com' + + - name: Sync android-real with Alpha rebase android-open + run: | + git fetch origin + git checkout origin/Alpha -b android-real + git rebase origin/android-open + + - name: Check for conflicts + run: | + CONFLICTS=$(git diff --name-only --diff-filter=U) + if [ ! -z "$CONFLICTS" ]; then + echo "There are conflicts in the following files:" + echo $CONFLICTS + exit 1 + fi + + - name: Push changes + run: | + git push origin android-real --force \ No newline at end of file From f6f8f27668763581e12b916b976aee8335781f44 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 23 Oct 2023 07:30:54 +0800 Subject: [PATCH 050/192] action: update sync --- .github/workflows/android-branch-auto-sync.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml index f1a5b2d8..5dbbd5be 100644 --- a/.github/workflows/android-branch-auto-sync.yml +++ b/.github/workflows/android-branch-auto-sync.yml @@ -34,7 +34,8 @@ jobs: run: | git fetch origin git checkout origin/Alpha -b android-real - git rebase origin/android-open + git merge --squash origin/android-open + git commit -m "Android: patch" - name: Check for conflicts run: | From 3564e96a0010a415e5dd22fc9deeb7efd381dcb5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 23 Oct 2023 16:45:22 +0800 Subject: [PATCH 051/192] chore: share some code --- adapter/inbound/http.go | 4 ++-- component/http/http.go | 2 ++ dns/{patch.go => local.go} | 0 listener/http/client.go | 4 ++-- listener/http/proxy.go | 2 +- listener/http/upgrade.go | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) rename dns/{patch.go => local.go} (100%) diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 2a6050e5..7f3b143f 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -8,11 +8,11 @@ import ( ) // NewHTTP receive normal http request and return HTTPContext -func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { +func NewHTTP(target socks5.Addr, srcConn net.Conn, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP - ApplyAdditions(metadata, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, WithSrcAddr(srcConn.RemoteAddr()), WithInAddr(conn.LocalAddr())) ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/component/http/http.go b/component/http/http.go index 8e682e94..073f0237 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -7,6 +7,7 @@ import ( "net" "net/http" URL "net/url" + "runtime" "strings" "time" @@ -47,6 +48,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st transport := &http.Transport{ // from http.DefaultTransport + DisableKeepAlives: runtime.GOOS == "android", MaxIdleConns: 100, IdleConnTimeout: 30 * time.Second, TLSHandshakeTimeout: 10 * time.Second, diff --git a/dns/patch.go b/dns/local.go similarity index 100% rename from dns/patch.go rename to dns/local.go diff --git a/listener/http/client.go b/listener/http/client.go index 76c7c8eb..84c284ff 100644 --- a/listener/http/client.go +++ b/listener/http/client.go @@ -12,7 +12,7 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -func newClient(source net.Addr, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { +func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { return &http.Client{ Transport: &http.Transport{ // from http.DefaultTransport @@ -32,7 +32,7 @@ func newClient(source net.Addr, tunnel C.Tunnel, additions ...inbound.Addition) left, right := net.Pipe() - go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, source, right, additions...)) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, srcConn, right, additions...)) return left, nil }, diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 44ff04c7..fa1d8f88 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -15,7 +15,7 @@ import ( ) func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { - client := newClient(c.RemoteAddr(), tunnel, additions...) + client := newClient(c, tunnel, additions...) defer client.CloseIdleConnections() conn := N.NewBufferedConn(c) diff --git a/listener/http/upgrade.go b/listener/http/upgrade.go index e67928ce..6e4f063d 100644 --- a/listener/http/upgrade.go +++ b/listener/http/upgrade.go @@ -43,7 +43,7 @@ func handleUpgrade(conn net.Conn, request *http.Request, tunnel C.Tunnel, additi left, right := net.Pipe() - go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right, additions...)) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, conn, right, additions...)) var bufferedLeft *N.BufferedConn if request.TLS != nil { From 01bc84db02f606693343eee9452f00e0744da079 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Mon, 23 Oct 2023 17:02:04 +0800 Subject: [PATCH 052/192] chore: add labels to issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 + .github/ISSUE_TEMPLATE/feature_request.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f8a0f4ae..bd44d025 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,7 @@ name: Bug report description: Create a report to help us improve title: "[Bug] " +labels: ["bug"] body: - type: checkboxes id: ensure diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index c8f70b19..a32d313d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,7 @@ name: Feature request description: Suggest an idea for this project title: "[Feature] " +labels: ["enhancement"] body: - type: checkboxes id: ensure From 875561891064ee1983adfe93d0c39931a66bf48a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 23 Oct 2023 23:33:44 +0800 Subject: [PATCH 053/192] fix: reality panic --- component/tls/reality.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index c995af0a..2902aa4b 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -43,7 +43,8 @@ type RealityConfig struct { func aesgcmPreferred(ciphers []uint16) bool func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) { - if fingerprint, exists := GetFingerprint(ClientFingerprint); exists { + retry := 0 + for fingerprint, exists := GetFingerprint(ClientFingerprint); exists; retry++ { verifier := &realityVerifier{ serverName: tlsConfig.ServerName, } @@ -80,7 +81,15 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) - authKey := uConn.HandshakeState.State13.EcdheParams.SharedKey(realityConfig.PublicKey[:]) + ecdheParams := uConn.HandshakeState.State13.EcdheParams + if ecdheParams == nil { + // WTF??? + if retry > 2 { + return nil, errors.New("nil ecdheParams") + } + continue // retry + } + authKey := ecdheParams.SharedKey(realityConfig.PublicKey[:]) if authKey == nil { return nil, errors.New("nil auth_key") } From e1e999180af7426790747b453bc5081fa480a91e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 24 Oct 2023 21:25:03 +0800 Subject: [PATCH 054/192] chore: inMemoryAuthenticator unneed sync map --- component/auth/auth.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/component/auth/auth.go b/component/auth/auth.go index 9b351606..b52fa135 100644 --- a/component/auth/auth.go +++ b/component/auth/auth.go @@ -1,9 +1,5 @@ package auth -import ( - "github.com/puzpuzpuz/xsync/v2" -) - type Authenticator interface { Verify(user string, pass string) bool Users() []string @@ -15,12 +11,12 @@ type AuthUser struct { } type inMemoryAuthenticator struct { - storage *xsync.MapOf[string, string] + storage map[string]string usernames []string } func (au *inMemoryAuthenticator) Verify(user string, pass string) bool { - realPass, ok := au.storage.Load(user) + realPass, ok := au.storage[user] return ok && realPass == pass } @@ -30,17 +26,13 @@ func NewAuthenticator(users []AuthUser) Authenticator { if len(users) == 0 { return nil } - - au := &inMemoryAuthenticator{storage: xsync.NewMapOf[string]()} - for _, user := range users { - au.storage.Store(user.User, user.Pass) + au := &inMemoryAuthenticator{ + storage: make(map[string]string), + usernames: make([]string, 0, len(users)), + } + for _, user := range users { + au.storage[user.User] = user.Pass + au.usernames = append(au.usernames, user.User) } - usernames := make([]string, 0, len(users)) - au.storage.Range(func(key string, value string) bool { - usernames = append(usernames, key) - return true - }) - au.usernames = usernames - return au } From fc5a3cf80c3352d33ff2a328e97b546fececd5ff Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Tue, 24 Oct 2023 21:53:56 +0800 Subject: [PATCH 055/192] action: ban black issues --- .github/ISSUE_TEMPLATE/config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..3ba13e0c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false From c1f24d8f0ee648ed268b98b037da037a2f8e9fc5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 25 Oct 2023 18:07:45 +0800 Subject: [PATCH 056/192] chore: code cleanup --- dns/client.go | 4 ---- dns/dhcp.go | 9 --------- dns/doh.go | 5 ----- dns/doq.go | 5 ----- dns/rcode.go | 6 +----- dns/resolver.go | 19 +++---------------- dns/util.go | 2 +- 7 files changed, 5 insertions(+), 45 deletions(-) diff --git a/dns/client.go b/dns/client.go index 89f083aa..f228b08e 100644 --- a/dns/client.go +++ b/dns/client.go @@ -48,10 +48,6 @@ func (c *client) Address() string { return c.addr } -func (c *client) Exchange(m *D.Msg) (*D.Msg, error) { - return c.ExchangeContext(context.Background(), m) -} - func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) { var ( ip netip.Addr diff --git a/dns/dhcp.go b/dns/dhcp.go index 7d420d89..e0373ab4 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -11,8 +11,6 @@ import ( "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" - "github.com/Dreamacro/clash/component/resolver" - D "github.com/miekg/dns" ) @@ -46,13 +44,6 @@ func (d *dhcpClient) Address() string { return strings.Join(addrs, ",") } -func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { - ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) - defer cancel() - - return d.ExchangeContext(ctx, m) -} - func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { clients, err := d.resolve(ctx) if err != nil { diff --git a/dns/doh.go b/dns/doh.go index 0d84fc4f..488e9025 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -157,11 +157,6 @@ func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D. return msg, err } -// Exchange implements the Upstream interface for *dnsOverHTTPS. -func (doh *dnsOverHTTPS) Exchange(m *D.Msg) (*D.Msg, error) { - return doh.ExchangeContext(context.Background(), m) -} - // Close implements the Upstream interface for *dnsOverHTTPS. func (doh *dnsOverHTTPS) Close() (err error) { doh.clientMu.Lock() diff --git a/dns/doq.go b/dns/doq.go index afa8259a..76da913f 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -134,11 +134,6 @@ func (doq *dnsOverQUIC) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.M return msg, err } -// Exchange implements the Upstream interface for *dnsOverQUIC. -func (doq *dnsOverQUIC) Exchange(m *D.Msg) (msg *D.Msg, err error) { - return doq.ExchangeContext(context.Background(), m) -} - // Close implements the Upstream interface for *dnsOverQUIC. func (doq *dnsOverQUIC) Close() (err error) { doq.connMu.Lock() diff --git a/dns/rcode.go b/dns/rcode.go index 61fc8d72..9777d2e7 100644 --- a/dns/rcode.go +++ b/dns/rcode.go @@ -39,16 +39,12 @@ type rcodeClient struct { var _ dnsClient = rcodeClient{} -func (r rcodeClient) Exchange(m *D.Msg) (*D.Msg, error) { +func (r rcodeClient) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) { m.Response = true m.Rcode = r.rcode return m, nil } -func (r rcodeClient) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) { - return r.Exchange(m) -} - func (r rcodeClient) Address() string { return r.addr } diff --git a/dns/resolver.go b/dns/resolver.go index 4696515f..f0183c16 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -23,7 +23,6 @@ import ( ) type dnsClient interface { - Exchange(m *D.Msg) (msg *D.Msg, err error) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) Address() string } @@ -136,11 +135,6 @@ func (r *Resolver) shouldIPFallback(ip netip.Addr) bool { return false } -// Exchange a batch of dns request, and it use cache -func (r *Resolver) Exchange(m *D.Msg) (msg *D.Msg, err error) { - return r.ExchangeContext(context.Background(), m) -} - // ExchangeContext a batch of dns request with context.Context, and it use cache func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { if len(m.Question) == 0 { @@ -210,10 +204,10 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M } if matched := r.matchPolicy(m); len(matched) != 0 { - result, cache, err = r.batchExchange(ctx, matched, m) + result, cache, err = batchExchange(ctx, matched, m) return } - result, cache, err = r.batchExchange(ctx, r.main, m) + result, cache, err = batchExchange(ctx, r.main, m) return } @@ -255,13 +249,6 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M return } -func (r *Resolver) batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) { - ctx, cancel := context.WithTimeout(ctx, resolver.DefaultDNSTimeout) - defer cancel() - - return batchExchange(ctx, clients, m) -} - func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient { if r.policy == nil { return nil @@ -385,7 +372,7 @@ func (r *Resolver) lookupIP(ctx context.Context, host string, dnsType uint16) (i func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D.Msg) <-chan *result { ch := make(chan *result, 1) go func() { - res, _, err := r.batchExchange(ctx, client, msg) + res, _, err := batchExchange(ctx, client, msg) ch <- &result{Msg: res, Error: err} }() return ch diff --git a/dns/util.go b/dns/util.go index 433ea9e2..6c196517 100644 --- a/dns/util.go +++ b/dns/util.go @@ -306,7 +306,7 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M domain := msgToDomain(m) for _, client := range clients { if _, isRCodeClient := client.(rcodeClient); isRCodeClient { - msg, err = client.Exchange(m) + msg, err = client.ExchangeContext(ctx, m) return msg, false, err } client := client // shadow define client to ensure the value captured by the closure will not be changed in the next loop From 431d52f2500f413450752d496c2013080fe065fa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 25 Oct 2023 19:20:44 +0800 Subject: [PATCH 057/192] chore: system resolver can autoupdate --- dns/system.go | 116 ++++++++++++++++++++++++++++++++++++++++++++------ dns/util.go | 11 +---- 2 files changed, 104 insertions(+), 23 deletions(-) diff --git a/dns/system.go b/dns/system.go index f5ab0efb..20282929 100644 --- a/dns/system.go +++ b/dns/system.go @@ -1,23 +1,113 @@ package dns import ( + "context" + "fmt" "net" + "strings" + "sync" + "time" + + "github.com/Dreamacro/clash/log" + + D "github.com/miekg/dns" + "golang.org/x/exp/slices" ) -func loadSystemResolver() (clients []dnsClient, err error) { - nameservers, err := dnsReadConfig() +const ( + SystemDnsFlushTime = 5 * time.Minute + SystemDnsDeleteTimes = 12 // 12*5 = 60min +) + +type systemDnsClient struct { + disableTimes uint32 + dnsClient +} + +type systemClient struct { + mu sync.Mutex + dnsClients map[string]*systemDnsClient + lastFlush time.Time +} + +func (c *systemClient) getDnsClients() ([]dnsClient, error) { + c.mu.Lock() + defer c.mu.Unlock() + var err error + if time.Since(c.lastFlush) > SystemDnsFlushTime { + var nameservers []string + if nameservers, err = dnsReadConfig(); err == nil { + log.Debugln("[DNS] system dns update to %s", nameservers) + for _, addr := range nameservers { + if _, ok := c.dnsClients[addr]; !ok { + clients := transform( + []NameServer{{ + Addr: net.JoinHostPort(addr, "53"), + Net: "udp", + }}, + nil, + ) + if len(clients) > 0 { + c.dnsClients[addr] = &systemDnsClient{ + disableTimes: 0, + dnsClient: clients[0], + } + } + } + } + available := 0 + for nameserver, sdc := range c.dnsClients { + if slices.Contains(nameservers, nameserver) { + sdc.disableTimes = 0 // enable + available++ + } else { + if sdc.disableTimes > SystemDnsDeleteTimes { + delete(c.dnsClients, nameserver) // drop too old dnsClient + } else { + sdc.disableTimes++ + } + } + } + if available > 0 { + c.lastFlush = time.Now() + } + } + } + dnsClients := make([]dnsClient, 0, len(c.dnsClients)) + for _, sdc := range c.dnsClients { + if sdc.disableTimes == 0 { + dnsClients = append(dnsClients, sdc.dnsClient) + } + } + if len(dnsClients) > 0 { + return dnsClients, nil + } + return nil, err +} + +func (c *systemClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { + dnsClients, err := c.getDnsClients() if err != nil { return } - if len(nameservers) == 0 { - return - } - servers := make([]NameServer, 0, len(nameservers)) - for _, addr := range nameservers { - servers = append(servers, NameServer{ - Addr: net.JoinHostPort(addr, "53"), - Net: "udp", - }) - } - return transform(servers, nil), nil + msg, _, err = batchExchange(ctx, dnsClients, m) + return +} + +// Address implements dnsClient +func (c *systemClient) Address() string { + dnsClients, _ := c.getDnsClients() + addrs := make([]string, 0, len(dnsClients)) + for _, c := range dnsClients { + addrs = append(addrs, c.Address()) + } + return fmt.Sprintf("system(%s)", strings.Join(addrs, ",")) +} + +var _ dnsClient = (*systemClient)(nil) + +func newSystemClient() *systemClient { + return &systemClient{ + dnsClients: map[string]*systemDnsClient{}, + } } diff --git a/dns/util.go b/dns/util.go index 6c196517..e8bdfd0b 100644 --- a/dns/util.go +++ b/dns/util.go @@ -107,16 +107,7 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { ret = append(ret, newDHCPClient(s.Addr)) continue case "system": - clients, err := loadSystemResolver() - if err != nil { - log.Errorln("[DNS:system] load system resolver failed: %s", err.Error()) - continue - } - if len(clients) == 0 { - log.Errorln("[DNS:system] no nameserver found in system") - continue - } - ret = append(ret, clients...) + ret = append(ret, newSystemClient()) continue case "rcode": ret = append(ret, newRCodeClient(s.Addr)) From 55f626424f944aedb2d7690dd10002d94c2b851f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 25 Oct 2023 20:16:44 +0800 Subject: [PATCH 058/192] chore: better dns batchExchange --- dns/util.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/dns/util.go b/dns/util.go index e8bdfd0b..668a3a2e 100644 --- a/dns/util.go +++ b/dns/util.go @@ -290,11 +290,14 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st return proxyAdapter.ListenPacketContext(ctx, metadata, opts...) } +var errIPNotFound = errors.New("couldn't find ip") + func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) { cache = true fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) defer fast.Close() domain := msgToDomain(m) + var noIpMsg *D.Msg for _, client := range clients { if _, isRCodeClient := client.(rcodeClient); isRCodeClient { msg, err = client.ExchangeContext(ctx, m) @@ -311,13 +314,31 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M // so we would ignore RCode errors from RCode clients. return nil, errors.New("server failure: " + D.RcodeToString[m.Rcode]) } - log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), client.Address()) + if ips := msgToIP(m); len(m.Question) > 0 { + qType := m.Question[0].Qtype + log.Debugln("[DNS] %s --> %s %s from %s", domain, ips, D.Type(qType), client.Address()) + switch qType { + case D.TypeAAAA: + if len(ips) == 0 { + noIpMsg = m + return nil, errIPNotFound + } + case D.TypeA: + if len(ips) == 0 { + noIpMsg = m + return nil, errIPNotFound + } + } + } return m, nil }) } msg = fast.Wait() if msg == nil { + if noIpMsg != nil { + return noIpMsg, false, nil + } err = errors.New("all DNS requests failed") if fErr := fast.Error(); fErr != nil { err = fmt.Errorf("%w, first error: %w", err, fErr) From cf93f69f40c7de2b298829671140cccd2e9e20e7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 09:07:49 +0800 Subject: [PATCH 059/192] chore: cleanup error using of dialer.DefaultInterface --- common/atomic/value.go | 7 +++++++ config/config.go | 2 -- dns/client.go | 7 +++---- dns/dhcp.go | 3 +-- dns/resolver.go | 3 +-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/common/atomic/value.go b/common/atomic/value.go index 95733533..708fcf90 100644 --- a/common/atomic/value.go +++ b/common/atomic/value.go @@ -12,6 +12,7 @@ func DefaultValue[T any]() T { type TypedValue[T any] struct { value atomic.Value + _ noCopy } func (t *TypedValue[T]) Load() T { @@ -55,3 +56,9 @@ func NewTypedValue[T any](t T) (v TypedValue[T]) { v.Store(t) return } + +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} +func (*noCopy) Unlock() {} diff --git a/config/config.go b/config/config.go index 97a193a1..994f897d 100644 --- a/config/config.go +++ b/config/config.go @@ -20,7 +20,6 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/auth" - "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata/router" @@ -1048,7 +1047,6 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) Net: dnsNetType, Addr: addr, ProxyName: proxyName, - Interface: dialer.DefaultInterface, Params: params, PreferH3: preferH3, }, diff --git a/dns/client.go b/dns/client.go index f228b08e..5cdd1ec0 100644 --- a/dns/client.go +++ b/dns/client.go @@ -8,7 +8,6 @@ import ( "net/netip" "strings" - "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" @@ -23,7 +22,7 @@ type client struct { r *Resolver port string host string - iface atomic.TypedValue[string] + iface string proxyAdapter C.ProxyAdapter proxyName string addr string @@ -74,8 +73,8 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) } var options []dialer.Option - if c.iface.Load() != "" { - options = append(options, dialer.WithInterface(c.iface.Load())) + if c.iface != "" { + options = append(options, dialer.WithInterface(c.iface)) } conn, err := getDialHandler(c.r, c.proxyAdapter, c.proxyName, options...)(ctx, network, net.JoinHostPort(ip.String(), c.port)) diff --git a/dns/dhcp.go b/dns/dhcp.go index e0373ab4..2fa2e8a4 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" D "github.com/miekg/dns" @@ -77,7 +76,7 @@ func (d *dhcpClient) resolve(ctx context.Context) ([]dnsClient, error) { for _, item := range dns { nameserver = append(nameserver, NameServer{ Addr: net.JoinHostPort(item.String(), "53"), - Interface: atomic.NewTypedValue(d.ifaceName), + Interface: d.ifaceName, }) } diff --git a/dns/resolver.go b/dns/resolver.go index f0183c16..2851f012 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata/router" @@ -389,7 +388,7 @@ func (r *Resolver) Invalid() bool { type NameServer struct { Net string Addr string - Interface atomic.TypedValue[string] + Interface string ProxyAdapter C.ProxyAdapter ProxyName string Params map[string]string From 4314b37d0445091acd20f0b4b75a96890bd61240 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 10:27:38 +0800 Subject: [PATCH 060/192] fix: dhcp not working on windows --- component/dhcp/conn.go | 12 +++++++- component/dialer/bind.go | 50 +++++++++++++++++++++++++++++++++ component/dialer/bind_others.go | 47 +++---------------------------- component/dialer/dialer.go | 12 ++++++-- component/dialer/options.go | 7 +++++ dns/util.go | 2 +- 6 files changed, 83 insertions(+), 47 deletions(-) diff --git a/component/dhcp/conn.go b/component/dhcp/conn.go index 90a9e25b..5b71d3cd 100644 --- a/component/dhcp/conn.go +++ b/component/dhcp/conn.go @@ -14,5 +14,15 @@ func ListenDHCPClient(ctx context.Context, ifaceName string) (net.PacketConn, er listenAddr = "255.255.255.255:68" } - return dialer.ListenPacket(ctx, "udp4", listenAddr, dialer.WithInterface(ifaceName), dialer.WithAddrReuse(true)) + options := []dialer.Option{ + dialer.WithInterface(ifaceName), + dialer.WithAddrReuse(true), + } + + // fallback bind on windows, because syscall bind can not receive broadcast + if runtime.GOOS == "windows" { + options = append(options, dialer.WithFallbackBind(true)) + } + + return dialer.ListenPacket(ctx, "udp4", listenAddr, options...) } diff --git a/component/dialer/bind.go b/component/dialer/bind.go index edfc79c7..4accabb3 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -3,6 +3,7 @@ package dialer import ( "net" "net/netip" + "strconv" "strings" "github.com/Dreamacro/clash/component/iface" @@ -49,3 +50,52 @@ func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination return nil, iface.ErrAddrNotFound } + +func fallbackBindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { + if !destination.IsGlobalUnicast() { + return nil + } + + local := uint64(0) + if dialer.LocalAddr != nil { + _, port, err := net.SplitHostPort(dialer.LocalAddr.String()) + if err == nil { + local, _ = strconv.ParseUint(port, 10, 16) + } + } + + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local)) + if err != nil { + return err + } + + dialer.LocalAddr = addr + + return nil +} + +func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) { + _, port, err := net.SplitHostPort(address) + if err != nil { + port = "0" + } + + local, _ := strconv.ParseUint(port, 10, 16) + + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local)) + if err != nil { + return "", err + } + + return addr.String(), nil +} + +func fallbackParseNetwork(network string, addr netip.Addr) string { + // fix fallbackBindIfaceToListenConfig() force bind to an ipv4 address + if !strings.HasSuffix(network, "4") && + !strings.HasSuffix(network, "6") && + addr.Unmap().Is6() { + network += "6" + } + return network +} diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go index 5fd02a66..44181610 100644 --- a/component/dialer/bind_others.go +++ b/component/dialer/bind_others.go @@ -5,55 +5,16 @@ package dialer import ( "net" "net/netip" - "strconv" - "strings" ) func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { - if !destination.IsGlobalUnicast() { - return nil - } - - local := uint64(0) - if dialer.LocalAddr != nil { - _, port, err := net.SplitHostPort(dialer.LocalAddr.String()) - if err == nil { - local, _ = strconv.ParseUint(port, 10, 16) - } - } - - addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local)) - if err != nil { - return err - } - - dialer.LocalAddr = addr - - return nil + return fallbackBindIfaceToDialer(ifaceName, dialer, network, destination) } -func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) { - _, port, err := net.SplitHostPort(address) - if err != nil { - port = "0" - } - - local, _ := strconv.ParseUint(port, 10, 16) - - addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local)) - if err != nil { - return "", err - } - - return addr.String(), nil +func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, network, address string) (string, error) { + return fallbackBindIfaceToListenConfig(ifaceName, lc, network, address) } func ParseNetwork(network string, addr netip.Addr) string { - // fix bindIfaceToListenConfig() force bind to an ipv4 address - if !strings.HasSuffix(network, "4") && - !strings.HasSuffix(network, "6") && - addr.Unmap().Is6() { - network += "6" - } - return network + return fallbackParseNetwork(network, addr) } diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 0cfa1b6c..3cb8bba9 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -74,7 +74,11 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio lc := &net.ListenConfig{} if cfg.interfaceName != "" { - addr, err := bindIfaceToListenConfig(cfg.interfaceName, lc, network, address) + bind := bindIfaceToListenConfig + if cfg.fallbackBind { + bind = fallbackBindIfaceToListenConfig + } + addr, err := bind(cfg.interfaceName, lc, network, address) if err != nil { return nil, err } @@ -125,7 +129,11 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po dialer := netDialer.(*net.Dialer) if opt.interfaceName != "" { - if err := bindIfaceToDialer(opt.interfaceName, dialer, network, destination); err != nil { + bind := bindIfaceToDialer + if opt.fallbackBind { + bind = fallbackBindIfaceToDialer + } + if err := bind(opt.interfaceName, dialer, network, destination); err != nil { return nil, err } } diff --git a/component/dialer/options.go b/component/dialer/options.go index 30771e71..781d7164 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -20,6 +20,7 @@ type NetDialer interface { type option struct { interfaceName string + fallbackBind bool addrReuse bool routingMark int network int @@ -38,6 +39,12 @@ func WithInterface(name string) Option { } } +func WithFallbackBind(fallback bool) Option { + return func(opt *option) { + opt.fallbackBind = fallback + } +} + func WithAddrReuse(reuse bool) Option { return func(opt *option) { opt.addrReuse = reuse diff --git a/dns/util.go b/dns/util.go index 668a3a2e..34f7aa94 100644 --- a/dns/util.go +++ b/dns/util.go @@ -280,7 +280,7 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st DstPort: uint16(uintPort), } if proxyAdapter == nil { - return dialer.NewDialer(opts...).ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) + return dialer.NewDialer(opts...).ListenPacket(ctx, network, "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) } if !proxyAdapter.SupportUDP() { From bffe47a9746c286c982091c21e61a84b1cd20841 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 10:39:54 +0800 Subject: [PATCH 061/192] chore: netip.Prefix should not using pointer --- component/dialer/bind.go | 2 +- component/fakeip/pool.go | 8 ++++---- component/fakeip/pool_test.go | 24 ++++++++++++------------ component/iface/iface.go | 24 ++++++++++++------------ config/config.go | 12 ++++++------ dns/dhcp.go | 2 +- dns/filters.go | 2 +- dns/resolver.go | 2 +- rules/common/ipcidr.go | 4 ++-- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/component/dialer/bind.go b/component/dialer/bind.go index 4accabb3..c90212ef 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -15,7 +15,7 @@ func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination return nil, err } - var addr *netip.Prefix + var addr netip.Prefix switch network { case "udp4", "tcp4": addr, err = ifaceObj.PickIPv4Addr(destination) diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index ee11fedd..9b51929e 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -36,7 +36,7 @@ type Pool struct { cycle bool mux sync.Mutex host *trie.DomainTrie[struct{}] - ipnet *netip.Prefix + ipnet netip.Prefix store store } @@ -91,7 +91,7 @@ func (p *Pool) Broadcast() netip.Addr { } // IPNet return raw ipnet -func (p *Pool) IPNet() *netip.Prefix { +func (p *Pool) IPNet() netip.Prefix { return p.ipnet } @@ -153,7 +153,7 @@ func (p *Pool) restoreState() { } type Options struct { - IPNet *netip.Prefix + IPNet netip.Prefix Host *trie.DomainTrie[struct{}] // Size sets the maximum number of entries in memory @@ -171,7 +171,7 @@ func New(options Options) (*Pool, error) { hostAddr = options.IPNet.Masked().Addr() gateway = hostAddr.Next() first = gateway.Next().Next().Next() // default start with 198.18.0.4 - last = nnip.UnMasked(*options.IPNet) + last = nnip.UnMasked(options.IPNet) ) if !options.IPNet.IsValid() || !first.IsValid() || !first.Less(last) { diff --git a/component/fakeip/pool_test.go b/component/fakeip/pool_test.go index ae343f96..183a7185 100644 --- a/component/fakeip/pool_test.go +++ b/component/fakeip/pool_test.go @@ -51,7 +51,7 @@ func createCachefileStore(options Options) (*Pool, string, error) { func TestPool_Basic(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.0/28") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -79,7 +79,7 @@ func TestPool_Basic(t *testing.T) { func TestPool_BasicV6(t *testing.T) { ipnet := netip.MustParsePrefix("2001:4860:4860::8888/118") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -107,7 +107,7 @@ func TestPool_BasicV6(t *testing.T) { func TestPool_Case_Insensitive(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/29") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -128,7 +128,7 @@ func TestPool_Case_Insensitive(t *testing.T) { func TestPool_CycleUsed(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.16/28") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -152,7 +152,7 @@ func TestPool_Skip(t *testing.T) { tree := trie.New[struct{}]() tree.Insert("example.com", struct{}{}) pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, Host: tree, }) @@ -168,7 +168,7 @@ func TestPool_Skip(t *testing.T) { func TestPool_MaxCacheSize(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/24") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) @@ -183,7 +183,7 @@ func TestPool_MaxCacheSize(t *testing.T) { func TestPool_DoubleMapping(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/24") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) @@ -213,7 +213,7 @@ func TestPool_DoubleMapping(t *testing.T) { func TestPool_Clone(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/24") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) @@ -223,7 +223,7 @@ func TestPool_Clone(t *testing.T) { assert.True(t, last == netip.AddrFrom4([4]byte{192, 168, 0, 5})) newPool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) newPool.CloneFrom(pool) @@ -236,7 +236,7 @@ func TestPool_Clone(t *testing.T) { func TestPool_Error(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/31") _, err := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) @@ -246,7 +246,7 @@ func TestPool_Error(t *testing.T) { func TestPool_FlushFileCache(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/28") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -278,7 +278,7 @@ func TestPool_FlushFileCache(t *testing.T) { func TestPool_FlushMemoryCache(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/28") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) diff --git a/component/iface/iface.go b/component/iface/iface.go index c32b65ab..03051cb3 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -13,7 +13,7 @@ import ( type Interface struct { Index int Name string - Addrs []*netip.Prefix + Addrs []netip.Prefix HardwareAddr net.HardwareAddr } @@ -43,7 +43,7 @@ func ResolveInterface(name string) (*Interface, error) { continue } - ipNets := make([]*netip.Prefix, 0, len(addrs)) + ipNets := make([]netip.Prefix, 0, len(addrs)) for _, addr := range addrs { ipNet := addr.(*net.IPNet) ip, _ := netip.AddrFromSlice(ipNet.IP) @@ -59,7 +59,7 @@ func ResolveInterface(name string) (*Interface, error) { } pf := netip.PrefixFrom(ip, ones) - ipNets = append(ipNets, &pf) + ipNets = append(ipNets, pf) } r[iface.Name] = &Interface{ @@ -89,27 +89,27 @@ func FlushCache() { interfaces.Reset() } -func (iface *Interface) PickIPv4Addr(destination netip.Addr) (*netip.Prefix, error) { - return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool { +func (iface *Interface) PickIPv4Addr(destination netip.Addr) (netip.Prefix, error) { + return iface.pickIPAddr(destination, func(addr netip.Prefix) bool { return addr.Addr().Is4() }) } -func (iface *Interface) PickIPv6Addr(destination netip.Addr) (*netip.Prefix, error) { - return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool { +func (iface *Interface) PickIPv6Addr(destination netip.Addr) (netip.Prefix, error) { + return iface.pickIPAddr(destination, func(addr netip.Prefix) bool { return addr.Addr().Is6() }) } -func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr *netip.Prefix) bool) (*netip.Prefix, error) { - var fallback *netip.Prefix +func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr netip.Prefix) bool) (netip.Prefix, error) { + var fallback netip.Prefix for _, addr := range iface.Addrs { if !accept(addr) { continue } - if fallback == nil && !addr.Addr().IsLinkLocalUnicast() { + if !fallback.IsValid() && !addr.Addr().IsLinkLocalUnicast() { fallback = addr if !destination.IsValid() { @@ -122,8 +122,8 @@ func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr *net } } - if fallback == nil { - return nil, ErrAddrNotFound + if !fallback.IsValid() { + return netip.Prefix{}, ErrAddrNotFound } return fallback, nil diff --git a/config/config.go b/config/config.go index 994f897d..ed2505d9 100644 --- a/config/config.go +++ b/config/config.go @@ -122,7 +122,7 @@ type DNS struct { type FallbackFilter struct { GeoIP bool `yaml:"geoip"` GeoIPCode string `yaml:"geoip-code"` - IPCIDR []*netip.Prefix `yaml:"ipcidr"` + IPCIDR []netip.Prefix `yaml:"ipcidr"` Domain []string `yaml:"domain"` GeoSite []*router.DomainMatcher `yaml:"geosite"` } @@ -1148,15 +1148,15 @@ func parseNameServerPolicy(nsPolicy map[string]any, ruleProviders map[string]pro return policy, nil } -func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) { - var ipNets []*netip.Prefix +func parseFallbackIPCIDR(ips []string) ([]netip.Prefix, error) { + var ipNets []netip.Prefix for idx, ip := range ips { ipnet, err := netip.ParsePrefix(ip) if err != nil { return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error()) } - ipNets = append(ipNets, &ipnet) + ipNets = append(ipNets, ipnet) } return ipNets, nil @@ -1224,7 +1224,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul IPv6: cfg.IPv6, EnhancedMode: cfg.EnhancedMode, FallbackFilter: FallbackFilter{ - IPCIDR: []*netip.Prefix{}, + IPCIDR: []netip.Prefix{}, GeoSite: []*router.DomainMatcher{}, }, } @@ -1298,7 +1298,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul } pool, err := fakeip.New(fakeip.Options{ - IPNet: &fakeIPRange, + IPNet: fakeIPRange, Size: 1000, Host: host, Persistence: rawCfg.Profile.StoreFakeIP, diff --git a/dns/dhcp.go b/dns/dhcp.go index 2fa2e8a4..70f9aeeb 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -26,7 +26,7 @@ type dhcpClient struct { ifaceInvalidate time.Time dnsInvalidate time.Time - ifaceAddr *netip.Prefix + ifaceAddr netip.Prefix done chan struct{} clients []dnsClient err error diff --git a/dns/filters.go b/dns/filters.go index 47e7adcd..f7e953e8 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -45,7 +45,7 @@ func (gf *geoipFilter) Match(ip netip.Addr) bool { } type ipnetFilter struct { - ipnet *netip.Prefix + ipnet netip.Prefix } func (inf *ipnetFilter) Match(ip netip.Addr) bool { diff --git a/dns/resolver.go b/dns/resolver.go index 2851f012..d27f7bcc 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -398,7 +398,7 @@ type NameServer struct { type FallbackFilter struct { GeoIP bool GeoIPCode string - IPCIDR []*netip.Prefix + IPCIDR []netip.Prefix Domain []string GeoSite []*router.DomainMatcher } diff --git a/rules/common/ipcidr.go b/rules/common/ipcidr.go index 8ab6cf5a..4cdf9106 100644 --- a/rules/common/ipcidr.go +++ b/rules/common/ipcidr.go @@ -22,7 +22,7 @@ func WithIPCIDRNoResolve(noResolve bool) IPCIDROption { type IPCIDR struct { *Base - ipnet *netip.Prefix + ipnet netip.Prefix adapter string isSourceIP bool noResolveIP bool @@ -63,7 +63,7 @@ func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) ipcidr := &IPCIDR{ Base: &Base{}, - ipnet: &ipnet, + ipnet: ipnet, adapter: adapter, } From c3a61e2db5f38c29139e9a77a1be3ee7f277d7ac Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 11:09:19 +0800 Subject: [PATCH 062/192] build: add go120 build for win7/8.1 --- .github/rename-go120.sh | 12 ++++++++++++ .github/workflows/build.yml | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 .github/rename-go120.sh diff --git a/.github/rename-go120.sh b/.github/rename-go120.sh new file mode 100644 index 00000000..136d74b5 --- /dev/null +++ b/.github/rename-go120.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +FILENAMES=$(ls) +for FILENAME in $FILENAMES +do + if [[ ! ($FILENAME =~ ".exe" || $FILENAME =~ ".sh")]];then + mc $FILENAME ${FILENAME}-go120 + elif [[ $FILENAME =~ ".exe" ]];then + mv $FILENAME ${FILENAME%.*}-go120.exe + else echo "skip $FILENAME" + fi +done \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index defd294b..df603041 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,6 +69,8 @@ jobs: target: "darwin-amd64 darwin-arm64 android-arm64", id: "9", } + # Go 1.21 requires at least Windows 10 or Windows Server 2016; support for previous versions has been discontinued. + - { type: "WithoutCGO-GO120", target: "windows-amd64-compatible windows-amd64 windows-386",id: "10" } - { type: "WithCGO", target: "windows/*", id: "1" } - { type: "WithCGO", target: "linux/386", id: "2" } - { type: "WithCGO", target: "linux/amd64", id: "3" } @@ -126,18 +128,26 @@ jobs: shell: bash - name: Setup Go + if: ${{ matrix.job.type!='WithoutCGO-GO120' }} uses: actions/setup-go@v4 with: go-version: "1.21" check-latest: true + - name: Setup Go + if: ${{ matrix.job.type=='WithoutCGO-GO120' }} + uses: actions/setup-go@v4 + with: + go-version: "1.20" + check-latest: true + - name: Test if: ${{ matrix.job.id=='1' && matrix.job.type=='WithoutCGO' }} run: | go test ./... - name: Build WithoutCGO - if: ${{ matrix.job.type=='WithoutCGO' }} + if: ${{ matrix.job.type!='WithCGO' }} env: NAME: Clash.Meta BINDIR: bin @@ -185,6 +195,17 @@ jobs: ls -la cd .. + - name: Rename + if: ${{ matrix.job.type=='WithoutCGO-GO120' }} + run: | + cd bin + ls -la + cp ../.github/rename-go120.sh ./ + bash ./rename-go120.sh + rm ./rename-go120.sh + ls -la + cd .. + - name: Zip if: ${{ success() }} run: | From 81a8a63861c56f1b81f59bc6b53d62d556a06baa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 11:39:54 +0800 Subject: [PATCH 063/192] build: more go120 build --- .github/rename-go120.sh | 2 +- .github/workflows/build.yml | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/rename-go120.sh b/.github/rename-go120.sh index 136d74b5..eddb1769 100644 --- a/.github/rename-go120.sh +++ b/.github/rename-go120.sh @@ -4,7 +4,7 @@ FILENAMES=$(ls) for FILENAME in $FILENAMES do if [[ ! ($FILENAME =~ ".exe" || $FILENAME =~ ".sh")]];then - mc $FILENAME ${FILENAME}-go120 + mv $FILENAME ${FILENAME}-go120 elif [[ $FILENAME =~ ".exe" ]];then mv $FILENAME ${FILENAME%.*}-go120.exe else echo "skip $FILENAME" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index df603041..57a00f3e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,8 +69,12 @@ jobs: target: "darwin-amd64 darwin-arm64 android-arm64", id: "9", } - # Go 1.21 requires at least Windows 10 or Windows Server 2016; support for previous versions has been discontinued. - - { type: "WithoutCGO-GO120", target: "windows-amd64-compatible windows-amd64 windows-386",id: "10" } + # only for test + - { type: "WithoutCGO-GO120", target: "linux-amd64 linux-amd64-compatible",id: "1" } + # Go 1.20 is the last release that will run on any release of Windows 7, 8, Server 2008 and Server 2012. Go 1.21 will require at least Windows 10 or Server 2016. + - { type: "WithoutCGO-GO120", target: "windows-amd64-compatible windows-amd64 windows-386",id: "2" } + # Go 1.20 is the last release that will run on macOS 10.13 High Sierra or 10.14 Mojave. Go 1.21 will require macOS 10.15 Catalina or later. + - { type: "WithoutCGO-GO120", target: "darwin-amd64 darwin-arm64 android-arm64",id: "3" } - { type: "WithCGO", target: "windows/*", id: "1" } - { type: "WithCGO", target: "linux/386", id: "2" } - { type: "WithCGO", target: "linux/amd64", id: "3" } @@ -142,7 +146,7 @@ jobs: check-latest: true - name: Test - if: ${{ matrix.job.id=='1' && matrix.job.type=='WithoutCGO' }} + if: ${{ matrix.job.id=='1' && matrix.job.type!='WithCGO' }} run: | go test ./... From d42e3f74ad89ef7827f4b7861efd0cdf880a8cde Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Thu, 26 Oct 2023 19:08:03 +0800 Subject: [PATCH 064/192] action: add question issue guidance --- .github/ISSUE_TEMPLATE/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3ba13e0c..0cf54628 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,5 @@ blank_issues_enabled: false +contact_links: + - name: Clash.Meta Community Support + url: https://github.com/MetaCubeX/Clash.Meta/discussions + about: Please ask and answer questions about Clash.Meta here. From 55255faa52455fdc51ae2037f3fc885f2cecb5b8 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Fri, 27 Oct 2023 17:49:12 +0800 Subject: [PATCH 065/192] chore: modify configuration fields --- config/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index ed2505d9..e467c603 100644 --- a/config/config.go +++ b/config/config.go @@ -231,8 +231,8 @@ type RawTun struct { //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6_route_address" json:"inet6_route_address,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` From 2b9141e0e56c749382f3cd4c3bc1377b8b48206a Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Mon, 30 Oct 2023 19:46:56 +0800 Subject: [PATCH 066/192] chore: geo link replaced with github --- config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index e467c603..6b324286 100644 --- a/config/config.go +++ b/config/config.go @@ -461,9 +461,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { StoreSelected: true, }, GeoXUrl: GeoXUrl{ - Mmdb: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb", - GeoIp: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat", - GeoSite: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat", + Mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + GeoIp: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", + GeoSite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", }, ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip", } From 261b6e8dce1f5d3519282b87bb4f53ba6d5b1dd9 Mon Sep 17 00:00:00 2001 From: Steve Johnson <144257728+stevejohnson7@users.noreply.github.com> Date: Mon, 30 Oct 2023 20:00:15 +0800 Subject: [PATCH 067/192] action: small fix to cmfa core-update trigger --- .github/workflows/cmfa-update-deps-trigger.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmfa-update-deps-trigger.yml b/.github/workflows/cmfa-update-deps-trigger.yml index 51736644..549b0098 100644 --- a/.github/workflows/cmfa-update-deps-trigger.yml +++ b/.github/workflows/cmfa-update-deps-trigger.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: push: tags: - - "v*" + - "*" pull_request_target: branches: - Alpha @@ -25,4 +25,4 @@ jobs: -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ -d '{"event_type": "core-updated"}' # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies - \ No newline at end of file + From 8ff476a3a1f2166d93bc0dda58b0350a970c3032 Mon Sep 17 00:00:00 2001 From: HolgerHuo Date: Tue, 31 Oct 2023 04:07:01 -0700 Subject: [PATCH 068/192] fix: remote logic rules cannot be parsed (#837) --- rules/provider/classical_strategy.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index e187e213..032204e4 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -76,7 +76,11 @@ func ruleParse(ruleRaw string) (string, string, []string) { } else if len(item) == 2 { return item[0], item[1], nil } else if len(item) > 2 { - return item[0], item[1], item[2:] + if item[0] == "NOT" || item[0] == "OR" || item[0] == "AND" || item[0] == "SUB-RULE" { + return item[0], strings.Join(item[1:len(item)], ","), nil + } else { + return item[0], item[1], item[2:] + } } return "", "", nil From 96220aa8eaaf01a4117e23d6cdb79c86245350d2 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 31 Oct 2023 11:10:38 +0000 Subject: [PATCH 069/192] feat: cancel RULE-SET nested SUB-RULE restrictions --- rules/provider/classical_strategy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index 032204e4..6561f12f 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -89,7 +89,7 @@ func ruleParse(ruleRaw string) (string, string, []string) { func NewClassicalStrategy(parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) *classicalStrategy { return &classicalStrategy{rules: []C.Rule{}, parse: func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) { switch tp { - case "MATCH", "SUB-RULE": + case "MATCH": return nil, fmt.Errorf("unsupported rule type on rule-set") default: return parse(tp, payload, target, params, nil) From b0638cfc49500f63eef6c8ef27d48b559dac7f3b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 10:31:58 +0800 Subject: [PATCH 070/192] chore: better bufio.Reader warp --- common/net/bufconn.go | 10 ++++++++++ transport/vmess/websocket.go | 23 ++++++++++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 6da2d9d1..b840fefc 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -22,6 +22,16 @@ func NewBufferedConn(c net.Conn) *BufferedConn { return &BufferedConn{bufio.NewReader(c), NewExtendedConn(c), false} } +func WarpConnWithBioReader(c net.Conn, br *bufio.Reader) net.Conn { + if br != nil && br.Buffered() > 0 { + if bc, ok := c.(*BufferedConn); ok && bc.r == br { + return bc + } + return &BufferedConn{br, NewExtendedConn(c), true} + } + return c +} + // Reader returns the internal bufio.Reader. func (c *BufferedConn) Reader() *bufio.Reader { return c.r diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 83f5e3c2..1117edaf 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -1,7 +1,6 @@ package vmess import ( - "bufio" "bytes" "context" "crypto/tls" @@ -393,7 +392,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return nil, fmt.Errorf("dial %s error: %w", uri.Host, err) } - conn = newWebsocketConn(conn, reader, ws.StateClientSide) + // some bytes which could be written by the peer right after response and be caught by us during buffered read, + // so we need warp Conn with bio.Reader + conn = N.WarpConnWithBioReader(conn, reader) + + conn = newWebsocketConn(conn, ws.StateClientSide) // websocketConn can't correct handle ReadDeadline // so call N.NewDeadlineConn to add a safe wrapper return N.NewDeadlineConn(conn), nil @@ -419,19 +422,13 @@ func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) return streamWebsocketConn(ctx, conn, c, nil) } -func newWebsocketConn(conn net.Conn, br *bufio.Reader, state ws.State) *websocketConn { +func newWebsocketConn(conn net.Conn, state ws.State) *websocketConn { controlHandler := wsutil.ControlFrameHandler(conn, state) - var reader io.Reader - if br != nil && br.Buffered() > 0 { - reader = br - } else { - reader = conn - } return &websocketConn{ Conn: conn, state: state, reader: &wsutil.Reader{ - Source: reader, + Source: conn, State: state, SkipHeaderCheck: true, CheckUTF8: false, @@ -463,7 +460,11 @@ func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Co if err != nil { return nil, err } - conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) + + // gobwas/ws will flush rw.Writer, so we only need warp rw.Reader + wsConn = N.WarpConnWithBioReader(wsConn, rw.Reader) + + conn := newWebsocketConn(wsConn, ws.StateServerSide) if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 { return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil } From ceac5bfaa4971c2e8215c9796b3fa96fab6b2828 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 11:11:19 +0800 Subject: [PATCH 071/192] feat: add `v2ray-http-upgrade` support --- adapter/outbound/shadowsocks.go | 26 ++++++++++--------- adapter/outbound/trojan.go | 7 ++--- adapter/outbound/vless.go | 1 + adapter/outbound/vmess.go | 2 ++ docs/config.yaml | 40 ++++++++++++++++------------- transport/trojan/trojan.go | 10 +++++--- transport/v2ray-plugin/websocket.go | 26 ++++++++++--------- transport/vmess/websocket.go | 34 ++++++++++++++++++++++++ 8 files changed, 97 insertions(+), 49 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 40868d04..1ae16c43 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -58,14 +58,15 @@ type simpleObfsOption struct { } type v2rayObfsOption struct { - Mode string `obfs:"mode"` - Host string `obfs:"host,omitempty"` - Path string `obfs:"path,omitempty"` - TLS bool `obfs:"tls,omitempty"` - Fingerprint string `obfs:"fingerprint,omitempty"` - Headers map[string]string `obfs:"headers,omitempty"` - SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` - Mux bool `obfs:"mux,omitempty"` + Mode string `obfs:"mode"` + Host string `obfs:"host,omitempty"` + Path string `obfs:"path,omitempty"` + TLS bool `obfs:"tls,omitempty"` + Fingerprint string `obfs:"fingerprint,omitempty"` + Headers map[string]string `obfs:"headers,omitempty"` + SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Mux bool `obfs:"mux,omitempty"` + V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"` } type shadowTLSOption struct { @@ -259,10 +260,11 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } obfsMode = opts.Mode v2rayOption = &v2rayObfs.Option{ - Host: opts.Host, - Path: opts.Path, - Headers: opts.Headers, - Mux: opts.Mux, + Host: opts.Host, + Path: opts.Path, + Headers: opts.Headers, + Mux: opts.Mux, + V2rayHttpUpgrade: opts.V2rayHttpUpgrade, } if opts.TLS { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 337f2a38..d3c14e8a 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -53,9 +53,10 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) if t.option.Network == "ws" { host, port, _ := net.SplitHostPort(t.addr) wsOpts := &trojan.WebsocketOption{ - Host: host, - Port: port, - Path: t.option.WSOpts.Path, + Host: host, + Port: port, + Path: t.option.WSOpts.Path, + V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade, } if t.option.SNI != "" { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 037f3367..5f54153b 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -93,6 +93,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M Path: v.option.WSOpts.Path, MaxEarlyData: v.option.WSOpts.MaxEarlyData, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, ClientFingerprint: v.option.ClientFingerprint, Headers: http.Header{}, } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 326f0c6f..aed61aa3 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -91,6 +91,7 @@ type WSOptions struct { Headers map[string]string `proxy:"headers,omitempty"` MaxEarlyData int `proxy:"max-early-data,omitempty"` EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` + V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"` } // StreamConnContext implements C.ProxyAdapter @@ -110,6 +111,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M Path: v.option.WSOpts.Path, MaxEarlyData: v.option.WSOpts.MaxEarlyData, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, ClientFingerprint: v.option.ClientFingerprint, Headers: http.Header{}, } diff --git a/docs/config.yaml b/docs/config.yaml index 80fc2995..61a2dee9 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -352,16 +352,17 @@ proxies: # socks5 plugin: v2ray-plugin plugin-opts: mode: websocket # no QUIC now - # tls: true # wss - # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 - # 配置指纹将实现 SSL Pining 效果 - # fingerprint: xxxx - # skip-cert-verify: true - # host: bing.com - # path: "/" - # mux: true - # headers: - # custom: value + # tls: true # wss + # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 + # 配置指纹将实现 SSL Pining 效果 + # fingerprint: xxxx + # skip-cert-verify: true + # host: bing.com + # path: "/" + # mux: true + # headers: + # custom: value + # v2ray-http-upgrade: false - name: "ss4-shadow-tls" type: ss @@ -434,11 +435,12 @@ proxies: # socks5 # servername: example.com # priority over wss host # network: ws # ws-opts: - # path: /path - # headers: - # Host: v2ray.com - # max-early-data: 2048 - # early-data-header-name: Sec-WebSocket-Protocol + # path: /path + # headers: + # Host: v2ray.com + # max-early-data: 2048 + # early-data-header-name: Sec-WebSocket-Protocol + # v2ray-http-upgrade: false - name: "vmess-h2" type: vmess @@ -566,6 +568,7 @@ proxies: # socks5 path: "/" headers: Host: example.com + # v2ray-http-upgrade: false # Trojan - name: "trojan" @@ -606,9 +609,10 @@ proxies: # socks5 # fingerprint: xxxx udp: true # ws-opts: - # path: /path - # headers: - # Host: example.com + # path: /path + # headers: + # Host: example.com + # v2ray-http-upgrade: false - name: "trojan-xtls" type: trojan diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 6dfcfe11..20ba80b3 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -55,10 +55,11 @@ type Option struct { } type WebsocketOption struct { - Host string - Port string - Path string - Headers http.Header + Host string + Port string + Path string + Headers http.Header + V2rayHttpUpgrade bool } type Trojan struct { @@ -132,6 +133,7 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio Port: wsOptions.Port, Path: wsOptions.Path, Headers: wsOptions.Headers, + V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade, TLS: true, TLSConfig: tlsConfig, ClientFingerprint: t.option.ClientFingerprint, diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 066a3e2a..9cb4420c 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -12,14 +12,15 @@ import ( // Option is options of websocket obfs type Option struct { - Host string - Port string - Path string - Headers map[string]string - TLS bool - SkipCertVerify bool - Fingerprint string - Mux bool + Host string + Port string + Path string + Headers map[string]string + TLS bool + SkipCertVerify bool + Fingerprint string + Mux bool + V2rayHttpUpgrade bool } // NewV2rayObfs return a HTTPObfs @@ -30,10 +31,11 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, } config := &vmess.WebsocketConfig{ - Host: option.Host, - Port: option.Port, - Path: option.Path, - Headers: header, + Host: option.Host, + Port: option.Port, + Path: option.Path, + V2rayHttpUpgrade: option.V2rayHttpUpgrade, + Headers: header, } if option.TLS { diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 1117edaf..9b325ee9 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -55,6 +55,7 @@ type WebsocketConfig struct { MaxEarlyData int EarlyDataHeaderName string ClientFingerprint string + V2rayHttpUpgrade bool } // Read implements net.Conn.Read() @@ -352,6 +353,39 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } + if c.V2rayHttpUpgrade { + if c.TLS { + if dialer.TLSClient != nil { + conn = dialer.TLSClient(conn, uri.Host) + } else { + conn = tls.Client(conn, dialer.TLSConfig) + } + } + request := &http.Request{ + Method: http.MethodGet, + URL: &uri, + Header: c.Headers.Clone(), + Host: c.Host, + } + request.Header.Set("Connection", "Upgrade") + request.Header.Set("Upgrade", "websocket") + err = request.Write(conn) + if err != nil { + return nil, err + } + bufferedConn := N.NewBufferedConn(conn) + response, err := http.ReadResponse(bufferedConn.Reader(), request) + if err != nil { + return nil, err + } + if response.StatusCode != 101 || + !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || + !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { + return nil, fmt.Errorf("unexpected status: %s", response.Status) + } + return bufferedConn, nil + } + headers := http.Header{} headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http if c.Headers != nil { From 5bfe7ba169d29fd99ef8e8d995d07c4d5de96f79 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 11:22:01 +0800 Subject: [PATCH 072/192] chore: better tls handshake --- component/tls/utls.go | 2 +- transport/gun/gun.go | 4 ++-- transport/vmess/websocket.go | 9 ++++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/component/tls/utls.go b/component/tls/utls.go index e3d101dc..3aa030d3 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -21,7 +21,7 @@ type UClientHelloID struct { var initRandomFingerprint UClientHelloID var initUtlsClient string -func UClient(c net.Conn, config *tls.Config, fingerprint UClientHelloID) net.Conn { +func UClient(c net.Conn, config *tls.Config, fingerprint UClientHelloID) *UConn { utlsConn := utls.UClient(c, copyConfig(config), utls.ClientHelloID{ Client: fingerprint.Client, Version: fingerprint.Version, diff --git a/transport/gun/gun.go b/transport/gun/gun.go index cfe8aa3d..d6ef6317 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -209,11 +209,11 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re if realityConfig == nil { if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { utlsConn := tlsC.UClient(pconn, cfg, fingerprint) - if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { + if err := utlsConn.HandshakeContext(ctx); err != nil { pconn.Close() return nil, err } - state := utlsConn.(*tlsC.UConn).ConnectionState() + state := utlsConn.ConnectionState() if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { utlsConn.Close() return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 9b325ee9..3f4c0a33 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -330,7 +330,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) - if err := utlsConn.(*tlsC.UConn).BuildWebsocketHandshakeState(); err != nil { + if err := utlsConn.BuildWebsocketHandshakeState(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } @@ -360,6 +360,13 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } else { conn = tls.Client(conn, dialer.TLSConfig) } + if tlsConn, ok := conn.(interface { + HandshakeContext(ctx context.Context) error + }); ok { + if err = tlsConn.HandshakeContext(ctx); err != nil { + return nil, err + } + } } request := &http.Request{ Method: http.MethodGet, From a82ce85707bf2077bb063a769bf02076af95fe9f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 11:37:40 +0800 Subject: [PATCH 073/192] chore: add route exclude support --- config/config.go | 64 ++++++++++++++------------- go.mod | 3 +- go.sum | 6 ++- hub/route/configs.go | 42 ++++++++++++------ listener/config/tun.go | 34 +++++++------- listener/inbound/tun.go | 88 +++++++++++++++++++++---------------- listener/listener.go | 10 +++++ listener/sing_tun/server.go | 34 +++++++------- 8 files changed, 164 insertions(+), 117 deletions(-) diff --git a/config/config.go b/config/config.go index 6b324286..11951aa1 100644 --- a/config/config.go +++ b/config/config.go @@ -229,20 +229,22 @@ type RawTun struct { MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` + Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4_route_exclude_address,omitempty"` + Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6_route_exclude_address,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } type RawTuicServer struct { @@ -1361,22 +1363,24 @@ func parseTun(rawTun RawTun, general *General) error { AutoDetectInterface: rawTun.AutoDetectInterface, RedirectToTun: rawTun.RedirectToTun, - MTU: rawTun.MTU, - Inet4Address: []netip.Prefix{tunAddressPrefix}, - Inet6Address: rawTun.Inet6Address, - StrictRoute: rawTun.StrictRoute, - Inet4RouteAddress: rawTun.Inet4RouteAddress, - Inet6RouteAddress: rawTun.Inet6RouteAddress, - IncludeUID: rawTun.IncludeUID, - IncludeUIDRange: rawTun.IncludeUIDRange, - ExcludeUID: rawTun.ExcludeUID, - ExcludeUIDRange: rawTun.ExcludeUIDRange, - IncludeAndroidUser: rawTun.IncludeAndroidUser, - IncludePackage: rawTun.IncludePackage, - ExcludePackage: rawTun.ExcludePackage, - EndpointIndependentNat: rawTun.EndpointIndependentNat, - UDPTimeout: rawTun.UDPTimeout, - FileDescriptor: rawTun.FileDescriptor, + MTU: rawTun.MTU, + Inet4Address: []netip.Prefix{tunAddressPrefix}, + Inet6Address: rawTun.Inet6Address, + StrictRoute: rawTun.StrictRoute, + Inet4RouteAddress: rawTun.Inet4RouteAddress, + Inet6RouteAddress: rawTun.Inet6RouteAddress, + Inet4RouteExcludeAddress: rawTun.Inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: rawTun.Inet6RouteExcludeAddress, + IncludeUID: rawTun.IncludeUID, + IncludeUIDRange: rawTun.IncludeUIDRange, + ExcludeUID: rawTun.ExcludeUID, + ExcludeUIDRange: rawTun.ExcludeUIDRange, + IncludeAndroidUser: rawTun.IncludeAndroidUser, + IncludePackage: rawTun.IncludePackage, + ExcludePackage: rawTun.ExcludePackage, + EndpointIndependentNat: rawTun.EndpointIndependentNat, + UDPTimeout: rawTun.UDPTimeout, + FileDescriptor: rawTun.FileDescriptor, } return nil diff --git a/go.mod b/go.mod index f355a977..5211f3ce 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 + github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 @@ -101,6 +101,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect + go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index be89ca4d..d8a56527 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 h1:JToLa8cxHrd6tOUHWCg9YM+o/4MXmjgagG909itmnyE= -github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700/go.mod h1:atkIOs6Y5NeUzstK5SBvnrFo4z1JLuORhEfQECEVUpI= +github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 h1:ietLSuWRlYrNukGEEn/WXioB4OKPebqpZCc93MRKxEU= +github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= @@ -211,6 +211,8 @@ go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= +go4.org/netipx v0.0.0-20230824141953-6213f710f925/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= diff --git a/hub/route/configs.go b/hub/route/configs.go index cb500157..e86bb2a8 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -70,20 +70,22 @@ type tunSchema struct { MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress *[]netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` - IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` + Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` + Inet4RouteAddress *[]netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress *[]netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress *[]netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` + IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` } type tuicServerSchema struct { @@ -148,6 +150,18 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p.Inet6Address != nil { def.Inet6Address = *p.Inet6Address } + if p.Inet4RouteAddress != nil { + def.Inet4RouteAddress = *p.Inet4RouteAddress + } + if p.Inet6RouteAddress != nil { + def.Inet6RouteAddress = *p.Inet6RouteAddress + } + if p.Inet4RouteExcludeAddress != nil { + def.Inet4RouteExcludeAddress = *p.Inet4RouteExcludeAddress + } + if p.Inet6RouteExcludeAddress != nil { + def.Inet6RouteExcludeAddress = *p.Inet6RouteExcludeAddress + } if p.IncludeUID != nil { def.IncludeUID = *p.IncludeUID } diff --git a/listener/config/tun.go b/listener/config/tun.go index 06e92188..3f151d1e 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -27,20 +27,22 @@ type Tun struct { AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` RedirectToTun []string `yaml:"-" json:"-"` - MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` - Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` + Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index 9ba7ae87..472269d6 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -18,22 +18,24 @@ type TunOption struct { AutoRoute bool `inbound:"auto-route,omitempty"` AutoDetectInterface bool `inbound:"auto-detect-interface,omitempty"` - MTU uint32 `inbound:"mtu,omitempty"` - Inet4Address []string `inbound:"inet4_address,omitempty"` - Inet6Address []string `inbound:"inet6_address,omitempty"` - StrictRoute bool `inbound:"strict_route,omitempty"` - Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"` - Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` - IncludeUID []uint32 `inbound:"include_uid,omitempty"` - IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` - ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` - ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` - IncludePackage []string `inbound:"include_package,omitempty"` - ExcludePackage []string `inbound:"exclude_package,omitempty"` - EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `inbound:"udp_timeout,omitempty"` - FileDescriptor int `inbound:"file-descriptor,omitempty"` + MTU uint32 `inbound:"mtu,omitempty"` + Inet4Address []string `inbound:"inet4_address,omitempty"` + Inet6Address []string `inbound:"inet6_address,omitempty"` + StrictRoute bool `inbound:"strict_route,omitempty"` + Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"` + Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` + Inet4RouteExcludeAddress []string `inbound:"inet4_route_exclude_address,omitempty"` + Inet6RouteExcludeAddress []string `inbound:"inet6_route_exclude_address,omitempty"` + IncludeUID []uint32 `inbound:"include_uid,omitempty"` + IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` + ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` + ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` + IncludePackage []string `inbound:"include_package,omitempty"` + ExcludePackage []string `inbound:"exclude_package,omitempty"` + EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `inbound:"udp_timeout,omitempty"` + FileDescriptor int `inbound:"file-descriptor,omitempty"` } func (o TunOption) Equal(config C.InboundConfig) bool { @@ -72,32 +74,42 @@ func NewTun(options *TunOption) (*Tun, error) { if err != nil { return nil, err } + inet4RouteExcludeAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet4RouteExcludeAddress) + if err != nil { + return nil, err + } + inet6RouteExcludeAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet6RouteExcludeAddress) + if err != nil { + return nil, err + } return &Tun{ Base: base, config: options, tun: LC.Tun{ - Enable: true, - Device: options.Device, - Stack: stack, - DNSHijack: options.DNSHijack, - AutoRoute: options.AutoRoute, - AutoDetectInterface: options.AutoDetectInterface, - MTU: options.MTU, - Inet4Address: inet4Address, - Inet6Address: inet6Address, - StrictRoute: options.StrictRoute, - Inet4RouteAddress: inet4RouteAddress, - Inet6RouteAddress: inet6RouteAddress, - IncludeUID: options.IncludeUID, - IncludeUIDRange: options.IncludeUIDRange, - ExcludeUID: options.ExcludeUID, - ExcludeUIDRange: options.ExcludeUIDRange, - IncludeAndroidUser: options.IncludeAndroidUser, - IncludePackage: options.IncludePackage, - ExcludePackage: options.ExcludePackage, - EndpointIndependentNat: options.EndpointIndependentNat, - UDPTimeout: options.UDPTimeout, - FileDescriptor: options.FileDescriptor, + Enable: true, + Device: options.Device, + Stack: stack, + DNSHijack: options.DNSHijack, + AutoRoute: options.AutoRoute, + AutoDetectInterface: options.AutoDetectInterface, + MTU: options.MTU, + Inet4Address: inet4Address, + Inet6Address: inet6Address, + StrictRoute: options.StrictRoute, + Inet4RouteAddress: inet4RouteAddress, + Inet6RouteAddress: inet6RouteAddress, + Inet4RouteExcludeAddress: inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: inet6RouteExcludeAddress, + IncludeUID: options.IncludeUID, + IncludeUIDRange: options.IncludeUIDRange, + ExcludeUID: options.ExcludeUID, + ExcludeUIDRange: options.ExcludeUIDRange, + IncludeAndroidUser: options.IncludeAndroidUser, + IncludePackage: options.IncludePackage, + ExcludePackage: options.ExcludePackage, + EndpointIndependentNat: options.EndpointIndependentNat, + UDPTimeout: options.UDPTimeout, + FileDescriptor: options.FileDescriptor, }, }, nil } diff --git a/listener/listener.go b/listener/listener.go index ad3b2351..a6bbdbf5 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -849,6 +849,14 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { return tunConf.Inet6RouteAddress[i].String() < tunConf.Inet6RouteAddress[j].String() }) + sort.Slice(tunConf.Inet4RouteExcludeAddress, func(i, j int) bool { + return tunConf.Inet4RouteExcludeAddress[i].String() < tunConf.Inet4RouteExcludeAddress[j].String() + }) + + sort.Slice(tunConf.Inet6RouteExcludeAddress, func(i, j int) bool { + return tunConf.Inet6RouteExcludeAddress[i].String() < tunConf.Inet6RouteExcludeAddress[j].String() + }) + sort.Slice(tunConf.IncludeUID, func(i, j int) bool { return tunConf.IncludeUID[i] < tunConf.IncludeUID[j] }) @@ -882,6 +890,8 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { !slices.Equal(tunConf.Inet6Address, LastTunConf.Inet6Address) || !slices.Equal(tunConf.Inet4RouteAddress, LastTunConf.Inet4RouteAddress) || !slices.Equal(tunConf.Inet6RouteAddress, LastTunConf.Inet6RouteAddress) || + !slices.Equal(tunConf.Inet4RouteExcludeAddress, LastTunConf.Inet4RouteExcludeAddress) || + !slices.Equal(tunConf.Inet6RouteExcludeAddress, LastTunConf.Inet6RouteExcludeAddress) || !slices.Equal(tunConf.IncludeUID, LastTunConf.IncludeUID) || !slices.Equal(tunConf.IncludeUIDRange, LastTunConf.IncludeUIDRange) || !slices.Equal(tunConf.ExcludeUID, LastTunConf.ExcludeUID) || diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 122e9af3..0548ac41 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -199,22 +199,24 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } tunOptions := tun.Options{ - Name: tunName, - MTU: tunMTU, - Inet4Address: options.Inet4Address, - Inet6Address: options.Inet6Address, - AutoRoute: options.AutoRoute, - StrictRoute: options.StrictRoute, - Inet4RouteAddress: options.Inet4RouteAddress, - Inet6RouteAddress: options.Inet6RouteAddress, - IncludeUID: includeUID, - ExcludeUID: excludeUID, - IncludeAndroidUser: options.IncludeAndroidUser, - IncludePackage: options.IncludePackage, - ExcludePackage: options.ExcludePackage, - FileDescriptor: options.FileDescriptor, - InterfaceMonitor: defaultInterfaceMonitor, - TableIndex: 2022, + Name: tunName, + MTU: tunMTU, + Inet4Address: options.Inet4Address, + Inet6Address: options.Inet6Address, + AutoRoute: options.AutoRoute, + StrictRoute: options.StrictRoute, + Inet4RouteAddress: options.Inet4RouteAddress, + Inet6RouteAddress: options.Inet6RouteAddress, + Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress, + IncludeUID: includeUID, + ExcludeUID: excludeUID, + IncludeAndroidUser: options.IncludeAndroidUser, + IncludePackage: options.IncludePackage, + ExcludePackage: options.ExcludePackage, + FileDescriptor: options.FileDescriptor, + InterfaceMonitor: defaultInterfaceMonitor, + TableIndex: 2022, } err = l.buildAndroidRules(&tunOptions) From ef303b11f21edb3716865a5b5f7c00faf152874b Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Thu, 2 Nov 2023 16:01:35 +0800 Subject: [PATCH 074/192] action: trigger CMFA PR update in every commit --- .../workflows/android-branch-auto-sync.yml | 20 ++++++++++++- .../workflows/cmfa-update-deps-trigger.yml | 28 ------------------- 2 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 .github/workflows/cmfa-update-deps-trigger.yml diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml index 5dbbd5be..c7ee5eba 100644 --- a/.github/workflows/android-branch-auto-sync.yml +++ b/.github/workflows/android-branch-auto-sync.yml @@ -48,4 +48,22 @@ jobs: - name: Push changes run: | - git push origin android-real --force \ No newline at end of file + git push origin android-real --force + + # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies + trigger-CMFA-update: + needs: update-dependencies + runs-on: ubuntu-latest + steps: + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.MAINTAINER_APPID }} + private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} + + - name: Trigger update-dependencies + run: | + curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ + -H "Accept: application/vnd.github.everest-preview+json" \ + -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ + -d '{"event_type": "core-updated"}' \ No newline at end of file diff --git a/.github/workflows/cmfa-update-deps-trigger.yml b/.github/workflows/cmfa-update-deps-trigger.yml deleted file mode 100644 index 549b0098..00000000 --- a/.github/workflows/cmfa-update-deps-trigger.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: CMFA auto update-dependencies trigger -on: - workflow_dispatch: - push: - tags: - - "*" - pull_request_target: - branches: - - Alpha - -jobs: - update-dependencies: - runs-on: ubuntu-latest - steps: - - uses: tibdex/github-app-token@v1 - id: generate-token - with: - app_id: ${{ secrets.MAINTAINER_APPID }} - private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} - - - name: Trigger update-dependencies - run: | - curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ - -H "Accept: application/vnd.github.everest-preview+json" \ - -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ - -d '{"event_type": "core-updated"}' - # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies - From 885ee7a8208aa461b1e322fa9fe6470f8a637c34 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 09:32:22 +0800 Subject: [PATCH 075/192] fix: v2ray http upgrade `Hosts` header not working --- transport/vmess/websocket.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 3f4c0a33..ebafefa4 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -376,6 +376,10 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } request.Header.Set("Connection", "Upgrade") request.Header.Set("Upgrade", "websocket") + if host := request.Header.Get("Host"); host != "" { + request.Header.Del("Host") + request.Host = host + } err = request.Write(conn) if err != nil { return nil, err @@ -415,16 +419,16 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if secProtocol := headers.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols // to avoid send repeatedly don't set it to headers - headers.Del("Sec-WebSocket-Protocol") dialer.Protocols = []string{secProtocol} } + headers.Del("Sec-WebSocket-Protocol") // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` // if headers has "Host" will send repeatedly if host := headers.Get("Host"); host != "" { - headers.Del("Host") uri.Host = host } + headers.Del("Host") dialer.Header = ws.HandshakeHeaderHTTP(headers) From ee3038d5e4e80fcc82cd849c30a5f6801af4607d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 11:00:40 +0800 Subject: [PATCH 076/192] chore: add SetupContextForConn for common/net --- common/net/context.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 common/net/context.go diff --git a/common/net/context.go b/common/net/context.go new file mode 100644 index 00000000..917028d1 --- /dev/null +++ b/common/net/context.go @@ -0,0 +1,31 @@ +package net + +import ( + "context" + "net" +) + +// SetupContextForConn is a helper function that starts connection I/O interrupter goroutine. +func SetupContextForConn(ctx context.Context, conn net.Conn) (done func(*error)) { + var ( + quit = make(chan struct{}) + interrupt = make(chan error, 1) + ) + go func() { + select { + case <-quit: + interrupt <- nil + case <-ctx.Done(): + // Close the connection, discarding the error + _ = conn.Close() + interrupt <- ctx.Err() + } + }() + return func(inputErr *error) { + close(quit) + if ctxErr := <-interrupt; ctxErr != nil && inputErr != nil { + // Return context error to user. + inputErr = &ctxErr + } + } +} From 665ba7f9f179a69e4da357ef2eae186fa32cdbd8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 11:02:19 +0800 Subject: [PATCH 077/192] chore: do websocket client upgrade directly instead of gobwas/ws --- transport/vmess/websocket.go | 165 +++++++++++++++++------------------ 1 file changed, 81 insertions(+), 84 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index ebafefa4..60353d5a 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -3,6 +3,7 @@ package vmess import ( "bytes" "context" + "crypto/sha1" "crypto/tls" "encoding/base64" "encoding/binary" @@ -19,6 +20,7 @@ import ( "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/log" "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" @@ -317,35 +319,35 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co } func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { - dialer := ws.Dialer{ - NetDial: func(ctx context.Context, network, addr string) (net.Conn, error) { - return conn, nil - }, - TLSConfig: c.TLSConfig, + u, err := url.Parse(c.Path) + if err != nil { + return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } + scheme := "ws" if c.TLS { scheme = "wss" if len(c.ClientFingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) - - if err := utlsConn.BuildWebsocketHandshakeState(); err != nil { + if err = utlsConn.BuildWebsocketHandshakeState(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } + conn = utlsConn + } + } else { + conn = tls.Client(conn, c.TLSConfig) + } - dialer.TLSClient = func(conn net.Conn, hostname string) net.Conn { - return utlsConn - } + if tlsConn, ok := conn.(interface { + HandshakeContext(ctx context.Context) error + }); ok { + if err = tlsConn.HandshakeContext(ctx); err != nil { + return nil, err } } } - u, err := url.Parse(c.Path) - if err != nil { - return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) - } - uri := url.URL{ Scheme: scheme, Host: net.JoinHostPort(c.Host, c.Port), @@ -353,56 +355,36 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } - if c.V2rayHttpUpgrade { - if c.TLS { - if dialer.TLSClient != nil { - conn = dialer.TLSClient(conn, uri.Host) - } else { - conn = tls.Client(conn, dialer.TLSConfig) - } - if tlsConn, ok := conn.(interface { - HandshakeContext(ctx context.Context) error - }); ok { - if err = tlsConn.HandshakeContext(ctx); err != nil { - return nil, err - } - } - } - request := &http.Request{ - Method: http.MethodGet, - URL: &uri, - Header: c.Headers.Clone(), - Host: c.Host, - } - request.Header.Set("Connection", "Upgrade") - request.Header.Set("Upgrade", "websocket") - if host := request.Header.Get("Host"); host != "" { - request.Header.Del("Host") - request.Host = host - } - err = request.Write(conn) - if err != nil { - return nil, err - } - bufferedConn := N.NewBufferedConn(conn) - response, err := http.ReadResponse(bufferedConn.Reader(), request) - if err != nil { - return nil, err - } - if response.StatusCode != 101 || - !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || - !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { - return nil, fmt.Errorf("unexpected status: %s", response.Status) - } - return bufferedConn, nil + request := &http.Request{ + Method: http.MethodGet, + URL: &uri, + Header: c.Headers.Clone(), + Host: c.Host, } - headers := http.Header{} - headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http - if c.Headers != nil { - for k := range c.Headers { - headers.Add(k, c.Headers.Get(k)) + request.Header.Set("Connection", "Upgrade") + request.Header.Set("Upgrade", "websocket") + + if host := request.Header.Get("Host"); host != "" { + // For client requests, Host optionally overrides the Host + // header to send. If empty, the Request.Write method uses + // the value of URL.Host. Host may contain an international + // domain name. + request.Host = host + } + request.Header.Del("Host") + + var nonce string + if !c.V2rayHttpUpgrade { + const nonceKeySize = 16 + // NOTE: bts does not escape. + bts := make([]byte, nonceKeySize) + if _, err = fastrand.Read(bts); err != nil { + return nil, fmt.Errorf("rand read error: %w", err) } + nonce = base64.StdEncoding.EncodeToString(bts) + request.Header.Set("Sec-WebSocket-Version", "13") + request.Header.Set("Sec-WebSocket-Key", nonce) } if earlyData != nil { @@ -410,36 +392,51 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if c.EarlyDataHeaderName == "" { uri.Path += earlyDataString } else { - headers.Set(c.EarlyDataHeaderName, earlyDataString) + request.Header.Set(c.EarlyDataHeaderName, earlyDataString) } } - // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer - // if not will cause ws.ErrHandshakeBadSubProtocol - if secProtocol := headers.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { - // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols - // to avoid send repeatedly don't set it to headers - dialer.Protocols = []string{secProtocol} + if ctx.Done() != nil { + done := N.SetupContextForConn(ctx, conn) + defer done(&err) } - headers.Del("Sec-WebSocket-Protocol") - // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` - // if headers has "Host" will send repeatedly - if host := headers.Get("Host"); host != "" { - uri.Host = host - } - headers.Del("Host") - - dialer.Header = ws.HandshakeHeaderHTTP(headers) - - conn, reader, _, err := dialer.Dial(ctx, uri.String()) + err = request.Write(conn) if err != nil { - return nil, fmt.Errorf("dial %s error: %w", uri.Host, err) + return nil, err + } + bufferedConn := N.NewBufferedConn(conn) + response, err := http.ReadResponse(bufferedConn.Reader(), request) + if err != nil { + return nil, err + } + if response.StatusCode != http.StatusSwitchingProtocols || + !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || + !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { + return nil, fmt.Errorf("unexpected status: %s", response.Status) } - // some bytes which could be written by the peer right after response and be caught by us during buffered read, - // so we need warp Conn with bio.Reader - conn = N.WarpConnWithBioReader(conn, reader) + if c.V2rayHttpUpgrade { + return bufferedConn, nil + } + + if log.Level() == log.DEBUG { // we might not check this for performance + secAccept := response.Header.Get("Sec-Websocket-Accept") + const acceptSize = 28 // base64.StdEncoding.EncodedLen(sha1.Size) + if lenSecAccept := len(secAccept); lenSecAccept != acceptSize { + return nil, fmt.Errorf("unexpected Sec-Websocket-Accept length: %d", lenSecAccept) + } + + const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) + p := make([]byte, nonceSize+len(magic)) + copy(p[:nonceSize], nonce) + copy(p[nonceSize:], magic) + sum := sha1.Sum(p) + if accept := base64.StdEncoding.EncodeToString(sum[:]); accept != secAccept { + return nil, errors.New("unexpected Sec-Websocket-Accept") + } + } conn = newWebsocketConn(conn, ws.StateClientSide) // websocketConn can't correct handle ReadDeadline From 09e7866a5c696b965b8d13eecbdf9612cc4ecdfe Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 11:08:04 +0800 Subject: [PATCH 078/192] fix: gvisor panic --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5211f3ce..80ab477c 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 + github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 diff --git a/go.sum b/go.sum index d8a56527..6a6356c1 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 h1:ietLSuWRlYrNukGEEn/WXioB4OKPebqpZCc93MRKxEU= -github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= +github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd h1:k0+92eARqyTAovGhg2AxdsMWHjUsdiGCnR5NuXF3CQY= +github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= From 228990472d8dd2856f7c4b6cac8d7dbe8f96fa3a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 12:04:22 +0800 Subject: [PATCH 079/192] fix: avoid tls panic --- transport/vmess/websocket.go | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 60353d5a..0c2a3a16 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -324,19 +324,34 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } - scheme := "ws" + uri := url.URL{ + Scheme: "ws", + Host: net.JoinHostPort(c.Host, c.Port), + Path: u.Path, + RawQuery: u.RawQuery, + } + if c.TLS { - scheme = "wss" + uri.Scheme = "wss" + config := c.TLSConfig + if config == nil { // The config cannot be nil + config = &tls.Config{NextProtos: []string{"http/1.1"}} + } + if config.ServerName == "" && !config.InsecureSkipVerify { // users must set either ServerName or InsecureSkipVerify in the config. + config = config.Clone() + config.ServerName = uri.Host + } + if len(c.ClientFingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { - utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) + utlsConn := tlsC.UClient(conn, config, fingerprint) if err = utlsConn.BuildWebsocketHandshakeState(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } conn = utlsConn } } else { - conn = tls.Client(conn, c.TLSConfig) + conn = tls.Client(conn, config) } if tlsConn, ok := conn.(interface { @@ -348,13 +363,6 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } } - uri := url.URL{ - Scheme: scheme, - Host: net.JoinHostPort(c.Host, c.Port), - Path: u.Path, - RawQuery: u.RawQuery, - } - request := &http.Request{ Method: http.MethodGet, URL: &uri, From 8c3557e96be1acbccd318584c48b587b59b3e7fb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 13:58:53 +0800 Subject: [PATCH 080/192] chore: support v2ray http upgrade server too --- common/net/cached.go | 49 +++++++++++++++++++++ transport/vmess/websocket.go | 82 ++++++++++++++++++++++++------------ 2 files changed, 105 insertions(+), 26 deletions(-) create mode 100644 common/net/cached.go diff --git a/common/net/cached.go b/common/net/cached.go new file mode 100644 index 00000000..3b7da44c --- /dev/null +++ b/common/net/cached.go @@ -0,0 +1,49 @@ +package net + +import ( + "net" + + "github.com/Dreamacro/clash/common/buf" +) + +var _ ExtendedConn = (*CachedConn)(nil) + +type CachedConn struct { + ExtendedConn + data []byte +} + +func NewCachedConn(c net.Conn, data []byte) *CachedConn { + return &CachedConn{NewExtendedConn(c), data} +} + +func (c *CachedConn) Read(b []byte) (n int, err error) { + if len(c.data) > 0 { + n = copy(b, c.data) + c.data = c.data[n:] + return + } + return c.ExtendedConn.Read(b) +} + +func (c *CachedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.Copy + if len(c.data) > 0 { + return buf.As(c.data) + } + return nil +} + +func (c *CachedConn) Upstream() any { + return c.ExtendedConn +} + +func (c *CachedConn) ReaderReplaceable() bool { + if len(c.data) > 0 { + return false + } + return true +} + +func (c *CachedConn) WriterReplaceable() bool { + return true +} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 0c2a3a16..9f09185b 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -1,6 +1,7 @@ package vmess import ( + "bufio" "bytes" "context" "crypto/sha1" @@ -382,7 +383,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } request.Header.Del("Host") - var nonce string + var secKey string if !c.V2rayHttpUpgrade { const nonceKeySize = 16 // NOTE: bts does not escape. @@ -390,9 +391,9 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if _, err = fastrand.Read(bts); err != nil { return nil, fmt.Errorf("rand read error: %w", err) } - nonce = base64.StdEncoding.EncodeToString(bts) + secKey = base64.StdEncoding.EncodeToString(bts) request.Header.Set("Sec-WebSocket-Version", "13") - request.Header.Set("Sec-WebSocket-Key", nonce) + request.Header.Set("Sec-WebSocket-Key", secKey) } if earlyData != nil { @@ -434,14 +435,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if lenSecAccept := len(secAccept); lenSecAccept != acceptSize { return nil, fmt.Errorf("unexpected Sec-Websocket-Accept length: %d", lenSecAccept) } - - const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) - p := make([]byte, nonceSize+len(magic)) - copy(p[:nonceSize], nonce) - copy(p[nonceSize:], magic) - sum := sha1.Sum(p) - if accept := base64.StdEncoding.EncodeToString(sum[:]); accept != secAccept { + if getSecAccept(secKey) != secAccept { return nil, errors.New("unexpected Sec-Websocket-Accept") } } @@ -452,6 +446,16 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return N.NewDeadlineConn(conn), nil } +func getSecAccept(secKey string) string { + const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) + p := make([]byte, nonceSize+len(magic)) + copy(p[:nonceSize], secKey) + copy(p[nonceSize:], magic) + sum := sha1.Sum(p) + return base64.StdEncoding.EncodeToString(sum[:]) +} + func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) (net.Conn, error) { if u, err := url.Parse(c.Path); err == nil { if q := u.Query(); q.Get("ed") != "" { @@ -505,27 +509,53 @@ func decodeXray0rtt(requestHeader http.Header) []byte { return nil } +func IsWebSocketUpgrade(r *http.Request) bool { + return r.Header.Get("Upgrade") == "websocket" +} + +func IsV2rayHttpUpdate(r *http.Request) bool { + return IsWebSocketUpgrade(r) && r.Header.Get("Sec-WebSocket-Key") == "" +} + func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { - wsConn, rw, _, err := ws.UpgradeHTTP(r, w) + var conn net.Conn + var rw *bufio.ReadWriter + var err error + isRaw := IsV2rayHttpUpdate(r) + w.Header().Set("Connection", "upgrade") + w.Header().Set("Upgrade", "websocket") + if !isRaw { + w.Header().Set("Sec-Websocket-Accept", getSecAccept(r.Header.Get("Sec-WebSocket-Key"))) + } + w.WriteHeader(http.StatusSwitchingProtocols) + if flusher, isFlusher := w.(interface{ FlushError() error }); isFlusher { + err = flusher.FlushError() + if err != nil { + return nil, fmt.Errorf("flush response: %w", err) + } + } + hijacker, canHijack := w.(http.Hijacker) + if !canHijack { + return nil, errors.New("invalid connection, maybe HTTP/2") + } + conn, rw, err = hijacker.Hijack() if err != nil { - return nil, err + return nil, fmt.Errorf("hijack failed: %w", err) } - // gobwas/ws will flush rw.Writer, so we only need warp rw.Reader - wsConn = N.WarpConnWithBioReader(wsConn, rw.Reader) + // rw.Writer was flushed, so we only need warp rw.Reader + conn = N.WarpConnWithBioReader(conn, rw.Reader) + + if !isRaw { + conn = newWebsocketConn(conn, ws.StateServerSide) + // websocketConn can't correct handle ReadDeadline + // so call N.NewDeadlineConn to add a safe wrapper + conn = N.NewDeadlineConn(conn) + } - conn := newWebsocketConn(wsConn, ws.StateServerSide) if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 { - return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil + conn = N.NewCachedConn(conn, edBuf) } - return N.NewDeadlineConn(conn), nil -} -type websocketWithReaderConn struct { - *websocketConn - reader io.Reader -} - -func (ws *websocketWithReaderConn) Read(b []byte) (n int, err error) { - return ws.reader.Read(b) + return conn, nil } From 17c9d507be0fec41ff2c4d7b1bb3019c82e091fc Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 21:01:45 +0800 Subject: [PATCH 081/192] chore: hello mihomo --- .github/ISSUE_TEMPLATE/bug_report.yml | 24 ++-- .github/ISSUE_TEMPLATE/config.yml | 6 +- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- .github/rename-cgo.sh | 26 ++--- .../workflows/android-branch-auto-sync.yml | 6 +- .github/workflows/build.yml | 8 +- .golangci.yaml | 2 +- Dockerfile | 26 ++--- Makefile | 6 +- README.md | 28 ++--- adapter/adapter.go | 12 +- adapter/inbound/addition.go | 2 +- adapter/inbound/auth.go | 2 +- adapter/inbound/http.go | 4 +- adapter/inbound/https.go | 2 +- adapter/inbound/packet.go | 4 +- adapter/inbound/socket.go | 4 +- adapter/inbound/util.go | 6 +- adapter/outbound/base.go | 8 +- adapter/outbound/direct.go | 8 +- adapter/outbound/http.go | 10 +- adapter/outbound/hysteria.go | 22 ++-- adapter/outbound/hysteria2.go | 12 +- adapter/outbound/reality.go | 2 +- adapter/outbound/reject.go | 6 +- adapter/outbound/shadowsocks.go | 20 ++-- adapter/outbound/shadowsocksr.go | 22 ++-- adapter/outbound/singmux.go | 10 +- adapter/outbound/snell.go | 14 +-- adapter/outbound/socks5.go | 12 +- adapter/outbound/trojan.go | 16 +-- adapter/outbound/tuic.go | 12 +- adapter/outbound/util.go | 6 +- adapter/outbound/vless.go | 28 ++--- adapter/outbound/vmess.go | 46 ++++---- adapter/outbound/wireguard.go | 14 +-- adapter/outboundgroup/fallback.go | 14 +-- adapter/outboundgroup/groupbase.go | 16 +-- adapter/outboundgroup/loadbalance.go | 16 +-- adapter/outboundgroup/parser.go | 12 +- adapter/outboundgroup/relay.go | 10 +- adapter/outboundgroup/selector.go | 8 +- adapter/outboundgroup/urltest.go | 14 +-- adapter/parser.go | 8 +- adapter/provider/healthcheck.go | 12 +- adapter/provider/parser.go | 10 +- adapter/provider/provider.go | 24 ++-- common/cache/lrucache.go | 2 +- common/callback/callback.go | 6 +- common/convert/converter.go | 4 +- common/convert/util.go | 2 +- common/net/bufconn.go | 2 +- common/net/cached.go | 2 +- common/net/deadline/packet.go | 4 +- common/net/deadline/packet_enhance.go | 2 +- common/net/deadline/packet_sing.go | 2 +- common/net/packet.go | 4 +- common/net/packet/packet.go | 2 +- common/net/packet/packet_posix.go | 2 +- common/net/refconn.go | 2 +- common/net/relay.go | 2 +- common/observable/observable_test.go | 2 +- common/singledo/singledo_test.go | 2 +- component/dhcp/conn.go | 2 +- component/dhcp/dhcp.go | 4 +- component/dialer/bind.go | 2 +- component/dialer/bind_darwin.go | 2 +- component/dialer/bind_windows.go | 2 +- component/dialer/dialer.go | 2 +- component/dialer/mark_nonlinux.go | 2 +- component/dialer/options.go | 4 +- component/ebpf/bpf/redir.c | 10 +- component/ebpf/bpf/tc.c | 10 +- component/ebpf/ebpf.go | 4 +- component/ebpf/ebpf_linux.go | 12 +- component/ebpf/redir/auto_redirect.go | 10 +- component/ebpf/tc/redirect_to_tun.go | 6 +- component/fakeip/cachefile.go | 2 +- component/fakeip/memory.go | 2 +- component/fakeip/pool.go | 6 +- component/fakeip/pool_test.go | 6 +- component/geodata/attr.go | 2 +- component/geodata/geodata.go | 4 +- component/geodata/geodataproto.go | 2 +- component/geodata/init.go | 12 +- component/geodata/memconservative/cache.go | 6 +- component/geodata/memconservative/memc.go | 4 +- component/geodata/router/condition.go | 2 +- component/geodata/router/config.pb.go | 30 ++--- component/geodata/router/config.proto | 8 +- component/geodata/standard/standard.go | 6 +- .../strmatcher/ac_automaton_matcher.go | 2 +- component/geodata/utils.go | 6 +- component/http/http.go | 6 +- component/iface/iface.go | 2 +- component/mmdb/mmdb.go | 8 +- component/nat/proxy.go | 4 +- component/nat/table.go | 2 +- component/process/process_freebsd_amd64.go | 4 +- component/process/process_windows.go | 4 +- component/profile/cachefile/cache.go | 6 +- component/profile/profile.go | 2 +- component/proxydialer/proxydialer.go | 12 +- component/proxydialer/sing.go | 2 +- component/resolver/host.go | 4 +- component/resolver/resolver.go | 4 +- component/resource/fetcher.go | 4 +- component/resource/vehicle.go | 6 +- component/sniffer/base_sniffer.go | 6 +- component/sniffer/dispatcher.go | 12 +- component/sniffer/http_sniffer.go | 6 +- component/sniffer/quic_sniffer.go | 6 +- component/sniffer/tls_sniffer.go | 6 +- component/tls/reality.go | 6 +- component/tls/utls.go | 2 +- component/trie/domain_set.go | 2 +- component/trie/domain_set_test.go | 2 +- component/trie/domain_test.go | 2 +- component/trie/ipcidr_trie.go | 2 +- config/config.go | 58 +++++----- config/initial.go | 4 +- config/update_geo.go | 6 +- config/update_ui.go | 2 +- config/utils.go | 8 +- constant/adapters.go | 6 +- constant/context.go | 2 +- constant/ebpf.go | 8 +- constant/metadata.go | 4 +- constant/path.go | 8 +- constant/provider/interface.go | 4 +- constant/rule_extra.go | 2 +- constant/sniffer/sniffer.go | 2 +- constant/version.go | 8 +- context/conn.go | 6 +- context/dns.go | 2 +- context/packetconn.go | 4 +- dns/client.go | 8 +- dns/dhcp.go | 4 +- dns/doh.go | 6 +- dns/doq.go | 6 +- dns/enhancer.go | 6 +- dns/filters.go | 12 +- dns/middleware.go | 14 +-- dns/resolver.go | 16 +-- dns/server.go | 6 +- dns/system.go | 2 +- dns/util.go | 18 +-- docker/file-name.sh | 2 +- docs/config.yaml | 16 +-- flake.nix | 14 +-- go.mod | 2 +- hub/executor/executor.go | 52 ++++----- hub/hub.go | 10 +- hub/route/cache.go | 2 +- hub/route/configs.go | 22 ++-- hub/route/connections.go | 2 +- hub/route/ctxkeys.go | 2 +- hub/route/dns.go | 2 +- hub/route/groups.go | 10 +- hub/route/provider.go | 6 +- hub/route/proxies.go | 12 +- hub/route/restart.go | 4 +- hub/route/rules.go | 4 +- hub/route/server.go | 14 +-- hub/route/upgrade.go | 6 +- hub/updater/updater.go | 20 ++-- listener/auth/auth.go | 2 +- listener/autoredir/tcp.go | 10 +- listener/config/tun.go | 2 +- listener/http/client.go | 6 +- listener/http/proxy.go | 12 +- listener/http/server.go | 6 +- listener/http/upgrade.go | 8 +- listener/inbound/base.go | 4 +- listener/inbound/http.go | 6 +- listener/inbound/hysteria2.go | 8 +- listener/inbound/mixed.go | 8 +- listener/inbound/redir.go | 6 +- listener/inbound/shadowsocks.go | 8 +- listener/inbound/socks.go | 6 +- listener/inbound/tproxy.go | 6 +- listener/inbound/tuic.go | 8 +- listener/inbound/tun.go | 8 +- listener/inbound/tunnel.go | 6 +- listener/inbound/vmess.go | 8 +- listener/inner/tcp.go | 4 +- listener/listener.go | 32 +++--- listener/mixed/mixed.go | 16 +-- listener/parse.go | 6 +- listener/redir/tcp.go | 6 +- listener/redir/tcp_darwin.go | 2 +- listener/redir/tcp_freebsd.go | 2 +- listener/redir/tcp_linux.go | 2 +- listener/redir/tcp_other.go | 2 +- listener/shadowsocks/tcp.go | 12 +- listener/shadowsocks/udp.go | 14 +-- listener/shadowsocks/utils.go | 2 +- listener/sing/context.go | 2 +- listener/sing/sing.go | 8 +- listener/sing_hysteria2/server.go | 16 +-- listener/sing_shadowsocks/server.go | 18 +-- listener/sing_tun/dns.go | 8 +- listener/sing_tun/server.go | 14 +-- listener/sing_tun/server_android.go | 2 +- listener/sing_tun/server_windows.go | 2 +- listener/sing_vmess/server.go | 16 +-- listener/socks/tcp.go | 12 +- listener/socks/udp.go | 12 +- listener/socks/utils.go | 2 +- listener/tproxy/packet.go | 8 +- listener/tproxy/tproxy.go | 8 +- listener/tproxy/tproxy_iptables.go | 104 +++++++++--------- listener/tproxy/udp.go | 8 +- listener/tuic/server.go | 18 +-- listener/tunnel/packet.go | 2 +- listener/tunnel/tcp.go | 8 +- listener/tunnel/udp.go | 8 +- log/log.go | 2 +- main.go | 16 +-- ntp/service.go | 6 +- rules/common/domain.go | 2 +- rules/common/domain_keyword.go | 2 +- rules/common/domain_suffix.go | 2 +- rules/common/final.go | 2 +- rules/common/geoip.go | 12 +- rules/common/geosite.go | 12 +- rules/common/in_name.go | 2 +- rules/common/in_type.go | 2 +- rules/common/in_user.go | 2 +- rules/common/ipcidr.go | 2 +- rules/common/ipsuffix.go | 2 +- rules/common/network_type.go | 2 +- rules/common/port.go | 4 +- rules/common/process.go | 2 +- rules/common/uid.go | 6 +- rules/logic/logic.go | 6 +- rules/logic_test/logic_test.go | 6 +- rules/parser.go | 8 +- rules/provider/classical_strategy.go | 4 +- rules/provider/domain_strategy.go | 6 +- rules/provider/ipcidr_strategy.go | 6 +- rules/provider/parse.go | 8 +- rules/provider/provider.go | 8 +- rules/provider/rule_set.go | 6 +- test/.golangci.yaml | 2 +- test/README.md | 6 +- test/clash_test.go | 10 +- test/dns_test.go | 8 +- test/go.mod | 22 ++-- test/go.sum | 99 +++++++---------- test/hysteria_test.go | 6 +- test/snell_test.go | 12 +- test/ss_test.go | 28 ++--- test/trojan_test.go | 12 +- test/vless_test.go | 11 +- test/vmess_test.go | 26 ++--- transport/gun/gun.go | 8 +- transport/hysteria/conns/faketcp/obfs.go | 2 +- transport/hysteria/conns/faketcp/tcp_linux.go | 2 +- transport/hysteria/conns/udp/hop.go | 4 +- transport/hysteria/conns/udp/obfs.go | 2 +- transport/hysteria/conns/wechat/obfs.go | 4 +- transport/hysteria/core/client.go | 8 +- transport/hysteria/transport/client.go | 10 +- transport/shadowsocks/core/cipher.go | 6 +- transport/shadowsocks/shadowaead/packet.go | 4 +- transport/shadowsocks/shadowaead/stream.go | 2 +- transport/shadowsocks/shadowstream/packet.go | 4 +- transport/shadowtls/shadowtls.go | 4 +- transport/simple-obfs/http.go | 2 +- transport/simple-obfs/tls.go | 2 +- transport/sing-shadowtls/shadowtls.go | 6 +- transport/snell/cipher.go | 2 +- transport/snell/pool.go | 6 +- transport/snell/snell.go | 6 +- transport/socks4/socks4.go | 2 +- transport/socks5/socks5.go | 2 +- transport/ssr/obfs/http_simple.go | 2 +- transport/ssr/obfs/random_head.go | 2 +- transport/ssr/obfs/tls1.2_ticket_auth.go | 4 +- transport/ssr/protocol/auth_aes128_md5.go | 2 +- transport/ssr/protocol/auth_aes128_sha1.go | 8 +- transport/ssr/protocol/auth_chain_a.go | 14 +-- transport/ssr/protocol/auth_chain_b.go | 2 +- transport/ssr/protocol/auth_sha1_v4.go | 6 +- transport/ssr/protocol/base.go | 6 +- transport/ssr/protocol/origin.go | 2 +- transport/ssr/protocol/packet.go | 4 +- transport/ssr/protocol/protocol.go | 2 +- transport/ssr/protocol/stream.go | 2 +- transport/ssr/tools/random.go | 2 +- transport/trojan/trojan.go | 14 +-- transport/tuic/common/congestion.go | 4 +- transport/tuic/common/type.go | 4 +- transport/tuic/pool_client.go | 8 +- transport/tuic/server.go | 16 +-- transport/tuic/tuic.go | 8 +- transport/tuic/v4/client.go | 14 +-- transport/tuic/v4/packet.go | 8 +- transport/tuic/v4/protocol.go | 4 +- transport/tuic/v4/server.go | 14 +-- transport/tuic/v5/client.go | 12 +- transport/tuic/v5/frag.go | 2 +- transport/tuic/v5/packet.go | 8 +- transport/tuic/v5/protocol.go | 6 +- transport/tuic/v5/server.go | 12 +- transport/v2ray-plugin/websocket.go | 4 +- transport/vless/config.pb.go | 2 +- transport/vless/config.proto | 8 +- transport/vless/conn.go | 6 +- transport/vless/vision/conn.go | 6 +- transport/vless/vision/filter.go | 2 +- transport/vless/vision/padding.go | 4 +- transport/vless/vision/vision.go | 4 +- transport/vless/vless.go | 2 +- transport/vmess/aead.go | 2 +- transport/vmess/chunk.go | 2 +- transport/vmess/http.go | 2 +- transport/vmess/tls.go | 4 +- transport/vmess/vmess.go | 2 +- transport/vmess/websocket.go | 8 +- tunnel/connection.go | 6 +- tunnel/statistic/manager.go | 2 +- tunnel/statistic/tracker.go | 10 +- tunnel/tunnel.go | 20 ++-- 325 files changed, 1297 insertions(+), 1315 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index bd44d025..d68bd252 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -13,8 +13,8 @@ Please verify that you've followed these steps " options: - label: " -确保你使用的是**本仓库**最新的的 clash 或 clash Alpha 版本 -Ensure you are using the latest version of Clash or Clash Premium from **this repository**. +确保你使用的是**本仓库**最新的的 mihomo 或 mihomo Alpha 版本 +Ensure you are using the latest version of Mihomo or Mihomo Alpha from **this repository**. " required: true - label: " @@ -38,14 +38,14 @@ I have read the [documentation](https://wiki.metacubex.one/) and was unable to s " required: true - label: " -这是 Clash 核心的问题,并非我所使用的 Clash 衍生版本(如 OpenClash、KoolClash 等)的特定问题 -This is an issue of the Clash core *per se*, not to the derivatives of Clash, like OpenClash or KoolClash. +这是 Mihomo 核心的问题,并非我所使用的 Mihomo 衍生版本(如 OpenMihomo、KoolMihomo 等)的特定问题 +This is an issue of the Mihomo core *per se*, not to the derivatives of Mihomo, like OpenMihomo or KoolMihomo. " required: true - type: input attributes: - label: Clash version - description: "use `clash -v`" + label: Mihomo version + description: "use `mihomo -v`" validations: required: true - type: dropdown @@ -61,20 +61,20 @@ This is an issue of the Clash core *per se*, not to the derivatives of Clash, li - type: textarea attributes: render: yaml - label: "Clash config" + label: "Mihomo config" description: " -在下方附上 Clash core 配置文件,请确保配置文件中没有敏感信息(比如:服务器地址,密码,端口等) -Paste the Clash core configuration file below, please make sure that there is no sensitive information in the configuration file (e.g., server address/url, password, port) +在下方附上 Mihomo core 配置文件,请确保配置文件中没有敏感信息(比如:服务器地址,密码,端口等) +Paste the Mihomo core configuration file below, please make sure that there is no sensitive information in the configuration file (e.g., server address/url, password, port) " validations: required: true - type: textarea attributes: render: shell - label: Clash log + label: Mihomo log description: " -在下方附上 Clash Core 的日志,log level 使用 DEBUG -Paste the Clash core log below with the log level set to `DEBUG`. +在下方附上 Mihomo Core 的日志,log level 使用 DEBUG +Paste the Mihomo core log below with the log level set to `DEBUG`. " - type: textarea attributes: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0cf54628..75d37b63 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Clash.Meta Community Support - url: https://github.com/MetaCubeX/Clash.Meta/discussions - about: Please ask and answer questions about Clash.Meta here. + - name: mihomo Community Support + url: https://github.com/MetaCubeX/mihomo/discussions + about: Please ask and answer questions about mihomo here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index a32d313d..7987526c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -25,7 +25,7 @@ I have read the [documentation](https://wiki.metacubex.one/) and was unable to s - type: textarea attributes: label: Description - description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Clash Core 的行为是什麽? + description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Mihomo Core 的行为是什麽? validations: required: true - type: textarea diff --git a/.github/rename-cgo.sh b/.github/rename-cgo.sh index a0d736de..2bfdb3c6 100644 --- a/.github/rename-cgo.sh +++ b/.github/rename-cgo.sh @@ -5,25 +5,25 @@ for FILENAME in $FILENAMES do if [[ $FILENAME =~ "darwin-10.16-arm64" ]];then echo "rename darwin-10.16-arm64 $FILENAME" - mv $FILENAME clash.meta-darwin-arm64-cgo + mv $FILENAME mihomo-darwin-arm64-cgo elif [[ $FILENAME =~ "darwin-10.16-amd64" ]];then echo "rename darwin-10.16-amd64 $FILENAME" - mv $FILENAME clash.meta-darwin-amd64-cgo + mv $FILENAME mihomo-darwin-amd64-cgo elif [[ $FILENAME =~ "windows-4.0-386" ]];then echo "rename windows 386 $FILENAME" - mv $FILENAME clash.meta-windows-386-cgo.exe + mv $FILENAME mihomo-windows-386-cgo.exe elif [[ $FILENAME =~ "windows-4.0-amd64" ]];then echo "rename windows amd64 $FILENAME" - mv $FILENAME clash.meta-windows-amd64-cgo.exe - elif [[ $FILENAME =~ "clash.meta-linux-arm-5" ]];then - echo "rename clash.meta-linux-arm-5 $FILENAME" - mv $FILENAME clash.meta-linux-armv5-cgo - elif [[ $FILENAME =~ "clash.meta-linux-arm-6" ]];then - echo "rename clash.meta-linux-arm-6 $FILENAME" - mv $FILENAME clash.meta-linux-armv6-cgo - elif [[ $FILENAME =~ "clash.meta-linux-arm-7" ]];then - echo "rename clash.meta-linux-arm-7 $FILENAME" - mv $FILENAME clash.meta-linux-armv7-cgo + mv $FILENAME mihomo-windows-amd64-cgo.exe + elif [[ $FILENAME =~ "mihomo-linux-arm-5" ]];then + echo "rename mihomo-linux-arm-5 $FILENAME" + mv $FILENAME mihomo-linux-armv5-cgo + elif [[ $FILENAME =~ "mihomo-linux-arm-6" ]];then + echo "rename mihomo-linux-arm-6 $FILENAME" + mv $FILENAME mihomo-linux-armv6-cgo + elif [[ $FILENAME =~ "mihomo-linux-arm-7" ]];then + echo "rename mihomo-linux-arm-7 $FILENAME" + mv $FILENAME mihomo-linux-armv7-cgo elif [[ $FILENAME =~ "linux" ]];then echo "rename linux $FILENAME" mv $FILENAME $FILENAME-cgo diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml index c7ee5eba..fd7c9d66 100644 --- a/.github/workflows/android-branch-auto-sync.yml +++ b/.github/workflows/android-branch-auto-sync.yml @@ -50,8 +50,8 @@ jobs: run: | git push origin android-real --force - # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies - trigger-CMFA-update: + # Send "core-updated" to MetaCubeX/MihomoForAndroid to trigger update-dependencies + trigger-MFA-update: needs: update-dependencies runs-on: ubuntu-latest steps: @@ -63,7 +63,7 @@ jobs: - name: Trigger update-dependencies run: | - curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ + curl -X POST https://api.github.com/repos/MetaCubeX/MihomoForAndroid/dispatches \ -H "Accept: application/vnd.github.everest-preview+json" \ -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ -d '{"event_type": "core-updated"}' \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57a00f3e..a644f97a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -118,7 +118,7 @@ jobs: - name: Set ENV run: | sudo timedatectl set-timezone "Asia/Shanghai" - echo "NAME=clash.meta" >> $GITHUB_ENV + echo "NAME=mihomo" >> $GITHUB_ENV echo "REPO=${{ github.repository }}" >> $GITHUB_ENV echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV echo "BUILDTIME=$(date)" >> $GITHUB_ENV @@ -128,7 +128,7 @@ jobs: - name: Set ENV run: | echo "TAGS=with_gvisor,with_lwip" >> $GITHUB_ENV - echo "LDFLAGS=-X 'github.com/Dreamacro/clash/constant.Version=${VERSION}' -X 'github.com/Dreamacro/clash/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" >> $GITHUB_ENV + echo "LDFLAGS=-X 'github.com/metacubex/mihomo/constant.Version=${VERSION}' -X 'github.com/metacubex/mihomo/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" >> $GITHUB_ENV shell: bash - name: Setup Go @@ -153,7 +153,7 @@ jobs: - name: Build WithoutCGO if: ${{ matrix.job.type!='WithCGO' }} env: - NAME: Clash.Meta + NAME: mihomo BINDIR: bin run: make -j$(($(nproc) + 1)) ${{ matrix.job.target }} @@ -271,7 +271,7 @@ jobs: Release created at ${{ env.BUILDTIME }} Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version
- [我应该下载哪个文件? / Which file should I download?](https://github.com/MetaCubeX/Clash.Meta/wiki/FAQ) + [我应该下载哪个文件? / Which file should I download?](https://github.com/MetaCubeX/mihomo/wiki/FAQ) [查看文档 / Docs](https://metacubex.github.io/Meta-Docs/) EOF diff --git a/.golangci.yaml b/.golangci.yaml index f5b67397..1de71ad8 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -11,7 +11,7 @@ linters-settings: custom-order: true sections: - standard - - prefix(github.com/Dreamacro/clash) + - prefix(github.com/metacubex/mihomo) - default staticcheck: go: '1.19' diff --git a/Dockerfile b/Dockerfile index 6c5a91f9..c9cd56b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,25 +3,25 @@ ARG TARGETPLATFORM RUN echo "I'm building for $TARGETPLATFORM" RUN apk add --no-cache gzip && \ - mkdir /clash-config && \ - wget -O /clash-config/geoip.metadb https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb && \ - wget -O /clash-config/geosite.dat https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat && \ - wget -O /clash-config/geoip.dat https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat + mkdir /mihomo-config && \ + wget -O /mihomo-config/geoip.metadb https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb && \ + wget -O /mihomo-config/geosite.dat https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat && \ + wget -O /mihomo-config/geoip.dat https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat -COPY docker/file-name.sh /clash/file-name.sh -WORKDIR /clash +COPY docker/file-name.sh /mihomo/file-name.sh +WORKDIR /mihomo COPY bin/ bin/ RUN FILE_NAME=`sh file-name.sh` && echo $FILE_NAME && \ FILE_NAME=`ls bin/ | egrep "$FILE_NAME.*"|awk NR==1` && echo $FILE_NAME && \ - mv bin/$FILE_NAME clash.gz && gzip -d clash.gz && echo "$FILE_NAME" > /clash-config/test + mv bin/$FILE_NAME mihomo.gz && gzip -d mihomo.gz && echo "$FILE_NAME" > /mihomo-config/test FROM alpine:latest -LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/Clash.Meta" +LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/mihomo" RUN apk add --no-cache ca-certificates tzdata iptables -VOLUME ["/root/.config/clash/"] +VOLUME ["/root/.config/mihomo/"] -COPY --from=builder /clash-config/ /root/.config/clash/ -COPY --from=builder /clash/clash /clash -RUN chmod +x /clash -ENTRYPOINT [ "/clash" ] +COPY --from=builder /mihomo-config/ /root/.config/mihomo/ +COPY --from=builder /mihomo/mihomo /mihomo +RUN chmod +x /mihomo +ENTRYPOINT [ "/mihomo" ] diff --git a/Makefile b/Makefile index 028b986c..f6ffcae5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -NAME=clash.meta +NAME=mihomo BINDIR=bin BRANCH=$(shell git branch --show-current) ifeq ($(BRANCH),Alpha) @@ -12,8 +12,8 @@ VERSION=$(shell git rev-parse --short HEAD) endif BUILDTIME=$(shell date -u) -GOBUILD=CGO_ENABLED=0 go build -tags with_gvisor -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \ - -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \ +GOBUILD=CGO_ENABLED=0 go build -tags with_gvisor -trimpath -ldflags '-X "github.com/metacubex/mihomo/constant.Version=$(VERSION)" \ + -X "github.com/metacubex/mihomo/constant.BuildTime=$(BUILDTIME)" \ -w -s -buildid=' PLATFORM_LIST = \ diff --git a/README.md b/README.md index d5022dfb..8c82536c 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,17 @@
Meta Kernel
-

Another Clash Kernel.

+

Another Mihomo Kernel.

- - + + - - - + + + - +

@@ -27,7 +27,7 @@ - Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node based off latency - Remote providers, allowing users to get node lists remotely instead of hard-coding in config -- Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`. +- Netfilter TCP redirecting. Deploy Mihomo on your Internet gateway with `iptables`. - Comprehensive HTTP RESTful API controller ## Dashboard @@ -36,22 +36,22 @@ A web dashboard with first-class support for this project has been created; it c ## Configration example -Configuration example is located at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml). +Configuration example is located at [/docs/config.yaml](https://github.com/MetaCubeX/mihomo/blob/Alpha/docs/config.yaml). ## Docs -Documentation can be found in [Clash.Meta Docs](https://clash-meta.wiki). +Documentation can be found in [mihomo Docs](https://wiki.metacubex.one/). ## For development Requirements: [Go 1.20 or newer](https://go.dev/dl/) -Build Clash.Meta: +Build mihomo: ```shell -git clone https://github.com/MetaCubeX/Clash.Meta.git -cd Clash.Meta && go mod download +git clone https://github.com/MetaCubeX/mihomo.git +cd mihomo && go mod download go build ``` @@ -98,4 +98,4 @@ API. This software is released under the GPL-3.0 license. -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FDreamacro%2Fclash.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FDreamacro%2Fclash?ref=badge_large) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FMetaCubeX%2Fmihomo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FMetaCubeX%2Fmihomo?ref=badge_large) diff --git a/adapter/adapter.go b/adapter/adapter.go index 62941e6d..74b11bd9 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -12,12 +12,12 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/queue" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/queue" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/puzpuzpuz/xsync/v2" ) diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index df03b84a..a9896c8c 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -3,7 +3,7 @@ package inbound import ( "net" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Addition func(metadata *C.Metadata) diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go index 4022659f..984c9bd6 100644 --- a/adapter/inbound/auth.go +++ b/adapter/inbound/auth.go @@ -4,7 +4,7 @@ import ( "net" "net/netip" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) var skipAuthPrefixes []netip.Prefix diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 7f3b143f..137e17d3 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -3,8 +3,8 @@ package inbound import ( "net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) // NewHTTP receive normal http request and return HTTPContext diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 891ac9e7..55f6731a 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -4,7 +4,7 @@ import ( "net" "net/http" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) // NewHTTPS receive CONNECT request and return ConnContext diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index 0e3f6c48..7e245f98 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -1,8 +1,8 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) // NewPacket is PacketAdapter generator diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 21cb490b..8cd301f7 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -3,8 +3,8 @@ package inbound import ( "net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) // NewSocket receive TCP inbound and return ConnContext diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index acae7c3e..743337fc 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -7,9 +7,9 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/common/nnip" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/common/nnip" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) func parseSocksAddr(target socks5.Addr) *C.Metadata { diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index ba991bfc..ae8c4651 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -7,10 +7,10 @@ import ( "strings" "syscall" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" ) type Base struct { diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index 75e999a6..b9b9fefc 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -5,10 +5,10 @@ import ( "errors" "net/netip" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" ) type Direct struct { diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 19074bb3..b837e49a 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -13,11 +13,11 @@ import ( "net/http" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" ) type Http struct { diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 5a41274c..dacffd10 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -14,17 +14,17 @@ import ( "github.com/metacubex/quic-go/congestion" M "github.com/sagernet/sing/common/metadata" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - hyCongestion "github.com/Dreamacro/clash/transport/hysteria/congestion" - "github.com/Dreamacro/clash/transport/hysteria/core" - "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/pmtud_fix" - "github.com/Dreamacro/clash/transport/hysteria/transport" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + hyCongestion "github.com/metacubex/mihomo/transport/hysteria/congestion" + "github.com/metacubex/mihomo/transport/hysteria/core" + "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/pmtud_fix" + "github.com/metacubex/mihomo/transport/hysteria/transport" + "github.com/metacubex/mihomo/transport/hysteria/utils" ) const ( diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 6ed4cd8c..ddd5ccea 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -9,12 +9,12 @@ import ( "runtime" "strconv" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - tuicCommon "github.com/Dreamacro/clash/transport/tuic/common" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + tuicCommon "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/sing-quic/hysteria2" diff --git a/adapter/outbound/reality.go b/adapter/outbound/reality.go index 23314e5f..766138da 100644 --- a/adapter/outbound/reality.go +++ b/adapter/outbound/reality.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "errors" - tlsC "github.com/Dreamacro/clash/component/tls" + tlsC "github.com/metacubex/mihomo/component/tls" "golang.org/x/crypto/curve25519" ) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index f1de3981..5625f932 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -6,9 +6,9 @@ import ( "net" "time" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" ) type Reject struct { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 1ae16c43..ffc72abb 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -7,16 +7,16 @@ import ( "net" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/structure" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/restls" - obfs "github.com/Dreamacro/clash/transport/simple-obfs" - shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls" - v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/restls" + obfs "github.com/metacubex/mihomo/transport/simple-obfs" + shadowtls "github.com/metacubex/mihomo/transport/sing-shadowtls" + v2rayObfs "github.com/metacubex/mihomo/transport/v2ray-plugin" restlsC "github.com/3andne/restls-client-go" shadowsocks "github.com/metacubex/sing-shadowsocks2" diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 0f03f86d..07d78047 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -7,16 +7,16 @@ import ( "net" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/ssr/obfs" - "github.com/Dreamacro/clash/transport/ssr/protocol" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowstream" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/ssr/obfs" + "github.com/metacubex/mihomo/transport/ssr/protocol" ) type ShadowSocksR struct { @@ -125,7 +125,7 @@ func (ssr *ShadowSocksR) SupportWithDialer() C.NetWork { func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { // SSR protocol compatibility - // https://github.com/Dreamacro/clash/pull/2056 + // https://github.com/metacubex/mihomo/pull/2056 if option.Cipher == "none" { option.Cipher = "dummy" } diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index fb6b1c29..dff1e8eb 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -5,11 +5,11 @@ import ( "errors" "runtime" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" mux "github.com/sagernet/sing-mux" E "github.com/sagernet/sing/common/exceptions" diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index 16405fcf..76ed4be9 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -6,13 +6,13 @@ import ( "net" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/structure" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - obfs "github.com/Dreamacro/clash/transport/simple-obfs" - "github.com/Dreamacro/clash/transport/snell" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + obfs "github.com/metacubex/mihomo/transport/simple-obfs" + "github.com/metacubex/mihomo/transport/snell" ) type Snell struct { diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 43dfe8ef..c17ee6a7 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -10,12 +10,12 @@ import ( "net/netip" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type Socks5 struct { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index d3c14e8a..cd1dd28c 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -8,14 +8,14 @@ import ( "net/http" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/gun" - "github.com/Dreamacro/clash/transport/trojan" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/gun" + "github.com/metacubex/mihomo/transport/trojan" ) type Trojan struct { diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 93e49dc7..666e72fa 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -10,12 +10,12 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/tuic" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/tuic" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index b048cd8b..ce9e5f65 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -11,9 +11,9 @@ import ( "strconv" "sync" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) var ( diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 5f54153b..dbe8b1a4 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -12,20 +12,20 @@ import ( "strconv" "sync" - "github.com/Dreamacro/clash/common/convert" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/gun" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/vless" - "github.com/Dreamacro/clash/transport/vmess" + "github.com/metacubex/mihomo/common/convert" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/gun" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/vless" + "github.com/metacubex/mihomo/transport/vmess" vmessSing "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index aed61aa3..8811fb0d 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -11,17 +11,17 @@ import ( "strings" "sync" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/ntp" - "github.com/Dreamacro/clash/transport/gun" - clashVMess "github.com/Dreamacro/clash/transport/vmess" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/ntp" + "github.com/metacubex/mihomo/transport/gun" + mihomoVMess "github.com/metacubex/mihomo/transport/vmess" vmess "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" @@ -105,7 +105,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M switch v.option.Network { case "ws": host, port, _ := net.SplitHostPort(v.addr) - wsOpts := &clashVMess.WebsocketConfig{ + wsOpts := &mihomoVMess.WebsocketConfig{ Host: host, Port: port, Path: v.option.WSOpts.Path, @@ -141,12 +141,12 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M wsOpts.TLSConfig.ServerName = host } } - c, err = clashVMess.StreamWebsocketConn(ctx, c, wsOpts) + c, err = mihomoVMess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic if v.option.TLS { host, _, _ := net.SplitHostPort(v.addr) - tlsOpts := &clashVMess.TLSConfig{ + tlsOpts := &mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, @@ -157,24 +157,24 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M if v.option.ServerName != "" { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) + c, err = mihomoVMess.StreamTLSConn(ctx, c, tlsOpts) if err != nil { return nil, err } } host, _, _ := net.SplitHostPort(v.addr) - httpOpts := &clashVMess.HTTPConfig{ + httpOpts := &mihomoVMess.HTTPConfig{ Host: host, Method: v.option.HTTPOpts.Method, Path: v.option.HTTPOpts.Path, Headers: v.option.HTTPOpts.Headers, } - c = clashVMess.StreamHTTPConn(c, httpOpts) + c = mihomoVMess.StreamHTTPConn(c, httpOpts) case "h2": host, _, _ := net.SplitHostPort(v.addr) - tlsOpts := clashVMess.TLSConfig{ + tlsOpts := mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, NextProtos: []string{"h2"}, @@ -186,24 +186,24 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(ctx, c, &tlsOpts) + c, err = mihomoVMess.StreamTLSConn(ctx, c, &tlsOpts) if err != nil { return nil, err } - h2Opts := &clashVMess.H2Config{ + h2Opts := &mihomoVMess.H2Config{ Hosts: v.option.HTTP2Opts.Host, Path: v.option.HTTP2Opts.Path, } - c, err = clashVMess.StreamH2Conn(c, h2Opts) + c, err = mihomoVMess.StreamH2Conn(c, h2Opts) case "grpc": c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // handle TLS if v.option.TLS { host, _, _ := net.SplitHostPort(v.addr) - tlsOpts := &clashVMess.TLSConfig{ + tlsOpts := &mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, @@ -215,7 +215,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) + c, err = mihomoVMess.StreamTLSConn(ctx, c, tlsOpts) } } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 6a11a234..9af1751b 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -13,13 +13,13 @@ import ( "strings" "sync" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/dns" - "github.com/Dreamacro/clash/log" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/dns" + "github.com/metacubex/mihomo/log" wireguard "github.com/metacubex/sing-wireguard" diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 899b9a9b..d0dd98b1 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -6,13 +6,13 @@ import ( "errors" "time" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/callback" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/callback" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type Fallback struct { diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 22dd407b..d4a812f6 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -7,14 +7,14 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - types "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + types "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" "github.com/dlclark/regexp2" ) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index e336c5f0..885aeaee 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -9,14 +9,14 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/common/callback" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/callback" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" "golang.org/x/net/publicsuffix" ) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index a8bdc557..8f3335d8 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -5,12 +5,12 @@ import ( "fmt" "strings" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/adapter/provider" - "github.com/Dreamacro/clash/common/structure" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - types "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/adapter/provider" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + types "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index ba733616..2b1be8a5 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -3,11 +3,11 @@ package outboundgroup import ( "context" "encoding/json" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type Relay struct { diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go index 96934f0c..4d06c544 100644 --- a/adapter/outboundgroup/selector.go +++ b/adapter/outboundgroup/selector.go @@ -5,10 +5,10 @@ import ( "encoding/json" "errors" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type Selector struct { diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 3f6c6ab0..8c861768 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -6,13 +6,13 @@ import ( "errors" "time" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/callback" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/singledo" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/callback" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/singledo" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type urlTestOption func(*URLTest) diff --git a/adapter/parser.go b/adapter/parser.go index 43ebfe5f..1d363c1f 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -3,11 +3,11 @@ package adapter import ( "fmt" - tlsC "github.com/Dreamacro/clash/component/tls" + tlsC "github.com/metacubex/mihomo/component/tls" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/structure" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/structure" + C "github.com/metacubex/mihomo/constant" ) func ParseProxy(mapping map[string]any) (C.Proxy, error) { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index feb972ab..e7f021e1 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -6,12 +6,12 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/batch" - "github.com/Dreamacro/clash/common/singledo" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/batch" + "github.com/metacubex/mihomo/common/singledo" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/dlclark/regexp2" ) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index d885a546..321380ed 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -5,11 +5,11 @@ import ( "fmt" "time" - "github.com/Dreamacro/clash/common/structure" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/resource" - C "github.com/Dreamacro/clash/constant" - types "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + types "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index d547dcb7..ffaec91b 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -10,15 +10,15 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/common/convert" - "github.com/Dreamacro/clash/common/utils" - clashHttp "github.com/Dreamacro/clash/component/http" - "github.com/Dreamacro/clash/component/resource" - C "github.com/Dreamacro/clash/constant" - types "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel/statistic" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/common/convert" + "github.com/metacubex/mihomo/common/utils" + mihomoHttp "github.com/metacubex/mihomo/component/http" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + types "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel/statistic" "github.com/dlclark/regexp2" "gopkg.in/yaml.v3" @@ -119,8 +119,8 @@ func (pp *proxySetProvider) getSubscriptionInfo() { go func() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), - http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), + http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } @@ -128,7 +128,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo")) if userInfoStr == "" { - resp2, err := clashHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), + resp2, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil) if err != nil { return diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go index 2f9d3e79..d71cc3b9 100644 --- a/common/cache/lrucache.go +++ b/common/cache/lrucache.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/generics/list" + "github.com/metacubex/mihomo/common/generics/list" "github.com/samber/lo" ) diff --git a/common/callback/callback.go b/common/callback/callback.go index fe76dc67..9ae0f94a 100644 --- a/common/callback/callback.go +++ b/common/callback/callback.go @@ -1,9 +1,9 @@ package callback import ( - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" ) type firstWriteCallBackConn struct { diff --git a/common/convert/converter.go b/common/convert/converter.go index 5a618f42..55035bbe 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -9,10 +9,10 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) -// ConvertsV2Ray convert V2Ray subscribe proxies data to clash proxies config +// ConvertsV2Ray convert V2Ray subscribe proxies data to mihomo proxies config func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { data := DecodeBase64(buf) diff --git a/common/convert/util.go b/common/convert/util.go index 0ec35acd..a715b556 100644 --- a/common/convert/util.go +++ b/common/convert/util.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/sing-shadowsocks/shadowimpl" "github.com/zhangyunhao116/fastrand" diff --git a/common/net/bufconn.go b/common/net/bufconn.go index b840fefc..37c8ba25 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -4,7 +4,7 @@ import ( "bufio" "net" - "github.com/Dreamacro/clash/common/buf" + "github.com/metacubex/mihomo/common/buf" ) var _ ExtendedConn = (*BufferedConn)(nil) diff --git a/common/net/cached.go b/common/net/cached.go index 3b7da44c..fb605b74 100644 --- a/common/net/cached.go +++ b/common/net/cached.go @@ -3,7 +3,7 @@ package net import ( "net" - "github.com/Dreamacro/clash/common/buf" + "github.com/metacubex/mihomo/common/buf" ) var _ ExtendedConn = (*CachedConn)(nil) diff --git a/common/net/deadline/packet.go b/common/net/deadline/packet.go index bcf2db9d..67043198 100644 --- a/common/net/deadline/packet.go +++ b/common/net/deadline/packet.go @@ -6,8 +6,8 @@ import ( "runtime" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/net/packet" ) type readResult struct { diff --git a/common/net/deadline/packet_enhance.go b/common/net/deadline/packet_enhance.go index 5b7d767f..3e314fb8 100644 --- a/common/net/deadline/packet_enhance.go +++ b/common/net/deadline/packet_enhance.go @@ -5,7 +5,7 @@ import ( "os" "runtime" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/net/packet" ) type EnhancePacketConn struct { diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go index f41f3f5b..65db1b8f 100644 --- a/common/net/deadline/packet_sing.go +++ b/common/net/deadline/packet_sing.go @@ -4,7 +4,7 @@ import ( "os" "runtime" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/net/packet" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" diff --git a/common/net/packet.go b/common/net/packet.go index fc562c42..fd03b4f8 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -1,8 +1,8 @@ package net import ( - "github.com/Dreamacro/clash/common/net/deadline" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/net/deadline" + "github.com/metacubex/mihomo/common/net/packet" ) type EnhancePacketConn = packet.EnhancePacketConn diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go index 6c9542c1..0cdbccae 100644 --- a/common/net/packet/packet.go +++ b/common/net/packet/packet.go @@ -3,7 +3,7 @@ package packet import ( "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type WaitReadFrom interface { diff --git a/common/net/packet/packet_posix.go b/common/net/packet/packet_posix.go index 2861482f..2073e35d 100644 --- a/common/net/packet/packet_posix.go +++ b/common/net/packet/packet_posix.go @@ -7,7 +7,7 @@ import ( "strconv" "syscall" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type enhanceUDPConn struct { diff --git a/common/net/refconn.go b/common/net/refconn.go index 5caaebc8..6d0dde98 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -5,7 +5,7 @@ import ( "runtime" "time" - "github.com/Dreamacro/clash/common/buf" + "github.com/metacubex/mihomo/common/buf" ) type refConn struct { diff --git a/common/net/relay.go b/common/net/relay.go index 6191e76b..f2a1b146 100644 --- a/common/net/relay.go +++ b/common/net/relay.go @@ -12,7 +12,7 @@ package net // // go func() { // // Wrapping to avoid using *net.TCPConn.(ReadFrom) -// // See also https://github.com/Dreamacro/clash/pull/1209 +// // See also https://github.com/metacubex/mihomo/pull/1209 // _, err := io.Copy(WriteOnlyWriter{Writer: leftConn}, ReadOnlyReader{Reader: rightConn}) // leftConn.SetReadDeadline(time.Now()) // ch <- err diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go index 5a02273d..d263cb94 100644 --- a/common/observable/observable_test.go +++ b/common/observable/observable_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" "github.com/stretchr/testify/assert" ) diff --git a/common/singledo/singledo_test.go b/common/singledo/singledo_test.go index 9e114fb7..2f92f0ae 100644 --- a/common/singledo/singledo_test.go +++ b/common/singledo/singledo_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" "github.com/stretchr/testify/assert" ) diff --git a/component/dhcp/conn.go b/component/dhcp/conn.go index 5b71d3cd..ff26275b 100644 --- a/component/dhcp/conn.go +++ b/component/dhcp/conn.go @@ -5,7 +5,7 @@ import ( "net" "runtime" - "github.com/Dreamacro/clash/component/dialer" + "github.com/metacubex/mihomo/component/dialer" ) func ListenDHCPClient(ctx context.Context, ifaceName string) (net.PacketConn, error) { diff --git a/component/dhcp/dhcp.go b/component/dhcp/dhcp.go index be2c578a..04ad2eda 100644 --- a/component/dhcp/dhcp.go +++ b/component/dhcp/dhcp.go @@ -6,8 +6,8 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/component/iface" "github.com/insomniacslk/dhcp/dhcpv4" ) diff --git a/component/dialer/bind.go b/component/dialer/bind.go index c90212ef..72df8c72 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/iface" ) func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index 8705a708..f83b86f8 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -6,7 +6,7 @@ import ( "net/netip" "syscall" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/iface" "golang.org/x/sys/unix" ) diff --git a/component/dialer/bind_windows.go b/component/dialer/bind_windows.go index 0d38d1c5..120f1657 100644 --- a/component/dialer/bind_windows.go +++ b/component/dialer/bind_windows.go @@ -9,7 +9,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/iface" ) const ( diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 3cb8bba9..0e0e3cef 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/component/resolver" ) type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) diff --git a/component/dialer/mark_nonlinux.go b/component/dialer/mark_nonlinux.go index ea448276..64e58784 100644 --- a/component/dialer/mark_nonlinux.go +++ b/component/dialer/mark_nonlinux.go @@ -7,7 +7,7 @@ import ( "net/netip" "sync" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) var printMarkWarnOnce sync.Once diff --git a/component/dialer/options.go b/component/dialer/options.go index 781d7164..c0c21891 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -4,8 +4,8 @@ import ( "context" "net" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/component/resolver" ) var ( diff --git a/component/ebpf/bpf/redir.c b/component/ebpf/bpf/redir.c index a24afec8..6ef5ee0c 100644 --- a/component/ebpf/bpf/redir.c +++ b/component/ebpf/bpf/redir.c @@ -173,7 +173,7 @@ static __always_inline bool is_lan_ip(__be32 addr) { return false; } -SEC("tc_clash_auto_redir_ingress") +SEC("tc_mihomo_auto_redir_ingress") int tc_redir_ingress_func(struct __sk_buff *skb) { void *data = (void *)(long)skb->data; void *data_end = (void *)(long)skb->data_end; @@ -264,7 +264,7 @@ int tc_redir_ingress_func(struct __sk_buff *skb) { return TC_ACT_OK; } -SEC("tc_clash_auto_redir_egress") +SEC("tc_mihomo_auto_redir_egress") int tc_redir_egress_func(struct __sk_buff *skb) { void *data = (void *)(long)skb->data; void *data_end = (void *)(long)skb->data_end; @@ -276,10 +276,10 @@ int tc_redir_egress_func(struct __sk_buff *skb) { if (eth->h_proto != bpf_htons(ETH_P_IP)) return TC_ACT_OK; - __u32 key = 0, *redir_ip, *redir_port; // *clash_mark + __u32 key = 0, *redir_ip, *redir_port; // *mihomo_mark -// clash_mark = bpf_map_lookup_elem(&redir_params_map, &key); -// if (clash_mark && *clash_mark != 0 && *clash_mark == skb->mark) +// mihomo_mark = bpf_map_lookup_elem(&redir_params_map, &key); +// if (mihomo_mark && *mihomo_mark != 0 && *mihomo_mark == skb->mark) // return TC_ACT_OK; struct iphdr *iph = (struct iphdr *)(eth + 1); diff --git a/component/ebpf/bpf/tc.c b/component/ebpf/bpf/tc.c index 4eebf41c..3513bf04 100644 --- a/component/ebpf/bpf/tc.c +++ b/component/ebpf/bpf/tc.c @@ -38,7 +38,7 @@ static __always_inline bool is_lan_ip(__be32 addr) { return false; } -SEC("tc_clash_redirect_to_tun") +SEC("tc_mihomo_redirect_to_tun") int tc_tun_func(struct __sk_buff *skb) { void *data = (void *)(long)skb->data; void *data_end = (void *)(long)skb->data_end; @@ -50,13 +50,13 @@ int tc_tun_func(struct __sk_buff *skb) { if (eth->h_proto == bpf_htons(ETH_P_ARP)) return TC_ACT_OK; - __u32 key = 0, *clash_mark, *tun_ifindex; + __u32 key = 0, *mihomo_mark, *tun_ifindex; - clash_mark = bpf_map_lookup_elem(&tc_params_map, &key); - if (!clash_mark) + mihomo_mark = bpf_map_lookup_elem(&tc_params_map, &key); + if (!mihomo_mark) return TC_ACT_OK; - if (skb->mark == *clash_mark) + if (skb->mark == *mihomo_mark) return TC_ACT_OK; if (eth->h_proto == bpf_htons(ETH_P_IP)) { diff --git a/component/ebpf/ebpf.go b/component/ebpf/ebpf.go index 6257675c..b0f5a65f 100644 --- a/component/ebpf/ebpf.go +++ b/component/ebpf/ebpf.go @@ -3,8 +3,8 @@ package ebpf import ( "net/netip" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type TcEBpfProgram struct { diff --git a/component/ebpf/ebpf_linux.go b/component/ebpf/ebpf_linux.go index 2ffd4bd5..304f32fe 100644 --- a/component/ebpf/ebpf_linux.go +++ b/component/ebpf/ebpf_linux.go @@ -6,11 +6,11 @@ import ( "fmt" "net/netip" - "github.com/Dreamacro/clash/common/cmd" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/ebpf/redir" - "github.com/Dreamacro/clash/component/ebpf/tc" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/cmd" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/ebpf/redir" + "github.com/metacubex/mihomo/component/ebpf/tc" + C "github.com/metacubex/mihomo/constant" "github.com/sagernet/netlink" ) @@ -47,7 +47,7 @@ func NewTcEBpfProgram(ifaceNames []string, tunName string) (*TcEBpfProgram, erro tunIndex := uint32(tunIface.Attrs().Index) - dialer.DefaultRoutingMark.Store(C.ClashTrafficMark) + dialer.DefaultRoutingMark.Store(C.MihomoTrafficMark) ifMark := uint32(dialer.DefaultRoutingMark.Load()) diff --git a/component/ebpf/redir/auto_redirect.go b/component/ebpf/redir/auto_redirect.go index 4fd8b785..57c99616 100644 --- a/component/ebpf/redir/auto_redirect.go +++ b/component/ebpf/redir/auto_redirect.go @@ -16,9 +16,9 @@ import ( "github.com/sagernet/netlink" "golang.org/x/sys/unix" - "github.com/Dreamacro/clash/component/ebpf/byteorder" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/component/ebpf/byteorder" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf ../bpf/redir.c @@ -131,7 +131,7 @@ func (e *EBpfRedirect) Start() error { filter := &netlink.BpfFilter{ FilterAttrs: filterAttrs, Fd: objs.bpfPrograms.TcRedirIngressFunc.FD(), - Name: "clash-redir-ingress-" + e.ifName, + Name: "mihomo-redir-ingress-" + e.ifName, DirectAction: true, } @@ -153,7 +153,7 @@ func (e *EBpfRedirect) Start() error { filterEgress := &netlink.BpfFilter{ FilterAttrs: filterAttrsEgress, Fd: objs.bpfPrograms.TcRedirEgressFunc.FD(), - Name: "clash-redir-egress-" + e.ifName, + Name: "mihomo-redir-egress-" + e.ifName, DirectAction: true, } diff --git a/component/ebpf/tc/redirect_to_tun.go b/component/ebpf/tc/redirect_to_tun.go index 1edc1781..d7be64af 100644 --- a/component/ebpf/tc/redirect_to_tun.go +++ b/component/ebpf/tc/redirect_to_tun.go @@ -14,8 +14,8 @@ import ( "github.com/sagernet/netlink" "golang.org/x/sys/unix" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf ../bpf/tc.c @@ -115,7 +115,7 @@ func (e *EBpfTC) Start() error { filter := &netlink.BpfFilter{ FilterAttrs: filterAttrs, Fd: objs.bpfPrograms.TcTunFunc.FD(), - Name: "clash-tc-" + e.ifName, + Name: "mihomo-tc-" + e.ifName, DirectAction: true, } diff --git a/component/fakeip/cachefile.go b/component/fakeip/cachefile.go index c31d751f..6f0cc48b 100644 --- a/component/fakeip/cachefile.go +++ b/component/fakeip/cachefile.go @@ -3,7 +3,7 @@ package fakeip import ( "net/netip" - "github.com/Dreamacro/clash/component/profile/cachefile" + "github.com/metacubex/mihomo/component/profile/cachefile" ) type cachefileStore struct { diff --git a/component/fakeip/memory.go b/component/fakeip/memory.go index 249c5e2a..f36bbb55 100644 --- a/component/fakeip/memory.go +++ b/component/fakeip/memory.go @@ -3,7 +3,7 @@ package fakeip import ( "net/netip" - "github.com/Dreamacro/clash/common/cache" + "github.com/metacubex/mihomo/common/cache" ) type memoryStore struct { diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index 9b51929e..2b06fc0b 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -6,9 +6,9 @@ import ( "strings" "sync" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/component/profile/cachefile" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/component/profile/cachefile" + "github.com/metacubex/mihomo/component/trie" ) const ( diff --git a/component/fakeip/pool_test.go b/component/fakeip/pool_test.go index 183a7185..a7569ab0 100644 --- a/component/fakeip/pool_test.go +++ b/component/fakeip/pool_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/component/profile/cachefile" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/component/profile/cachefile" + "github.com/metacubex/mihomo/component/trie" "github.com/stretchr/testify/assert" "go.etcd.io/bbolt" @@ -32,7 +32,7 @@ func createCachefileStore(options Options) (*Pool, string, error) { if err != nil { return nil, "", err } - f, err := os.CreateTemp("", "clash") + f, err := os.CreateTemp("", "mihomo") if err != nil { return nil, "", err } diff --git a/component/geodata/attr.go b/component/geodata/attr.go index e35a25ca..a9742aca 100644 --- a/component/geodata/attr.go +++ b/component/geodata/attr.go @@ -3,7 +3,7 @@ package geodata import ( "strings" - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata/router" ) type AttributeList struct { diff --git a/component/geodata/geodata.go b/component/geodata/geodata.go index 9d0b0df0..a6ef146a 100644 --- a/component/geodata/geodata.go +++ b/component/geodata/geodata.go @@ -3,8 +3,8 @@ package geodata import ( "fmt" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" ) type loader struct { diff --git a/component/geodata/geodataproto.go b/component/geodata/geodataproto.go index 34bdad70..0f1ce4d2 100644 --- a/component/geodata/geodataproto.go +++ b/component/geodata/geodataproto.go @@ -1,7 +1,7 @@ package geodata import ( - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata/router" ) type LoaderImplementation interface { diff --git a/component/geodata/init.go b/component/geodata/init.go index acae1a34..0b193c94 100644 --- a/component/geodata/init.go +++ b/component/geodata/init.go @@ -8,10 +8,10 @@ import ( "os" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - "github.com/Dreamacro/clash/component/mmdb" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + mihomoHttp "github.com/metacubex/mihomo/component/http" + "github.com/metacubex/mihomo/component/mmdb" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) var initGeoSite bool @@ -44,7 +44,7 @@ func InitGeoSite() error { func downloadGeoSite(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } @@ -63,7 +63,7 @@ func downloadGeoSite(path string) (err error) { func downloadGeoIP(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } diff --git a/component/geodata/memconservative/cache.go b/component/geodata/memconservative/cache.go index ca78d19d..ef76a42c 100644 --- a/component/geodata/memconservative/cache.go +++ b/component/geodata/memconservative/cache.go @@ -5,9 +5,9 @@ import ( "os" "strings" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "google.golang.org/protobuf/proto" ) diff --git a/component/geodata/memconservative/memc.go b/component/geodata/memconservative/memc.go index 88d3b4e5..30d89f10 100644 --- a/component/geodata/memconservative/memc.go +++ b/component/geodata/memconservative/memc.go @@ -5,8 +5,8 @@ import ( "fmt" "runtime" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" ) type memConservativeLoader struct { diff --git a/component/geodata/router/condition.go b/component/geodata/router/condition.go index 4e0ad46c..156614ae 100644 --- a/component/geodata/router/condition.go +++ b/component/geodata/router/condition.go @@ -7,7 +7,7 @@ import ( "sort" "strings" - "github.com/Dreamacro/clash/component/geodata/strmatcher" + "github.com/metacubex/mihomo/component/geodata/strmatcher" ) var matcherTypeMap = map[Domain_Type]strmatcher.Type{ diff --git a/component/geodata/router/config.pb.go b/component/geodata/router/config.pb.go index 7c3af22a..59d90c7a 100644 --- a/component/geodata/router/config.pb.go +++ b/component/geodata/router/config.pb.go @@ -84,7 +84,7 @@ type Domain struct { unknownFields protoimpl.UnknownFields // Domain matching type. - Type Domain_Type `protobuf:"varint,1,opt,name=type,proto3,enum=clash.component.geodata.router.Domain_Type" json:"type,omitempty"` + Type Domain_Type `protobuf:"varint,1,opt,name=type,proto3,enum=mihomo.component.geodata.router.Domain_Type" json:"type,omitempty"` // Domain value. Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` // Attributes of this domain. May be used for filtering. @@ -585,22 +585,22 @@ func file_component_geodata_router_config_proto_rawDescGZIP() []byte { var file_component_geodata_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_component_geodata_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_component_geodata_router_config_proto_goTypes = []interface{}{ - (Domain_Type)(0), // 0: clash.component.geodata.router.Domain.Type - (*Domain)(nil), // 1: clash.component.geodata.router.Domain - (*CIDR)(nil), // 2: clash.component.geodata.router.CIDR - (*GeoIP)(nil), // 3: clash.component.geodata.router.GeoIP - (*GeoIPList)(nil), // 4: clash.component.geodata.router.GeoIPList - (*GeoSite)(nil), // 5: clash.component.geodata.router.GeoSite - (*GeoSiteList)(nil), // 6: clash.component.geodata.router.GeoSiteList - (*Domain_Attribute)(nil), // 7: clash.component.geodata.router.Domain.Attribute + (Domain_Type)(0), // 0: mihomo.component.geodata.router.Domain.Type + (*Domain)(nil), // 1: mihomo.component.geodata.router.Domain + (*CIDR)(nil), // 2: mihomo.component.geodata.router.CIDR + (*GeoIP)(nil), // 3: mihomo.component.geodata.router.GeoIP + (*GeoIPList)(nil), // 4: mihomo.component.geodata.router.GeoIPList + (*GeoSite)(nil), // 5: mihomo.component.geodata.router.GeoSite + (*GeoSiteList)(nil), // 6: mihomo.component.geodata.router.GeoSiteList + (*Domain_Attribute)(nil), // 7: mihomo.component.geodata.router.Domain.Attribute } var file_component_geodata_router_config_proto_depIdxs = []int32{ - 0, // 0: clash.component.geodata.router.Domain.type:type_name -> clash.component.geodata.router.Domain.Type - 7, // 1: clash.component.geodata.router.Domain.attribute:type_name -> clash.component.geodata.router.Domain.Attribute - 2, // 2: clash.component.geodata.router.GeoIP.cidr:type_name -> clash.component.geodata.router.CIDR - 3, // 3: clash.component.geodata.router.GeoIPList.entry:type_name -> clash.component.geodata.router.GeoIP - 1, // 4: clash.component.geodata.router.GeoSite.domain:type_name -> clash.component.geodata.router.Domain - 5, // 5: clash.component.geodata.router.GeoSiteList.entry:type_name -> clash.component.geodata.router.GeoSite + 0, // 0: mihomo.component.geodata.router.Domain.type:type_name -> mihomo.component.geodata.router.Domain.Type + 7, // 1: mihomo.component.geodata.router.Domain.attribute:type_name -> mihomo.component.geodata.router.Domain.Attribute + 2, // 2: mihomo.component.geodata.router.GeoIP.cidr:type_name -> mihomo.component.geodata.router.CIDR + 3, // 3: mihomo.component.geodata.router.GeoIPList.entry:type_name -> mihomo.component.geodata.router.GeoIP + 1, // 4: mihomo.component.geodata.router.GeoSite.domain:type_name -> mihomo.component.geodata.router.Domain + 5, // 5: mihomo.component.geodata.router.GeoSiteList.entry:type_name -> mihomo.component.geodata.router.GeoSite 6, // [6:6] is the sub-list for method output_type 6, // [6:6] is the sub-list for method input_type 6, // [6:6] is the sub-list for extension type_name diff --git a/component/geodata/router/config.proto b/component/geodata/router/config.proto index 245faadf..98795740 100644 --- a/component/geodata/router/config.proto +++ b/component/geodata/router/config.proto @@ -1,9 +1,9 @@ syntax = "proto3"; -package clash.component.geodata.router; -option csharp_namespace = "Clash.Component.Geodata.Router"; -option go_package = "github.com/Dreamacro/clash/component/geodata/router"; -option java_package = "com.clash.component.geodata.router"; +package mihomo.component.geodata.router; +option csharp_namespace = "Mihomo.Component.Geodata.Router"; +option go_package = "github.com/metacubex/mihomo/component/geodata/router"; +option java_package = "com.mihomo.component.geodata.router"; option java_multiple_files = true; // Domain for routing decision. diff --git a/component/geodata/standard/standard.go b/component/geodata/standard/standard.go index 355cbf34..bfaae5ec 100644 --- a/component/geodata/standard/standard.go +++ b/component/geodata/standard/standard.go @@ -6,9 +6,9 @@ import ( "os" "strings" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" "google.golang.org/protobuf/proto" ) diff --git a/component/geodata/strmatcher/ac_automaton_matcher.go b/component/geodata/strmatcher/ac_automaton_matcher.go index d134c68a..ca7dc48b 100644 --- a/component/geodata/strmatcher/ac_automaton_matcher.go +++ b/component/geodata/strmatcher/ac_automaton_matcher.go @@ -1,7 +1,7 @@ package strmatcher import ( - "github.com/Dreamacro/clash/common/generics/list" + "github.com/metacubex/mihomo/common/generics/list" ) const validCharCount = 53 diff --git a/component/geodata/utils.go b/component/geodata/utils.go index 04ccfa51..4716ccbd 100644 --- a/component/geodata/utils.go +++ b/component/geodata/utils.go @@ -6,9 +6,9 @@ import ( "golang.org/x/sync/singleflight" "strings" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) var geoLoaderName = "memconservative" diff --git a/component/http/http.go b/component/http/http.go index 073f0237..455db681 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -11,9 +11,9 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/component/ca" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/inner" + "github.com/metacubex/mihomo/component/ca" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/inner" ) func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { diff --git a/component/iface/iface.go b/component/iface/iface.go index 03051cb3..bf186165 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/singledo" + "github.com/metacubex/mihomo/common/singledo" ) type Interface struct { diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go index 5db8bee9..f83b9922 100644 --- a/component/mmdb/mmdb.go +++ b/component/mmdb/mmdb.go @@ -8,9 +8,9 @@ import ( "sync" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + mihomoHttp "github.com/metacubex/mihomo/component/http" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/oschwald/maxminddb-golang" ) @@ -79,7 +79,7 @@ func Instance() Reader { func DownloadMMDB(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } diff --git a/component/nat/proxy.go b/component/nat/proxy.go index 29ff3c81..66af3be2 100644 --- a/component/nat/proxy.go +++ b/component/nat/proxy.go @@ -3,8 +3,8 @@ package nat import ( "net" - "github.com/Dreamacro/clash/common/atomic" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/atomic" + C "github.com/metacubex/mihomo/constant" ) type writeBackProxy struct { diff --git a/component/nat/table.go b/component/nat/table.go index df258dc2..b2908c94 100644 --- a/component/nat/table.go +++ b/component/nat/table.go @@ -4,7 +4,7 @@ import ( "net" "sync" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "github.com/puzpuzpuz/xsync/v2" ) diff --git a/component/process/process_freebsd_amd64.go b/component/process/process_freebsd_amd64.go index 709ade3b..1884afcc 100644 --- a/component/process/process_freebsd_amd64.go +++ b/component/process/process_freebsd_amd64.go @@ -10,8 +10,8 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/log" ) // store process name for when dealing with multiple PROCESS-NAME rules diff --git a/component/process/process_windows.go b/component/process/process_windows.go index 21878bf6..d43c78c6 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -7,8 +7,8 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/log" "golang.org/x/sys/windows" ) diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go index 3d2dd1de..68812824 100644 --- a/component/profile/cachefile/cache.go +++ b/component/profile/cachefile/cache.go @@ -5,9 +5,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/profile" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/profile" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "go.etcd.io/bbolt" ) diff --git a/component/profile/profile.go b/component/profile/profile.go index aa6df2f7..36db8cc3 100644 --- a/component/profile/profile.go +++ b/component/profile/profile.go @@ -1,7 +1,7 @@ package profile import ( - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" ) // StoreSelected is a global switch for storing selected proxy to cache diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 2d14abae..71a658b8 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -8,12 +8,12 @@ import ( "net/netip" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/tunnel" - "github.com/Dreamacro/clash/tunnel/statistic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel" + "github.com/metacubex/mihomo/tunnel/statistic" ) type proxyDialer struct { diff --git a/component/proxydialer/sing.go b/component/proxydialer/sing.go index 9b116527..71180c01 100644 --- a/component/proxydialer/sing.go +++ b/component/proxydialer/sing.go @@ -4,7 +4,7 @@ import ( "context" "net" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" diff --git a/component/resolver/host.go b/component/resolver/host.go index d6eb5873..69c29a3c 100644 --- a/component/resolver/host.go +++ b/component/resolver/host.go @@ -6,8 +6,8 @@ import ( "strings" _ "unsafe" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/trie" "github.com/zhangyunhao116/fastrand" ) diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 6be6a95f..8cbc62fa 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -9,8 +9,8 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/trie" "github.com/miekg/dns" "github.com/zhangyunhao116/fastrand" diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index c92687b1..31dc5c08 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -7,8 +7,8 @@ import ( "path/filepath" "time" - types "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/log" + types "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" "github.com/samber/lo" ) diff --git a/component/resource/vehicle.go b/component/resource/vehicle.go index 2f4bfbc8..b2e29418 100644 --- a/component/resource/vehicle.go +++ b/component/resource/vehicle.go @@ -8,8 +8,8 @@ import ( "os" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - types "github.com/Dreamacro/clash/constant/provider" + mihomoHttp "github.com/metacubex/mihomo/component/http" + types "github.com/metacubex/mihomo/constant/provider" ) type FileVehicle struct { @@ -52,7 +52,7 @@ func (h *HTTPVehicle) Path() string { func (h *HTTPVehicle) Read() ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil) + resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil) if err != nil { return nil, err } diff --git a/component/sniffer/base_sniffer.go b/component/sniffer/base_sniffer.go index 6d869aa0..55f51c50 100644 --- a/component/sniffer/base_sniffer.go +++ b/component/sniffer/base_sniffer.go @@ -3,9 +3,9 @@ package sniffer import ( "errors" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" ) type SnifferConfig struct { diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 11deb1ed..29bea088 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -8,12 +8,12 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" + "github.com/metacubex/mihomo/log" ) var ( diff --git a/component/sniffer/http_sniffer.go b/component/sniffer/http_sniffer.go index ee958a1c..76bf1559 100644 --- a/component/sniffer/http_sniffer.go +++ b/component/sniffer/http_sniffer.go @@ -7,9 +7,9 @@ import ( "net" "strings" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" ) var ( diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index ef49e5ad..0e3994f0 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -8,9 +8,9 @@ import ( "errors" "io" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/quic-go/quicvarint" "golang.org/x/crypto/hkdf" diff --git a/component/sniffer/tls_sniffer.go b/component/sniffer/tls_sniffer.go index b695c76f..974df79a 100644 --- a/component/sniffer/tls_sniffer.go +++ b/component/sniffer/tls_sniffer.go @@ -5,9 +5,9 @@ import ( "errors" "strings" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" ) var ( diff --git a/component/tls/reality.go b/component/tls/reality.go index 2902aa4b..250dc4d0 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -20,9 +20,9 @@ import ( "time" "unsafe" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/ntp" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/ntp" utls "github.com/sagernet/utls" "github.com/zhangyunhao116/fastrand" diff --git a/component/tls/utls.go b/component/tls/utls.go index 3aa030d3..787f6fad 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -4,7 +4,7 @@ import ( "crypto/tls" "net" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" "github.com/mroth/weightedrand/v2" utls "github.com/sagernet/utls" diff --git a/component/trie/domain_set.go b/component/trie/domain_set.go index e1ad6559..860d1235 100644 --- a/component/trie/domain_set.go +++ b/component/trie/domain_set.go @@ -7,7 +7,7 @@ import ( "sort" "strings" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/openacid/low/bitmap" ) diff --git a/component/trie/domain_set_test.go b/component/trie/domain_set_test.go index 9e0e0b70..77106d5f 100644 --- a/component/trie/domain_set_test.go +++ b/component/trie/domain_set_test.go @@ -3,7 +3,7 @@ package trie_test import ( "testing" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/component/trie" "github.com/stretchr/testify/assert" ) diff --git a/component/trie/domain_test.go b/component/trie/domain_test.go index 976055a9..4c5d8002 100644 --- a/component/trie/domain_test.go +++ b/component/trie/domain_test.go @@ -4,7 +4,7 @@ import ( "net/netip" "testing" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/component/trie" "github.com/stretchr/testify/assert" ) diff --git a/component/trie/ipcidr_trie.go b/component/trie/ipcidr_trie.go index 08edbbeb..a2ccfa16 100644 --- a/component/trie/ipcidr_trie.go +++ b/component/trie/ipcidr_trie.go @@ -3,7 +3,7 @@ package trie import ( "net" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) type IPV6 bool diff --git a/config/config.go b/config/config.go index 11951aa1..76ff9d68 100644 --- a/config/config.go +++ b/config/config.go @@ -13,31 +13,31 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/adapter/provider" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/auth" - "github.com/Dreamacro/clash/component/fakeip" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - P "github.com/Dreamacro/clash/component/process" - "github.com/Dreamacro/clash/component/resolver" - SNIFF "github.com/Dreamacro/clash/component/sniffer" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - providerTypes "github.com/Dreamacro/clash/constant/provider" - snifferTypes "github.com/Dreamacro/clash/constant/sniffer" - "github.com/Dreamacro/clash/dns" - L "github.com/Dreamacro/clash/listener" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/log" - R "github.com/Dreamacro/clash/rules" - RP "github.com/Dreamacro/clash/rules/provider" - T "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/adapter/provider" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/auth" + "github.com/metacubex/mihomo/component/fakeip" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + P "github.com/metacubex/mihomo/component/process" + "github.com/metacubex/mihomo/component/resolver" + SNIFF "github.com/metacubex/mihomo/component/sniffer" + tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + providerTypes "github.com/metacubex/mihomo/constant/provider" + snifferTypes "github.com/metacubex/mihomo/constant/sniffer" + "github.com/metacubex/mihomo/dns" + L "github.com/metacubex/mihomo/listener" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/log" + R "github.com/metacubex/mihomo/rules" + RP "github.com/metacubex/mihomo/rules/provider" + T "github.com/metacubex/mihomo/tunnel" "gopkg.in/yaml.v3" ) @@ -162,7 +162,7 @@ type Experimental struct { QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` } -// Config is clash config manager +// Config is mihomo config manager type Config struct { General *General IPTables *IPTables @@ -381,7 +381,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ProxyGroup: []map[string]any{}, TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, - GlobalUA: "clash.meta", + GlobalUA: "mihomo", Tun: RawTun{ Enable: false, Device: "", @@ -917,9 +917,9 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { if len(cfg.Hosts) != 0 { for domain, anyValue := range cfg.Hosts { - if str, ok := anyValue.(string); ok && str == "clash" { + if str, ok := anyValue.(string); ok && str == "mihomo" { if addrs, err := net.InterfaceAddrs(); err != nil { - log.Errorln("insert clash to host error: %s", err) + log.Errorln("insert mihomo to host error: %s", err) } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { diff --git a/config/initial.go b/config/initial.go index 6d6429ab..61d12895 100644 --- a/config/initial.go +++ b/config/initial.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) // Init prepare necessary files diff --git a/config/update_geo.go b/config/update_geo.go index 07f211e4..718c2d07 100644 --- a/config/update_geo.go +++ b/config/update_geo.go @@ -4,9 +4,9 @@ import ( "fmt" "runtime" - "github.com/Dreamacro/clash/component/geodata" - _ "github.com/Dreamacro/clash/component/geodata/standard" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/geodata" + _ "github.com/metacubex/mihomo/component/geodata/standard" + C "github.com/metacubex/mihomo/constant" "github.com/oschwald/maxminddb-golang" ) diff --git a/config/update_ui.go b/config/update_ui.go index 27e0f382..e5596597 100644 --- a/config/update_ui.go +++ b/config/update_ui.go @@ -11,7 +11,7 @@ import ( "strings" "sync" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) var ( diff --git a/config/utils.go b/config/utils.go index 1fa54634..5a4fecbf 100644 --- a/config/utils.go +++ b/config/utils.go @@ -11,15 +11,15 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/common/structure" - clashHttp "github.com/Dreamacro/clash/component/http" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/common/structure" + mihomoHttp "github.com/metacubex/mihomo/component/http" ) func downloadForBytes(url string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return nil, err } diff --git a/constant/adapters.go b/constant/adapters.go index ad50a8ab..5cf6e07c 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -9,9 +9,9 @@ import ( "sync" "time" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/dialer" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" ) // Adapter Type diff --git a/constant/context.go b/constant/context.go index 1c70124b..11ad7011 100644 --- a/constant/context.go +++ b/constant/context.go @@ -3,7 +3,7 @@ package constant import ( "net" - N "github.com/Dreamacro/clash/common/net" + N "github.com/metacubex/mihomo/common/net" "github.com/gofrs/uuid/v5" ) diff --git a/constant/ebpf.go b/constant/ebpf.go index b722dce1..e3bb62fe 100644 --- a/constant/ebpf.go +++ b/constant/ebpf.go @@ -3,14 +3,14 @@ package constant import ( "net/netip" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) const ( - BpfFSPath = "/sys/fs/bpf/clash" + BpfFSPath = "/sys/fs/bpf/mihomo" - TcpAutoRedirPort = 't'<<8 | 'r'<<0 - ClashTrafficMark = 'c'<<24 | 'l'<<16 | 't'<<8 | 'm'<<0 + TcpAutoRedirPort = 't'<<8 | 'r'<<0 + MihomoTrafficMark = 'c'<<24 | 'l'<<16 | 't'<<8 | 'm'<<0 ) type EBpf interface { diff --git a/constant/metadata.go b/constant/metadata.go index 5f472205..4b547a81 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -7,7 +7,7 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) // Socks addr type @@ -161,7 +161,7 @@ func (m *Metadata) SourceAddress() string { func (m *Metadata) SourceDetail() string { if m.Type == INNER { - return fmt.Sprintf("%s", ClashName) + return fmt.Sprintf("%s", MihomoName) } switch { diff --git a/constant/path.go b/constant/path.go index 0d82f549..a920fbbc 100644 --- a/constant/path.go +++ b/constant/path.go @@ -10,7 +10,7 @@ import ( "strings" ) -const Name = "clash" +const Name = "mihomo" var ( GeositeName = "GeoSite.dat" @@ -19,8 +19,8 @@ var ( // Path is used to get the configuration path // -// on Unix systems, `$HOME/.config/clash`. -// on Windows, `%USERPROFILE%/.config/clash`. +// on Unix systems, `$HOME/.config/mihomo`. +// on Windows, `%USERPROFILE%/.config/mihomo`. var Path = func() *path { homeDir, err := os.UserHomeDir() if err != nil { @@ -165,7 +165,7 @@ func (p *path) GetAssetLocation(file string) string { func (p *path) GetExecutableFullPath() string { exePath, err := os.Executable() if err != nil { - return "clash" + return "mihomo" } res, _ := filepath.EvalSymlinks(exePath) return res diff --git a/constant/provider/interface.go b/constant/provider/interface.go index 34590a48..809db9c5 100644 --- a/constant/provider/interface.go +++ b/constant/provider/interface.go @@ -1,8 +1,8 @@ package provider import ( - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/constant" ) // Vehicle Type diff --git a/constant/rule_extra.go b/constant/rule_extra.go index 3c5de5d5..62dc1cc3 100644 --- a/constant/rule_extra.go +++ b/constant/rule_extra.go @@ -1,7 +1,7 @@ package constant import ( - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata/router" ) type RuleGeoSite interface { diff --git a/constant/sniffer/sniffer.go b/constant/sniffer/sniffer.go index 47dbd069..36da69a3 100644 --- a/constant/sniffer/sniffer.go +++ b/constant/sniffer/sniffer.go @@ -1,6 +1,6 @@ package sniffer -import "github.com/Dreamacro/clash/constant" +import "github.com/metacubex/mihomo/constant" type Sniffer interface { SupportNetwork() constant.NetWork diff --git a/constant/version.go b/constant/version.go index cbb7ab61..c71024c2 100644 --- a/constant/version.go +++ b/constant/version.go @@ -1,8 +1,8 @@ package constant var ( - Meta = true - Version = "1.10.0" - BuildTime = "unknown time" - ClashName = "clash.meta" + Meta = true + Version = "1.10.0" + BuildTime = "unknown time" + MihomoName = "mihomo" ) diff --git a/context/conn.go b/context/conn.go index afeed852..bae07c23 100644 --- a/context/conn.go +++ b/context/conn.go @@ -1,11 +1,11 @@ package context import ( - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "net" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" "github.com/gofrs/uuid/v5" ) diff --git a/context/dns.go b/context/dns.go index ae29154f..1cc2067d 100644 --- a/context/dns.go +++ b/context/dns.go @@ -2,7 +2,7 @@ package context import ( "context" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/gofrs/uuid/v5" "github.com/miekg/dns" diff --git a/context/packetconn.go b/context/packetconn.go index d695bae5..feab7666 100644 --- a/context/packetconn.go +++ b/context/packetconn.go @@ -3,8 +3,8 @@ package context import ( "net" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" "github.com/gofrs/uuid/v5" ) diff --git a/dns/client.go b/dns/client.go index 5cdd1ec0..95f0f29b 100644 --- a/dns/client.go +++ b/dns/client.go @@ -8,10 +8,10 @@ import ( "net/netip" "strings" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" D "github.com/miekg/dns" "github.com/zhangyunhao116/fastrand" diff --git a/dns/dhcp.go b/dns/dhcp.go index 70f9aeeb..dc1344f5 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -8,8 +8,8 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/dhcp" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/dhcp" + "github.com/metacubex/mihomo/component/iface" D "github.com/miekg/dns" ) diff --git a/dns/doh.go b/dns/doh.go index 488e9025..9e173c84 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -15,9 +15,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/ca" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ca" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/http3" D "github.com/miekg/dns" diff --git a/dns/doq.go b/dns/doq.go index 76da913f..70b67c2a 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -12,9 +12,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/ca" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ca" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" D "github.com/miekg/dns" diff --git a/dns/enhancer.go b/dns/enhancer.go index ab144fd3..82fdd35a 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -3,9 +3,9 @@ package dns import ( "net/netip" - "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/component/fakeip" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/component/fakeip" + C "github.com/metacubex/mihomo/constant" ) type ResolverEnhancer struct { diff --git a/dns/filters.go b/dns/filters.go index f7e953e8..8eb1e48e 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -4,12 +4,12 @@ import ( "net/netip" "strings" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/component/mmdb" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + "github.com/metacubex/mihomo/component/mmdb" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type fallbackIPFilter interface { diff --git a/dns/middleware.go b/dns/middleware.go index 695432da..f8e051a0 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -5,13 +5,13 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/component/fakeip" - R "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/component/fakeip" + R "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/context" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" ) diff --git a/dns/resolver.go b/dns/resolver.go index d27f7bcc..610a06f0 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -7,14 +7,14 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/component/fakeip" - "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/component/fakeip" + "github.com/metacubex/mihomo/component/geodata/router" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" "github.com/samber/lo" diff --git a/dns/server.go b/dns/server.go index 5c5970db..1cf58d4d 100644 --- a/dns/server.go +++ b/dns/server.go @@ -5,9 +5,9 @@ import ( "errors" "net" - "github.com/Dreamacro/clash/common/sockopt" - "github.com/Dreamacro/clash/context" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/sockopt" + "github.com/metacubex/mihomo/context" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" ) diff --git a/dns/system.go b/dns/system.go index 20282929..37607a60 100644 --- a/dns/system.go +++ b/dns/system.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" "golang.org/x/exp/slices" diff --git a/dns/util.go b/dns/util.go index 34f7aa94..c354a73d 100644 --- a/dns/util.go +++ b/dns/util.go @@ -11,15 +11,15 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/common/picker" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/common/picker" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" D "github.com/miekg/dns" "github.com/samber/lo" diff --git a/docker/file-name.sh b/docker/file-name.sh index 1ac2cee0..3b2d61f9 100644 --- a/docker/file-name.sh +++ b/docker/file-name.sh @@ -1,5 +1,5 @@ #!/bin/sh -os="clash.meta-linux-" +os="mihomo-linux-" case $TARGETPLATFORM in "linux/amd64") arch="amd64-compatible" diff --git a/docs/config.yaml b/docs/config.yaml index 61a2dee9..d5e1174a 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -16,7 +16,7 @@ skip-auth-prefixes: # 设置跳过验证的IP段 # find-process-mode has 3 values:always, strict, off # - always, 开启,强制匹配所有进程 -# - strict, 默认,由 clash 判断是否开启 +# - strict, 默认,由 mihomo 判断是否开启 # - off, 不匹配进程,推荐在路由器上使用此模式 find-process-mode: strict @@ -74,11 +74,11 @@ experimental: # 类似于 /etc/hosts, 仅支持配置单个 IP hosts: -# '*.clash.dev': 127.0.0.1 +# '*.mihomo.dev': 127.0.0.1 # '.dev': 127.0.0.1 -# 'alpha.clash.dev': '::1' +# 'alpha.mihomo.dev': '::1' # test.com: [1.1.1.1, 2.2.2.2] -# clash.lan: clash # clash 为特别字段,将加入本地所有网卡的地址 +# mihomo.lan: mihomo # mihomo 为特别字段,将加入本地所有网卡的地址 # baidu.com: google.com # 只允许配置一个别名 profile: # 存储 select 选择记录 @@ -754,7 +754,7 @@ proxies: # socks5 proxy-groups: # 代理链,目前relay可以支持udp的只有vmess/vless/trojan/ss/ssr/tuic # wireguard目前不支持在relay中使用,请使用proxy中的dialer-proxy配置项 - # Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet + # Traffic: mihomo <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet - name: "relay" type: relay proxies: @@ -823,13 +823,13 @@ proxy-groups: - Proxy - DIRECT -# Clash 格式的节点或支持 *ray 的分享格式 +# Mihomo 格式的节点或支持 *ray 的分享格式 proxy-providers: provider1: type: http # http 的 path 可空置,默认储存路径为 homedir的proxies文件夹,文件名为url的md5 url: "url" interval: 3600 - path: ./provider1.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 + path: ./provider1.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 health-check: enable: true interval: 600 @@ -846,7 +846,7 @@ rule-providers: rule1: behavior: classical # domain ipcidr interval: 259200 - path: /path/to/save/file.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 + path: /path/to/save/file.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 type: http # http 的 path 可空置,默认储存路径为 homedir的rules文件夹,文件名为url的md5 url: "url" rule2: diff --git a/flake.nix b/flake.nix index ffd18629..afe6e1c1 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "Another Clash Kernel"; + description = "Another Mihomo Kernel"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/master"; @@ -15,7 +15,7 @@ }; in rec { - packages.default = pkgs.clash-meta; + packages.default = pkgs.mihomo-meta; } ) // ( @@ -23,8 +23,8 @@ { overlay = final: prev: { - clash-meta = final.buildGo119Module { - pname = "clash-meta"; + mihomo-meta = final.buildGo119Module { + pname = "mihomo-meta"; inherit version; src = ./.; @@ -38,8 +38,8 @@ ldflags = [ "-s" "-w" - "-X github.com/Dreamacro/clash/constant.Version=dev-${version}" - "-X github.com/Dreamacro/clash/constant.BuildTime=${version}" + "-X github.com/metacubex/mihomo/constant.Version=dev-${version}" + "-X github.com/metacubex/mihomo/constant.BuildTime=${version}" ]; tags = [ @@ -50,7 +50,7 @@ doCheck = false; postInstall = '' - mv $out/bin/clash $out/bin/clash-meta + mv $out/bin/mihomo $out/bin/mihomo-meta ''; }; diff --git a/go.mod b/go.mod index 80ab477c..da45cd28 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/Dreamacro/clash +module github.com/metacubex/mihomo go 1.20 diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 87e0e0b1..6ea02989 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -11,32 +11,32 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/ntp" + "github.com/metacubex/mihomo/ntp" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/component/auth" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - G "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/iface" - "github.com/Dreamacro/clash/component/profile" - "github.com/Dreamacro/clash/component/profile/cachefile" - "github.com/Dreamacro/clash/component/resolver" - SNI "github.com/Dreamacro/clash/component/sniffer" - "github.com/Dreamacro/clash/component/trie" - "github.com/Dreamacro/clash/config" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/dns" - "github.com/Dreamacro/clash/listener" - authStore "github.com/Dreamacro/clash/listener/auth" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/inner" - "github.com/Dreamacro/clash/listener/tproxy" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/component/auth" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + G "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/iface" + "github.com/metacubex/mihomo/component/profile" + "github.com/metacubex/mihomo/component/profile/cachefile" + "github.com/metacubex/mihomo/component/resolver" + SNI "github.com/metacubex/mihomo/component/sniffer" + "github.com/metacubex/mihomo/component/trie" + "github.com/metacubex/mihomo/config" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/dns" + "github.com/metacubex/mihomo/listener" + authStore "github.com/metacubex/mihomo/listener/auth" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/inner" + "github.com/metacubex/mihomo/listener/tproxy" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" ) var mux sync.Mutex @@ -505,5 +505,5 @@ func Shutdown() { tproxy.CleanupTProxyIPTables() resolver.StoreFakePoolState() - log.Warnln("Clash shutting down") + log.Warnln("Mihomo shutting down") } diff --git a/hub/hub.go b/hub/hub.go index bd228fad..323f8749 100644 --- a/hub/hub.go +++ b/hub/hub.go @@ -1,10 +1,10 @@ package hub import ( - "github.com/Dreamacro/clash/config" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/hub/route" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/config" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/hub/route" + "github.com/metacubex/mihomo/log" ) type Option func(*config.Config) @@ -27,7 +27,7 @@ func WithSecret(secret string) Option { } } -// Parse call at the beginning of clash +// Parse call at the beginning of mihomo func Parse(options ...Option) error { cfg, err := executor.Parse() if err != nil { diff --git a/hub/route/cache.go b/hub/route/cache.go index bdfd2e35..f07eb33a 100644 --- a/hub/route/cache.go +++ b/hub/route/cache.go @@ -3,7 +3,7 @@ package route import ( "net/http" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/component/resolver" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/configs.go b/hub/route/configs.go index e86bb2a8..3b5f62b3 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -6,17 +6,17 @@ import ( "path/filepath" "sync" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/config" - "github.com/Dreamacro/clash/constant" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/hub/executor" - P "github.com/Dreamacro/clash/listener" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/config" + "github.com/metacubex/mihomo/constant" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/hub/executor" + P "github.com/metacubex/mihomo/listener" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/connections.go b/hub/route/connections.go index 67d5afa3..e0ff2426 100644 --- a/hub/route/connections.go +++ b/hub/route/connections.go @@ -7,7 +7,7 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/tunnel/statistic" + "github.com/metacubex/mihomo/tunnel/statistic" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/ctxkeys.go b/hub/route/ctxkeys.go index 56370192..6883b208 100644 --- a/hub/route/ctxkeys.go +++ b/hub/route/ctxkeys.go @@ -10,5 +10,5 @@ var ( type contextKey string func (c contextKey) String() string { - return "clash context key " + string(c) + return "mihomo context key " + string(c) } diff --git a/hub/route/dns.go b/hub/route/dns.go index 2918b059..1762c947 100644 --- a/hub/route/dns.go +++ b/hub/route/dns.go @@ -5,7 +5,7 @@ import ( "math" "net/http" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/component/resolver" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/groups.go b/hub/route/groups.go index c82207f0..e36b8ab0 100644 --- a/hub/route/groups.go +++ b/hub/route/groups.go @@ -8,11 +8,11 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel" ) func GroupRouter() http.Handler { diff --git a/hub/route/provider.go b/hub/route/provider.go index c050a9f1..a8611a79 100644 --- a/hub/route/provider.go +++ b/hub/route/provider.go @@ -4,9 +4,9 @@ import ( "context" "net/http" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/tunnel" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/proxies.go b/hub/route/proxies.go index c1e30b21..759e64d2 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -7,12 +7,12 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/profile/cachefile" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/profile/cachefile" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/restart.go b/hub/route/restart.go index a907021f..49d7e517 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -8,8 +8,8 @@ import ( "runtime" "syscall" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/log" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/rules.go b/hub/route/rules.go index 51f8f01c..43d33299 100644 --- a/hub/route/rules.go +++ b/hub/route/rules.go @@ -1,10 +1,10 @@ package route import ( - "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/constant" "net/http" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/server.go b/hub/route/server.go index 93afd989..d510e986 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -11,12 +11,12 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/inbound" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel/statistic" + "github.com/metacubex/mihomo/adapter/inbound" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel/statistic" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -189,7 +189,7 @@ func authentication(next http.Handler) http.Handler { } func hello(w http.ResponseWriter, r *http.Request) { - render.JSON(w, r, render.M{"hello": "clash.meta"}) + render.JSON(w, r, render.M{"hello": "mihomo"}) } func traffic(w http.ResponseWriter, r *http.Request) { diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 7b486ee3..ea371798 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -6,9 +6,9 @@ import ( "net/http" "os" - "github.com/Dreamacro/clash/config" - "github.com/Dreamacro/clash/hub/updater" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/config" + "github.com/metacubex/mihomo/hub/updater" + "github.com/metacubex/mihomo/log" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 1a930c03..a3bc9a42 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -15,15 +15,15 @@ import ( "sync" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + mihomoHttp "github.com/metacubex/mihomo/component/http" + "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/klauspost/cpuid/v2" ) // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/updater/updater.go -// Updater is the Clash.Meta updater. +// Updater is the mihomo updater. var ( goarm string gomips string @@ -41,8 +41,8 @@ var ( backupExeName string // 备份文件名 updateExeName string // 更新后的可执行文件 - baseURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/clash.meta" - versionURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/version.txt" + baseURL string = "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/mihomo" + versionURL string = "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt" packageURL string latestVersion string ) @@ -135,9 +135,9 @@ func prepare(exePath string) (err error) { backupDir = filepath.Join(workDir, "meta-backup") if runtime.GOOS == "windows" { - updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + ".exe" + updateExeName = "mihomo" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + ".exe" } else { - updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + updateExeName = "mihomo" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible } log.Infoln("updateExeName: %s ", updateExeName) @@ -231,7 +231,7 @@ const MaxPackageFileSize = 32 * 1024 * 1024 func downloadPackageFile() (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return fmt.Errorf("http request failed: %w", err) } @@ -412,7 +412,7 @@ func copyFile(src, dst string) error { func getLatestVersion() (version string, err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return "", fmt.Errorf("get Latest Version fail: %w", err) } diff --git a/listener/auth/auth.go b/listener/auth/auth.go index 70473114..46f552b8 100644 --- a/listener/auth/auth.go +++ b/listener/auth/auth.go @@ -1,7 +1,7 @@ package auth import ( - "github.com/Dreamacro/clash/component/auth" + "github.com/metacubex/mihomo/component/auth" ) var authenticator auth.Authenticator diff --git a/listener/autoredir/tcp.go b/listener/autoredir/tcp.go index 57df45f3..2b21b087 100644 --- a/listener/autoredir/tcp.go +++ b/listener/autoredir/tcp.go @@ -4,11 +4,11 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/config/tun.go b/listener/config/tun.go index 3f151d1e..6db1fd66 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -3,7 +3,7 @@ package config import ( "net/netip" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) func StringSliceToNetipPrefixSlice(ss []string) ([]netip.Prefix, error) { diff --git a/listener/http/client.go b/listener/http/client.go index 84c284ff..c35cadad 100644 --- a/listener/http/client.go +++ b/listener/http/client.go @@ -7,9 +7,9 @@ import ( "net/http" "time" - "github.com/Dreamacro/clash/adapter/inbound" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { diff --git a/listener/http/proxy.go b/listener/http/proxy.go index fa1d8f88..76da4d95 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -6,12 +6,12 @@ import ( "net/http" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - authStore "github.com/Dreamacro/clash/listener/auth" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + authStore "github.com/metacubex/mihomo/listener/auth" + "github.com/metacubex/mihomo/log" ) func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { diff --git a/listener/http/server.go b/listener/http/server.go index 0377d3b6..a75e2092 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -3,9 +3,9 @@ package http import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/cache" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/cache" + C "github.com/metacubex/mihomo/constant" ) type Listener struct { diff --git a/listener/http/upgrade.go b/listener/http/upgrade.go index 6e4f063d..8a6291d1 100644 --- a/listener/http/upgrade.go +++ b/listener/http/upgrade.go @@ -7,10 +7,10 @@ import ( "net/http" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) func isUpgradeRequest(req *http.Request) bool { diff --git a/listener/inbound/base.go b/listener/inbound/base.go index 83695bb1..e8f860a0 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -6,8 +6,8 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/adapter/inbound" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/inbound" + C "github.com/metacubex/mihomo/constant" ) type Base struct { diff --git a/listener/inbound/http.go b/listener/inbound/http.go index 99577177..f5301f46 100644 --- a/listener/inbound/http.go +++ b/listener/inbound/http.go @@ -1,9 +1,9 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/http" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/http" + "github.com/metacubex/mihomo/log" ) type HTTPOption struct { diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index df537a41..112d03f8 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_hysteria2" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_hysteria2" + "github.com/metacubex/mihomo/log" ) type Hysteria2Option struct { diff --git a/listener/inbound/mixed.go b/listener/inbound/mixed.go index ce445bda..fc643821 100644 --- a/listener/inbound/mixed.go +++ b/listener/inbound/mixed.go @@ -3,11 +3,11 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" - "github.com/Dreamacro/clash/listener/mixed" - "github.com/Dreamacro/clash/listener/socks" + "github.com/metacubex/mihomo/listener/mixed" + "github.com/metacubex/mihomo/listener/socks" ) type MixedOption struct { diff --git a/listener/inbound/redir.go b/listener/inbound/redir.go index 085bf3a8..ee090ade 100644 --- a/listener/inbound/redir.go +++ b/listener/inbound/redir.go @@ -1,9 +1,9 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/redir" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/redir" + "github.com/metacubex/mihomo/log" ) type RedirOption struct { diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index fa5b3082..cb32dcfb 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_shadowsocks" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_shadowsocks" + "github.com/metacubex/mihomo/log" ) type ShadowSocksOption struct { diff --git a/listener/inbound/socks.go b/listener/inbound/socks.go index 09580a57..7e10d93a 100644 --- a/listener/inbound/socks.go +++ b/listener/inbound/socks.go @@ -2,9 +2,9 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/socks" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/socks" + "github.com/metacubex/mihomo/log" ) type SocksOption struct { diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index 682188f5..acc8cb5e 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -3,9 +3,9 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/tproxy" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/tproxy" + "github.com/metacubex/mihomo/log" ) type TProxyOption struct { diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index e7b51392..c2a73b84 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/tuic" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/tuic" + "github.com/metacubex/mihomo/log" ) type TuicOption struct { diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index 472269d6..d1044b8e 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -4,10 +4,10 @@ import ( "errors" "strings" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_tun" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_tun" + "github.com/metacubex/mihomo/log" ) type TunOption struct { diff --git a/listener/inbound/tunnel.go b/listener/inbound/tunnel.go index 2af663a5..2dfaac74 100644 --- a/listener/inbound/tunnel.go +++ b/listener/inbound/tunnel.go @@ -3,9 +3,9 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - LT "github.com/Dreamacro/clash/listener/tunnel" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LT "github.com/metacubex/mihomo/listener/tunnel" + "github.com/metacubex/mihomo/log" ) type TunnelOption struct { diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 3f516198..3508aa3c 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_vmess" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_vmess" + "github.com/metacubex/mihomo/log" ) type VmessOption struct { diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index 8973c431..373fd2b4 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -6,7 +6,7 @@ import ( "net/netip" "strconv" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) var tunnel C.Tunnel @@ -26,7 +26,7 @@ func HandleTcp(address string) (conn net.Conn, err error) { metadata.NetWork = C.TCP metadata.Type = C.INNER metadata.DNSMode = C.DNSNormal - metadata.Process = C.ClashName + metadata.Process = C.MihomoName if h, port, err := net.SplitHostPort(address); err == nil { if port, err := strconv.ParseUint(port, 10, 16); err == nil { metadata.DstPort = uint16(port) diff --git a/listener/listener.go b/listener/listener.go index a6bbdbf5..903cb64b 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -9,22 +9,22 @@ import ( "strings" "sync" - "github.com/Dreamacro/clash/component/ebpf" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/autoredir" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/http" - "github.com/Dreamacro/clash/listener/mixed" - "github.com/Dreamacro/clash/listener/redir" - embedSS "github.com/Dreamacro/clash/listener/shadowsocks" - "github.com/Dreamacro/clash/listener/sing_shadowsocks" - "github.com/Dreamacro/clash/listener/sing_tun" - "github.com/Dreamacro/clash/listener/sing_vmess" - "github.com/Dreamacro/clash/listener/socks" - "github.com/Dreamacro/clash/listener/tproxy" - "github.com/Dreamacro/clash/listener/tuic" - LT "github.com/Dreamacro/clash/listener/tunnel" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ebpf" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/autoredir" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/http" + "github.com/metacubex/mihomo/listener/mixed" + "github.com/metacubex/mihomo/listener/redir" + embedSS "github.com/metacubex/mihomo/listener/shadowsocks" + "github.com/metacubex/mihomo/listener/sing_shadowsocks" + "github.com/metacubex/mihomo/listener/sing_tun" + "github.com/metacubex/mihomo/listener/sing_vmess" + "github.com/metacubex/mihomo/listener/socks" + "github.com/metacubex/mihomo/listener/tproxy" + "github.com/metacubex/mihomo/listener/tuic" + LT "github.com/metacubex/mihomo/listener/tunnel" + "github.com/metacubex/mihomo/log" "github.com/samber/lo" ) diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index d2ede096..97d1407c 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -3,14 +3,14 @@ package mixed import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/http" - "github.com/Dreamacro/clash/listener/socks" - "github.com/Dreamacro/clash/transport/socks4" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/http" + "github.com/metacubex/mihomo/listener/socks" + "github.com/metacubex/mihomo/transport/socks4" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/parse.go b/listener/parse.go index b0fac86a..1c8b6463 100644 --- a/listener/parse.go +++ b/listener/parse.go @@ -3,9 +3,9 @@ package listener import ( "fmt" - "github.com/Dreamacro/clash/common/structure" - C "github.com/Dreamacro/clash/constant" - IN "github.com/Dreamacro/clash/listener/inbound" + "github.com/metacubex/mihomo/common/structure" + C "github.com/metacubex/mihomo/constant" + IN "github.com/metacubex/mihomo/listener/inbound" ) func ParseListener(mapping map[string]any) (C.InboundListener, error) { diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go index 6419760f..8474a8e2 100644 --- a/listener/redir/tcp.go +++ b/listener/redir/tcp.go @@ -3,9 +3,9 @@ package redir import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" ) type Listener struct { diff --git a/listener/redir/tcp_darwin.go b/listener/redir/tcp_darwin.go index 5a2f331c..6e1821bb 100644 --- a/listener/redir/tcp_darwin.go +++ b/listener/redir/tcp_darwin.go @@ -5,7 +5,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) func parserPacket(c net.Conn) (socks5.Addr, error) { diff --git a/listener/redir/tcp_freebsd.go b/listener/redir/tcp_freebsd.go index 6ecb2496..9eb199f0 100644 --- a/listener/redir/tcp_freebsd.go +++ b/listener/redir/tcp_freebsd.go @@ -8,7 +8,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" "golang.org/x/sys/unix" ) diff --git a/listener/redir/tcp_linux.go b/listener/redir/tcp_linux.go index b65c34ee..fce74678 100644 --- a/listener/redir/tcp_linux.go +++ b/listener/redir/tcp_linux.go @@ -8,7 +8,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" "golang.org/x/sys/unix" ) diff --git a/listener/redir/tcp_other.go b/listener/redir/tcp_other.go index a01550c7..ae3bebfd 100644 --- a/listener/redir/tcp_other.go +++ b/listener/redir/tcp_other.go @@ -6,7 +6,7 @@ import ( "errors" "net" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) func parserPacket(conn net.Conn) (socks5.Addr, error) { diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 8959e6ba..c08667de 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -4,12 +4,12 @@ import ( "net" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index 53f5549a..4336db22 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -3,13 +3,13 @@ package shadowsocks import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/socks5" ) type UDPListener struct { diff --git a/listener/shadowsocks/utils.go b/listener/shadowsocks/utils.go index a732cbbe..5d6a2977 100644 --- a/listener/shadowsocks/utils.go +++ b/listener/shadowsocks/utils.go @@ -6,7 +6,7 @@ import ( "net" "net/url" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) type packet struct { diff --git a/listener/sing/context.go b/listener/sing/context.go index 4204757a..e1e8b452 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -4,7 +4,7 @@ import ( "context" "golang.org/x/exp/slices" - "github.com/Dreamacro/clash/adapter/inbound" + "github.com/metacubex/mihomo/adapter/inbound" "github.com/sagernet/sing/common/auth" ) diff --git a/listener/sing/sing.go b/listener/sing/sing.go index ff72f67d..306bd705 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" vmess "github.com/metacubex/sing-vmess" mux "github.com/sagernet/sing-mux" diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index bc25ec2a..96553995 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -11,14 +11,14 @@ import ( "net/url" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/adapter/outbound" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/adapter/outbound" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" "github.com/metacubex/sing-quic/hysteria2" diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 51baeaa1..5a4896af 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -6,15 +6,15 @@ import ( "net" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - embedSS "github.com/Dreamacro/clash/listener/shadowsocks" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/ntp" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + embedSS "github.com/metacubex/mihomo/listener/shadowsocks" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/ntp" shadowsocks "github.com/metacubex/sing-shadowsocks" "github.com/metacubex/sing-shadowsocks/shadowaead" diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 88e3f6d6..62a15c6c 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -9,10 +9,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 0548ac41..212c3d90 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -10,13 +10,13 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/iface" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/iface" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" "github.com/sagernet/sing/common" diff --git a/listener/sing_tun/server_android.go b/listener/sing_tun/server_android.go index 4f85c418..ac41282d 100644 --- a/listener/sing_tun/server_android.go +++ b/listener/sing_tun/server_android.go @@ -1,7 +1,7 @@ package sing_tun import ( - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" "github.com/sagernet/netlink" "golang.org/x/sys/unix" diff --git a/listener/sing_tun/server_windows.go b/listener/sing_tun/server_windows.go index 9584f32f..8da21287 100644 --- a/listener/sing_tun/server_windows.go +++ b/listener/sing_tun/server_windows.go @@ -3,7 +3,7 @@ package sing_tun import ( "time" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" ) diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 014e86f9..e790e3bc 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -8,13 +8,13 @@ import ( "net/url" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/ntp" - clashVMess "github.com/Dreamacro/clash/transport/vmess" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/ntp" + mihomoVMess "github.com/metacubex/mihomo/transport/vmess" vmess "github.com/metacubex/sing-vmess" "github.com/sagernet/sing/common" @@ -81,7 +81,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) if config.WsPath != "" { httpMux = http.NewServeMux() httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { - conn, err := clashVMess.StreamUpgradedWebsocketConn(w, r) + conn, err := mihomoVMess.StreamUpgradedWebsocketConn(w, r) if err != nil { http.Error(w, err.Error(), 500) return diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index 9448f269..c8c33e7b 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -4,12 +4,12 @@ import ( "io" "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - authStore "github.com/Dreamacro/clash/listener/auth" - "github.com/Dreamacro/clash/transport/socks4" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + authStore "github.com/metacubex/mihomo/listener/auth" + "github.com/metacubex/mihomo/transport/socks4" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/socks/udp.go b/listener/socks/udp.go index 2f786e95..ef31b20e 100644 --- a/listener/socks/udp.go +++ b/listener/socks/udp.go @@ -3,12 +3,12 @@ package socks import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/socks5" ) type UDPListener struct { diff --git a/listener/socks/utils.go b/listener/socks/utils.go index 3456b595..d113d45c 100644 --- a/listener/socks/utils.go +++ b/listener/socks/utils.go @@ -3,7 +3,7 @@ package socks import ( "net" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) type packet struct { diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index 24fff09a..e4852665 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -6,10 +6,10 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type packet struct { diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go index 319d5c30..efb144a9 100644 --- a/listener/tproxy/tproxy.go +++ b/listener/tproxy/tproxy.go @@ -3,10 +3,10 @@ package tproxy import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/tproxy/tproxy_iptables.go b/listener/tproxy/tproxy_iptables.go index 31ac24e5..5ddd7b4c 100644 --- a/listener/tproxy/tproxy_iptables.go +++ b/listener/tproxy/tproxy_iptables.go @@ -6,9 +6,9 @@ import ( "net" "runtime" - "github.com/Dreamacro/clash/common/cmd" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cmd" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/log" ) var ( @@ -48,25 +48,25 @@ func SetTProxyIPTables(ifname string, bypass []string, tport uint16, dport uint1 execCmd(fmt.Sprintf("iptables -t filter -A FORWARD -i %s -o %s -j ACCEPT", interfaceName, interfaceName)) } - // set clash divert - execCmd("iptables -t mangle -N clash_divert") - execCmd("iptables -t mangle -F clash_divert") - execCmd(fmt.Sprintf("iptables -t mangle -A clash_divert -j MARK --set-mark %s", PROXY_FWMARK)) - execCmd("iptables -t mangle -A clash_divert -j ACCEPT") + // set mihomo divert + execCmd("iptables -t mangle -N mihomo_divert") + execCmd("iptables -t mangle -F mihomo_divert") + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_divert -j MARK --set-mark %s", PROXY_FWMARK)) + execCmd("iptables -t mangle -A mihomo_divert -j ACCEPT") // set pre routing - execCmd("iptables -t mangle -N clash_prerouting") - execCmd("iptables -t mangle -F clash_prerouting") - execCmd("iptables -t mangle -A clash_prerouting -s 172.17.0.0/16 -j RETURN") - execCmd("iptables -t mangle -A clash_prerouting -p udp --dport 53 -j ACCEPT") - execCmd("iptables -t mangle -A clash_prerouting -p tcp --dport 53 -j ACCEPT") - execCmd("iptables -t mangle -A clash_prerouting -m addrtype --dst-type LOCAL -j RETURN") - addLocalnetworkToChain("clash_prerouting", bypass) - execCmd("iptables -t mangle -A clash_prerouting -p tcp -m socket -j clash_divert") - execCmd("iptables -t mangle -A clash_prerouting -p udp -m socket -j clash_divert") - execCmd(fmt.Sprintf("iptables -t mangle -A clash_prerouting -p tcp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) - execCmd(fmt.Sprintf("iptables -t mangle -A clash_prerouting -p udp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) - execCmd("iptables -t mangle -A PREROUTING -j clash_prerouting") + execCmd("iptables -t mangle -N mihomo_prerouting") + execCmd("iptables -t mangle -F mihomo_prerouting") + execCmd("iptables -t mangle -A mihomo_prerouting -s 172.17.0.0/16 -j RETURN") + execCmd("iptables -t mangle -A mihomo_prerouting -p udp --dport 53 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_prerouting -p tcp --dport 53 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_prerouting -m addrtype --dst-type LOCAL -j RETURN") + addLocalnetworkToChain("mihomo_prerouting", bypass) + execCmd("iptables -t mangle -A mihomo_prerouting -p tcp -m socket -j mihomo_divert") + execCmd("iptables -t mangle -A mihomo_prerouting -p udp -m socket -j mihomo_divert") + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_prerouting -p tcp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_prerouting -p udp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) + execCmd("iptables -t mangle -A PREROUTING -j mihomo_prerouting") execCmd(fmt.Sprintf("iptables -t nat -I PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p tcp --dport 53 -j REDIRECT --to %d", dnsPort)) execCmd(fmt.Sprintf("iptables -t nat -I PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p udp --dport 53 -j REDIRECT --to %d", dnsPort)) @@ -77,27 +77,27 @@ func SetTProxyIPTables(ifname string, bypass []string, tport uint16, dport uint1 } // set output - execCmd("iptables -t mangle -N clash_output") - execCmd("iptables -t mangle -F clash_output") - execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) - execCmd("iptables -t mangle -A clash_output -p udp -m multiport --dports 53,123,137 -j ACCEPT") - execCmd("iptables -t mangle -A clash_output -p tcp --dport 53 -j ACCEPT") - execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type LOCAL -j RETURN") - execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type BROADCAST -j RETURN") - addLocalnetworkToChain("clash_output", bypass) - execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -p tcp -j MARK --set-mark %s", PROXY_FWMARK)) - execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -p udp -j MARK --set-mark %s", PROXY_FWMARK)) - execCmd(fmt.Sprintf("iptables -t mangle -I OUTPUT -o %s -j clash_output", interfaceName)) + execCmd("iptables -t mangle -N mihomo_output") + execCmd("iptables -t mangle -F mihomo_output") + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) + execCmd("iptables -t mangle -A mihomo_output -p udp -m multiport --dports 53,123,137 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_output -p tcp --dport 53 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_output -m addrtype --dst-type LOCAL -j RETURN") + execCmd("iptables -t mangle -A mihomo_output -m addrtype --dst-type BROADCAST -j RETURN") + addLocalnetworkToChain("mihomo_output", bypass) + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -p tcp -j MARK --set-mark %s", PROXY_FWMARK)) + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -p udp -j MARK --set-mark %s", PROXY_FWMARK)) + execCmd(fmt.Sprintf("iptables -t mangle -I OUTPUT -o %s -j mihomo_output", interfaceName)) // set dns output - execCmd("iptables -t nat -N clash_dns_output") - execCmd("iptables -t nat -F clash_dns_output") - execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) - execCmd("iptables -t nat -A clash_dns_output -s 172.17.0.0/16 -j RETURN") - execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p udp -j REDIRECT --to-ports %d", dnsPort)) - execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p tcp -j REDIRECT --to-ports %d", dnsPort)) - execCmd("iptables -t nat -I OUTPUT -p tcp --dport 53 -j clash_dns_output") - execCmd("iptables -t nat -I OUTPUT -p udp --dport 53 -j clash_dns_output") + execCmd("iptables -t nat -N mihomo_dns_output") + execCmd("iptables -t nat -F mihomo_dns_output") + execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) + execCmd("iptables -t nat -A mihomo_dns_output -s 172.17.0.0/16 -j RETURN") + execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -p udp -j REDIRECT --to-ports %d", dnsPort)) + execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -p tcp -j REDIRECT --to-ports %d", dnsPort)) + execCmd("iptables -t nat -I OUTPUT -p tcp --dport 53 -j mihomo_dns_output") + execCmd("iptables -t nat -I OUTPUT -p udp --dport 53 -j mihomo_dns_output") return nil } @@ -113,7 +113,7 @@ func CleanupTProxyIPTables() { dialer.DefaultRoutingMark.Store(0) } - if _, err := cmd.ExecCmd("iptables -t mangle -L clash_divert"); err != nil { + if _, err := cmd.ExecCmd("iptables -t mangle -L mihomo_divert"); err != nil { return } @@ -132,7 +132,7 @@ func CleanupTProxyIPTables() { // clean PREROUTING execCmd(fmt.Sprintf("iptables -t nat -D PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p tcp --dport 53 -j REDIRECT --to %d", dnsPort)) execCmd(fmt.Sprintf("iptables -t nat -D PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p udp --dport 53 -j REDIRECT --to %d", dnsPort)) - execCmd("iptables -t mangle -D PREROUTING -j clash_prerouting") + execCmd("iptables -t mangle -D PREROUTING -j mihomo_prerouting") // clean POSTROUTING if interfaceName != "lo" { @@ -140,19 +140,19 @@ func CleanupTProxyIPTables() { } // clean OUTPUT - execCmd(fmt.Sprintf("iptables -t mangle -D OUTPUT -o %s -j clash_output", interfaceName)) - execCmd("iptables -t nat -D OUTPUT -p tcp --dport 53 -j clash_dns_output") - execCmd("iptables -t nat -D OUTPUT -p udp --dport 53 -j clash_dns_output") + execCmd(fmt.Sprintf("iptables -t mangle -D OUTPUT -o %s -j mihomo_output", interfaceName)) + execCmd("iptables -t nat -D OUTPUT -p tcp --dport 53 -j mihomo_dns_output") + execCmd("iptables -t nat -D OUTPUT -p udp --dport 53 -j mihomo_dns_output") // clean chain - execCmd("iptables -t mangle -F clash_prerouting") - execCmd("iptables -t mangle -X clash_prerouting") - execCmd("iptables -t mangle -F clash_divert") - execCmd("iptables -t mangle -X clash_divert") - execCmd("iptables -t mangle -F clash_output") - execCmd("iptables -t mangle -X clash_output") - execCmd("iptables -t nat -F clash_dns_output") - execCmd("iptables -t nat -X clash_dns_output") + execCmd("iptables -t mangle -F mihomo_prerouting") + execCmd("iptables -t mangle -X mihomo_prerouting") + execCmd("iptables -t mangle -F mihomo_divert") + execCmd("iptables -t mangle -X mihomo_divert") + execCmd("iptables -t mangle -F mihomo_output") + execCmd("iptables -t mangle -X mihomo_output") + execCmd("iptables -t nat -F mihomo_dns_output") + execCmd("iptables -t nat -X mihomo_dns_output") interfaceName = "" tProxyPort = 0 diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go index c8460def..aa0fee19 100644 --- a/listener/tproxy/udp.go +++ b/listener/tproxy/udp.go @@ -4,10 +4,10 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type UDPListener struct { diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 544f1328..7fa7b18e 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -7,15 +7,15 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/inbound" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/tuic" + "github.com/metacubex/mihomo/adapter/inbound" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/listener/tunnel/packet.go b/listener/tunnel/packet.go index 35601e38..165004d6 100644 --- a/listener/tunnel/packet.go +++ b/listener/tunnel/packet.go @@ -3,7 +3,7 @@ package tunnel import ( "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type packet struct { diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index 9fca14dd..794dc8ac 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -4,10 +4,10 @@ import ( "fmt" "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index 00d61663..f7d980ab 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -4,10 +4,10 @@ import ( "fmt" "net" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type PacketConn struct { diff --git a/log/log.go b/log/log.go index acddeaff..d431dcb1 100644 --- a/log/log.go +++ b/log/log.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/Dreamacro/clash/common/observable" + "github.com/metacubex/mihomo/common/observable" log "github.com/sirupsen/logrus" ) diff --git a/main.go b/main.go index d41450b6..fd1e065c 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import ( "flag" "fmt" - "github.com/Dreamacro/clash/constant/features" + "github.com/metacubex/mihomo/constant/features" "os" "os/signal" "path/filepath" @@ -11,11 +11,11 @@ import ( "strings" "syscall" - "github.com/Dreamacro/clash/config" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/hub" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/config" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/hub" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/log" "go.uber.org/automaxprocs/maxprocs" ) @@ -38,7 +38,7 @@ func init() { flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), "override external controller address") flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API") flag.BoolVar(&geodataMode, "m", false, "set geodata mode") - flag.BoolVar(&version, "v", false, "show current version of clash") + flag.BoolVar(&version, "v", false, "show current version of mihomo") flag.BoolVar(&testConfig, "t", false, "test configuration and exit") flag.Parse() } @@ -46,7 +46,7 @@ func init() { func main() { _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {})) if version { - fmt.Printf("Clash Meta %s %s %s with %s %s\n", + fmt.Printf("Mihomo Meta %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) if len(features.TAGS) != 0 { fmt.Printf("Use tags: %s\n", strings.Join(features.TAGS, ", ")) diff --git a/ntp/service.go b/ntp/service.go index c5506197..4c95045a 100644 --- a/ntp/service.go +++ b/ntp/service.go @@ -5,9 +5,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/log" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/ntp" diff --git a/rules/common/domain.go b/rules/common/domain.go index 35a06a70..23f21185 100644 --- a/rules/common/domain.go +++ b/rules/common/domain.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Domain struct { diff --git a/rules/common/domain_keyword.go b/rules/common/domain_keyword.go index d945f200..ec01293a 100644 --- a/rules/common/domain_keyword.go +++ b/rules/common/domain_keyword.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type DomainKeyword struct { diff --git a/rules/common/domain_suffix.go b/rules/common/domain_suffix.go index b13036a3..b7b1794d 100644 --- a/rules/common/domain_suffix.go +++ b/rules/common/domain_suffix.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type DomainSuffix struct { diff --git a/rules/common/final.go b/rules/common/final.go index 8aa5ed7b..d3a415a0 100644 --- a/rules/common/final.go +++ b/rules/common/final.go @@ -1,7 +1,7 @@ package common import ( - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Match struct { diff --git a/rules/common/geoip.go b/rules/common/geoip.go index 2f96c2ef..3a29fae4 100644 --- a/rules/common/geoip.go +++ b/rules/common/geoip.go @@ -4,12 +4,12 @@ import ( "fmt" "strings" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/component/mmdb" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + "github.com/metacubex/mihomo/component/mmdb" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type GEOIP struct { diff --git a/rules/common/geosite.go b/rules/common/geosite.go index e89dc19b..e9b19d0e 100644 --- a/rules/common/geosite.go +++ b/rules/common/geosite.go @@ -3,12 +3,12 @@ package common import ( "fmt" - "github.com/Dreamacro/clash/component/geodata" - _ "github.com/Dreamacro/clash/component/geodata/memconservative" - "github.com/Dreamacro/clash/component/geodata/router" - _ "github.com/Dreamacro/clash/component/geodata/standard" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata" + _ "github.com/metacubex/mihomo/component/geodata/memconservative" + "github.com/metacubex/mihomo/component/geodata/router" + _ "github.com/metacubex/mihomo/component/geodata/standard" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type GEOSITE struct { diff --git a/rules/common/in_name.go b/rules/common/in_name.go index 1e2abe15..9b14ef6a 100644 --- a/rules/common/in_name.go +++ b/rules/common/in_name.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/in_type.go b/rules/common/in_type.go index 453045d8..fc73b208 100644 --- a/rules/common/in_type.go +++ b/rules/common/in_type.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/in_user.go b/rules/common/in_user.go index 24f4b2e5..ebe881af 100644 --- a/rules/common/in_user.go +++ b/rules/common/in_user.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/ipcidr.go b/rules/common/ipcidr.go index 4cdf9106..663c9397 100644 --- a/rules/common/ipcidr.go +++ b/rules/common/ipcidr.go @@ -3,7 +3,7 @@ package common import ( "net/netip" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type IPCIDROption func(*IPCIDR) diff --git a/rules/common/ipsuffix.go b/rules/common/ipsuffix.go index b01557dc..3251faf8 100644 --- a/rules/common/ipsuffix.go +++ b/rules/common/ipsuffix.go @@ -1,7 +1,7 @@ package common import ( - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "net/netip" ) diff --git a/rules/common/network_type.go b/rules/common/network_type.go index 1184ba89..83a332d8 100644 --- a/rules/common/network_type.go +++ b/rules/common/network_type.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/port.go b/rules/common/port.go index 334d083f..ec76cf30 100644 --- a/rules/common/port.go +++ b/rules/common/port.go @@ -3,8 +3,8 @@ package common import ( "fmt" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" ) type Port struct { diff --git a/rules/common/process.go b/rules/common/process.go index e972d2bc..ce643594 100644 --- a/rules/common/process.go +++ b/rules/common/process.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Process struct { diff --git a/rules/common/uid.go b/rules/common/uid.go index 3b20928f..de46c409 100644 --- a/rules/common/uid.go +++ b/rules/common/uid.go @@ -4,9 +4,9 @@ import ( "fmt" "runtime" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type Uid struct { diff --git a/rules/logic/logic.go b/rules/logic/logic.go index a53503df..4256a200 100644 --- a/rules/logic/logic.go +++ b/rules/logic/logic.go @@ -5,9 +5,9 @@ import ( "regexp" "strings" - "github.com/Dreamacro/clash/common/collections" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/rules/common" + "github.com/metacubex/mihomo/common/collections" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/rules/common" ) type Logic struct { diff --git a/rules/logic_test/logic_test.go b/rules/logic_test/logic_test.go index 52318b3f..e88c8578 100644 --- a/rules/logic_test/logic_test.go +++ b/rules/logic_test/logic_test.go @@ -2,10 +2,10 @@ package logic_test import ( // https://github.com/golang/go/wiki/CodeReviewComments#import-dot - . "github.com/Dreamacro/clash/rules/logic" + . "github.com/metacubex/mihomo/rules/logic" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/rules" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/rules" "github.com/stretchr/testify/assert" "testing" ) diff --git a/rules/parser.go b/rules/parser.go index df790bc3..b1baa758 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -2,10 +2,10 @@ package rules import ( "fmt" - C "github.com/Dreamacro/clash/constant" - RC "github.com/Dreamacro/clash/rules/common" - "github.com/Dreamacro/clash/rules/logic" - RP "github.com/Dreamacro/clash/rules/provider" + C "github.com/metacubex/mihomo/constant" + RC "github.com/metacubex/mihomo/rules/common" + "github.com/metacubex/mihomo/rules/logic" + RP "github.com/metacubex/mihomo/rules/provider" ) func ParseRule(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error) { diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index 6561f12f..f8042164 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -2,8 +2,8 @@ package provider import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "strings" ) diff --git a/rules/provider/domain_strategy.go b/rules/provider/domain_strategy.go index d686d598..c0787d58 100644 --- a/rules/provider/domain_strategy.go +++ b/rules/provider/domain_strategy.go @@ -1,9 +1,9 @@ package provider import ( - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type domainStrategy struct { diff --git a/rules/provider/ipcidr_strategy.go b/rules/provider/ipcidr_strategy.go index f54302f1..321e901a 100644 --- a/rules/provider/ipcidr_strategy.go +++ b/rules/provider/ipcidr_strategy.go @@ -1,9 +1,9 @@ package provider import ( - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type ipcidrStrategy struct { diff --git a/rules/provider/parse.go b/rules/provider/parse.go index 0fbfb2cc..3a5c4fd7 100644 --- a/rules/provider/parse.go +++ b/rules/provider/parse.go @@ -5,10 +5,10 @@ import ( "fmt" "time" - "github.com/Dreamacro/clash/common/structure" - "github.com/Dreamacro/clash/component/resource" - C "github.com/Dreamacro/clash/constant" - P "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + P "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/rules/provider/provider.go b/rules/provider/provider.go index 65d21d2f..adc2e44a 100644 --- a/rules/provider/provider.go +++ b/rules/provider/provider.go @@ -9,10 +9,10 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/component/resource" - C "github.com/Dreamacro/clash/constant" - P "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + P "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/rules/provider/rule_set.go b/rules/provider/rule_set.go index 45cddf6c..1d940188 100644 --- a/rules/provider/rule_set.go +++ b/rules/provider/rule_set.go @@ -2,9 +2,9 @@ package provider import ( "fmt" - C "github.com/Dreamacro/clash/constant" - P "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/rules/common" + C "github.com/metacubex/mihomo/constant" + P "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/rules/common" ) type RuleSet struct { diff --git a/test/.golangci.yaml b/test/.golangci.yaml index b65afc5e..e1fbbf76 100644 --- a/test/.golangci.yaml +++ b/test/.golangci.yaml @@ -10,7 +10,7 @@ linters-settings: gci: sections: - standard - - prefix(github.com/Dreamacro/clash) + - prefix(github.com/metacubex/mihomo) - default staticcheck: go: '1.19' diff --git a/test/README.md b/test/README.md index a95f3aea..e9fa5630 100644 --- a/test/README.md +++ b/test/README.md @@ -1,4 +1,4 @@ -## Clash testing suit +## Mihomo testing suit ### Protocol testing suit @@ -51,8 +51,8 @@ $ make test benchmark (Linux) > Cannot represent the throughput of the protocol on your machine -> but you can compare the corresponding throughput of the protocol on clash -> (change chunkSize to measure the maximum throughput of clash on your machine) +> but you can compare the corresponding throughput of the protocol on mihomo +> (change chunkSize to measure the maximum throughput of mihomo on your machine) ``` $ make benchmark diff --git a/test/clash_test.go b/test/clash_test.go index 60b99791..90ac9d22 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -16,13 +16,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/transport/socks5" "github.com/docker/docker/api/types" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/transport/socks5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -658,7 +658,7 @@ func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) { }) } -func TestClash_Basic(t *testing.T) { +func TestMihomo_Basic(t *testing.T) { basic := ` mixed-port: 10000 log-level: silent diff --git a/test/dns_test.go b/test/dns_test.go index 8e30ba98..f45ffbe0 100644 --- a/test/dns_test.go +++ b/test/dns_test.go @@ -21,7 +21,7 @@ func exchange(address, domain string, tp uint16) ([]dns.RR, error) { return r.Answer, nil } -func TestClash_DNS(t *testing.T) { +func TestMihomo_DNS(t *testing.T) { basic := ` log-level: silent dns: @@ -49,11 +49,11 @@ dns: assert.Empty(t, rr) } -func TestClash_DNSHostAndFakeIP(t *testing.T) { +func TestMihomo_DNSHostAndFakeIP(t *testing.T) { basic := ` log-level: silent hosts: - foo.clash.dev: 1.1.1.1 + foo.mihomo.dev: 1.1.1.1 dns: enable: true listen: 0.0.0.0:8553 @@ -81,7 +81,7 @@ dns: {"foo.org", "198.18.0.4"}, {"bar.org", "198.18.0.5"}, {"foo.org", "198.18.0.4"}, - {"foo.clash.dev", "1.1.1.1"}, + {"foo.mihomo.dev", "1.1.1.1"}, } for _, pair := range list { diff --git a/test/go.mod b/test/go.mod index 36fa7256..adb42a2c 100644 --- a/test/go.mod +++ b/test/go.mod @@ -1,17 +1,17 @@ -module clash-test +module mihomo-test -go 1.19 +go 1.20 require ( - github.com/Dreamacro/clash v0.0.0 github.com/docker/docker v20.10.21+incompatible github.com/docker/go-connections v0.4.0 + github.com/metacubex/mihomo v0.0.0 github.com/miekg/dns v1.1.56 github.com/stretchr/testify v1.8.4 golang.org/x/net v0.17.0 ) -replace github.com/Dreamacro/clash => ../ +replace github.com/metacubex/mihomo => ../ require ( github.com/3andne/restls-client-go v0.1.6 // indirect @@ -30,17 +30,18 @@ require ( github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.3.0 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/mock v1.6.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect - github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a // indirect github.com/josharian/native v1.1.0 // indirect @@ -54,9 +55,10 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b // indirect + github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 // indirect github.com/metacubex/sing-shadowsocks v0.2.5 // indirect github.com/metacubex/sing-shadowsocks2 v0.1.4 // indirect - github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c // indirect + github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd // indirect github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 // indirect github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 // indirect github.com/moby/term v0.5.0 // indirect @@ -77,7 +79,7 @@ require ( github.com/quic-go/qtls-go1-20 v0.3.4 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.2.13 // indirect + github.com/sagernet/sing v0.2.14 // indirect github.com/sagernet/sing-mux v0.1.3 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect @@ -100,6 +102,8 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.etcd.io/bbolt v1.3.7 // indirect + go.uber.org/mock v0.3.0 // indirect + go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect diff --git a/test/go.sum b/test/go.sum index 10d016c9..c7524eff 100644 --- a/test/go.sum +++ b/test/go.sum @@ -15,8 +15,7 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= -github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= +github.com/cilium/ebpf v0.12.0 h1:oQEuIQIXgYhe1v7sYUG0P9vtJTYZLLdA6tiQmrOB1mo= github.com/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= @@ -43,22 +42,26 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4Rfsap github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0= +github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= -github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -71,8 +74,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -101,29 +102,23 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= -github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= -github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= +github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= -github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= -github.com/metacubex/sing-shadowsocks v0.2.4/go.mod h1:w9qoEZSh9aKeXSLXHe0DGbG2UE9/2VlLGwukzQZ7byI= +github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= +github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= +github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= -github.com/metacubex/sing-shadowsocks2 v0.1.3 h1:nZvH+4jQXZ92NeNdR9fXaUGTPNJPt6u0nkcuh/NEt5Y= -github.com/metacubex/sing-shadowsocks2 v0.1.3/go.mod h1:5Mt93RlmRlIcDmvtapkhQJ8YTRGLFhHciLYopJjs7j8= +github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.11 h1:B8meDewklvKkeUfjqR2ViuYLam0/m4IgkTi3qcJIOuc= -github.com/metacubex/sing-tun v0.1.11/go.mod h1:vbki176Y5sxXC1DWXucrPh3q5j8cKai1D87y8m8rjQc= -github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= -github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 h1:AqqZCr9gOeKdO6oIzFh4b2puOUFcw8MdpmGHWRehyX8= -github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8/go.mod h1:tyJg7b4s8NrSztl/Y1ajA7X0sJLlIsEJWkgRVocjmgY= +github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd h1:k0+92eARqyTAovGhg2AxdsMWHjUsdiGCnR5NuXF3CQY= +github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= +github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= -github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= -github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= +github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= @@ -155,13 +150,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= -github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= -github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= @@ -170,11 +163,9 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6E github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4= -github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= -github.com/sagernet/sing v0.2.13/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= -github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I= -github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= +github.com/sagernet/sing v0.2.14 h1:L3AXDh22nsOOYz2nTRU1JvpRsmzViWKI1B8TsQYG1eY= +github.com/sagernet/sing v0.2.14/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= @@ -190,8 +181,7 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= @@ -228,7 +218,6 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695AP github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= @@ -237,37 +226,33 @@ gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiV gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= +go4.org/netipx v0.0.0-20230824141953-6213f710f925/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= 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= @@ -277,22 +262,18 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= @@ -304,9 +285,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= diff --git a/test/hysteria_test.go b/test/hysteria_test.go index ae638e62..e783d9c2 100644 --- a/test/hysteria_test.go +++ b/test/hysteria_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/assert" ) -func TestClash_Hysteria(t *testing.T) { +func TestMihomo_Hysteria(t *testing.T) { cfg := &container.Config{ Image: ImageHysteria, ExposedPorts: defaultExposedPorts, diff --git a/test/snell_test.go b/test/snell_test.go index ae9ce0c1..311ca7b7 100644 --- a/test/snell_test.go +++ b/test/snell_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_SnellObfsHTTP(t *testing.T) { +func TestMihomo_SnellObfsHTTP(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, @@ -44,7 +44,7 @@ func TestClash_SnellObfsHTTP(t *testing.T) { testSuit(t, proxy) } -func TestClash_SnellObfsTLS(t *testing.T) { +func TestMihomo_SnellObfsTLS(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, @@ -77,7 +77,7 @@ func TestClash_SnellObfsTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_Snell(t *testing.T) { +func TestMihomo_Snell(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, @@ -107,7 +107,7 @@ func TestClash_Snell(t *testing.T) { testSuit(t, proxy) } -func TestClash_Snellv3(t *testing.T) { +func TestMihomo_Snellv3(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, diff --git a/test/ss_test.go b/test/ss_test.go index bec1734b..866fe3a8 100644 --- a/test/ss_test.go +++ b/test/ss_test.go @@ -8,13 +8,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_Shadowsocks(t *testing.T) { +func TestMihomo_Shadowsocks(t *testing.T) { for _, method := range []string{ "aes-128-ctr", "aes-192-ctr", @@ -30,7 +30,7 @@ func TestClash_Shadowsocks(t *testing.T) { "xchacha20-ietf-poly1305", } { t.Run(method, func(t *testing.T) { - testClash_Shadowsocks(t, method, "FzcLbKs2dY9mhL") + testMihomo_Shadowsocks(t, method, "FzcLbKs2dY9mhL") }) } for _, method := range []string{ @@ -39,17 +39,17 @@ func TestClash_Shadowsocks(t *testing.T) { "chacha20-ietf-poly1305", } { t.Run(method, func(t *testing.T) { - testClash_ShadowsocksRust(t, method, "FzcLbKs2dY9mhL") + testMihomo_ShadowsocksRust(t, method, "FzcLbKs2dY9mhL") }) } } -func TestClash_Shadowsocks2022(t *testing.T) { +func TestMihomo_Shadowsocks2022(t *testing.T) { for _, method := range []string{ "2022-blake3-aes-128-gcm", } { t.Run(method, func(t *testing.T) { - testClash_ShadowsocksRust(t, method, mkKey(16)) + testMihomo_ShadowsocksRust(t, method, mkKey(16)) }) } for _, method := range []string{ @@ -57,7 +57,7 @@ func TestClash_Shadowsocks2022(t *testing.T) { "2022-blake3-chacha20-poly1305", } { t.Run(method, func(t *testing.T) { - testClash_ShadowsocksRust(t, method, mkKey(32)) + testMihomo_ShadowsocksRust(t, method, mkKey(32)) }) } } @@ -68,7 +68,7 @@ func mkKey(bits int) string { return base64.StdEncoding.EncodeToString(k) } -func testClash_Shadowsocks(t *testing.T, method string, password string) { +func testMihomo_Shadowsocks(t *testing.T, method string, password string) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -102,7 +102,7 @@ func testClash_Shadowsocks(t *testing.T, method string, password string) { testSuit(t, proxy) } -func testClash_ShadowsocksRust(t *testing.T, method string, password string) { +func testMihomo_ShadowsocksRust(t *testing.T, method string, password string) { cfg := &container.Config{ Image: ImageShadowsocksRust, Entrypoint: []string{"ssserver"}, @@ -134,7 +134,7 @@ func testClash_ShadowsocksRust(t *testing.T, method string, password string) { testSuit(t, proxy) } -func TestClash_ShadowsocksObfsHTTP(t *testing.T) { +func TestMihomo_ShadowsocksObfsHTTP(t *testing.T) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -172,7 +172,7 @@ func TestClash_ShadowsocksObfsHTTP(t *testing.T) { testSuit(t, proxy) } -func TestClash_ShadowsocksObfsTLS(t *testing.T) { +func TestMihomo_ShadowsocksObfsTLS(t *testing.T) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -210,7 +210,7 @@ func TestClash_ShadowsocksObfsTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_ShadowsocksV2RayPlugin(t *testing.T) { +func TestMihomo_ShadowsocksV2RayPlugin(t *testing.T) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -280,7 +280,7 @@ func Benchmark_Shadowsocks(b *testing.B) { benchmarkProxy(b, proxy) } -func TestClash_ShadowsocksUoT(t *testing.T) { +func TestMihomo_ShadowsocksUoT(t *testing.T) { configPath := C.Path.Resolve("xray-shadowsocks.json") cfg := &container.Config{ diff --git a/test/trojan_test.go b/test/trojan_test.go index 4885fd3b..c6b1fea0 100644 --- a/test/trojan_test.go +++ b/test/trojan_test.go @@ -6,13 +6,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_Trojan(t *testing.T) { +func TestMihomo_Trojan(t *testing.T) { cfg := &container.Config{ Image: ImageTrojan, ExposedPorts: defaultExposedPorts, @@ -48,7 +48,7 @@ func TestClash_Trojan(t *testing.T) { testSuit(t, proxy) } -func TestClash_TrojanGrpc(t *testing.T) { +func TestMihomo_TrojanGrpc(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, @@ -87,7 +87,7 @@ func TestClash_TrojanGrpc(t *testing.T) { testSuit(t, proxy) } -func TestClash_TrojanWebsocket(t *testing.T) { +func TestMihomo_TrojanWebsocket(t *testing.T) { cfg := &container.Config{ Image: ImageTrojanGo, ExposedPorts: defaultExposedPorts, @@ -123,7 +123,7 @@ func TestClash_TrojanWebsocket(t *testing.T) { testSuit(t, proxy) } -func TestClash_TrojanXTLS(t *testing.T) { +func TestMihomo_TrojanXTLS(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, diff --git a/test/vless_test.go b/test/vless_test.go index b75fb3ad..d0e6f071 100644 --- a/test/vless_test.go +++ b/test/vless_test.go @@ -5,14 +5,14 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/assert" ) // TODO: fix udp test -func TestClash_VlessTLS(t *testing.T) { +func TestMihomo_VlessTLS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -51,7 +51,7 @@ func TestClash_VlessTLS(t *testing.T) { } // TODO: fix udp test -func TestClash_VlessXTLS(t *testing.T) { +func TestMihomo_VlessXTLS(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, @@ -81,7 +81,6 @@ func TestClash_VlessXTLS(t *testing.T) { ServerName: "example.org", UDP: true, Flow: "xtls-rprx-direct", - FlowShow: true, }) if err != nil { assert.FailNow(t, err.Error()) @@ -92,7 +91,7 @@ func TestClash_VlessXTLS(t *testing.T) { } // TODO: fix udp test -func TestClash_VlessWS(t *testing.T) { +func TestMihomo_VlessWS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, diff --git a/test/vmess_test.go b/test/vmess_test.go index fd83fff8..80c3d4d8 100644 --- a/test/vmess_test.go +++ b/test/vmess_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_Vmess(t *testing.T) { +func TestMihomo_Vmess(t *testing.T) { configPath := C.Path.Resolve("vmess.json") cfg := &container.Config{ @@ -44,7 +44,7 @@ func TestClash_Vmess(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessAuthenticatedLength(t *testing.T) { +func TestMihomo_VmessAuthenticatedLength(t *testing.T) { configPath := C.Path.Resolve("vmess.json") cfg := &container.Config{ @@ -78,7 +78,7 @@ func TestClash_VmessAuthenticatedLength(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessPacketAddr(t *testing.T) { +func TestMihomo_VmessPacketAddr(t *testing.T) { configPath := C.Path.Resolve("vmess.json") cfg := &container.Config{ @@ -112,7 +112,7 @@ func TestClash_VmessPacketAddr(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessTLS(t *testing.T) { +func TestMihomo_VmessTLS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -149,7 +149,7 @@ func TestClash_VmessTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessHTTP2(t *testing.T) { +func TestMihomo_VmessHTTP2(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -191,7 +191,7 @@ func TestClash_VmessHTTP2(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessHTTP(t *testing.T) { +func TestMihomo_VmessHTTP(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -241,7 +241,7 @@ func TestClash_VmessHTTP(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocket(t *testing.T) { +func TestMihomo_VmessWebsocket(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -274,7 +274,7 @@ func TestClash_VmessWebsocket(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocketTLS(t *testing.T) { +func TestMihomo_VmessWebsocketTLS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -311,7 +311,7 @@ func TestClash_VmessWebsocketTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessGrpc(t *testing.T) { +func TestMihomo_VmessGrpc(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -352,7 +352,7 @@ func TestClash_VmessGrpc(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocket0RTT(t *testing.T) { +func TestMihomo_VmessWebsocket0RTT(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -390,7 +390,7 @@ func TestClash_VmessWebsocket0RTT(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocketXray0RTT(t *testing.T) { +func TestMihomo_VmessWebsocketXray0RTT(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, diff --git a/transport/gun/gun.go b/transport/gun/gun.go index d6ef6317..cf986c8e 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -17,10 +17,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/common/pool" - tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/common/pool" + tlsC "github.com/metacubex/mihomo/component/tls" "golang.org/x/net/http2" ) diff --git a/transport/hysteria/conns/faketcp/obfs.go b/transport/hysteria/conns/faketcp/obfs.go index 35f7d013..cf58e569 100644 --- a/transport/hysteria/conns/faketcp/obfs.go +++ b/transport/hysteria/conns/faketcp/obfs.go @@ -1,7 +1,7 @@ package faketcp import ( - "github.com/Dreamacro/clash/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/obfs" "net" "sync" "syscall" diff --git a/transport/hysteria/conns/faketcp/tcp_linux.go b/transport/hysteria/conns/faketcp/tcp_linux.go index 76ed0d5e..2aaaf139 100644 --- a/transport/hysteria/conns/faketcp/tcp_linux.go +++ b/transport/hysteria/conns/faketcp/tcp_linux.go @@ -20,7 +20,7 @@ import ( "github.com/metacubex/gopacket" "github.com/metacubex/gopacket/layers" - "github.com/Dreamacro/clash/component/dialer" + "github.com/metacubex/mihomo/component/dialer" ) var ( diff --git a/transport/hysteria/conns/udp/hop.go b/transport/hysteria/conns/udp/hop.go index 447a7592..eb0732f0 100644 --- a/transport/hysteria/conns/udp/hop.go +++ b/transport/hysteria/conns/udp/hop.go @@ -9,8 +9,8 @@ import ( "syscall" "time" - "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/utils" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/hysteria/conns/udp/obfs.go b/transport/hysteria/conns/udp/obfs.go index d63034b5..a5c6c06c 100644 --- a/transport/hysteria/conns/udp/obfs.go +++ b/transport/hysteria/conns/udp/obfs.go @@ -1,7 +1,7 @@ package udp import ( - "github.com/Dreamacro/clash/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/obfs" "net" "sync" "time" diff --git a/transport/hysteria/conns/wechat/obfs.go b/transport/hysteria/conns/wechat/obfs.go index d13cca55..4266d268 100644 --- a/transport/hysteria/conns/wechat/obfs.go +++ b/transport/hysteria/conns/wechat/obfs.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/hysteria/obfs" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/hysteria/obfs" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index ecc8a6f1..b556c70d 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -11,10 +11,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/pmtud_fix" - "github.com/Dreamacro/clash/transport/hysteria/transport" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/pmtud_fix" + "github.com/metacubex/mihomo/transport/hysteria/transport" + "github.com/metacubex/mihomo/transport/hysteria/utils" "github.com/lunixbochs/struc" "github.com/metacubex/quic-go" diff --git a/transport/hysteria/transport/client.go b/transport/hysteria/transport/client.go index 67568bc8..f5cc9f07 100644 --- a/transport/hysteria/transport/client.go +++ b/transport/hysteria/transport/client.go @@ -9,11 +9,11 @@ import ( "github.com/metacubex/quic-go" - "github.com/Dreamacro/clash/transport/hysteria/conns/faketcp" - "github.com/Dreamacro/clash/transport/hysteria/conns/udp" - "github.com/Dreamacro/clash/transport/hysteria/conns/wechat" - obfsPkg "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/transport/hysteria/conns/faketcp" + "github.com/metacubex/mihomo/transport/hysteria/conns/udp" + "github.com/metacubex/mihomo/transport/hysteria/conns/wechat" + obfsPkg "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/utils" ) type ClientTransport struct { diff --git a/transport/shadowsocks/core/cipher.go b/transport/shadowsocks/core/cipher.go index cd30360c..44b2e8d4 100644 --- a/transport/shadowsocks/core/cipher.go +++ b/transport/shadowsocks/core/cipher.go @@ -7,9 +7,9 @@ import ( "sort" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowstream" ) type Cipher interface { diff --git a/transport/shadowsocks/shadowaead/packet.go b/transport/shadowsocks/shadowaead/packet.go index e84ac570..f9d21ec7 100644 --- a/transport/shadowsocks/shadowaead/packet.go +++ b/transport/shadowsocks/shadowaead/packet.go @@ -6,8 +6,8 @@ import ( "io" "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" ) // ErrShortPacket means that the packet is too short for a valid encrypted packet. diff --git a/transport/shadowsocks/shadowaead/stream.go b/transport/shadowsocks/shadowaead/stream.go index e92bddab..de0993b2 100644 --- a/transport/shadowsocks/shadowaead/stream.go +++ b/transport/shadowsocks/shadowaead/stream.go @@ -7,7 +7,7 @@ import ( "io" "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) const ( diff --git a/transport/shadowsocks/shadowstream/packet.go b/transport/shadowsocks/shadowstream/packet.go index f0bf43ef..39d09a70 100644 --- a/transport/shadowsocks/shadowstream/packet.go +++ b/transport/shadowsocks/shadowstream/packet.go @@ -6,8 +6,8 @@ import ( "io" "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" ) // ErrShortPacket means the packet is too short to be a valid encrypted packet. diff --git a/transport/shadowtls/shadowtls.go b/transport/shadowtls/shadowtls.go index 2c0c5946..a0a3d7fb 100644 --- a/transport/shadowtls/shadowtls.go +++ b/transport/shadowtls/shadowtls.go @@ -11,8 +11,8 @@ import ( "io" "net" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" ) const ( diff --git a/transport/simple-obfs/http.go b/transport/simple-obfs/http.go index 80db34ba..681c1864 100644 --- a/transport/simple-obfs/http.go +++ b/transport/simple-obfs/http.go @@ -8,7 +8,7 @@ import ( "net" "net/http" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/simple-obfs/tls.go b/transport/simple-obfs/tls.go index 20166bbe..78317f0a 100644 --- a/transport/simple-obfs/tls.go +++ b/transport/simple-obfs/tls.go @@ -7,7 +7,7 @@ import ( "net" "time" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go index 6d731ae6..982d847a 100644 --- a/transport/sing-shadowtls/shadowtls.go +++ b/transport/sing-shadowtls/shadowtls.go @@ -5,9 +5,9 @@ import ( "crypto/tls" "net" - "github.com/Dreamacro/clash/component/ca" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ca" + tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/log" "github.com/sagernet/sing-shadowtls" sing_common "github.com/sagernet/sing/common" diff --git a/transport/snell/cipher.go b/transport/snell/cipher.go index 24999e28..e18ce510 100644 --- a/transport/snell/cipher.go +++ b/transport/snell/cipher.go @@ -4,7 +4,7 @@ import ( "crypto/aes" "crypto/cipher" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" "golang.org/x/crypto/argon2" "golang.org/x/crypto/chacha20poly1305" diff --git a/transport/snell/pool.go b/transport/snell/pool.go index 2a233a75..cc097df7 100644 --- a/transport/snell/pool.go +++ b/transport/snell/pool.go @@ -5,8 +5,8 @@ import ( "net" "time" - "github.com/Dreamacro/clash/component/pool" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/component/pool" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" ) type Pool struct { @@ -61,7 +61,7 @@ func (pc *PoolConn) Write(b []byte) (int, error) { } func (pc *PoolConn) Close() error { - // clash use SetReadDeadline to break bidirectional copy between client and server. + // mihomo use SetReadDeadline to break bidirectional copy between client and server. // reset it before reuse connection to avoid io timeout error. _ = pc.Snell.Conn.SetReadDeadline(time.Time{}) pc.pool.Put(pc.Snell) diff --git a/transport/snell/snell.go b/transport/snell/snell.go index e2bd2820..fe3e4ee0 100644 --- a/transport/snell/snell.go +++ b/transport/snell/snell.go @@ -8,9 +8,9 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/socks5" ) const ( diff --git a/transport/socks4/socks4.go b/transport/socks4/socks4.go index 0d5c5a77..9533a1c0 100644 --- a/transport/socks4/socks4.go +++ b/transport/socks4/socks4.go @@ -9,7 +9,7 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/component/auth" + "github.com/metacubex/mihomo/component/auth" ) const Version = 0x04 diff --git a/transport/socks5/socks5.go b/transport/socks5/socks5.go index 6f95cce9..c97c370c 100644 --- a/transport/socks5/socks5.go +++ b/transport/socks5/socks5.go @@ -9,7 +9,7 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/component/auth" + "github.com/metacubex/mihomo/component/auth" ) // Error represents a SOCKS error diff --git a/transport/ssr/obfs/http_simple.go b/transport/ssr/obfs/http_simple.go index c91cca49..359ca342 100644 --- a/transport/ssr/obfs/http_simple.go +++ b/transport/ssr/obfs/http_simple.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/obfs/random_head.go b/transport/ssr/obfs/random_head.go index 4c55d951..9a2072fe 100644 --- a/transport/ssr/obfs/random_head.go +++ b/transport/ssr/obfs/random_head.go @@ -5,7 +5,7 @@ import ( "hash/crc32" "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/obfs/tls1.2_ticket_auth.go b/transport/ssr/obfs/tls1.2_ticket_auth.go index af945133..d5e3ca88 100644 --- a/transport/ssr/obfs/tls1.2_ticket_auth.go +++ b/transport/ssr/obfs/tls1.2_ticket_auth.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/ssr/tools" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/ssr/tools" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/auth_aes128_md5.go b/transport/ssr/protocol/auth_aes128_md5.go index d3bc9417..c6ae415e 100644 --- a/transport/ssr/protocol/auth_aes128_md5.go +++ b/transport/ssr/protocol/auth_aes128_md5.go @@ -1,6 +1,6 @@ package protocol -import "github.com/Dreamacro/clash/transport/ssr/tools" +import "github.com/metacubex/mihomo/transport/ssr/tools" func init() { register("auth_aes128_md5", newAuthAES128MD5, 9) diff --git a/transport/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go index e2f0e143..6ee4160e 100644 --- a/transport/ssr/protocol/auth_aes128_sha1.go +++ b/transport/ssr/protocol/auth_aes128_sha1.go @@ -8,10 +8,10 @@ import ( "strconv" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/ssr/tools" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/ssr/tools" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go index 12345db6..396172ef 100644 --- a/transport/ssr/protocol/auth_chain_a.go +++ b/transport/ssr/protocol/auth_chain_a.go @@ -12,11 +12,11 @@ import ( "strconv" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/ssr/tools" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/ssr/tools" ) func init() { @@ -108,7 +108,7 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { dataLength := int(binary.LittleEndian.Uint16(src.Bytes()[:2]) ^ binary.LittleEndian.Uint16(a.lastServerHash[14:16])) randDataLength := a.randDataLength(dataLength, a.lastServerHash, &a.randomServer) length := dataLength + randDataLength - // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + // Temporary workaround for https://github.com/metacubex/mihomo/issues/1352 if dataLength < 0 || randDataLength < 0 || length < 0 { return errors.New("ssr crashing blocked") } @@ -135,7 +135,7 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { if dataLength > 0 && randDataLength > 0 { pos += getRandStartPos(randDataLength, &a.randomServer) } - // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + // Temporary workaround for https://github.com/metacubex/mihomo/issues/1352 if pos < 0 || pos+dataLength < 0 || dataLength < 0 { return errors.New("ssr crashing blocked") } diff --git a/transport/ssr/protocol/auth_chain_b.go b/transport/ssr/protocol/auth_chain_b.go index 857b2a3a..223613a9 100644 --- a/transport/ssr/protocol/auth_chain_b.go +++ b/transport/ssr/protocol/auth_chain_b.go @@ -4,7 +4,7 @@ import ( "net" "sort" - "github.com/Dreamacro/clash/transport/ssr/tools" + "github.com/metacubex/mihomo/transport/ssr/tools" ) func init() { diff --git a/transport/ssr/protocol/auth_sha1_v4.go b/transport/ssr/protocol/auth_sha1_v4.go index 26039181..ed1a39f1 100644 --- a/transport/ssr/protocol/auth_sha1_v4.go +++ b/transport/ssr/protocol/auth_sha1_v4.go @@ -7,9 +7,9 @@ import ( "hash/crc32" "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/ssr/tools" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/ssr/tools" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/base.go b/transport/ssr/protocol/base.go index a826bec8..e26a6587 100644 --- a/transport/ssr/protocol/base.go +++ b/transport/ssr/protocol/base.go @@ -9,9 +9,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/shadowsocks/core" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/shadowsocks/core" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/origin.go b/transport/ssr/protocol/origin.go index 52525a2f..4d8b630a 100644 --- a/transport/ssr/protocol/origin.go +++ b/transport/ssr/protocol/origin.go @@ -4,7 +4,7 @@ import ( "bytes" "net" - N "github.com/Dreamacro/clash/common/net" + N "github.com/metacubex/mihomo/common/net" ) type origin struct{} diff --git a/transport/ssr/protocol/packet.go b/transport/ssr/protocol/packet.go index 988ff75d..86d573f3 100644 --- a/transport/ssr/protocol/packet.go +++ b/transport/ssr/protocol/packet.go @@ -3,8 +3,8 @@ package protocol import ( "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" ) type PacketConn struct { diff --git a/transport/ssr/protocol/protocol.go b/transport/ssr/protocol/protocol.go index 1c27da48..a04e6bd4 100644 --- a/transport/ssr/protocol/protocol.go +++ b/transport/ssr/protocol/protocol.go @@ -6,7 +6,7 @@ import ( "fmt" "net" - N "github.com/Dreamacro/clash/common/net" + N "github.com/metacubex/mihomo/common/net" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/stream.go b/transport/ssr/protocol/stream.go index 3c846157..436859c3 100644 --- a/transport/ssr/protocol/stream.go +++ b/transport/ssr/protocol/stream.go @@ -4,7 +4,7 @@ import ( "bytes" "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type Conn struct { diff --git a/transport/ssr/tools/random.go b/transport/ssr/tools/random.go index 338543ea..c76011e4 100644 --- a/transport/ssr/tools/random.go +++ b/transport/ssr/tools/random.go @@ -3,7 +3,7 @@ package tools import ( "encoding/binary" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) // XorShift128Plus - a pseudorandom number generator diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 20ba80b3..c4bd1167 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -12,13 +12,13 @@ import ( "net/http" "sync" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/component/ca" - tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/vmess" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/component/ca" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/vmess" ) const ( diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 13c1300f..485e2e6a 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -1,8 +1,8 @@ package common import ( - "github.com/Dreamacro/clash/transport/tuic/congestion" - congestionv2 "github.com/Dreamacro/clash/transport/tuic/congestion_v2" + "github.com/metacubex/mihomo/transport/tuic/congestion" + congestionv2 "github.com/metacubex/mihomo/transport/tuic/congestion_v2" "github.com/metacubex/quic-go" c "github.com/metacubex/quic-go/congestion" diff --git a/transport/tuic/common/type.go b/transport/tuic/common/type.go index 9a568dd7..c663fa0b 100644 --- a/transport/tuic/common/type.go +++ b/transport/tuic/common/type.go @@ -7,8 +7,8 @@ import ( "net" "time" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/pool_client.go b/transport/tuic/pool_client.go index 4a779706..e492fba7 100644 --- a/transport/tuic/pool_client.go +++ b/transport/tuic/pool_client.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/generics/list" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/generics/list" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/server.go b/transport/tuic/server.go index cabc04e0..a273e462 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -7,14 +7,14 @@ import ( "net" "time" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/tuic/common" - v4 "github.com/Dreamacro/clash/transport/tuic/v4" - v5 "github.com/Dreamacro/clash/transport/tuic/v5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic/common" + v4 "github.com/metacubex/mihomo/transport/tuic/v4" + v5 "github.com/metacubex/mihomo/transport/tuic/v5" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/transport/tuic/tuic.go b/transport/tuic/tuic.go index 387a152c..02aaa3ad 100644 --- a/transport/tuic/tuic.go +++ b/transport/tuic/tuic.go @@ -1,10 +1,10 @@ package tuic import ( - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/tuic/common" - v4 "github.com/Dreamacro/clash/transport/tuic/v4" - v5 "github.com/Dreamacro/clash/transport/tuic/v5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/tuic/common" + v4 "github.com/metacubex/mihomo/transport/tuic/v4" + v5 "github.com/metacubex/mihomo/transport/tuic/v5" ) type ClientOptionV4 = v4.ClientOption diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index ce33b72b..0bc8f9bb 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -13,13 +13,13 @@ import ( "time" "unsafe" - atomic2 "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/tuic/common" + atomic2 "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/puzpuzpuz/xsync/v2" diff --git a/transport/tuic/v4/packet.go b/transport/tuic/v4/packet.go index 2066ceb7..5bd6504c 100644 --- a/transport/tuic/v4/packet.go +++ b/transport/tuic/v4/packet.go @@ -5,10 +5,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/tuic/common" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/v4/protocol.go b/transport/tuic/v4/protocol.go index bbdca67c..29536742 100644 --- a/transport/tuic/v4/protocol.go +++ b/transport/tuic/v4/protocol.go @@ -11,8 +11,8 @@ import ( "github.com/metacubex/quic-go" "lukechampine.com/blake3" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type BufferedReader interface { diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index 56133fea..c4e4d735 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -7,13 +7,13 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/atomic" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/tuic/common" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index c4ac25d4..e37d60fc 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -12,12 +12,12 @@ import ( "sync/atomic" "time" - atomic2 "github.com/Dreamacro/clash/common/atomic" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/tuic/common" + atomic2 "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/puzpuzpuz/xsync/v2" diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go index 8df9f785..4e07a1c7 100644 --- a/transport/tuic/v5/frag.go +++ b/transport/tuic/v5/frag.go @@ -4,7 +4,7 @@ import ( "bytes" "sync" - "github.com/Dreamacro/clash/common/cache" + "github.com/metacubex/mihomo/common/cache" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index efbe0bb9..8ab45068 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -6,10 +6,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/tuic/common" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/zhangyunhao116/fastrand" diff --git a/transport/tuic/v5/protocol.go b/transport/tuic/v5/protocol.go index 964401e1..de51a080 100644 --- a/transport/tuic/v5/protocol.go +++ b/transport/tuic/v5/protocol.go @@ -8,9 +8,9 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index 10003a9d..c8170f62 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -7,12 +7,12 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/atomic" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/tuic/common" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 9cb4420c..1c7056d6 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -6,8 +6,8 @@ import ( "net" "net/http" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/transport/vmess" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/transport/vmess" ) // Option is options of websocket obfs diff --git a/transport/vless/config.pb.go b/transport/vless/config.pb.go index 1407e4d7..14fcc5f9 100644 --- a/transport/vless/config.pb.go +++ b/transport/vless/config.pb.go @@ -108,7 +108,7 @@ func file_transport_vless_config_proto_rawDescGZIP() []byte { var file_transport_vless_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_transport_vless_config_proto_goTypes = []interface{}{ - (*Addons)(nil), // 0: clash.transport.vless.Addons + (*Addons)(nil), // 0: mihomo.transport.vless.Addons } var file_transport_vless_config_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type diff --git a/transport/vless/config.proto b/transport/vless/config.proto index 80900230..44cad479 100644 --- a/transport/vless/config.proto +++ b/transport/vless/config.proto @@ -1,9 +1,9 @@ syntax = "proto3"; -package clash.transport.vless; -option csharp_namespace = "Clash.Transport.Vless"; -option go_package = "github.com/Dreamacro/clash/transport/vless"; -option java_package = "com.clash.transport.vless"; +package mihomo.transport.vless; +option csharp_namespace = "Mihomo.Transport.Vless"; +option go_package = "github.com/metacubex/mihomo/transport/vless"; +option java_package = "com.mihomo.transport.vless"; option java_multiple_files = true; message Addons { diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 33ecd97a..02224892 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -7,9 +7,9 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/transport/vless/vision" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/transport/vless/vision" "github.com/gofrs/uuid/v5" "google.golang.org/protobuf/proto" diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index 03f524aa..79c77835 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -9,9 +9,9 @@ import ( "io" "net" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/log" "github.com/gofrs/uuid/v5" utls "github.com/sagernet/utls" diff --git a/transport/vless/vision/filter.go b/transport/vless/vision/filter.go index e070de35..55b5663f 100644 --- a/transport/vless/vision/filter.go +++ b/transport/vless/vision/filter.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/binary" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) var ( diff --git a/transport/vless/vision/padding.go b/transport/vless/vision/padding.go index d5a230d1..e5f9dc85 100644 --- a/transport/vless/vision/padding.go +++ b/transport/vless/vision/padding.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/binary" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/log" "github.com/gofrs/uuid/v5" "github.com/zhangyunhao116/fastrand" diff --git a/transport/vless/vision/vision.go b/transport/vless/vision/vision.go index 3b52dd4b..09299b23 100644 --- a/transport/vless/vision/vision.go +++ b/transport/vless/vision/vision.go @@ -10,8 +10,8 @@ import ( "reflect" "unsafe" - N "github.com/Dreamacro/clash/common/net" - tlsC "github.com/Dreamacro/clash/component/tls" + N "github.com/metacubex/mihomo/common/net" + tlsC "github.com/metacubex/mihomo/component/tls" "github.com/gofrs/uuid/v5" "github.com/sagernet/sing/common" diff --git a/transport/vless/vless.go b/transport/vless/vless.go index 6c01b839..ce07cdb4 100644 --- a/transport/vless/vless.go +++ b/transport/vless/vless.go @@ -3,7 +3,7 @@ package vless import ( "net" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/gofrs/uuid/v5" ) diff --git a/transport/vmess/aead.go b/transport/vmess/aead.go index d4fbf2d9..89ec6a3b 100644 --- a/transport/vmess/aead.go +++ b/transport/vmess/aead.go @@ -7,7 +7,7 @@ import ( "io" "sync" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type aeadWriter struct { diff --git a/transport/vmess/chunk.go b/transport/vmess/chunk.go index ab1adb6d..f52fc82c 100644 --- a/transport/vmess/chunk.go +++ b/transport/vmess/chunk.go @@ -5,7 +5,7 @@ import ( "errors" "io" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) const ( diff --git a/transport/vmess/http.go b/transport/vmess/http.go index d9e73f68..782e7eb2 100644 --- a/transport/vmess/http.go +++ b/transport/vmess/http.go @@ -8,7 +8,7 @@ import ( "net/http" "net/textproto" - "github.com/Dreamacro/clash/common/util" + "github.com/metacubex/mihomo/common/util" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 8bcb6513..bdaa8ccc 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -6,8 +6,8 @@ import ( "errors" "net" - "github.com/Dreamacro/clash/component/ca" - tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/metacubex/mihomo/component/ca" + tlsC "github.com/metacubex/mihomo/component/tls" ) type TLSConfig struct { diff --git a/transport/vmess/vmess.go b/transport/vmess/vmess.go index 2dd071eb..7c587c6a 100644 --- a/transport/vmess/vmess.go +++ b/transport/vmess/vmess.go @@ -5,7 +5,7 @@ import ( "net" "runtime" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/gofrs/uuid/v5" "github.com/zhangyunhao116/fastrand" diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 9f09185b..b30bb8aa 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -18,10 +18,10 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/log" "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" diff --git a/tunnel/connection.go b/tunnel/connection.go index 9fc4f405..33cc4e8d 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -6,9 +6,9 @@ import ( "net/netip" "time" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error { diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 4797829f..8e962dae 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -4,7 +4,7 @@ import ( "os" "time" - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" "github.com/puzpuzpuz/xsync/v2" "github.com/shirou/gopsutil/v3/process" diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index bc2dbd5c..0bf7995d 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -6,11 +6,11 @@ import ( "net/netip" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" "github.com/gofrs/uuid/v5" ) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index fe37d75e..596e26d7 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -12,16 +12,16 @@ import ( "github.com/jpillora/backoff" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/nat" - P "github.com/Dreamacro/clash/component/process" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/component/sniffer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - icontext "github.com/Dreamacro/clash/context" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel/statistic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/nat" + P "github.com/metacubex/mihomo/component/process" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/component/sniffer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + icontext "github.com/metacubex/mihomo/context" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel/statistic" ) var ( From 575c1d4129f978c353fe72d5e729935333a18aef Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 8 Nov 2023 19:29:26 +0800 Subject: [PATCH 082/192] chore: NameServerPolicy will match inorder --- common/utils/ordered_map.go | 40 +++++++++++ config/config.go | 54 +++++++------- dns/policy.go | 60 ++++++++++------ dns/resolver.go | 138 +++++++++++++++++------------------- hub/executor/executor.go | 28 ++------ 5 files changed, 178 insertions(+), 142 deletions(-) create mode 100644 common/utils/ordered_map.go diff --git a/common/utils/ordered_map.go b/common/utils/ordered_map.go new file mode 100644 index 00000000..9ffc70c2 --- /dev/null +++ b/common/utils/ordered_map.go @@ -0,0 +1,40 @@ +package utils + +// modify from https://github.com/go-yaml/yaml/issues/698#issuecomment-1482026841 + +import ( + "errors" + "gopkg.in/yaml.v3" +) + +type StringMapSlice[V any] []StringMapSliceItem[V] + +type StringMapSliceItem[V any] struct { + Key string + Value V +} + +func (s *StringMapSlice[V]) UnmarshalYAML(value *yaml.Node) error { + for i := 0; i < len(value.Content); i += 2 { + if i+1 >= len(value.Content) { + return errors.New("not a dict") + } + item := StringMapSliceItem[V]{} + item.Key = value.Content[i].Value + if err := value.Content[i+1].Decode(&item.Value); err != nil { + return err + } + + *s = append(*s, item) + } + + return nil +} + +func (s *StringMapSlice[V]) Add(key string, value V) { + *s = append(*s, StringMapSliceItem[V]{Key: key, Value: value}) +} + +func (i *StringMapSliceItem[V]) Extract() (key string, value V) { + return i.Key, i.Value +} diff --git a/config/config.go b/config/config.go index 76ff9d68..7ef395b3 100644 --- a/config/config.go +++ b/config/config.go @@ -114,7 +114,7 @@ type DNS struct { DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` FakeIPRange *fakeip.Pool Hosts *trie.DomainTrie[resolver.HostValue] - NameServerPolicy map[string][]dns.NameServer + NameServerPolicy utils.StringMapSlice[[]dns.NameServer] ProxyServerNameserver []dns.NameServer } @@ -193,21 +193,21 @@ type RawNTP struct { } type RawDNS struct { - Enable bool `yaml:"enable"` - PreferH3 bool `yaml:"prefer-h3"` - IPv6 bool `yaml:"ipv6"` - IPv6Timeout uint `yaml:"ipv6-timeout"` - UseHosts bool `yaml:"use-hosts"` - NameServer []string `yaml:"nameserver"` - Fallback []string `yaml:"fallback"` - FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` - Listen string `yaml:"listen"` - EnhancedMode C.DNSMode `yaml:"enhanced-mode"` - FakeIPRange string `yaml:"fake-ip-range"` - FakeIPFilter []string `yaml:"fake-ip-filter"` - DefaultNameserver []string `yaml:"default-nameserver"` - NameServerPolicy map[string]any `yaml:"nameserver-policy"` - ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` + Enable bool `yaml:"enable"` + PreferH3 bool `yaml:"prefer-h3"` + IPv6 bool `yaml:"ipv6"` + IPv6Timeout uint `yaml:"ipv6-timeout"` + UseHosts bool `yaml:"use-hosts"` + NameServer []string `yaml:"nameserver"` + Fallback []string `yaml:"fallback"` + FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` + Listen string `yaml:"listen"` + EnhancedMode C.DNSMode `yaml:"enhanced-mode"` + FakeIPRange string `yaml:"fake-ip-range"` + FakeIPFilter []string `yaml:"fake-ip-filter"` + DefaultNameserver []string `yaml:"default-nameserver"` + NameServerPolicy utils.StringMapSlice[any] `yaml:"nameserver-policy"` + ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` } type RawFallbackFilter struct { @@ -1085,12 +1085,13 @@ func parsePureDNSServer(server string) string { } } } -func parseNameServerPolicy(nsPolicy map[string]any, ruleProviders map[string]providerTypes.RuleProvider, preferH3 bool) (map[string][]dns.NameServer, error) { - policy := map[string][]dns.NameServer{} - updatedPolicy := make(map[string]interface{}) +func parseNameServerPolicy(nsPolicy utils.StringMapSlice[any], ruleProviders map[string]providerTypes.RuleProvider, preferH3 bool) (utils.StringMapSlice[[]dns.NameServer], error) { + policy := utils.StringMapSlice[[]dns.NameServer]{} + updatedPolicy := utils.StringMapSlice[any]{} re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`) - for k, v := range nsPolicy { + for _, p := range nsPolicy { + k, v := p.Extract() if strings.Contains(k, ",") { if strings.Contains(k, "geosite:") { subkeys := strings.Split(k, ":") @@ -1098,7 +1099,7 @@ func parseNameServerPolicy(nsPolicy map[string]any, ruleProviders map[string]pro subkeys = strings.Split(subkeys[0], ",") for _, subkey := range subkeys { newKey := "geosite:" + subkey - updatedPolicy[newKey] = v + updatedPolicy.Add(newKey, v) } } else if strings.Contains(k, "rule-set:") { subkeys := strings.Split(k, ":") @@ -1106,20 +1107,21 @@ func parseNameServerPolicy(nsPolicy map[string]any, ruleProviders map[string]pro subkeys = strings.Split(subkeys[0], ",") for _, subkey := range subkeys { newKey := "rule-set:" + subkey - updatedPolicy[newKey] = v + updatedPolicy.Add(newKey, v) } } else if re.MatchString(k) { subkeys := strings.Split(k, ",") for _, subkey := range subkeys { - updatedPolicy[subkey] = v + updatedPolicy.Add(subkey, v) } } } else { - updatedPolicy[k] = v + updatedPolicy.Add(k, v) } } - for domain, server := range updatedPolicy { + for _, p := range updatedPolicy { + domain, server := p.Extract() servers, err := utils.ToStringSlice(server) if err != nil { return nil, err @@ -1144,7 +1146,7 @@ func parseNameServerPolicy(nsPolicy map[string]any, ruleProviders map[string]pro } } } - policy[domain] = nameservers + policy.Add(domain, nameservers) } return policy, nil diff --git a/dns/policy.go b/dns/policy.go index a8b423e1..a58123e3 100644 --- a/dns/policy.go +++ b/dns/policy.go @@ -1,30 +1,50 @@ package dns -type Policy struct { - data []dnsClient +import ( + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" +) + +type dnsPolicy interface { + Match(domain string) []dnsClient } -func (p *Policy) GetData() []dnsClient { - return p.data +type domainTriePolicy struct { + *trie.DomainTrie[[]dnsClient] } -func (p *Policy) Compare(p2 *Policy) int { - if p2 == nil { - return 1 +func (p domainTriePolicy) Match(domain string) []dnsClient { + record := p.DomainTrie.Search(domain) + if record != nil { + return record.Data() } - l1 := len(p.data) - l2 := len(p2.data) - if l1 == l2 { - return 0 - } - if l1 > l2 { - return 1 - } - return -1 + return nil } -func NewPolicy(data []dnsClient) *Policy { - return &Policy{ - data: data, - } +type geositePolicy struct { + matcher fallbackDomainFilter + inverse bool + dnsClients []dnsClient +} + +func (p geositePolicy) Match(domain string) []dnsClient { + matched := p.matcher.Match(domain) + if matched != p.inverse { + return p.dnsClients + } + return nil +} + +type domainSetPolicy struct { + domainSetProvider provider.RuleProvider + dnsClients []dnsClient +} + +func (p domainSetPolicy) Match(domain string) []dnsClient { + metadata := &C.Metadata{Host: domain} + if ok := p.domainSetProvider.Match(metadata); ok { + return p.dnsClients + } + return nil } diff --git a/dns/resolver.go b/dns/resolver.go index 610a06f0..7e45252e 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -8,6 +8,7 @@ import ( "time" "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/fakeip" "github.com/metacubex/mihomo/component/geodata/router" "github.com/metacubex/mihomo/component/resolver" @@ -31,17 +32,6 @@ type result struct { Error error } -type geositePolicyRecord struct { - matcher fallbackDomainFilter - policy *Policy - inversedMatching bool -} - -type domainSetPolicyRecord struct { - domainSetProvider provider.RuleProvider - policy *Policy -} - type Resolver struct { ipv6 bool ipv6Timeout time.Duration @@ -52,9 +42,7 @@ type Resolver struct { fallbackIPFilters []fallbackIPFilter group singleflight.Group lruCache *cache.LruCache[string, *D.Msg] - policy *trie.DomainTrie[*Policy] - domainSetPolicy []domainSetPolicyRecord - geositePolicy []geositePolicyRecord + policy []dnsPolicy proxyServer []dnsClient } @@ -258,22 +246,9 @@ func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient { return nil } - record := r.policy.Search(domain) - if record != nil { - p := record.Data() - return p.GetData() - } - - for _, geositeRecord := range r.geositePolicy { - matched := geositeRecord.matcher.Match(domain) - if matched != geositeRecord.inversedMatching { - return geositeRecord.policy.GetData() - } - } - metadata := &C.Metadata{Host: domain} - for _, domainSetRecord := range r.domainSetPolicy { - if ok := domainSetRecord.domainSetProvider.Match(metadata); ok { - return domainSetRecord.policy.GetData() + for _, policy := range r.policy { + if dnsClients := policy.Match(domain); len(dnsClients) > 0 { + return dnsClients } } return nil @@ -404,18 +379,17 @@ type FallbackFilter struct { } type Config struct { - Main, Fallback []NameServer - Default []NameServer - ProxyServer []NameServer - IPv6 bool - IPv6Timeout uint - EnhancedMode C.DNSMode - FallbackFilter FallbackFilter - Pool *fakeip.Pool - Hosts *trie.DomainTrie[resolver.HostValue] - Policy map[string][]NameServer - DomainSetPolicy map[provider.RuleProvider][]NameServer - GeositePolicy map[router.DomainMatcher][]NameServer + Main, Fallback []NameServer + Default []NameServer + ProxyServer []NameServer + IPv6 bool + IPv6Timeout uint + EnhancedMode C.DNSMode + FallbackFilter FallbackFilter + Pool *fakeip.Pool + Hosts *trie.DomainTrie[resolver.HostValue] + Policy utils.StringMapSlice[[]NameServer] + RuleProviders map[string]provider.RuleProvider } func NewResolver(config Config) *Resolver { @@ -442,38 +416,59 @@ func NewResolver(config Config) *Resolver { } if len(config.Policy) != 0 { - r.policy = trie.New[*Policy]() - for domain, nameserver := range config.Policy { - if strings.HasPrefix(strings.ToLower(domain), "geosite:") { - groupname := domain[8:] - inverse := false - if strings.HasPrefix(groupname, "!") { - inverse = true - groupname = groupname[1:] - } - log.Debugln("adding geosite policy: %s inversed %t", groupname, inverse) - matcher, err := NewGeoSite(groupname) - if err != nil { - continue - } - r.geositePolicy = append(r.geositePolicy, geositePolicyRecord{ - matcher: matcher, - policy: NewPolicy(transform(nameserver, defaultResolver)), - inversedMatching: inverse, - }) - } else { - _ = r.policy.Insert(domain, NewPolicy(transform(nameserver, defaultResolver))) + r.policy = make([]dnsPolicy, 0) + + var triePolicy *trie.DomainTrie[[]dnsClient] + insertTriePolicy := func() { + if triePolicy != nil { + triePolicy.Optimize() + r.policy = append(r.policy, domainTriePolicy{triePolicy}) + triePolicy = nil } } - r.policy.Optimize() - } - if len(config.DomainSetPolicy) > 0 { - for p, n := range config.DomainSetPolicy { - r.domainSetPolicy = append(r.domainSetPolicy, domainSetPolicyRecord{ - domainSetProvider: p, - policy: NewPolicy(transform(n, defaultResolver)), - }) + for _, p := range config.Policy { + domain, nameserver := p.Extract() + domain = strings.ToLower(domain) + + if temp := strings.Split(domain, ":"); len(temp) == 2 { + prefix := temp[0] + key := temp[1] + switch strings.ToLower(prefix) { + case "rule-set": + if p, ok := config.RuleProviders[key]; ok { + insertTriePolicy() + r.policy = append(r.policy, domainSetPolicy{ + domainSetProvider: p, + dnsClients: transform(nameserver, defaultResolver), + }) + continue + } + case "geosite": + inverse := false + if strings.HasPrefix(key, "!") { + inverse = true + key = key[1:] + } + log.Debugln("adding geosite policy: %s inversed %t", key, inverse) + matcher, err := NewGeoSite(key) + if err != nil { + continue + } + insertTriePolicy() + r.policy = append(r.policy, geositePolicy{ + matcher: matcher, + inverse: inverse, + dnsClients: transform(nameserver, defaultResolver), + }) + continue + } + } + if triePolicy == nil { + triePolicy = trie.New[[]dnsClient]() + } + _ = triePolicy.Insert(domain, transform(nameserver, defaultResolver)) } + insertTriePolicy() } fallbackIPFilters := []fallbackIPFilter{} @@ -508,7 +503,6 @@ func NewProxyServerHostResolver(old *Resolver) *Resolver { main: old.proxyServer, lruCache: old.lruCache, hosts: old.hosts, - policy: trie.New[*Policy](), ipv6Timeout: old.ipv6Timeout, } return r diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 6ea02989..f1c108cf 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -7,7 +7,6 @@ import ( "os" "runtime" "strconv" - "strings" "sync" "time" @@ -208,25 +207,6 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen dns.ReCreateServer("", nil, nil) return } - policy := make(map[string][]dns.NameServer) - domainSetPolicies := make(map[provider.RuleProvider][]dns.NameServer) - for key, nameservers := range c.NameServerPolicy { - temp := strings.Split(key, ":") - if len(temp) == 2 { - prefix := temp[0] - key := temp[1] - switch strings.ToLower(prefix) { - case "rule-set": - if p, ok := ruleProvider[key]; ok { - domainSetPolicies[p] = nameservers - } - case "geosite": - // TODO: - } - } else { - policy[key] = nameservers - } - } cfg := dns.Config{ Main: c.NameServer, Fallback: c.Fallback, @@ -242,10 +222,10 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen Domain: c.FallbackFilter.Domain, GeoSite: c.FallbackFilter.GeoSite, }, - Default: c.DefaultNameserver, - Policy: c.NameServerPolicy, - ProxyServer: c.ProxyServerNameserver, - DomainSetPolicy: domainSetPolicies, + Default: c.DefaultNameserver, + Policy: c.NameServerPolicy, + ProxyServer: c.ProxyServerNameserver, + RuleProviders: ruleProvider, } r := dns.NewResolver(cfg) From f260d8cf01b5b2a1512ad230b2b4c2ad2b22f35d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 8 Nov 2023 20:19:48 +0800 Subject: [PATCH 083/192] chore: share dnsClient in NewResolver --- dns/resolver.go | 58 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/dns/resolver.go b/dns/resolver.go index 7e45252e..38c5d375 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -19,6 +19,7 @@ import ( D "github.com/miekg/dns" "github.com/samber/lo" + "golang.org/x/exp/maps" "golang.org/x/sync/singleflight" ) @@ -370,6 +371,23 @@ type NameServer struct { PreferH3 bool } +func (ns NameServer) Equal(ns2 NameServer) bool { + defer func() { + // C.ProxyAdapter compare maybe panic, just ignore + recover() + }() + if ns.Net == ns2.Net && + ns.Addr == ns2.Addr && + ns.Interface == ns2.Interface && + ns.ProxyAdapter == ns2.ProxyAdapter && + ns.ProxyName == ns2.ProxyName && + maps.Equal(ns.Params, ns2.Params) && + ns.PreferH3 == ns2.PreferH3 { + return true + } + return false +} + type FallbackFilter struct { GeoIP bool GeoIPCode string @@ -399,20 +417,47 @@ func NewResolver(config Config) *Resolver { ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond, } + var nameServerCache []struct { + NameServer + dnsClient + } + cacheTransform := func(nameserver []NameServer) (result []dnsClient) { + LOOP: + for _, ns := range nameserver { + for _, nsc := range nameServerCache { + if nsc.NameServer.Equal(ns) { + result = append(result, nsc.dnsClient) + continue LOOP + } + } + // not in cache + dc := transform([]NameServer{ns}, defaultResolver) + if len(dc) > 0 { + dc := dc[0] + nameServerCache = append(nameServerCache, struct { + NameServer + dnsClient + }{NameServer: ns, dnsClient: dc}) + result = append(result, dc) + } + } + return + } + r := &Resolver{ ipv6: config.IPv6, - main: transform(config.Main, defaultResolver), + main: cacheTransform(config.Main), lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), hosts: config.Hosts, ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond, } if len(config.Fallback) != 0 { - r.fallback = transform(config.Fallback, defaultResolver) + r.fallback = cacheTransform(config.Fallback) } if len(config.ProxyServer) != 0 { - r.proxyServer = transform(config.ProxyServer, defaultResolver) + r.proxyServer = cacheTransform(config.ProxyServer) } if len(config.Policy) != 0 { @@ -426,6 +471,7 @@ func NewResolver(config Config) *Resolver { triePolicy = nil } } + for _, p := range config.Policy { domain, nameserver := p.Extract() domain = strings.ToLower(domain) @@ -439,7 +485,7 @@ func NewResolver(config Config) *Resolver { insertTriePolicy() r.policy = append(r.policy, domainSetPolicy{ domainSetProvider: p, - dnsClients: transform(nameserver, defaultResolver), + dnsClients: cacheTransform(nameserver), }) continue } @@ -458,7 +504,7 @@ func NewResolver(config Config) *Resolver { r.policy = append(r.policy, geositePolicy{ matcher: matcher, inverse: inverse, - dnsClients: transform(nameserver, defaultResolver), + dnsClients: cacheTransform(nameserver), }) continue } @@ -466,7 +512,7 @@ func NewResolver(config Config) *Resolver { if triePolicy == nil { triePolicy = trie.New[[]dnsClient]() } - _ = triePolicy.Insert(domain, transform(nameserver, defaultResolver)) + _ = triePolicy.Insert(domain, cacheTransform(nameserver)) } insertTriePolicy() } From 6901afb4064e58ed134fe0d88ea2bb9453b842e2 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:15:29 +0800 Subject: [PATCH 084/192] ci: fix android build --- .github/workflows/build.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a644f97a..7dff1e6c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,9 +161,8 @@ jobs: if: ${{ matrix.job.type=='WithCGO' && matrix.job.target=='android' }} id: setup-ndk with: - ndk-version: r26 - add-to-path: false - local-cache: true + ndk-version: r26b + add-to-path: true - name: Build Android if: ${{ matrix.job.type=='WithCGO' && matrix.job.target=='android' }} From e8e4288d8535cd47039ef45b139a2dbca7f254a5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 8 Nov 2023 23:05:27 +0800 Subject: [PATCH 085/192] action: test_author.yml --- .github/workflows/test_author.yml | 38 +++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/test_author.yml diff --git a/.github/workflows/test_author.yml b/.github/workflows/test_author.yml new file mode 100644 index 00000000..1a13612e --- /dev/null +++ b/.github/workflows/test_author.yml @@ -0,0 +1,38 @@ +name: Test Change Author Name +on: + workflow_dispatch: + push: + branches: + - Alpha + pull_request_target: + branches: + - Alpha + +jobs: + update-dependencies: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config --global user.name 'gVisor bot' + git config --global user.email 'gvisor-bot@google.com' + + - name: Change Author Name + run: | + git fetch origin + git checkout origin/Alpha -b test-author + git filter-branch -f --env-filter " + GIT_AUTHOR_NAME='gVisor bot' + GIT_AUTHOR_EMAIL='gvisor-bot@google.com' + GIT_COMMITTER_NAME='gVisor bot' + GIT_COMMITTER_EMAIL='gvisor-bot@google.com' + " HEAD + + - name: Push changes + run: | + git push origin test-author --force \ No newline at end of file From fe7c1a2cdb46a4434581d2b4b5186c3a96aa34e5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 9 Nov 2023 08:47:44 +0800 Subject: [PATCH 086/192] chore: using wk8/go-ordered-map/v2 replace internal StringMapSlice --- common/cache/lrucache.go | 3 +- common/generics/list/list.go | 235 ------------------ common/{util => utils}/manipulation.go | 2 +- common/utils/ordered_map.go | 40 --- .../strmatcher/ac_automaton_matcher.go | 2 +- config/config.go | 57 ++--- dns/resolver.go | 10 +- go.mod | 4 + go.sum | 9 + transport/tuic/pool_client.go | 3 +- transport/vmess/http.go | 4 +- 11 files changed, 54 insertions(+), 315 deletions(-) delete mode 100644 common/generics/list/list.go rename common/{util => utils}/manipulation.go (89%) delete mode 100644 common/utils/ordered_map.go diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go index d71cc3b9..9f19787a 100644 --- a/common/cache/lrucache.go +++ b/common/cache/lrucache.go @@ -6,8 +6,7 @@ import ( "sync" "time" - "github.com/metacubex/mihomo/common/generics/list" - + list "github.com/bahlo/generic-list-go" "github.com/samber/lo" ) diff --git a/common/generics/list/list.go b/common/generics/list/list.go deleted file mode 100644 index 04d84180..00000000 --- a/common/generics/list/list.go +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package list implements a doubly linked list. -// -// To iterate over a list (where l is a *List): -// -// for e := l.Front(); e != nil; e = e.Next() { -// // do something with e.Value -// } -package list - -// Element is an element of a linked list. -type Element[T any] struct { - // Next and previous pointers in the doubly-linked list of elements. - // To simplify the implementation, internally a list l is implemented - // as a ring, such that &l.root is both the next element of the last - // list element (l.Back()) and the previous element of the first list - // element (l.Front()). - next, prev *Element[T] - - // The list to which this element belongs. - list *List[T] - - // The value stored with this element. - Value T -} - -// Next returns the next list element or nil. -func (e *Element[T]) Next() *Element[T] { - if p := e.next; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// Prev returns the previous list element or nil. -func (e *Element[T]) Prev() *Element[T] { - if p := e.prev; e.list != nil && p != &e.list.root { - return p - } - return nil -} - -// List represents a doubly linked list. -// The zero value for List is an empty list ready to use. -type List[T any] struct { - root Element[T] // sentinel list element, only &root, root.prev, and root.next are used - len int // current list length excluding (this) sentinel element -} - -// Init initializes or clears list l. -func (l *List[T]) Init() *List[T] { - l.root.next = &l.root - l.root.prev = &l.root - l.len = 0 - return l -} - -// New returns an initialized list. -func New[T any]() *List[T] { return new(List[T]).Init() } - -// Len returns the number of elements of list l. -// The complexity is O(1). -func (l *List[T]) Len() int { return l.len } - -// Front returns the first element of list l or nil if the list is empty. -func (l *List[T]) Front() *Element[T] { - if l.len == 0 { - return nil - } - return l.root.next -} - -// Back returns the last element of list l or nil if the list is empty. -func (l *List[T]) Back() *Element[T] { - if l.len == 0 { - return nil - } - return l.root.prev -} - -// lazyInit lazily initializes a zero List value. -func (l *List[T]) lazyInit() { - if l.root.next == nil { - l.Init() - } -} - -// insert inserts e after at, increments l.len, and returns e. -func (l *List[T]) insert(e, at *Element[T]) *Element[T] { - e.prev = at - e.next = at.next - e.prev.next = e - e.next.prev = e - e.list = l - l.len++ - return e -} - -// insertValue is a convenience wrapper for insert(&Element{Value: v}, at). -func (l *List[T]) insertValue(v T, at *Element[T]) *Element[T] { - return l.insert(&Element[T]{Value: v}, at) -} - -// remove removes e from its list, decrements l.len -func (l *List[T]) remove(e *Element[T]) { - e.prev.next = e.next - e.next.prev = e.prev - e.next = nil // avoid memory leaks - e.prev = nil // avoid memory leaks - e.list = nil - l.len-- -} - -// move moves e to next to at. -func (l *List[T]) move(e, at *Element[T]) { - if e == at { - return - } - e.prev.next = e.next - e.next.prev = e.prev - - e.prev = at - e.next = at.next - e.prev.next = e - e.next.prev = e -} - -// Remove removes e from l if e is an element of list l. -// It returns the element value e.Value. -// The element must not be nil. -func (l *List[T]) Remove(e *Element[T]) T { - if e.list == l { - // if e.list == l, l must have been initialized when e was inserted - // in l or l == nil (e is a zero Element) and l.remove will crash - l.remove(e) - } - return e.Value -} - -// PushFront inserts a new element e with value v at the front of list l and returns e. -func (l *List[T]) PushFront(v T) *Element[T] { - l.lazyInit() - return l.insertValue(v, &l.root) -} - -// PushBack inserts a new element e with value v at the back of list l and returns e. -func (l *List[T]) PushBack(v T) *Element[T] { - l.lazyInit() - return l.insertValue(v, l.root.prev) -} - -// InsertBefore inserts a new element e with value v immediately before mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *List[T]) InsertBefore(v T, mark *Element[T]) *Element[T] { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark.prev) -} - -// InsertAfter inserts a new element e with value v immediately after mark and returns e. -// If mark is not an element of l, the list is not modified. -// The mark must not be nil. -func (l *List[T]) InsertAfter(v T, mark *Element[T]) *Element[T] { - if mark.list != l { - return nil - } - // see comment in List.Remove about initialization of l - return l.insertValue(v, mark) -} - -// MoveToFront moves element e to the front of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *List[T]) MoveToFront(e *Element[T]) { - if e.list != l || l.root.next == e { - return - } - // see comment in List.Remove about initialization of l - l.move(e, &l.root) -} - -// MoveToBack moves element e to the back of list l. -// If e is not an element of l, the list is not modified. -// The element must not be nil. -func (l *List[T]) MoveToBack(e *Element[T]) { - if e.list != l || l.root.prev == e { - return - } - // see comment in List.Remove about initialization of l - l.move(e, l.root.prev) -} - -// MoveBefore moves element e to its new position before mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *List[T]) MoveBefore(e, mark *Element[T]) { - if e.list != l || e == mark || mark.list != l { - return - } - l.move(e, mark.prev) -} - -// MoveAfter moves element e to its new position after mark. -// If e or mark is not an element of l, or e == mark, the list is not modified. -// The element and mark must not be nil. -func (l *List[T]) MoveAfter(e, mark *Element[T]) { - if e.list != l || e == mark || mark.list != l { - return - } - l.move(e, mark) -} - -// PushBackList inserts a copy of another list at the back of list l. -// The lists l and other may be the same. They must not be nil. -func (l *List[T]) PushBackList(other *List[T]) { - l.lazyInit() - for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { - l.insertValue(e.Value, l.root.prev) - } -} - -// PushFrontList inserts a copy of another list at the front of list l. -// The lists l and other may be the same. They must not be nil. -func (l *List[T]) PushFrontList(other *List[T]) { - l.lazyInit() - for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { - l.insertValue(e.Value, &l.root) - } -} diff --git a/common/util/manipulation.go b/common/utils/manipulation.go similarity index 89% rename from common/util/manipulation.go rename to common/utils/manipulation.go index d2c861eb..6c98a729 100644 --- a/common/util/manipulation.go +++ b/common/utils/manipulation.go @@ -1,4 +1,4 @@ -package util +package utils import "github.com/samber/lo" diff --git a/common/utils/ordered_map.go b/common/utils/ordered_map.go deleted file mode 100644 index 9ffc70c2..00000000 --- a/common/utils/ordered_map.go +++ /dev/null @@ -1,40 +0,0 @@ -package utils - -// modify from https://github.com/go-yaml/yaml/issues/698#issuecomment-1482026841 - -import ( - "errors" - "gopkg.in/yaml.v3" -) - -type StringMapSlice[V any] []StringMapSliceItem[V] - -type StringMapSliceItem[V any] struct { - Key string - Value V -} - -func (s *StringMapSlice[V]) UnmarshalYAML(value *yaml.Node) error { - for i := 0; i < len(value.Content); i += 2 { - if i+1 >= len(value.Content) { - return errors.New("not a dict") - } - item := StringMapSliceItem[V]{} - item.Key = value.Content[i].Value - if err := value.Content[i+1].Decode(&item.Value); err != nil { - return err - } - - *s = append(*s, item) - } - - return nil -} - -func (s *StringMapSlice[V]) Add(key string, value V) { - *s = append(*s, StringMapSliceItem[V]{Key: key, Value: value}) -} - -func (i *StringMapSliceItem[V]) Extract() (key string, value V) { - return i.Key, i.Value -} diff --git a/component/geodata/strmatcher/ac_automaton_matcher.go b/component/geodata/strmatcher/ac_automaton_matcher.go index ca7dc48b..a21a83a2 100644 --- a/component/geodata/strmatcher/ac_automaton_matcher.go +++ b/component/geodata/strmatcher/ac_automaton_matcher.go @@ -1,7 +1,7 @@ package strmatcher import ( - "github.com/metacubex/mihomo/common/generics/list" + list "github.com/bahlo/generic-list-go" ) const validCharCount = 53 diff --git a/config/config.go b/config/config.go index 7ef395b3..11db26c8 100644 --- a/config/config.go +++ b/config/config.go @@ -39,6 +39,7 @@ import ( RP "github.com/metacubex/mihomo/rules/provider" T "github.com/metacubex/mihomo/tunnel" + orderedmap "github.com/wk8/go-ordered-map/v2" "gopkg.in/yaml.v3" ) @@ -114,7 +115,7 @@ type DNS struct { DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` FakeIPRange *fakeip.Pool Hosts *trie.DomainTrie[resolver.HostValue] - NameServerPolicy utils.StringMapSlice[[]dns.NameServer] + NameServerPolicy *orderedmap.OrderedMap[string, []dns.NameServer] ProxyServerNameserver []dns.NameServer } @@ -193,21 +194,21 @@ type RawNTP struct { } type RawDNS struct { - Enable bool `yaml:"enable"` - PreferH3 bool `yaml:"prefer-h3"` - IPv6 bool `yaml:"ipv6"` - IPv6Timeout uint `yaml:"ipv6-timeout"` - UseHosts bool `yaml:"use-hosts"` - NameServer []string `yaml:"nameserver"` - Fallback []string `yaml:"fallback"` - FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` - Listen string `yaml:"listen"` - EnhancedMode C.DNSMode `yaml:"enhanced-mode"` - FakeIPRange string `yaml:"fake-ip-range"` - FakeIPFilter []string `yaml:"fake-ip-filter"` - DefaultNameserver []string `yaml:"default-nameserver"` - NameServerPolicy utils.StringMapSlice[any] `yaml:"nameserver-policy"` - ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` + Enable bool `yaml:"enable"` + PreferH3 bool `yaml:"prefer-h3"` + IPv6 bool `yaml:"ipv6"` + IPv6Timeout uint `yaml:"ipv6-timeout"` + UseHosts bool `yaml:"use-hosts"` + NameServer []string `yaml:"nameserver"` + Fallback []string `yaml:"fallback"` + FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` + Listen string `yaml:"listen"` + EnhancedMode C.DNSMode `yaml:"enhanced-mode"` + FakeIPRange string `yaml:"fake-ip-range"` + FakeIPFilter []string `yaml:"fake-ip-filter"` + DefaultNameserver []string `yaml:"default-nameserver"` + NameServerPolicy *orderedmap.OrderedMap[string, any] `yaml:"nameserver-policy"` + ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` } type RawFallbackFilter struct { @@ -1085,13 +1086,13 @@ func parsePureDNSServer(server string) string { } } } -func parseNameServerPolicy(nsPolicy utils.StringMapSlice[any], ruleProviders map[string]providerTypes.RuleProvider, preferH3 bool) (utils.StringMapSlice[[]dns.NameServer], error) { - policy := utils.StringMapSlice[[]dns.NameServer]{} - updatedPolicy := utils.StringMapSlice[any]{} +func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], ruleProviders map[string]providerTypes.RuleProvider, preferH3 bool) (*orderedmap.OrderedMap[string, []dns.NameServer], error) { + policy := orderedmap.New[string, []dns.NameServer]() + updatedPolicy := orderedmap.New[string, any]() re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`) - for _, p := range nsPolicy { - k, v := p.Extract() + for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() { + k, v := pair.Key, pair.Value if strings.Contains(k, ",") { if strings.Contains(k, "geosite:") { subkeys := strings.Split(k, ":") @@ -1099,7 +1100,7 @@ func parseNameServerPolicy(nsPolicy utils.StringMapSlice[any], ruleProviders map subkeys = strings.Split(subkeys[0], ",") for _, subkey := range subkeys { newKey := "geosite:" + subkey - updatedPolicy.Add(newKey, v) + updatedPolicy.Store(newKey, v) } } else if strings.Contains(k, "rule-set:") { subkeys := strings.Split(k, ":") @@ -1107,21 +1108,21 @@ func parseNameServerPolicy(nsPolicy utils.StringMapSlice[any], ruleProviders map subkeys = strings.Split(subkeys[0], ",") for _, subkey := range subkeys { newKey := "rule-set:" + subkey - updatedPolicy.Add(newKey, v) + updatedPolicy.Store(newKey, v) } } else if re.MatchString(k) { subkeys := strings.Split(k, ",") for _, subkey := range subkeys { - updatedPolicy.Add(subkey, v) + updatedPolicy.Store(subkey, v) } } } else { - updatedPolicy.Add(k, v) + updatedPolicy.Store(k, v) } } - for _, p := range updatedPolicy { - domain, server := p.Extract() + for pair := updatedPolicy.Oldest(); pair != nil; pair = pair.Next() { + domain, server := pair.Key, pair.Value servers, err := utils.ToStringSlice(server) if err != nil { return nil, err @@ -1146,7 +1147,7 @@ func parseNameServerPolicy(nsPolicy utils.StringMapSlice[any], ruleProviders map } } } - policy.Add(domain, nameservers) + policy.Store(domain, nameservers) } return policy, nil diff --git a/dns/resolver.go b/dns/resolver.go index 38c5d375..368f0b41 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -8,7 +8,6 @@ import ( "time" "github.com/metacubex/mihomo/common/cache" - "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/fakeip" "github.com/metacubex/mihomo/component/geodata/router" "github.com/metacubex/mihomo/component/resolver" @@ -19,6 +18,7 @@ import ( D "github.com/miekg/dns" "github.com/samber/lo" + orderedmap "github.com/wk8/go-ordered-map/v2" "golang.org/x/exp/maps" "golang.org/x/sync/singleflight" ) @@ -406,7 +406,7 @@ type Config struct { FallbackFilter FallbackFilter Pool *fakeip.Pool Hosts *trie.DomainTrie[resolver.HostValue] - Policy utils.StringMapSlice[[]NameServer] + Policy *orderedmap.OrderedMap[string, []NameServer] RuleProviders map[string]provider.RuleProvider } @@ -460,7 +460,7 @@ func NewResolver(config Config) *Resolver { r.proxyServer = cacheTransform(config.ProxyServer) } - if len(config.Policy) != 0 { + if config.Policy.Len() != 0 { r.policy = make([]dnsPolicy, 0) var triePolicy *trie.DomainTrie[[]dnsClient] @@ -472,8 +472,8 @@ func NewResolver(config Config) *Resolver { } } - for _, p := range config.Policy { - domain, nameserver := p.Extract() + for pair := config.Policy.Oldest(); pair != nil; pair = pair.Next() { + domain, nameserver := pair.Key, pair.Value domain = strings.ToLower(domain) if temp := strings.Split(domain, ":"); len(temp) == 2 { diff --git a/go.mod b/go.mod index da45cd28..f7ba243a 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/3andne/restls-client-go v0.1.6 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da + github.com/bahlo/generic-list-go v0.2.0 github.com/cilium/ebpf v0.12.0 github.com/coreos/go-iptables v0.7.0 github.com/dlclark/regexp2 v1.10.0 @@ -42,6 +43,7 @@ require ( github.com/shirou/gopsutil/v3 v3.23.9 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 + github.com/wk8/go-ordered-map/v2 v2.1.8 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.3 @@ -60,6 +62,7 @@ require ( github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect @@ -78,6 +81,7 @@ require ( github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect diff --git a/go.sum b/go.sum index 6a6356c1..f1cbc511 100644 --- a/go.sum +++ b/go.sum @@ -10,7 +10,11 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -74,6 +78,7 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -89,6 +94,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= @@ -199,6 +206,8 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= diff --git a/transport/tuic/pool_client.go b/transport/tuic/pool_client.go index e492fba7..b4c319d8 100644 --- a/transport/tuic/pool_client.go +++ b/transport/tuic/pool_client.go @@ -8,12 +8,13 @@ import ( "sync" "time" - "github.com/metacubex/mihomo/common/generics/list" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" + + list "github.com/bahlo/generic-list-go" ) type dialResult struct { diff --git a/transport/vmess/http.go b/transport/vmess/http.go index 782e7eb2..c77a7e9d 100644 --- a/transport/vmess/http.go +++ b/transport/vmess/http.go @@ -8,7 +8,7 @@ import ( "net/http" "net/textproto" - "github.com/metacubex/mihomo/common/util" + "github.com/metacubex/mihomo/common/utils" "github.com/zhangyunhao116/fastrand" ) @@ -61,7 +61,7 @@ func (hc *httpConn) Write(b []byte) (int, error) { } u := fmt.Sprintf("http://%s%s", host, path) - req, _ := http.NewRequest(util.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b)) + req, _ := http.NewRequest(utils.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b)) for key, list := range hc.cfg.Headers { req.Header.Set(key, list[fastrand.Intn(len(list))]) } From 832dae34219ec7f9775648754e94d4cd35eb98fa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 9 Nov 2023 22:19:29 +0800 Subject: [PATCH 087/192] chore: direct append data to bufio.Reader's internal buffer as much as possible --- common/net/bufconn.go | 2 +- common/net/bufconn_unsafe.go | 34 ++++++++++++++++++++++++++++++++++ transport/vmess/websocket.go | 9 ++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 common/net/bufconn_unsafe.go diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 37c8ba25..b7e98e04 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -84,9 +84,9 @@ func (c *BufferedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.C length := c.r.Buffered() b, _ := c.r.Peek(length) _, _ = c.r.Discard(length) - c.r = nil // drop bufio.Reader to let gc can clean up its internal buf return buf.As(b) } + c.r = nil // drop bufio.Reader to let gc can clean up its internal buf return nil } diff --git a/common/net/bufconn_unsafe.go b/common/net/bufconn_unsafe.go new file mode 100644 index 00000000..349321df --- /dev/null +++ b/common/net/bufconn_unsafe.go @@ -0,0 +1,34 @@ +package net + +import ( + "io" + "unsafe" +) + +// bufioReader copy from stdlib bufio/bufio.go +// This structure has remained unchanged from go1.5 to go1.21. +type bufioReader struct { + buf []byte + rd io.Reader // reader provided by the client + r, w int // buf read and write positions + err error + lastByte int // last byte read for UnreadByte; -1 means invalid + lastRuneSize int // size of last rune read for UnreadRune; -1 means invalid +} + +func (c *BufferedConn) AppendData(buf []byte) (ok bool) { + b := (*bufioReader)(unsafe.Pointer(c.r)) + pos := len(b.buf) - b.w - len(buf) + if pos >= -b.r { // len(b.buf)-(b.w - b.r) >= len(buf) + if pos < 0 { // len(b.buf)-b.w < len(buf) + // Slide existing data to beginning. + copy(b.buf, b.buf[b.r:b.w]) + b.w -= b.r + b.r = 0 + } + + b.w += copy(b.buf[b.w:], buf) + return true + } + return false +} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index b30bb8aa..8e675bb0 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -554,7 +554,14 @@ func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Co } if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 { - conn = N.NewCachedConn(conn, edBuf) + appendOk := false + if bufConn, ok := conn.(*N.BufferedConn); ok { + appendOk = bufConn.AppendData(edBuf) + } + if !appendOk { + conn = N.NewCachedConn(conn, edBuf) + } + } return conn, nil From 288c0c27d65b8d30c525c56cac4e507beee7b090 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sat, 11 Nov 2023 22:15:57 +0800 Subject: [PATCH 088/192] feat: add `include-all-providers` to proxy-groups --- adapter/outboundgroup/parser.go | 42 +++++++++++++++++++++------------ adapter/provider/provider.go | 3 +++ 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 8f3335d8..806732cf 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -22,18 +22,19 @@ var ( type GroupCommonOption struct { outbound.BasicOption - Name string `group:"name"` - Type string `group:"type"` - Proxies []string `group:"proxies,omitempty"` - Use []string `group:"use,omitempty"` - URL string `group:"url,omitempty"` - Interval int `group:"interval,omitempty"` - Lazy bool `group:"lazy,omitempty"` - DisableUDP bool `group:"disable-udp,omitempty"` - Filter string `group:"filter,omitempty"` - ExcludeFilter string `group:"exclude-filter,omitempty"` - ExcludeType string `group:"exclude-type,omitempty"` - ExpectedStatus string `group:"expected-status,omitempty"` + Name string `group:"name"` + Type string `group:"type"` + Proxies []string `group:"proxies,omitempty"` + Use []string `group:"use,omitempty"` + URL string `group:"url,omitempty"` + Interval int `group:"interval,omitempty"` + Lazy bool `group:"lazy,omitempty"` + DisableUDP bool `group:"disable-udp,omitempty"` + Filter string `group:"filter,omitempty"` + ExcludeFilter string `group:"exclude-filter,omitempty"` + ExcludeType string `group:"exclude-type,omitempty"` + ExpectedStatus string `group:"expected-status,omitempty"` + IncludeAllProviders bool `group:"include-all-providers,omitempty"` } func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) { @@ -54,7 +55,18 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide providers := []types.ProxyProvider{} - if len(groupOption.Proxies) == 0 && len(groupOption.Use) == 0 { + var GroupUse []string + visited := make(map[string]bool) + if groupOption.IncludeAllProviders { + for name := range provider.ProxyProviderName { + GroupUse = append(GroupUse, name) + visited[name] = true + } + } else { + GroupUse = groupOption.Use + } + + if len(groupOption.Proxies) == 0 && len(GroupUse) == 0 { return nil, fmt.Errorf("%s: %w", groupName, errMissProxy) } @@ -107,8 +119,8 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide providersMap[groupName] = pd } - if len(groupOption.Use) != 0 { - list, err := getProviders(providersMap, groupOption.Use) + if len(GroupUse) != 0 { + list, err := getProviders(providersMap, GroupUse) if err != nil { return nil, fmt.Errorf("%s: %w", groupName, err) } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index ffaec91b..aa434a11 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -24,6 +24,8 @@ import ( "gopkg.in/yaml.v3" ) +var ProxyProviderName = make(map[string]struct{}) + const ( ReservedName = "default" ) @@ -193,6 +195,7 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy), proxiesOnUpdate(pd)) pd.Fetcher = fetcher + ProxyProviderName[name] = struct{}{} wrapper := &ProxySetProvider{pd} runtime.SetFinalizer(wrapper, stopProxyProvider) return wrapper, nil From daa332e7b0f5e2e060e6c136785378905f2dd9a5 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sun, 12 Nov 2023 02:44:55 +0800 Subject: [PATCH 089/192] chore: modify ua --- adapter/provider/provider.go | 2 +- component/geodata/init.go | 4 ++-- component/mmdb/mmdb.go | 2 +- config/utils.go | 3 ++- hub/updater/updater.go | 5 +++-- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index aa434a11..5c1b0f76 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -122,7 +122,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() resp, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), - http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) + http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) if err != nil { return } diff --git a/component/geodata/init.go b/component/geodata/init.go index 0b193c94..842efcc5 100644 --- a/component/geodata/init.go +++ b/component/geodata/init.go @@ -44,7 +44,7 @@ func InitGeoSite() error { func downloadGeoSite(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) if err != nil { return } @@ -63,7 +63,7 @@ func downloadGeoSite(path string) (err error) { func downloadGeoIP(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) if err != nil { return } diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go index f83b9922..d411b2b4 100644 --- a/component/mmdb/mmdb.go +++ b/component/mmdb/mmdb.go @@ -79,7 +79,7 @@ func Instance() Reader { func DownloadMMDB(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) if err != nil { return } diff --git a/config/utils.go b/config/utils.go index 5a4fecbf..66bf3441 100644 --- a/config/utils.go +++ b/config/utils.go @@ -14,12 +14,13 @@ import ( "github.com/metacubex/mihomo/adapter/outboundgroup" "github.com/metacubex/mihomo/common/structure" mihomoHttp "github.com/metacubex/mihomo/component/http" + C "github.com/metacubex/mihomo/constant" ) func downloadForBytes(url string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) if err != nil { return nil, err } diff --git a/hub/updater/updater.go b/hub/updater/updater.go index a3bc9a42..1967af42 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -17,6 +17,7 @@ import ( mihomoHttp "github.com/metacubex/mihomo/component/http" "github.com/metacubex/mihomo/constant" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" "github.com/klauspost/cpuid/v2" @@ -231,7 +232,7 @@ const MaxPackageFileSize = 32 * 1024 * 1024 func downloadPackageFile() (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) if err != nil { return fmt.Errorf("http request failed: %w", err) } @@ -412,7 +413,7 @@ func copyFile(src, dst string) error { func getLatestVersion() (version string, err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {C.UA}}, nil) if err != nil { return "", fmt.Errorf("get Latest Version fail: %w", err) } From 2577dd3af40d721ac25c4111cd17128051869638 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sun, 12 Nov 2023 03:17:37 +0800 Subject: [PATCH 090/192] chore: fix subscription_info --- adapter/provider/subscription_info.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/adapter/provider/subscription_info.go b/adapter/provider/subscription_info.go index 8b90601c..3a9e2d72 100644 --- a/adapter/provider/subscription_info.go +++ b/adapter/provider/subscription_info.go @@ -25,7 +25,11 @@ func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo, err error) { case "total": si.Total, err = strconv.ParseInt(value, 10, 64) case "expire": - si.Expire, err = strconv.ParseInt(value, 10, 64) + if value == "" { + si.Expire = 0 + } else { + si.Expire, err = strconv.ParseInt(value, 10, 64) + } } if err != nil { return From 7979eb654f7454c51c630fa9c80641eac6bbbe0a Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 13 Nov 2023 15:42:31 +0800 Subject: [PATCH 091/192] fix: health check at startup --- hub/executor/executor.go | 1 + 1 file changed, 1 insertion(+) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index f1c108cf..c752122d 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -310,6 +310,7 @@ func loadProxyProvider(proxyProviders map[string]provider.ProxyProvider) { go func() { defer func() { <-ch; wg.Done() }() loadProvider(proxyProvider) + go proxyProvider.HealthCheck() }() } From d85d8ac13f310bd87da31ff55eaef3382d5ff7b5 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 13 Nov 2023 08:06:51 +0000 Subject: [PATCH 092/192] fix: only force health check compatible providers --- hub/executor/executor.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index c752122d..e0b12039 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -310,7 +310,9 @@ func loadProxyProvider(proxyProviders map[string]provider.ProxyProvider) { go func() { defer func() { <-ch; wg.Done() }() loadProvider(proxyProvider) - go proxyProvider.HealthCheck() + if proxyProvider.VehicleType()==provider.Compatible{ + go proxyProvider.HealthCheck() + } }() } From 7d222b1b713156e2e4c408d9f5d882ecde07116d Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:42:25 +0800 Subject: [PATCH 093/192] fix: health check available for 'selector' if configured --- adapter/outboundgroup/parser.go | 9 ++------- hub/executor/executor.go | 5 ++--- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 806732cf..8607bea1 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -92,9 +92,6 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, fmt.Errorf("%s: %w", groupName, errDuplicateProvider) } - var url string - var interval uint - // select don't need health check if groupOption.Type != "select" && groupOption.Type != "relay" { if groupOption.URL == "" { @@ -104,12 +101,10 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide if groupOption.Interval == 0 { groupOption.Interval = 300 } - - url = groupOption.URL - interval = uint(groupOption.Interval) } - hc := provider.NewHealthCheck(ps, url, interval, true, expectedStatus) + hc := provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), true, expectedStatus) + pd, err := provider.NewCompatibleProvider(groupName, ps, hc) if err != nil { return nil, fmt.Errorf("%s: %w", groupName, err) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index e0b12039..efd9a076 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -10,8 +10,6 @@ import ( "sync" "time" - "github.com/metacubex/mihomo/ntp" - "github.com/metacubex/mihomo/adapter" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/adapter/outboundgroup" @@ -35,6 +33,7 @@ import ( "github.com/metacubex/mihomo/listener/inner" "github.com/metacubex/mihomo/listener/tproxy" "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/tunnel" ) @@ -310,7 +309,7 @@ func loadProxyProvider(proxyProviders map[string]provider.ProxyProvider) { go func() { defer func() { <-ch; wg.Done() }() loadProvider(proxyProvider) - if proxyProvider.VehicleType()==provider.Compatible{ + if proxyProvider.VehicleType() == provider.Compatible { go proxyProvider.HealthCheck() } }() From 2f203330e41acda7feded70f0dfc5585fc54b270 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 17 Nov 2023 00:37:54 +0800 Subject: [PATCH 094/192] feat: add `override` to proxy-providers Co-authored-by: xishang0128 --- adapter/provider/parser.go | 31 +++++++++++++++++++++---------- adapter/provider/provider.go | 25 ++++++++++++++++++++++--- component/resource/fetcher.go | 2 +- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 321380ed..966d33d6 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -25,16 +25,26 @@ type healthCheckSchema struct { ExpectedStatus string `provider:"expected-status,omitempty"` } +type OverrideSchema struct { + UDP *bool `proxy:"udp,omitempty"` + Up *string `proxy:"up,omitempty"` + Down *string `proxy:"down,omitempty"` + DialerProxy *string `provider:"dialer-proxy,omitempty"` + SkipCertVerify *bool `proxy:"skip-cert-verify,omitempty"` +} + type proxyProviderSchema struct { - Type string `provider:"type"` - Path string `provider:"path,omitempty"` - URL string `provider:"url,omitempty"` - Interval int `provider:"interval,omitempty"` - Filter string `provider:"filter,omitempty"` - ExcludeFilter string `provider:"exclude-filter,omitempty"` - ExcludeType string `provider:"exclude-type,omitempty"` - DialerProxy string `provider:"dialer-proxy,omitempty"` - HealthCheck healthCheckSchema `provider:"health-check,omitempty"` + Type string `provider:"type"` + Path string `provider:"path,omitempty"` + URL string `provider:"url,omitempty"` + Interval int `provider:"interval,omitempty"` + Filter string `provider:"filter,omitempty"` + ExcludeFilter string `provider:"exclude-filter,omitempty"` + ExcludeType string `provider:"exclude-type,omitempty"` + DialerProxy string `provider:"dialer-proxy,omitempty"` + + HealthCheck healthCheckSchema `provider:"health-check,omitempty"` + Override OverrideSchema `provider:"override,omitempty"` } func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvider, error) { @@ -85,6 +95,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide excludeFilter := schema.ExcludeFilter excludeType := schema.ExcludeType dialerProxy := schema.DialerProxy + override := schema.Override - return NewProxySetProvider(name, interval, filter, excludeFilter, excludeType, dialerProxy, vehicle, hc) + return NewProxySetProvider(name, interval, filter, excludeFilter, excludeType, dialerProxy, override, vehicle, hc) } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 5c1b0f76..cd8b0e90 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -165,7 +165,7 @@ func stopProxyProvider(pd *ProxySetProvider) { _ = pd.Fetcher.Destroy() } -func NewProxySetProvider(name string, interval time.Duration, filter string, excludeFilter string, excludeType string, dialerProxy string, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) { +func NewProxySetProvider(name string, interval time.Duration, filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) { excludeFilterReg, err := regexp2.Compile(excludeFilter, 0) if err != nil { return nil, fmt.Errorf("invalid excludeFilter regex: %w", err) @@ -193,7 +193,7 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc healthCheck: hc, } - fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy), proxiesOnUpdate(pd)) + fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy, override), proxiesOnUpdate(pd)) pd.Fetcher = fetcher ProxyProviderName[name] = struct{}{} wrapper := &ProxySetProvider{pd} @@ -295,7 +295,7 @@ func proxiesOnUpdate(pd *proxySetProvider) func([]C.Proxy) { } } -func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray []string, filterRegs []*regexp2.Regexp, excludeFilterReg *regexp2.Regexp, dialerProxy string) resource.Parser[[]C.Proxy] { +func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray []string, filterRegs []*regexp2.Regexp, excludeFilterReg *regexp2.Regexp, dialerProxy string, override OverrideSchema) resource.Parser[[]C.Proxy] { return func(buf []byte) ([]C.Proxy, error) { schema := &ProxySchema{} @@ -358,13 +358,32 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray if _, ok := proxiesSet[name]; ok { continue } + if len(dialerProxy) > 0 { mapping["dialer-proxy"] = dialerProxy } + + if override.UDP != nil { + mapping["udp"] = *override.UDP + } + if override.Up != nil { + mapping["up"] = *override.Up + } + if override.Down != nil { + mapping["down"] = *override.Down + } + if override.DialerProxy != nil { + mapping["dialer-proxy"] = *override.DialerProxy + } + if override.SkipCertVerify != nil { + mapping["skip-cert-verify"] = *override.SkipCertVerify + } + proxy, err := adapter.ParseProxy(mapping) if err != nil { return nil, fmt.Errorf("proxy %d error: %w", idx, err) } + proxiesSet[name] = struct{}{} proxies = append(proxies, proxy) } diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index 31dc5c08..3d749645 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -59,7 +59,7 @@ func (f *Fetcher[V]) Initial() (V, error) { f.UpdatedAt = &modTime isLocal = true if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) { - log.Warnln("[Provider] %s not updated for a long time, force refresh", f.Name()) + log.Warnln("[Provider] %s not updated for %s, force update", f.Name(), time.Now().Sub(modTime)) forceUpdate = true } } else { From d28c3b50e3421f5155c85003f8e75bc05d1369ab Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 9 Nov 2023 23:20:57 +0800 Subject: [PATCH 095/192] ci: push to ghcr.io instead --- .github/workflows/build.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7dff1e6c..34c80619 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ concurrency: cancel-in-progress: true env: - REGISTRY: docker.io + REGISTRY: ghcr.io jobs: Build: permissions: write-all @@ -342,24 +342,25 @@ jobs: id: meta uses: docker/metadata-action@v4 with: - images: ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_ACCOUNT }}/${{secrets.DOCKERHUB_REPO}} + images: ${{ env.REGISTRY }}/${{ github.repository }} + - name: Show files run: | ls . ls bin/ - - name: Log into registry - if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + + - name: login to ghcr.io + uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action - name: Build and push Docker image id: build-and-push - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile @@ -367,8 +368,7 @@ jobs: platforms: | linux/386 linux/amd64 - linux/arm64/v8 + linux/arm64 linux/arm/v7 - # linux/riscv64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} From 9e96d7084006b25b13369119d8cf650ccefd2002 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 01:19:20 +0800 Subject: [PATCH 096/192] feat: share more code from android branch --- adapter/inbound/http.go | 2 + adapter/inbound/packet.go | 2 + adapter/outboundgroup/patch_android.go | 64 ++++++++++++++++++++ adapter/provider/healthcheck.go | 6 ++ adapter/provider/patch_android.go | 36 ++++++++++++ component/dialer/patch_android.go | 39 +++++++++++++ component/mmdb/patch_android.go | 18 ++++++ component/process/patch_android.go | 16 +++++ config/config.go | 17 ++++-- constant/metadata.go | 3 + dns/dhcp.go | 2 + dns/patch_!android.go | 7 +++ dns/patch_android.go | 81 ++++++++++++++++++++++++++ dns/server.go | 2 + listener/http/patch_android.go | 9 +++ rules/provider/patch_android.go | 27 +++++++++ tunnel/statistic/patch_android.go | 7 +++ 17 files changed, 333 insertions(+), 5 deletions(-) create mode 100644 adapter/outboundgroup/patch_android.go create mode 100644 adapter/provider/patch_android.go create mode 100644 component/dialer/patch_android.go create mode 100644 component/mmdb/patch_android.go create mode 100644 component/process/patch_android.go create mode 100644 dns/patch_!android.go create mode 100644 dns/patch_android.go create mode 100644 listener/http/patch_android.go create mode 100644 rules/provider/patch_android.go create mode 100644 tunnel/statistic/patch_android.go diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 137e17d3..8f912fbe 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -12,6 +12,8 @@ func NewHTTP(target socks5.Addr, srcConn net.Conn, conn net.Conn, additions ...A metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP + metadata.RawSrcAddr = srcConn.RemoteAddr() + metadata.RawDstAddr = srcConn.LocalAddr() ApplyAdditions(metadata, WithSrcAddr(srcConn.RemoteAddr()), WithInAddr(conn.LocalAddr())) ApplyAdditions(metadata, additions...) return conn, metadata diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index 7e245f98..a10d402e 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -10,6 +10,8 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source + metadata.RawSrcAddr = packet.LocalAddr() + metadata.RawDstAddr = metadata.UDPAddr() ApplyAdditions(metadata, WithSrcAddr(packet.LocalAddr())) if p, ok := packet.(C.UDPPacketInAddr); ok { ApplyAdditions(metadata, WithInAddr(p.InAddr())) diff --git a/adapter/outboundgroup/patch_android.go b/adapter/outboundgroup/patch_android.go new file mode 100644 index 00000000..e219ca9f --- /dev/null +++ b/adapter/outboundgroup/patch_android.go @@ -0,0 +1,64 @@ +// +build android + +package outboundgroup + +import ( + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" +) + +type ProxyGroup interface { + C.ProxyAdapter + + Providers() []provider.ProxyProvider + Proxies() []C.Proxy + Now() string +} + +func (f *Fallback) Providers() []provider.ProxyProvider { + return f.providers +} + +func (lb *LoadBalance) Providers() []provider.ProxyProvider { + return lb.providers +} + +func (f *Fallback) Proxies() []C.Proxy { + return f.GetProxies(false) +} + +func (lb *LoadBalance) Proxies() []C.Proxy { + return lb.GetProxies(false) +} + +func (lb *LoadBalance) Now() string { + return "" +} + +func (r *Relay) Providers() []provider.ProxyProvider { + return r.providers +} + +func (r *Relay) Proxies() []C.Proxy { + return r.GetProxies(false) +} + +func (r *Relay) Now() string { + return "" +} + +func (s *Selector) Providers() []provider.ProxyProvider { + return s.providers +} + +func (s *Selector) Proxies() []C.Proxy { + return s.GetProxies(false) +} + +func (u *URLTest) Providers() []provider.ProxyProvider { + return u.providers +} + +func (u *URLTest) Proxies() []C.Proxy { + return u.GetProxies(false) +} diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index e7f021e1..6a7cd3ef 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -18,6 +18,7 @@ import ( const ( defaultURLTestTimeout = time.Second * 5 + defaultURLTestURL = "https://www.gstatic.com/generate_204" ) type HealthCheckOption struct { @@ -148,6 +149,10 @@ func (hc *HealthCheck) stop() { } func (hc *HealthCheck) check() { + if len(hc.proxies) == 0 { + return + } + _, _, _ = hc.singleDo.Do(func() (struct{}, error) { id := utils.NewUUIDV4().String() log.Debugln("Start New Health Checking {%s}", id) @@ -223,6 +228,7 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, exp if len(url) == 0 { interval = 0 expectedStatus = nil + url = defaultURLTestURL } return &HealthCheck{ diff --git a/adapter/provider/patch_android.go b/adapter/provider/patch_android.go new file mode 100644 index 00000000..eb0ca1f9 --- /dev/null +++ b/adapter/provider/patch_android.go @@ -0,0 +1,36 @@ +// +build android + +package provider + +import ( + "time" +) + +var ( + suspended bool +) + +type UpdatableProvider interface { + UpdatedAt() time.Time +} + +func (pp *proxySetProvider) UpdatedAt() time.Time { + return pp.Fetcher.UpdatedAt +} + +func (pp *proxySetProvider) Close() error { + pp.healthCheck.close() + pp.Fetcher.Destroy() + + return nil +} + +func (cp *compatibleProvider) Close() error { + cp.healthCheck.close() + + return nil +} + +func Suspend(s bool) { + suspended = s +} diff --git a/component/dialer/patch_android.go b/component/dialer/patch_android.go new file mode 100644 index 00000000..2fe39924 --- /dev/null +++ b/component/dialer/patch_android.go @@ -0,0 +1,39 @@ +// +build android + +package dialer + +import ( + "context" + "net" + "net/netip" + "syscall" +) + +type SocketControl func(network, address string, conn syscall.RawConn) error + +var DefaultSocketHook SocketControl + +func dialContextHooked(ctx context.Context, network string, destination netip.Addr, port string) (net.Conn, error) { + dialer := &net.Dialer{ + Control: DefaultSocketHook, + } + + conn, err := dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port)) + if err != nil { + return nil, err + } + + if t, ok := conn.(*net.TCPConn); ok { + t.SetKeepAlive(false) + } + + return conn, nil +} + +func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { + lc := &net.ListenConfig{ + Control: DefaultSocketHook, + } + + return lc.ListenPacket(ctx, network, address) +} diff --git a/component/mmdb/patch_android.go b/component/mmdb/patch_android.go new file mode 100644 index 00000000..23afbb90 --- /dev/null +++ b/component/mmdb/patch_android.go @@ -0,0 +1,18 @@ +// +build android + +package mmdb + +import "github.com/oschwald/maxminddb-golang" + +func InstallOverride(override *maxminddb.Reader) { + newReader := Reader{Reader: override} + switch override.Metadata.DatabaseType { + case "sing-geoip": + reader.databaseType = typeSing + case "Meta-geoip0": + reader.databaseType = typeMetaV0 + default: + reader.databaseType = typeMaxmind + } + reader = newReader +} diff --git a/component/process/patch_android.go b/component/process/patch_android.go new file mode 100644 index 00000000..ae68d7b2 --- /dev/null +++ b/component/process/patch_android.go @@ -0,0 +1,16 @@ +// +build android + +package process + +import "github.com/metacubex/mihomo/constant" + +type PackageNameResolver func(metadata *constant.Metadata) (string, error) + +var DefaultPackageNameResolver PackageNameResolver + +func FindPackageName(metadata *constant.Metadata) (string, error) { + if resolver := DefaultPackageNameResolver; resolver != nil { + return resolver(metadata) + } + return "", ErrPlatformNotSupport +} diff --git a/config/config.go b/config/config.go index 11db26c8..d808f702 100644 --- a/config/config.go +++ b/config/config.go @@ -212,11 +212,16 @@ type RawDNS struct { } type RawFallbackFilter struct { - GeoIP bool `yaml:"geoip"` - GeoIPCode string `yaml:"geoip-code"` - IPCIDR []string `yaml:"ipcidr"` - Domain []string `yaml:"domain"` - GeoSite []string `yaml:"geosite"` + GeoIP bool `yaml:"geoip" json:"geoip"` + GeoIPCode string `yaml:"geoip-code" json:"geoip-code"` + IPCIDR []string `yaml:"ipcidr" json:"ipcidr"` + Domain []string `yaml:"domain" json:"domain"` + GeoSite []string `yaml:"geosite" json:"geosite"` +} + +type RawClashForAndroid struct { + AppendSystemDNS bool `yaml:"append-system-dns" json:"append-system-dns"` + UiSubtitlePattern string `yaml:"ui-subtitle-pattern" json:"ui-subtitle-pattern"` } type RawTun struct { @@ -317,6 +322,8 @@ type RawConfig struct { SubRules map[string][]string `yaml:"sub-rules"` RawTLS TLS `yaml:"tls"` Listeners []map[string]any `yaml:"listeners"` + + ClashForAndroid RawClashForAndroid `yaml:"clash-for-android"` } type GeoXUrl struct { diff --git a/constant/metadata.go b/constant/metadata.go index 4b547a81..09a2f152 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -147,6 +147,9 @@ type Metadata struct { SpecialProxy string `json:"specialProxy"` SpecialRules string `json:"specialRules"` RemoteDst string `json:"remoteDestination"` + + RawSrcAddr net.Addr `json:"-"` + RawDstAddr net.Addr `json:"-"` // Only domain rule SniffHost string `json:"sniffHost"` } diff --git a/dns/dhcp.go b/dns/dhcp.go index dc1344f5..bd3143c6 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -1,3 +1,5 @@ +// +build !android + package dns import ( diff --git a/dns/patch_!android.go b/dns/patch_!android.go new file mode 100644 index 00000000..566d8fd5 --- /dev/null +++ b/dns/patch_!android.go @@ -0,0 +1,7 @@ +// +build !android + +package dns + +func UpdateIsolateHandler(resolver *Resolver, mapper *ResolverEnhancer) { + return +} \ No newline at end of file diff --git a/dns/patch_android.go b/dns/patch_android.go new file mode 100644 index 00000000..56f5ef54 --- /dev/null +++ b/dns/patch_android.go @@ -0,0 +1,81 @@ +// +build android + +package dns + +import ( + "context" + + D "github.com/miekg/dns" + + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/component/dhcp" + "github.com/metacubex/mihomo/component/resolver" +) + +const SystemDNSPlaceholder = "system" + +var systemResolver *Resolver +var isolateHandler handler + +var _ dnsClient = (*dhcpClient)(nil) + +type dhcpClient struct { + enable bool +} + +func (d *dhcpClient) Address() string { + return SystemDNSPlaceholder +} + +func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { + return d.ExchangeContext(context.Background(), m) +} + +func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { + if s := systemResolver; s != nil { + return s.ExchangeContext(ctx, m) + } + + return nil, dhcp.ErrNotFound +} + +func ServeDNSWithDefaultServer(msg *D.Msg) (*D.Msg, error) { + if h := isolateHandler; h != nil { + return handlerWithContext(context.Background(), h, msg) + } + + return nil, D.ErrTime +} + +func FlushCacheWithDefaultResolver() { + if r := resolver.DefaultResolver; r != nil { + r.(*Resolver).lruCache = cache.New[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)) + } +} + +func UpdateSystemDNS(addr []string) { + if len(addr) == 0 { + systemResolver = nil + } + + ns := make([]NameServer, 0, len(addr)) + for _, d := range addr { + ns = append(ns, NameServer{Addr: d}) + } + + systemResolver = NewResolver(Config{Main: ns}) +} + +func UpdateIsolateHandler(resolver *Resolver, mapper *ResolverEnhancer) { + if resolver == nil { + isolateHandler = nil + + return + } + + isolateHandler = NewHandler(resolver, mapper) +} + +func newDHCPClient(ifaceName string) *dhcpClient { + return &dhcpClient{enable: ifaceName == SystemDNSPlaceholder} +} diff --git a/dns/server.go b/dns/server.go index 1cf58d4d..2eac173e 100644 --- a/dns/server.go +++ b/dns/server.go @@ -49,6 +49,8 @@ func (s *Server) SetHandler(handler handler) { } func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) { + UpdateIsolateHandler(resolver, mapper) + if addr == address && resolver != nil { handler := NewHandler(resolver, mapper) server.SetHandler(handler) diff --git a/listener/http/patch_android.go b/listener/http/patch_android.go new file mode 100644 index 00000000..33dc0874 --- /dev/null +++ b/listener/http/patch_android.go @@ -0,0 +1,9 @@ +// +build android + +package http + +import "net" + +func (l *Listener) Listener() net.Listener { + return l.listener +} diff --git a/rules/provider/patch_android.go b/rules/provider/patch_android.go new file mode 100644 index 00000000..2bea2fa3 --- /dev/null +++ b/rules/provider/patch_android.go @@ -0,0 +1,27 @@ +// +build android + +package provider + +import "time" + +var ( + suspended bool +) + +type UpdatableProvider interface { + UpdatedAt() time.Time +} + +func (f *ruleSetProvider) UpdatedAt() time.Time { + return f.Fetcher.UpdatedAt +} + +func (rp *ruleSetProvider) Close() error { + rp.Fetcher.Destroy() + + return nil +} + +func Suspend(s bool) { + suspended = s +} diff --git a/tunnel/statistic/patch_android.go b/tunnel/statistic/patch_android.go new file mode 100644 index 00000000..c000567f --- /dev/null +++ b/tunnel/statistic/patch_android.go @@ -0,0 +1,7 @@ +// +build android + +package statistic + +func (m *Manager) Total() (up, down int64) { + return m.uploadTotal.Load(), m.downloadTotal.Load() +} From b73382f60ac5b15a40ad990e0a6ae2bf4c8b0f4b Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 10:18:14 +0800 Subject: [PATCH 097/192] fix: fix android-arm64 build --- adapter/outboundgroup/patch_android.go | 2 +- adapter/provider/patch_android.go | 2 +- component/dialer/patch_android.go | 2 +- component/mmdb/patch_android.go | 2 +- component/process/patch_android.go | 2 +- dns/dhcp.go | 2 +- dns/patch_android.go | 2 +- dns/{patch_!android.go => patch_common.go} | 2 +- listener/http/patch_android.go | 2 +- rules/provider/patch_android.go | 2 +- tunnel/statistic/patch_android.go | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) rename dns/{patch_!android.go => patch_common.go} (83%) diff --git a/adapter/outboundgroup/patch_android.go b/adapter/outboundgroup/patch_android.go index e219ca9f..c9c1725b 100644 --- a/adapter/outboundgroup/patch_android.go +++ b/adapter/outboundgroup/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package outboundgroup diff --git a/adapter/provider/patch_android.go b/adapter/provider/patch_android.go index eb0ca1f9..eba560eb 100644 --- a/adapter/provider/patch_android.go +++ b/adapter/provider/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package provider diff --git a/component/dialer/patch_android.go b/component/dialer/patch_android.go index 2fe39924..b1e80a5d 100644 --- a/component/dialer/patch_android.go +++ b/component/dialer/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package dialer diff --git a/component/mmdb/patch_android.go b/component/mmdb/patch_android.go index 23afbb90..9ded6566 100644 --- a/component/mmdb/patch_android.go +++ b/component/mmdb/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package mmdb diff --git a/component/process/patch_android.go b/component/process/patch_android.go index ae68d7b2..f9018557 100644 --- a/component/process/patch_android.go +++ b/component/process/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package process diff --git a/dns/dhcp.go b/dns/dhcp.go index bd3143c6..09aec799 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -1,4 +1,4 @@ -// +build !android +// +build !cmfa package dns diff --git a/dns/patch_android.go b/dns/patch_android.go index 56f5ef54..8ffa5af6 100644 --- a/dns/patch_android.go +++ b/dns/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package dns diff --git a/dns/patch_!android.go b/dns/patch_common.go similarity index 83% rename from dns/patch_!android.go rename to dns/patch_common.go index 566d8fd5..afb60d6d 100644 --- a/dns/patch_!android.go +++ b/dns/patch_common.go @@ -1,4 +1,4 @@ -// +build !android +// +build !cmfa package dns diff --git a/listener/http/patch_android.go b/listener/http/patch_android.go index 33dc0874..46d2eee5 100644 --- a/listener/http/patch_android.go +++ b/listener/http/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package http diff --git a/rules/provider/patch_android.go b/rules/provider/patch_android.go index 2bea2fa3..28a0d47d 100644 --- a/rules/provider/patch_android.go +++ b/rules/provider/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package provider diff --git a/tunnel/statistic/patch_android.go b/tunnel/statistic/patch_android.go index c000567f..235ab701 100644 --- a/tunnel/statistic/patch_android.go +++ b/tunnel/statistic/patch_android.go @@ -1,4 +1,4 @@ -// +build android +// +build android,cmfa package statistic From d9cfdc3242ae677dcfd2bec005e57a0ce56a3e42 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 13:19:24 +0800 Subject: [PATCH 098/192] chore: add android feature and patch --- component/dialer/dialer.go | 10 +++++++++ component/dialer/patch_common.go | 17 ++++++++++++++ component/resource/fetcher.go | 38 ++++++++++++++++++-------------- constant/features/cmfa.go | 6 +++++ hub/executor/executor.go | 6 ++++- listener/http/server.go | 7 ++++++ 6 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 component/dialer/patch_common.go create mode 100644 constant/features/cmfa.go diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 0e0e3cef..37a2bcba 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -12,6 +12,8 @@ import ( "time" "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/constant/features" + "golang.org/x/exp/slices" ) type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) @@ -70,6 +72,10 @@ func DialContext(ctx context.Context, network, address string, options ...Option } func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) { + if slices.Contains(features.TAGS, "cmfa") { + return listenPacketHooked(ctx, network, address) + } + cfg := applyOptions(options...) lc := &net.ListenConfig{} @@ -114,6 +120,10 @@ func GetTcpConcurrent() bool { } func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) { + if slices.Contains(features.TAGS, "cmfa") { + return dialContextHooked(ctx, network, destination, port) + } + address := net.JoinHostPort(destination.String(), port) netDialer := opt.netDialer diff --git a/component/dialer/patch_common.go b/component/dialer/patch_common.go new file mode 100644 index 00000000..9253d6b7 --- /dev/null +++ b/component/dialer/patch_common.go @@ -0,0 +1,17 @@ +// +build !cmfa + +package dialer + +import ( + "context" + "net" + "net/netip" +) + +func dialContextHooked(ctx context.Context, network string, destination netip.Addr, port string) (net.Conn, error) { + return nil, nil +} + +func listenPacketHooked(ctx context.Context, network, address string) (net.PacketConn, error) { + return nil, nil +} diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index 3d749645..44ca45c2 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -13,6 +13,10 @@ import ( "github.com/samber/lo" ) +const ( + minInterval = time.Minute * 5 +) + var ( fileMode os.FileMode = 0o666 dirMode os.FileMode = 0o755 @@ -24,8 +28,7 @@ type Fetcher[V any] struct { resourceType string name string vehicle types.Vehicle - UpdatedAt *time.Time - ticker *time.Ticker + UpdatedAt time.Time done chan struct{} hash [16]byte parser Parser[V] @@ -56,14 +59,15 @@ func (f *Fetcher[V]) Initial() (V, error) { if stat, fErr := os.Stat(f.vehicle.Path()); fErr == nil { buf, err = os.ReadFile(f.vehicle.Path()) modTime := stat.ModTime() - f.UpdatedAt = &modTime + f.UpdatedAt = modTime isLocal = true if f.interval != 0 && modTime.Add(f.interval).Before(time.Now()) { - log.Warnln("[Provider] %s not updated for %s, force update", f.Name(), time.Now().Sub(modTime)) + log.Warnln("[Provider] %s not updated for a long time, force refresh", f.Name()) forceUpdate = true } } else { buf, err = f.vehicle.Read() + f.UpdatedAt = time.Now() } if err != nil { @@ -113,7 +117,7 @@ func (f *Fetcher[V]) Initial() (V, error) { f.hash = md5.Sum(buf) // pull contents automatically - if f.ticker != nil { + if f.interval > 0 { go f.pullLoop() } @@ -129,7 +133,7 @@ func (f *Fetcher[V]) Update() (V, bool, error) { now := time.Now() hash := md5.Sum(buf) if bytes.Equal(f.hash[:], hash[:]) { - f.UpdatedAt = &now + f.UpdatedAt = now _ = os.Chtimes(f.vehicle.Path(), now, now) return lo.Empty[V](), true, nil } @@ -145,23 +149,31 @@ func (f *Fetcher[V]) Update() (V, bool, error) { } } - f.UpdatedAt = &now + f.UpdatedAt = now f.hash = hash return contents, false, nil } func (f *Fetcher[V]) Destroy() error { - if f.ticker != nil { + if f.interval > 0 { f.done <- struct{}{} } return nil } func (f *Fetcher[V]) pullLoop() { + initialInterval := f.interval - time.Since(f.UpdatedAt) + if initialInterval < minInterval { + initialInterval = minInterval + } + + timer := time.NewTimer(initialInterval) + defer timer.Stop() for { select { - case <-f.ticker.C: + case <-timer.C: + timer.Reset(f.interval) elm, same, err := f.Update() if err != nil { log.Errorln("[Provider] %s pull error: %s", f.Name(), err.Error()) @@ -178,7 +190,6 @@ func (f *Fetcher[V]) pullLoop() { f.OnUpdate(elm) } case <-f.done: - f.ticker.Stop() return } } @@ -197,17 +208,12 @@ func safeWrite(path string, buf []byte) error { } func NewFetcher[V any](name string, interval time.Duration, vehicle types.Vehicle, parser Parser[V], onUpdate func(V)) *Fetcher[V] { - var ticker *time.Ticker - if interval != 0 { - ticker = time.NewTicker(interval) - } return &Fetcher[V]{ name: name, - ticker: ticker, vehicle: vehicle, parser: parser, - done: make(chan struct{}, 1), + done: make(chan struct{}, 8), OnUpdate: onUpdate, interval: interval, } diff --git a/constant/features/cmfa.go b/constant/features/cmfa.go new file mode 100644 index 00000000..ab76b06d --- /dev/null +++ b/constant/features/cmfa.go @@ -0,0 +1,6 @@ +//go:build cmfa +package features + +func init() { + TAGS = append(TAGS, "cmfa") +} diff --git a/hub/executor/executor.go b/hub/executor/executor.go index efd9a076..216754cc 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -35,6 +35,8 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/tunnel" + "github.com/metacubex/mihomo/constant/features" + "golang.org/x/exp/slices" ) var mux sync.Mutex @@ -170,7 +172,9 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList listener.ReCreateHTTP(general.Port, tunnel.Tunnel) listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) - listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) + if !slices.Contains(features.TAGS, "cmfa") { + listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) + } listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel) listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) diff --git a/listener/http/server.go b/listener/http/server.go index a75e2092..06389185 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -6,6 +6,8 @@ import ( "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/common/cache" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" + "golang.org/x/exp/slices" ) type Listener struct { @@ -65,6 +67,11 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi } continue } + if slices.Contains(features.TAGS, "cmfa") { + if t, ok := conn.(*net.TCPConn); ok { + t.SetKeepAlive(false) + } + } go HandleConn(conn, tunnel, c, additions...) } }() From b5a8f0fce123cb9735f2a81639f36679140160b6 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 19:03:39 +0800 Subject: [PATCH 099/192] fix: improve feature check and add missing patches --- adapter/inbound/packet.go | 1 + adapter/provider/parser.go | 3 +- component/dialer/dialer.go | 5 +-- component/dialer/patch_common.go | 5 +++ config/config.go | 71 ++++++++++++++++---------------- constant/features/cmfa.go | 1 + constant/features/low_memory.go | 1 + constant/features/tags.go | 8 ++++ dns/server.go | 5 ++- hub/executor/executor.go | 3 +- listener/http/server.go | 3 +- rules/provider/parse.go | 3 +- 12 files changed, 64 insertions(+), 45 deletions(-) diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index a10d402e..a87c6276 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -3,6 +3,7 @@ package inbound import ( C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/constant/features" ) // NewPacket is PacketAdapter generator diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 966d33d6..f055e596 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -9,6 +9,7 @@ import ( "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/resource" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" types "github.com/metacubex/mihomo/constant/provider" ) @@ -78,7 +79,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide case "http": if schema.Path != "" { path := C.Path.Resolve(schema.Path) - if !C.Path.IsSafePath(path) { + if !features.Contains("cmfa") && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } vehicle = resource.NewHTTPVehicle(schema.URL, path) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 37a2bcba..8d1f671f 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -13,7 +13,6 @@ import ( "github.com/metacubex/mihomo/component/resolver" "github.com/metacubex/mihomo/constant/features" - "golang.org/x/exp/slices" ) type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) @@ -72,7 +71,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option } func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) { - if slices.Contains(features.TAGS, "cmfa") { + if features.Contains("cmfa") && DefaultSocketHook != nil{ return listenPacketHooked(ctx, network, address) } @@ -120,7 +119,7 @@ func GetTcpConcurrent() bool { } func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) { - if slices.Contains(features.TAGS, "cmfa") { + if features.Contains("cmfa") && DefaultSocketHook != nil{ return dialContextHooked(ctx, network, destination, port) } diff --git a/component/dialer/patch_common.go b/component/dialer/patch_common.go index 9253d6b7..b1e8f2f9 100644 --- a/component/dialer/patch_common.go +++ b/component/dialer/patch_common.go @@ -6,8 +6,13 @@ import ( "context" "net" "net/netip" + "syscall" ) +type SocketControl func(network, address string, conn syscall.RawConn) error + +var DefaultSocketHook SocketControl + func dialContextHooked(ctx context.Context, network string, destination netip.Addr, port string) (net.Conn, error) { return nil, nil } diff --git a/config/config.go b/config/config.go index d808f702..c6c9aa55 100644 --- a/config/config.go +++ b/config/config.go @@ -29,6 +29,7 @@ import ( tlsC "github.com/metacubex/mihomo/component/tls" "github.com/metacubex/mihomo/component/trie" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" providerTypes "github.com/metacubex/mihomo/constant/provider" snifferTypes "github.com/metacubex/mihomo/constant/sniffer" "github.com/metacubex/mihomo/dns" @@ -194,21 +195,21 @@ type RawNTP struct { } type RawDNS struct { - Enable bool `yaml:"enable"` - PreferH3 bool `yaml:"prefer-h3"` - IPv6 bool `yaml:"ipv6"` - IPv6Timeout uint `yaml:"ipv6-timeout"` - UseHosts bool `yaml:"use-hosts"` - NameServer []string `yaml:"nameserver"` - Fallback []string `yaml:"fallback"` - FallbackFilter RawFallbackFilter `yaml:"fallback-filter"` - Listen string `yaml:"listen"` - EnhancedMode C.DNSMode `yaml:"enhanced-mode"` - FakeIPRange string `yaml:"fake-ip-range"` - FakeIPFilter []string `yaml:"fake-ip-filter"` - DefaultNameserver []string `yaml:"default-nameserver"` - NameServerPolicy *orderedmap.OrderedMap[string, any] `yaml:"nameserver-policy"` - ProxyServerNameserver []string `yaml:"proxy-server-nameserver"` + Enable bool `yaml:"enable" json:"enable"` + PreferH3 bool `yaml:"prefer-h3" json:"prefer-h3"` + IPv6 bool `yaml:"ipv6" json:"ipv6"` + IPv6Timeout uint `yaml:"ipv6-timeout" json:"ipv6-timeout"` + UseHosts bool `yaml:"use-hosts" json:"use-hosts"` + NameServer []string `yaml:"nameserver" json:"nameserver"` + Fallback []string `yaml:"fallback" json:"fallback"` + FallbackFilter RawFallbackFilter `yaml:"fallback-filter" json:"fallback-filter"` + Listen string `yaml:"listen" json:"listen"` + EnhancedMode C.DNSMode `yaml:"enhanced-mode" json:"enhanced-mode"` + FakeIPRange string `yaml:"fake-ip-range" json:"fake-ip-range"` + FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"` + DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"` + NameServerPolicy *orderedmap.OrderedMap[string, any] `yaml:"nameserver-policy" json:"nameserver-policy"` + ProxyServerNameserver []string `yaml:"proxy-server-nameserver" json:"proxy-server-nameserver"` } type RawFallbackFilter struct { @@ -269,23 +270,23 @@ type RawTuicServer struct { } type RawConfig struct { - Port int `yaml:"port"` - SocksPort int `yaml:"socks-port"` - RedirPort int `yaml:"redir-port"` - TProxyPort int `yaml:"tproxy-port"` - MixedPort int `yaml:"mixed-port"` + Port int `yaml:"port" json:"port"` + SocksPort int `yaml:"socks-port" json:"socks-port"` + RedirPort int `yaml:"redir-port" json:"redir-port"` + TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"` + MixedPort int `yaml:"mixed-port" json:"mixed-port"` ShadowSocksConfig string `yaml:"ss-config"` VmessConfig string `yaml:"vmess-config"` InboundTfo bool `yaml:"inbound-tfo"` InboundMPTCP bool `yaml:"inbound-mptcp"` - Authentication []string `yaml:"authentication"` + Authentication []string `yaml:"authentication" json:"authentication"` SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"` - AllowLan bool `yaml:"allow-lan"` - BindAddress string `yaml:"bind-address"` - Mode T.TunnelMode `yaml:"mode"` - UnifiedDelay bool `yaml:"unified-delay"` - LogLevel log.LogLevel `yaml:"log-level"` - IPv6 bool `yaml:"ipv6"` + AllowLan bool `yaml:"allow-lan" json:"allow-lan"` + BindAddress string `yaml:"bind-address" json:"bind-address"` + Mode T.TunnelMode `yaml:"mode" json:"mode"` + UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"` + LogLevel log.LogLevel `yaml:"log-level" json:"log-level"` + IPv6 bool `yaml:"ipv6" json:"ipv6"` ExternalController string `yaml:"external-controller"` ExternalControllerTLS string `yaml:"external-controller-tls"` ExternalUI string `yaml:"external-ui"` @@ -295,20 +296,20 @@ type RawConfig struct { Interface string `yaml:"interface-name"` RoutingMark int `yaml:"routing-mark"` Tunnels []LC.Tunnel `yaml:"tunnels"` - GeodataMode bool `yaml:"geodata-mode"` - GeodataLoader string `yaml:"geodata-loader"` + GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"` + GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"` TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` GlobalClientFingerprint string `yaml:"global-client-fingerprint"` GlobalUA string `yaml:"global-ua"` KeepAliveInterval int `yaml:"keep-alive-interval"` - Sniffer RawSniffer `yaml:"sniffer"` + Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` RuleProvider map[string]map[string]any `yaml:"rule-providers"` - Hosts map[string]any `yaml:"hosts"` - NTP RawNTP `yaml:"ntp"` - DNS RawDNS `yaml:"dns"` + Hosts map[string]any `yaml:"hosts" json:"hosts"` + NTP RawNTP `yaml:"ntp" json:"ntp"` + DNS RawDNS `yaml:"dns" json:"dns"` Tun RawTun `yaml:"tun"` TuicServer RawTuicServer `yaml:"tuic-server"` EBpf EBpf `yaml:"ebpf"` @@ -323,7 +324,7 @@ type RawConfig struct { RawTLS TLS `yaml:"tls"` Listeners []map[string]any `yaml:"listeners"` - ClashForAndroid RawClashForAndroid `yaml:"clash-for-android"` + ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"` } type GeoXUrl struct { @@ -553,7 +554,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config.DNS = dnsCfg err = parseTun(rawCfg.Tun, config.General) - if err != nil { + if !features.Contains("cmfa") && err != nil { return nil, err } diff --git a/constant/features/cmfa.go b/constant/features/cmfa.go index ab76b06d..e93ad625 100644 --- a/constant/features/cmfa.go +++ b/constant/features/cmfa.go @@ -1,4 +1,5 @@ //go:build cmfa + package features func init() { diff --git a/constant/features/low_memory.go b/constant/features/low_memory.go index 0d252113..ad52b555 100644 --- a/constant/features/low_memory.go +++ b/constant/features/low_memory.go @@ -1,4 +1,5 @@ //go:build with_low_memory + package features func init() { diff --git a/constant/features/tags.go b/constant/features/tags.go index c81f6d4e..8fe639a0 100644 --- a/constant/features/tags.go +++ b/constant/features/tags.go @@ -1,3 +1,11 @@ package features +import( + "golang.org/x/exp/slices" +) + var TAGS = make([]string, 0, 0) + +func Contains(feat string) (bool) { + return slices.Contains(TAGS, feat) +} \ No newline at end of file diff --git a/dns/server.go b/dns/server.go index 2eac173e..8371dbd8 100644 --- a/dns/server.go +++ b/dns/server.go @@ -6,6 +6,7 @@ import ( "net" "github.com/metacubex/mihomo/common/sockopt" + "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/context" "github.com/metacubex/mihomo/log" @@ -49,7 +50,9 @@ func (s *Server) SetHandler(handler handler) { } func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) { - UpdateIsolateHandler(resolver, mapper) + if features.Contains("cmfa") { + UpdateIsolateHandler(resolver, mapper) + } if addr == address && resolver != nil { handler := NewHandler(resolver, mapper) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 216754cc..88da9d5d 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -36,7 +36,6 @@ import ( "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/tunnel" "github.com/metacubex/mihomo/constant/features" - "golang.org/x/exp/slices" ) var mux sync.Mutex @@ -172,7 +171,7 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList listener.ReCreateHTTP(general.Port, tunnel.Tunnel) listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) - if !slices.Contains(features.TAGS, "cmfa") { + if !features.Contains("cmfa") { listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) } listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) diff --git a/listener/http/server.go b/listener/http/server.go index 06389185..06797273 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -7,7 +7,6 @@ import ( "github.com/metacubex/mihomo/common/cache" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/features" - "golang.org/x/exp/slices" ) type Listener struct { @@ -67,7 +66,7 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi } continue } - if slices.Contains(features.TAGS, "cmfa") { + if features.Contains("cmfa") { if t, ok := conn.(*net.TCPConn); ok { t.SetKeepAlive(false) } diff --git a/rules/provider/parse.go b/rules/provider/parse.go index 3a5c4fd7..8319b737 100644 --- a/rules/provider/parse.go +++ b/rules/provider/parse.go @@ -8,6 +8,7 @@ import ( "github.com/metacubex/mihomo/common/structure" "github.com/metacubex/mihomo/component/resource" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" P "github.com/metacubex/mihomo/constant/provider" ) @@ -62,7 +63,7 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t case "http": if schema.Path != "" { path := C.Path.Resolve(schema.Path) - if !C.Path.IsSafePath(path) { + if !features.Contains("cmfa") && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } vehicle = resource.NewHTTPVehicle(schema.URL, path) From aa3c1ac6234d24d25a3d492173c31654561c119e Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 19:39:57 +0800 Subject: [PATCH 100/192] fix: fix package name rules match --- adapter/inbound/packet.go | 1 - component/process/process.go | 5 +++++ tunnel/tunnel.go | 24 ++++++++++++++++++------ 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index a87c6276..a10d402e 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -3,7 +3,6 @@ package inbound import ( C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/transport/socks5" - "github.com/metacubex/mihomo/constant/features" ) // NewPacket is PacketAdapter generator diff --git a/component/process/process.go b/component/process/process.go index 76ec2c45..5b49134e 100644 --- a/component/process/process.go +++ b/component/process/process.go @@ -3,6 +3,7 @@ package process import ( "errors" "net/netip" + "github.com/metacubex/mihomo/constant" ) var ( @@ -19,3 +20,7 @@ const ( func FindProcessName(network string, srcIP netip.Addr, srcPort int) (uint32, string, error) { return findProcessName(network, srcIP, srcPort) } + +func FindPackageName(metadata *constant.Metadata) (string, error) { + return "", nil +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 596e26d7..bbc2d1a1 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -18,6 +18,7 @@ import ( "github.com/metacubex/mihomo/component/resolver" "github.com/metacubex/mihomo/component/sniffer" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/constant/provider" icontext "github.com/metacubex/mihomo/context" "github.com/metacubex/mihomo/log" @@ -620,13 +621,24 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { if attemptProcessLookup && !findProcessMode.Off() && (findProcessMode.Always() || rule.ShouldFindProcess()) { attemptProcessLookup = false - uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort)) - if err != nil { - log.Debugln("[Process] find process %s: %v", metadata.String(), err) + if !features.Contains("cmfa") { + // normal check for process + uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort)) + if err != nil { + log.Debugln("[Process] find process %s error: %v", metadata.String(), err) + } else { + metadata.Process = filepath.Base(path) + metadata.ProcessPath = path + metadata.Uid = uid + } } else { - metadata.Process = filepath.Base(path) - metadata.ProcessPath = path - metadata.Uid = uid + // check package names + pkg, err := P.FindPackageName(metadata) + if err != nil { + log.Debugln("[Process] find process %s error: %v", metadata.String(), err) + } else { + metadata.Process = pkg + } } } From fef5ad780db838a3779e49e2d5f3be9ba04646ca Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Fri, 17 Nov 2023 19:49:55 +0800 Subject: [PATCH 101/192] action: remove code about android branches --- .../workflows/android-branch-auto-sync.yml | 69 ------------------- .github/workflows/trigger-cmfa-update.yml | 33 +++++++++ 2 files changed, 33 insertions(+), 69 deletions(-) delete mode 100644 .github/workflows/android-branch-auto-sync.yml create mode 100644 .github/workflows/trigger-cmfa-update.yml diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml deleted file mode 100644 index fd7c9d66..00000000 --- a/.github/workflows/android-branch-auto-sync.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Android Branch Auto Sync -on: - workflow_dispatch: - push: - paths-ignore: - - "docs/**" - - "README.md" - - ".github/ISSUE_TEMPLATE/**" - branches: - - Alpha - - android-open - tags: - - "v*" - pull_request_target: - branches: - - Alpha - - android-open - -jobs: - update-dependencies: - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Configure Git - run: | - git config --global user.name 'GitHub Action' - git config --global user.email 'action@github.com' - - - name: Sync android-real with Alpha rebase android-open - run: | - git fetch origin - git checkout origin/Alpha -b android-real - git merge --squash origin/android-open - git commit -m "Android: patch" - - - name: Check for conflicts - run: | - CONFLICTS=$(git diff --name-only --diff-filter=U) - if [ ! -z "$CONFLICTS" ]; then - echo "There are conflicts in the following files:" - echo $CONFLICTS - exit 1 - fi - - - name: Push changes - run: | - git push origin android-real --force - - # Send "core-updated" to MetaCubeX/MihomoForAndroid to trigger update-dependencies - trigger-MFA-update: - needs: update-dependencies - runs-on: ubuntu-latest - steps: - - uses: tibdex/github-app-token@v1 - id: generate-token - with: - app_id: ${{ secrets.MAINTAINER_APPID }} - private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} - - - name: Trigger update-dependencies - run: | - curl -X POST https://api.github.com/repos/MetaCubeX/MihomoForAndroid/dispatches \ - -H "Accept: application/vnd.github.everest-preview+json" \ - -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ - -d '{"event_type": "core-updated"}' \ No newline at end of file diff --git a/.github/workflows/trigger-cmfa-update.yml b/.github/workflows/trigger-cmfa-update.yml new file mode 100644 index 00000000..d767657e --- /dev/null +++ b/.github/workflows/trigger-cmfa-update.yml @@ -0,0 +1,33 @@ +name: Trigger CMFA Update +on: + workflow_dispatch: + push: + paths-ignore: + - "docs/**" + - "README.md" + - ".github/ISSUE_TEMPLATE/**" + branches: + - Alpha + tags: + - "v*" + pull_request_target: + branches: + - Alpha + +jobs: + # Send "core-updated" to MetaCubeX/MihomoForAndroid to trigger update-dependencies + trigger-CMFA-update: + runs-on: ubuntu-latest + steps: + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.MAINTAINER_APPID }} + private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} + + - name: Trigger update-dependencies + run: | + curl -X POST https://api.github.com/repos/MetaCubeX/MihomoForAndroid/dispatches \ + -H "Accept: application/vnd.github.everest-preview+json" \ + -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ + -d '{"event_type": "core-updated"}' \ No newline at end of file From 1479b449dfd51060749139d8a3c175be767ce2b1 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 17 Nov 2023 23:12:10 +0800 Subject: [PATCH 102/192] chore: Cleanup code --- adapter/outboundgroup/patch_android.go | 2 +- adapter/provider/parser.go | 2 +- adapter/provider/patch_android.go | 2 +- component/dialer/dialer.go | 8 +++---- component/dialer/patch_android.go | 2 +- component/dialer/patch_common.go | 2 +- component/mmdb/patch_android.go | 2 +- component/process/process.go | 5 ---- .../{patch_android.go => process_android.go} | 2 +- component/process/process_common.go | 9 +++++++ config/config.go | 4 ++-- constant/features/cmfa.go | 4 +--- constant/features/cmfa_stub.go | 5 ++++ constant/features/low_memory.go | 4 +--- constant/features/low_memory_stub.go | 5 ++++ constant/features/no_fake_tcp.go | 4 +--- constant/features/no_fake_tcp_stub.go | 5 ++++ constant/features/tags.go | 24 ++++++++++++------- constant/features/with_gvisor.go | 4 +--- constant/features/with_gvisor_stub.go | 5 ++++ dns/dhcp.go | 2 +- dns/patch_android.go | 2 +- dns/patch_common.go | 5 ++-- dns/server.go | 4 ++-- hub/executor/executor.go | 4 ++-- listener/http/patch_android.go | 2 +- listener/http/server.go | 2 +- main.go | 4 ++-- rules/provider/parse.go | 2 +- rules/provider/patch_android.go | 2 +- tunnel/statistic/patch_android.go | 2 +- tunnel/tunnel.go | 2 +- 32 files changed, 77 insertions(+), 56 deletions(-) rename component/process/{patch_android.go => process_android.go} (93%) create mode 100644 component/process/process_common.go create mode 100644 constant/features/cmfa_stub.go create mode 100644 constant/features/low_memory_stub.go create mode 100644 constant/features/no_fake_tcp_stub.go create mode 100644 constant/features/with_gvisor_stub.go diff --git a/adapter/outboundgroup/patch_android.go b/adapter/outboundgroup/patch_android.go index c9c1725b..c6566814 100644 --- a/adapter/outboundgroup/patch_android.go +++ b/adapter/outboundgroup/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package outboundgroup diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index f055e596..09ae4332 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -79,7 +79,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide case "http": if schema.Path != "" { path := C.Path.Resolve(schema.Path) - if !features.Contains("cmfa") && !C.Path.IsSafePath(path) { + if !features.CMFA && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } vehicle = resource.NewHTTPVehicle(schema.URL, path) diff --git a/adapter/provider/patch_android.go b/adapter/provider/patch_android.go index eba560eb..e9042bda 100644 --- a/adapter/provider/patch_android.go +++ b/adapter/provider/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package provider diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 8d1f671f..985e2195 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -71,10 +71,10 @@ func DialContext(ctx context.Context, network, address string, options ...Option } func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) { - if features.Contains("cmfa") && DefaultSocketHook != nil{ + if features.CMFA && DefaultSocketHook != nil { return listenPacketHooked(ctx, network, address) } - + cfg := applyOptions(options...) lc := &net.ListenConfig{} @@ -119,10 +119,10 @@ func GetTcpConcurrent() bool { } func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) { - if features.Contains("cmfa") && DefaultSocketHook != nil{ + if features.CMFA && DefaultSocketHook != nil { return dialContextHooked(ctx, network, destination, port) } - + address := net.JoinHostPort(destination.String(), port) netDialer := opt.netDialer diff --git a/component/dialer/patch_android.go b/component/dialer/patch_android.go index b1e80a5d..7c33a6c0 100644 --- a/component/dialer/patch_android.go +++ b/component/dialer/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package dialer diff --git a/component/dialer/patch_common.go b/component/dialer/patch_common.go index b1e8f2f9..bad0ef48 100644 --- a/component/dialer/patch_common.go +++ b/component/dialer/patch_common.go @@ -1,4 +1,4 @@ -// +build !cmfa +//go:build !(android && cmfa) package dialer diff --git a/component/mmdb/patch_android.go b/component/mmdb/patch_android.go index 9ded6566..a994b75e 100644 --- a/component/mmdb/patch_android.go +++ b/component/mmdb/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package mmdb diff --git a/component/process/process.go b/component/process/process.go index 5b49134e..76ec2c45 100644 --- a/component/process/process.go +++ b/component/process/process.go @@ -3,7 +3,6 @@ package process import ( "errors" "net/netip" - "github.com/metacubex/mihomo/constant" ) var ( @@ -20,7 +19,3 @@ const ( func FindProcessName(network string, srcIP netip.Addr, srcPort int) (uint32, string, error) { return findProcessName(network, srcIP, srcPort) } - -func FindPackageName(metadata *constant.Metadata) (string, error) { - return "", nil -} diff --git a/component/process/patch_android.go b/component/process/process_android.go similarity index 93% rename from component/process/patch_android.go rename to component/process/process_android.go index f9018557..fd5d3b6c 100644 --- a/component/process/patch_android.go +++ b/component/process/process_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package process diff --git a/component/process/process_common.go b/component/process/process_common.go new file mode 100644 index 00000000..fa7eeb9f --- /dev/null +++ b/component/process/process_common.go @@ -0,0 +1,9 @@ +//go:build !(android && cmfa) + +package process + +import "github.com/metacubex/mihomo/constant" + +func FindPackageName(metadata *constant.Metadata) (string, error) { + return "", nil +} diff --git a/config/config.go b/config/config.go index c6c9aa55..c2b389c3 100644 --- a/config/config.go +++ b/config/config.go @@ -324,7 +324,7 @@ type RawConfig struct { RawTLS TLS `yaml:"tls"` Listeners []map[string]any `yaml:"listeners"` - ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"` + ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"` } type GeoXUrl struct { @@ -554,7 +554,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config.DNS = dnsCfg err = parseTun(rawCfg.Tun, config.General) - if !features.Contains("cmfa") && err != nil { + if !features.CMFA && err != nil { return nil, err } diff --git a/constant/features/cmfa.go b/constant/features/cmfa.go index e93ad625..9a81d82f 100644 --- a/constant/features/cmfa.go +++ b/constant/features/cmfa.go @@ -2,6 +2,4 @@ package features -func init() { - TAGS = append(TAGS, "cmfa") -} +const CMFA = true diff --git a/constant/features/cmfa_stub.go b/constant/features/cmfa_stub.go new file mode 100644 index 00000000..f7ef0827 --- /dev/null +++ b/constant/features/cmfa_stub.go @@ -0,0 +1,5 @@ +//go:build !cmfa + +package features + +const CMFA = false diff --git a/constant/features/low_memory.go b/constant/features/low_memory.go index ad52b555..2f0f4d50 100644 --- a/constant/features/low_memory.go +++ b/constant/features/low_memory.go @@ -2,6 +2,4 @@ package features -func init() { - TAGS = append(TAGS, "with_low_memory") -} +const WithLowMemory = true diff --git a/constant/features/low_memory_stub.go b/constant/features/low_memory_stub.go new file mode 100644 index 00000000..00b0b947 --- /dev/null +++ b/constant/features/low_memory_stub.go @@ -0,0 +1,5 @@ +//go:build !with_low_memory + +package features + +const WithLowMemory = false diff --git a/constant/features/no_fake_tcp.go b/constant/features/no_fake_tcp.go index f536a066..a9e09728 100644 --- a/constant/features/no_fake_tcp.go +++ b/constant/features/no_fake_tcp.go @@ -2,6 +2,4 @@ package features -func init() { - TAGS = append(TAGS, "no_fake_tcp") -} +const NoFakeTCP = true diff --git a/constant/features/no_fake_tcp_stub.go b/constant/features/no_fake_tcp_stub.go new file mode 100644 index 00000000..f1620a2b --- /dev/null +++ b/constant/features/no_fake_tcp_stub.go @@ -0,0 +1,5 @@ +//go:build !no_fake_tcp + +package features + +const NoFakeTCP = false diff --git a/constant/features/tags.go b/constant/features/tags.go index 8fe639a0..12a5fbdd 100644 --- a/constant/features/tags.go +++ b/constant/features/tags.go @@ -1,11 +1,17 @@ package features -import( - "golang.org/x/exp/slices" -) - -var TAGS = make([]string, 0, 0) - -func Contains(feat string) (bool) { - return slices.Contains(TAGS, feat) -} \ No newline at end of file +func Tags() (tags []string) { + if CMFA { + tags = append(tags, "cmfa") + } + if WithLowMemory { + tags = append(tags, "with_low_memory") + } + if NoFakeTCP { + tags = append(tags, "no_fake_tcp") + } + if WithGVisor { + tags = append(tags, "with_gvisor") + } + return +} diff --git a/constant/features/with_gvisor.go b/constant/features/with_gvisor.go index 1b3417b3..c00cc34e 100644 --- a/constant/features/with_gvisor.go +++ b/constant/features/with_gvisor.go @@ -2,6 +2,4 @@ package features -func init() { - TAGS = append(TAGS, "with_gvisor") -} +const WithGVisor = true diff --git a/constant/features/with_gvisor_stub.go b/constant/features/with_gvisor_stub.go new file mode 100644 index 00000000..5684c1b1 --- /dev/null +++ b/constant/features/with_gvisor_stub.go @@ -0,0 +1,5 @@ +//go:build !with_gvisor + +package features + +const WithGVisor = false diff --git a/dns/dhcp.go b/dns/dhcp.go index 09aec799..d4944a96 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -1,4 +1,4 @@ -// +build !cmfa +//go:build !(android && cmfa) package dns diff --git a/dns/patch_android.go b/dns/patch_android.go index 8ffa5af6..8cb4286e 100644 --- a/dns/patch_android.go +++ b/dns/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package dns diff --git a/dns/patch_common.go b/dns/patch_common.go index afb60d6d..fae1e126 100644 --- a/dns/patch_common.go +++ b/dns/patch_common.go @@ -1,7 +1,6 @@ -// +build !cmfa +//go:build !(android && cmfa) package dns func UpdateIsolateHandler(resolver *Resolver, mapper *ResolverEnhancer) { - return -} \ No newline at end of file +} diff --git a/dns/server.go b/dns/server.go index 8371dbd8..d45fb5eb 100644 --- a/dns/server.go +++ b/dns/server.go @@ -50,10 +50,10 @@ func (s *Server) SetHandler(handler handler) { } func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) { - if features.Contains("cmfa") { + if features.CMFA { UpdateIsolateHandler(resolver, mapper) } - + if addr == address && resolver != nil { handler := NewHandler(resolver, mapper) server.SetHandler(handler) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 88da9d5d..f8ba31a5 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -25,6 +25,7 @@ import ( "github.com/metacubex/mihomo/component/trie" "github.com/metacubex/mihomo/config" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/constant/provider" "github.com/metacubex/mihomo/dns" "github.com/metacubex/mihomo/listener" @@ -35,7 +36,6 @@ import ( "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/ntp" "github.com/metacubex/mihomo/tunnel" - "github.com/metacubex/mihomo/constant/features" ) var mux sync.Mutex @@ -171,7 +171,7 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList listener.ReCreateHTTP(general.Port, tunnel.Tunnel) listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) - if !features.Contains("cmfa") { + if !features.CMFA { listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) } listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) diff --git a/listener/http/patch_android.go b/listener/http/patch_android.go index 46d2eee5..b1b8bfc7 100644 --- a/listener/http/patch_android.go +++ b/listener/http/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package http diff --git a/listener/http/server.go b/listener/http/server.go index 06797273..d5e20601 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -66,7 +66,7 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi } continue } - if features.Contains("cmfa") { + if features.CMFA { if t, ok := conn.(*net.TCPConn); ok { t.SetKeepAlive(false) } diff --git a/main.go b/main.go index fd1e065c..01edee9f 100644 --- a/main.go +++ b/main.go @@ -48,8 +48,8 @@ func main() { if version { fmt.Printf("Mihomo Meta %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) - if len(features.TAGS) != 0 { - fmt.Printf("Use tags: %s\n", strings.Join(features.TAGS, ", ")) + if tags := features.Tags(); len(tags) != 0 { + fmt.Printf("Use tags: %s\n", strings.Join(tags, ", ")) } return diff --git a/rules/provider/parse.go b/rules/provider/parse.go index 8319b737..a867d570 100644 --- a/rules/provider/parse.go +++ b/rules/provider/parse.go @@ -63,7 +63,7 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t case "http": if schema.Path != "" { path := C.Path.Resolve(schema.Path) - if !features.Contains("cmfa") && !C.Path.IsSafePath(path) { + if !features.CMFA && !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } vehicle = resource.NewHTTPVehicle(schema.URL, path) diff --git a/rules/provider/patch_android.go b/rules/provider/patch_android.go index 28a0d47d..2bd5ffc8 100644 --- a/rules/provider/patch_android.go +++ b/rules/provider/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package provider diff --git a/tunnel/statistic/patch_android.go b/tunnel/statistic/patch_android.go index 235ab701..f1eee346 100644 --- a/tunnel/statistic/patch_android.go +++ b/tunnel/statistic/patch_android.go @@ -1,4 +1,4 @@ -// +build android,cmfa +//go:build android && cmfa package statistic diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index bbc2d1a1..c37b0c7d 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -621,7 +621,7 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { if attemptProcessLookup && !findProcessMode.Off() && (findProcessMode.Always() || rule.ShouldFindProcess()) { attemptProcessLookup = false - if !features.Contains("cmfa") { + if !features.CMFA { // normal check for process uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort)) if err != nil { From 54a7f52fe324ad381675f48a636018849ee0f28d Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 18 Nov 2023 00:07:07 +0800 Subject: [PATCH 103/192] feat: Add outbound sing-mux tcp-brutal support --- adapter/outbound/singmux.go | 31 +++++++++++++++++++++++-------- go.mod | 12 ++++++------ go.sum | 20 ++++++++++---------- listener/sing/sing.go | 23 ++++++++++++++++++++++- test/go.mod | 16 ++++++++++------ test/go.sum | 33 +++++++++++++++++++++------------ 6 files changed, 92 insertions(+), 43 deletions(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index dff1e8eb..292ad1d8 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -25,14 +25,21 @@ type SingMux struct { } type SingMuxOption struct { - Enabled bool `proxy:"enabled,omitempty"` - Protocol string `proxy:"protocol,omitempty"` - MaxConnections int `proxy:"max-connections,omitempty"` - MinStreams int `proxy:"min-streams,omitempty"` - MaxStreams int `proxy:"max-streams,omitempty"` - Padding bool `proxy:"padding,omitempty"` - Statistic bool `proxy:"statistic,omitempty"` - OnlyTcp bool `proxy:"only-tcp,omitempty"` + Enabled bool `proxy:"enabled,omitempty"` + Protocol string `proxy:"protocol,omitempty"` + MaxConnections int `proxy:"max-connections,omitempty"` + MinStreams int `proxy:"min-streams,omitempty"` + MaxStreams int `proxy:"max-streams,omitempty"` + Padding bool `proxy:"padding,omitempty"` + Statistic bool `proxy:"statistic,omitempty"` + OnlyTcp bool `proxy:"only-tcp,omitempty"` + BrutalOpts BrutalOption `proxy:"brutal-opts,omitempty"` +} + +type BrutalOption struct { + Enabled bool `proxy:"enabled,omitempty"` + Up string `proxy:"up,omitempty"` + Down string `proxy:"down,omitempty"` } type ProxyBase interface { @@ -94,6 +101,9 @@ func closeSingMux(s *SingMux) { } func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) { + if !mux.BrutalAvailable && option.BrutalOpts.Enabled { + return nil, errors.New("TCP Brutal is only supported on Linux-based systems") + } singDialer := proxydialer.NewSingDialer(proxy, dialer.NewDialer(), option.Statistic) client, err := mux.NewClient(mux.Options{ Dialer: singDialer, @@ -102,6 +112,11 @@ func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.P MinStreams: option.MinStreams, MaxStreams: option.MaxStreams, Padding: option.Padding, + Brutal: mux.BrutalOptions{ + Enabled: option.BrutalOpts.Enabled, + SendBPS: StringToBps(option.BrutalOpts.Up), + ReceiveBPS: StringToBps(option.BrutalOpts.Down), + }, }) if err != nil { return nil, err diff --git a/go.mod b/go.mod index f7ba243a..69894ed3 100644 --- a/go.mod +++ b/go.mod @@ -33,8 +33,8 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.1 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.14 - github.com/sagernet/sing-mux v0.1.3 + github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c + github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 @@ -47,11 +47,11 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.3 - golang.org/x/crypto v0.14.0 + golang.org/x/crypto v0.15.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d - golang.org/x/net v0.17.0 + golang.org/x/net v0.18.0 golang.org/x/sync v0.4.0 - golang.org/x/sys v0.13.0 + golang.org/x/sys v0.14.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 @@ -107,7 +107,7 @@ require ( go.uber.org/mock v0.3.0 // indirect go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect golang.org/x/mod v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect ) diff --git a/go.sum b/go.sum index f1cbc511..2eaf82b1 100644 --- a/go.sum +++ b/go.sum @@ -155,8 +155,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= -github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -224,8 +224,8 @@ go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0Eq go4.org/netipx v0.0.0-20230824141953-6213f710f925/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -234,8 +234,8 @@ golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= @@ -255,11 +255,11 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 306bd705..deec7bf8 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -31,6 +31,7 @@ type ListenerHandler struct { Type C.Type Additions []inbound.Addition UDPTimeout time.Duration + MuxService *mux.Service } func UpstreamMetadata(metadata M.Metadata) M.Metadata { @@ -48,6 +49,20 @@ func ConvertMetadata(metadata *C.Metadata) M.Metadata { } } +func (h *ListenerHandler) ConfigureSingMux() (err error) { + h.MuxService, err = mux.NewService(mux.ServiceOptions{ + NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context { + return ctx + }, + Logger: log.SingLogger, + Handler: h, + Brutal: mux.BrutalOptions{ + // TODO: sing-mux tcp brutal inbound + }, + }) + return +} + func (h *ListenerHandler) IsSpecialFqdn(fqdn string) bool { switch fqdn { case mux.Destination.Fqdn: @@ -63,7 +78,13 @@ func (h *ListenerHandler) IsSpecialFqdn(fqdn string) bool { func (h *ListenerHandler) ParseSpecialFqdn(ctx context.Context, conn net.Conn, metadata M.Metadata) error { switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: - return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata)) + if h.MuxService == nil { + err := h.ConfigureSingMux() + if err != nil { + return err + } + } + return h.MuxService.NewConnection(ctx, conn, UpstreamMetadata(metadata)) case vmess.MuxDestination.Fqdn: return vmess.HandleMuxConnection(ctx, conn, h) case uot.MagicAddress: diff --git a/test/go.mod b/test/go.mod index adb42a2c..82d75ba9 100644 --- a/test/go.mod +++ b/test/go.mod @@ -8,7 +8,7 @@ require ( github.com/metacubex/mihomo v0.0.0 github.com/miekg/dns v1.1.56 github.com/stretchr/testify v1.8.4 - golang.org/x/net v0.17.0 + golang.org/x/net v0.18.0 ) replace github.com/metacubex/mihomo => ../ @@ -20,6 +20,8 @@ require ( github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/andybalholm/brotli v1.0.5 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/buger/jsonparser v1.1.1 // indirect github.com/cilium/ebpf v0.12.0 // indirect github.com/coreos/go-iptables v0.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -50,6 +52,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect @@ -79,8 +82,8 @@ require ( github.com/quic-go/qtls-go1-20 v0.3.4 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.2.14 // indirect - github.com/sagernet/sing-mux v0.1.3 // indirect + github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c // indirect + github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect @@ -98,18 +101,19 @@ require ( github.com/tklauser/numcpus v0.6.1 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zhangyunhao116/fastrand v0.3.0 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.etcd.io/bbolt v1.3.7 // indirect go.uber.org/mock v0.3.0 // indirect go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect - golang.org/x/crypto v0.14.0 // indirect + golang.org/x/crypto v0.15.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.14.0 // indirect google.golang.org/protobuf v1.31.0 // indirect diff --git a/test/go.sum b/test/go.sum index c7524eff..2e72ca34 100644 --- a/test/go.sum +++ b/test/go.sum @@ -11,7 +11,11 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -79,6 +83,7 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -96,6 +101,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= @@ -163,10 +170,10 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6E github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.14 h1:L3AXDh22nsOOYz2nTRU1JvpRsmzViWKI1B8TsQYG1eY= -github.com/sagernet/sing v0.2.14/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= -github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= -github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= +github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c h1:uask61Pxc3nGqsOSjqnBKrwfODWRoEa80lXm04LNk0E= +github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= +github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -216,6 +223,8 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= +github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= +github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= @@ -233,8 +242,8 @@ go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -247,8 +256,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -272,12 +281,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= From 3a3d88c6680372e4ba504ed41da0c388ea50d727 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 18 Nov 2023 11:26:27 +0800 Subject: [PATCH 104/192] chore: Update dependencies --- component/fakeip/pool_test.go | 2 +- component/profile/cachefile/cache.go | 2 +- go.mod | 28 ++++++------- go.sum | 56 +++++++++++++------------- test/go.mod | 29 +++++++------- test/go.sum | 59 +++++++++++++++------------- 6 files changed, 91 insertions(+), 85 deletions(-) diff --git a/component/fakeip/pool_test.go b/component/fakeip/pool_test.go index a7569ab0..cc50fcf7 100644 --- a/component/fakeip/pool_test.go +++ b/component/fakeip/pool_test.go @@ -10,8 +10,8 @@ import ( "github.com/metacubex/mihomo/component/profile/cachefile" "github.com/metacubex/mihomo/component/trie" + "github.com/sagernet/bbolt" "github.com/stretchr/testify/assert" - "go.etcd.io/bbolt" ) func createPools(options Options) ([]*Pool, string, error) { diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go index 68812824..11068647 100644 --- a/component/profile/cachefile/cache.go +++ b/component/profile/cachefile/cache.go @@ -9,7 +9,7 @@ import ( C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" - "go.etcd.io/bbolt" + "github.com/sagernet/bbolt" ) var ( diff --git a/go.mod b/go.mod index 69894ed3..8e86bb85 100644 --- a/go.mod +++ b/go.mod @@ -6,17 +6,17 @@ require ( github.com/3andne/restls-client-go v0.1.6 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/bahlo/generic-list-go v0.2.0 - github.com/cilium/ebpf v0.12.0 + github.com/cilium/ebpf v0.12.3 github.com/coreos/go-iptables v0.7.0 github.com/dlclark/regexp2 v1.10.0 github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 - github.com/gobwas/ws v1.3.0 + github.com/gobwas/ws v1.3.1 github.com/gofrs/uuid/v5 v5.0.0 - github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a + github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c github.com/jpillora/backoff v1.0.0 - github.com/klauspost/cpuid/v2 v2.2.5 + github.com/klauspost/cpuid/v2 v2.2.6 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 @@ -27,11 +27,12 @@ require ( github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 - github.com/miekg/dns v1.1.56 + github.com/miekg/dns v1.1.57 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.1 + github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 @@ -40,18 +41,17 @@ require ( github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.9 + github.com/shirou/gopsutil/v3 v3.23.10 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 github.com/wk8/go-ordered-map/v2 v2.1.8 github.com/zhangyunhao116/fastrand v0.3.0 - go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.3 golang.org/x/crypto v0.15.0 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/net v0.18.0 - golang.org/x/sync v0.4.0 - golang.org/x/sys v0.14.0 + golang.org/x/sync v0.5.0 + golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 @@ -75,7 +75,7 @@ require ( github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/josharian/native v1.1.0 // indirect @@ -106,10 +106,10 @@ require ( gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect - golang.org/x/mod v0.13.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c diff --git a/go.sum b/go.sum index 2eaf82b1..7fddd84e 100644 --- a/go.sum +++ b/go.sum @@ -18,8 +18,8 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.12.0 h1:oQEuIQIXgYhe1v7sYUG0P9vtJTYZLLdA6tiQmrOB1mo= -github.com/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= +github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= +github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -57,8 +57,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0= -github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= +github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU= +github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -68,16 +68,17 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -86,8 +87,8 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -106,8 +107,8 @@ github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8 github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= -github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c h1:SZwaf42NVCIDaHw5X2HOnNcEiK9ao6yO+N4zYyKfXe8= +github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= @@ -120,8 +121,8 @@ github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFk github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= @@ -151,6 +152,8 @@ github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1 github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= @@ -171,8 +174,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= -github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= +github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= +github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -214,8 +217,6 @@ github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtb github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= @@ -226,19 +227,19 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -254,17 +255,18 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= diff --git a/test/go.mod b/test/go.mod index 82d75ba9..d399e3eb 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,7 +6,7 @@ require ( github.com/docker/docker v20.10.21+incompatible github.com/docker/go-connections v0.4.0 github.com/metacubex/mihomo v0.0.0 - github.com/miekg/dns v1.1.56 + github.com/miekg/dns v1.1.57 github.com/stretchr/testify v1.8.4 golang.org/x/net v0.18.0 ) @@ -22,11 +22,12 @@ require ( github.com/andybalholm/brotli v1.0.5 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect - github.com/cilium/ebpf v0.12.0 // indirect + github.com/cilium/ebpf v0.12.3 // indirect github.com/coreos/go-iptables v0.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/distribution/reference v0.5.0 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect - github.com/docker/distribution v2.8.2+incompatible // indirect + github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/go-units v0.4.0 // indirect github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect @@ -38,18 +39,18 @@ require ( github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gobwas/httphead v0.1.0 // indirect github.com/gobwas/pool v0.2.1 // indirect - github.com/gobwas/ws v1.3.0 // indirect + github.com/gobwas/ws v1.3.1 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/btree v1.1.2 // indirect - github.com/google/go-cmp v0.5.9 // indirect + github.com/google/go-cmp v0.6.0 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a // indirect + github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c // indirect github.com/josharian/native v1.1.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.16.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect github.com/mailru/easyjson v0.7.7 // indirect @@ -80,6 +81,7 @@ require ( github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.4 // indirect + github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c // indirect @@ -91,7 +93,7 @@ require ( github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // indirect github.com/samber/lo v1.38.1 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect - github.com/shirou/gopsutil/v3 v3.23.9 // indirect + github.com/shirou/gopsutil/v3 v3.23.10 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect @@ -105,17 +107,16 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zhangyunhao116/fastrand v0.3.0 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect - go.etcd.io/bbolt v1.3.7 // indirect go.uber.org/mock v0.3.0 // indirect go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect golang.org/x/crypto v0.15.0 // indirect - golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/mod v0.13.0 // indirect - golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.14.0 // indirect + golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/mod v0.14.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.14.0 // indirect + golang.org/x/tools v0.15.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect diff --git a/test/go.sum b/test/go.sum index 2e72ca34..98f88d6a 100644 --- a/test/go.sum +++ b/test/go.sum @@ -19,17 +19,19 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.12.0 h1:oQEuIQIXgYhe1v7sYUG0P9vtJTYZLLdA6tiQmrOB1mo= -github.com/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= +github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= +github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= +github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= -github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= +github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog= github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -60,8 +62,8 @@ github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0= -github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= +github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU= +github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -73,16 +75,17 @@ github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= -github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= +github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -93,8 +96,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= -github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= -github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= +github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -125,8 +128,8 @@ github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFk github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= -github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= -github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= +github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= +github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -164,6 +167,8 @@ github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1 github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= +github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= @@ -188,8 +193,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= -github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= +github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= +github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -233,8 +238,6 @@ github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtb github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= -go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= -go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= @@ -244,14 +247,14 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= +golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -261,8 +264,8 @@ golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -280,9 +283,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= +golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -294,8 +297,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= -golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= +golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= +golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= 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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= From 117228fa8c22f0673c1656959538b2d3de8953cb Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 18 Nov 2023 13:17:15 +0800 Subject: [PATCH 105/192] feat: support REJECT-DROP --- adapter/outbound/reject.go | 94 ++++++++++++++++++++++-------- adapter/outboundgroup/groupbase.go | 2 +- config/config.go | 1 + constant/adapters.go | 4 ++ 4 files changed, 77 insertions(+), 24 deletions(-) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index 5625f932..b564e28d 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -13,6 +13,7 @@ import ( type Reject struct { *Base + drop bool } type RejectOption struct { @@ -21,12 +22,18 @@ type RejectOption struct { // DialContext implements C.ProxyAdapter func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { + if r.drop { + return NewConn(dropConn{}, r), nil + } return NewConn(nopConn{}, r), nil } // ListenPacketContext implements C.ProxyAdapter func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - return newPacketConn(nopPacketConn{}, r), nil + if r.drop { + return newPacketConn(&dropPacketConn{}, r), nil + } + return newPacketConn(&nopPacketConn{}, r), nil } func NewRejectWithOption(option RejectOption) *Reject { @@ -50,6 +57,18 @@ func NewReject() *Reject { } } +func NewRejectDrop() *Reject { + return &Reject{ + Base: &Base{ + name: "REJECT-DROP", + tp: C.RejectDrop, + udp: true, + prefer: C.DualStack, + }, + drop: true, + } +} + func NewPass() *Reject { return &Reject{ Base: &Base{ @@ -63,35 +82,29 @@ func NewPass() *Reject { type nopConn struct{} -func (rw nopConn) Read(b []byte) (int, error) { - return 0, io.EOF -} +func (rw nopConn) Read(b []byte) (int, error) { return 0, io.EOF } -func (rw nopConn) ReadBuffer(buffer *buf.Buffer) error { - return io.EOF -} +func (rw nopConn) ReadBuffer(buffer *buf.Buffer) error { return io.EOF } -func (rw nopConn) Write(b []byte) (int, error) { - return 0, io.EOF -} - -func (rw nopConn) WriteBuffer(buffer *buf.Buffer) error { - return io.EOF -} - -func (rw nopConn) Close() error { return nil } -func (rw nopConn) LocalAddr() net.Addr { return nil } -func (rw nopConn) RemoteAddr() net.Addr { return nil } -func (rw nopConn) SetDeadline(time.Time) error { return nil } -func (rw nopConn) SetReadDeadline(time.Time) error { return nil } -func (rw nopConn) SetWriteDeadline(time.Time) error { return nil } +func (rw nopConn) Write(b []byte) (int, error) { return 0, io.EOF } +func (rw nopConn) WriteBuffer(buffer *buf.Buffer) error { return io.EOF } +func (rw nopConn) Close() error { return nil } +func (rw nopConn) LocalAddr() net.Addr { return nil } +func (rw nopConn) RemoteAddr() net.Addr { return nil } +func (rw nopConn) SetDeadline(time.Time) error { return nil } +func (rw nopConn) SetReadDeadline(time.Time) error { return nil } +func (rw nopConn) SetWriteDeadline(time.Time) error { return nil } var udpAddrIPv4Unspecified = &net.UDPAddr{IP: net.IPv4zero, Port: 0} type nopPacketConn struct{} -func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { return len(b), nil } -func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF } +func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + return len(b), nil +} +func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { + return 0, nil, io.EOF +} func (npc nopPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { return nil, nil, nil, io.EOF } @@ -100,3 +113,38 @@ func (npc nopPacketConn) LocalAddr() net.Addr { return udpAddrIPv4U func (npc nopPacketConn) SetDeadline(time.Time) error { return nil } func (npc nopPacketConn) SetReadDeadline(time.Time) error { return nil } func (npc nopPacketConn) SetWriteDeadline(time.Time) error { return nil } + +type dropConn struct{} + +func (rw dropConn) Read(b []byte) (int, error) { return 0, io.EOF } +func (rw dropConn) ReadBuffer(buffer *buf.Buffer) error { + time.Sleep(C.DefaultDropTime) + return io.EOF +} +func (rw dropConn) Write(b []byte) (int, error) { return 0, io.EOF } +func (rw dropConn) WriteBuffer(buffer *buf.Buffer) error { return io.EOF } +func (rw dropConn) Close() error { return nil } +func (rw dropConn) LocalAddr() net.Addr { return nil } +func (rw dropConn) RemoteAddr() net.Addr { return nil } +func (rw dropConn) SetDeadline(time.Time) error { return nil } +func (rw dropConn) SetReadDeadline(time.Time) error { return nil } +func (rw dropConn) SetWriteDeadline(time.Time) error { return nil } + +type dropPacketConn struct{} + +func (npc dropPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + time.Sleep(C.DefaultDropTime) + return len(b), nil +} +func (npc dropPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { + time.Sleep(C.DefaultDropTime) + return 0, nil, io.EOF +} +func (npc dropPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { + return nil, nil, nil, io.EOF +} +func (npc dropPacketConn) Close() error { return nil } +func (npc dropPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } +func (npc dropPacketConn) SetDeadline(time.Time) error { return nil } +func (npc dropPacketConn) SetReadDeadline(time.Time) error { return nil } +func (npc dropPacketConn) SetWriteDeadline(time.Time) error { return nil } diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index d4a812f6..8f5f92df 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -222,7 +222,7 @@ func (gb *GroupBase) URLTest(ctx context.Context, url string, expectedStatus uti } func (gb *GroupBase) onDialFailed(adapterType C.AdapterType, err error) { - if adapterType == C.Direct || adapterType == C.Compatible || adapterType == C.Reject || adapterType == C.Pass { + if adapterType == C.Direct || adapterType == C.Compatible || adapterType == C.Reject || adapterType == C.Pass || adapterType == C.RejectDrop { return } diff --git a/config/config.go b/config/config.go index c2b389c3..0158ac71 100644 --- a/config/config.go +++ b/config/config.go @@ -673,6 +673,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[ proxies["DIRECT"] = adapter.NewProxy(outbound.NewDirect()) proxies["REJECT"] = adapter.NewProxy(outbound.NewReject()) + proxies["REJECT-DROP"] = adapter.NewProxy(outbound.NewRejectDrop()) proxies["COMPATIBLE"] = adapter.NewProxy(outbound.NewCompatible()) proxies["PASS"] = adapter.NewProxy(outbound.NewPass()) proxyList = append(proxyList, "DIRECT", "REJECT") diff --git a/constant/adapters.go b/constant/adapters.go index 5cf6e07c..757068f3 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -18,6 +18,7 @@ import ( const ( Direct AdapterType = iota Reject + RejectDrop Compatible Pass @@ -43,6 +44,7 @@ const ( const ( DefaultTCPTimeout = 5 * time.Second + DefaultDropTime = 12 * DefaultTCPTimeout DefaultUDPTimeout = DefaultTCPTimeout DefaultTLSTimeout = DefaultTCPTimeout DefaultMaxHealthCheckUrlNum = 16 @@ -179,6 +181,8 @@ func (at AdapterType) String() string { return "Direct" case Reject: return "Reject" + case RejectDrop: + return "RejectDrop" case Compatible: return "Compatible" case Pass: From 05b9071ca6e8baacd74271a814077dbeb7bcaacc Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 18 Nov 2023 13:50:32 +0800 Subject: [PATCH 106/192] chore: Pool allocate arrays instead of slices This is inspired by https://go-review.googlesource.com/c/net/+/539915 --- common/pool/alloc.go | 118 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 15 deletions(-) diff --git a/common/pool/alloc.go b/common/pool/alloc.go index 5722b047..ee3fa1a1 100644 --- a/common/pool/alloc.go +++ b/common/pool/alloc.go @@ -12,22 +12,34 @@ var defaultAllocator = NewAllocator() // Allocator for incoming frames, optimized to prevent overwriting after zeroing type Allocator struct { - buffers []sync.Pool + buffers [17]sync.Pool } // NewAllocator initiates a []byte allocator for frames less than 65536 bytes, // the waste(memory fragmentation) of space allocation is guaranteed to be // no more than 50%. func NewAllocator() *Allocator { - alloc := new(Allocator) - alloc.buffers = make([]sync.Pool, 17) // 1B -> 64K - for k := range alloc.buffers { - i := k - alloc.buffers[k].New = func() any { - return make([]byte, 1< 64K + {New: func() any { return new([1]byte) }}, + {New: func() any { return new([1 << 1]byte) }}, + {New: func() any { return new([1 << 2]byte) }}, + {New: func() any { return new([1 << 3]byte) }}, + {New: func() any { return new([1 << 4]byte) }}, + {New: func() any { return new([1 << 5]byte) }}, + {New: func() any { return new([1 << 6]byte) }}, + {New: func() any { return new([1 << 7]byte) }}, + {New: func() any { return new([1 << 8]byte) }}, + {New: func() any { return new([1 << 9]byte) }}, + {New: func() any { return new([1 << 10]byte) }}, + {New: func() any { return new([1 << 11]byte) }}, + {New: func() any { return new([1 << 12]byte) }}, + {New: func() any { return new([1 << 13]byte) }}, + {New: func() any { return new([1 << 14]byte) }}, + {New: func() any { return new([1 << 15]byte) }}, + {New: func() any { return new([1 << 16]byte) }}, + }, } - return alloc } // Get a []byte from pool with most appropriate cap @@ -40,12 +52,50 @@ func (alloc *Allocator) Get(size int) []byte { case size > 65536: return make([]byte, size) default: - bits := msb(size) - if size == 1< 65536 { return nil } - + bits := msb(cap(buf)) if cap(buf) != 1< Date: Sat, 18 Nov 2023 15:30:35 +0800 Subject: [PATCH 107/192] fix: Mux missing sing logger & initializing race --- adapter/outbound/singmux.go | 2 ++ listener/sing/sing.go | 24 +++++++++--------------- listener/sing_hysteria2/server.go | 4 ++++ listener/sing_shadowsocks/server.go | 4 ++++ listener/sing_tun/server.go | 4 ++++ listener/sing_vmess/server.go | 4 ++++ listener/tuic/server.go | 4 ++++ 7 files changed, 31 insertions(+), 15 deletions(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index 292ad1d8..e9dc660b 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -10,6 +10,7 @@ import ( "github.com/metacubex/mihomo/component/proxydialer" "github.com/metacubex/mihomo/component/resolver" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" mux "github.com/sagernet/sing-mux" E "github.com/sagernet/sing/common/exceptions" @@ -107,6 +108,7 @@ func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.P singDialer := proxydialer.NewSingDialer(proxy, dialer.NewDialer(), option.Statistic) client, err := mux.NewClient(mux.Options{ Dialer: singDialer, + Logger: log.SingLogger, Protocol: option.Protocol, MaxConnections: option.MaxConnections, MinStreams: option.MinStreams, diff --git a/listener/sing/sing.go b/listener/sing/sing.go index deec7bf8..990bbb14 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -31,7 +31,7 @@ type ListenerHandler struct { Type C.Type Additions []inbound.Addition UDPTimeout time.Duration - MuxService *mux.Service + muxService *mux.Service } func UpstreamMetadata(metadata M.Metadata) M.Metadata { @@ -49,8 +49,8 @@ func ConvertMetadata(metadata *C.Metadata) M.Metadata { } } -func (h *ListenerHandler) ConfigureSingMux() (err error) { - h.MuxService, err = mux.NewService(mux.ServiceOptions{ +func (h *ListenerHandler) Initialize() (err error) { + h.muxService, err = mux.NewService(mux.ServiceOptions{ NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context { return ctx }, @@ -65,26 +65,20 @@ func (h *ListenerHandler) ConfigureSingMux() (err error) { func (h *ListenerHandler) IsSpecialFqdn(fqdn string) bool { switch fqdn { - case mux.Destination.Fqdn: - case vmess.MuxDestination.Fqdn: - case uot.MagicAddress: - case uot.LegacyMagicAddress: + case mux.Destination.Fqdn, + vmess.MuxDestination.Fqdn, + uot.MagicAddress, + uot.LegacyMagicAddress: + return true default: return false } - return true } func (h *ListenerHandler) ParseSpecialFqdn(ctx context.Context, conn net.Conn, metadata M.Metadata) error { switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: - if h.MuxService == nil { - err := h.ConfigureSingMux() - if err != nil { - return err - } - } - return h.MuxService.NewConnection(ctx, conn, UpstreamMetadata(metadata)) + return h.muxService.NewConnection(ctx, conn, UpstreamMetadata(metadata)) case vmess.MuxDestination.Fqdn: return vmess.HandleMuxConnection(ctx, conn, h) case uot.MagicAddress: diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 96553995..f6c646a8 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -47,6 +47,10 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi Type: C.HYSTERIA2, Additions: additions, } + err = h.Initialize() + if err != nil { + return nil, err + } sl = &Listener{false, config, nil, nil} diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 5a4896af..af122775 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -55,6 +55,10 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi Type: C.SHADOWSOCKS, Additions: additions, } + err = h.Initialize() + if err != nil { + return nil, err + } sl = &Listener{false, config, nil, nil, nil} diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 212c3d90..5b28da04 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -159,6 +159,10 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis }, DnsAdds: dnsAdds, } + err = handler.Initialize() + if err != nil { + return nil, err + } l = &Listener{ closed: false, options: options, diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index e790e3bc..d444a53e 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -45,6 +45,10 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) Type: C.VMESS, Additions: additions, } + err = h.Initialize() + if err != nil { + return nil, err + } service := vmess.NewService[string](h, vmess.ServiceWithDisableHeaderProtection(), vmess.ServiceWithTimeFunc(ntp.Now)) err = service.UpdateUsers( diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 7fa7b18e..36d86e7f 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -43,6 +43,10 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( Type: C.TUIC, Additions: additions, } + err := h.Initialize() + if err != nil { + return nil, err + } cert, err := CN.ParseCert(config.Certificate, config.PrivateKey, C.Path) if err != nil { From 3c088b33a234395e2fdd5cb7c99fb8689b549976 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 18 Nov 2023 21:40:50 +0800 Subject: [PATCH 108/192] chore: Shrink allocator pool range --- common/pool/alloc.go | 85 ++++++++++++++------------------------- common/pool/alloc_test.go | 4 +- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/common/pool/alloc.go b/common/pool/alloc.go index ee3fa1a1..0a629403 100644 --- a/common/pool/alloc.go +++ b/common/pool/alloc.go @@ -12,7 +12,7 @@ var defaultAllocator = NewAllocator() // Allocator for incoming frames, optimized to prevent overwriting after zeroing type Allocator struct { - buffers [17]sync.Pool + buffers [11]sync.Pool } // NewAllocator initiates a []byte allocator for frames less than 65536 bytes, @@ -20,13 +20,7 @@ type Allocator struct { // no more than 50%. func NewAllocator() *Allocator { return &Allocator{ - buffers: [...]sync.Pool{ // 1B -> 64K - {New: func() any { return new([1]byte) }}, - {New: func() any { return new([1 << 1]byte) }}, - {New: func() any { return new([1 << 2]byte) }}, - {New: func() any { return new([1 << 3]byte) }}, - {New: func() any { return new([1 << 4]byte) }}, - {New: func() any { return new([1 << 5]byte) }}, + buffers: [...]sync.Pool{ // 64B -> 64K {New: func() any { return new([1 << 6]byte) }}, {New: func() any { return new([1 << 7]byte) }}, {New: func() any { return new([1 << 8]byte) }}, @@ -52,46 +46,38 @@ func (alloc *Allocator) Get(size int) []byte { case size > 65536: return make([]byte, size) default: - index := msb(size) - if size != 1< 64 { + index = msb(size) + if size != 1< Date: Sun, 19 Nov 2023 13:26:53 +0800 Subject: [PATCH 109/192] chore: temporary seal --- adapter/outbound/singmux.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index e9dc660b..67267744 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -102,9 +102,9 @@ func closeSingMux(s *SingMux) { } func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) { - if !mux.BrutalAvailable && option.BrutalOpts.Enabled { - return nil, errors.New("TCP Brutal is only supported on Linux-based systems") - } + // TODO + // "TCP Brutal is only supported on Linux-based systems" + singDialer := proxydialer.NewSingDialer(proxy, dialer.NewDialer(), option.Statistic) client, err := mux.NewClient(mux.Options{ Dialer: singDialer, From 84299606f43adb686d3d20ff60cb726f2c3d4360 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Sun, 19 Nov 2023 18:23:48 +0800 Subject: [PATCH 110/192] chore: revert default global ua --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 0158ac71..e8cc0198 100644 --- a/config/config.go +++ b/config/config.go @@ -390,7 +390,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ProxyGroup: []map[string]any{}, TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, - GlobalUA: "mihomo", + GlobalUA: "clash.meta", Tun: RawTun{ Enable: false, Device: "", From b9d48f41158ebce4b2f6ffbdbce528ecee98eb0b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 20 Nov 2023 19:02:52 +0800 Subject: [PATCH 111/192] fix: parsing override --- adapter/provider/parser.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 09ae4332..a22492d2 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -27,11 +27,11 @@ type healthCheckSchema struct { } type OverrideSchema struct { - UDP *bool `proxy:"udp,omitempty"` - Up *string `proxy:"up,omitempty"` - Down *string `proxy:"down,omitempty"` + UDP *bool `provider:"udp,omitempty"` + Up *string `provider:"up,omitempty"` + Down *string `provider:"down,omitempty"` DialerProxy *string `provider:"dialer-proxy,omitempty"` - SkipCertVerify *bool `proxy:"skip-cert-verify,omitempty"` + SkipCertVerify *bool `provider:"skip-cert-verify,omitempty"` } type proxyProviderSchema struct { From bb9ad6cac075d55471b3a14f60b9d25c7a980461 Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 20 Nov 2023 22:19:38 +0800 Subject: [PATCH 112/192] fix: Trojan websocket header panic --- adapter/outbound/trojan.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index cd1dd28c..f03c3be9 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -57,6 +57,7 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) Port: port, Path: t.option.WSOpts.Path, V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade, + Headers: http.Header{}, } if t.option.SNI != "" { @@ -64,11 +65,9 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) } if len(t.option.WSOpts.Headers) != 0 { - header := http.Header{} for key, value := range t.option.WSOpts.Headers { - header.Add(key, value) + wsOpts.Headers.Add(key, value) } - wsOpts.Headers = header } return t.instance.StreamWebsocketConn(ctx, c, wsOpts) From a6b816b1c69abc1fffc9a686cac18196308d7c46 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 20 Nov 2023 14:40:21 +0800 Subject: [PATCH 113/192] chore: reduce memory alloc --- adapter/outbound/reject.go | 62 ++++++++++++++++---------------------- constant/adapters.go | 2 +- listener/sing/sing.go | 1 + 3 files changed, 28 insertions(+), 37 deletions(-) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index b564e28d..199c4452 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -23,7 +23,9 @@ type RejectOption struct { // DialContext implements C.ProxyAdapter func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { if r.drop { - return NewConn(dropConn{}, r), nil + c, _ := net.Pipe() + _ = c.SetDeadline(time.Now().Add(C.DefaultDropTime)) + return NewConn(c, r), nil } return NewConn(nopConn{}, r), nil } @@ -31,7 +33,11 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ... // ListenPacketContext implements C.ProxyAdapter func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { if r.drop { - return newPacketConn(&dropPacketConn{}, r), nil + c, _ := net.Pipe() + _ = c.SetDeadline(time.Now().Add(C.DefaultDropTime)) + pc := newDropPacketConnWrapper(c) + return newPacketConn(pc, r), nil + } return newPacketConn(&nopPacketConn{}, r), nil } @@ -99,12 +105,8 @@ var udpAddrIPv4Unspecified = &net.UDPAddr{IP: net.IPv4zero, Port: 0} type nopPacketConn struct{} -func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - return len(b), nil -} -func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - return 0, nil, io.EOF -} +func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { return len(b), nil } +func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF } func (npc nopPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { return nil, nil, nil, io.EOF } @@ -114,37 +116,25 @@ func (npc nopPacketConn) SetDeadline(time.Time) error { return nil } func (npc nopPacketConn) SetReadDeadline(time.Time) error { return nil } func (npc nopPacketConn) SetWriteDeadline(time.Time) error { return nil } -type dropConn struct{} - -func (rw dropConn) Read(b []byte) (int, error) { return 0, io.EOF } -func (rw dropConn) ReadBuffer(buffer *buf.Buffer) error { - time.Sleep(C.DefaultDropTime) - return io.EOF +type dropPacketConn struct { + conn net.Conn } -func (rw dropConn) Write(b []byte) (int, error) { return 0, io.EOF } -func (rw dropConn) WriteBuffer(buffer *buf.Buffer) error { return io.EOF } -func (rw dropConn) Close() error { return nil } -func (rw dropConn) LocalAddr() net.Addr { return nil } -func (rw dropConn) RemoteAddr() net.Addr { return nil } -func (rw dropConn) SetDeadline(time.Time) error { return nil } -func (rw dropConn) SetReadDeadline(time.Time) error { return nil } -func (rw dropConn) SetWriteDeadline(time.Time) error { return nil } -type dropPacketConn struct{} - -func (npc dropPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - time.Sleep(C.DefaultDropTime) +func newDropPacketConnWrapper(conn net.Conn) net.PacketConn { + return &dropPacketConn{conn} +} +func (dpc dropPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { return len(b), nil } -func (npc dropPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - time.Sleep(C.DefaultDropTime) - return 0, nil, io.EOF -} -func (npc dropPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { +func (dpc dropPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF } +func (dpc dropPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { return nil, nil, nil, io.EOF } -func (npc dropPacketConn) Close() error { return nil } -func (npc dropPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } -func (npc dropPacketConn) SetDeadline(time.Time) error { return nil } -func (npc dropPacketConn) SetReadDeadline(time.Time) error { return nil } -func (npc dropPacketConn) SetWriteDeadline(time.Time) error { return nil } +func (dpc dropPacketConn) Close() error { + dpc.conn = nil + return nil +} +func (dpc dropPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } +func (dpc dropPacketConn) SetDeadline(time.Time) error { return nil } +func (dpc dropPacketConn) SetReadDeadline(time.Time) error { return nil } +func (dpc dropPacketConn) SetWriteDeadline(time.Time) error { return nil } diff --git a/constant/adapters.go b/constant/adapters.go index 757068f3..a2fe15a2 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -44,7 +44,7 @@ const ( const ( DefaultTCPTimeout = 5 * time.Second - DefaultDropTime = 12 * DefaultTCPTimeout + DefaultDropTime = 30 * time.Second DefaultUDPTimeout = DefaultTCPTimeout DefaultTLSTimeout = DefaultTCPTimeout DefaultMaxHealthCheckUrlNum = 16 diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 990bbb14..017c3f79 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -129,6 +129,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. conn2 = nil }() var buff *buf.Buffer + defer buff.Release() newBuffer := func() *buf.Buffer { buff = buf.NewPacket() // do not use stack buffer return buff From b05cf14b986b49519d833eb789da704b66321f0b Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 20 Nov 2023 23:48:07 +0800 Subject: [PATCH 114/192] chore: Replace stack collection with list --- common/collections/stack.go | 56 ------------------------------------- rules/logic/logic.go | 13 +++++---- 2 files changed, 7 insertions(+), 62 deletions(-) delete mode 100644 common/collections/stack.go diff --git a/common/collections/stack.go b/common/collections/stack.go deleted file mode 100644 index 74673f9a..00000000 --- a/common/collections/stack.go +++ /dev/null @@ -1,56 +0,0 @@ -package collections - -import "sync" - -type ( - stack struct { - top *node - length int - lock *sync.RWMutex - } - - node struct { - value interface{} - prev *node - } -) - -// NewStack Create a new stack -func NewStack() *stack { - return &stack{nil, 0, &sync.RWMutex{}} -} - -// Len Return the number of items in the stack -func (this *stack) Len() int { - return this.length -} - -// Peek View the top item on the stack -func (this *stack) Peek() interface{} { - if this.length == 0 { - return nil - } - return this.top.value -} - -// Pop the top item of the stack and return it -func (this *stack) Pop() interface{} { - this.lock.Lock() - defer this.lock.Unlock() - if this.length == 0 { - return nil - } - n := this.top - this.top = n.prev - this.length-- - return n.value -} - -// Push a value onto the top of the stack -func (this *stack) Push(value interface{}) { - this.lock.Lock() - defer this.lock.Unlock() - n := &node{value, this.top} - this.top = n - this.length++ -} diff --git a/rules/logic/logic.go b/rules/logic/logic.go index 4256a200..fde96e19 100644 --- a/rules/logic/logic.go +++ b/rules/logic/logic.go @@ -2,10 +2,10 @@ package logic import ( "fmt" + list "github.com/bahlo/generic-list-go" "regexp" "strings" - "github.com/metacubex/mihomo/common/collections" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/rules/common" ) @@ -133,7 +133,7 @@ func (logic *Logic) payloadToRule(subPayload string, parseRule ParseRuleFunc) (C } func (logic *Logic) format(payload string) ([]Range, error) { - stack := collections.NewStack() + stack := list.New[Range]() num := 0 subRanges := make([]Range, 0) for i, c := range payload { @@ -144,15 +144,16 @@ func (logic *Logic) format(payload string) ([]Range, error) { } num++ - stack.Push(sr) + stack.PushBack(sr) } else if c == ')' { if stack.Len() == 0 { return nil, fmt.Errorf("missing '('") } - sr := stack.Pop().(Range) - sr.end = i - subRanges = append(subRanges, sr) + sr := stack.Back() + stack.Remove(sr) + sr.Value.end = i + subRanges = append(subRanges, sr.Value) } } From 6a3e28c3846a35db00a032067412573ea4a9a0be Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 21 Nov 2023 22:35:24 +0800 Subject: [PATCH 115/192] chore: print colored log --- log/log.go | 1 + 1 file changed, 1 insertion(+) diff --git a/log/log.go b/log/log.go index d431dcb1..d0c9b330 100644 --- a/log/log.go +++ b/log/log.go @@ -21,6 +21,7 @@ func init() { log.SetFormatter(&log.TextFormatter{ FullTimestamp: true, TimestampFormat: "2006-01-02T15:04:05.999999999Z07:00", + ForceColors: true, }) } From 8b4499e461c98fe730c2ac0fe2f0852bed72a110 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 22 Nov 2023 19:22:15 +0800 Subject: [PATCH 116/192] Revert "chore: reduce memory alloc" This reverts commit a6b816b1c69abc1fffc9a686cac18196308d7c46. --- adapter/outbound/reject.go | 62 ++++++++++++++++++++++---------------- constant/adapters.go | 2 +- listener/sing/sing.go | 1 - 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index 199c4452..b564e28d 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -23,9 +23,7 @@ type RejectOption struct { // DialContext implements C.ProxyAdapter func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { if r.drop { - c, _ := net.Pipe() - _ = c.SetDeadline(time.Now().Add(C.DefaultDropTime)) - return NewConn(c, r), nil + return NewConn(dropConn{}, r), nil } return NewConn(nopConn{}, r), nil } @@ -33,11 +31,7 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ... // ListenPacketContext implements C.ProxyAdapter func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { if r.drop { - c, _ := net.Pipe() - _ = c.SetDeadline(time.Now().Add(C.DefaultDropTime)) - pc := newDropPacketConnWrapper(c) - return newPacketConn(pc, r), nil - + return newPacketConn(&dropPacketConn{}, r), nil } return newPacketConn(&nopPacketConn{}, r), nil } @@ -105,8 +99,12 @@ var udpAddrIPv4Unspecified = &net.UDPAddr{IP: net.IPv4zero, Port: 0} type nopPacketConn struct{} -func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { return len(b), nil } -func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF } +func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + return len(b), nil +} +func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { + return 0, nil, io.EOF +} func (npc nopPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { return nil, nil, nil, io.EOF } @@ -116,25 +114,37 @@ func (npc nopPacketConn) SetDeadline(time.Time) error { return nil } func (npc nopPacketConn) SetReadDeadline(time.Time) error { return nil } func (npc nopPacketConn) SetWriteDeadline(time.Time) error { return nil } -type dropPacketConn struct { - conn net.Conn -} +type dropConn struct{} -func newDropPacketConnWrapper(conn net.Conn) net.PacketConn { - return &dropPacketConn{conn} +func (rw dropConn) Read(b []byte) (int, error) { return 0, io.EOF } +func (rw dropConn) ReadBuffer(buffer *buf.Buffer) error { + time.Sleep(C.DefaultDropTime) + return io.EOF } -func (dpc dropPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { +func (rw dropConn) Write(b []byte) (int, error) { return 0, io.EOF } +func (rw dropConn) WriteBuffer(buffer *buf.Buffer) error { return io.EOF } +func (rw dropConn) Close() error { return nil } +func (rw dropConn) LocalAddr() net.Addr { return nil } +func (rw dropConn) RemoteAddr() net.Addr { return nil } +func (rw dropConn) SetDeadline(time.Time) error { return nil } +func (rw dropConn) SetReadDeadline(time.Time) error { return nil } +func (rw dropConn) SetWriteDeadline(time.Time) error { return nil } + +type dropPacketConn struct{} + +func (npc dropPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + time.Sleep(C.DefaultDropTime) return len(b), nil } -func (dpc dropPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF } -func (dpc dropPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { +func (npc dropPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { + time.Sleep(C.DefaultDropTime) + return 0, nil, io.EOF +} +func (npc dropPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { return nil, nil, nil, io.EOF } -func (dpc dropPacketConn) Close() error { - dpc.conn = nil - return nil -} -func (dpc dropPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } -func (dpc dropPacketConn) SetDeadline(time.Time) error { return nil } -func (dpc dropPacketConn) SetReadDeadline(time.Time) error { return nil } -func (dpc dropPacketConn) SetWriteDeadline(time.Time) error { return nil } +func (npc dropPacketConn) Close() error { return nil } +func (npc dropPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } +func (npc dropPacketConn) SetDeadline(time.Time) error { return nil } +func (npc dropPacketConn) SetReadDeadline(time.Time) error { return nil } +func (npc dropPacketConn) SetWriteDeadline(time.Time) error { return nil } diff --git a/constant/adapters.go b/constant/adapters.go index a2fe15a2..757068f3 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -44,7 +44,7 @@ const ( const ( DefaultTCPTimeout = 5 * time.Second - DefaultDropTime = 30 * time.Second + DefaultDropTime = 12 * DefaultTCPTimeout DefaultUDPTimeout = DefaultTCPTimeout DefaultTLSTimeout = DefaultTCPTimeout DefaultMaxHealthCheckUrlNum = 16 diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 017c3f79..990bbb14 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -129,7 +129,6 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. conn2 = nil }() var buff *buf.Buffer - defer buff.Release() newBuffer := func() *buf.Buffer { buff = buf.NewPacket() // do not use stack buffer return buff From 96f0254a4858f2e70b419a7f4be9f87096386816 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Nov 2023 08:20:26 +0800 Subject: [PATCH 117/192] chore: listeners can set `mux-option` --- listener/config/hysteria2.go | 7 ++++++- listener/config/shadowsocks.go | 13 ++++++++----- listener/config/tuic.go | 3 +++ listener/config/vmess.go | 3 +++ listener/inbound/hysteria2.go | 2 ++ listener/inbound/mux.go | 25 +++++++++++++++++++++++++ listener/inbound/shadowsocks.go | 18 ++++++++++-------- listener/inbound/tuic.go | 2 ++ listener/inbound/vmess.go | 2 ++ listener/sing/sing.go | 29 +++++++++++++++++++++++++---- listener/sing_hysteria2/server.go | 6 +++--- listener/sing_shadowsocks/server.go | 6 +++--- listener/sing_tun/dns.go | 2 +- listener/sing_tun/server.go | 21 ++++++++++----------- listener/sing_vmess/server.go | 6 +++--- listener/tuic/server.go | 6 +++--- 16 files changed, 109 insertions(+), 42 deletions(-) create mode 100644 listener/inbound/mux.go diff --git a/listener/config/hysteria2.go b/listener/config/hysteria2.go index 5520babc..898204c6 100644 --- a/listener/config/hysteria2.go +++ b/listener/config/hysteria2.go @@ -1,6 +1,10 @@ package config -import "encoding/json" +import ( + "github.com/metacubex/mihomo/listener/sing" + + "encoding/json" +) type Hysteria2Server struct { Enable bool `yaml:"enable" json:"enable"` @@ -17,6 +21,7 @@ type Hysteria2Server struct { IgnoreClientBandwidth bool `yaml:"ignore-client-bandwidth" json:"ignore-client-bandwidth,omitempty"` Masquerade string `yaml:"masquerade" json:"masquerade,omitempty"` CWND int `yaml:"cwnd" json:"cwnd,omitempty"` + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (h Hysteria2Server) String() string { diff --git a/listener/config/shadowsocks.go b/listener/config/shadowsocks.go index 60540bbd..c5c60f10 100644 --- a/listener/config/shadowsocks.go +++ b/listener/config/shadowsocks.go @@ -1,15 +1,18 @@ package config import ( + "github.com/metacubex/mihomo/listener/sing" + "encoding/json" ) type ShadowsocksServer struct { - Enable bool - Listen string - Password string - Cipher string - Udp bool + Enable bool + Listen string + Password string + Cipher string + Udp bool + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t ShadowsocksServer) String() string { diff --git a/listener/config/tuic.go b/listener/config/tuic.go index 191cb59c..14a46809 100644 --- a/listener/config/tuic.go +++ b/listener/config/tuic.go @@ -1,6 +1,8 @@ package config import ( + "github.com/metacubex/mihomo/listener/sing" + "encoding/json" ) @@ -18,6 +20,7 @@ type TuicServer struct { MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` MaxDatagramFrameSize int `yaml:"max-datagram-frame-size" json:"max-datagram-frame-size,omitempty"` CWND int `yaml:"cwnd" json:"cwnd,omitempty"` + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t TuicServer) String() string { diff --git a/listener/config/vmess.go b/listener/config/vmess.go index 1cf2d46c..810d6bc1 100644 --- a/listener/config/vmess.go +++ b/listener/config/vmess.go @@ -1,6 +1,8 @@ package config import ( + "github.com/metacubex/mihomo/listener/sing" + "encoding/json" ) @@ -17,6 +19,7 @@ type VmessServer struct { WsPath string Certificate string PrivateKey string + MuxOption sing.MuxOption `yaml:"mux-option" json:"mux-option,omitempty"` } func (t VmessServer) String() string { diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index 112d03f8..acd5f9a8 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -21,6 +21,7 @@ type Hysteria2Option struct { IgnoreClientBandwidth bool `inbound:"ignore-client-bandwidth,omitempty"` Masquerade string `inbound:"masquerade,omitempty"` CWND int `inbound:"cwnd,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } func (o Hysteria2Option) Equal(config C.InboundConfig) bool { @@ -57,6 +58,7 @@ func NewHysteria2(options *Hysteria2Option) (*Hysteria2, error) { IgnoreClientBandwidth: options.IgnoreClientBandwidth, Masquerade: options.Masquerade, CWND: options.CWND, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/inbound/mux.go b/listener/inbound/mux.go new file mode 100644 index 00000000..c4068e10 --- /dev/null +++ b/listener/inbound/mux.go @@ -0,0 +1,25 @@ +package inbound + +import "github.com/metacubex/mihomo/listener/sing" + +type MuxOption struct { + Padding bool `inbound:"padding,omitempty"` + Brutal BrutalOptions `inbound:"brutal,omitempty"` +} + +type BrutalOptions struct { + Enabled bool `inbound:"enabled,omitempty"` + Up string `inbound:"up,omitempty"` + Down string `inbound:"down,omitempty"` +} + +func (m MuxOption) Build() sing.MuxOption { + return sing.MuxOption{ + Padding: m.Padding, + Brutal: sing.BrutalOptions{ + Enabled: m.Brutal.Enabled, + Up: m.Brutal.Up, + Down: m.Brutal.Down, + }, + } +} diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index cb32dcfb..240e6419 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -9,9 +9,10 @@ import ( type ShadowSocksOption struct { BaseOption - Password string `inbound:"password"` - Cipher string `inbound:"cipher"` - UDP bool `inbound:"udp,omitempty"` + Password string `inbound:"password"` + Cipher string `inbound:"cipher"` + UDP bool `inbound:"udp,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } func (o ShadowSocksOption) Equal(config C.InboundConfig) bool { @@ -34,11 +35,12 @@ func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) { Base: base, config: options, ss: LC.ShadowsocksServer{ - Enable: true, - Listen: base.RawAddress(), - Password: options.Password, - Cipher: options.Cipher, - Udp: options.UDP, + Enable: true, + Listen: base.RawAddress(), + Password: options.Password, + Cipher: options.Cipher, + Udp: options.UDP, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index c2a73b84..562228ee 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -19,6 +19,7 @@ type TuicOption struct { ALPN []string `inbound:"alpn,omitempty"` MaxUdpRelayPacketSize int `inbound:"max-udp-relay-packet-size,omitempty"` CWND int `inbound:"cwnd,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } func (o TuicOption) Equal(config C.InboundConfig) bool { @@ -53,6 +54,7 @@ func NewTuic(options *TuicOption) (*Tuic, error) { ALPN: options.ALPN, MaxUdpRelayPacketSize: options.MaxUdpRelayPacketSize, CWND: options.CWND, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 3508aa3c..226a54d5 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -13,6 +13,7 @@ type VmessOption struct { WsPath string `inbound:"ws-path,omitempty"` Certificate string `inbound:"certificate,omitempty"` PrivateKey string `inbound:"private-key,omitempty"` + MuxOption MuxOption `inbound:"mux-option,omitempty"` } type VmessUser struct { @@ -55,6 +56,7 @@ func NewVmess(options *VmessOption) (*Vmess, error) { WsPath: options.WsPath, Certificate: options.Certificate, PrivateKey: options.PrivateKey, + MuxOption: options.MuxOption.Build(), }, }, nil } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 990bbb14..65c42b6a 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -9,6 +9,7 @@ import ( "time" "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/adapter/outbound" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" @@ -26,11 +27,27 @@ import ( const UDPTimeout = 5 * time.Minute -type ListenerHandler struct { +type ListenerConfig struct { Tunnel C.Tunnel Type C.Type Additions []inbound.Addition UDPTimeout time.Duration + MuxOption MuxOption +} + +type MuxOption struct { + Padding bool `yaml:"padding" json:"padding,omitempty"` + Brutal BrutalOptions `yaml:"brutal" json:"brutal,omitempty"` +} + +type BrutalOptions struct { + Enabled bool `yaml:"enabled" json:"enabled"` + Up string `yaml:"up" json:"up,omitempty"` + Down string `yaml:"down" json:"down,omitempty"` +} + +type ListenerHandler struct { + ListenerConfig muxService *mux.Service } @@ -49,15 +66,19 @@ func ConvertMetadata(metadata *C.Metadata) M.Metadata { } } -func (h *ListenerHandler) Initialize() (err error) { +func NewListenerHandler(lc ListenerConfig) (h *ListenerHandler, err error) { + h = &ListenerHandler{ListenerConfig: lc} h.muxService, err = mux.NewService(mux.ServiceOptions{ NewStreamContext: func(ctx context.Context, conn net.Conn) context.Context { return ctx }, Logger: log.SingLogger, Handler: h, - Brutal: mux.BrutalOptions{ - // TODO: sing-mux tcp brutal inbound + Padding: lc.MuxOption.Padding, + Brutal: mux.BrutalOptions{ + Enabled: lc.MuxOption.Brutal.Enabled, + SendBPS: outbound.StringToBps(lc.MuxOption.Brutal.Up), + ReceiveBPS: outbound.StringToBps(lc.MuxOption.Brutal.Down), }, }) return diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index f6c646a8..de4c95f5 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -42,12 +42,12 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi } } - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.HYSTERIA2, Additions: additions, - } - err = h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index af122775..1760e43c 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -50,12 +50,12 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi udpTimeout := int64(sing.UDPTimeout.Seconds()) - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.SHADOWSOCKS, Additions: additions, - } - err = h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 62a15c6c..122f5a32 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -26,7 +26,7 @@ const DefaultDnsReadTimeout = time.Second * 10 const DefaultDnsRelayTimeout = time.Second * 5 type ListenerHandler struct { - sing.ListenerHandler + *sing.ListenerHandler DnsAdds []netip.AddrPort } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 5b28da04..2017e922 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -8,7 +8,6 @@ import ( "runtime" "strconv" "strings" - "time" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/dialer" @@ -150,19 +149,19 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis dnsAdds = append(dnsAdds, addrPort) } - handler := &ListenerHandler{ - ListenerHandler: sing.ListenerHandler{ - Tunnel: tunnel, - Type: C.TUN, - Additions: additions, - UDPTimeout: time.Second * time.Duration(udpTimeout), - }, - DnsAdds: dnsAdds, - } - err = handler.Initialize() + h, err := sing.NewListenerHandler(sing.ListenerConfig{ + Tunnel: tunnel, + Type: C.TUN, + Additions: additions, + }) if err != nil { return nil, err } + + handler := &ListenerHandler{ + ListenerHandler: h, + DnsAdds: dnsAdds, + } l = &Listener{ closed: false, options: options, diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index d444a53e..ce422b16 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -40,12 +40,12 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) _listener = sl }() } - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.VMESS, Additions: additions, - } - err = h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 36d86e7f..5d807cbc 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -38,12 +38,12 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( inbound.WithSpecialRules(""), } } - h := &sing.ListenerHandler{ + h, err := sing.NewListenerHandler(sing.ListenerConfig{ Tunnel: tunnel, Type: C.TUIC, Additions: additions, - } - err := h.Initialize() + MuxOption: config.MuxOption, + }) if err != nil { return nil, err } From 37791acb5947e9b978f0494f3aa91eaadb2bdf46 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Nov 2023 10:24:01 +0800 Subject: [PATCH 118/192] chore: upgrade xsync to v3 --- adapter/adapter.go | 4 ++-- component/nat/table.go | 10 +++++----- go.mod | 2 +- go.sum | 4 ++-- transport/tuic/v4/client.go | 4 ++-- transport/tuic/v4/server.go | 4 ++-- transport/tuic/v5/client.go | 4 ++-- transport/tuic/v5/server.go | 4 ++-- tunnel/statistic/manager.go | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 74b11bd9..33f567c5 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -19,7 +19,7 @@ import ( C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" - "github.com/puzpuzpuz/xsync/v2" + "github.com/puzpuzpuz/xsync/v3" ) var UnifiedDelay = atomic.NewBool(false) @@ -316,7 +316,7 @@ func NewProxy(adapter C.ProxyAdapter) *Proxy { history: queue.New[C.DelayHistory](defaultHistoriesNum), alive: atomic.NewBool(true), url: "", - extra: xsync.NewMapOf[*extraProxyState]()} + extra: xsync.NewMapOf[string, *extraProxyState]()} } func urlToMetadata(rawURL string) (addr C.Metadata, err error) { diff --git a/component/nat/table.go b/component/nat/table.go index b2908c94..bb5ab755 100644 --- a/component/nat/table.go +++ b/component/nat/table.go @@ -6,7 +6,7 @@ import ( C "github.com/metacubex/mihomo/constant" - "github.com/puzpuzpuz/xsync/v2" + "github.com/puzpuzpuz/xsync/v3" ) type Table struct { @@ -25,8 +25,8 @@ func (t *Table) Set(key string, e C.PacketConn, w C.WriteBackProxy) { t.mapping.Store(key, &Entry{ PacketConn: e, WriteBackProxy: w, - LocalUDPConnMap: xsync.NewMapOf[*net.UDPConn](), - LocalLockMap: xsync.NewMapOf[*sync.Cond](), + LocalUDPConnMap: xsync.NewMapOf[string, *net.UDPConn](), + LocalLockMap: xsync.NewMapOf[string, *sync.Cond](), }) } @@ -116,7 +116,7 @@ func makeLock() *sync.Cond { // New return *Cache func New() *Table { return &Table{ - mapping: xsync.NewMapOf[*Entry](), - lockMap: xsync.NewMapOf[*sync.Cond](), + mapping: xsync.NewMapOf[string, *Entry](), + lockMap: xsync.NewMapOf[string, *sync.Cond](), } } diff --git a/go.mod b/go.mod index 8e86bb85..5bd66cd0 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 - github.com/puzpuzpuz/xsync/v2 v2.5.1 + github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c diff --git a/go.sum b/go.sum index 7fddd84e..3a606050 100644 --- a/go.sum +++ b/go.sum @@ -145,8 +145,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= -github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew= +github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index 0bc8f9bb..a553db82 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -22,7 +22,7 @@ import ( "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" - "github.com/puzpuzpuz/xsync/v2" + "github.com/puzpuzpuz/xsync/v3" "github.com/zhangyunhao116/fastrand" ) @@ -469,7 +469,7 @@ func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client ClientOption: clientOption, udp: udp, dialerRef: dialerRef, - udpInputMap: xsync.NewIntegerMapOf[uint32, net.Conn](), + udpInputMap: xsync.NewMapOf[uint32, net.Conn](), } c := &Client{ci} runtime.SetFinalizer(c, closeClient) diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index c4e4d735..2430866f 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -17,7 +17,7 @@ import ( "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" - "github.com/puzpuzpuz/xsync/v2" + "github.com/puzpuzpuz/xsync/v3" ) type ServerOption struct { @@ -34,7 +34,7 @@ func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid quicConn: quicConn, uuid: uuid, authCh: make(chan struct{}), - udpInputMap: xsync.NewIntegerMapOf[uint32, *atomic.Bool](), + udpInputMap: xsync.NewMapOf[uint32, *atomic.Bool](), } } diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index e37d60fc..81da80e7 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -20,7 +20,7 @@ import ( "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" - "github.com/puzpuzpuz/xsync/v2" + "github.com/puzpuzpuz/xsync/v3" "github.com/zhangyunhao116/fastrand" ) @@ -406,7 +406,7 @@ func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client ClientOption: clientOption, udp: udp, dialerRef: dialerRef, - udpInputMap: *xsync.NewIntegerMapOf[uint16, net.Conn](), + udpInputMap: *xsync.NewMapOf[uint16, net.Conn](), } c := &Client{ci} runtime.SetFinalizer(c, closeClient) diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index c8170f62..8454b64c 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -16,7 +16,7 @@ import ( "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" - "github.com/puzpuzpuz/xsync/v2" + "github.com/puzpuzpuz/xsync/v3" ) type ServerOption struct { @@ -33,7 +33,7 @@ func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid quicConn: quicConn, uuid: uuid, authCh: make(chan struct{}), - udpInputMap: xsync.NewIntegerMapOf[uint16, *serverUDPInput](), + udpInputMap: xsync.NewMapOf[uint16, *serverUDPInput](), } } diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 8e962dae..08747118 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -6,7 +6,7 @@ import ( "github.com/metacubex/mihomo/common/atomic" - "github.com/puzpuzpuz/xsync/v2" + "github.com/puzpuzpuz/xsync/v3" "github.com/shirou/gopsutil/v3/process" ) @@ -14,7 +14,7 @@ var DefaultManager *Manager func init() { DefaultManager = &Manager{ - connections: xsync.NewMapOf[Tracker](), + connections: xsync.NewMapOf[string, Tracker](), uploadTemp: atomic.NewInt64(0), downloadTemp: atomic.NewInt64(0), uploadBlip: atomic.NewInt64(0), From 7d15ce2b33cc0bfc7bbe8dd30f5e5709aa7cd8b5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Nov 2023 10:39:29 +0800 Subject: [PATCH 119/192] chore: add some warning log --- dns/resolver.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dns/resolver.go b/dns/resolver.go index 368f0b41..fa11830e 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -488,6 +488,8 @@ func NewResolver(config Config) *Resolver { dnsClients: cacheTransform(nameserver), }) continue + } else { + log.Warnln("can't found ruleset policy: %s", key) } case "geosite": inverse := false @@ -498,6 +500,7 @@ func NewResolver(config Config) *Resolver { log.Debugln("adding geosite policy: %s inversed %t", key, inverse) matcher, err := NewGeoSite(key) if err != nil { + log.Warnln("adding geosite policy %s error: %s", key) continue } insertTriePolicy() @@ -506,7 +509,7 @@ func NewResolver(config Config) *Resolver { inverse: inverse, dnsClients: cacheTransform(nameserver), }) - continue + continue // skip triePolicy new } } if triePolicy == nil { From 84a334dd3aeaa7447a7cfa67cda2998764ce25df Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Nov 2023 22:39:47 +0800 Subject: [PATCH 120/192] chore: reorder atomic TypedValue see: https://gfw.go101.org/article/unofficial-faq.html#final-zero-size-field --- common/atomic/value.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/atomic/value.go b/common/atomic/value.go index 708fcf90..cbc6c5b8 100644 --- a/common/atomic/value.go +++ b/common/atomic/value.go @@ -11,8 +11,8 @@ func DefaultValue[T any]() T { } type TypedValue[T any] struct { - value atomic.Value _ noCopy + value atomic.Value } func (t *TypedValue[T]) Load() T { From 5f7053c519b16888f9f2ded3c84bef4246274f69 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 24 Nov 2023 13:02:00 +0800 Subject: [PATCH 121/192] feat: Add v2ray httpupgrade fast open support --- adapter/outbound/shadowsocks.go | 30 ++++++------- adapter/outbound/trojan.go | 11 ++--- adapter/outbound/vless.go | 17 ++++---- adapter/outbound/vmess.go | 28 +++++++------ transport/trojan/trojan.go | 28 +++++++------ transport/v2ray-plugin/websocket.go | 30 ++++++------- transport/vmess/httpupgrade.go | 65 +++++++++++++++++++++++++++++ transport/vmess/websocket.go | 28 ++++++++----- 8 files changed, 160 insertions(+), 77 deletions(-) create mode 100644 transport/vmess/httpupgrade.go diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index ffc72abb..859a10d6 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -58,15 +58,16 @@ type simpleObfsOption struct { } type v2rayObfsOption struct { - Mode string `obfs:"mode"` - Host string `obfs:"host,omitempty"` - Path string `obfs:"path,omitempty"` - TLS bool `obfs:"tls,omitempty"` - Fingerprint string `obfs:"fingerprint,omitempty"` - Headers map[string]string `obfs:"headers,omitempty"` - SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` - Mux bool `obfs:"mux,omitempty"` - V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"` + Mode string `obfs:"mode"` + Host string `obfs:"host,omitempty"` + Path string `obfs:"path,omitempty"` + TLS bool `obfs:"tls,omitempty"` + Fingerprint string `obfs:"fingerprint,omitempty"` + Headers map[string]string `obfs:"headers,omitempty"` + SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Mux bool `obfs:"mux,omitempty"` + V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"` + V2rayHttpUpgradeFastOpen bool `obfs:"v2ray-http-upgrade-fast-open,omitempty"` } type shadowTLSOption struct { @@ -260,11 +261,12 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } obfsMode = opts.Mode v2rayOption = &v2rayObfs.Option{ - Host: opts.Host, - Path: opts.Path, - Headers: opts.Headers, - Mux: opts.Mux, - V2rayHttpUpgrade: opts.V2rayHttpUpgrade, + Host: opts.Host, + Path: opts.Path, + Headers: opts.Headers, + Mux: opts.Mux, + V2rayHttpUpgrade: opts.V2rayHttpUpgrade, + V2rayHttpUpgradeFastOpen: opts.V2rayHttpUpgradeFastOpen, } if opts.TLS { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index f03c3be9..b14761a4 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -53,11 +53,12 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) if t.option.Network == "ws" { host, port, _ := net.SplitHostPort(t.addr) wsOpts := &trojan.WebsocketOption{ - Host: host, - Port: port, - Path: t.option.WSOpts.Path, - V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade, - Headers: http.Header{}, + Host: host, + Port: port, + Path: t.option.WSOpts.Path, + V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade, + V2rayHttpUpgradeFastOpen: t.option.WSOpts.V2rayHttpUpgradeFastOpen, + Headers: http.Header{}, } if t.option.SNI != "" { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index dbe8b1a4..ceeb52a5 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -88,14 +88,15 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M case "ws": host, port, _ := net.SplitHostPort(v.addr) wsOpts := &vmess.WebsocketConfig{ - Host: host, - Port: port, - Path: v.option.WSOpts.Path, - MaxEarlyData: v.option.WSOpts.MaxEarlyData, - EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, - V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, - ClientFingerprint: v.option.ClientFingerprint, - Headers: http.Header{}, + Host: host, + Port: port, + Path: v.option.WSOpts.Path, + MaxEarlyData: v.option.WSOpts.MaxEarlyData, + EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, + V2rayHttpUpgradeFastOpen: v.option.WSOpts.V2rayHttpUpgradeFastOpen, + ClientFingerprint: v.option.ClientFingerprint, + Headers: http.Header{}, } if len(v.option.WSOpts.Headers) != 0 { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 8811fb0d..c1c981ce 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -87,11 +87,12 @@ type GrpcOptions struct { } type WSOptions struct { - Path string `proxy:"path,omitempty"` - Headers map[string]string `proxy:"headers,omitempty"` - MaxEarlyData int `proxy:"max-early-data,omitempty"` - EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` - V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"` + Path string `proxy:"path,omitempty"` + Headers map[string]string `proxy:"headers,omitempty"` + MaxEarlyData int `proxy:"max-early-data,omitempty"` + EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` + V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"` + V2rayHttpUpgradeFastOpen bool `proxy:"v2ray-http-upgrade-fast-open,omitempty"` } // StreamConnContext implements C.ProxyAdapter @@ -106,14 +107,15 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M case "ws": host, port, _ := net.SplitHostPort(v.addr) wsOpts := &mihomoVMess.WebsocketConfig{ - Host: host, - Port: port, - Path: v.option.WSOpts.Path, - MaxEarlyData: v.option.WSOpts.MaxEarlyData, - EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, - V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, - ClientFingerprint: v.option.ClientFingerprint, - Headers: http.Header{}, + Host: host, + Port: port, + Path: v.option.WSOpts.Path, + MaxEarlyData: v.option.WSOpts.MaxEarlyData, + EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, + V2rayHttpUpgradeFastOpen: v.option.WSOpts.V2rayHttpUpgradeFastOpen, + ClientFingerprint: v.option.ClientFingerprint, + Headers: http.Header{}, } if len(v.option.WSOpts.Headers) != 0 { diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index c4bd1167..09be1124 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -55,11 +55,12 @@ type Option struct { } type WebsocketOption struct { - Host string - Port string - Path string - Headers http.Header - V2rayHttpUpgrade bool + Host string + Port string + Path string + Headers http.Header + V2rayHttpUpgrade bool + V2rayHttpUpgradeFastOpen bool } type Trojan struct { @@ -129,14 +130,15 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio } return vmess.StreamWebsocketConn(ctx, conn, &vmess.WebsocketConfig{ - Host: wsOptions.Host, - Port: wsOptions.Port, - Path: wsOptions.Path, - Headers: wsOptions.Headers, - V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade, - TLS: true, - TLSConfig: tlsConfig, - ClientFingerprint: t.option.ClientFingerprint, + Host: wsOptions.Host, + Port: wsOptions.Port, + Path: wsOptions.Path, + Headers: wsOptions.Headers, + V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade, + V2rayHttpUpgradeFastOpen: wsOptions.V2rayHttpUpgradeFastOpen, + TLS: true, + TLSConfig: tlsConfig, + ClientFingerprint: t.option.ClientFingerprint, }) } diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 1c7056d6..90ff5efe 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -12,15 +12,16 @@ import ( // Option is options of websocket obfs type Option struct { - Host string - Port string - Path string - Headers map[string]string - TLS bool - SkipCertVerify bool - Fingerprint string - Mux bool - V2rayHttpUpgrade bool + Host string + Port string + Path string + Headers map[string]string + TLS bool + SkipCertVerify bool + Fingerprint string + Mux bool + V2rayHttpUpgrade bool + V2rayHttpUpgradeFastOpen bool } // NewV2rayObfs return a HTTPObfs @@ -31,11 +32,12 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, } config := &vmess.WebsocketConfig{ - Host: option.Host, - Port: option.Port, - Path: option.Path, - V2rayHttpUpgrade: option.V2rayHttpUpgrade, - Headers: header, + Host: option.Host, + Port: option.Port, + Path: option.Path, + V2rayHttpUpgrade: option.V2rayHttpUpgrade, + V2rayHttpUpgradeFastOpen: option.V2rayHttpUpgradeFastOpen, + Headers: header, } if option.TLS { diff --git a/transport/vmess/httpupgrade.go b/transport/vmess/httpupgrade.go new file mode 100644 index 00000000..f7e819db --- /dev/null +++ b/transport/vmess/httpupgrade.go @@ -0,0 +1,65 @@ +package vmess + +import ( + "fmt" + "net/http" + "strings" + "sync" + + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/common/net" +) + +type httpUpgradeEarlyConn struct { + *net.BufferedConn + create sync.Once + done bool + err error +} + +func (c *httpUpgradeEarlyConn) readResponse() { + var request http.Request + response, err := http.ReadResponse(c.Reader(), &request) + c.done = true + if err != nil { + c.err = err + return + } + if response.StatusCode != http.StatusSwitchingProtocols || + !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || + !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { + c.err = fmt.Errorf("unexpected status: %s", response.Status) + return + } +} + +func (c *httpUpgradeEarlyConn) Read(p []byte) (int, error) { + c.create.Do(c.readResponse) + if c.err != nil { + return 0, c.err + } + return c.BufferedConn.Read(p) +} + +func (c *httpUpgradeEarlyConn) ReadBuffer(buffer *buf.Buffer) error { + c.create.Do(c.readResponse) + if c.err != nil { + return c.err + } + return c.BufferedConn.ReadBuffer(buffer) +} + +func (c *httpUpgradeEarlyConn) ReaderReplaceable() bool { + return c.done +} + +func (c *httpUpgradeEarlyConn) ReaderPossiblyReplaceable() bool { + return !c.done +} + +func (c *httpUpgradeEarlyConn) ReadCached() *buf.Buffer { + if c.done { + return c.BufferedConn.ReadCached() + } + return nil +} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 8e675bb0..e898400c 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -49,16 +49,17 @@ type websocketWithEarlyDataConn struct { } type WebsocketConfig struct { - Host string - Port string - Path string - Headers http.Header - TLS bool - TLSConfig *tls.Config - MaxEarlyData int - EarlyDataHeaderName string - ClientFingerprint string - V2rayHttpUpgrade bool + Host string + Port string + Path string + Headers http.Header + TLS bool + TLSConfig *tls.Config + MaxEarlyData int + EarlyDataHeaderName string + ClientFingerprint string + V2rayHttpUpgrade bool + V2rayHttpUpgradeFastOpen bool } // Read implements net.Conn.Read() @@ -415,6 +416,13 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return nil, err } bufferedConn := N.NewBufferedConn(conn) + + if c.V2rayHttpUpgrade && c.V2rayHttpUpgradeFastOpen { + return &httpUpgradeEarlyConn{ + BufferedConn: bufferedConn, + }, nil + } + response, err := http.ReadResponse(bufferedConn.Reader(), request) if err != nil { return nil, err From db973de7bd3729220ed62f1156e3b73746fe00a3 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:04:41 +0800 Subject: [PATCH 122/192] chore: update dependencies --- test/go.mod | 2 +- test/go.sum | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/test/go.mod b/test/go.mod index d399e3eb..d62c4350 100644 --- a/test/go.mod +++ b/test/go.mod @@ -78,7 +78,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect - github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect + github.com/puzpuzpuz/xsync/v3 v3.0.2 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.3.4 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect diff --git a/test/go.sum b/test/go.sum index 98f88d6a..aaf9010e 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,28 +1,44 @@ github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08= github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM= github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/bazelbuild/rules_go v0.38.1/go.mod h1:TMHmtfpvyfsxaqfL9WnahCsXMWDMICTw7XeK9yVb+YU= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= +github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= +github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= +github.com/containerd/containerd v1.4.13/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= +github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= +github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= +github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= +github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= +github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -38,21 +54,30 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391/go.mod h1:K2R7GhgxrlJzHw2qiPWsCZXf/kXEJN9PLnQK73Ll0po= github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c h1:RUzBDdZ+e/HEe2Nh8lYsduiPAZygUfVXJn0Ncj5sHMg= +github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c/go.mod h1:ETASDWf/FmEb6Ysrtd1QhjNedUU/ZQxBCRLh60bQ/UI= github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBEz5nGDMvswiajqh7k8ogWRlhRwKy5mY= github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= +github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= +github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -64,13 +89,17 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU= github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -78,11 +107,19 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= +github.com/google/tink/go v1.6.1/go.mod h1:IGW53kTgag+st5yPhKKwJ6u2l+SSp5/v9XF7spovjlY= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/hanwen/go-fuse/v2 v2.3.0/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= @@ -92,6 +129,8 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= +github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= @@ -99,15 +138,20 @@ github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQs github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= @@ -132,6 +176,9 @@ github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= @@ -141,6 +188,7 @@ github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:U github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= +github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= @@ -150,6 +198,7 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= +github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= @@ -160,13 +209,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= -github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbAaew= +github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= @@ -207,6 +257,7 @@ github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIF github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -217,6 +268,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -224,6 +276,7 @@ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9f github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= @@ -232,12 +285,15 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= +go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= @@ -249,6 +305,7 @@ golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -261,6 +318,7 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -286,6 +344,7 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -303,14 +362,33 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= +google.golang.org/grpc v1.53.0-dev.0.20230123225046-4075ef07c5d5/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= +gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= +honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= +k8s.io/api v0.23.16/go.mod h1:Fk/eWEGf3ZYZTCVLbsgzlxekG6AtnT3QItT3eOSyFRE= +k8s.io/apimachinery v0.23.16/go.mod h1:RMMUoABRwnjoljQXKJ86jT5FkTZPPnZsNv70cMsKIP0= +k8s.io/client-go v0.23.16/go.mod h1:CUfIIQL+hpzxnD9nxiVGb99BNTp00mPFp3Pk26sTFys= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= +sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= From 599ce784d2289590ea2a87d0a28f2aa53121fd7f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 30 Nov 2023 20:00:24 +0800 Subject: [PATCH 123/192] chore: simplify fast open code --- common/net/earlyconn.go | 67 +++++++++++++++++++++++++++ transport/tuic/v4/client.go | 85 ++++++++-------------------------- transport/vmess/httpupgrade.go | 65 -------------------------- transport/vmess/websocket.go | 15 ++++-- 4 files changed, 98 insertions(+), 134 deletions(-) create mode 100644 common/net/earlyconn.go delete mode 100644 transport/vmess/httpupgrade.go diff --git a/common/net/earlyconn.go b/common/net/earlyconn.go new file mode 100644 index 00000000..c9a42819 --- /dev/null +++ b/common/net/earlyconn.go @@ -0,0 +1,67 @@ +package net + +import ( + "net" + "sync" + "sync/atomic" + "unsafe" + + "github.com/metacubex/mihomo/common/buf" +) + +type earlyConn struct { + ExtendedConn // only expose standard N.ExtendedConn function to outside + resFunc func() error + resOnce sync.Once + resErr error +} + +func (conn *earlyConn) Response() error { + conn.resOnce.Do(func() { + conn.resErr = conn.resFunc() + }) + return conn.resErr +} + +func (conn *earlyConn) Read(b []byte) (n int, err error) { + err = conn.Response() + if err != nil { + return 0, err + } + return conn.ExtendedConn.Read(b) +} + +func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) { + err = conn.Response() + if err != nil { + return err + } + return conn.ExtendedConn.ReadBuffer(buffer) +} + +func (conn *earlyConn) Upstream() any { + return conn.ExtendedConn +} + +func (conn *earlyConn) Success() bool { + // atomic visit sync.Once.done + return atomic.LoadUint32((*uint32)(unsafe.Pointer(&conn.resOnce))) == 1 && conn.resErr == nil +} + +func (conn *earlyConn) ReaderReplaceable() bool { + return conn.Success() +} + +func (conn *earlyConn) ReaderPossiblyReplaceable() bool { + return !conn.Success() +} + +func (conn *earlyConn) WriterReplaceable() bool { + return true +} + +var _ ExtendedConn = (*earlyConn)(nil) + +func NewEarlyConn(c net.Conn, f func() error) net.Conn { + return &earlyConn{ExtendedConn: NewExtendedConn(c), resFunc: f} +} diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index a553db82..a8474376 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -11,10 +11,8 @@ import ( "sync" "sync/atomic" "time" - "unsafe" atomic2 "github.com/metacubex/mihomo/common/atomic" - "github.com/metacubex/mihomo/common/buf" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/pool" C "github.com/metacubex/mihomo/constant" @@ -329,75 +327,30 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta } bufConn := N.NewBufferedConn(stream) - conn := &earlyConn{ExtendedConn: bufConn, bufConn: bufConn, RequestTimeout: t.RequestTimeout} - if !t.FastOpen { - err = conn.Response() - if err != nil { - return nil, err + response := func() error { + if t.RequestTimeout > 0 { + _ = bufConn.SetReadDeadline(time.Now().Add(t.RequestTimeout)) } + response, err := ReadResponse(bufConn) + if err != nil { + _ = bufConn.Close() + return err + } + if response.IsFailed() { + _ = bufConn.Close() + return errors.New("connect failed") + } + _ = bufConn.SetReadDeadline(time.Time{}) + return nil } - return conn, nil -} - -type earlyConn struct { - N.ExtendedConn // only expose standard N.ExtendedConn function to outside - bufConn *N.BufferedConn - resOnce sync.Once - resErr error - - RequestTimeout time.Duration -} - -func (conn *earlyConn) response() error { - if conn.RequestTimeout > 0 { - _ = conn.SetReadDeadline(time.Now().Add(conn.RequestTimeout)) + if t.FastOpen { + return N.NewEarlyConn(bufConn, response), nil } - response, err := ReadResponse(conn.bufConn) + err = response() if err != nil { - _ = conn.Close() - return err + return nil, err } - if response.IsFailed() { - _ = conn.Close() - return errors.New("connect failed") - } - _ = conn.SetReadDeadline(time.Time{}) - return nil -} - -func (conn *earlyConn) Response() error { - conn.resOnce.Do(func() { - conn.resErr = conn.response() - }) - return conn.resErr -} - -func (conn *earlyConn) Read(b []byte) (n int, err error) { - err = conn.Response() - if err != nil { - return 0, err - } - return conn.bufConn.Read(b) -} - -func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) { - err = conn.Response() - if err != nil { - return err - } - return conn.bufConn.ReadBuffer(buffer) -} - -func (conn *earlyConn) Upstream() any { - return conn.bufConn -} - -func (conn *earlyConn) ReaderReplaceable() bool { - return atomic.LoadUint32((*uint32)(unsafe.Pointer(&conn.resOnce))) == 1 && conn.resErr == nil -} - -func (conn *earlyConn) WriterReplaceable() bool { - return true + return bufConn, nil } func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { diff --git a/transport/vmess/httpupgrade.go b/transport/vmess/httpupgrade.go deleted file mode 100644 index f7e819db..00000000 --- a/transport/vmess/httpupgrade.go +++ /dev/null @@ -1,65 +0,0 @@ -package vmess - -import ( - "fmt" - "net/http" - "strings" - "sync" - - "github.com/metacubex/mihomo/common/buf" - "github.com/metacubex/mihomo/common/net" -) - -type httpUpgradeEarlyConn struct { - *net.BufferedConn - create sync.Once - done bool - err error -} - -func (c *httpUpgradeEarlyConn) readResponse() { - var request http.Request - response, err := http.ReadResponse(c.Reader(), &request) - c.done = true - if err != nil { - c.err = err - return - } - if response.StatusCode != http.StatusSwitchingProtocols || - !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || - !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { - c.err = fmt.Errorf("unexpected status: %s", response.Status) - return - } -} - -func (c *httpUpgradeEarlyConn) Read(p []byte) (int, error) { - c.create.Do(c.readResponse) - if c.err != nil { - return 0, c.err - } - return c.BufferedConn.Read(p) -} - -func (c *httpUpgradeEarlyConn) ReadBuffer(buffer *buf.Buffer) error { - c.create.Do(c.readResponse) - if c.err != nil { - return c.err - } - return c.BufferedConn.ReadBuffer(buffer) -} - -func (c *httpUpgradeEarlyConn) ReaderReplaceable() bool { - return c.done -} - -func (c *httpUpgradeEarlyConn) ReaderPossiblyReplaceable() bool { - return !c.done -} - -func (c *httpUpgradeEarlyConn) ReadCached() *buf.Buffer { - if c.done { - return c.BufferedConn.ReadCached() - } - return nil -} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index e898400c..43faac5a 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -418,9 +418,18 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, bufferedConn := N.NewBufferedConn(conn) if c.V2rayHttpUpgrade && c.V2rayHttpUpgradeFastOpen { - return &httpUpgradeEarlyConn{ - BufferedConn: bufferedConn, - }, nil + return N.NewEarlyConn(bufferedConn, func() error { + response, err := http.ReadResponse(bufferedConn.Reader(), request) + if err != nil { + return err + } + if response.StatusCode != http.StatusSwitchingProtocols || + !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || + !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { + return fmt.Errorf("unexpected status: %s", response.Status) + } + return nil + }), nil } response, err := http.ReadResponse(bufferedConn.Reader(), request) From a974e810c254b820678b043b974982304af43996 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 30 Nov 2023 20:20:45 +0800 Subject: [PATCH 124/192] fix: build error --- .github/workflows/test_author.yml | 38 ------------------------------- dns/resolver.go | 2 +- 2 files changed, 1 insertion(+), 39 deletions(-) delete mode 100644 .github/workflows/test_author.yml diff --git a/.github/workflows/test_author.yml b/.github/workflows/test_author.yml deleted file mode 100644 index 1a13612e..00000000 --- a/.github/workflows/test_author.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: Test Change Author Name -on: - workflow_dispatch: - push: - branches: - - Alpha - pull_request_target: - branches: - - Alpha - -jobs: - update-dependencies: - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Configure Git - run: | - git config --global user.name 'gVisor bot' - git config --global user.email 'gvisor-bot@google.com' - - - name: Change Author Name - run: | - git fetch origin - git checkout origin/Alpha -b test-author - git filter-branch -f --env-filter " - GIT_AUTHOR_NAME='gVisor bot' - GIT_AUTHOR_EMAIL='gvisor-bot@google.com' - GIT_COMMITTER_NAME='gVisor bot' - GIT_COMMITTER_EMAIL='gvisor-bot@google.com' - " HEAD - - - name: Push changes - run: | - git push origin test-author --force \ No newline at end of file diff --git a/dns/resolver.go b/dns/resolver.go index fa11830e..f236e141 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -500,7 +500,7 @@ func NewResolver(config Config) *Resolver { log.Debugln("adding geosite policy: %s inversed %t", key, inverse) matcher, err := NewGeoSite(key) if err != nil { - log.Warnln("adding geosite policy %s error: %s", key) + log.Warnln("adding geosite policy %s error: %s", key, err) continue } insertTriePolicy() From 8f61b0e180665ac1cebb9b657185fc490e3bc345 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 30 Nov 2023 20:30:05 +0800 Subject: [PATCH 125/192] Revert "chore: Shrink allocator pool range" This reverts commit 3c088b33a234395e2fdd5cb7c99fb8689b549976. --- common/pool/alloc.go | 85 +++++++++++++++++++++++++-------------- common/pool/alloc_test.go | 4 +- 2 files changed, 57 insertions(+), 32 deletions(-) diff --git a/common/pool/alloc.go b/common/pool/alloc.go index 0a629403..ee3fa1a1 100644 --- a/common/pool/alloc.go +++ b/common/pool/alloc.go @@ -12,7 +12,7 @@ var defaultAllocator = NewAllocator() // Allocator for incoming frames, optimized to prevent overwriting after zeroing type Allocator struct { - buffers [11]sync.Pool + buffers [17]sync.Pool } // NewAllocator initiates a []byte allocator for frames less than 65536 bytes, @@ -20,7 +20,13 @@ type Allocator struct { // no more than 50%. func NewAllocator() *Allocator { return &Allocator{ - buffers: [...]sync.Pool{ // 64B -> 64K + buffers: [...]sync.Pool{ // 1B -> 64K + {New: func() any { return new([1]byte) }}, + {New: func() any { return new([1 << 1]byte) }}, + {New: func() any { return new([1 << 2]byte) }}, + {New: func() any { return new([1 << 3]byte) }}, + {New: func() any { return new([1 << 4]byte) }}, + {New: func() any { return new([1 << 5]byte) }}, {New: func() any { return new([1 << 6]byte) }}, {New: func() any { return new([1 << 7]byte) }}, {New: func() any { return new([1 << 8]byte) }}, @@ -46,38 +52,46 @@ func (alloc *Allocator) Get(size int) []byte { case size > 65536: return make([]byte, size) default: - var index uint16 - if size > 64 { - index = msb(size) - if size != 1< Date: Thu, 30 Nov 2023 21:12:30 +0800 Subject: [PATCH 126/192] chore: modify some fields --- config/config.go | 4 ++-- docs/config.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index e8cc0198..07d8597a 100644 --- a/config/config.go +++ b/config/config.go @@ -927,9 +927,9 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { if len(cfg.Hosts) != 0 { for domain, anyValue := range cfg.Hosts { - if str, ok := anyValue.(string); ok && str == "mihomo" { + if str, ok := anyValue.(string); ok && str == "lan" { if addrs, err := net.InterfaceAddrs(); err != nil { - log.Errorln("insert mihomo to host error: %s", err) + log.Errorln("insert lan to host error: %s", err) } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { diff --git a/docs/config.yaml b/docs/config.yaml index d5e1174a..5c2a82b9 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -78,7 +78,7 @@ hosts: # '.dev': 127.0.0.1 # 'alpha.mihomo.dev': '::1' # test.com: [1.1.1.1, 2.2.2.2] -# mihomo.lan: mihomo # mihomo 为特别字段,将加入本地所有网卡的地址 +# home.lan: lan # lan 为特别字段,将加入本地所有网卡的地址 # baidu.com: google.com # 只允许配置一个别名 profile: # 存储 select 选择记录 From d773d335a2d97f7a23a7ee362b8d2641c55a0feb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 30 Nov 2023 22:22:19 +0800 Subject: [PATCH 127/192] chore: Update quic-go to v0.40.0 --- go.mod | 10 +++++----- go.sum | 10 ++++++++++ transport/hysteria/core/client.go | 6 +++--- transport/tuic/server.go | 2 +- transport/tuic/v4/client.go | 2 +- transport/tuic/v4/packet.go | 2 +- transport/tuic/v5/client.go | 2 +- transport/tuic/v5/frag.go | 2 +- transport/tuic/v5/packet.go | 2 +- 9 files changed, 24 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index 5bd66cd0..b4462c5c 100644 --- a/go.mod +++ b/go.mod @@ -20,8 +20,8 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b - github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 + github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 + github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd @@ -47,11 +47,11 @@ require ( github.com/wk8/go-ordered-map/v2 v2.1.8 github.com/zhangyunhao116/fastrand v0.3.0 go.uber.org/automaxprocs v1.5.3 - golang.org/x/crypto v0.15.0 + golang.org/x/crypto v0.16.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa golang.org/x/net v0.18.0 golang.org/x/sync v0.5.0 - golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c + golang.org/x/sys v0.15.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 @@ -90,7 +90,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.4 // indirect + github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect diff --git a/go.sum b/go.sum index 3a606050..ad32f25d 100644 --- a/go.sum +++ b/go.sum @@ -107,10 +107,14 @@ github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8 github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= +github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c h1:SZwaf42NVCIDaHw5X2HOnNcEiK9ao6yO+N4zYyKfXe8= github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= +github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b h1:7XXoEePvxfkQN9b2wB8UXU3uzb9uL8syEFF7A9VAKKQ= +github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b/go.mod h1:Gu5/zqZDd5G1AUtoV2yjAPWOEy7zwbU2DBUjdxJh0Kw= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= @@ -151,6 +155,8 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= +github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= @@ -227,6 +233,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -259,6 +267,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index b556c70d..258a0005 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -135,7 +135,7 @@ func (c *Client) handleControlStream(qs quic.Connection, stream quic.Stream) (bo func (c *Client) handleMessage(qs quic.Connection) { for { - msg, err := qs.ReceiveMessage(context.Background()) + msg, err := qs.ReceiveDatagram(context.Background()) if err != nil { break } @@ -400,7 +400,7 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error { // try no frag first var msgBuf bytes.Buffer _ = struc.Pack(&msgBuf, &msg) - err = c.Session.SendMessage(msgBuf.Bytes()) + err = c.Session.SendDatagram(msgBuf.Bytes()) if err != nil { if errSize, ok := err.(quic.ErrMessageTooLarge); ok { // need to frag @@ -409,7 +409,7 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error { for _, fragMsg := range fragMsgs { msgBuf.Reset() _ = struc.Pack(&msgBuf, &fragMsg) - err = c.Session.SendMessage(msgBuf.Bytes()) + err = c.Session.SendDatagram(msgBuf.Bytes()) if err != nil { return err } diff --git a/transport/tuic/server.go b/transport/tuic/server.go index a273e462..354533aa 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -114,7 +114,7 @@ func (s *serverHandler) handle() { func (s *serverHandler) handleMessage() (err error) { for { var message []byte - message, err = s.quicConn.ReceiveMessage(context.Background()) + message, err = s.quicConn.ReceiveDatagram(context.Background()) if err != nil { return err } diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index a8474376..67906959 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -195,7 +195,7 @@ func (t *clientImpl) handleMessage(quicConn quic.Connection) (err error) { }() for { var message []byte - message, err = quicConn.ReceiveMessage(context.Background()) + message, err = quicConn.ReceiveDatagram(context.Background()) if err != nil { return err } diff --git a/transport/tuic/v4/packet.go b/transport/tuic/v4/packet.go index 5bd6504c..f282b3ed 100644 --- a/transport/tuic/v4/packet.go +++ b/transport/tuic/v4/packet.go @@ -161,7 +161,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro } default: // native data := buf.Bytes() - err = q.quicConn.SendMessage(data) + err = q.quicConn.SendDatagram(data) if err != nil { return } diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index 81da80e7..8daa0925 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -196,7 +196,7 @@ func (t *clientImpl) handleMessage(quicConn quic.Connection) (err error) { }() for { var message []byte - message, err = quicConn.ReceiveMessage(context.Background()) + message, err = quicConn.ReceiveDatagram(context.Background()) if err != nil { return err } diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go index 4e07a1c7..3ec965f6 100644 --- a/transport/tuic/v5/frag.go +++ b/transport/tuic/v5/frag.go @@ -37,7 +37,7 @@ func fragWriteNative(quicConn quic.Connection, packet Packet, buf *bytes.Buffer, return } data := buf.Bytes() - err = quicConn.SendMessage(data) + err = quicConn.SendDatagram(data) if err != nil { return } diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index 8ab45068..a34e6a58 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -184,7 +184,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro return } data := buf.Bytes() - err = q.quicConn.SendMessage(data) + err = q.quicConn.SendDatagram(data) } var tooLarge quic.ErrMessageTooLarge From 7efd692bbc73a9adc72433d7113be9105d19d5bd Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 1 Dec 2023 23:06:29 +0800 Subject: [PATCH 128/192] Revert "Revert "chore: Shrink allocator pool range"" This reverts commit 8f61b0e180665ac1cebb9b657185fc490e3bc345. --- common/pool/alloc.go | 85 ++++++++++++++------------------------- common/pool/alloc_test.go | 4 +- 2 files changed, 32 insertions(+), 57 deletions(-) diff --git a/common/pool/alloc.go b/common/pool/alloc.go index ee3fa1a1..0a629403 100644 --- a/common/pool/alloc.go +++ b/common/pool/alloc.go @@ -12,7 +12,7 @@ var defaultAllocator = NewAllocator() // Allocator for incoming frames, optimized to prevent overwriting after zeroing type Allocator struct { - buffers [17]sync.Pool + buffers [11]sync.Pool } // NewAllocator initiates a []byte allocator for frames less than 65536 bytes, @@ -20,13 +20,7 @@ type Allocator struct { // no more than 50%. func NewAllocator() *Allocator { return &Allocator{ - buffers: [...]sync.Pool{ // 1B -> 64K - {New: func() any { return new([1]byte) }}, - {New: func() any { return new([1 << 1]byte) }}, - {New: func() any { return new([1 << 2]byte) }}, - {New: func() any { return new([1 << 3]byte) }}, - {New: func() any { return new([1 << 4]byte) }}, - {New: func() any { return new([1 << 5]byte) }}, + buffers: [...]sync.Pool{ // 64B -> 64K {New: func() any { return new([1 << 6]byte) }}, {New: func() any { return new([1 << 7]byte) }}, {New: func() any { return new([1 << 8]byte) }}, @@ -52,46 +46,38 @@ func (alloc *Allocator) Get(size int) []byte { case size > 65536: return make([]byte, size) default: - index := msb(size) - if size != 1< 64 { + index = msb(size) + if size != 1< Date: Fri, 1 Dec 2023 23:13:14 +0800 Subject: [PATCH 129/192] fix: Pool panic when putting small buffer --- common/pool/alloc.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/pool/alloc.go b/common/pool/alloc.go index 0a629403..80927a2c 100644 --- a/common/pool/alloc.go +++ b/common/pool/alloc.go @@ -96,6 +96,9 @@ func (alloc *Allocator) Put(buf []byte) error { if cap(buf) != 1< Date: Fri, 1 Dec 2023 16:44:30 +0800 Subject: [PATCH 130/192] return expected status through Rest API and clean useless code --- adapter/adapter.go | 40 +++--------------------------- adapter/outboundgroup/fallback.go | 15 +++++------ adapter/outboundgroup/groupbase.go | 2 +- adapter/outboundgroup/parser.go | 3 ++- adapter/outboundgroup/urltest.go | 16 +++++------- adapter/provider/healthcheck.go | 16 ++---------- adapter/provider/provider.go | 22 ++++++++++++---- common/utils/ranges.go | 23 +++++++++++++++++ constant/adapters.go | 20 +++++---------- hub/route/proxies.go | 2 +- 10 files changed, 68 insertions(+), 91 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 33f567c5..ae9584be 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -17,8 +17,6 @@ import ( "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/dialer" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/log" - "github.com/puzpuzpuz/xsync/v3" ) @@ -41,11 +39,6 @@ type Proxy struct { extra *xsync.MapOf[string, *extraProxyState] } -// Alive implements C.Proxy -func (p *Proxy) Alive() bool { - return p.alive.Load() -} - // AliveForTestUrl implements C.Proxy func (p *Proxy) AliveForTestUrl(url string) bool { if state, ok := p.extra.Load(url); ok { @@ -181,7 +174,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { _ = json.Unmarshal(inner, &mapping) mapping["history"] = p.DelayHistory() mapping["extra"] = p.ExtraDelayHistory() - mapping["alive"] = p.Alive() + mapping["alive"] = p.AliveForTestUrl(p.url) mapping["name"] = p.Name() mapping["udp"] = p.SupportUDP() mapping["xudp"] = p.SupportXUDP() @@ -191,13 +184,11 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { // URLTest get the delay for the specified URL // implements C.Proxy -func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16], store C.DelayHistoryStoreType) (t uint16, err error) { +func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (t uint16, err error) { defer func() { alive := err == nil - store = p.determineFinalStoreType(store, url) - switch store { - case C.OriginalHistory: + if len(p.url) == 0 || url == p.url { p.alive.Store(alive) record := C.DelayHistory{Time: time.Now()} if alive { @@ -212,7 +203,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In if len(p.url) == 0 { p.url = url } - case C.ExtraHistory: + } else { record := C.DelayHistory{Time: time.Now()} if alive { record.Delay = t @@ -236,8 +227,6 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In if state.history.Len() > defaultHistoriesNum { state.history.Pop() } - default: - log.Debugln("health check result will be discarded, url: %s alive: %t, delay: %d", url, alive, t) } }() @@ -349,24 +338,3 @@ func urlToMetadata(rawURL string) (addr C.Metadata, err error) { } return } - -func (p *Proxy) determineFinalStoreType(store C.DelayHistoryStoreType, url string) C.DelayHistoryStoreType { - if store != C.DropHistory { - return store - } - - if len(p.url) == 0 || url == p.url { - return C.OriginalHistory - } - - if p.extra.Size() < 2*C.DefaultMaxHealthCheckUrlNum { - return C.ExtraHistory - } - - _, ok := p.extra.Load(url) - if ok { - return C.ExtraHistory - } - - return store -} diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index d0dd98b1..50427e53 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -84,11 +84,11 @@ func (f *Fallback) MarshalJSON() ([]byte, error) { all = append(all, proxy.Name()) } return json.Marshal(map[string]any{ - "type": f.Type().String(), - "now": f.Now(), - "all": all, - "testUrl": f.testUrl, - "expected": f.expectedStatus, + "type": f.Type().String(), + "now": f.Now(), + "all": all, + "testUrl": f.testUrl, + "expectedStatus": f.expectedStatus, }) } @@ -102,13 +102,11 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy { proxies := f.GetProxies(touch) for _, proxy := range proxies { if len(f.selected) == 0 { - // if proxy.Alive() { if proxy.AliveForTestUrl(f.testUrl) { return proxy } } else { if proxy.Name() == f.selected { - // if proxy.Alive() { if proxy.AliveForTestUrl(f.testUrl) { return proxy } else { @@ -135,12 +133,11 @@ func (f *Fallback) Set(name string) error { } f.selected = name - // if !p.Alive() { if !p.AliveForTestUrl(f.testUrl) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000)) defer cancel() expectedStatus, _ := utils.NewIntRanges[uint16](f.expectedStatus) - _, _ = p.URLTest(ctx, f.testUrl, expectedStatus, C.ExtraHistory) + _, _ = p.URLTest(ctx, f.testUrl, expectedStatus) } return nil diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 8f5f92df..0ea3685b 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -202,7 +202,7 @@ func (gb *GroupBase) URLTest(ctx context.Context, url string, expectedStatus uti proxy := proxy wg.Add(1) go func() { - delay, err := proxy.URLTest(ctx, url, expectedStatus, C.DropHistory) + delay, err := proxy.URLTest(ctx, url, expectedStatus) if err == nil { lock.Lock() mp[proxy.Name()] = delay diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 8607bea1..422349fe 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -95,7 +95,8 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide // select don't need health check if groupOption.Type != "select" && groupOption.Type != "relay" { if groupOption.URL == "" { - groupOption.URL = "https://cp.cloudflare.com/generate_204" + groupOption.URL = C.DefaultTestURL + testUrl = groupOption.URL } if groupOption.Interval == 0 { diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 8c861768..bdac909f 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -101,7 +101,7 @@ func (u *URLTest) fast(touch bool) C.Proxy { proxies := u.GetProxies(touch) if u.selected != "" { for _, proxy := range proxies { - if !proxy.Alive() { + if !proxy.AliveForTestUrl(u.testUrl) { continue } if proxy.Name() == u.selected { @@ -113,7 +113,6 @@ func (u *URLTest) fast(touch bool) C.Proxy { elm, _, shared := u.fastSingle.Do(func() (C.Proxy, error) { fast := proxies[0] - // min := fast.LastDelay() min := fast.LastDelayForTestUrl(u.testUrl) fastNotExist := true @@ -122,12 +121,10 @@ func (u *URLTest) fast(touch bool) C.Proxy { fastNotExist = false } - // if !proxy.Alive() { if !proxy.AliveForTestUrl(u.testUrl) { continue } - // delay := proxy.LastDelay() delay := proxy.LastDelayForTestUrl(u.testUrl) if delay < min { fast = proxy @@ -136,7 +133,6 @@ func (u *URLTest) fast(touch bool) C.Proxy { } // tolerance - // if u.fastNode == nil || fastNotExist || !u.fastNode.Alive() || u.fastNode.LastDelay() > fast.LastDelay()+u.tolerance { if u.fastNode == nil || fastNotExist || !u.fastNode.AliveForTestUrl(u.testUrl) || u.fastNode.LastDelayForTestUrl(u.testUrl) > fast.LastDelayForTestUrl(u.testUrl)+u.tolerance { u.fastNode = fast } @@ -169,11 +165,11 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { all = append(all, proxy.Name()) } return json.Marshal(map[string]any{ - "type": u.Type().String(), - "now": u.Now(), - "all": all, - "testUrl": u.testUrl, - "expected": u.expectedStatus, + "type": u.Type().String(), + "now": u.Now(), + "all": all, + "testUrl": u.testUrl, + "expectedStatus": u.expectedStatus, }) } diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 6a7cd3ef..d8e56192 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -18,7 +18,6 @@ import ( const ( defaultURLTestTimeout = time.Second * 5 - defaultURLTestURL = "https://www.gstatic.com/generate_204" ) type HealthCheckOption struct { @@ -105,12 +104,6 @@ func (hc *HealthCheck) registerHealthCheckTask(url string, expectedStatus utils. return } - // due to the time-consuming nature of health checks, a maximum of defaultMaxTestURLNum URLs can be set for testing - if len(hc.extra) > C.DefaultMaxHealthCheckUrlNum { - log.Debugln("skip add url: %s to health check because it has reached the maximum limit: %d", url, C.DefaultMaxHealthCheckUrlNum) - return - } - option := &extraOption{filters: map[string]struct{}{}, expectedStatus: expectedStatus} splitAndAddFiltersToExtra(filter, option) hc.extra[url] = option @@ -182,13 +175,8 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex } var filterReg *regexp2.Regexp - var store = C.OriginalHistory var expectedStatus utils.IntRanges[uint16] if option != nil { - if url != hc.url { - store = C.ExtraHistory - } - expectedStatus = option.expectedStatus if len(option.filters) != 0 { filters := make([]string, 0, len(option.filters)) @@ -213,7 +201,7 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout) defer cancel() log.Debugln("Health Checking, proxy: %s, url: %s, id: {%s}", p.Name(), url, uid) - _, _ = p.URLTest(ctx, url, expectedStatus, store) + _, _ = p.URLTest(ctx, url, expectedStatus) log.Debugln("Health Checked, proxy: %s, url: %s, alive: %t, delay: %d ms uid: {%s}", p.Name(), url, p.AliveForTestUrl(url), p.LastDelayForTestUrl(url), uid) return false, nil }) @@ -228,7 +216,7 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, exp if len(url) == 0 { interval = 0 expectedStatus = nil - url = defaultURLTestURL + url = C.DefaultTestURL } return &HealthCheck{ diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index cd8b0e90..01ae44ee 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -48,12 +48,18 @@ type proxySetProvider struct { } func (pp *proxySetProvider) MarshalJSON() ([]byte, error) { + expectedStatus := "*" + if pp.healthCheck.expectedStatus != nil { + expectedStatus = pp.healthCheck.expectedStatus.ToString() + } + return json.Marshal(map[string]any{ "name": pp.Name(), "type": pp.Type().String(), "vehicleType": pp.VehicleType().String(), "proxies": pp.Proxies(), "testUrl": pp.healthCheck.url, + "expectedStatus": expectedStatus, "updatedAt": pp.UpdatedAt, "subscriptionInfo": pp.subscriptionInfo, }) @@ -214,12 +220,18 @@ type compatibleProvider struct { } func (cp *compatibleProvider) MarshalJSON() ([]byte, error) { + expectedStatus := "*" + if cp.healthCheck.expectedStatus != nil { + expectedStatus = cp.healthCheck.expectedStatus.ToString() + } + return json.Marshal(map[string]any{ - "name": cp.Name(), - "type": cp.Type().String(), - "vehicleType": cp.VehicleType().String(), - "proxies": cp.Proxies(), - "testUrl": cp.healthCheck.url, + "name": cp.Name(), + "type": cp.Type().String(), + "vehicleType": cp.VehicleType().String(), + "proxies": cp.Proxies(), + "testUrl": cp.healthCheck.url, + "expectedStatus": expectedStatus, }) } diff --git a/common/utils/ranges.go b/common/utils/ranges.go index 705bbdee..f36c22ec 100644 --- a/common/utils/ranges.go +++ b/common/utils/ranges.go @@ -75,3 +75,26 @@ func (ranges IntRanges[T]) Check(status T) bool { return false } + +func (ranges IntRanges[T]) ToString() string { + if len(ranges) == 0 { + return "*" + } + + terms := make([]string, len(ranges)) + for i, r := range ranges { + start := r.Start() + end := r.End() + + var term string + if start == end { + term = strconv.Itoa(int(start)) + } else { + term = strconv.Itoa(int(start)) + "-" + strconv.Itoa(int(end)) + } + + terms[i] = term + } + + return strings.Join(terms, "/") +} diff --git a/constant/adapters.go b/constant/adapters.go index 757068f3..68d4aa4e 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -43,11 +43,11 @@ const ( ) const ( - DefaultTCPTimeout = 5 * time.Second - DefaultDropTime = 12 * DefaultTCPTimeout - DefaultUDPTimeout = DefaultTCPTimeout - DefaultTLSTimeout = DefaultTCPTimeout - DefaultMaxHealthCheckUrlNum = 16 + DefaultTCPTimeout = 5 * time.Second + DefaultDropTime = 12 * DefaultTCPTimeout + DefaultUDPTimeout = DefaultTCPTimeout + DefaultTLSTimeout = DefaultTCPTimeout + DefaultTestURL = "https://cp.cloudflare.com/generate_204" ) var ErrNotSupport = errors.New("no support") @@ -149,21 +149,13 @@ type DelayHistory struct { type DelayHistoryStoreType int -const ( - OriginalHistory DelayHistoryStoreType = iota - ExtraHistory - DropHistory -) - type Proxy interface { ProxyAdapter - Alive() bool AliveForTestUrl(url string) bool DelayHistory() []DelayHistory ExtraDelayHistory() map[string][]DelayHistory - LastDelay() uint16 LastDelayForTestUrl(url string) uint16 - URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16], store DelayHistoryStoreType) (uint16, error) + URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (uint16, error) // Deprecated: use DialContext instead. Dial(metadata *Metadata) (Conn, error) diff --git a/hub/route/proxies.go b/hub/route/proxies.go index 759e64d2..48359749 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -125,7 +125,7 @@ func getProxyDelay(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout)) defer cancel() - delay, err := proxy.URLTest(ctx, url, expectedStatus, C.ExtraHistory) + delay, err := proxy.URLTest(ctx, url, expectedStatus) if ctx.Err() != nil { render.Status(r, http.StatusGatewayTimeout) render.JSON(w, r, ErrRequestTimeout) From bc74c943b878aa45e169148dffa693f41a0fdfcc Mon Sep 17 00:00:00 2001 From: snakem982 Date: Sat, 2 Dec 2023 12:56:52 +0800 Subject: [PATCH 131/192] [fix] append tuic to proxies --- common/convert/converter.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/common/convert/converter.go b/common/convert/converter.go index 55035bbe..bf5bcbd7 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -142,6 +142,8 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { tuic["udp-relay-mode"] = udpRelayMode } + proxies = append(proxies, tuic) + case "trojan": urlTrojan, err := url.Parse(line) if err != nil { From 1a0932c210c97ce646fedce98966ebe35985e667 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 2 Dec 2023 17:07:36 +0800 Subject: [PATCH 132/192] feat: support ARC for DNS cache --- adapter/outboundgroup/loadbalance.go | 8 +- common/arc/arc.go | 229 +++++++++++++++++++++++++ common/arc/arc_test.go | 59 +++++++ common/arc/entry.go | 32 ++++ common/{cache => lru}/lrucache.go | 2 +- common/{cache => lru}/lrucache_test.go | 2 +- component/fakeip/memory.go | 10 +- component/sniffer/dispatcher.go | 6 +- config/config.go | 8 + dns/enhancer.go | 8 +- dns/middleware.go | 6 +- dns/patch_android.go | 4 +- dns/resolver.go | 33 +++- dns/util.go | 3 +- docs/config.yaml | 1 + go.sum | 10 -- hub/executor/executor.go | 9 +- hub/route/server.go | 2 +- listener/http/proxy.go | 8 +- listener/http/server.go | 6 +- listener/mixed/mixed.go | 8 +- test/go.mod | 10 +- test/go.sum | 98 ++--------- transport/tuic/v5/frag.go | 10 +- 24 files changed, 416 insertions(+), 156 deletions(-) create mode 100644 common/arc/arc.go create mode 100644 common/arc/arc_test.go create mode 100644 common/arc/entry.go rename common/{cache => lru}/lrucache.go (99%) rename common/{cache => lru}/lrucache_test.go (99%) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 885aeaee..7fbc91a7 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -10,8 +10,8 @@ import ( "time" "github.com/metacubex/mihomo/adapter/outbound" - "github.com/metacubex/mihomo/common/cache" "github.com/metacubex/mihomo/common/callback" + "github.com/metacubex/mihomo/common/lru" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/dialer" @@ -190,9 +190,9 @@ func strategyConsistentHashing(url string) strategyFn { func strategyStickySessions(url string) strategyFn { ttl := time.Minute * 10 maxRetry := 5 - lruCache := cache.New[uint64, int]( - cache.WithAge[uint64, int](int64(ttl.Seconds())), - cache.WithSize[uint64, int](1000)) + lruCache := lru.New[uint64, int]( + lru.WithAge[uint64, int](int64(ttl.Seconds())), + lru.WithSize[uint64, int](1000)) return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { key := utils.MapHash(getKeyWithSrcAndDst(metadata)) length := len(proxies) diff --git a/common/arc/arc.go b/common/arc/arc.go new file mode 100644 index 00000000..8e62c906 --- /dev/null +++ b/common/arc/arc.go @@ -0,0 +1,229 @@ +package arc + +import ( + "sync" + "time" + + list "github.com/bahlo/generic-list-go" + "github.com/samber/lo" +) + +//modify from https://github.com/alexanderGugel/arc + +// Option is part of Functional Options Pattern +type Option[K comparable, V any] func(*ARC[K, V]) + +func WithSize[K comparable, V any](maxSize int) Option[K, V] { + return func(a *ARC[K, V]) { + a.c = maxSize + } +} + +type ARC[K comparable, V any] struct { + p int + c int + t1 *list.List[*entry[K, V]] + b1 *list.List[*entry[K, V]] + t2 *list.List[*entry[K, V]] + b2 *list.List[*entry[K, V]] + mutex sync.Mutex + len int + cache map[K]*entry[K, V] + staleReturn bool +} + +// New returns a new Adaptive Replacement Cache (ARC). +func New[K comparable, V any](options ...Option[K, V]) *ARC[K, V] { + arc := &ARC[K, V]{ + p: 0, + t1: list.New[*entry[K, V]](), + b1: list.New[*entry[K, V]](), + t2: list.New[*entry[K, V]](), + b2: list.New[*entry[K, V]](), + len: 0, + cache: make(map[K]*entry[K, V]), + } + + for _, option := range options { + option(arc) + } + return arc +} + +// Set inserts a new key-value pair into the cache. +// This optimizes future access to this entry (side effect). +func (a *ARC[K, V]) Set(key K, value V) { + a.mutex.Lock() + defer a.mutex.Unlock() + + a.set(key, value) +} + +func (a *ARC[K, V]) set(key K, value V) { + a.setWithExpire(key, value, time.Unix(0, 0)) +} + +// SetWithExpire stores any representation of a response for a given key and given expires. +// The expires time will round to second. +func (a *ARC[K, V]) SetWithExpire(key K, value V, expires time.Time) { + a.mutex.Lock() + defer a.mutex.Unlock() + + a.setWithExpire(key, value, expires) +} + +func (a *ARC[K, V]) setWithExpire(key K, value V, expires time.Time) { + ent, ok := a.cache[key] + if ok != true { + a.len++ + ent := &entry[K, V]{key: key, value: value, ghost: false, expires: expires.Unix()} + a.req(ent) + a.cache[key] = ent + } else { + if ent.ghost { + a.len++ + } + ent.value = value + ent.ghost = false + ent.expires = expires.Unix() + a.req(ent) + } +} + +// Get retrieves a previously via Set inserted entry. +// This optimizes future access to this entry (side effect). +func (a *ARC[K, V]) Get(key K) (value V, ok bool) { + a.mutex.Lock() + defer a.mutex.Unlock() + + ent, ok := a.get(key) + if ok { + return ent.value, true + } + return lo.Empty[V](), false +} + +func (a *ARC[K, V]) get(key K) (e *entry[K, V], ok bool) { + ent, ok := a.cache[key] + if ok { + a.req(ent) + return ent, !ent.ghost + } + return ent, false +} + +// GetWithExpire returns any representation of a cached response, +// a time.Time Give expected expires, +// and a bool set to true if the key was found. +// This method will NOT check the maxAge of element and will NOT update the expires. +func (a *ARC[K, V]) GetWithExpire(key K) (V, time.Time, bool) { + a.mutex.Lock() + defer a.mutex.Unlock() + + ent, ok := a.get(key) + if !ok { + return lo.Empty[V](), time.Time{}, false + } + + return ent.value, time.Unix(ent.expires, 0), true +} + +// Len determines the number of currently cached entries. +// This method is side-effect free in the sense that it does not attempt to optimize random cache access. +func (a *ARC[K, V]) Len() int { + a.mutex.Lock() + defer a.mutex.Unlock() + + return a.len +} + +func (a *ARC[K, V]) req(ent *entry[K, V]) { + if ent.ll == a.t1 || ent.ll == a.t2 { + // Case I + ent.setMRU(a.t2) + } else if ent.ll == a.b1 { + // Case II + // Cache Miss in t1 and t2 + + // Adaptation + var d int + if a.b1.Len() >= a.b2.Len() { + d = 1 + } else { + d = a.b2.Len() / a.b1.Len() + } + + // a.p = min(a.p+d, a.c) + a.p = a.p + d + if a.c < a.p { + a.p = a.c + } + + a.replace(ent) + ent.setMRU(a.t2) + } else if ent.ll == a.b2 { + // Case III + // Cache Miss in t1 and t2 + + // Adaptation + var d int + if a.b2.Len() >= a.b1.Len() { + d = 1 + } else { + d = a.b1.Len() / a.b2.Len() + } + //a.p = max(a.p-d, 0) + a.p = a.p - d + if a.p < 0 { + a.p = 0 + } + + a.replace(ent) + ent.setMRU(a.t2) + } else if ent.ll == nil { + // Case IV + + if a.t1.Len()+a.b1.Len() == a.c { + // Case A + if a.t1.Len() < a.c { + a.delLRU(a.b1) + a.replace(ent) + } else { + a.delLRU(a.t1) + } + } else if a.t1.Len()+a.b1.Len() < a.c { + // Case B + if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() >= a.c { + if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() == 2*a.c { + a.delLRU(a.b2) + } + a.replace(ent) + } + } + + ent.setMRU(a.t1) + } +} + +func (a *ARC[K, V]) delLRU(list *list.List[*entry[K, V]]) { + lru := list.Back() + list.Remove(lru) + a.len-- + delete(a.cache, lru.Value.key) +} + +func (a *ARC[K, V]) replace(ent *entry[K, V]) { + if a.t1.Len() > 0 && ((a.t1.Len() > a.p) || (ent.ll == a.b2 && a.t1.Len() == a.p)) { + lru := a.t1.Back().Value + lru.value = lo.Empty[V]() + lru.ghost = true + a.len-- + lru.setMRU(a.b1) + } else { + lru := a.t2.Back().Value + lru.value = lo.Empty[V]() + lru.ghost = true + a.len-- + lru.setMRU(a.b2) + } +} diff --git a/common/arc/arc_test.go b/common/arc/arc_test.go new file mode 100644 index 00000000..cb9835a3 --- /dev/null +++ b/common/arc/arc_test.go @@ -0,0 +1,59 @@ +package arc + +import "testing" + +func TestBasic(t *testing.T) { + cache := New[string, string](WithSize[string, string](3)) + if cache.Len() != 0 { + t.Error("Empty cache should have length 0") + } + + cache.Set("Hello", "World") + if cache.Len() != 1 { + t.Error("Cache should have length 1") + } + + var val interface{} + var ok bool + + if val, ok = cache.Get("Hello"); val != "World" || ok != true { + t.Error("Didn't set \"Hello\" to \"World\"") + } + + cache.Set("Hello", "World1") + if cache.Len() != 1 { + t.Error("Inserting the same entry multiple times shouldn't increase cache size") + } + + if val, ok = cache.Get("Hello"); val != "World1" || ok != true { + t.Error("Didn't update \"Hello\" to \"World1\"") + } + + cache.Set("Hallo", "Welt") + if cache.Len() != 2 { + t.Error("Inserting two different entries should result into lenght=2") + } + + if val, ok = cache.Get("Hallo"); val != "Welt" || ok != true { + t.Error("Didn't set \"Hallo\" to \"Welt\"") + } +} + +func TestBasicReplace(t *testing.T) { + cache := New[string, string](WithSize[string, string](3)) + + cache.Set("Hello", "Hallo") + cache.Set("World", "Welt") + cache.Get("World") + cache.Set("Cache", "Cache") + cache.Set("Replace", "Ersetzen") + + value, ok := cache.Get("World") + if !ok || value != "Welt" { + t.Error("ARC should have replaced \"Hello\"") + } + + if cache.Len() != 3 { + t.Error("ARC should have a maximum size of 3") + } +} diff --git a/common/arc/entry.go b/common/arc/entry.go new file mode 100644 index 00000000..679cbc1c --- /dev/null +++ b/common/arc/entry.go @@ -0,0 +1,32 @@ +package arc + +import ( + list "github.com/bahlo/generic-list-go" +) + +type entry[K comparable, V any] struct { + key K + value V + ll *list.List[*entry[K, V]] + el *list.Element[*entry[K, V]] + ghost bool + expires int64 +} + +func (e *entry[K, V]) setLRU(list *list.List[*entry[K, V]]) { + e.detach() + e.ll = list + e.el = e.ll.PushBack(e) +} + +func (e *entry[K, V]) setMRU(list *list.List[*entry[K, V]]) { + e.detach() + e.ll = list + e.el = e.ll.PushFront(e) +} + +func (e *entry[K, V]) detach() { + if e.ll != nil { + e.ll.Remove(e.el) + } +} diff --git a/common/cache/lrucache.go b/common/lru/lrucache.go similarity index 99% rename from common/cache/lrucache.go rename to common/lru/lrucache.go index 9f19787a..d23277c2 100644 --- a/common/cache/lrucache.go +++ b/common/lru/lrucache.go @@ -1,4 +1,4 @@ -package cache +package lru // Modified by https://github.com/die-net/lrucache diff --git a/common/cache/lrucache_test.go b/common/lru/lrucache_test.go similarity index 99% rename from common/cache/lrucache_test.go rename to common/lru/lrucache_test.go index 4cbc1ff8..340b3da3 100644 --- a/common/cache/lrucache_test.go +++ b/common/lru/lrucache_test.go @@ -1,4 +1,4 @@ -package cache +package lru import ( "testing" diff --git a/component/fakeip/memory.go b/component/fakeip/memory.go index f36bbb55..00eff810 100644 --- a/component/fakeip/memory.go +++ b/component/fakeip/memory.go @@ -3,12 +3,12 @@ package fakeip import ( "net/netip" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" ) type memoryStore struct { - cacheIP *cache.LruCache[string, netip.Addr] - cacheHost *cache.LruCache[netip.Addr, string] + cacheIP *lru.LruCache[string, netip.Addr] + cacheHost *lru.LruCache[netip.Addr, string] } // GetByHost implements store.GetByHost @@ -73,7 +73,7 @@ func (m *memoryStore) FlushFakeIP() error { func newMemoryStore(size int) *memoryStore { return &memoryStore{ - cacheIP: cache.New[string, netip.Addr](cache.WithSize[string, netip.Addr](size)), - cacheHost: cache.New[netip.Addr, string](cache.WithSize[netip.Addr, string](size)), + cacheIP: lru.New[string, netip.Addr](lru.WithSize[string, netip.Addr](size)), + cacheHost: lru.New[netip.Addr, string](lru.WithSize[netip.Addr, string](size)), } } diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 29bea088..96e9272c 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/component/trie" C "github.com/metacubex/mihomo/constant" @@ -29,7 +29,7 @@ type SnifferDispatcher struct { sniffers map[sniffer.Sniffer]SnifferConfig forceDomain *trie.DomainSet skipSNI *trie.DomainSet - skipList *cache.LruCache[string, uint8] + skipList *lru.LruCache[string, uint8] rwMux sync.RWMutex forceDnsMapping bool parsePureIp bool @@ -202,7 +202,7 @@ func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, enable: true, forceDomain: forceDomain, skipSNI: skipSNI, - skipList: cache.New(cache.WithSize[string, uint8](128), cache.WithAge[string, uint8](600)), + skipList: lru.New(lru.WithSize[string, uint8](128), lru.WithAge[string, uint8](600)), forceDnsMapping: forceDnsMapping, parsePureIp: parsePureIp, sniffers: make(map[sniffer.Sniffer]SnifferConfig, 0), diff --git a/config/config.go b/config/config.go index 07d8597a..9cba5d09 100644 --- a/config/config.go +++ b/config/config.go @@ -114,6 +114,7 @@ type DNS struct { Listen string `yaml:"listen"` EnhancedMode C.DNSMode `yaml:"enhanced-mode"` DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` + CacheAlgorithm string `yaml:"cache-algorithm"` FakeIPRange *fakeip.Pool Hosts *trie.DomainTrie[resolver.HostValue] NameServerPolicy *orderedmap.OrderedMap[string, []dns.NameServer] @@ -208,6 +209,7 @@ type RawDNS struct { FakeIPRange string `yaml:"fake-ip-range" json:"fake-ip-range"` FakeIPFilter []string `yaml:"fake-ip-filter" json:"fake-ip-filter"` DefaultNameserver []string `yaml:"default-nameserver" json:"default-nameserver"` + CacheAlgorithm string `yaml:"cache-algorithm" json:"cache-algorithm"` NameServerPolicy *orderedmap.OrderedMap[string, any] `yaml:"nameserver-policy" json:"nameserver-policy"` ProxyServerNameserver []string `yaml:"proxy-server-nameserver" json:"proxy-server-nameserver"` } @@ -1342,6 +1344,12 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul dnsCfg.Hosts = hosts } + if cfg.CacheAlgorithm == "" || cfg.CacheAlgorithm == "lru" { + dnsCfg.CacheAlgorithm = "lru" + } else { + dnsCfg.CacheAlgorithm = "arc" + } + return dnsCfg, nil } diff --git a/dns/enhancer.go b/dns/enhancer.go index 82fdd35a..a8c0a5ac 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -3,7 +3,7 @@ package dns import ( "net/netip" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" "github.com/metacubex/mihomo/component/fakeip" C "github.com/metacubex/mihomo/constant" ) @@ -11,7 +11,7 @@ import ( type ResolverEnhancer struct { mode C.DNSMode fakePool *fakeip.Pool - mapping *cache.LruCache[netip.Addr, string] + mapping *lru.LruCache[netip.Addr, string] } func (h *ResolverEnhancer) FakeIPEnabled() bool { @@ -105,11 +105,11 @@ func (h *ResolverEnhancer) StoreFakePoolState() { func NewEnhancer(cfg Config) *ResolverEnhancer { var fakePool *fakeip.Pool - var mapping *cache.LruCache[netip.Addr, string] + var mapping *lru.LruCache[netip.Addr, string] if cfg.EnhancedMode != C.DNSNormal { fakePool = cfg.Pool - mapping = cache.New(cache.WithSize[netip.Addr, string](4096)) + mapping = lru.New(lru.WithSize[netip.Addr, string](4096)) } return &ResolverEnhancer{ diff --git a/dns/middleware.go b/dns/middleware.go index f8e051a0..b55adc6b 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -5,7 +5,7 @@ import ( "strings" "time" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" "github.com/metacubex/mihomo/common/nnip" "github.com/metacubex/mihomo/component/fakeip" R "github.com/metacubex/mihomo/component/resolver" @@ -21,7 +21,7 @@ type ( middleware func(next handler) handler ) -func withHosts(hosts R.Hosts, mapping *cache.LruCache[netip.Addr, string]) middleware { +func withHosts(hosts R.Hosts, mapping *lru.LruCache[netip.Addr, string]) middleware { return func(next handler) handler { return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) { q := r.Question[0] @@ -98,7 +98,7 @@ func withHosts(hosts R.Hosts, mapping *cache.LruCache[netip.Addr, string]) middl } } -func withMapping(mapping *cache.LruCache[netip.Addr, string]) middleware { +func withMapping(mapping *lru.LruCache[netip.Addr, string]) middleware { return func(next handler) handler { return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) { q := r.Question[0] diff --git a/dns/patch_android.go b/dns/patch_android.go index 8cb4286e..2e9a6b9f 100644 --- a/dns/patch_android.go +++ b/dns/patch_android.go @@ -7,7 +7,7 @@ import ( D "github.com/miekg/dns" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" "github.com/metacubex/mihomo/component/dhcp" "github.com/metacubex/mihomo/component/resolver" ) @@ -49,7 +49,7 @@ func ServeDNSWithDefaultServer(msg *D.Msg) (*D.Msg, error) { func FlushCacheWithDefaultResolver() { if r := resolver.DefaultResolver; r != nil { - r.(*Resolver).lruCache = cache.New[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)) + r.(*Resolver).lruCache = lru.New[string, *D.Msg](lru.WithSize[string, *D.Msg](4096), lru.WithStale[string, *D.Msg](true)) } } diff --git a/dns/resolver.go b/dns/resolver.go index f236e141..e1ca95dd 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -7,7 +7,8 @@ import ( "strings" "time" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/arc" + "github.com/metacubex/mihomo/common/lru" "github.com/metacubex/mihomo/component/fakeip" "github.com/metacubex/mihomo/component/geodata/router" "github.com/metacubex/mihomo/component/resolver" @@ -28,6 +29,11 @@ type dnsClient interface { Address() string } +type dnsCache interface { + GetWithExpire(key string) (*D.Msg, time.Time, bool) + SetWithExpire(key string, value *D.Msg, expire time.Time) +} + type result struct { Msg *D.Msg Error error @@ -42,7 +48,7 @@ type Resolver struct { fallbackDomainFilters []fallbackDomainFilter fallbackIPFilters []fallbackIPFilter group singleflight.Group - lruCache *cache.LruCache[string, *D.Msg] + cache dnsCache policy []dnsPolicy proxyServer []dnsClient } @@ -140,8 +146,9 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e }() q := m.Question[0] - cacheM, expireTime, hit := r.lruCache.GetWithExpire(q.String()) + cacheM, expireTime, hit := r.cache.GetWithExpire(q.String()) if hit { + log.Debugln("[DNS] cache hit for %s, expire at %s", q.Name, expireTime.Format("2006-01-02 15:04:05")) now := time.Now() msg = cacheM.Copy() if expireTime.Before(now) { @@ -181,7 +188,7 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M msg.Extra = lo.Filter(msg.Extra, func(rr D.RR, index int) bool { return rr.Header().Rrtype != D.TypeOPT }) - putMsgToCache(r.lruCache, q.String(), q, msg) + putMsgToCache(r.cache, q.String(), q, msg) } }() @@ -408,12 +415,19 @@ type Config struct { Hosts *trie.DomainTrie[resolver.HostValue] Policy *orderedmap.OrderedMap[string, []NameServer] RuleProviders map[string]provider.RuleProvider + CacheAlgorithm string } func NewResolver(config Config) *Resolver { + var cache dnsCache + if config.CacheAlgorithm == "lru" { + cache = lru.New(lru.WithSize[string, *D.Msg](4096), lru.WithStale[string, *D.Msg](true)) + } else { + cache = arc.New(arc.WithSize[string, *D.Msg](4096)) + } defaultResolver := &Resolver{ main: transform(config.Default, nil), - lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), + cache: cache, ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond, } @@ -444,10 +458,15 @@ func NewResolver(config Config) *Resolver { return } + if config.CacheAlgorithm == "" || config.CacheAlgorithm == "lru" { + cache = lru.New(lru.WithSize[string, *D.Msg](4096), lru.WithStale[string, *D.Msg](true)) + } else { + cache = arc.New(arc.WithSize[string, *D.Msg](4096)) + } r := &Resolver{ ipv6: config.IPv6, main: cacheTransform(config.Main), - lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), + cache: cache, hosts: config.Hosts, ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond, } @@ -550,7 +569,7 @@ func NewProxyServerHostResolver(old *Resolver) *Resolver { r := &Resolver{ ipv6: old.ipv6, main: old.proxyServer, - lruCache: old.lruCache, + cache: old.cache, hosts: old.hosts, ipv6Timeout: old.ipv6Timeout, } diff --git a/dns/util.go b/dns/util.go index c354a73d..f2243917 100644 --- a/dns/util.go +++ b/dns/util.go @@ -11,7 +11,6 @@ import ( "strings" "time" - "github.com/metacubex/mihomo/common/cache" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/nnip" "github.com/metacubex/mihomo/common/picker" @@ -51,7 +50,7 @@ func updateTTL(records []D.RR, ttl uint32) { } } -func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, q D.Question, msg *D.Msg) { +func putMsgToCache(c dnsCache, key string, q D.Question, msg *D.Msg) { // skip dns cache for acme challenge if q.Qtype == D.TypeTXT && strings.HasPrefix(q.Name, "_acme-challenge.") { log.Debugln("[DNS] dns cache ignored because of acme challenge for: %s", q.Name) diff --git a/docs/config.yaml b/docs/config.yaml index 5c2a82b9..bdb822f7 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -183,6 +183,7 @@ tunnels: # one line config # DNS配置 dns: + cache-algorithm: arc enable: false # 关闭将使用系统 DNS prefer-h3: true # 开启 DoH 支持 HTTP/3,将并发尝试 listen: 0.0.0.0:53 # 开启 DNS 服务器监听 diff --git a/go.sum b/go.sum index ad32f25d..0e0ab68c 100644 --- a/go.sum +++ b/go.sum @@ -105,14 +105,10 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= -github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c h1:SZwaf42NVCIDaHw5X2HOnNcEiK9ao6yO+N4zYyKfXe8= github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= -github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b h1:7XXoEePvxfkQN9b2wB8UXU3uzb9uL8syEFF7A9VAKKQ= github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b/go.mod h1:Gu5/zqZDd5G1AUtoV2yjAPWOEy7zwbU2DBUjdxJh0Kw= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= @@ -153,8 +149,6 @@ github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbA github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= -github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -231,8 +225,6 @@ go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0Eq go4.org/netipx v0.0.0-20230824141953-6213f710f925/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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= @@ -265,8 +257,6 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= -golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/hub/executor/executor.go b/hub/executor/executor.go index f8ba31a5..72d7380e 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -224,10 +224,11 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen Domain: c.FallbackFilter.Domain, GeoSite: c.FallbackFilter.GeoSite, }, - Default: c.DefaultNameserver, - Policy: c.NameServerPolicy, - ProxyServer: c.ProxyServerNameserver, - RuleProviders: ruleProvider, + Default: c.DefaultNameserver, + Policy: c.NameServerPolicy, + ProxyServer: c.ProxyServerNameserver, + RuleProviders: ruleProvider, + CacheAlgorithm: c.CacheAlgorithm, } r := dns.NewResolver(cfg) diff --git a/hub/route/server.go b/hub/route/server.go index d510e986..6ececddb 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -89,7 +89,7 @@ func Start(addr string, tlsAddr string, secret string, r.Mount("/connections", connectionRouter()) r.Mount("/providers/proxies", proxyProviderRouter()) r.Mount("/providers/rules", ruleProviderRouter()) - r.Mount("/cache", cacheRouter()) + r.Mount("/lru", cacheRouter()) r.Mount("/dns", dnsRouter()) r.Mount("/restart", restartRouter()) r.Mount("/upgrade", upgradeRouter()) diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 76da4d95..45f53d6b 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -7,21 +7,21 @@ import ( "strings" "github.com/metacubex/mihomo/adapter/inbound" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" authStore "github.com/metacubex/mihomo/listener/auth" "github.com/metacubex/mihomo/log" ) -func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { +func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) { client := newClient(c, tunnel, additions...) defer client.CloseIdleConnections() conn := N.NewBufferedConn(c) keepAlive := true - trusted := cache == nil // disable authenticate if cache is nil + trusted := cache == nil // disable authenticate if lru is nil for keepAlive { request, err := ReadRequest(conn.Reader()) @@ -98,7 +98,7 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool] _ = conn.Close() } -func authenticate(request *http.Request, cache *cache.LruCache[string, bool]) *http.Response { +func authenticate(request *http.Request, cache *lru.LruCache[string, bool]) *http.Response { authenticator := authStore.Authenticator() if inbound.SkipAuthRemoteAddress(request.RemoteAddr) { authenticator = nil diff --git a/listener/http/server.go b/listener/http/server.go index d5e20601..be397d9a 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -4,7 +4,7 @@ import ( "net" "github.com/metacubex/mihomo/adapter/inbound" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/features" ) @@ -48,9 +48,9 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi return nil, err } - var c *cache.LruCache[string, bool] + var c *lru.LruCache[string, bool] if authenticate { - c = cache.New[string, bool](cache.WithAge[string, bool](30)) + c = lru.New[string, bool](lru.WithAge[string, bool](30)) } hl := &Listener{ diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index 97d1407c..0f1b3aab 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -4,7 +4,7 @@ import ( "net" "github.com/metacubex/mihomo/adapter/inbound" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" N "github.com/metacubex/mihomo/common/net" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/listener/http" @@ -16,7 +16,7 @@ import ( type Listener struct { listener net.Listener addr string - cache *cache.LruCache[string, bool] + cache *lru.LruCache[string, bool] closed bool } @@ -51,7 +51,7 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener ml := &Listener{ listener: l, addr: addr, - cache: cache.New[string, bool](cache.WithAge[string, bool](30)), + cache: lru.New[string, bool](lru.WithAge[string, bool](30)), } go func() { for { @@ -69,7 +69,7 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener return ml, nil } -func handleConn(conn net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { +func handleConn(conn net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) { N.TCPKeepAlive(conn) bufConn := N.NewBufferedConn(conn) diff --git a/test/go.mod b/test/go.mod index d62c4350..92374886 100644 --- a/test/go.mod +++ b/test/go.mod @@ -58,8 +58,8 @@ require ( github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect - github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b // indirect - github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 // indirect + github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 // indirect + github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b // indirect github.com/metacubex/sing-shadowsocks v0.2.5 // indirect github.com/metacubex/sing-shadowsocks2 v0.1.4 // indirect github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd // indirect @@ -80,7 +80,7 @@ require ( github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/puzpuzpuz/xsync/v3 v3.0.2 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.4 // indirect + github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect @@ -109,11 +109,11 @@ require ( gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect - golang.org/x/crypto v0.15.0 // indirect + golang.org/x/crypto v0.16.0 // indirect golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/sync v0.5.0 // indirect - golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c // indirect + golang.org/x/sys v0.15.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.15.0 // indirect diff --git a/test/go.sum b/test/go.sum index aaf9010e..af34b356 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,44 +1,28 @@ github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08= github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg= github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM= github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= -github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= -github.com/bazelbuild/rules_go v0.38.1/go.mod h1:TMHmtfpvyfsxaqfL9WnahCsXMWDMICTw7XeK9yVb+YU= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= -github.com/containerd/cgroups v1.0.1/go.mod h1:0SJrPIenamHDcZhEcJMNBB85rHcUsw4f25ZfBiPYRkU= -github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= -github.com/containerd/containerd v1.4.13/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/containerd/fifo v1.0.0/go.mod h1:ocF/ME1SX5b1AOlWi9r677YJmCPSwwWnQ9O123vzpE4= -github.com/containerd/go-runc v1.0.0/go.mod h1:cNU0ZbCgCQVZK4lgG3P+9tn9/PaJNmoDXPpoJhDR+Ok= -github.com/containerd/ttrpc v1.1.0/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Evzy5KFQpQ= -github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -54,30 +38,21 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391/go.mod h1:K2R7GhgxrlJzHw2qiPWsCZXf/kXEJN9PLnQK73Ll0po= github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c h1:RUzBDdZ+e/HEe2Nh8lYsduiPAZygUfVXJn0Ncj5sHMg= -github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c/go.mod h1:ETASDWf/FmEb6Ysrtd1QhjNedUU/ZQxBCRLh60bQ/UI= github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBEz5nGDMvswiajqh7k8ogWRlhRwKy5mY= github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= -github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= -github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= -github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= -github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= -github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= @@ -89,17 +64,13 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= github.com/gobwas/ws v1.3.1 h1:Qi34dfLMWJbiKaNbDVzM9x27nZBjmkaW6i4+Ku+pGVU= github.com/gobwas/ws v1.3.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -107,19 +78,11 @@ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/subcommands v1.0.2-0.20190508160503-636abe8753b8/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= -github.com/google/tink/go v1.6.1/go.mod h1:IGW53kTgag+st5yPhKKwJ6u2l+SSp5/v9XF7spovjlY= -github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= -github.com/hanwen/go-fuse/v2 v2.3.0/go.mod h1:xKwi1cF7nXAOBCXujD5ie0ZKsxc8GGSA1rlMJc+8IJs= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= -github.com/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= @@ -129,8 +92,6 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jsimonetti/rtnetlink v1.3.5/go.mod h1:0LFedyiTkebnd43tE4YAkWGIq9jQphow4CcwxaT2Y00= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= @@ -138,30 +99,25 @@ github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQs github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= -github.com/mdlayher/packet v1.1.2/go.mod h1:GEu1+n9sG5VtiRE4SydOmX5GTwyyYlteZiFU+x0kew4= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= -github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= -github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= +github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= +github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= +github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b h1:7XXoEePvxfkQN9b2wB8UXU3uzb9uL8syEFF7A9VAKKQ= +github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b/go.mod h1:Gu5/zqZDd5G1AUtoV2yjAPWOEy7zwbU2DBUjdxJh0Kw= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= @@ -176,9 +132,6 @@ github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/mohae/deepcopy v0.0.0-20170308212314-bb9b5e7adda9/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= @@ -188,7 +141,6 @@ github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:U github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= @@ -198,7 +150,6 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= @@ -213,10 +164,9 @@ github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbA github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= -github.com/quic-go/qtls-go1-20 v0.3.4/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= +github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= @@ -257,7 +207,6 @@ github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIF github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -268,7 +217,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -276,7 +224,6 @@ github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9f github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netlink v1.1.1-0.20211118161826-650dca95af54/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho= github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= @@ -285,15 +232,12 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= @@ -301,11 +245,10 @@ go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= -golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= -golang.org/x/exp/typeparams v0.0.0-20221208152030-732eee02a75a/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -318,7 +261,6 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= -golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -342,9 +284,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c h1:3kC/TjQ+xzIblQv39bCOyRk8fbEeJcDHwbyxPUU2BpA= -golang.org/x/sys v0.14.1-0.20231108175955-e4099bfacb8c/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -362,33 +303,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/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-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= -google.golang.org/grpc v1.53.0-dev.0.20230123225046-4075ef07c5d5/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -honnef.co/go/tools v0.4.5/go.mod h1:GUV+uIBCLpdf0/v6UhHHG/yzI/z6qPskBeQCjcNB96k= -k8s.io/api v0.23.16/go.mod h1:Fk/eWEGf3ZYZTCVLbsgzlxekG6AtnT3QItT3eOSyFRE= -k8s.io/apimachinery v0.23.16/go.mod h1:RMMUoABRwnjoljQXKJ86jT5FkTZPPnZsNv70cMsKIP0= -k8s.io/client-go v0.23.16/go.mod h1:CUfIIQL+hpzxnD9nxiVGb99BNTp00mPFp3Pk26sTFys= -k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= -k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= -sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= -sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go index 3ec965f6..b0e1a174 100644 --- a/transport/tuic/v5/frag.go +++ b/transport/tuic/v5/frag.go @@ -4,7 +4,7 @@ import ( "bytes" "sync" - "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/lru" "github.com/metacubex/quic-go" ) @@ -47,7 +47,7 @@ func fragWriteNative(quicConn quic.Connection, packet Packet, buf *bytes.Buffer, } type deFragger struct { - lru *cache.LruCache[uint16, *packetBag] + lru *lru.LruCache[uint16, *packetBag] once sync.Once } @@ -63,9 +63,9 @@ func newPacketBag() *packetBag { func (d *deFragger) init() { if d.lru == nil { - d.lru = cache.New( - cache.WithAge[uint16, *packetBag](10), - cache.WithUpdateAgeOnGet[uint16, *packetBag](), + d.lru = lru.New( + lru.WithAge[uint16, *packetBag](10), + lru.WithUpdateAgeOnGet[uint16, *packetBag](), ) } } From 22ed13b9df97394702f4a741b147749b7df2637b Mon Sep 17 00:00:00 2001 From: snakem982 Date: Sun, 3 Dec 2023 09:39:34 +0800 Subject: [PATCH 133/192] feat: support external api extensions (#852) --- hub/route/external.go | 21 +++++++++++++++++++++ hub/route/server.go | 1 + 2 files changed, 22 insertions(+) create mode 100644 hub/route/external.go diff --git a/hub/route/external.go b/hub/route/external.go new file mode 100644 index 00000000..d2f06358 --- /dev/null +++ b/hub/route/external.go @@ -0,0 +1,21 @@ +package route + +import "github.com/go-chi/chi/v5" + +type externalRouter func(r chi.Router) + +var externalRouters = make([]externalRouter, 0) + +func Register(route ...externalRouter) { + externalRouters = append(externalRouters, route...) +} + +func addExternalRouters(r chi.Router) { + if len(externalRouters) == 0 { + return + } + + for _, caller := range externalRouters { + caller(r) + } +} diff --git a/hub/route/server.go b/hub/route/server.go index 6ececddb..0733b310 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -93,6 +93,7 @@ func Start(addr string, tlsAddr string, secret string, r.Mount("/dns", dnsRouter()) r.Mount("/restart", restartRouter()) r.Mount("/upgrade", upgradeRouter()) + addExternalRouters(r) }) From 071e8488a862ba7d7a6ccf08f95606c7957594f0 Mon Sep 17 00:00:00 2001 From: wzdnzd Date: Sun, 3 Dec 2023 12:08:10 +0800 Subject: [PATCH 134/192] [fix] latency of extra should not overwrite the history (#855) --- adapter/adapter.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index ae9584be..e239ab7b 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -208,10 +208,6 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In if alive { record.Delay = t } - p.history.Put(record) - if p.history.Len() > defaultHistoriesNum { - p.history.Pop() - } state, ok := p.extra.Load(url) if !ok { From 5f493fbcfba5cd3d1bc709da65e7c5fbd2e3df49 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 3 Dec 2023 14:39:01 +0800 Subject: [PATCH 135/192] fix: mount cache --- hub/route/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hub/route/server.go b/hub/route/server.go index 0733b310..a3a387c9 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -89,7 +89,7 @@ func Start(addr string, tlsAddr string, secret string, r.Mount("/connections", connectionRouter()) r.Mount("/providers/proxies", proxyProviderRouter()) r.Mount("/providers/rules", ruleProviderRouter()) - r.Mount("/lru", cacheRouter()) + r.Mount("/cache", cacheRouter()) r.Mount("/dns", dnsRouter()) r.Mount("/restart", restartRouter()) r.Mount("/upgrade", upgradeRouter()) From aef87b29ba8bab652dce24a08560d257e1fb3c78 Mon Sep 17 00:00:00 2001 From: Kuingsmile Date: Sun, 3 Dec 2023 07:10:09 -0800 Subject: [PATCH 136/192] feat: Add GeoAutoUpdate and GeoUpdateInterval to config (#857) --- config/config.go | 42 ++++++++++++++++++++++------------- config/update_geo.go | 7 +++--- config/update_ui.go | 2 +- constant/geodata.go | 10 +++++---- docs/config.yaml | 3 +++ main.go | 53 +++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 91 insertions(+), 26 deletions(-) diff --git a/config/config.go b/config/config.go index 9cba5d09..45c4cfdb 100644 --- a/config/config.go +++ b/config/config.go @@ -55,6 +55,8 @@ type General struct { Interface string `json:"interface-name"` RoutingMark int `json:"-"` GeoXUrl GeoXUrl `json:"geox-url"` + GeoAutoUpdate bool `json:"geo-auto-update"` + GeoUpdateInterval int `json:"geo-update-interval"` GeodataMode bool `json:"geodata-mode"` GeodataLoader string `json:"geodata-loader"` TCPConcurrent bool `json:"tcp-concurrent"` @@ -298,6 +300,8 @@ type RawConfig struct { Interface string `yaml:"interface-name"` RoutingMark int `yaml:"routing-mark"` Tunnels []LC.Tunnel `yaml:"tunnels"` + GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"` + GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"` GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"` GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"` TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` @@ -377,22 +381,24 @@ func Parse(buf []byte) (*Config, error) { func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { // config with default value rawCfg := &RawConfig{ - AllowLan: false, - BindAddress: "*", - IPv6: true, - Mode: T.Rule, - GeodataMode: C.GeodataMode, - GeodataLoader: "memconservative", - UnifiedDelay: false, - Authentication: []string{}, - LogLevel: log.INFO, - Hosts: map[string]any{}, - Rule: []string{}, - Proxy: []map[string]any{}, - ProxyGroup: []map[string]any{}, - TCPConcurrent: false, - FindProcessMode: P.FindProcessStrict, - GlobalUA: "clash.meta", + AllowLan: false, + BindAddress: "*", + IPv6: true, + Mode: T.Rule, + GeoAutoUpdate: false, + GeoUpdateInterval: 24, + GeodataMode: C.GeodataMode, + GeodataLoader: "memconservative", + UnifiedDelay: false, + Authentication: []string{}, + LogLevel: log.INFO, + Hosts: map[string]any{}, + Rule: []string{}, + Proxy: []map[string]any{}, + ProxyGroup: []map[string]any{}, + TCPConcurrent: false, + FindProcessMode: P.FindProcessStrict, + GlobalUA: "clash.meta", Tun: RawTun{ Enable: false, Device: "", @@ -590,6 +596,8 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { func parseGeneral(cfg *RawConfig) (*General, error) { geodata.SetLoader(cfg.GeodataLoader) + C.GeoAutoUpdate = cfg.GeoAutoUpdate + C.GeoUpdateInterval = cfg.GeoUpdateInterval C.GeoIpUrl = cfg.GeoXUrl.GeoIp C.GeoSiteUrl = cfg.GeoXUrl.GeoSite C.MmdbUrl = cfg.GeoXUrl.Mmdb @@ -652,6 +660,8 @@ func parseGeneral(cfg *RawConfig) (*General, error) { Interface: cfg.Interface, RoutingMark: cfg.RoutingMark, GeoXUrl: cfg.GeoXUrl, + GeoAutoUpdate: cfg.GeoAutoUpdate, + GeoUpdateInterval: cfg.GeoUpdateInterval, GeodataMode: cfg.GeodataMode, GeodataLoader: cfg.GeodataLoader, TCPConcurrent: cfg.TCPConcurrent, diff --git a/config/update_geo.go b/config/update_geo.go index 718c2d07..2cde47a1 100644 --- a/config/update_geo.go +++ b/config/update_geo.go @@ -28,7 +28,7 @@ func UpdateGeoDatabases() error { return fmt.Errorf("invalid GeoIP database file: %s", err) } - if saveFile(data, C.Path.GeoIP()) != nil { + if err = saveFile(data, C.Path.GeoIP()); err != nil { return fmt.Errorf("can't save GeoIP database file: %w", err) } @@ -43,8 +43,7 @@ func UpdateGeoDatabases() error { return fmt.Errorf("invalid MMDB database file: %s", err) } _ = instance.Close() - - if saveFile(data, C.Path.MMDB()) != nil { + if err = saveFile(data, C.Path.MMDB()); err != nil { return fmt.Errorf("can't save MMDB database file: %w", err) } } @@ -58,7 +57,7 @@ func UpdateGeoDatabases() error { return fmt.Errorf("invalid GeoSite database file: %s", err) } - if saveFile(data, C.Path.GeoSite()) != nil { + if err = saveFile(data, C.Path.GeoSite()); err != nil { return fmt.Errorf("can't save GeoSite database file: %w", err) } diff --git a/config/update_ui.go b/config/update_ui.go index e5596597..cff1d6d7 100644 --- a/config/update_ui.go +++ b/config/update_ui.go @@ -40,7 +40,7 @@ func UpdateUI() error { } saved := path.Join(C.Path.HomeDir(), "download.zip") - if saveFile(data, saved) != nil { + if err = saveFile(data, saved); err != nil { return fmt.Errorf("can't save zip file: %w", err) } defer os.Remove(saved) diff --git a/constant/geodata.go b/constant/geodata.go index 72452270..e93d56b3 100644 --- a/constant/geodata.go +++ b/constant/geodata.go @@ -1,8 +1,10 @@ package constant var ( - GeodataMode bool - GeoIpUrl string - MmdbUrl string - GeoSiteUrl string + GeodataMode bool + GeoAutoUpdate bool + GeoUpdateInterval int + GeoIpUrl string + MmdbUrl string + GeoSiteUrl string ) diff --git a/docs/config.yaml b/docs/config.yaml index bdb822f7..b2524329 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -28,6 +28,9 @@ geox-url: geosite: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat" mmdb: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb" +geo-auto-update: false # 是否自动更新 geodata +geo-update-interval: 24 # 更新间隔,单位:小时 + log-level: debug # 日志等级 silent/error/warning/info/debug ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS 请求 AAAA 记录 diff --git a/main.go b/main.go index 01edee9f..425b4661 100644 --- a/main.go +++ b/main.go @@ -3,16 +3,18 @@ package main import ( "flag" "fmt" - "github.com/metacubex/mihomo/constant/features" "os" "os/signal" "path/filepath" "runtime" "strings" + "sync" "syscall" + "time" "github.com/metacubex/mihomo/config" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/hub" "github.com/metacubex/mihomo/hub/executor" "github.com/metacubex/mihomo/log" @@ -29,6 +31,8 @@ var ( externalUI string externalController string secret string + updateGeoMux sync.Mutex + updatingGeo = false ) func init() { @@ -107,6 +111,17 @@ func main() { log.Fatalln("Parse config error: %s", err.Error()) } + if C.GeoAutoUpdate { + ticker := time.NewTicker(time.Duration(C.GeoUpdateInterval) * time.Hour) + + log.Infoln("[GEO] Start update GEO database every %d hours", C.GeoUpdateInterval) + go func() { + for range ticker.C { + updateGeoDatabases() + } + }() + } + defer executor.Shutdown() termSign := make(chan os.Signal, 1) @@ -126,3 +141,39 @@ func main() { } } } + +func updateGeoDatabases() { + log.Infoln("[GEO] Start updating GEO database") + updateGeoMux.Lock() + + if updatingGeo { + updateGeoMux.Unlock() + log.Infoln("[GEO] GEO database is updating, skip") + return + } + + updatingGeo = true + updateGeoMux.Unlock() + + go func() { + defer func() { + updatingGeo = false + }() + + log.Infoln("[GEO] Updating GEO database") + + if err := config.UpdateGeoDatabases(); err != nil { + log.Errorln("[GEO] update GEO database error: %s", err.Error()) + return + } + + cfg, err := executor.ParseWithPath(C.Path.Config()) + if err != nil { + log.Errorln("[GEO] update GEO database failed: %s", err.Error()) + return + } + + log.Infoln("[GEO] Update GEO database success, apply new config") + executor.ApplyConfig(cfg, false) + }() +} From 2d7538aca6f184d548dc7c890e02d77ecffea806 Mon Sep 17 00:00:00 2001 From: tommytag Date: Mon, 4 Dec 2023 18:10:45 +0800 Subject: [PATCH 137/192] [fix] incorrect data save location for latency --- adapter/adapter.go | 4 ++++ adapter/provider/provider.go | 4 ++++ constant/adapters.go | 1 + 3 files changed, 9 insertions(+) diff --git a/adapter/adapter.go b/adapter/adapter.go index e239ab7b..60b6ad94 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -48,6 +48,10 @@ func (p *Proxy) AliveForTestUrl(url string) bool { return p.alive.Load() } +func (p *Proxy) OriginalHealthCheckUrl(url string) { + p.url = url +} + // Dial implements C.Proxy func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 01ae44ee..37106e63 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -114,6 +114,10 @@ func (pp *proxySetProvider) RegisterHealthCheckTask(url string, expectedStatus u func (pp *proxySetProvider) setProxies(proxies []C.Proxy) { pp.proxies = proxies + for _, proxy := range pp.proxies { + proxy.OriginalHealthCheckUrl(pp.healthCheck.url) + } + pp.healthCheck.setProxy(proxies) if pp.healthCheck.auto() { go pp.healthCheck.check() diff --git a/constant/adapters.go b/constant/adapters.go index 68d4aa4e..4a8de89b 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -155,6 +155,7 @@ type Proxy interface { DelayHistory() []DelayHistory ExtraDelayHistory() map[string][]DelayHistory LastDelayForTestUrl(url string) uint16 + OriginalHealthCheckUrl(url string) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (uint16, error) // Deprecated: use DialContext instead. From 2d73bcb951d82765cdce03da972a2a9d0e4c887f Mon Sep 17 00:00:00 2001 From: giveup Date: Tue, 5 Dec 2023 13:27:59 +0800 Subject: [PATCH 138/192] chore: fix typo chore: fix typo --- docs/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index b2524329..562468de 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -740,7 +740,7 @@ proxies: # socks5 # The supported obfses: # plain http_simple http_post # random_head tls1.2_ticket_auth tls1.2_ticket_fastauth - # The supported supported protocols: + # The supported protocols: # origin auth_sha1_v4 auth_aes128_md5 # auth_aes128_sha1 auth_chain_a auth_chain_b - name: "ssr" From ee6b974c18c996134488747116ac5d81c1f5a90b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 5 Dec 2023 20:29:56 +0800 Subject: [PATCH 139/192] fix: let input prefix to lower case when parsing. Fix #868 --- config/config.go | 9 +++++++-- dns/resolver.go | 9 ++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/config/config.go b/config/config.go index 45c4cfdb..665b8539 100644 --- a/config/config.go +++ b/config/config.go @@ -1114,7 +1114,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro for pair := nsPolicy.Oldest(); pair != nil; pair = pair.Next() { k, v := pair.Key, pair.Value - if strings.Contains(k, ",") { + if strings.Contains(strings.ToLower(k), ",") { if strings.Contains(k, "geosite:") { subkeys := strings.Split(k, ":") subkeys = subkeys[1:] @@ -1123,7 +1123,7 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro newKey := "geosite:" + subkey updatedPolicy.Store(newKey, v) } - } else if strings.Contains(k, "rule-set:") { + } else if strings.Contains(strings.ToLower(k), "rule-set:") { subkeys := strings.Split(k, ":") subkeys = subkeys[1:] subkeys = strings.Split(subkeys[0], ",") @@ -1138,6 +1138,11 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rulePro } } } else { + if strings.Contains(strings.ToLower(k), "geosite:") { + updatedPolicy.Store("geosite:"+k[8:], v) + } else if strings.Contains(strings.ToLower(k), "rule-set:") { + updatedPolicy.Store("rule-set:"+k[9:], v) + } updatedPolicy.Store(k, v) } } diff --git a/dns/resolver.go b/dns/resolver.go index e1ca95dd..0f2873f0 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -493,22 +493,21 @@ func NewResolver(config Config) *Resolver { for pair := config.Policy.Oldest(); pair != nil; pair = pair.Next() { domain, nameserver := pair.Key, pair.Value - domain = strings.ToLower(domain) if temp := strings.Split(domain, ":"); len(temp) == 2 { prefix := temp[0] key := temp[1] - switch strings.ToLower(prefix) { + switch prefix { case "rule-set": if p, ok := config.RuleProviders[key]; ok { - insertTriePolicy() + log.Debugln("Adding rule-set policy: %s ", key) r.policy = append(r.policy, domainSetPolicy{ domainSetProvider: p, dnsClients: cacheTransform(nameserver), }) continue } else { - log.Warnln("can't found ruleset policy: %s", key) + log.Warnln("Can't found ruleset policy: %s", key) } case "geosite": inverse := false @@ -516,7 +515,7 @@ func NewResolver(config Config) *Resolver { inverse = true key = key[1:] } - log.Debugln("adding geosite policy: %s inversed %t", key, inverse) + log.Debugln("Adding geosite policy: %s inversed %t", key, inverse) matcher, err := NewGeoSite(key) if err != nil { log.Warnln("adding geosite policy %s error: %s", key, err) From 92129b33e73b39be7b250c5ca9152915b4e8d13c Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 5 Dec 2023 21:07:21 +0800 Subject: [PATCH 140/192] ci: push images to docker.io for storage conservation --- .github/workflows/build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 34c80619..2767af8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ concurrency: cancel-in-progress: true env: - REGISTRY: ghcr.io + REGISTRY: docker.io jobs: Build: permissions: write-all @@ -349,12 +349,12 @@ jobs: ls . ls bin/ - - name: login to ghcr.io + - name: login to docker REGISTRY uses: docker/login-action@v3 with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} + registry: ${{ env.REGISTRY }} + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} # Build and push Docker image with Buildx (don't push on PR) # https://github.com/docker/build-push-action From ed210ee4039306def6dcaff75da2e5fa0fa5e1e3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 6 Dec 2023 11:00:45 +0800 Subject: [PATCH 141/192] fix: only using xsync with pointer to avoid unaligned 64-bit atomic operation closed #783 --- transport/tuic/v5/client.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index 8daa0925..8a4d6fb1 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -47,7 +47,7 @@ type clientImpl struct { openStreams atomic.Int64 closed atomic.Bool - udpInputMap xsync.MapOf[uint16, net.Conn] + udpInputMap *xsync.MapOf[uint16, net.Conn] // only ready for PoolClient dialerRef C.Dialer @@ -270,7 +270,7 @@ func (t *clientImpl) forceClose(quicConn quic.Connection, err error) { if quicConn != nil { _ = quicConn.CloseWithError(ProtocolError, errStr) } - udpInputMap := &t.udpInputMap + udpInputMap := t.udpInputMap udpInputMap.Range(func(key uint16, value net.Conn) bool { conn := value _ = conn.Close() @@ -406,7 +406,7 @@ func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client ClientOption: clientOption, udp: udp, dialerRef: dialerRef, - udpInputMap: *xsync.NewMapOf[uint16, net.Conn](), + udpInputMap: xsync.NewMapOf[uint16, net.Conn](), } c := &Client{ci} runtime.SetFinalizer(c, closeClient) From f572e7fba8eeb13b448c4d01f4b6a2ed9944bd00 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 6 Dec 2023 12:02:50 +0800 Subject: [PATCH 142/192] fix: avoid gobwas/ws pbytes.GetLen panic --- transport/vmess/websocket.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 43faac5a..acca049f 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -65,6 +65,11 @@ type WebsocketConfig struct { // Read implements net.Conn.Read() // modify from gobwas/ws/wsutil.readData func (wsc *websocketConn) Read(b []byte) (n int, err error) { + defer func() { // avoid gobwas/ws pbytes.GetLen panic + if value := recover(); value != nil { + err = fmt.Errorf("websocket error: %s", value) + } + }() var header ws.Header for { n, err = wsc.reader.Read(b) From f63acc02026c727ab40932a90a7231b26eb65577 Mon Sep 17 00:00:00 2001 From: tommytag Date: Wed, 6 Dec 2023 17:11:24 +0800 Subject: [PATCH 143/192] healthcheck latency of the provider is also stored in the extra, without compromising rest api compatibility --- adapter/adapter.go | 138 ++++++++++----------------- adapter/outboundgroup/fallback.go | 6 +- adapter/outboundgroup/loadbalance.go | 12 +-- adapter/outboundgroup/urltest.go | 6 +- adapter/provider/healthcheck.go | 2 +- adapter/provider/provider.go | 4 - constant/adapters.go | 10 +- 7 files changed, 69 insertions(+), 109 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 60b6ad94..a3af6471 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -26,21 +26,20 @@ const ( defaultHistoriesNum = 10 ) -type extraProxyState struct { - history *queue.Queue[C.DelayHistory] +type internalProxyState struct { alive atomic.Bool + history *queue.Queue[C.DelayHistory] } type Proxy struct { C.ProxyAdapter history *queue.Queue[C.DelayHistory] alive atomic.Bool - url string - extra *xsync.MapOf[string, *extraProxyState] + extra *xsync.MapOf[string, *internalProxyState] } -// AliveForTestUrl implements C.Proxy -func (p *Proxy) AliveForTestUrl(url string) bool { +// Alive implements C.Proxy +func (p *Proxy) Alive(url string) bool { if state, ok := p.extra.Load(url); ok { return state.alive.Load() } @@ -48,10 +47,6 @@ func (p *Proxy) AliveForTestUrl(url string) bool { return p.alive.Load() } -func (p *Proxy) OriginalHealthCheckUrl(url string) { - p.url = url -} - // Dial implements C.Proxy func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) @@ -81,7 +76,7 @@ func (p *Proxy) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // DelayHistory implements C.Proxy func (p *Proxy) DelayHistory() []C.DelayHistory { queueM := p.history.Copy() - histories := []C.DelayHistory{} + var histories []C.DelayHistory for _, item := range queueM { histories = append(histories, item) } @@ -97,71 +92,52 @@ func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory { queueM = state.history.Copy() } - if queueM == nil { - queueM = p.history.Copy() - } - - histories := []C.DelayHistory{} + var histories []C.DelayHistory for _, item := range queueM { histories = append(histories, item) } return histories } -func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory { - extraHistory := map[string][]C.DelayHistory{} - - p.extra.Range(func(k string, v *extraProxyState) bool { +// ExtraDelayHistories return all delay histories for each test URL +// implements C.Proxy +func (p *Proxy) ExtraDelayHistories() map[string]C.ProxyState { + histories := map[string]C.ProxyState{} + p.extra.Range(func(k string, v *internalProxyState) bool { testUrl := k state := v - histories := []C.DelayHistory{} queueM := state.history.Copy() + var history []C.DelayHistory for _, item := range queueM { - histories = append(histories, item) + history = append(history, item) } - extraHistory[testUrl] = histories - + histories[testUrl] = C.ProxyState{ + Alive: state.alive.Load(), + History: history, + } return true }) - return extraHistory + return histories } -// LastDelay return last history record. if proxy is not alive, return the max value of uint16. +// LastDelayForTestUrl return last history record of the specified URL. if proxy is not alive, return the max value of uint16. // implements C.Proxy -func (p *Proxy) LastDelay() (delay uint16) { - var max uint16 = 0xffff - if !p.alive.Load() { - return max - } - - history := p.history.Last() - if history.Delay == 0 { - return max - } - return history.Delay -} - -// LastDelayForTestUrl implements C.Proxy func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { var max uint16 = 0xffff - alive := p.alive.Load() - history := p.history.Last() + alive := false + var history C.DelayHistory if state, ok := p.extra.Load(url); ok { alive = state.alive.Load() history = state.history.Last() } - if !alive { - return max - } - - if history.Delay == 0 { + if !alive || history.Delay == 0 { return max } return history.Delay @@ -177,8 +153,8 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { mapping := map[string]any{} _ = json.Unmarshal(inner, &mapping) mapping["history"] = p.DelayHistory() - mapping["extra"] = p.ExtraDelayHistory() - mapping["alive"] = p.AliveForTestUrl(p.url) + mapping["extra"] = p.ExtraDelayHistories() + mapping["alive"] = p.alive.Load() mapping["name"] = p.Name() mapping["udp"] = p.SupportUDP() mapping["xudp"] = p.SupportXUDP() @@ -191,43 +167,32 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (t uint16, err error) { defer func() { alive := err == nil - - if len(p.url) == 0 || url == p.url { - p.alive.Store(alive) - record := C.DelayHistory{Time: time.Now()} - if alive { - record.Delay = t - } - p.history.Put(record) - if p.history.Len() > defaultHistoriesNum { - p.history.Pop() - } - - // test URL configured by the proxy provider - if len(p.url) == 0 { - p.url = url - } - } else { - record := C.DelayHistory{Time: time.Now()} - if alive { - record.Delay = t - } - - state, ok := p.extra.Load(url) - if !ok { - state = &extraProxyState{ - history: queue.New[C.DelayHistory](defaultHistoriesNum), - alive: atomic.NewBool(true), - } - p.extra.Store(url, state) - } - - state.alive.Store(alive) - state.history.Put(record) - if state.history.Len() > defaultHistoriesNum { - state.history.Pop() - } + record := C.DelayHistory{Time: time.Now()} + if alive { + record.Delay = t } + + p.alive.Store(alive) + p.history.Put(record) + if p.history.Len() > defaultHistoriesNum { + p.history.Pop() + } + + state, ok := p.extra.Load(url) + if !ok { + state = &internalProxyState{ + history: queue.New[C.DelayHistory](defaultHistoriesNum), + alive: atomic.NewBool(true), + } + p.extra.Store(url, state) + } + + state.alive.Store(alive) + state.history.Put(record) + if state.history.Len() > defaultHistoriesNum { + state.history.Pop() + } + }() unifiedDelay := UnifiedDelay.Load() @@ -304,8 +269,7 @@ func NewProxy(adapter C.ProxyAdapter) *Proxy { ProxyAdapter: adapter, history: queue.New[C.DelayHistory](defaultHistoriesNum), alive: atomic.NewBool(true), - url: "", - extra: xsync.NewMapOf[string, *extraProxyState]()} + extra: xsync.NewMapOf[string, *internalProxyState]()} } func urlToMetadata(rawURL string) (addr C.Metadata, err error) { diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 50427e53..72d7e62a 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -102,12 +102,12 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy { proxies := f.GetProxies(touch) for _, proxy := range proxies { if len(f.selected) == 0 { - if proxy.AliveForTestUrl(f.testUrl) { + if proxy.Alive(f.testUrl) { return proxy } } else { if proxy.Name() == f.selected { - if proxy.AliveForTestUrl(f.testUrl) { + if proxy.Alive(f.testUrl) { return proxy } else { f.selected = "" @@ -133,7 +133,7 @@ func (f *Fallback) Set(name string) error { } f.selected = name - if !p.AliveForTestUrl(f.testUrl) { + if !p.Alive(f.testUrl) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000)) defer cancel() expectedStatus, _ := utils.NewIntRanges[uint16](f.expectedStatus) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 7fbc91a7..8bcd661f 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -150,8 +150,7 @@ func strategyRoundRobin(url string) strategyFn { for ; i < length; i++ { id := (idx + i) % length proxy := proxies[id] - // if proxy.Alive() { - if proxy.AliveForTestUrl(url) { + if proxy.Alive(url) { i++ return proxy } @@ -169,16 +168,14 @@ func strategyConsistentHashing(url string) strategyFn { for i := 0; i < maxRetry; i, key = i+1, key+1 { idx := jumpHash(key, buckets) proxy := proxies[idx] - // if proxy.Alive() { - if proxy.AliveForTestUrl(url) { + if proxy.Alive(url) { return proxy } } // when availability is poor, traverse the entire list to get the available nodes for _, proxy := range proxies { - // if proxy.Alive() { - if proxy.AliveForTestUrl(url) { + if proxy.Alive(url) { return proxy } } @@ -204,8 +201,7 @@ func strategyStickySessions(url string) strategyFn { nowIdx := idx for i := 1; i < maxRetry; i++ { proxy := proxies[nowIdx] - // if proxy.Alive() { - if proxy.AliveForTestUrl(url) { + if proxy.Alive(url) { if nowIdx != idx { lruCache.Delete(key) lruCache.Set(key, nowIdx) diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index bdac909f..2e533415 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -101,7 +101,7 @@ func (u *URLTest) fast(touch bool) C.Proxy { proxies := u.GetProxies(touch) if u.selected != "" { for _, proxy := range proxies { - if !proxy.AliveForTestUrl(u.testUrl) { + if !proxy.Alive(u.testUrl) { continue } if proxy.Name() == u.selected { @@ -121,7 +121,7 @@ func (u *URLTest) fast(touch bool) C.Proxy { fastNotExist = false } - if !proxy.AliveForTestUrl(u.testUrl) { + if !proxy.Alive(u.testUrl) { continue } @@ -133,7 +133,7 @@ func (u *URLTest) fast(touch bool) C.Proxy { } // tolerance - if u.fastNode == nil || fastNotExist || !u.fastNode.AliveForTestUrl(u.testUrl) || u.fastNode.LastDelayForTestUrl(u.testUrl) > fast.LastDelayForTestUrl(u.testUrl)+u.tolerance { + if u.fastNode == nil || fastNotExist || !u.fastNode.Alive(u.testUrl) || u.fastNode.LastDelayForTestUrl(u.testUrl) > fast.LastDelayForTestUrl(u.testUrl)+u.tolerance { u.fastNode = fast } return u.fastNode, nil diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index d8e56192..11118501 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -202,7 +202,7 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex defer cancel() log.Debugln("Health Checking, proxy: %s, url: %s, id: {%s}", p.Name(), url, uid) _, _ = p.URLTest(ctx, url, expectedStatus) - log.Debugln("Health Checked, proxy: %s, url: %s, alive: %t, delay: %d ms uid: {%s}", p.Name(), url, p.AliveForTestUrl(url), p.LastDelayForTestUrl(url), uid) + log.Debugln("Health Checked, proxy: %s, url: %s, alive: %t, delay: %d ms uid: {%s}", p.Name(), url, p.Alive(url), p.LastDelayForTestUrl(url), uid) return false, nil }) } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 37106e63..01ae44ee 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -114,10 +114,6 @@ func (pp *proxySetProvider) RegisterHealthCheckTask(url string, expectedStatus u func (pp *proxySetProvider) setProxies(proxies []C.Proxy) { pp.proxies = proxies - for _, proxy := range pp.proxies { - proxy.OriginalHealthCheckUrl(pp.healthCheck.url) - } - pp.healthCheck.setProxy(proxies) if pp.healthCheck.auto() { go pp.healthCheck.check() diff --git a/constant/adapters.go b/constant/adapters.go index 4a8de89b..58b2a92b 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -147,15 +147,19 @@ type DelayHistory struct { Delay uint16 `json:"delay"` } +type ProxyState struct { + Alive bool `json:"alive"` + History []DelayHistory `json:"history"` +} + type DelayHistoryStoreType int type Proxy interface { ProxyAdapter - AliveForTestUrl(url string) bool + Alive(url string) bool DelayHistory() []DelayHistory - ExtraDelayHistory() map[string][]DelayHistory + ExtraDelayHistories() map[string]ProxyState LastDelayForTestUrl(url string) uint16 - OriginalHealthCheckUrl(url string) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (uint16, error) // Deprecated: use DialContext instead. From ad263f7229e73bceddcd745b132fca3d4ee9048e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 6 Dec 2023 21:08:04 +0800 Subject: [PATCH 144/192] fix: ss uot add thread safe wrapper --- adapter/outbound/shadowsocks.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 859a10d6..3b183b7c 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -210,9 +210,9 @@ func (ss *ShadowSocks) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, destination := M.SocksaddrFromNet(metadata.UDPAddr()) if ss.option.UDPOverTCPVersion == uot.LegacyVersion { - return newPacketConn(uot.NewConn(c, uot.Request{Destination: destination}), ss), nil + return newPacketConn(N.NewThreadSafePacketConn(uot.NewConn(c, uot.Request{Destination: destination})), ss), nil } else { - return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), ss), nil + return newPacketConn(N.NewThreadSafePacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination})), ss), nil } } return nil, C.ErrNotSupport From c5d1db7905245f5947d3f6134617dd6123d6a054 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 7 Dec 2023 07:55:21 +0800 Subject: [PATCH 145/192] chore: update gvisor --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b4462c5c..95bf96fa 100644 --- a/go.mod +++ b/go.mod @@ -83,7 +83,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect + github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect diff --git a/go.sum b/go.sum index 0e0ab68c..caab0d23 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= -github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= -github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= +github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b h1:xJHepHYyQ7NOpUkEcz9wC3TnMRFjFQ3KVVqtHC/6G5s= +github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c h1:SZwaf42NVCIDaHw5X2HOnNcEiK9ao6yO+N4zYyKfXe8= From cbec564af904d68917ed28310ed3d9b4ee897f10 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 7 Dec 2023 23:32:37 +0800 Subject: [PATCH 146/192] chore: adapt new ReadWait interfaces --- adapter/outbound/shadowsocks.go | 3 +- common/net/deadline/conn.go | 149 ++++++++++++++++++++++++++++ common/net/deadline/packet_sing.go | 16 +-- common/net/packet/packet_sing.go | 20 ++-- common/net/sing.go | 7 +- go.mod | 22 ++-- go.sum | 41 ++++---- listener/sing/sing.go | 42 +++----- listener/sing_shadowsocks/server.go | 24 +++-- listener/sing_tun/dns.go | 24 ++--- transport/vless/vision/conn.go | 13 +-- tunnel/tunnel.go | 2 - 12 files changed, 249 insertions(+), 114 deletions(-) create mode 100644 common/net/deadline/conn.go diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 3b183b7c..98932f0c 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -20,6 +20,7 @@ import ( restlsC "github.com/3andne/restls-client-go" shadowsocks "github.com/metacubex/sing-shadowsocks2" + "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/uot" ) @@ -187,7 +188,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - pc = ss.method.DialPacketConn(N.NewBindPacketConn(pc, addr)) + pc = ss.method.DialPacketConn(bufio.NewBindPacketConn(pc, addr)) return newPacketConn(pc, ss), nil } diff --git a/common/net/deadline/conn.go b/common/net/deadline/conn.go new file mode 100644 index 00000000..e8446ce2 --- /dev/null +++ b/common/net/deadline/conn.go @@ -0,0 +1,149 @@ +package deadline + +import ( + "net" + "os" + "time" + + "github.com/metacubex/mihomo/common/atomic" + + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/network" +) + +type connReadResult struct { + buffer []byte + err error +} + +type Conn struct { + network.ExtendedConn + deadline atomic.TypedValue[time.Time] + pipeDeadline pipeDeadline + disablePipe atomic.Bool + inRead atomic.Bool + resultCh chan *connReadResult +} + +func NewConn(conn net.Conn) *Conn { + c := &Conn{ + ExtendedConn: bufio.NewExtendedConn(conn), + pipeDeadline: makePipeDeadline(), + resultCh: make(chan *connReadResult, 1), + } + c.resultCh <- nil + return c +} + +func (c *Conn) Read(p []byte) (n int, err error) { + select { + case result := <-c.resultCh: + if result != nil { + n = copy(p, result.buffer) + err = result.err + if n >= len(result.buffer) { + c.resultCh <- nil // finish cache read + } else { + result.buffer = result.buffer[n:] + c.resultCh <- result // push back for next call + } + return + } else { + c.resultCh <- nil + break + } + case <-c.pipeDeadline.wait(): + return 0, os.ErrDeadlineExceeded + } + + if c.disablePipe.Load() { + return c.ExtendedConn.Read(p) + } else if c.deadline.Load().IsZero() { + c.inRead.Store(true) + defer c.inRead.Store(false) + return c.ExtendedConn.Read(p) + } + + <-c.resultCh + go c.pipeRead(len(p)) + + return c.Read(p) +} + +func (c *Conn) pipeRead(size int) { + buffer := make([]byte, size) + n, err := c.ExtendedConn.Read(buffer) + buffer = buffer[:n] + c.resultCh <- &connReadResult{ + buffer: buffer, + err: err, + } +} + +func (c *Conn) ReadBuffer(buffer *buf.Buffer) (err error) { + select { + case result := <-c.resultCh: + if result != nil { + n, _ := buffer.Write(result.buffer) + err = result.err + + if n >= len(result.buffer) { + c.resultCh <- nil // finish cache read + } else { + result.buffer = result.buffer[n:] + c.resultCh <- result // push back for next call + } + return + } else { + c.resultCh <- nil + break + } + case <-c.pipeDeadline.wait(): + return os.ErrDeadlineExceeded + } + + if c.disablePipe.Load() { + return c.ExtendedConn.ReadBuffer(buffer) + } else if c.deadline.Load().IsZero() { + c.inRead.Store(true) + defer c.inRead.Store(false) + return c.ExtendedConn.ReadBuffer(buffer) + } + + <-c.resultCh + go c.pipeRead(buffer.FreeLen()) + + return c.ReadBuffer(buffer) +} + +func (c *Conn) SetReadDeadline(t time.Time) error { + if c.disablePipe.Load() { + return c.ExtendedConn.SetReadDeadline(t) + } else if c.inRead.Load() { + c.disablePipe.Store(true) + return c.ExtendedConn.SetReadDeadline(t) + } + c.deadline.Store(t) + c.pipeDeadline.set(t) + return nil +} + +func (c *Conn) ReaderReplaceable() bool { + select { + case result := <-c.resultCh: + c.resultCh <- result + if result != nil { + return false // cache reading + } else { + break + } + default: + return false // pipe reading + } + return c.disablePipe.Load() || c.deadline.Load().IsZero() +} + +func (c *Conn) Upstream() any { + return c.ExtendedConn +} diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go index 65db1b8f..d54748b0 100644 --- a/common/net/deadline/packet_sing.go +++ b/common/net/deadline/packet_sing.go @@ -5,6 +5,7 @@ import ( "runtime" "github.com/metacubex/mihomo/common/net/packet" + "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" @@ -121,17 +122,18 @@ type singPacketReadWaiter struct { type singWaitReadResult singReadResult -func (c *singPacketReadWaiter) InitializeReadWaiter(newBuffer func() *buf.Buffer) { - c.packetReadWaiter.InitializeReadWaiter(newBuffer) +func (c *singPacketReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { + return c.packetReadWaiter.InitializeReadWaiter(options) } -func (c *singPacketReadWaiter) WaitReadPacket() (destination M.Socksaddr, err error) { +func (c *singPacketReadWaiter) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { FOR: for { select { case result := <-c.netPacketConn.resultCh: if result != nil { if result, ok := result.(*singWaitReadResult); ok { + buffer = result.buffer destination = result.destination err = result.err c.netPacketConn.resultCh <- nil // finish cache read @@ -145,7 +147,7 @@ FOR: break FOR } case <-c.netPacketConn.pipeDeadline.wait(): - return M.Socksaddr{}, os.ErrDeadlineExceeded + return nil, M.Socksaddr{}, os.ErrDeadlineExceeded } } @@ -154,8 +156,7 @@ FOR: } else if c.netPacketConn.deadline.Load().IsZero() { c.netPacketConn.inRead.Store(true) defer c.netPacketConn.inRead.Store(false) - destination, err = c.packetReadWaiter.WaitReadPacket() - return + return c.packetReadWaiter.WaitReadPacket() } <-c.netPacketConn.resultCh @@ -165,8 +166,9 @@ FOR: } func (c *singPacketReadWaiter) pipeWaitReadPacket() { - destination, err := c.packetReadWaiter.WaitReadPacket() + buffer, destination, err := c.packetReadWaiter.WaitReadPacket() result := &singWaitReadResult{} + result.buffer = buffer result.destination = destination result.err = err c.netPacketConn.resultCh <- result diff --git a/common/net/packet/packet_sing.go b/common/net/packet/packet_sing.go index cfcf5ed0..6e25eb4d 100644 --- a/common/net/packet/packet_sing.go +++ b/common/net/packet/packet_sing.go @@ -24,16 +24,16 @@ type enhanceSingPacketConn struct { func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { var buff *buf.Buffer var dest M.Socksaddr - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff - } + rwOptions := N.ReadWaitOptions{} if c.packetReadWaiter != nil { - c.packetReadWaiter.InitializeReadWaiter(newBuffer) - defer c.packetReadWaiter.InitializeReadWaiter(nil) - dest, err = c.packetReadWaiter.WaitReadPacket() + c.packetReadWaiter.InitializeReadWaiter(rwOptions) + buff, dest, err = c.packetReadWaiter.WaitReadPacket() } else { - dest, err = c.SingPacketConn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = c.SingPacketConn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if dest.IsFqdn() { addr = dest @@ -41,9 +41,7 @@ func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr ne addr = dest.UDPAddr() } if err != nil { - if buff != nil { - buff.Release() - } + buff.Release() return } if buff == nil { diff --git a/common/net/sing.go b/common/net/sing.go index c92008ba..f8698620 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -5,9 +5,10 @@ import ( "net" "runtime" + "github.com/metacubex/mihomo/common/net/deadline" + "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/bufio/deadline" "github.com/sagernet/sing/common/network" ) @@ -19,8 +20,10 @@ type ExtendedConn = network.ExtendedConn type ExtendedWriter = network.ExtendedWriter type ExtendedReader = network.ExtendedReader +var WriteBuffer = bufio.WriteBuffer + func NewDeadlineConn(conn net.Conn) ExtendedConn { - return deadline.NewFallbackConn(conn) + return deadline.NewConn(conn) } func NeedHandshake(conn any) bool { diff --git a/go.mod b/go.mod index 95bf96fa..a3ca754f 100644 --- a/go.mod +++ b/go.mod @@ -21,12 +21,12 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 - github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b + github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 github.com/metacubex/sing-shadowsocks v0.2.5 - github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd - github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 - github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 + github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d + github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a + github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f + github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173 github.com/miekg/dns v1.1.57 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 @@ -34,8 +34,8 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.18-0.20231108041402-4fbbd193203c - github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 + github.com/sagernet/sing v0.2.19-0.20231207034108-445cd4f41e3f + github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 @@ -49,7 +49,7 @@ require ( go.uber.org/automaxprocs v1.5.3 golang.org/x/crypto v0.16.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa - golang.org/x/net v0.18.0 + golang.org/x/net v0.19.0 golang.org/x/sync v0.5.0 golang.org/x/sys v0.15.0 google.golang.org/protobuf v1.31.0 @@ -105,11 +105,11 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect - go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect + go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.4.0 // indirect golang.org/x/tools v0.15.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02 diff --git a/go.sum b/go.sum index caab0d23..e63025bf 100644 --- a/go.sum +++ b/go.sum @@ -107,20 +107,20 @@ github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b h1:xJHepHYyQ7NOpU github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c h1:SZwaf42NVCIDaHw5X2HOnNcEiK9ao6yO+N4zYyKfXe8= -github.com/metacubex/sing v0.0.0-20231118023733-957d84f17d2c/go.mod h1:OL6k2F0vHmEzXz2KW19qQzu172FDgSbUSODylighuVo= -github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b h1:7XXoEePvxfkQN9b2wB8UXU3uzb9uL8syEFF7A9VAKKQ= -github.com/metacubex/sing-quic v0.0.0-20231130141855-0022295e524b/go.mod h1:Gu5/zqZDd5G1AUtoV2yjAPWOEy7zwbU2DBUjdxJh0Kw= +github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02 h1:gB2vNdDTaOfko9z9WJXQkNn+rbdSEMTM7s61V4TaKhI= +github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= +github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= +github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= -github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= -github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd h1:k0+92eARqyTAovGhg2AxdsMWHjUsdiGCnR5NuXF3CQY= -github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= -github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= -github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= -github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= -github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= +github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d h1:hMs2isnO6198XaBwqbPff5bYt3uz1498osDC0sVe/dA= +github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d/go.mod h1:Y7Dm/rJpieN2xkU/pnxJCQxqmFptUCYiGd8oJhiHd0w= +github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a h1:uVDQ9vdp9MXzaX0GUf5sTqCYkf3P3v+vNcddR84F7F4= +github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a/go.mod h1:c/FrkpUp2emectVh3getHn5BxvvaEiNuEVrBdonw8U8= +github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= +github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= +github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173 h1:q5wu7tynMlhGPsRXgZ2+a16vDo6uOe9cwz483n7MRwM= +github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173/go.mod h1:swI5NYmpSOavsMyKnxSLikD9CvnCUcpjzwLdaWPNS9g= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= @@ -158,8 +158,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07 h1:ncKb5tVOsCQgCsv6UpsA0jinbNb5OQ5GMPJlyQP3EHM= -github.com/sagernet/sing-mux v0.1.5-0.20231109075101-6b086ed6bb07/go.mod h1:u/MZf32xPG8jEKe3t+xUV67EBnKtDtCaPhsJQOQGUYU= +github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266 h1:QqwwUyEfmOuoGVTZ2cYvUJEeSWlzunvQLRmv+9B41uk= +github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266/go.mod h1:uxpcXa8JqSR+ufC1sGAPsCs027wpE7v1ltnhuJKqyBQ= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -221,8 +221,8 @@ go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= -go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= +go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M= +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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= @@ -235,8 +235,8 @@ golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= -golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -256,14 +256,13 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= +golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 65c42b6a..4e31faeb 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -138,41 +138,36 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta } func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { - if deadline.NeedAdditionalReadDeadline(conn) { - conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline - } defer func() { _ = conn.Close() }() mutex := sync.Mutex{} - conn2 := conn // a new interface to set nil in defer + conn2 := bufio.NewNetPacketConn(conn) // a new interface to set nil in defer defer func() { mutex.Lock() // this goroutine must exit after all conn.WritePacket() is not running defer mutex.Unlock() conn2 = nil }() - var buff *buf.Buffer - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff - } + rwOptions := network.ReadWaitOptions{} readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { - readWaiter.InitializeReadWaiter(newBuffer) + readWaiter.InitializeReadWaiter(rwOptions) } for { var ( + buff *buf.Buffer dest M.Socksaddr err error ) - buff = nil // clear last loop status, avoid repeat release if isReadWaiter { - dest, err = readWaiter.WaitReadPacket() + buff, dest, err = readWaiter.WaitReadPacket() } else { - dest, err = conn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = conn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if err != nil { - if buff != nil { - buff.Release() - } + buff.Release() if ShouldIgnorePacketError(err) { break } @@ -212,7 +207,7 @@ func ShouldIgnorePacketError(err error) bool { } type packet struct { - conn *network.PacketConn + conn *network.NetPacketConn mutex *sync.Mutex rAddr net.Addr lAddr net.Addr @@ -238,18 +233,7 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { return } - buff := buf.NewPacket() - defer buff.Release() - n, err = buff.Write(b) - if err != nil { - return - } - - err = conn.WritePacket(buff, M.SocksaddrFromNet(addr)) - if err != nil { - return - } - return + return conn.WriteTo(b, addr) } // LocalAddr returns the source IP/Port of UDP Packet diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 1760e43c..bd5002a4 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -23,6 +23,7 @@ import ( "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/common/network" ) type Listener struct { @@ -96,30 +97,33 @@ func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addi go func() { conn := bufio.NewPacketConn(ul) - var buff *buf.Buffer - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff + rwOptions := network.ReadWaitOptions{ + FrontHeadroom: network.CalculateFrontHeadroom(sl.service), + RearHeadroom: network.CalculateRearHeadroom(sl.service), + MTU: network.CalculateMTU(conn, sl.service), } readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { - readWaiter.InitializeReadWaiter(newBuffer) + readWaiter.InitializeReadWaiter(rwOptions) } for { var ( + buff *buf.Buffer dest M.Socksaddr err error ) buff = nil // clear last loop status, avoid repeat release if isReadWaiter { - dest, err = readWaiter.WaitReadPacket() + buff, dest, err = readWaiter.WaitReadPacket() } else { - dest, err = conn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = conn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if err != nil { - if buff != nil { - buff.Release() - } + buff.Release() if sl.closed { break } diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 122f5a32..4fd38e1d 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -109,29 +109,29 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() - - var buff *buf.Buffer - newBuffer := func() *buf.Buffer { - // safe size which is 1232 from https://dnsflagday.net/2020/. - // so 2048 is enough - buff = buf.NewSize(2 * 1024) - return buff + rwOptions := network.ReadWaitOptions{ + MTU: 2 * 1024, // safe size which is 1232 from https://dnsflagday.net/2020/, so 2048 is enough } readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { - readWaiter.InitializeReadWaiter(newBuffer) + readWaiter.InitializeReadWaiter(rwOptions) } for { var ( + buff *buf.Buffer dest M.Socksaddr err error ) _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) buff = nil // clear last loop status, avoid repeat release if isReadWaiter { - dest, err = readWaiter.WaitReadPacket() + buff, dest, err = readWaiter.WaitReadPacket() } else { - dest, err = conn.ReadPacket(newBuffer()) + buff = rwOptions.NewPacketBuffer() + dest, err = conn.ReadPacket(buff) + if buff != nil { + rwOptions.PostReturn(buff) + } } if err != nil { if buff != nil { @@ -142,7 +142,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } return err } - go func(buff *buf.Buffer) { + go func() { ctx, cancel := context.WithTimeout(ctx, DefaultDnsRelayTimeout) defer cancel() inData := buff.Bytes() @@ -167,7 +167,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. if err != nil { return } - }(buff) // catch buff at goroutine create, avoid next loop change buff + }() } return nil } diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index 79c77835..5ad28134 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -157,14 +157,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { func (vc *Conn) Write(p []byte) (int, error) { if vc.writeFilterApplicationData { - buffer := buf.New() - defer buffer.Release() - buffer.Write(p) - err := vc.WriteBuffer(buffer) - if err != nil { - return 0, err - } - return len(p), nil + return N.WriteBuffer(vc, buf.As(p)) } return vc.ExtendedWriter.Write(p) } @@ -266,6 +259,10 @@ func (vc *Conn) FrontHeadroom() int { return PaddingHeaderLen - uuid.Size } +func (vc *Conn) RearHeadroom() int { + return 500 + 900 +} + func (vc *Conn) NeedHandshake() bool { return vc.needHandshake } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index c37b0c7d..2454fd9a 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -375,7 +375,6 @@ func handleUDPConn(packet C.PacketAdapter) { cond.Broadcast() }() - pCtx := icontext.NewPacketConnContext(metadata) proxy, rule, err := resolveMetadata(metadata) if err != nil { log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) @@ -402,7 +401,6 @@ func handleUDPConn(packet C.PacketAdapter) { if err != nil { return } - pCtx.InjectPacketConn(rawPc) pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true) From 9ac4738ef9af9bd78a6db4b76e84418bfec05595 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 01:25:07 +0800 Subject: [PATCH 147/192] fix: system stack's dns hijack not working --- listener/sing_tun/dns.go | 58 ++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 4fd38e1d..57dcb1a5 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -73,7 +73,7 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta ctx, cancel := context.WithTimeout(ctx, DefaultDnsRelayTimeout) defer cancel() inData := buff[:n] - msg, err := RelayDnsPacket(ctx, inData) + msg, err := RelayDnsPacket(ctx, inData, buff) if err != nil { return err } @@ -110,7 +110,9 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. conn2 = nil }() rwOptions := network.ReadWaitOptions{ - MTU: 2 * 1024, // safe size which is 1232 from https://dnsflagday.net/2020/, so 2048 is enough + FrontHeadroom: network.CalculateFrontHeadroom(conn), + RearHeadroom: network.CalculateRearHeadroom(conn), + MTU: 2 * 1024, // safe size which is 1232 from https://dnsflagday.net/2020/, so 2048 is enough } readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { @@ -118,24 +120,24 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } for { var ( - buff *buf.Buffer - dest M.Socksaddr - err error + readBuff *buf.Buffer + dest M.Socksaddr + err error ) _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) - buff = nil // clear last loop status, avoid repeat release + readBuff = nil // clear last loop status, avoid repeat release if isReadWaiter { - buff, dest, err = readWaiter.WaitReadPacket() + readBuff, dest, err = readWaiter.WaitReadPacket() } else { - buff = rwOptions.NewPacketBuffer() - dest, err = conn.ReadPacket(buff) - if buff != nil { - rwOptions.PostReturn(buff) + readBuff = rwOptions.NewPacketBuffer() + dest, err = conn.ReadPacket(readBuff) + if readBuff != nil { + rwOptions.PostReturn(readBuff) } } if err != nil { - if buff != nil { - buff.Release() + if readBuff != nil { + readBuff.Release() } if sing.ShouldIgnorePacketError(err) { break @@ -145,26 +147,30 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. go func() { ctx, cancel := context.WithTimeout(ctx, DefaultDnsRelayTimeout) defer cancel() - inData := buff.Bytes() - msg, err := RelayDnsPacket(ctx, inData) + inData := readBuff.Bytes() + writeBuff := readBuff + if writeBuff.Cap() < rwOptions.MTU { // only create a new buffer when space don't enough + writeBuff = rwOptions.NewPacketBuffer() + } + msg, err := RelayDnsPacket(ctx, inData, writeBuff.FreeBytes()) + if writeBuff != readBuff { + readBuff.Release() + } if err != nil { - buff.Release() - return - } - buff.Reset() - _, err = buff.Write(msg) - if err != nil { - buff.Release() + writeBuff.Release() return } + writeBuff.Truncate(len(msg)) mutex.Lock() defer mutex.Unlock() conn := conn2 if conn == nil { + writeBuff.Release() return } - err = conn.WritePacket(buff, dest) // WritePacket will release buff + err = conn.WritePacket(writeBuff, dest) // WritePacket will release writeBuff if err != nil { + writeBuff.Release() return } }() @@ -174,7 +180,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. return h.ListenerHandler.NewPacketConnection(ctx, conn, metadata) } -func RelayDnsPacket(ctx context.Context, payload []byte) ([]byte, error) { +func RelayDnsPacket(ctx context.Context, payload []byte, target []byte) ([]byte, error) { msg := &D.Msg{} if err := msg.Unpack(payload); err != nil { return nil, err @@ -184,10 +190,10 @@ func RelayDnsPacket(ctx context.Context, payload []byte) ([]byte, error) { if err != nil { m := new(D.Msg) m.SetRcode(msg, D.RcodeServerFailure) - return m.Pack() + return m.PackBuffer(target) } r.SetRcode(msg, r.Rcode) r.Compress = true - return r.Pack() + return r.PackBuffer(target) } From 73e16c912fdae77f465acdc883c6cc9740bdf04f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 07:16:45 +0800 Subject: [PATCH 148/192] fix: remove unneeded health check --- hub/executor/executor.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 72d7380e..857ed3c6 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -313,9 +313,6 @@ func loadProxyProvider(proxyProviders map[string]provider.ProxyProvider) { go func() { defer func() { <-ch; wg.Done() }() loadProvider(proxyProvider) - if proxyProvider.VehicleType() == provider.Compatible { - go proxyProvider.HealthCheck() - } }() } From 1b527fd494e8b2ad713ea0afcf9af485d452d61c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 08:55:45 +0800 Subject: [PATCH 149/192] chore: windows process will return DOS format instead of NT format --- component/process/process_windows.go | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/component/process/process_windows.go b/component/process/process_windows.go index d43c78c6..820493ec 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -3,6 +3,8 @@ package process import ( "fmt" "net/netip" + "path/filepath" + "strings" "sync" "syscall" "unsafe" @@ -101,6 +103,10 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string return 0, "", err } pp, err := getExecPathFromPID(pid) + if err != nil { + return 0, "", err + } + pp, err = convertDOSPath(pp) return 0, pp, err } @@ -227,3 +233,29 @@ func getExecPathFromPID(pid uint32) (string, error) { } return syscall.UTF16ToString(buf[:size]), nil } + +// modify from https://github.com/shirou/gopsutil/blob/9deadc99147d80f732af3a59e624af73d0143891/internal/common/common_windows.go#L220-L241 +// Convert paths using native DOS format like: +// +// "\Device\HarddiskVolume1\Windows\systemew\file.txt" +// +// into: +// +// "C:\Windows\systemew\file.txt" +func convertDOSPath(p string) (string, error) { + rawDrive := strings.Join(strings.Split(p, `\`)[:3], `\`) + + for d := 'A'; d <= 'Z'; d++ { + szDeviceName := string(d) + ":" + deviceName, err := syscall.UTF16PtrFromString(szDeviceName) + if err != nil { + return "", err + } + szTarget := make([]uint16, 512) + n, err := windows.QueryDosDevice(deviceName, &szTarget[0], uint32(len(szTarget))) + if err == nil && windows.UTF16ToString(szTarget[:n]) == rawDrive { + return filepath.Join(szDeviceName, p[len(rawDrive):]), nil + } + } + return p, nil +} From 1d1841f7aad3f45526aec0000511c8ea3b64e9fe Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 08:59:59 +0800 Subject: [PATCH 150/192] fix: missing insertTriePolicy when process rule-set --- dns/resolver.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dns/resolver.go b/dns/resolver.go index 0f2873f0..67e6fbc2 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -501,6 +501,7 @@ func NewResolver(config Config) *Resolver { case "rule-set": if p, ok := config.RuleProviders[key]; ok { log.Debugln("Adding rule-set policy: %s ", key) + insertTriePolicy() r.policy = append(r.policy, domainSetPolicy{ domainSetProvider: p, dnsClients: cacheTransform(nameserver), From b538aa6ca2f0e736b9544f011ddd8a5056da2ae2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 09:26:24 +0800 Subject: [PATCH 151/192] chore: code cleanup --- dns/resolver.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dns/resolver.go b/dns/resolver.go index 67e6fbc2..47ea78d8 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -483,12 +483,15 @@ func NewResolver(config Config) *Resolver { r.policy = make([]dnsPolicy, 0) var triePolicy *trie.DomainTrie[[]dnsClient] - insertTriePolicy := func() { + insertPolicy := func(policy dnsPolicy) { if triePolicy != nil { triePolicy.Optimize() r.policy = append(r.policy, domainTriePolicy{triePolicy}) triePolicy = nil } + if policy != nil { + r.policy = append(r.policy, policy) + } } for pair := config.Policy.Oldest(); pair != nil; pair = pair.Next() { @@ -501,8 +504,7 @@ func NewResolver(config Config) *Resolver { case "rule-set": if p, ok := config.RuleProviders[key]; ok { log.Debugln("Adding rule-set policy: %s ", key) - insertTriePolicy() - r.policy = append(r.policy, domainSetPolicy{ + insertPolicy(domainSetPolicy{ domainSetProvider: p, dnsClients: cacheTransform(nameserver), }) @@ -522,8 +524,7 @@ func NewResolver(config Config) *Resolver { log.Warnln("adding geosite policy %s error: %s", key, err) continue } - insertTriePolicy() - r.policy = append(r.policy, geositePolicy{ + insertPolicy(geositePolicy{ matcher: matcher, inverse: inverse, dnsClients: cacheTransform(nameserver), @@ -536,7 +537,7 @@ func NewResolver(config Config) *Resolver { } _ = triePolicy.Insert(domain, cacheTransform(nameserver)) } - insertTriePolicy() + insertPolicy(nil) } fallbackIPFilters := []fallbackIPFilter{} From fdc9c01df15e334f49af8777326a6b225c95b4a4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 10:13:08 +0800 Subject: [PATCH 152/192] fix: gvisor stack's dns hijack not working --- listener/sing_tun/dns.go | 1 + 1 file changed, 1 insertion(+) diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 57dcb1a5..9974eae4 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -149,6 +149,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer cancel() inData := readBuff.Bytes() writeBuff := readBuff + writeBuff.Resize(writeBuff.Start(), 0) if writeBuff.Cap() < rwOptions.MTU { // only create a new buffer when space don't enough writeBuff = rwOptions.NewPacketBuffer() } From 941dd6c76d014229577f38e1b69815a80232ab62 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 13:04:17 +0800 Subject: [PATCH 153/192] fix: CopyExtendedOnce can't exit loop --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a3ca754f..388b1cd2 100644 --- a/go.mod +++ b/go.mod @@ -112,4 +112,4 @@ require ( golang.org/x/tools v0.15.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231208050038-06f23c7aec62 diff --git a/go.sum b/go.sum index e63025bf..d78d492f 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b h1:xJHepHYyQ7NOpU github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02 h1:gB2vNdDTaOfko9z9WJXQkNn+rbdSEMTM7s61V4TaKhI= -github.com/metacubex/sing v0.0.0-20231207144554-52b6f9095d02/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= +github.com/metacubex/sing v0.0.0-20231208050038-06f23c7aec62 h1:4GllFkmFfTJO2zBZkmt1ry6oIG8TtptphXEhGcHyHio= +github.com/metacubex/sing v0.0.0-20231208050038-06f23c7aec62/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= From 8dbc5e2100aa99851efeced9436238211afecbdd Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 13:13:47 +0800 Subject: [PATCH 154/192] chore: limit max CopyExtendedOnce execute times to 10 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 388b1cd2..0a1e47a4 100644 --- a/go.mod +++ b/go.mod @@ -112,4 +112,4 @@ require ( golang.org/x/tools v0.15.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231208050038-06f23c7aec62 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231208051255-e793d03637a2 diff --git a/go.sum b/go.sum index d78d492f..ba80508c 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b h1:xJHepHYyQ7NOpU github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231208050038-06f23c7aec62 h1:4GllFkmFfTJO2zBZkmt1ry6oIG8TtptphXEhGcHyHio= -github.com/metacubex/sing v0.0.0-20231208050038-06f23c7aec62/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= +github.com/metacubex/sing v0.0.0-20231208051255-e793d03637a2 h1:1OyvD7+5A6qc2iPTzjwjNvgXTvJ/pdbFd9FSFHG4Dhs= +github.com/metacubex/sing v0.0.0-20231208051255-e793d03637a2/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= From 262d3295d181c52b65931db9f4fbe53e6c69a96f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 8 Dec 2023 19:04:29 +0800 Subject: [PATCH 155/192] chore: using stable api --- go.mod | 6 +++--- go.sum | 13 +++++++------ listener/sing_tun/dns.go | 6 ++++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 0a1e47a4..ab7cdf11 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 - github.com/metacubex/sing-shadowsocks v0.2.5 + github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f @@ -58,7 +58,7 @@ require ( ) require ( - github.com/RyuaNerin/go-krypto v1.0.2 // indirect + github.com/RyuaNerin/go-krypto v1.2.4 // indirect github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect @@ -112,4 +112,4 @@ require ( golang.org/x/tools v0.15.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231208051255-e793d03637a2 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231208104608-1d45b24eb8fa diff --git a/go.sum b/go.sum index ba80508c..408f665f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,8 @@ github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08= github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY= -github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM= -github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA= +github.com/RyuaNerin/elliptic2 v1.0.0/go.mod h1:wWB8fWrJI/6EPJkyV/r1Rj0hxUgrusmqSj8JN6yNf/A= +github.com/RyuaNerin/go-krypto v1.2.4 h1:mXuNdK6M317aPV0llW6Xpjbo4moOlPF7Yxz4tb4b4Go= +github.com/RyuaNerin/go-krypto v1.2.4/go.mod h1:QqCYkoutU3yInyD9INt2PGolVRsc3W4oraQadVGXJ/8= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= @@ -107,12 +108,12 @@ github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b h1:xJHepHYyQ7NOpU github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231208051255-e793d03637a2 h1:1OyvD7+5A6qc2iPTzjwjNvgXTvJ/pdbFd9FSFHG4Dhs= -github.com/metacubex/sing v0.0.0-20231208051255-e793d03637a2/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= +github.com/metacubex/sing v0.0.0-20231208104608-1d45b24eb8fa h1:M1jWSzH2aw2GapJbwHf4PWKEz/5q9I2bfmIdkQVcJ/0= +github.com/metacubex/sing v0.0.0-20231208104608-1d45b24eb8fa/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= -github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= -github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= +github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= +github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d h1:hMs2isnO6198XaBwqbPff5bYt3uz1498osDC0sVe/dA= github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d/go.mod h1:Y7Dm/rJpieN2xkU/pnxJCQxqmFptUCYiGd8oJhiHd0w= github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a h1:uVDQ9vdp9MXzaX0GUf5sTqCYkf3P3v+vNcddR84F7F4= diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 9974eae4..056c9169 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -98,6 +98,8 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta return h.ListenerHandler.NewConnection(ctx, conn, metadata) } +const SafeDnsPacketSize = 2 * 1024 // safe size which is 1232 from https://dnsflagday.net/2020/, so 2048 is enough + func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { if h.ShouldHijackDns(metadata.Destination.AddrPort()) { log.Debugln("[DNS] hijack udp:%s from %s", metadata.Destination.String(), metadata.Source.String()) @@ -112,7 +114,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. rwOptions := network.ReadWaitOptions{ FrontHeadroom: network.CalculateFrontHeadroom(conn), RearHeadroom: network.CalculateRearHeadroom(conn), - MTU: 2 * 1024, // safe size which is 1232 from https://dnsflagday.net/2020/, so 2048 is enough + MTU: SafeDnsPacketSize, } readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) if isReadWaiter { @@ -150,7 +152,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. inData := readBuff.Bytes() writeBuff := readBuff writeBuff.Resize(writeBuff.Start(), 0) - if writeBuff.Cap() < rwOptions.MTU { // only create a new buffer when space don't enough + if len(writeBuff.FreeBytes()) < SafeDnsPacketSize { // only create a new buffer when space don't enough writeBuff = rwOptions.NewPacketBuffer() } msg, err := RelayDnsPacket(ctx, inData, writeBuff.FreeBytes()) From 582ac28728d2366bdd2a335a178c9949fd9c0624 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 8 Dec 2023 21:22:20 +0800 Subject: [PATCH 156/192] chore: Update bandwidth convertor Sync with https://github.com/apernet/hysteria/commit/6d6a26b3995dec982d5989ef738796a23a0a6495 --- adapter/outbound/util.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index ce9e5f65..2c85c7c8 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -140,24 +140,25 @@ func StringToBps(s string) uint64 { if m == nil { return 0 } - var n uint64 + var n uint64 = 1 switch m[2] { - case "K": - n = 1 << 10 - case "M": - n = 1 << 20 - case "G": - n = 1 << 30 case "T": - n = 1 << 40 - default: - n = 1 + n *= 1000 + fallthrough + case "G": + n *= 1000 + fallthrough + case "M": + n *= 1000 + fallthrough + case "K": + n *= 1000 } v, _ := strconv.ParseUint(m[1], 10, 64) - n = v * n + n *= v if m[3] == "b" { // Bits, need to convert to bytes - n = n >> 3 + n /= 8 } return n } From da65f8f935c118ddae5d1a44f1c64093e9df8c2b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 9 Dec 2023 09:24:41 +0800 Subject: [PATCH 157/192] action: add GOTOOLCHAIN=local in build.yml --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2767af8b..1b7086dd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -129,6 +129,7 @@ jobs: run: | echo "TAGS=with_gvisor,with_lwip" >> $GITHUB_ENV echo "LDFLAGS=-X 'github.com/metacubex/mihomo/constant.Version=${VERSION}' -X 'github.com/metacubex/mihomo/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" >> $GITHUB_ENV + echo "GOTOOLCHAIN=local" >> $GITHUB_ENV shell: bash - name: Setup Go From c5d1e20a64d70cb428ebd3ff6aa33a0eca6eefc0 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 9 Dec 2023 09:46:37 +0800 Subject: [PATCH 158/192] chore: Update dependencies --- go.mod | 16 ++++++++-------- go.sum | 29 ++++++++++++++--------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index ab7cdf11..54df3fd6 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/go-chi/render v1.0.3 github.com/gobwas/ws v1.3.1 github.com/gofrs/uuid/v5 v5.0.0 - github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c + github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 github.com/jpillora/backoff v1.0.0 github.com/klauspost/cpuid/v2 v2.2.6 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 @@ -34,21 +34,21 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.19-0.20231207034108-445cd4f41e3f - github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266 + github.com/sagernet/sing v0.2.19-0.20231208110306-a3ce328ce759 + github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f - github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.10 + github.com/samber/lo v1.39.0 + github.com/shirou/gopsutil/v3 v3.23.11 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 github.com/wk8/go-ordered-map/v2 v2.1.8 github.com/zhangyunhao116/fastrand v0.3.0 go.uber.org/automaxprocs v1.5.3 golang.org/x/crypto v0.16.0 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa + golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb golang.org/x/net v0.19.0 golang.org/x/sync v0.5.0 golang.org/x/sys v0.15.0 @@ -92,7 +92,7 @@ require ( github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect + github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect @@ -109,7 +109,7 @@ require ( golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.4.0 // indirect - golang.org/x/tools v0.15.0 // indirect + golang.org/x/tools v0.16.0 // indirect ) replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231208104608-1d45b24eb8fa diff --git a/go.sum b/go.sum index 408f665f..9e736299 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,8 @@ github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c h1:PgxFEySCI41sH0mB7/2XswdXbUykQsRUGod8Rn+NubM= -github.com/insomniacslk/dhcp v0.0.0-20231016090811-6a2c8fbdcc1c/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= +github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2 h1:9K06NfxkBh25x56yVhWWlKFE8YpicaSfHwoV8SFbueA= +github.com/insomniacslk/dhcp v0.0.0-20231206064809-8c70d406f6d2/go.mod h1:3A9PQ1cunSDF/1rbTq99Ts4pVnycWg+vlPkfeD2NLFI= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= @@ -159,24 +159,24 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266 h1:QqwwUyEfmOuoGVTZ2cYvUJEeSWlzunvQLRmv+9B41uk= -github.com/sagernet/sing-mux v0.1.6-0.20231207143704-9f6c20fb5266/go.mod h1:uxpcXa8JqSR+ufC1sGAPsCs027wpE7v1ltnhuJKqyBQ= +github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 h1:rRlYQPbMKmzKX+43XC04gEQvxc45/AxfteRWfcl2/rw= +github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2/go.mod h1:IdSrwwqBeJTrjLZJRFXE+F8mYXNI/rPAjzlgTFuEVmo= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= -github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= -github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= +github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= +github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q= github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= -github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= -github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= +github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= +github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM= -github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE= +github.com/shirou/gopsutil/v3 v3.23.11 h1:i3jP9NjCPUz7FiZKxlMnODZkdSIp2gnzfrvsu9CuWEQ= +github.com/shirou/gopsutil/v3 v3.23.11/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -228,8 +228,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb h1:c0vyKkb6yr3KR7jEfJaOSv4lG7xPkbN6r52aJz1d8a8= +golang.org/x/exp v0.0.0-20231206192017-f3f8817b8deb/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= @@ -256,7 +256,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -265,8 +264,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.15.0 h1:zdAyfUGbYmuVokhzVmghFl2ZJh5QhcfebBgmVPFYA+8= -golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk= +golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= +golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= From 9729c2e440f5a288eaea4d364786d0ebddf6d054 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 9 Dec 2023 10:53:19 +0800 Subject: [PATCH 159/192] chore: don't force output color in log but you can set `CLICOLOR_FORCE=1` environment variable --- log/log.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/log/log.go b/log/log.go index d0c9b330..6f565e7c 100644 --- a/log/log.go +++ b/log/log.go @@ -19,9 +19,9 @@ func init() { log.SetOutput(os.Stdout) log.SetLevel(log.DebugLevel) log.SetFormatter(&log.TextFormatter{ - FullTimestamp: true, - TimestampFormat: "2006-01-02T15:04:05.999999999Z07:00", - ForceColors: true, + FullTimestamp: true, + TimestampFormat: "2006-01-02T15:04:05.999999999Z07:00", + EnvironmentOverrideColors: true, }) } From 5a2ed71bd9adc08e5423a5ffc713065489aeed5b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 9 Dec 2023 12:28:19 +0800 Subject: [PATCH 160/192] chore: update uTLS to 1.5.4 --- component/tls/reality.go | 16 ++++++++++++---- component/tls/utls.go | 25 +++++++++++++++---------- go.mod | 9 +++++---- go.sum | 18 ++++++++++-------- 4 files changed, 42 insertions(+), 26 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index 250dc4d0..f8d5ab23 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -5,6 +5,7 @@ import ( "context" "crypto/aes" "crypto/cipher" + "crypto/ecdh" "crypto/ed25519" "crypto/hmac" "crypto/sha256" @@ -81,15 +82,22 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) - ecdheParams := uConn.HandshakeState.State13.EcdheParams - if ecdheParams == nil { + publicKey, err := ecdh.X25519().NewPublicKey(realityConfig.PublicKey[:]) + if err != nil { + return nil, err + } + ecdheKey := uConn.HandshakeState.State13.EcdheKey + if ecdheKey == nil { // WTF??? if retry > 2 { - return nil, errors.New("nil ecdheParams") + return nil, errors.New("nil ecdheKey") } continue // retry } - authKey := ecdheParams.SharedKey(realityConfig.PublicKey[:]) + authKey, err := ecdheKey.ECDH(publicKey) + if err != nil { + return nil, err + } if authKey == nil { return nil, errors.New("nil auth_key") } diff --git a/component/tls/utls.go b/component/tls/utls.go index 787f6fad..3063fc55 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -68,16 +68,21 @@ func RollFingerprint() (UClientHelloID, bool) { } var Fingerprints = map[string]UClientHelloID{ - "chrome": {&utls.HelloChrome_Auto}, - "firefox": {&utls.HelloFirefox_Auto}, - "safari": {&utls.HelloSafari_Auto}, - "ios": {&utls.HelloIOS_Auto}, - "android": {&utls.HelloAndroid_11_OkHttp}, - "edge": {&utls.HelloEdge_Auto}, - "360": {&utls.Hello360_Auto}, - "qq": {&utls.HelloQQ_Auto}, - "random": {nil}, - "randomized": {nil}, + "chrome": {&utls.HelloChrome_Auto}, + "chrome_psk": {&utls.HelloChrome_100_PSK}, + "chrome_psk_shuffle": {&utls.HelloChrome_106_Shuffle}, + "chrome_padding_psk_shuffle": {&utls.HelloChrome_114_Padding_PSK_Shuf}, + "chrome_pq": {&utls.HelloChrome_115_PQ}, + "chrome_pq_psk": {&utls.HelloChrome_115_PQ_PSK}, + "firefox": {&utls.HelloFirefox_Auto}, + "safari": {&utls.HelloSafari_Auto}, + "ios": {&utls.HelloIOS_Auto}, + "android": {&utls.HelloAndroid_11_OkHttp}, + "edge": {&utls.HelloEdge_Auto}, + "360": {&utls.Hello360_Auto}, + "qq": {&utls.HelloQQ_Auto}, + "random": {nil}, + "randomized": {nil}, } func init() { diff --git a/go.mod b/go.mod index 54df3fd6..cab1173c 100644 --- a/go.mod +++ b/go.mod @@ -37,8 +37,8 @@ require ( github.com/sagernet/sing v0.2.19-0.20231208110306-a3ce328ce759 github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 - github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 + github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 + github.com/sagernet/utls v1.5.4 github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f github.com/samber/lo v1.39.0 github.com/shirou/gopsutil/v3 v3.23.11 @@ -61,8 +61,9 @@ require ( github.com/RyuaNerin/go-krypto v1.2.4 // indirect github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/ajg/form v1.5.1 // indirect - github.com/andybalholm/brotli v1.0.5 // indirect + github.com/andybalholm/brotli v1.0.6 // indirect github.com/buger/jsonparser v1.1.1 // indirect + github.com/cloudflare/circl v1.3.6 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect @@ -79,7 +80,7 @@ require ( github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/josharian/native v1.1.0 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.4 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/socket v0.4.1 // indirect diff --git a/go.sum b/go.sum index 9e736299..f44e84fb 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= -github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI= +github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= @@ -21,6 +21,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= +github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= +github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -86,8 +88,8 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= +github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -165,10 +167,10 @@ github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnV github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= -github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q= -github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= -github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= -github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= +github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26Wn/UByW6b7q8QKB0ZkPqsyqcz2PI= +github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6/go.mod h1:73xRZuxwkFk4aiLw28hG8W6o9cr2UPrGL9pdY2UTbvY= +github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co= +github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= From d80fcb77f6314d2f961b26a4584eccd84576230b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 9 Dec 2023 18:58:36 +0800 Subject: [PATCH 161/192] chore: health check for compatible providers after startup --- adapter/outboundgroup/parser.go | 2 +- adapter/provider/provider.go | 3 +++ hub/executor/executor.go | 23 ++++++++++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 422349fe..ea1b51e1 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -104,7 +104,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide } } - hc := provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), true, expectedStatus) + hc := provider.NewHealthCheck(ps, testUrl, uint(groupOption.Interval), groupOption.Lazy, expectedStatus) pd, err := provider.NewCompatibleProvider(groupName, ps, hc) if err != nil { diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 01ae44ee..81ec6c63 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -252,6 +252,9 @@ func (cp *compatibleProvider) Update() error { } func (cp *compatibleProvider) Initial() error { + if cp.healthCheck.interval != 0 && cp.healthCheck.url != "" { + cp.HealthCheck() + } return nil } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 857ed3c6..edab400f 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -112,6 +112,7 @@ func ApplyConfig(cfg *config.Config, force bool) { loadRuleProvider(cfg.RuleProviders) runtime.GC() tunnel.OnRunning() + hcCompatibleProvider(cfg.Providers) log.SetLevel(cfg.General.LogLevel) } @@ -265,7 +266,7 @@ func updateRules(rules []C.Rule, subRules map[string][]C.Rule, ruleProviders map func loadProvider(pv provider.Provider) { if pv.VehicleType() == provider.Compatible { - log.Infoln("Start initial compatible provider %s", pv.Name()) + return } else { log.Infoln("Start initial provider %s", (pv).Name()) } @@ -318,7 +319,27 @@ func loadProxyProvider(proxyProviders map[string]provider.ProxyProvider) { wg.Wait() } +func hcCompatibleProvider(proxyProviders map[string]provider.ProxyProvider) { + // limit concurrent size + wg := sync.WaitGroup{} + ch := make(chan struct{}, concurrentCount) + for _, proxyProvider := range proxyProviders { + proxyProvider := proxyProvider + if proxyProvider.VehicleType() == provider.Compatible { + log.Infoln("Start initial Compatible provider %s", proxyProvider.Name()) + wg.Add(1) + ch <- struct{}{} + go func() { + defer func() { <-ch; wg.Done() }() + if err := proxyProvider.Initial(); err != nil { + log.Errorln("initial Compatible provider %s error: %v", proxyProvider.Name(), err) + } + }() + } + } + +} func updateTun(general *config.General) { if general == nil { return From 9fc1fc4cfea082ccf88a645d0cdb374985d4bbdf Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 10 Dec 2023 08:32:54 +0800 Subject: [PATCH 162/192] chore: add GSO support for TUN lwip had been dropped, also cgo build will be removed --- .github/workflows/build.yml | 22 +++++++++++----------- config/config.go | 10 +++++++++- constant/tun.go | 4 ---- docs/config.yaml | 8 +++++++- go.mod | 15 +++++++-------- go.sum | 26 ++++++++++++-------------- hub/route/configs.go | 18 +++++++++++++++++- listener/config/tun.go | 4 ++++ listener/inbound/tun.go | 8 ++++++++ listener/listener.go | 12 ++++++++++++ listener/sing_tun/server.go | 14 +++++++++----- 11 files changed, 96 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b7086dd..da340282 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -75,17 +75,17 @@ jobs: - { type: "WithoutCGO-GO120", target: "windows-amd64-compatible windows-amd64 windows-386",id: "2" } # Go 1.20 is the last release that will run on macOS 10.13 High Sierra or 10.14 Mojave. Go 1.21 will require macOS 10.15 Catalina or later. - { type: "WithoutCGO-GO120", target: "darwin-amd64 darwin-arm64 android-arm64",id: "3" } - - { type: "WithCGO", target: "windows/*", id: "1" } - - { type: "WithCGO", target: "linux/386", id: "2" } - - { type: "WithCGO", target: "linux/amd64", id: "3" } - - { type: "WithCGO", target: "linux/arm64,linux/riscv64", id: "4" } - - { type: "WithCGO", target: "linux/arm,", id: "5" } - - { type: "WithCGO", target: "linux/arm-6,linux/arm-7", id: "6" } - - { type: "WithCGO", target: "linux/mips,linux/mipsle", id: "7" } - - { type: "WithCGO", target: "linux/mips64", id: "8" } - - { type: "WithCGO", target: "linux/mips64le", id: "9" } - - { type: "WithCGO", target: "darwin-10.16/*", id: "10" } - - { type: "WithCGO", target: "android", id: "11" } +# - { type: "WithCGO", target: "windows/*", id: "1" } +# - { type: "WithCGO", target: "linux/386", id: "2" } +# - { type: "WithCGO", target: "linux/amd64", id: "3" } +# - { type: "WithCGO", target: "linux/arm64,linux/riscv64", id: "4" } +# - { type: "WithCGO", target: "linux/arm,", id: "5" } +# - { type: "WithCGO", target: "linux/arm-6,linux/arm-7", id: "6" } +# - { type: "WithCGO", target: "linux/mips,linux/mipsle", id: "7" } +# - { type: "WithCGO", target: "linux/mips64", id: "8" } +# - { type: "WithCGO", target: "linux/mips64le", id: "9" } +# - { type: "WithCGO", target: "darwin-10.16/*", id: "10" } +# - { type: "WithCGO", target: "android", id: "11" } steps: - name: Check out code into the Go module directory diff --git a/config/config.go b/config/config.go index 665b8539..5f4995fe 100644 --- a/config/config.go +++ b/config/config.go @@ -238,7 +238,9 @@ type RawTun struct { AutoDetectInterface bool `yaml:"auto-detect-interface"` RedirectToTun []string `yaml:"-" json:"-"` - MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` + MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` + GSO bool `yaml:"gso" json:"gso,omitempty"` + GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` @@ -246,6 +248,8 @@ type RawTun struct { Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4_route_exclude_address,omitempty"` Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6_route_exclude_address,omitempty"` + IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` + ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` @@ -1399,6 +1403,8 @@ func parseTun(rawTun RawTun, general *General) error { RedirectToTun: rawTun.RedirectToTun, MTU: rawTun.MTU, + GSO: rawTun.GSO, + GSOMaxSize: rawTun.GSOMaxSize, Inet4Address: []netip.Prefix{tunAddressPrefix}, Inet6Address: rawTun.Inet6Address, StrictRoute: rawTun.StrictRoute, @@ -1406,6 +1412,8 @@ func parseTun(rawTun RawTun, general *General) error { Inet6RouteAddress: rawTun.Inet6RouteAddress, Inet4RouteExcludeAddress: rawTun.Inet4RouteExcludeAddress, Inet6RouteExcludeAddress: rawTun.Inet6RouteExcludeAddress, + IncludeInterface: rawTun.IncludeInterface, + ExcludeInterface: rawTun.ExcludeInterface, IncludeUID: rawTun.IncludeUID, IncludeUIDRange: rawTun.IncludeUIDRange, ExcludeUID: rawTun.ExcludeUID, diff --git a/constant/tun.go b/constant/tun.go index 5e2841bc..f6c0e011 100644 --- a/constant/tun.go +++ b/constant/tun.go @@ -9,14 +9,12 @@ import ( var StackTypeMapping = map[string]TUNStack{ strings.ToLower(TunGvisor.String()): TunGvisor, strings.ToLower(TunSystem.String()): TunSystem, - strings.ToLower(TunLWIP.String()): TunLWIP, strings.ToLower(TunMixed.String()): TunMixed, } const ( TunGvisor TUNStack = iota TunSystem - TunLWIP TunMixed ) @@ -64,8 +62,6 @@ func (e TUNStack) String() string { return "gVisor" case TunSystem: return "System" - case TunLWIP: - return "LWIP" case TunMixed: return "Mixed" default: diff --git a/docs/config.yaml b/docs/config.yaml index 562468de..43bbe0ac 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -93,12 +93,14 @@ profile: # 存储 select 选择记录 # Tun 配置 tun: enable: false - stack: system # gvisor / lwip + stack: system # gvisor/mixed dns-hijack: - 0.0.0.0:53 # 需要劫持的 DNS # auto-detect-interface: true # 自动识别出口网卡 # auto-route: true # 配置路由表 # mtu: 9000 # 最大传输单元 + # gso: false # 启用通用分段卸载, 仅支持 Linux + # gso-max-size: 65536 # 通用分段卸载包的最大大小 # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 inet4-route-address: # 启用 auto_route 时使用自定义路由而不是默认路由 - 0.0.0.0/1 @@ -107,6 +109,10 @@ tun: - "::/1" - "8000::/1" # endpoint-independent-nat: false # 启用独立于端点的 NAT + # include_interface: # 限制被路由的接口。默认不限制, 与 `exclude_interface` 冲突 + # - "lan0" + # exclude_interface: # 排除路由的接口, 与 `include_interface` 冲突 + # - "lan1" # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route # - 0 # include-uid-range: # 限制被路由的的用户范围 diff --git a/go.mod b/go.mod index cab1173c..99d54132 100644 --- a/go.mod +++ b/go.mod @@ -24,9 +24,9 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d - github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a + github.com/metacubex/sing-tun v0.1.15-0.20231210002555-d1b0097255dd github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f - github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173 + github.com/metacubex/sing-wireguard v0.0.0-20231209125515-0594297f7232 github.com/miekg/dns v1.1.57 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 @@ -34,12 +34,12 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.19-0.20231208110306-a3ce328ce759 + github.com/sagernet/sing v0.2.19-0.20231209022445-766839c00099 github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 github.com/sagernet/utls v1.5.4 - github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f + github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e github.com/samber/lo v1.39.0 github.com/shirou/gopsutil/v3 v3.23.11 github.com/sirupsen/logrus v1.9.3 @@ -84,7 +84,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b // indirect + github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect @@ -92,7 +92,6 @@ require ( github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-20 v0.4.1 // indirect - github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect @@ -109,8 +108,8 @@ require ( go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.4.0 // indirect + golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.16.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231208104608-1d45b24eb8fa +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231210002924-c2e1b943c79e diff --git a/go.sum b/go.sum index f44e84fb..9d745916 100644 --- a/go.sum +++ b/go.sum @@ -106,24 +106,24 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= -github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b h1:xJHepHYyQ7NOpUkEcz9wC3TnMRFjFQ3KVVqtHC/6G5s= -github.com/metacubex/gvisor v0.0.0-20231206145044-b6960a648d8b/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= +github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc h1:+yTZ6q2EeQCAJNpKNEu5j32Pm23ShD38ElIa635wTrk= +github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231208104608-1d45b24eb8fa h1:M1jWSzH2aw2GapJbwHf4PWKEz/5q9I2bfmIdkQVcJ/0= -github.com/metacubex/sing v0.0.0-20231208104608-1d45b24eb8fa/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= +github.com/metacubex/sing v0.0.0-20231210002924-c2e1b943c79e h1:c37RHcmi2z1q1zGfOsKeue0BbrCNfdsmJkrztTh0mPI= +github.com/metacubex/sing v0.0.0-20231210002924-c2e1b943c79e/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d h1:hMs2isnO6198XaBwqbPff5bYt3uz1498osDC0sVe/dA= github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d/go.mod h1:Y7Dm/rJpieN2xkU/pnxJCQxqmFptUCYiGd8oJhiHd0w= -github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a h1:uVDQ9vdp9MXzaX0GUf5sTqCYkf3P3v+vNcddR84F7F4= -github.com/metacubex/sing-tun v0.1.15-0.20231207115657-1aa1d8cadd9a/go.mod h1:c/FrkpUp2emectVh3getHn5BxvvaEiNuEVrBdonw8U8= +github.com/metacubex/sing-tun v0.1.15-0.20231210002555-d1b0097255dd h1:UY/Q/Nf3IwLxwrLQXFof3ENCYbR/lUx8Xd/kIHyjkfQ= +github.com/metacubex/sing-tun v0.1.15-0.20231210002555-d1b0097255dd/go.mod h1:eS+glMH6cXwDc5RKiF53XGbypBMPD8EfiXXs2G++8tE= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= -github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173 h1:q5wu7tynMlhGPsRXgZ2+a16vDo6uOe9cwz483n7MRwM= -github.com/metacubex/sing-wireguard v0.0.0-20231207123053-1367f0b8f173/go.mod h1:swI5NYmpSOavsMyKnxSLikD9CvnCUcpjzwLdaWPNS9g= +github.com/metacubex/sing-wireguard v0.0.0-20231209125515-0594297f7232 h1:loWjR+k9dxqBSgruGyT5hE8UCRMmCEjxqZbryfY9no4= +github.com/metacubex/sing-wireguard v0.0.0-20231209125515-0594297f7232/go.mod h1:NGCrBZ+fUmp81yaA1kVskcNWBnwl5z4UHxz47A01zm8= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= @@ -157,8 +157,6 @@ github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkkD2QgdTuzQG263YZ+2emfpeyGqW0= github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= -github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= -github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 h1:rRlYQPbMKmzKX+43XC04gEQvxc45/AxfteRWfcl2/rw= @@ -171,8 +169,8 @@ github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 h1:z3SJQhVyU63FT26 github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6/go.mod h1:73xRZuxwkFk4aiLw28hG8W6o9cr2UPrGL9pdY2UTbvY= github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co= github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s= -github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= -github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= +github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2FzELOFNFQtvsxH7NPmlo7X5JizEK51UCojo= +github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= @@ -263,8 +261,8 @@ golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY= -golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM= golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= diff --git a/hub/route/configs.go b/hub/route/configs.go index 3b5f62b3..7b579cb4 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -68,7 +68,9 @@ type tunSchema struct { AutoDetectInterface *bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` //RedirectToTun []string `yaml:"-" json:"-"` - MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` + MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` + GSO *bool `yaml:"gso" json:"gso,omitempty"` + GSOMaxSize *uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` @@ -76,6 +78,8 @@ type tunSchema struct { Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` Inet4RouteExcludeAddress *[]netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` Inet6RouteExcludeAddress *[]netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` + IncludeInterface *[]string `yaml:"include-interface" json:"include-interface,omitempty"` + ExcludeInterface *[]string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` @@ -144,6 +148,12 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p.MTU != nil { def.MTU = *p.MTU } + if p.GSO != nil { + def.GSO = *p.GSO + } + if p.GSOMaxSize != nil { + def.GSOMaxSize = *p.GSOMaxSize + } //if p.Inet4Address != nil { // def.Inet4Address = *p.Inet4Address //} @@ -162,6 +172,12 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p.Inet6RouteExcludeAddress != nil { def.Inet6RouteExcludeAddress = *p.Inet6RouteExcludeAddress } + if p.IncludeInterface != nil { + def.IncludeInterface = *p.IncludeInterface + } + if p.ExcludeInterface != nil { + def.ExcludeInterface = *p.ExcludeInterface + } if p.IncludeUID != nil { def.IncludeUID = *p.IncludeUID } diff --git a/listener/config/tun.go b/listener/config/tun.go index 6db1fd66..1772c6f5 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -28,6 +28,8 @@ type Tun struct { RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` + GSO bool `yaml:"gso" json:"gso,omitempty"` + GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` @@ -35,6 +37,8 @@ type Tun struct { Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` + IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` + ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index d1044b8e..a1fdebfa 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -19,6 +19,8 @@ type TunOption struct { AutoDetectInterface bool `inbound:"auto-detect-interface,omitempty"` MTU uint32 `inbound:"mtu,omitempty"` + GSO bool `inbound:"gso,omitempty"` + GSOMaxSize uint32 `inbound:"gso-max-size,omitempty"` Inet4Address []string `inbound:"inet4_address,omitempty"` Inet6Address []string `inbound:"inet6_address,omitempty"` StrictRoute bool `inbound:"strict_route,omitempty"` @@ -26,6 +28,8 @@ type TunOption struct { Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` Inet4RouteExcludeAddress []string `inbound:"inet4_route_exclude_address,omitempty"` Inet6RouteExcludeAddress []string `inbound:"inet6_route_exclude_address,omitempty"` + IncludeInterface []string `inbound:"include-interface,omitempty"` + ExcludeInterface []string `inbound:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID []uint32 `inbound:"include_uid,omitempty"` IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` @@ -93,6 +97,8 @@ func NewTun(options *TunOption) (*Tun, error) { AutoRoute: options.AutoRoute, AutoDetectInterface: options.AutoDetectInterface, MTU: options.MTU, + GSO: options.GSO, + GSOMaxSize: options.GSOMaxSize, Inet4Address: inet4Address, Inet6Address: inet6Address, StrictRoute: options.StrictRoute, @@ -100,6 +106,8 @@ func NewTun(options *TunOption) (*Tun, error) { Inet6RouteAddress: inet6RouteAddress, Inet4RouteExcludeAddress: inet4RouteExcludeAddress, Inet6RouteExcludeAddress: inet6RouteExcludeAddress, + IncludeInterface: options.IncludeInterface, + ExcludeInterface: options.ExcludeInterface, IncludeUID: options.IncludeUID, IncludeUIDRange: options.IncludeUIDRange, ExcludeUID: options.ExcludeUID, diff --git a/listener/listener.go b/listener/listener.go index 903cb64b..ac602971 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -818,6 +818,8 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { LastTunConf.AutoRoute != tunConf.AutoRoute || LastTunConf.AutoDetectInterface != tunConf.AutoDetectInterface || LastTunConf.MTU != tunConf.MTU || + LastTunConf.GSO != tunConf.GSO || + LastTunConf.GSOMaxSize != tunConf.GSOMaxSize || LastTunConf.StrictRoute != tunConf.StrictRoute || LastTunConf.EndpointIndependentNat != tunConf.EndpointIndependentNat || LastTunConf.UDPTimeout != tunConf.UDPTimeout || @@ -857,6 +859,14 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { return tunConf.Inet6RouteExcludeAddress[i].String() < tunConf.Inet6RouteExcludeAddress[j].String() }) + sort.Slice(tunConf.IncludeInterface, func(i, j int) bool { + return tunConf.IncludeInterface[i] < tunConf.IncludeInterface[j] + }) + + sort.Slice(tunConf.ExcludeInterface, func(i, j int) bool { + return tunConf.ExcludeInterface[i] < tunConf.ExcludeInterface[j] + }) + sort.Slice(tunConf.IncludeUID, func(i, j int) bool { return tunConf.IncludeUID[i] < tunConf.IncludeUID[j] }) @@ -892,6 +902,8 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { !slices.Equal(tunConf.Inet6RouteAddress, LastTunConf.Inet6RouteAddress) || !slices.Equal(tunConf.Inet4RouteExcludeAddress, LastTunConf.Inet4RouteExcludeAddress) || !slices.Equal(tunConf.Inet6RouteExcludeAddress, LastTunConf.Inet6RouteExcludeAddress) || + !slices.Equal(tunConf.IncludeInterface, LastTunConf.IncludeInterface) || + !slices.Equal(tunConf.ExcludeInterface, LastTunConf.ExcludeInterface) || !slices.Equal(tunConf.IncludeUID, LastTunConf.IncludeUID) || !slices.Equal(tunConf.IncludeUIDRange, LastTunConf.IncludeUIDRange) || !slices.Equal(tunConf.ExcludeUID, LastTunConf.ExcludeUID) || diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 2017e922..0827af5e 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -94,6 +94,9 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis inbound.WithSpecialRules(""), } } + if options.GSOMaxSize == 0 { + options.GSOMaxSize = 65536 + } tunName := options.Device if tunName == "" || !checkTunName(tunName) { tunName = CalculateInterfaceName(InterfaceName) @@ -204,6 +207,8 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis tunOptions := tun.Options{ Name: tunName, MTU: tunMTU, + GSO: options.GSO, + GSOMaxSize: options.GSOMaxSize, Inet4Address: options.Inet4Address, Inet6Address: options.Inet6Address, AutoRoute: options.AutoRoute, @@ -212,6 +217,8 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis Inet6RouteAddress: options.Inet6RouteAddress, Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress, Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress, + IncludeInterface: options.IncludeInterface, + ExcludeInterface: options.ExcludeInterface, IncludeUID: includeUID, ExcludeUID: excludeUID, IncludeAndroidUser: options.IncludeAndroidUser, @@ -236,10 +243,7 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis stackOptions := tun.StackOptions{ Context: context.TODO(), Tun: tunIf, - MTU: tunOptions.MTU, - Name: tunOptions.Name, - Inet4Address: tunOptions.Inet4Address, - Inet6Address: tunOptions.Inet6Address, + TunOptions: tunOptions, EndpointIndependentNat: options.EndpointIndependentNat, UDPTimeout: udpTimeout, Handler: handler, @@ -248,7 +252,7 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis if options.FileDescriptor > 0 { if tunName, err := getTunnelName(int32(options.FileDescriptor)); err != nil { - stackOptions.Name = tunName + stackOptions.TunOptions.Name = tunName stackOptions.ForwarderBindInterface = true } } From 3cf865e5f07d71ec3a8ce2483ba250bb0ff8c980 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 11 Dec 2023 16:41:50 +0800 Subject: [PATCH 163/192] fix: GSO support for TUN --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 99d54132..e53d2103 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d - github.com/metacubex/sing-tun v0.1.15-0.20231210002555-d1b0097255dd + github.com/metacubex/sing-tun v0.1.15-0.20231211084005-e7b0b6c7c698 github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f github.com/metacubex/sing-wireguard v0.0.0-20231209125515-0594297f7232 github.com/miekg/dns v1.1.57 diff --git a/go.sum b/go.sum index 9d745916..a0a2d3ab 100644 --- a/go.sum +++ b/go.sum @@ -118,8 +118,8 @@ github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwV github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d h1:hMs2isnO6198XaBwqbPff5bYt3uz1498osDC0sVe/dA= github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d/go.mod h1:Y7Dm/rJpieN2xkU/pnxJCQxqmFptUCYiGd8oJhiHd0w= -github.com/metacubex/sing-tun v0.1.15-0.20231210002555-d1b0097255dd h1:UY/Q/Nf3IwLxwrLQXFof3ENCYbR/lUx8Xd/kIHyjkfQ= -github.com/metacubex/sing-tun v0.1.15-0.20231210002555-d1b0097255dd/go.mod h1:eS+glMH6cXwDc5RKiF53XGbypBMPD8EfiXXs2G++8tE= +github.com/metacubex/sing-tun v0.1.15-0.20231211084005-e7b0b6c7c698 h1:evcXZKgMO6NiGOB5nWTAAUANq7nXodN23P8SpyDm+78= +github.com/metacubex/sing-tun v0.1.15-0.20231211084005-e7b0b6c7c698/go.mod h1:eS+glMH6cXwDc5RKiF53XGbypBMPD8EfiXXs2G++8tE= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= github.com/metacubex/sing-wireguard v0.0.0-20231209125515-0594297f7232 h1:loWjR+k9dxqBSgruGyT5hE8UCRMmCEjxqZbryfY9no4= From 7ee68092574bb29f62cb20ccaaba12adf5aff13a Mon Sep 17 00:00:00 2001 From: Kuingsmile Date: Tue, 12 Dec 2023 04:39:11 -0800 Subject: [PATCH 164/192] feat: Add LAN allowed and disallowed IP configurations (#861) --- adapter/inbound/ipfilter.go | 57 +++++++++++++++++++++++++++++++++++++ config/config.go | 7 +++++ docs/config.yaml | 5 ++++ hub/executor/executor.go | 4 +++ hub/route/configs.go | 15 ++++++++-- listener/http/server.go | 6 ++++ listener/mixed/mixed.go | 6 ++++ listener/socks/tcp.go | 6 ++++ 8 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 adapter/inbound/ipfilter.go diff --git a/adapter/inbound/ipfilter.go b/adapter/inbound/ipfilter.go new file mode 100644 index 00000000..7fa218c1 --- /dev/null +++ b/adapter/inbound/ipfilter.go @@ -0,0 +1,57 @@ +package inbound + +import ( + "net" + "net/netip" + + C "github.com/metacubex/mihomo/constant" +) + +var lanAllowedIPs []netip.Prefix +var lanDisAllowedIPs []netip.Prefix + +func SetAllowedIPs(prefixes []netip.Prefix) { + lanAllowedIPs = prefixes +} + +func SetDisAllowedIPs(prefixes []netip.Prefix) { + lanDisAllowedIPs = prefixes +} + +func AllowedIPs() []netip.Prefix { + return lanAllowedIPs +} + +func DisAllowedIPs() []netip.Prefix { + return lanDisAllowedIPs +} + +func IsRemoteAddrDisAllowed(addr net.Addr) bool { + m := C.Metadata{} + if err := m.SetRemoteAddr(addr); err != nil { + return false + } + return isAllowed(m.AddrPort().Addr().Unmap()) && !isDisAllowed(m.AddrPort().Addr().Unmap()) +} + +func isAllowed(addr netip.Addr) bool { + if addr.IsValid() { + for _, prefix := range lanAllowedIPs { + if prefix.Contains(addr) { + return true + } + } + } + return false +} + +func isDisAllowed(addr netip.Addr) bool { + if addr.IsValid() { + for _, prefix := range lanDisAllowedIPs { + if prefix.Contains(addr) { + return true + } + } + } + return false +} diff --git a/config/config.go b/config/config.go index 5f4995fe..469a58ca 100644 --- a/config/config.go +++ b/config/config.go @@ -80,6 +80,8 @@ type Inbound struct { VmessConfig string `json:"vmess-config"` Authentication []string `json:"authentication"` SkipAuthPrefixes []netip.Prefix `json:"skip-auth-prefixes"` + LanAllowedIPs []netip.Prefix `json:"lan-allowed-ips"` + LanDisAllowedIPs []netip.Prefix `json:"lan-disallowed-ips"` AllowLan bool `json:"allow-lan"` BindAddress string `json:"bind-address"` InboundTfo bool `json:"inbound-tfo"` @@ -289,6 +291,8 @@ type RawConfig struct { InboundMPTCP bool `yaml:"inbound-mptcp"` Authentication []string `yaml:"authentication" json:"authentication"` SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"` + LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips"` + LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips"` AllowLan bool `yaml:"allow-lan" json:"allow-lan"` BindAddress string `yaml:"bind-address" json:"bind-address"` Mode T.TunnelMode `yaml:"mode" json:"mode"` @@ -387,6 +391,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { rawCfg := &RawConfig{ AllowLan: false, BindAddress: "*", + LanAllowedIPs: []netip.Prefix{netip.MustParsePrefix("0.0.0.0/0"), netip.MustParsePrefix("::/0")}, IPv6: true, Mode: T.Rule, GeoAutoUpdate: false, @@ -647,6 +652,8 @@ func parseGeneral(cfg *RawConfig) (*General, error) { VmessConfig: cfg.VmessConfig, AllowLan: cfg.AllowLan, SkipAuthPrefixes: cfg.SkipAuthPrefixes, + LanAllowedIPs: cfg.LanAllowedIPs, + LanDisAllowedIPs: cfg.LanDisAllowedIPs, BindAddress: cfg.BindAddress, InboundTfo: cfg.InboundTfo, InboundMPTCP: cfg.InboundMPTCP, diff --git a/docs/config.yaml b/docs/config.yaml index 43bbe0ac..f69ab41f 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -13,6 +13,11 @@ authentication: # http,socks入口的验证用户名,密码 skip-auth-prefixes: # 设置跳过验证的IP段 - 127.0.0.1/8 - ::1/128 +lan-allowed-ips: # 允许连接的 IP 地址段,仅作用于 allow-lan 为 true, 默认值为0.0.0.0/0和::/0 + - 0.0.0.0/0 + - ::/0 +lan-disallowed-ips: # 禁止连接的 IP 地址段, 黑名单优先级高于白名单, 默认值为空 + - 192.168.0.3/32 # find-process-mode has 3 values:always, strict, off # - always, 开启,强制匹配所有进程 diff --git a/hub/executor/executor.go b/hub/executor/executor.go index edab400f..b9e27bfa 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -141,6 +141,8 @@ func GetGeneral() *config.General { VmessConfig: ports.VmessConfig, Authentication: authenticator, SkipAuthPrefixes: inbound.SkipAuthPrefixes(), + LanAllowedIPs: inbound.AllowedIPs(), + LanDisAllowedIPs: inbound.DisAllowedIPs(), AllowLan: listener.AllowLan(), BindAddress: listener.BindAddress(), }, @@ -166,6 +168,8 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList allowLan := general.AllowLan listener.SetAllowLan(allowLan) inbound.SetSkipAuthPrefixes(general.SkipAuthPrefixes) + inbound.SetAllowedIPs(general.LanAllowedIPs) + inbound.SetDisAllowedIPs(general.LanDisAllowedIPs) bindAddress := general.BindAddress listener.SetBindAddress(bindAddress) diff --git a/hub/route/configs.go b/hub/route/configs.go index 7b579cb4..ec0b464c 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -10,7 +10,6 @@ import ( "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/resolver" "github.com/metacubex/mihomo/config" - "github.com/metacubex/mihomo/constant" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/hub/executor" P "github.com/metacubex/mihomo/listener" @@ -50,6 +49,8 @@ type configSchema struct { UdptunConfig *string `json:"udptun-config"` AllowLan *bool `json:"allow-lan"` SkipAuthPrefixes *[]netip.Prefix `json:"skip-auth-prefixes"` + LanAllowedIPs *[]netip.Prefix `json:"lan-allowed-ips"` + LanDisAllowedIPs *[]netip.Prefix `json:"lan-disallowed-ips"` BindAddress *string `json:"bind-address"` Mode *tunnel.TunnelMode `json:"mode"` LogLevel *log.LogLevel `json:"log-level"` @@ -268,6 +269,14 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { inbound.SetSkipAuthPrefixes(*general.SkipAuthPrefixes) } + if general.LanAllowedIPs != nil { + inbound.SetAllowedIPs(*general.LanAllowedIPs) + } + + if general.LanDisAllowedIPs != nil { + inbound.SetDisAllowedIPs(*general.LanDisAllowedIPs) + } + if general.BindAddress != nil { P.SetBindAddress(*general.BindAddress) } @@ -335,7 +344,7 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) { } } else { if req.Path == "" { - req.Path = constant.Path.Config() + req.Path = C.Path.Config() } if !filepath.IsAbs(req.Path) { render.Status(r, http.StatusBadRequest) @@ -380,7 +389,7 @@ func updateGeoDatabases(w http.ResponseWriter, r *http.Request) { return } - cfg, err := executor.ParseWithPath(constant.Path.Config()) + cfg, err := executor.ParseWithPath(C.Path.Config()) if err != nil { log.Errorln("[REST-API] update GEO databases failed: %v", err) return diff --git a/listener/http/server.go b/listener/http/server.go index be397d9a..3ff1679d 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -71,6 +71,12 @@ func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additi t.SetKeepAlive(false) } } + if len(additions) == 0 { // only apply on default listener + if inbound.IsRemoteAddrDisAllowed(conn.RemoteAddr()) { + _ = conn.Close() + continue + } + } go HandleConn(conn, tunnel, c, additions...) } }() diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index 0f1b3aab..94613039 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -62,6 +62,12 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener } continue } + if len(additions) == 0 { // only apply on default listener + if inbound.IsRemoteAddrDisAllowed(c.RemoteAddr()) { + _ = c.Close() + continue + } + } go handleConn(c, tunnel, ml.cache, additions...) } }() diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index c8c33e7b..8016e958 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -59,6 +59,12 @@ func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener } continue } + if len(additions) == 0 { // only apply on default listener + if inbound.IsRemoteAddrDisAllowed(c.RemoteAddr()) { + _ = c.Close() + continue + } + } go handleSocks(c, tunnel, additions...) } }() From 0ab73a9beb7a5700ffa8e5b2c8188bb4bb8c8e3f Mon Sep 17 00:00:00 2001 From: bobo liu <7552030+fakeboboliu@users.noreply.github.com> Date: Thu, 14 Dec 2023 10:19:19 +0800 Subject: [PATCH 165/192] fix: the right way to get process in win32 format (#909) --- component/process/process_windows.go | 34 +--------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/component/process/process_windows.go b/component/process/process_windows.go index 820493ec..f8cd00d8 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -3,8 +3,6 @@ package process import ( "fmt" "net/netip" - "path/filepath" - "strings" "sync" "syscall" "unsafe" @@ -103,10 +101,6 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string return 0, "", err } pp, err := getExecPathFromPID(pid) - if err != nil { - return 0, "", err - } - pp, err = convertDOSPath(pp) return 0, pp, err } @@ -224,7 +218,7 @@ func getExecPathFromPID(pid uint32) (string, error) { r1, _, err := syscall.SyscallN( queryProcName, uintptr(h), - uintptr(1), + uintptr(0), uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&size)), ) @@ -233,29 +227,3 @@ func getExecPathFromPID(pid uint32) (string, error) { } return syscall.UTF16ToString(buf[:size]), nil } - -// modify from https://github.com/shirou/gopsutil/blob/9deadc99147d80f732af3a59e624af73d0143891/internal/common/common_windows.go#L220-L241 -// Convert paths using native DOS format like: -// -// "\Device\HarddiskVolume1\Windows\systemew\file.txt" -// -// into: -// -// "C:\Windows\systemew\file.txt" -func convertDOSPath(p string) (string, error) { - rawDrive := strings.Join(strings.Split(p, `\`)[:3], `\`) - - for d := 'A'; d <= 'Z'; d++ { - szDeviceName := string(d) + ":" - deviceName, err := syscall.UTF16PtrFromString(szDeviceName) - if err != nil { - return "", err - } - szTarget := make([]uint16, 512) - n, err := windows.QueryDosDevice(deviceName, &szTarget[0], uint32(len(szTarget))) - if err == nil && windows.UTF16ToString(szTarget[:n]) == rawDrive { - return filepath.Join(szDeviceName, p[len(rawDrive):]), nil - } - } - return p, nil -} From 78e5d3229ee52943b25c6129591d6ae23667c4b9 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 9 Dec 2023 15:43:40 +0800 Subject: [PATCH 166/192] chore: Remove the use of curve25519 package --- adapter/outbound/reality.go | 14 ++++++++++---- component/tls/reality.go | 9 ++------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/adapter/outbound/reality.go b/adapter/outbound/reality.go index 766138da..6711f378 100644 --- a/adapter/outbound/reality.go +++ b/adapter/outbound/reality.go @@ -1,13 +1,13 @@ package outbound import ( + "crypto/ecdh" "encoding/base64" "encoding/hex" "errors" + "fmt" tlsC "github.com/metacubex/mihomo/component/tls" - - "golang.org/x/crypto/curve25519" ) type RealityOptions struct { @@ -19,10 +19,16 @@ func (o RealityOptions) Parse() (*tlsC.RealityConfig, error) { if o.PublicKey != "" { config := new(tlsC.RealityConfig) - n, err := base64.RawURLEncoding.Decode(config.PublicKey[:], []byte(o.PublicKey)) - if err != nil || n != curve25519.ScalarSize { + const x25519ScalarSize = 32 + var publicKey [x25519ScalarSize]byte + n, err := base64.RawURLEncoding.Decode(publicKey[:], []byte(o.PublicKey)) + if err != nil || n != x25519ScalarSize { return nil, errors.New("invalid REALITY public key") } + config.PublicKey, err = ecdh.X25519().NewPublicKey(publicKey[:]) + if err != nil { + return nil, fmt.Errorf("fail to create REALITY public key: %w", err) + } n, err = hex.Decode(config.ShortID[:], []byte(o.ShortID)) if err != nil || n > tlsC.RealityMaxShortIDLen { diff --git a/component/tls/reality.go b/component/tls/reality.go index f8d5ab23..687ef1ef 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -28,7 +28,6 @@ import ( utls "github.com/sagernet/utls" "github.com/zhangyunhao116/fastrand" "golang.org/x/crypto/chacha20poly1305" - "golang.org/x/crypto/curve25519" "golang.org/x/crypto/hkdf" "golang.org/x/net/http2" ) @@ -36,7 +35,7 @@ import ( const RealityMaxShortIDLen = 8 type RealityConfig struct { - PublicKey [curve25519.ScalarSize]byte + PublicKey *ecdh.PublicKey ShortID [RealityMaxShortIDLen]byte } @@ -82,10 +81,6 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) - publicKey, err := ecdh.X25519().NewPublicKey(realityConfig.PublicKey[:]) - if err != nil { - return nil, err - } ecdheKey := uConn.HandshakeState.State13.EcdheKey if ecdheKey == nil { // WTF??? @@ -94,7 +89,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string } continue // retry } - authKey, err := ecdheKey.ECDH(publicKey) + authKey, err := ecdheKey.ECDH(realityConfig.PublicKey) if err != nil { return nil, err } From 5b23b979df46a46c2fa0684e88538f6d630ff3d4 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 16 Dec 2023 22:03:32 +0800 Subject: [PATCH 167/192] chore: do not always trigger upload on PR #912 Co-authored-by: bobo liu <7552030+fakeboboliu@users.noreply.github.com> --- .github/workflows/build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da340282..311532f2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ on: - Alpha concurrency: - group: ${{ github.ref }}-${{ github.workflow }} + group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: @@ -234,7 +234,7 @@ jobs: Upload-Prerelease: permissions: write-all - if: ${{ github.ref_type=='branch' && github.event_name != 'pull_request' }} + if: ${{ github.ref_type == 'branch' && !startsWith(github.event_name, 'pull_request') }} needs: [Build] runs-on: ubuntu-latest steps: @@ -310,7 +310,7 @@ jobs: generate_release_notes: true Docker: - if: ${{ github.event_name != 'pull_request' }} + if: ${{ !startsWith(github.event_name, 'pull_request') }} permissions: write-all needs: [Build] runs-on: ubuntu-latest From 2bba8aa14a98ae756b488aa9b75b7c848b391d7c Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 17 Dec 2023 00:00:35 +0800 Subject: [PATCH 168/192] feat: Add succinct matcher support for GeoSite and use it by default --- component/geodata/router/condition.go | 71 ++++++++++++++++++++++++--- component/geodata/utils.go | 28 +++++++++-- config/config.go | 20 +++++--- constant/rule_extra.go | 2 +- dns/filters.go | 4 +- dns/resolver.go | 2 +- docs/config.yaml | 5 ++ hub/executor/executor.go | 21 ++++---- rules/common/geosite.go | 4 +- 9 files changed, 122 insertions(+), 35 deletions(-) diff --git a/component/geodata/router/condition.go b/component/geodata/router/condition.go index 156614ae..82684d93 100644 --- a/component/geodata/router/condition.go +++ b/component/geodata/router/condition.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/metacubex/mihomo/component/geodata/strmatcher" + "github.com/metacubex/mihomo/component/trie" ) var matcherTypeMap = map[Domain_Type]strmatcher.Type{ @@ -31,12 +32,69 @@ func domainToMatcher(domain *Domain) (strmatcher.Matcher, error) { return matcher, nil } -type DomainMatcher struct { +type DomainMatcher interface { + ApplyDomain(string) bool +} + +type succinctDomainMatcher struct { + set *trie.DomainSet + otherMatchers []strmatcher.Matcher + not bool +} + +func (m succinctDomainMatcher) ApplyDomain(domain string) bool { + isMatched := m.set.Has(domain) + if !isMatched { + for _, matcher := range m.otherMatchers { + isMatched = matcher.Match(domain) + if isMatched { + break + } + } + } + if m.not { + isMatched = !isMatched + } + return isMatched +} + +func NewSuccinctMatcherGroup(domains []*Domain, not bool) (DomainMatcher, error) { + t := trie.New[struct{}]() + m := &succinctDomainMatcher{ + not: not, + } + for _, d := range domains { + switch d.Type { + case Domain_Plain, Domain_Regex: + matcher, err := matcherTypeMap[d.Type].New(d.Value) + if err != nil { + return nil, err + } + m.otherMatchers = append(m.otherMatchers, matcher) + + case Domain_Domain: + err := t.Insert("+."+d.Value, struct{}{}) + if err != nil { + return nil, err + } + + case Domain_Full: + err := t.Insert(d.Value, struct{}{}) + if err != nil { + return nil, err + } + } + } + m.set = t.NewDomainSet() + return m, nil +} + +type v2rayDomainMatcher struct { matchers strmatcher.IndexMatcher not bool } -func NewMphMatcherGroup(domains []*Domain, not bool) (*DomainMatcher, error) { +func NewMphMatcherGroup(domains []*Domain, not bool) (DomainMatcher, error) { g := strmatcher.NewMphMatcherGroup() for _, d := range domains { matcherType, f := matcherTypeMap[d.Type] @@ -49,14 +107,13 @@ func NewMphMatcherGroup(domains []*Domain, not bool) (*DomainMatcher, error) { } } g.Build() - return &DomainMatcher{ + return &v2rayDomainMatcher{ matchers: g, not: not, }, nil } -// NewDomainMatcher new domain matcher. -func NewDomainMatcher(domains []*Domain, not bool) (*DomainMatcher, error) { +func NewDomainMatcher(domains []*Domain, not bool) (DomainMatcher, error) { g := new(strmatcher.MatcherGroup) for _, d := range domains { m, err := domainToMatcher(d) @@ -66,13 +123,13 @@ func NewDomainMatcher(domains []*Domain, not bool) (*DomainMatcher, error) { g.Add(m) } - return &DomainMatcher{ + return &v2rayDomainMatcher{ matchers: g, not: not, }, nil } -func (m *DomainMatcher) ApplyDomain(domain string) bool { +func (m *v2rayDomainMatcher) ApplyDomain(domain string) bool { isMatched := len(m.matchers.Match(strings.ToLower(domain))) > 0 if m.not { isMatched = !isMatched diff --git a/component/geodata/utils.go b/component/geodata/utils.go index 4716ccbd..33c12e68 100644 --- a/component/geodata/utils.go +++ b/component/geodata/utils.go @@ -12,6 +12,7 @@ import ( ) var geoLoaderName = "memconservative" +var geoSiteMatcher = "succinct" // geoLoaderName = "standard" @@ -19,6 +20,10 @@ func LoaderName() string { return geoLoaderName } +func SiteMatcherName() string { + return geoSiteMatcher +} + func SetLoader(newLoader string) { if newLoader == "memc" { newLoader = "memconservative" @@ -26,6 +31,16 @@ func SetLoader(newLoader string) { geoLoaderName = newLoader } +func SetSiteMatcher(newMatcher string) { + switch newMatcher { + case "hybrid": + newMatcher = "mph" + default: + newMatcher = "succinct" + } + geoSiteMatcher = newMatcher +} + func Verify(name string) error { switch name { case C.GeositeName: @@ -41,8 +56,8 @@ func Verify(name string) error { var loadGeoSiteMatcherSF = singleflight.Group{} -func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) { - if len(countryCode) == 0 { +func LoadGeoSiteMatcher(countryCode string) (router.DomainMatcher, int, error) { + if countryCode == "" { return nil, 0, fmt.Errorf("country code could not be empty") } @@ -60,7 +75,7 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) listName := strings.TrimSpace(parts[0]) attrVal := parts[1:] - if len(listName) == 0 { + if listName == "" { return nil, 0, fmt.Errorf("empty listname in rule: %s", countryCode) } @@ -104,7 +119,12 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) matcher, err := router.NewDomainMatcher(domains) mph:minimal perfect hash algorithm */ - matcher, err := router.NewMphMatcherGroup(domains, not) + var matcher router.DomainMatcher + if geoSiteMatcher == "mph" { + matcher, err = router.NewMphMatcherGroup(domains, not) + } else { + matcher, err = router.NewSuccinctMatcherGroup(domains, not) + } if err != nil { return nil, 0, err } diff --git a/config/config.go b/config/config.go index 469a58ca..9eaf5a49 100644 --- a/config/config.go +++ b/config/config.go @@ -59,6 +59,7 @@ type General struct { GeoUpdateInterval int `json:"geo-update-interval"` GeodataMode bool `json:"geodata-mode"` GeodataLoader string `json:"geodata-loader"` + GeositeMatcher string `json:"geosite-matcher"` TCPConcurrent bool `json:"tcp-concurrent"` FindProcessMode P.FindProcessMode `json:"find-process-mode"` Sniffing bool `json:"sniffing"` @@ -127,11 +128,11 @@ type DNS struct { // FallbackFilter config type FallbackFilter struct { - GeoIP bool `yaml:"geoip"` - GeoIPCode string `yaml:"geoip-code"` - IPCIDR []netip.Prefix `yaml:"ipcidr"` - Domain []string `yaml:"domain"` - GeoSite []*router.DomainMatcher `yaml:"geosite"` + GeoIP bool `yaml:"geoip"` + GeoIPCode string `yaml:"geoip-code"` + IPCIDR []netip.Prefix `yaml:"ipcidr"` + Domain []string `yaml:"domain"` + GeoSite []router.DomainMatcher `yaml:"geosite"` } // Profile config @@ -312,6 +313,7 @@ type RawConfig struct { GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"` GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"` GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"` + GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"` TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` GlobalClientFingerprint string `yaml:"global-client-fingerprint"` @@ -537,6 +539,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config.Listeners = listener log.Infoln("Geodata Loader mode: %s", geodata.LoaderName()) + log.Infoln("Geosite Matcher implementation: %s", geodata.SiteMatcherName()) ruleProviders, err := parseRuleProviders(rawCfg) if err != nil { return nil, err @@ -605,6 +608,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { func parseGeneral(cfg *RawConfig) (*General, error) { geodata.SetLoader(cfg.GeodataLoader) + geodata.SetSiteMatcher(cfg.GeositeMatcher) C.GeoAutoUpdate = cfg.GeoAutoUpdate C.GeoUpdateInterval = cfg.GeoUpdateInterval C.GeoIpUrl = cfg.GeoXUrl.GeoIp @@ -1204,8 +1208,8 @@ func parseFallbackIPCIDR(ips []string) ([]netip.Prefix, error) { return ipNets, nil } -func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainMatcher, error) { - var sites []*router.DomainMatcher +func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]router.DomainMatcher, error) { + var sites []router.DomainMatcher if len(countries) > 0 { if err := geodata.InitGeoSite(); err != nil { return nil, fmt.Errorf("can't initial GeoSite: %s", err) @@ -1267,7 +1271,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul EnhancedMode: cfg.EnhancedMode, FallbackFilter: FallbackFilter{ IPCIDR: []netip.Prefix{}, - GeoSite: []*router.DomainMatcher{}, + GeoSite: []router.DomainMatcher{}, }, } var err error diff --git a/constant/rule_extra.go b/constant/rule_extra.go index 62dc1cc3..b4ba65d9 100644 --- a/constant/rule_extra.go +++ b/constant/rule_extra.go @@ -5,7 +5,7 @@ import ( ) type RuleGeoSite interface { - GetDomainMatcher() *router.DomainMatcher + GetDomainMatcher() router.DomainMatcher } type RuleGeoIP interface { diff --git a/dns/filters.go b/dns/filters.go index 8eb1e48e..46244c35 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -74,7 +74,7 @@ func (df *domainFilter) Match(domain string) bool { } type geoSiteFilter struct { - matchers []*router.DomainMatcher + matchers []router.DomainMatcher } func NewGeoSite(group string) (fallbackDomainFilter, error) { @@ -87,7 +87,7 @@ func NewGeoSite(group string) (fallbackDomainFilter, error) { return nil, err } filter := &geoSiteFilter{ - matchers: []*router.DomainMatcher{matcher}, + matchers: []router.DomainMatcher{matcher}, } return filter, nil } diff --git a/dns/resolver.go b/dns/resolver.go index 47ea78d8..8ea68ed7 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -400,7 +400,7 @@ type FallbackFilter struct { GeoIPCode string IPCIDR []netip.Prefix Domain []string - GeoSite []*router.DomainMatcher + GeoSite []router.DomainMatcher } type Config struct { diff --git a/docs/config.yaml b/docs/config.yaml index f69ab41f..702ff831 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -36,6 +36,11 @@ geox-url: geo-auto-update: false # 是否自动更新 geodata geo-update-interval: 24 # 更新间隔,单位:小时 +# Matcher implementation used by GeoSite, available implementations: +# - succinct (default, same as rule-set) +# - mph (from V2Ray, also `hybrid` in Xray) +# geosite-matcher: succinct + log-level: debug # 日志等级 silent/error/warning/info/debug ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS 请求 AAAA 记录 diff --git a/hub/executor/executor.go b/hub/executor/executor.go index b9e27bfa..783da4d3 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -146,14 +146,15 @@ func GetGeneral() *config.General { AllowLan: listener.AllowLan(), BindAddress: listener.BindAddress(), }, - Controller: config.Controller{}, - Mode: tunnel.Mode(), - LogLevel: log.Level(), - IPv6: !resolver.DisableIPv6, - GeodataLoader: G.LoaderName(), - Interface: dialer.DefaultInterface.Load(), - Sniffing: tunnel.IsSniffing(), - TCPConcurrent: dialer.GetTcpConcurrent(), + Controller: config.Controller{}, + Mode: tunnel.Mode(), + LogLevel: log.Level(), + IPv6: !resolver.DisableIPv6, + GeodataLoader: G.LoaderName(), + GeositeMatcher: G.SiteMatcherName(), + Interface: dialer.DefaultInterface.Load(), + Sniffing: tunnel.IsSniffing(), + TCPConcurrent: dialer.GetTcpConcurrent(), } return general @@ -401,8 +402,8 @@ func updateGeneral(general *config.General) { } iface.FlushCache() - geodataLoader := general.GeodataLoader - G.SetLoader(geodataLoader) + G.SetLoader(general.GeodataLoader) + G.SetSiteMatcher(general.GeositeMatcher) } func updateUsers(users []auth.AuthUser) { diff --git a/rules/common/geosite.go b/rules/common/geosite.go index e9b19d0e..1e3c1ab5 100644 --- a/rules/common/geosite.go +++ b/rules/common/geosite.go @@ -15,7 +15,7 @@ type GEOSITE struct { *Base country string adapter string - matcher *router.DomainMatcher + matcher router.DomainMatcher recodeSize int } @@ -39,7 +39,7 @@ func (gs *GEOSITE) Payload() string { return gs.country } -func (gs *GEOSITE) GetDomainMatcher() *router.DomainMatcher { +func (gs *GEOSITE) GetDomainMatcher() router.DomainMatcher { return gs.matcher } From 8cf14bb67e51cf47da4fbc6ae14d35aa2f9532fa Mon Sep 17 00:00:00 2001 From: PuerNya Date: Mon, 18 Dec 2023 14:51:36 +0800 Subject: [PATCH 169/192] chore: reslove udp host after rule matching --- tunnel/tunnel.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 2454fd9a..64ae91bf 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -328,16 +328,6 @@ func handleUDPConn(packet C.PacketAdapter) { sniffer.Dispatcher.UDPSniff(packet) } - // local resolve UDP dns - if !metadata.Resolved() { - ip, err := resolver.ResolveIP(context.Background(), metadata.Host) - if err != nil { - packet.Drop() - return - } - metadata.DstIP = ip - } - key := packet.LocalAddr().String() handle := func() bool { @@ -381,6 +371,16 @@ func handleUDPConn(packet C.PacketAdapter) { return } + // local resolve UDP dns + if !metadata.Resolved() && proxy.Type() != C.Reject && proxy.Type() != C.RejectDrop { + ip, err := resolver.ResolveIP(context.Background(), metadata.Host) + if err != nil { + packet.Drop() + return + } + metadata.DstIP = ip + } + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout) defer cancel() rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) { From f29329fe80af751fec58b54b838369ef7c999dda Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 18 Dec 2023 23:08:35 +0800 Subject: [PATCH 170/192] fix: sing vectorised writer --- go.mod | 10 +++++----- go.sum | 16 ++++++++-------- listener/sing_tun/server.go | 1 - 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index e53d2103..6e92f38e 100644 --- a/go.mod +++ b/go.mod @@ -23,8 +23,8 @@ require ( github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 github.com/metacubex/sing-shadowsocks v0.2.6 - github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d - github.com/metacubex/sing-tun v0.1.15-0.20231211084005-e7b0b6c7c698 + github.com/metacubex/sing-shadowsocks2 v0.1.6-beta.1 + github.com/metacubex/sing-tun v0.2.0-beta.4 github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f github.com/metacubex/sing-wireguard v0.0.0-20231209125515-0594297f7232 github.com/miekg/dns v1.1.57 @@ -34,8 +34,8 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.19-0.20231209022445-766839c00099 - github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 + github.com/sagernet/sing v0.3.0-beta.6 + github.com/sagernet/sing-mux v0.1.6-beta.1 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 github.com/sagernet/utls v1.5.4 @@ -112,4 +112,4 @@ require ( golang.org/x/tools v0.16.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231210002924-c2e1b943c79e +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8 diff --git a/go.sum b/go.sum index a0a2d3ab..94e4317e 100644 --- a/go.sum +++ b/go.sum @@ -110,16 +110,16 @@ github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc h1:+yTZ6q2EeQCAJN github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231210002924-c2e1b943c79e h1:c37RHcmi2z1q1zGfOsKeue0BbrCNfdsmJkrztTh0mPI= -github.com/metacubex/sing v0.0.0-20231210002924-c2e1b943c79e/go.mod h1:Ce5LNojQOgOiWhiD8pPD6E9H7e2KgtOe3Zxx4Ou5u80= +github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8 h1:VEos1wHxHMPoFUGTq4HNrPhhbaFmwM1IsvE9rwwQp0Q= +github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= -github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d h1:hMs2isnO6198XaBwqbPff5bYt3uz1498osDC0sVe/dA= -github.com/metacubex/sing-shadowsocks2 v0.1.5-0.20231207115048-3abf19378f0d/go.mod h1:Y7Dm/rJpieN2xkU/pnxJCQxqmFptUCYiGd8oJhiHd0w= -github.com/metacubex/sing-tun v0.1.15-0.20231211084005-e7b0b6c7c698 h1:evcXZKgMO6NiGOB5nWTAAUANq7nXodN23P8SpyDm+78= -github.com/metacubex/sing-tun v0.1.15-0.20231211084005-e7b0b6c7c698/go.mod h1:eS+glMH6cXwDc5RKiF53XGbypBMPD8EfiXXs2G++8tE= +github.com/metacubex/sing-shadowsocks2 v0.1.6-beta.1 h1:ftbpVCK1+n3jxIP7+NMkRYOFEQtGPodV42MizsPey0w= +github.com/metacubex/sing-shadowsocks2 v0.1.6-beta.1/go.mod h1:kUVj2X+2wUh6Z5pAk9WrjDRehPyXolC6nJyFl7ln4V4= +github.com/metacubex/sing-tun v0.2.0-beta.4 h1:42F+uF9zKsaWsiUXNKzZD8aRkyPN9m5SdpF2yZEZar8= +github.com/metacubex/sing-tun v0.2.0-beta.4/go.mod h1:O8wFThUDfiwb6y56I714dQuyaqT8DW9VCD/wvGesyLM= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= github.com/metacubex/sing-wireguard v0.0.0-20231209125515-0594297f7232 h1:loWjR+k9dxqBSgruGyT5hE8UCRMmCEjxqZbryfY9no4= @@ -159,8 +159,8 @@ github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a h1:+NkI2670SQpQWvkk github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a/go.mod h1:63s7jpZqcDAIpj8oI/1v4Izok+npJOHACFCU6+huCkM= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2 h1:rRlYQPbMKmzKX+43XC04gEQvxc45/AxfteRWfcl2/rw= -github.com/sagernet/sing-mux v0.1.6-0.20231208180947-9053c29513a2/go.mod h1:IdSrwwqBeJTrjLZJRFXE+F8mYXNI/rPAjzlgTFuEVmo= +github.com/sagernet/sing-mux v0.1.6-beta.1 h1:ADs1TgiMfA628Y2qfv21tEvePDZjBRRYddwtNFZiwe8= +github.com/sagernet/sing-mux v0.1.6-beta.1/go.mod h1:WWtRmrwCDgb+g+7Da6o62I9WiMNB0a3w6BJhEpNQlNA= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 0827af5e..cc26d37d 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -208,7 +208,6 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis Name: tunName, MTU: tunMTU, GSO: options.GSO, - GSOMaxSize: options.GSOMaxSize, Inet4Address: options.Inet4Address, Inet6Address: options.Inet6Address, AutoRoute: options.AutoRoute, From f16ebf9bfeaac55b2e203af9f2436c4897ac65b7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 18 Dec 2023 23:22:50 +0800 Subject: [PATCH 171/192] chore: add leading slash to ws-path --- transport/vmess/websocket.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index acca049f..f6914199 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -338,6 +338,10 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } + if !strings.HasPrefix(uri.Path, "/") { + uri.Path = "/" + uri.Path + } + if c.TLS { uri.Scheme = "wss" config := c.TLSConfig From 9d8c3b0a3be6f9a7d9ea89b9c4d8840755ccafad Mon Sep 17 00:00:00 2001 From: PuerNya Date: Mon, 18 Dec 2023 23:44:19 +0800 Subject: [PATCH 172/192] fix: udp nat handle --- tunnel/tunnel.go | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 64ae91bf..9891d96f 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -342,29 +342,9 @@ func handleUDPConn(packet C.PacketAdapter) { return false } - if handle() { - packet.Drop() - return - } - - cond, loaded := natTable.GetOrCreateLock(key) - go func() { defer packet.Drop() - if loaded { - cond.L.Lock() - cond.Wait() - handle() - cond.L.Unlock() - return - } - - defer func() { - natTable.DeleteLock(key) - cond.Broadcast() - }() - proxy, rule, err := resolveMetadata(metadata) if err != nil { log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) @@ -381,6 +361,25 @@ func handleUDPConn(packet C.PacketAdapter) { metadata.DstIP = ip } + if handle() { + return + } + + cond, loaded := natTable.GetOrCreateLock(key) + + if loaded { + cond.L.Lock() + cond.Wait() + handle() + cond.L.Unlock() + return + } + + defer func() { + natTable.DeleteLock(key) + cond.Broadcast() + }() + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout) defer cancel() rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) { From 16769865e46972e5e3dec47db0b566867b2c576e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A5=9D=E5=AD=90=E7=A5=BA?= Date: Tue, 19 Dec 2023 21:01:28 +0800 Subject: [PATCH 173/192] support loong64 (#871) --- component/ebpf/byteorder/byteorder_littleendian.go | 2 +- component/ebpf/redir/bpf_bpfel.go | 4 ++-- component/ebpf/tc/bpf_bpfel.go | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/component/ebpf/byteorder/byteorder_littleendian.go b/component/ebpf/byteorder/byteorder_littleendian.go index 216a5e5a..d40f3517 100644 --- a/component/ebpf/byteorder/byteorder_littleendian.go +++ b/component/ebpf/byteorder/byteorder_littleendian.go @@ -1,4 +1,4 @@ -//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64 +//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64 || loong64 package byteorder diff --git a/component/ebpf/redir/bpf_bpfel.go b/component/ebpf/redir/bpf_bpfel.go index 936b84eb..1fe3454a 100644 --- a/component/ebpf/redir/bpf_bpfel.go +++ b/component/ebpf/redir/bpf_bpfel.go @@ -1,6 +1,6 @@ // Code generated by bpf2go; DO NOT EDIT. -//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64 -// +build 386 amd64 amd64p32 arm arm64 mips64le mips64p32le mipsle ppc64le riscv64 +//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64 || loong64 +// +build 386 amd64 amd64p32 arm arm64 mips64le mips64p32le mipsle ppc64le riscv64 loong64 package redir diff --git a/component/ebpf/tc/bpf_bpfel.go b/component/ebpf/tc/bpf_bpfel.go index 07daba12..3bfa1655 100644 --- a/component/ebpf/tc/bpf_bpfel.go +++ b/component/ebpf/tc/bpf_bpfel.go @@ -1,6 +1,6 @@ -// Code generated by bpf2go; DO NOT EDIT. -//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64 -// +build 386 amd64 amd64p32 arm arm64 mips64le mips64p32le mipsle ppc64le riscv64 +// +//go:build 386 || amd64 || amd64p32 || arm || arm64 || mips64le || mips64p32le || mipsle || ppc64le || riscv64 || loong64 +// +build 386 amd64 amd64p32 arm arm64 mips64le mips64p32le mipsle ppc64le riscv64 loong64 package tc From 518c31dd0ef4e97b7a7a06ca24449cb6925d3d4b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 19 Dec 2023 21:10:02 +0800 Subject: [PATCH 174/192] ci: build loong64 --- .github/workflows/build.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 311532f2..f9e04574 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -48,7 +48,7 @@ jobs: target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", id: "4", } - - { type: "WithoutCGO", target: "linux-386 linux-riscv64", id: "5" } + - { type: "WithoutCGO", target: "linux-386 linux-riscv64 linux-loong64", id: "5" } - { type: "WithoutCGO", target: "freebsd-386 freebsd-amd64 freebsd-arm64", @@ -118,11 +118,7 @@ jobs: - name: Set ENV run: | sudo timedatectl set-timezone "Asia/Shanghai" - echo "NAME=mihomo" >> $GITHUB_ENV - echo "REPO=${{ github.repository }}" >> $GITHUB_ENV - echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV echo "BUILDTIME=$(date)" >> $GITHUB_ENV - echo "BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV shell: bash - name: Set ENV From 429a03d9868f7c4817d4041d0ea77378cceb8941 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 20 Dec 2023 13:11:00 +0800 Subject: [PATCH 175/192] chore: add loopback detect for direct outbound --- adapter/outbound/direct.go | 15 ++++- adapter/outbound/direct_loopback_detect.go | 68 ++++++++++++++++++++++ common/callback/close_callback.go | 61 +++++++++++++++++++ constant/metadata.go | 8 ++- 4 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 adapter/outbound/direct_loopback_detect.go create mode 100644 common/callback/close_callback.go diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index b9b9fefc..7def7b20 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -3,6 +3,7 @@ package outbound import ( "context" "errors" + "fmt" "net/netip" N "github.com/metacubex/mihomo/common/net" @@ -13,6 +14,7 @@ import ( type Direct struct { *Base + loopBack *loopBackDetector } type DirectOption struct { @@ -22,17 +24,23 @@ type DirectOption struct { // DialContext implements C.ProxyAdapter func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { + if d.loopBack.CheckConn(metadata.SourceAddrPort()) { + return nil, fmt.Errorf("reject loopback connection to: %s", metadata.RemoteAddress()) + } opts = append(opts, dialer.WithResolver(resolver.DefaultResolver)) c, err := dialer.DialContext(ctx, "tcp", metadata.RemoteAddress(), d.Base.DialOptions(opts...)...) if err != nil { return nil, err } N.TCPKeepAlive(c) - return NewConn(c, d), nil + return d.loopBack.NewConn(NewConn(c, d)), nil } // ListenPacketContext implements C.ProxyAdapter func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { + if d.loopBack.CheckPacketConn(metadata.SourceAddrPort()) { + return nil, fmt.Errorf("reject loopback connection to: %s", metadata.RemoteAddress()) + } // net.UDPConn.WriteTo only working with *net.UDPAddr, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, resolver.DefaultResolver) @@ -45,7 +53,7 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, if err != nil { return nil, err } - return newPacketConn(pc, d), nil + return d.loopBack.NewPacketConn(newPacketConn(pc, d)), nil } func NewDirectWithOption(option DirectOption) *Direct { @@ -60,6 +68,7 @@ func NewDirectWithOption(option DirectOption) *Direct { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, + loopBack: newLoopBackDetector(), } } @@ -71,6 +80,7 @@ func NewDirect() *Direct { udp: true, prefer: C.DualStack, }, + loopBack: newLoopBackDetector(), } } @@ -82,5 +92,6 @@ func NewCompatible() *Direct { udp: true, prefer: C.DualStack, }, + loopBack: newLoopBackDetector(), } } diff --git a/adapter/outbound/direct_loopback_detect.go b/adapter/outbound/direct_loopback_detect.go new file mode 100644 index 00000000..410d5a2f --- /dev/null +++ b/adapter/outbound/direct_loopback_detect.go @@ -0,0 +1,68 @@ +package outbound + +import ( + "net/netip" + + "github.com/metacubex/mihomo/common/callback" + C "github.com/metacubex/mihomo/constant" + + "github.com/puzpuzpuz/xsync/v3" +) + +type loopBackDetector struct { + connMap *xsync.MapOf[netip.AddrPort, struct{}] + packetConnMap *xsync.MapOf[netip.AddrPort, struct{}] +} + +func newLoopBackDetector() *loopBackDetector { + return &loopBackDetector{ + connMap: xsync.NewMapOf[netip.AddrPort, struct{}](), + packetConnMap: xsync.NewMapOf[netip.AddrPort, struct{}](), + } +} + +func (l *loopBackDetector) NewConn(conn C.Conn) C.Conn { + metadata := C.Metadata{} + if metadata.SetRemoteAddr(conn.LocalAddr()) != nil { + return conn + } + connAddr := metadata.AddrPort() + if !connAddr.IsValid() { + return conn + } + l.connMap.Store(connAddr, struct{}{}) + return callback.NewCloseCallbackConn(conn, func() { + l.connMap.Delete(connAddr) + }) +} + +func (l *loopBackDetector) NewPacketConn(conn C.PacketConn) C.PacketConn { + metadata := C.Metadata{} + if metadata.SetRemoteAddr(conn.LocalAddr()) != nil { + return conn + } + connAddr := metadata.AddrPort() + if !connAddr.IsValid() { + return conn + } + l.packetConnMap.Store(connAddr, struct{}{}) + return callback.NewCloseCallbackPacketConn(conn, func() { + l.packetConnMap.Delete(connAddr) + }) +} + +func (l *loopBackDetector) CheckConn(connAddr netip.AddrPort) bool { + if !connAddr.IsValid() { + return false + } + _, ok := l.connMap.Load(connAddr) + return ok +} + +func (l *loopBackDetector) CheckPacketConn(connAddr netip.AddrPort) bool { + if !connAddr.IsValid() { + return false + } + _, ok := l.packetConnMap.Load(connAddr) + return ok +} diff --git a/common/callback/close_callback.go b/common/callback/close_callback.go new file mode 100644 index 00000000..630ee5d7 --- /dev/null +++ b/common/callback/close_callback.go @@ -0,0 +1,61 @@ +package callback + +import ( + "sync" + + C "github.com/metacubex/mihomo/constant" +) + +type closeCallbackConn struct { + C.Conn + closeFunc func() + closeOnce sync.Once +} + +func (w *closeCallbackConn) Close() error { + w.closeOnce.Do(w.closeFunc) + return w.Conn.Close() +} + +func (w *closeCallbackConn) ReaderReplaceable() bool { + return true +} + +func (w *closeCallbackConn) WriterReplaceable() bool { + return true +} + +func (w *closeCallbackConn) Upstream() any { + return w.Conn +} + +func NewCloseCallbackConn(conn C.Conn, callback func()) C.Conn { + return &closeCallbackConn{Conn: conn, closeFunc: callback} +} + +type closeCallbackPacketConn struct { + C.PacketConn + closeFunc func() + closeOnce sync.Once +} + +func (w *closeCallbackPacketConn) Close() error { + w.closeOnce.Do(w.closeFunc) + return w.PacketConn.Close() +} + +func (w *closeCallbackPacketConn) ReaderReplaceable() bool { + return true +} + +func (w *closeCallbackPacketConn) WriterReplaceable() bool { + return true +} + +func (w *closeCallbackPacketConn) Upstream() any { + return w.PacketConn +} + +func NewCloseCallbackPacketConn(conn C.PacketConn, callback func()) C.PacketConn { + return &closeCallbackPacketConn{PacketConn: conn, closeFunc: callback} +} diff --git a/constant/metadata.go b/constant/metadata.go index 09a2f152..3c712909 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -148,8 +148,8 @@ type Metadata struct { SpecialRules string `json:"specialRules"` RemoteDst string `json:"remoteDestination"` - RawSrcAddr net.Addr `json:"-"` - RawDstAddr net.Addr `json:"-"` + RawSrcAddr net.Addr `json:"-"` + RawDstAddr net.Addr `json:"-"` // Only domain rule SniffHost string `json:"sniffHost"` } @@ -162,6 +162,10 @@ func (m *Metadata) SourceAddress() string { return net.JoinHostPort(m.SrcIP.String(), strconv.FormatUint(uint64(m.SrcPort), 10)) } +func (m *Metadata) SourceAddrPort() netip.AddrPort { + return netip.AddrPortFrom(m.SrcIP.Unmap(), m.SrcPort) +} + func (m *Metadata) SourceDetail() string { if m.Type == INNER { return fmt.Sprintf("%s", MihomoName) From 27635ea027364f33d6e8cbed6d1c6e6a790332a3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 20 Dec 2023 23:30:06 +0800 Subject: [PATCH 176/192] fix: hy2 missing UDP timeout --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6e92f38e..054b04dc 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 - github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 + github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.1.6-beta.1 github.com/metacubex/sing-tun v0.2.0-beta.4 diff --git a/go.sum b/go.sum index 94e4317e..0637fff6 100644 --- a/go.sum +++ b/go.sum @@ -112,8 +112,8 @@ github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hkn github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8 h1:VEos1wHxHMPoFUGTq4HNrPhhbaFmwM1IsvE9rwwQp0Q= github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= -github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8 h1:gmZb7M2Z4y6BQSWljJORGVGZlKaYWEpoIJlVMg9naEY= -github.com/metacubex/sing-quic v0.0.0-20231207122758-cc17b154daa8/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= +github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796 h1:xiCPttMGAaIh4Ad6t85VxUoUv+Sg88eXzzUvYN8gT5w= +github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.1.6-beta.1 h1:ftbpVCK1+n3jxIP7+NMkRYOFEQtGPodV42MizsPey0w= From 8822349f946143362137c0b7c4350b408ae9f274 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Dec 2023 21:18:26 +0800 Subject: [PATCH 177/192] chore: support waitRead in windows --- common/net/packet/packet_windows.go | 62 ++++++++++++++++++++++++++++- go.mod | 4 +- go.sum | 4 +- 3 files changed, 65 insertions(+), 5 deletions(-) diff --git a/common/net/packet/packet_windows.go b/common/net/packet/packet_windows.go index cb4c518b..3c467c6d 100644 --- a/common/net/packet/packet_windows.go +++ b/common/net/packet/packet_windows.go @@ -4,12 +4,72 @@ package packet import ( "net" + "strconv" + "syscall" + + "github.com/metacubex/mihomo/common/pool" + + "golang.org/x/sys/windows" ) type enhanceUDPConn struct { *net.UDPConn + rawConn syscall.RawConn } func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { - return waitReadFrom(c.UDPConn) + if c.rawConn == nil { + c.rawConn, _ = c.UDPConn.SyscallConn() + } + var readErr error + hasData := false + err = c.rawConn.Read(func(fd uintptr) (done bool) { + if !hasData { + hasData = true + // golang's internal/poll.FD.RawRead will Use a zero-byte read as a way to get notified when this + // socket is readable if we return false. So the `recvfrom` syscall will not block the system thread. + return false + } + readBuf := pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(readBuf) + } + var readFrom windows.Sockaddr + var readN int + readN, readFrom, readErr = windows.Recvfrom(windows.Handle(fd), readBuf, 0) + if readN > 0 { + data = readBuf[:readN] + } else { + put() + put = nil + data = nil + } + if readErr == windows.WSAEWOULDBLOCK { + return false + } + if readFrom != nil { + switch from := readFrom.(type) { + case *windows.SockaddrInet4: + ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes + addr = &net.UDPAddr{IP: ip[:], Port: from.Port} + case *windows.SockaddrInet6: + ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes + addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)} + } + } + // udp should not convert readN == 0 to io.EOF + //if readN == 0 { + // readErr = io.EOF + //} + hasData = false + return true + }) + if err != nil { + return + } + if readErr != nil { + err = readErr + return + } + return } diff --git a/go.mod b/go.mod index 054b04dc..866ac035 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/puzpuzpuz/xsync/v3 v3.0.2 github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.3.0-beta.6 + github.com/sagernet/sing v0.3.0-rc.3 github.com/sagernet/sing-mux v0.1.6-beta.1 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6 @@ -112,4 +112,4 @@ require ( golang.org/x/tools v0.16.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231221131356-d73c21c7ea3f diff --git a/go.sum b/go.sum index 0637fff6..3f80c92d 100644 --- a/go.sum +++ b/go.sum @@ -110,8 +110,8 @@ github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc h1:+yTZ6q2EeQCAJN github.com/metacubex/gvisor v0.0.0-20231209122014-3e43224c7bbc/go.mod h1:rhBU9tD5ktoGPBtXUquhWuGJ4u+8ZZzBMi2cAdv9q8Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394 h1:dIT+KB2hknBCrwVAXPeY9tpzzkOZP5m40yqUteRT6/Y= github.com/metacubex/quic-go v0.40.1-0.20231130135418-0c1b47cf9394/go.mod h1:F/t8VnA47xoia8ABlNA4InkZjssvFJ5p6E6jKdbkgAs= -github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8 h1:VEos1wHxHMPoFUGTq4HNrPhhbaFmwM1IsvE9rwwQp0Q= -github.com/metacubex/sing v0.0.0-20231218144940-fc8dd41d68e8/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= +github.com/metacubex/sing v0.0.0-20231221131356-d73c21c7ea3f h1:T2PuaAiXMSC3mjRRUmIomuiu3jhi7EWSbzXtVIrVUC4= +github.com/metacubex/sing v0.0.0-20231221131356-d73c21c7ea3f/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796 h1:xiCPttMGAaIh4Ad6t85VxUoUv+Sg88eXzzUvYN8gT5w= github.com/metacubex/sing-quic v0.0.0-20231220152840-85620b446796/go.mod h1:E1e1Uu6YaJddD+c0DtJlSOkfMI0NLdOVhM60KAlcssY= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= From ac381736a5473c2afe46a49d42896e73d3297032 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 22 Dec 2023 21:18:17 +0800 Subject: [PATCH 178/192] chore: restore function name to AliveForTestUrl --- adapter/adapter.go | 10 +++++----- adapter/outboundgroup/fallback.go | 6 +++--- adapter/outboundgroup/loadbalance.go | 8 ++++---- adapter/outboundgroup/urltest.go | 12 ++++++------ adapter/provider/healthcheck.go | 2 +- constant/adapters.go | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index a3af6471..695033b7 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -33,13 +33,13 @@ type internalProxyState struct { type Proxy struct { C.ProxyAdapter - history *queue.Queue[C.DelayHistory] alive atomic.Bool + history *queue.Queue[C.DelayHistory] extra *xsync.MapOf[string, *internalProxyState] } -// Alive implements C.Proxy -func (p *Proxy) Alive(url string) bool { +// AliveForTestUrl implements C.Proxy +func (p *Proxy) AliveForTestUrl(url string) bool { if state, ok := p.extra.Load(url); ok { return state.alive.Load() } @@ -127,7 +127,7 @@ func (p *Proxy) ExtraDelayHistories() map[string]C.ProxyState { // LastDelayForTestUrl return last history record of the specified URL. if proxy is not alive, return the max value of uint16. // implements C.Proxy func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { - var max uint16 = 0xffff + var maxDelay uint16 = 0xffff alive := false var history C.DelayHistory @@ -138,7 +138,7 @@ func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { } if !alive || history.Delay == 0 { - return max + return maxDelay } return history.Delay } diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 72d7e62a..50427e53 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -102,12 +102,12 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy { proxies := f.GetProxies(touch) for _, proxy := range proxies { if len(f.selected) == 0 { - if proxy.Alive(f.testUrl) { + if proxy.AliveForTestUrl(f.testUrl) { return proxy } } else { if proxy.Name() == f.selected { - if proxy.Alive(f.testUrl) { + if proxy.AliveForTestUrl(f.testUrl) { return proxy } else { f.selected = "" @@ -133,7 +133,7 @@ func (f *Fallback) Set(name string) error { } f.selected = name - if !p.Alive(f.testUrl) { + if !p.AliveForTestUrl(f.testUrl) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000)) defer cancel() expectedStatus, _ := utils.NewIntRanges[uint16](f.expectedStatus) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 8bcd661f..79b18948 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -150,7 +150,7 @@ func strategyRoundRobin(url string) strategyFn { for ; i < length; i++ { id := (idx + i) % length proxy := proxies[id] - if proxy.Alive(url) { + if proxy.AliveForTestUrl(url) { i++ return proxy } @@ -168,14 +168,14 @@ func strategyConsistentHashing(url string) strategyFn { for i := 0; i < maxRetry; i, key = i+1, key+1 { idx := jumpHash(key, buckets) proxy := proxies[idx] - if proxy.Alive(url) { + if proxy.AliveForTestUrl(url) { return proxy } } // when availability is poor, traverse the entire list to get the available nodes for _, proxy := range proxies { - if proxy.Alive(url) { + if proxy.AliveForTestUrl(url) { return proxy } } @@ -201,7 +201,7 @@ func strategyStickySessions(url string) strategyFn { nowIdx := idx for i := 1; i < maxRetry; i++ { proxy := proxies[nowIdx] - if proxy.Alive(url) { + if proxy.AliveForTestUrl(url) { if nowIdx != idx { lruCache.Delete(key) lruCache.Set(key, nowIdx) diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 2e533415..29d749f9 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -101,7 +101,7 @@ func (u *URLTest) fast(touch bool) C.Proxy { proxies := u.GetProxies(touch) if u.selected != "" { for _, proxy := range proxies { - if !proxy.Alive(u.testUrl) { + if !proxy.AliveForTestUrl(u.testUrl) { continue } if proxy.Name() == u.selected { @@ -113,7 +113,7 @@ func (u *URLTest) fast(touch bool) C.Proxy { elm, _, shared := u.fastSingle.Do(func() (C.Proxy, error) { fast := proxies[0] - min := fast.LastDelayForTestUrl(u.testUrl) + minDelay := fast.LastDelayForTestUrl(u.testUrl) fastNotExist := true for _, proxy := range proxies[1:] { @@ -121,19 +121,19 @@ func (u *URLTest) fast(touch bool) C.Proxy { fastNotExist = false } - if !proxy.Alive(u.testUrl) { + if !proxy.AliveForTestUrl(u.testUrl) { continue } delay := proxy.LastDelayForTestUrl(u.testUrl) - if delay < min { + if delay < minDelay { fast = proxy - min = delay + minDelay = delay } } // tolerance - if u.fastNode == nil || fastNotExist || !u.fastNode.Alive(u.testUrl) || u.fastNode.LastDelayForTestUrl(u.testUrl) > fast.LastDelayForTestUrl(u.testUrl)+u.tolerance { + if u.fastNode == nil || fastNotExist || !u.fastNode.AliveForTestUrl(u.testUrl) || u.fastNode.LastDelayForTestUrl(u.testUrl) > fast.LastDelayForTestUrl(u.testUrl)+u.tolerance { u.fastNode = fast } return u.fastNode, nil diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 11118501..d8e56192 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -202,7 +202,7 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex defer cancel() log.Debugln("Health Checking, proxy: %s, url: %s, id: {%s}", p.Name(), url, uid) _, _ = p.URLTest(ctx, url, expectedStatus) - log.Debugln("Health Checked, proxy: %s, url: %s, alive: %t, delay: %d ms uid: {%s}", p.Name(), url, p.Alive(url), p.LastDelayForTestUrl(url), uid) + log.Debugln("Health Checked, proxy: %s, url: %s, alive: %t, delay: %d ms uid: {%s}", p.Name(), url, p.AliveForTestUrl(url), p.LastDelayForTestUrl(url), uid) return false, nil }) } diff --git a/constant/adapters.go b/constant/adapters.go index 58b2a92b..6d7acd63 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -156,7 +156,7 @@ type DelayHistoryStoreType int type Proxy interface { ProxyAdapter - Alive(url string) bool + AliveForTestUrl(url string) bool DelayHistory() []DelayHistory ExtraDelayHistories() map[string]ProxyState LastDelayForTestUrl(url string) uint16 From 147400fbe037e24d7e71d78c5bd1009f088fc1d8 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 16 Dec 2023 20:38:20 +0800 Subject: [PATCH 179/192] chore: cleanup code --- common/arc/arc.go | 128 +++++++++++++++++++++-------------------- common/arc/arc_test.go | 122 +++++++++++++++++++++++++++------------ common/lru/lrucache.go | 8 +-- 3 files changed, 155 insertions(+), 103 deletions(-) diff --git a/common/arc/arc.go b/common/arc/arc.go index 8e62c906..da78b1c1 100644 --- a/common/arc/arc.go +++ b/common/arc/arc.go @@ -20,16 +20,15 @@ func WithSize[K comparable, V any](maxSize int) Option[K, V] { } type ARC[K comparable, V any] struct { - p int - c int - t1 *list.List[*entry[K, V]] - b1 *list.List[*entry[K, V]] - t2 *list.List[*entry[K, V]] - b2 *list.List[*entry[K, V]] - mutex sync.Mutex - len int - cache map[K]*entry[K, V] - staleReturn bool + p int + c int + t1 *list.List[*entry[K, V]] + b1 *list.List[*entry[K, V]] + t2 *list.List[*entry[K, V]] + b2 *list.List[*entry[K, V]] + mutex sync.Mutex + len int + cache map[K]*entry[K, V] } // New returns a new Adaptive Replacement Cache (ARC). @@ -74,20 +73,22 @@ func (a *ARC[K, V]) SetWithExpire(key K, value V, expires time.Time) { func (a *ARC[K, V]) setWithExpire(key K, value V, expires time.Time) { ent, ok := a.cache[key] - if ok != true { + if !ok { a.len++ ent := &entry[K, V]{key: key, value: value, ghost: false, expires: expires.Unix()} a.req(ent) a.cache[key] = ent - } else { - if ent.ghost { - a.len++ - } - ent.value = value - ent.ghost = false - ent.expires = expires.Unix() - a.req(ent) + return } + + if ent.ghost { + a.len++ + } + + ent.value = value + ent.ghost = false + ent.expires = expires.Unix() + a.req(ent) } // Get retrieves a previously via Set inserted entry. @@ -97,25 +98,25 @@ func (a *ARC[K, V]) Get(key K) (value V, ok bool) { defer a.mutex.Unlock() ent, ok := a.get(key) - if ok { - return ent.value, true + if !ok { + return lo.Empty[V](), false } - return lo.Empty[V](), false + return ent.value, true } func (a *ARC[K, V]) get(key K) (e *entry[K, V], ok bool) { ent, ok := a.cache[key] - if ok { - a.req(ent) - return ent, !ent.ghost + if !ok { + return ent, false } - return ent, false + a.req(ent) + return ent, !ent.ghost } // GetWithExpire returns any representation of a cached response, // a time.Time Give expected expires, // and a bool set to true if the key was found. -// This method will NOT check the maxAge of element and will NOT update the expires. +// This method will NOT update the expires. func (a *ARC[K, V]) GetWithExpire(key K) (V, time.Time, bool) { a.mutex.Lock() defer a.mutex.Unlock() @@ -138,10 +139,11 @@ func (a *ARC[K, V]) Len() int { } func (a *ARC[K, V]) req(ent *entry[K, V]) { - if ent.ll == a.t1 || ent.ll == a.t2 { + switch { + case ent.ll == a.t1 || ent.ll == a.t2: // Case I ent.setMRU(a.t2) - } else if ent.ll == a.b1 { + case ent.ll == a.b1: // Case II // Cache Miss in t1 and t2 @@ -152,16 +154,11 @@ func (a *ARC[K, V]) req(ent *entry[K, V]) { } else { d = a.b2.Len() / a.b1.Len() } - - // a.p = min(a.p+d, a.c) - a.p = a.p + d - if a.c < a.p { - a.p = a.c - } + a.p = min(a.p+d, a.c) a.replace(ent) ent.setMRU(a.t2) - } else if ent.ll == a.b2 { + case ent.ll == a.b2: // Case III // Cache Miss in t1 and t2 @@ -172,35 +169,30 @@ func (a *ARC[K, V]) req(ent *entry[K, V]) { } else { d = a.b1.Len() / a.b2.Len() } - //a.p = max(a.p-d, 0) - a.p = a.p - d - if a.p < 0 { - a.p = 0 - } + a.p = max(a.p-d, 0) a.replace(ent) ent.setMRU(a.t2) - } else if ent.ll == nil { - // Case IV - - if a.t1.Len()+a.b1.Len() == a.c { - // Case A - if a.t1.Len() < a.c { - a.delLRU(a.b1) - a.replace(ent) - } else { - a.delLRU(a.t1) - } - } else if a.t1.Len()+a.b1.Len() < a.c { - // Case B - if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() >= a.c { - if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() == 2*a.c { - a.delLRU(a.b2) - } - a.replace(ent) - } + case ent.ll == nil && a.t1.Len()+a.b1.Len() == a.c: + // Case IV A + if a.t1.Len() < a.c { + a.delLRU(a.b1) + a.replace(ent) + } else { + a.delLRU(a.t1) } - + ent.setMRU(a.t1) + case ent.ll == nil && a.t1.Len()+a.b1.Len() < a.c: + // Case IV B + if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() >= a.c { + if a.t1.Len()+a.t2.Len()+a.b1.Len()+a.b2.Len() == 2*a.c { + a.delLRU(a.b2) + } + a.replace(ent) + } + ent.setMRU(a.t1) + case ent.ll == nil: + // Case IV, not A nor B ent.setMRU(a.t1) } } @@ -227,3 +219,17 @@ func (a *ARC[K, V]) replace(ent *entry[K, V]) { lru.setMRU(a.b2) } } + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a int, b int) int { + if a < b { + return b + } + return a +} diff --git a/common/arc/arc_test.go b/common/arc/arc_test.go index cb9835a3..a9d8a0c1 100644 --- a/common/arc/arc_test.go +++ b/common/arc/arc_test.go @@ -1,59 +1,105 @@ package arc -import "testing" +import ( + "testing" +) -func TestBasic(t *testing.T) { +func TestInsertion(t *testing.T) { cache := New[string, string](WithSize[string, string](3)) - if cache.Len() != 0 { - t.Error("Empty cache should have length 0") + if got, want := cache.Len(), 0; got != want { + t.Errorf("empty cache.Len(): got %d want %d", cache.Len(), want) } - cache.Set("Hello", "World") - if cache.Len() != 1 { - t.Error("Cache should have length 1") + const ( + k1 = "Hello" + k2 = "Hallo" + k3 = "Ciao" + k4 = "Salut" + + v1 = "World" + v2 = "Worlds" + v3 = "Welt" + ) + + // Insert the first value + cache.Set(k1, v1) + if got, want := cache.Len(), 1; got != want { + t.Errorf("insertion of key #%d: cache.Len(): got %d want %d", want, cache.Len(), want) + } + if got, ok := cache.Get(k1); !ok || got != v1 { + t.Errorf("cache.Get(%v): got (%v,%t) want (%v,true)", k1, got, ok, v1) } - var val interface{} - var ok bool - - if val, ok = cache.Get("Hello"); val != "World" || ok != true { - t.Error("Didn't set \"Hello\" to \"World\"") + // Replace existing value for a given key + cache.Set(k1, v2) + if got, want := cache.Len(), 1; got != want { + t.Errorf("re-insertion: cache.Len(): got %d want %d", cache.Len(), want) + } + if got, ok := cache.Get(k1); !ok || got != v2 { + t.Errorf("re-insertion: cache.Get(%v): got (%v,%t) want (%v,true)", k1, got, ok, v2) } - cache.Set("Hello", "World1") - if cache.Len() != 1 { - t.Error("Inserting the same entry multiple times shouldn't increase cache size") + // Add a second different key + cache.Set(k2, v3) + if got, want := cache.Len(), 2; got != want { + t.Errorf("insertion of key #%d: cache.Len(): got %d want %d", want, cache.Len(), want) + } + if got, ok := cache.Get(k1); !ok || got != v2 { + t.Errorf("cache.Get(%v): got (%v,%t) want (%v,true)", k1, got, ok, v2) + } + if got, ok := cache.Get(k2); !ok || got != v3 { + t.Errorf("cache.Get(%v): got (%v,%t) want (%v,true)", k2, got, ok, v3) } - if val, ok = cache.Get("Hello"); val != "World1" || ok != true { - t.Error("Didn't update \"Hello\" to \"World1\"") + // Fill cache + cache.Set(k3, v1) + if got, want := cache.Len(), 3; got != want { + t.Errorf("insertion of key #%d: cache.Len(): got %d want %d", want, cache.Len(), want) } - cache.Set("Hallo", "Welt") - if cache.Len() != 2 { - t.Error("Inserting two different entries should result into lenght=2") - } - - if val, ok = cache.Get("Hallo"); val != "Welt" || ok != true { - t.Error("Didn't set \"Hallo\" to \"Welt\"") + // Exceed size, this should not exceed size: + cache.Set(k4, v1) + if got, want := cache.Len(), 3; got != want { + t.Errorf("insertion of key out of size: cache.Len(): got %d want %d", cache.Len(), want) } } -func TestBasicReplace(t *testing.T) { - cache := New[string, string](WithSize[string, string](3)) - - cache.Set("Hello", "Hallo") - cache.Set("World", "Welt") - cache.Get("World") - cache.Set("Cache", "Cache") - cache.Set("Replace", "Ersetzen") - - value, ok := cache.Get("World") - if !ok || value != "Welt" { - t.Error("ARC should have replaced \"Hello\"") +func TestEviction(t *testing.T) { + size := 3 + cache := New[string, string](WithSize[string, string](size)) + if got, want := cache.Len(), 0; got != want { + t.Errorf("empty cache.Len(): got %d want %d", cache.Len(), want) } - if cache.Len() != 3 { - t.Error("ARC should have a maximum size of 3") + tests := []struct { + k, v string + }{ + {"k1", "v1"}, + {"k2", "v2"}, + {"k3", "v3"}, + {"k4", "v4"}, + } + for i, tt := range tests[:size] { + cache.Set(tt.k, tt.v) + if got, want := cache.Len(), i+1; got != want { + t.Errorf("insertion of key #%d: cache.Len(): got %d want %d", want, cache.Len(), want) + } + } + + // Exceed size and check we don't outgrow it: + cache.Set(tests[size].k, tests[size].v) + if got := cache.Len(); got != size { + t.Errorf("insertion of overflow key #%d: cache.Len(): got %d want %d", 4, cache.Len(), size) + } + + // Check that LRU got evicted: + if got, ok := cache.Get(tests[0].k); ok || got != "" { + t.Errorf("cache.Get(%v): got (%v,%t) want (,true)", tests[0].k, got, ok) + } + + for _, tt := range tests[1:] { + if got, ok := cache.Get(tt.k); !ok || got != tt.v { + t.Errorf("cache.Get(%v): got (%v,%t) want (%v,true)", tt.k, got, ok, tt.v) + } } } diff --git a/common/lru/lrucache.go b/common/lru/lrucache.go index d23277c2..6f32ed18 100644 --- a/common/lru/lrucache.go +++ b/common/lru/lrucache.go @@ -80,7 +80,7 @@ func New[K comparable, V any](options ...Option[K, V]) *LruCache[K, V] { return lc } -// Get returns the any representation of a cached response and a bool +// Get returns any representation of a cached response and a bool // set to true if the key was found. func (c *LruCache[K, V]) Get(key K) (V, bool) { c.mu.Lock() @@ -110,7 +110,7 @@ func (c *LruCache[K, V]) GetOrStore(key K, constructor func() V) (V, bool) { return value, true } -// GetWithExpire returns the any representation of a cached response, +// GetWithExpire returns any representation of a cached response, // a time.Time Give expected expires, // and a bool set to true if the key was found. // This method will NOT check the maxAge of element and will NOT update the expires. @@ -135,7 +135,7 @@ func (c *LruCache[K, V]) Exist(key K) bool { return ok } -// Set stores the any representation of a response for a given key. +// Set stores any representation of a response for a given key. func (c *LruCache[K, V]) Set(key K, value V) { c.mu.Lock() defer c.mu.Unlock() @@ -151,7 +151,7 @@ func (c *LruCache[K, V]) set(key K, value V) { c.setWithExpire(key, value, time.Unix(expires, 0)) } -// SetWithExpire stores the any representation of a response for a given key and given expires. +// SetWithExpire stores any representation of a response for a given key and given expires. // The expires time will round to second. func (c *LruCache[K, V]) SetWithExpire(key K, value V, expires time.Time) { c.mu.Lock() From 59ab4fe745e2ecbc3b4676d2b7d54c50d4f290ca Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 19 Dec 2023 19:59:37 +0800 Subject: [PATCH 180/192] chore: better Reject-Drop for UDP --- adapter/outbound/reject.go | 22 ---------------------- tunnel/tunnel.go | 5 ++++- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index b564e28d..62f4aaa5 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -30,9 +30,6 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ... // ListenPacketContext implements C.ProxyAdapter func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - if r.drop { - return newPacketConn(&dropPacketConn{}, r), nil - } return newPacketConn(&nopPacketConn{}, r), nil } @@ -129,22 +126,3 @@ func (rw dropConn) RemoteAddr() net.Addr { return nil } func (rw dropConn) SetDeadline(time.Time) error { return nil } func (rw dropConn) SetReadDeadline(time.Time) error { return nil } func (rw dropConn) SetWriteDeadline(time.Time) error { return nil } - -type dropPacketConn struct{} - -func (npc dropPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - time.Sleep(C.DefaultDropTime) - return len(b), nil -} -func (npc dropPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - time.Sleep(C.DefaultDropTime) - return 0, nil, io.EOF -} -func (npc dropPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { - return nil, nil, nil, io.EOF -} -func (npc dropPacketConn) Close() error { return nil } -func (npc dropPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } -func (npc dropPacketConn) SetDeadline(time.Time) error { return nil } -func (npc dropPacketConn) SetReadDeadline(time.Time) error { return nil } -func (npc dropPacketConn) SetWriteDeadline(time.Time) error { return nil } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 9891d96f..71772e71 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -355,7 +355,6 @@ func handleUDPConn(packet C.PacketAdapter) { if !metadata.Resolved() && proxy.Type() != C.Reject && proxy.Type() != C.RejectDrop { ip, err := resolver.ResolveIP(context.Background(), metadata.Host) if err != nil { - packet.Drop() return } metadata.DstIP = ip @@ -409,6 +408,10 @@ func handleUDPConn(packet C.PacketAdapter) { case rule != nil: if rule.Payload() != "" { log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), fmt.Sprintf("%s(%s)", rule.RuleType().String(), rule.Payload()), rawPc.Chains().String()) + if rawPc.Chains().Last() == "REJECT-DROP" { + pc.Close() + return + } } else { log.Infoln("[UDP] %s --> %s match %s using %s", metadata.SourceDetail(), metadata.RemoteAddress(), rule.Payload(), rawPc.Chains().String()) } From b632575e39c5da5fceca85084fa91869a7daebd4 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 23 Dec 2023 00:05:07 +0800 Subject: [PATCH 181/192] chore: Cleanup unused GeoSite matchers --- component/geodata/router/condition.go | 18 +--- .../strmatcher/ac_automaton_matcher.go | 2 +- .../geodata/strmatcher/domain_matcher.go | 98 ------------------- component/geodata/strmatcher/full_matcher.go | 25 ----- component/geodata/strmatcher/mph_matcher.go | 28 +++--- component/geodata/strmatcher/strmatcher.go | 47 --------- component/geodata/utils.go | 7 +- 7 files changed, 17 insertions(+), 208 deletions(-) delete mode 100644 component/geodata/strmatcher/domain_matcher.go delete mode 100644 component/geodata/strmatcher/full_matcher.go diff --git a/component/geodata/router/condition.go b/component/geodata/router/condition.go index 82684d93..73bc88d4 100644 --- a/component/geodata/router/condition.go +++ b/component/geodata/router/condition.go @@ -42,7 +42,7 @@ type succinctDomainMatcher struct { not bool } -func (m succinctDomainMatcher) ApplyDomain(domain string) bool { +func (m *succinctDomainMatcher) ApplyDomain(domain string) bool { isMatched := m.set.Has(domain) if !isMatched { for _, matcher := range m.otherMatchers { @@ -113,22 +113,6 @@ func NewMphMatcherGroup(domains []*Domain, not bool) (DomainMatcher, error) { }, nil } -func NewDomainMatcher(domains []*Domain, not bool) (DomainMatcher, error) { - g := new(strmatcher.MatcherGroup) - for _, d := range domains { - m, err := domainToMatcher(d) - if err != nil { - return nil, err - } - g.Add(m) - } - - return &v2rayDomainMatcher{ - matchers: g, - not: not, - }, nil -} - func (m *v2rayDomainMatcher) ApplyDomain(domain string) bool { isMatched := len(m.matchers.Match(strings.ToLower(domain))) > 0 if m.not { diff --git a/component/geodata/strmatcher/ac_automaton_matcher.go b/component/geodata/strmatcher/ac_automaton_matcher.go index a21a83a2..fd02d511 100644 --- a/component/geodata/strmatcher/ac_automaton_matcher.go +++ b/component/geodata/strmatcher/ac_automaton_matcher.go @@ -39,7 +39,7 @@ func newNode() [validCharCount]Edge { return s } -var char2Index = []int{ +var char2Index = [...]int{ 'A': 0, 'a': 0, 'B': 1, diff --git a/component/geodata/strmatcher/domain_matcher.go b/component/geodata/strmatcher/domain_matcher.go deleted file mode 100644 index ae8e65bc..00000000 --- a/component/geodata/strmatcher/domain_matcher.go +++ /dev/null @@ -1,98 +0,0 @@ -package strmatcher - -import "strings" - -func breakDomain(domain string) []string { - return strings.Split(domain, ".") -} - -type node struct { - values []uint32 - sub map[string]*node -} - -// DomainMatcherGroup is a IndexMatcher for a large set of Domain matchers. -// Visible for testing only. -type DomainMatcherGroup struct { - root *node -} - -func (g *DomainMatcherGroup) Add(domain string, value uint32) { - if g.root == nil { - g.root = new(node) - } - - current := g.root - parts := breakDomain(domain) - for i := len(parts) - 1; i >= 0; i-- { - part := parts[i] - if current.sub == nil { - current.sub = make(map[string]*node) - } - next := current.sub[part] - if next == nil { - next = new(node) - current.sub[part] = next - } - current = next - } - - current.values = append(current.values, value) -} - -func (g *DomainMatcherGroup) addMatcher(m domainMatcher, value uint32) { - g.Add(string(m), value) -} - -func (g *DomainMatcherGroup) Match(domain string) []uint32 { - if domain == "" { - return nil - } - - current := g.root - if current == nil { - return nil - } - - nextPart := func(idx int) int { - for i := idx - 1; i >= 0; i-- { - if domain[i] == '.' { - return i - } - } - return -1 - } - - matches := [][]uint32{} - idx := len(domain) - for { - if idx == -1 || current.sub == nil { - break - } - - nidx := nextPart(idx) - part := domain[nidx+1 : idx] - next := current.sub[part] - if next == nil { - break - } - current = next - idx = nidx - if len(current.values) > 0 { - matches = append(matches, current.values) - } - } - switch len(matches) { - case 0: - return nil - case 1: - return matches[0] - default: - result := []uint32{} - for idx := range matches { - // Insert reversely, the subdomain that matches further ranks higher - result = append(result, matches[len(matches)-1-idx]...) - } - return result - } -} diff --git a/component/geodata/strmatcher/full_matcher.go b/component/geodata/strmatcher/full_matcher.go deleted file mode 100644 index e00d02aa..00000000 --- a/component/geodata/strmatcher/full_matcher.go +++ /dev/null @@ -1,25 +0,0 @@ -package strmatcher - -type FullMatcherGroup struct { - matchers map[string][]uint32 -} - -func (g *FullMatcherGroup) Add(domain string, value uint32) { - if g.matchers == nil { - g.matchers = make(map[string][]uint32) - } - - g.matchers[domain] = append(g.matchers[domain], value) -} - -func (g *FullMatcherGroup) addMatcher(m fullMatcher, value uint32) { - g.Add(string(m), value) -} - -func (g *FullMatcherGroup) Match(str string) []uint32 { - if g.matchers == nil { - return nil - } - - return g.matchers[str] -} diff --git a/component/geodata/strmatcher/mph_matcher.go b/component/geodata/strmatcher/mph_matcher.go index 8d8b0508..7c1b4062 100644 --- a/component/geodata/strmatcher/mph_matcher.go +++ b/component/geodata/strmatcher/mph_matcher.go @@ -236,25 +236,25 @@ tail: h ^= uint64(*(*byte)(p)) h ^= uint64(*(*byte)(unsafe.Add(p, s>>1))) << 8 h ^= uint64(*(*byte)(unsafe.Add(p, s-1))) << 16 - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 case s <= 8: h ^= uint64(readUnaligned32(p)) h ^= uint64(readUnaligned32(unsafe.Add(p, s-4))) << 32 - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 case s <= 16: h ^= readUnaligned64(p) - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 h ^= readUnaligned64(unsafe.Add(p, s-8)) - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 case s <= 32: h ^= readUnaligned64(p) - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 h ^= readUnaligned64(unsafe.Add(p, 8)) - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 h ^= readUnaligned64(unsafe.Add(p, s-16)) - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 h ^= readUnaligned64(unsafe.Add(p, s-8)) - h = rotl31(h*m1) * m2 + h = bits.RotateLeft64(h*m1, 31) * m2 default: v1 := h v2 := uint64(seed * hashkey[1]) @@ -262,16 +262,16 @@ tail: v4 := uint64(seed * hashkey[3]) for s >= 32 { v1 ^= readUnaligned64(p) - v1 = rotl31(v1*m1) * m2 + v1 = bits.RotateLeft64(v1*m1, 31) * m2 p = unsafe.Add(p, 8) v2 ^= readUnaligned64(p) - v2 = rotl31(v2*m2) * m3 + v2 = bits.RotateLeft64(v2*m2, 31) * m3 p = unsafe.Add(p, 8) v3 ^= readUnaligned64(p) - v3 = rotl31(v3*m3) * m4 + v3 = bits.RotateLeft64(v3*m3, 31) * m4 p = unsafe.Add(p, 8) v4 ^= readUnaligned64(p) - v4 = rotl31(v4*m4) * m1 + v4 = bits.RotateLeft64(v4*m4, 31) * m1 p = unsafe.Add(p, 8) s -= 32 } @@ -290,10 +290,6 @@ func readUnaligned32(p unsafe.Pointer) uint32 { return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24 } -func rotl31(x uint64) uint64 { - return (x << 31) | (x >> (64 - 31)) -} - func readUnaligned64(p unsafe.Pointer) uint64 { q := (*[8]byte)(p) return uint64(q[0]) | uint64(q[1])<<8 | uint64(q[2])<<16 | uint64(q[3])<<24 | uint64(q[4])<<32 | uint64(q[5])<<40 | uint64(q[6])<<48 | uint64(q[7])<<56 diff --git a/component/geodata/strmatcher/strmatcher.go b/component/geodata/strmatcher/strmatcher.go index 294e6e73..6bdb8b97 100644 --- a/component/geodata/strmatcher/strmatcher.go +++ b/component/geodata/strmatcher/strmatcher.go @@ -58,50 +58,3 @@ type matcherEntry struct { m Matcher id uint32 } - -// MatcherGroup is an implementation of IndexMatcher. -// Empty initialization works. -type MatcherGroup struct { - count uint32 - fullMatcher FullMatcherGroup - domainMatcher DomainMatcherGroup - otherMatchers []matcherEntry -} - -// Add adds a new Matcher into the MatcherGroup, and returns its index. The index will never be 0. -func (g *MatcherGroup) Add(m Matcher) uint32 { - g.count++ - c := g.count - - switch tm := m.(type) { - case fullMatcher: - g.fullMatcher.addMatcher(tm, c) - case domainMatcher: - g.domainMatcher.addMatcher(tm, c) - default: - g.otherMatchers = append(g.otherMatchers, matcherEntry{ - m: m, - id: c, - }) - } - - return c -} - -// Match implements IndexMatcher.Match. -func (g *MatcherGroup) Match(pattern string) []uint32 { - result := []uint32{} - result = append(result, g.fullMatcher.Match(pattern)...) - result = append(result, g.domainMatcher.Match(pattern)...) - for _, e := range g.otherMatchers { - if e.m.Match(pattern) { - result = append(result, e.id) - } - } - return result -} - -// Size returns the number of matchers in the MatcherGroup. -func (g *MatcherGroup) Size() uint32 { - return g.count -} diff --git a/component/geodata/utils.go b/component/geodata/utils.go index 33c12e68..a4002aeb 100644 --- a/component/geodata/utils.go +++ b/component/geodata/utils.go @@ -33,12 +33,11 @@ func SetLoader(newLoader string) { func SetSiteMatcher(newMatcher string) { switch newMatcher { - case "hybrid": - newMatcher = "mph" + case "mph", "hybrid": + geoSiteMatcher = "mph" default: - newMatcher = "succinct" + geoSiteMatcher = "succinct" } - geoSiteMatcher = newMatcher } func Verify(name string) error { From 997663a4adadba154f3b1d5afc823890cd31009e Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 23 Dec 2023 13:10:29 +0800 Subject: [PATCH 182/192] chore: avoid return nil. fix #930 --- adapter/adapter.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 695033b7..da6171f1 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -76,11 +76,10 @@ func (p *Proxy) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // DelayHistory implements C.Proxy func (p *Proxy) DelayHistory() []C.DelayHistory { queueM := p.history.Copy() - var histories []C.DelayHistory + histories := []C.DelayHistory{} for _, item := range queueM { histories = append(histories, item) } - return histories } @@ -91,8 +90,7 @@ func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory { if state, ok := p.extra.Load(url); ok { queueM = state.history.Copy() } - - var histories []C.DelayHistory + histories := []C.DelayHistory{} for _, item := range queueM { histories = append(histories, item) } From 4cea3125e6fbc3b6abcb95b7920862160ed51198 Mon Sep 17 00:00:00 2001 From: PuerNya Date: Sun, 24 Dec 2023 22:22:18 +0800 Subject: [PATCH 183/192] Revert `8cf14bb6` and `9d8c3b0a` --- tunnel/tunnel.go | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 71772e71..391fe7c1 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -328,6 +328,15 @@ func handleUDPConn(packet C.PacketAdapter) { sniffer.Dispatcher.UDPSniff(packet) } + // local resolve UDP dns + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(context.Background(), metadata.Host) + if err != nil { + return + } + metadata.DstIP = ip + } + key := packet.LocalAddr().String() handle := func() bool { @@ -342,30 +351,16 @@ func handleUDPConn(packet C.PacketAdapter) { return false } + if handle() { + packet.Drop() + return + } + + cond, loaded := natTable.GetOrCreateLock(key) + go func() { defer packet.Drop() - proxy, rule, err := resolveMetadata(metadata) - if err != nil { - log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) - return - } - - // local resolve UDP dns - if !metadata.Resolved() && proxy.Type() != C.Reject && proxy.Type() != C.RejectDrop { - ip, err := resolver.ResolveIP(context.Background(), metadata.Host) - if err != nil { - return - } - metadata.DstIP = ip - } - - if handle() { - return - } - - cond, loaded := natTable.GetOrCreateLock(key) - if loaded { cond.L.Lock() cond.Wait() @@ -379,6 +374,12 @@ func handleUDPConn(packet C.PacketAdapter) { cond.Broadcast() }() + proxy, rule, err := resolveMetadata(metadata) + if err != nil { + log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) + return + } + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultUDPTimeout) defer cancel() rawPc, err := retry(ctx, func(ctx context.Context) (C.PacketConn, error) { From 41a05d96a58dd511cd7d0eefe53379b88eceaa1a Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Tue, 26 Dec 2023 01:45:32 +0800 Subject: [PATCH 184/192] chore: add some fields for `override` --- adapter/provider/parser.go | 3 +++ adapter/provider/provider.go | 9 +++++++++ docs/config.yaml | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index a22492d2..90d7482c 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -32,6 +32,9 @@ type OverrideSchema struct { Down *string `provider:"down,omitempty"` DialerProxy *string `provider:"dialer-proxy,omitempty"` SkipCertVerify *bool `provider:"skip-cert-verify,omitempty"` + Interface *string `provider:"interface-name,omitempty"` + RoutingMark *int `provider:"routing-mark,omitempty"` + IPVersion *string `provider:"ip-version,omitempty"` } type proxyProviderSchema struct { diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 81ec6c63..a2db06fc 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -393,6 +393,15 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray if override.SkipCertVerify != nil { mapping["skip-cert-verify"] = *override.SkipCertVerify } + if override.Interface != nil { + mapping["interface-name"] = *override.Interface + } + if override.RoutingMark != nil { + mapping["routing-mark"] = *override.RoutingMark + } + if override.IPVersion != nil { + mapping["ip-version"] = *override.IPVersion + } proxy, err := adapter.ParseProxy(mapping) if err != nil { diff --git a/docs/config.yaml b/docs/config.yaml index 702ff831..1d195c35 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -855,6 +855,15 @@ proxy-providers: interval: 600 # lazy: true url: https://cp.cloudflare.com/generate_204 + override: # 覆写节点加载时的一些配置项 + skip-cert-verify: true + udp: true + # down: "50 Mbps" + # up: "10 Mbps" + # dialer-proxy: proxy + # interface-name: tailscale0 + # routing-mark: 233 + # ip-version: ipv4-prefer test: type: file path: /test.yaml From 0d07cf40b8440dc9715ee6b58c5f06848a7d4b02 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Tue, 26 Dec 2023 03:49:00 +0800 Subject: [PATCH 185/192] fix: try fixing automatic policy --- adapter/outboundgroup/fallback.go | 1 + adapter/outboundgroup/urltest.go | 1 + hub/route/groups.go | 10 ++++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 50427e53..488c2d34 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -89,6 +89,7 @@ func (f *Fallback) MarshalJSON() ([]byte, error) { "all": all, "testUrl": f.testUrl, "expectedStatus": f.expectedStatus, + "fixed": f.selected, }) } diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 29d749f9..8dcf674c 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -170,6 +170,7 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { "all": all, "testUrl": u.testUrl, "expectedStatus": u.expectedStatus, + "fixed": u.selected, }) } diff --git a/hub/route/groups.go b/hub/route/groups.go index e36b8ab0..18aabf74 100644 --- a/hub/route/groups.go +++ b/hub/route/groups.go @@ -2,15 +2,17 @@ package route import ( "context" - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" "net/http" "strconv" "time" + "github.com/go-chi/chi/v5" + "github.com/go-chi/render" + "github.com/metacubex/mihomo/adapter" "github.com/metacubex/mihomo/adapter/outboundgroup" "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/profile/cachefile" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/tunnel" ) @@ -63,6 +65,10 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) { URLTestGroup.ForceSet("") } + if proxy.(*adapter.Proxy).Type() != C.Selector { + cachefile.Cache().SetSelected(proxy.Name(), "") + } + query := r.URL.Query() url := query.Get("url") timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 32) From 1701e4715d319a9b684391c5aafd93ce5b52618e Mon Sep 17 00:00:00 2001 From: PuerNya Date: Wed, 27 Dec 2023 09:02:02 +0800 Subject: [PATCH 186/192] fix: stop using insert url when get urltest delay --- adapter/outboundgroup/urltest.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 8dcf674c..2f9456fa 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -4,12 +4,15 @@ import ( "context" "encoding/json" "errors" + "fmt" + "sync" "time" "github.com/metacubex/mihomo/adapter/outbound" "github.com/metacubex/mihomo/common/callback" N "github.com/metacubex/mihomo/common/net" "github.com/metacubex/mihomo/common/singledo" + "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/dialer" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/provider" @@ -174,6 +177,34 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { }) } +func (u *URLTest) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (map[string]uint16, error) { + var wg sync.WaitGroup + var lock sync.Mutex + mp := map[string]uint16{} + proxies := u.GetProxies(false) + for _, proxy := range proxies { + proxy := proxy + wg.Add(1) + go func() { + delay, err := proxy.URLTest(ctx, u.testUrl, expectedStatus) + if err == nil { + lock.Lock() + mp[proxy.Name()] = delay + lock.Unlock() + } + + wg.Done() + }() + } + wg.Wait() + + if len(mp) == 0 { + return mp, fmt.Errorf("get delay: all proxies timeout") + } else { + return mp, nil + } +} + func parseURLTestOption(config map[string]any) []urlTestOption { opts := []urlTestOption{} From fb1c0aa387e350ad61b7fe62a0230934e390a50c Mon Sep 17 00:00:00 2001 From: PuerNya Date: Wed, 27 Dec 2023 11:58:39 +0800 Subject: [PATCH 187/192] chore: change DefaultTestUrl --- constant/adapters.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/constant/adapters.go b/constant/adapters.go index 6d7acd63..9752de55 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -47,7 +47,7 @@ const ( DefaultDropTime = 12 * DefaultTCPTimeout DefaultUDPTimeout = DefaultTCPTimeout DefaultTLSTimeout = DefaultTCPTimeout - DefaultTestURL = "https://cp.cloudflare.com/generate_204" + DefaultTestURL = "https://www.gstatic.com/generate_204" ) var ErrNotSupport = errors.New("no support") From 2e87c6f4daa4acffe697162a0c6daae4d5e5f000 Mon Sep 17 00:00:00 2001 From: PuerNya Date: Wed, 27 Dec 2023 16:20:40 +0800 Subject: [PATCH 188/192] chore: add a new cors response header --- hub/route/server.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/hub/route/server.go b/hub/route/server.go index a3a387c9..8e7f225f 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -63,6 +63,7 @@ func Start(addr string, tlsAddr string, secret string, AllowedHeaders: []string{"Content-Type", "Authorization"}, MaxAge: 300, }) + r.Use(setPrivateNetworkAccess) r.Use(corsM.Handler) if isDebug { r.Mount("/debug", func() http.Handler { @@ -149,6 +150,15 @@ func Start(addr string, tlsAddr string, secret string, } +func setPrivateNetworkAccess(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodOptions && r.Header.Get("Access-Control-Request-Method") != "" { + w.Header().Add("Access-Control-Allow-Private-Network", "true") + } + next.ServeHTTP(w, r) + }) +} + func safeEuqal(a, b string) bool { aBuf := utils.ImmutableBytesFromString(a) bBuf := utils.ImmutableBytesFromString(b) From 22862f20cce0e72d682ff85258ae8809972cddf0 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sun, 31 Dec 2023 03:22:01 +0800 Subject: [PATCH 189/192] chore: update docs --- docs/config.yaml | 72 +++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 1d195c35..2a44a993 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -112,25 +112,25 @@ tun: # gso: false # 启用通用分段卸载, 仅支持 Linux # gso-max-size: 65536 # 通用分段卸载包的最大大小 # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 - inet4-route-address: # 启用 auto_route 时使用自定义路由而不是默认路由 + inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 - 0.0.0.0/1 - 128.0.0.0/1 - inet6-route-address: # 启用 auto_route 时使用自定义路由而不是默认路由 + inet6-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 - "::/1" - "8000::/1" # endpoint-independent-nat: false # 启用独立于端点的 NAT - # include_interface: # 限制被路由的接口。默认不限制, 与 `exclude_interface` 冲突 + # include-interface: # 限制被路由的接口。默认不限制, 与 `exclude-interface` 冲突 # - "lan0" - # exclude_interface: # 排除路由的接口, 与 `include_interface` 冲突 + # exclude-interface: # 排除路由的接口, 与 `include-interface` 冲突 # - "lan1" - # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route + # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto-route # - 0 # include-uid-range: # 限制被路由的的用户范围 - # - 1000-99999 + # - 1000:9999 # exclude-uid: # 排除路由的的用户 #- 1000 # exclude-uid-range: # 排除路由的的用户范围 - # - 1000-99999 + # - 1000:9999 # Android 用户和应用规则仅在 Android 下被支持 # 并且需要 auto-route @@ -651,9 +651,8 @@ proxies: # socks5 type: hysteria server: server.com port: 443 - # ports: 1000,2000-3000,5000 # port 不可省略, - auth_str: yourpassword # 将会在未来某个时候删除 - # auth-str: yourpassword + # ports: 1000,2000-3000,5000 # port 不可省略 + auth-str: yourpassword # obfs: obfs_str # alpn: # - h3 @@ -662,14 +661,11 @@ proxies: # socks5 down: "200 Mbps" # 若不写单位,默认为 Mbps # sni: server.com # skip-cert-verify: false - # recv_window_conn: 12582912 # 将会在未来某个时候删除 # recv-window-conn: 12582912 - # recv_window: 52428800 # 将会在未来某个时候删除 # recv-window: 52428800 # ca: "./my.ca" - # ca_str: "xyz" # 将会在未来某个时候删除 # ca-str: "xyz" - # disable_mtu_discovery: false + # disable-mtu-discovery: false # fingerprint: xxxx # fast-open: true # 支持 TCP 快速打开,默认为 false @@ -710,7 +706,7 @@ proxies: # socks5 # dialer-proxy: "ss1" # remote-dns-resolve: true # 强制dns远程解析,默认值为false # dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在remote-dns-resolve为true时生效 - # 如果peers不为空,该段落中的allowed_ips不可为空;前面段落的server,port,ip,ipv6,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定 + # 如果peers不为空,该段落中的allowed-ips不可为空;前面段落的server,port,ip,ipv6,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定 # peers: # - server: 162.159.192.1 # port: 2480 @@ -718,7 +714,7 @@ proxies: # socks5 # ipv6: fd01:5ca1:ab1e:80fa:ab85:6eea:213f:f4a5 # public-key: Cr8hWlKvtDt7nrvf+f0brNQQzabAqrjfBvas9pmowjo= # # pre-shared-key: 31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM= - # allowed_ips: ['0.0.0.0/0'] + # allowed-ips: ['0.0.0.0/0'] # reserved: [209,98,59] # tuic @@ -1014,42 +1010,42 @@ listeners: type: tun # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - stack: system # gvisor / lwip + stack: system # gvisor / mixed dns-hijack: - - 0.0.0.0:53 # 需要劫持的 DNS + - 0.0.0.0:53 # 需要劫持的 DNS # auto-detect-interface: false # 自动识别出口网卡 # auto-route: false # 配置路由表 # mtu: 9000 # 最大传输单元 inet4-address: # 必须手动设置ipv4地址段 - - 198.19.0.1/30 + - 198.19.0.1/30 inet6-address: # 必须手动设置ipv6地址段 - - "fdfe:dcba:9877::1/126" - # strict_route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 - # inet4_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 - # - 0.0.0.0/1 - # - 128.0.0.0/1 - # inet6_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 - # - "::/1" - # - "8000::/1" - # endpoint_independent_nat: false # 启用独立于端点的 NAT - # include_uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route + - "fdfe:dcba:9877::1/126" + # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 + # inet4-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 + # - 0.0.0.0/1 + # - 128.0.0.0/1 + # inet6-route-address: # 启用 auto-route 时使用自定义路由而不是默认路由 + # - "::/1" + # - "8000::/1" + # endpoint-independent-nat: false # 启用独立于端点的 NAT + # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto-route # - 0 - # include_uid_range: # 限制被路由的的用户范围 - # - 1000-99999 - # exclude_uid: # 排除路由的的用户 + # include-uid-range: # 限制被路由的的用户范围 + # - 1000:99999 + # exclude-uid: # 排除路由的的用户 # - 1000 - # exclude_uid_range: # 排除路由的的用户范围 - # - 1000-99999 + # exclude-uid-range: # 排除路由的的用户范围 + # - 1000:99999 # Android 用户和应用规则仅在 Android 下被支持 - # 并且需要 auto_route + # 并且需要 auto-route - # include_android_user: # 限制被路由的 Android 用户 + # include-android-user: # 限制被路由的 Android 用户 # - 0 # - 10 - # include_package: # 限制被路由的 Android 应用包名 + # include-package: # 限制被路由的 Android 应用包名 # - com.android.chrome - # exclude_package: # 排除被路由的 Android 应用包名 + # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin # 入口配置与 Listener 等价,传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理 # shadowsocks,vmess 入口配置(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) From 3d643cb95a32e0cef69c4411af9655fa0ee6851a Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sun, 31 Dec 2023 07:39:17 +0800 Subject: [PATCH 190/192] chore: modify default url --- adapter/outboundgroup/parser.go | 10 +++++----- adapter/provider/healthcheck.go | 5 ++--- adapter/provider/parser.go | 3 +++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index ea1b51e1..c23147d7 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -82,6 +82,11 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide groupOption.ExpectedStatus = status testUrl := groupOption.URL + if groupOption.URL == "" { + groupOption.URL = C.DefaultTestURL + testUrl = groupOption.URL + } + if len(groupOption.Proxies) != 0 { ps, err := getProxies(proxyMap, groupOption.Proxies) if err != nil { @@ -94,11 +99,6 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide // select don't need health check if groupOption.Type != "select" && groupOption.Type != "relay" { - if groupOption.URL == "" { - groupOption.URL = C.DefaultTestURL - testUrl = groupOption.URL - } - if groupOption.Interval == 0 { groupOption.Interval = 300 } diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index d8e56192..12e1df42 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -213,9 +213,8 @@ func (hc *HealthCheck) close() { } func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, expectedStatus utils.IntRanges[uint16]) *HealthCheck { - if len(url) == 0 { - interval = 0 - expectedStatus = nil + if url == "" { + // expectedStatus = nil url = C.DefaultTestURL } diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 90d7482c..c78a9d39 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -70,6 +70,9 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide var hcInterval uint if schema.HealthCheck.Enable { + if schema.HealthCheck.Interval == 0 { + schema.HealthCheck.Interval = 300 + } hcInterval = uint(schema.HealthCheck.Interval) } hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, hcInterval, schema.HealthCheck.Lazy, expectedStatus) From 1d3e9f4889a7f5e6a62888452835c7a9cfe5b327 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sun, 31 Dec 2023 09:43:52 +0800 Subject: [PATCH 191/192] feat: add `include-all` to proxy-groups --- adapter/outboundgroup/parser.go | 26 +++++++++++++++++--------- adapter/provider/provider.go | 3 --- config/config.go | 6 +++++- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index c23147d7..3f7f9770 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -34,10 +34,12 @@ type GroupCommonOption struct { ExcludeFilter string `group:"exclude-filter,omitempty"` ExcludeType string `group:"exclude-type,omitempty"` ExpectedStatus string `group:"expected-status,omitempty"` + IncludeAll bool `group:"include-all,omitempty"` + IncludeAllProxies bool `group:"include-all-proxies,omitempty"` IncludeAllProviders bool `group:"include-all-providers,omitempty"` } -func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) { +func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider, AllProxies []string, AllProviders []string) (C.ProxyAdapter, error) { decoder := structure.NewDecoder(structure.Option{TagName: "group", WeaklyTypedInput: true}) groupOption := &GroupCommonOption{ @@ -55,18 +57,24 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide providers := []types.ProxyProvider{} + if groupOption.IncludeAll { + groupOption.IncludeAllProviders = true + groupOption.IncludeAllProxies = true + } var GroupUse []string - visited := make(map[string]bool) + var GroupProxies []string if groupOption.IncludeAllProviders { - for name := range provider.ProxyProviderName { - GroupUse = append(GroupUse, name) - visited[name] = true - } + GroupUse = append(GroupUse, AllProviders...) } else { GroupUse = groupOption.Use } + if groupOption.IncludeAllProxies { + GroupProxies = append(groupOption.Proxies, AllProxies...) + } else { + GroupProxies = groupOption.Proxies + } - if len(groupOption.Proxies) == 0 && len(GroupUse) == 0 { + if len(GroupProxies) == 0 && len(GroupUse) == 0 { return nil, fmt.Errorf("%s: %w", groupName, errMissProxy) } @@ -87,8 +95,8 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide testUrl = groupOption.URL } - if len(groupOption.Proxies) != 0 { - ps, err := getProxies(proxyMap, groupOption.Proxies) + if len(GroupProxies) != 0 { + ps, err := getProxies(proxyMap, GroupProxies) if err != nil { return nil, fmt.Errorf("%s: %w", groupName, err) } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index a2db06fc..d710d3a4 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -24,8 +24,6 @@ import ( "gopkg.in/yaml.v3" ) -var ProxyProviderName = make(map[string]struct{}) - const ( ReservedName = "default" ) @@ -201,7 +199,6 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy, override), proxiesOnUpdate(pd)) pd.Fetcher = fetcher - ProxyProviderName[name] = struct{}{} wrapper := &ProxySetProvider{pd} runtime.SetFinalizer(wrapper, stopProxyProvider) return wrapper, nil diff --git a/config/config.go b/config/config.go index 9eaf5a49..bb503b49 100644 --- a/config/config.go +++ b/config/config.go @@ -695,6 +695,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[ providersConfig := cfg.ProxyProvider var proxyList []string + var AllProxies []string proxiesList := list.New() groupsList := list.New() @@ -717,6 +718,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[ } proxies[proxy.Name()] = proxy proxyList = append(proxyList, proxy.Name()) + AllProxies = append(AllProxies, proxy.Name()) proxiesList.PushBack(mapping) } @@ -735,6 +737,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[ return nil, nil, err } + var AllProviders []string // parse and initial providers for name, mapping := range providersConfig { if name == provider.ReservedName { @@ -747,11 +750,12 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[ } providersMap[name] = pd + AllProviders = append(AllProviders, name) } // parse proxy group for idx, mapping := range groupsConfig { - group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap) + group, err := outboundgroup.ParseProxyGroup(mapping, proxies, providersMap, AllProxies, AllProviders) if err != nil { return nil, nil, fmt.Errorf("proxy group[%d]: %w", idx, err) } From 4ee267ca7e7c475381cee226ead9b75b54762ea2 Mon Sep 17 00:00:00 2001 From: hunshcn Date: Tue, 2 Jan 2024 13:45:40 +0800 Subject: [PATCH 192/192] fix: add backgroundRead for plain http inbound (#952) https://github.com/golang/go/blob/go1.21.5/src/net/http/server.go#L682 --- listener/http/proxy.go | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 45f53d6b..4822eabc 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -1,10 +1,14 @@ package http import ( + "context" "fmt" + "io" "net" "net/http" "strings" + "sync" + _ "unsafe" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/common/lru" @@ -14,9 +18,18 @@ import ( "github.com/metacubex/mihomo/log" ) +//go:linkname registerOnHitEOF net/http.registerOnHitEOF +func registerOnHitEOF(rc io.ReadCloser, fn func()) + +//go:linkname requestBodyRemains net/http.requestBodyRemains +func requestBodyRemains(rc io.ReadCloser) bool + func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) { client := newClient(c, tunnel, additions...) defer client.CloseIdleConnections() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + peekMutex := sync.Mutex{} conn := N.NewBufferedConn(c) @@ -24,7 +37,9 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], trusted := cache == nil // disable authenticate if lru is nil for keepAlive { + peekMutex.Lock() request, err := ReadRequest(conn.Reader()) + peekMutex.Unlock() if err != nil { break } @@ -72,6 +87,23 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], if request.URL.Scheme == "" || request.URL.Host == "" { resp = responseWith(request, http.StatusBadRequest) } else { + request = request.WithContext(ctx) + + startBackgroundRead := func() { + go func() { + peekMutex.Lock() + defer peekMutex.Unlock() + _, err := conn.Peek(1) + if err != nil { + cancel() + } + }() + } + if requestBodyRemains(request.Body) { + registerOnHitEOF(request.Body, startBackgroundRead) + } else { + startBackgroundRead() + } resp, err = client.Do(request) if err != nil { resp = responseWith(request, http.StatusBadGateway)