Merge branch 'Alpha' into Meta
This commit is contained in:
commit
880cc90e10
96 changed files with 2635 additions and 1017 deletions
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
|
@ -126,7 +126,7 @@ jobs:
|
|||
shell: bash
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v3
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.20"
|
||||
check-latest: true
|
||||
|
@ -223,7 +223,7 @@ jobs:
|
|||
working-directory: bin
|
||||
|
||||
- name: Delete current release assets
|
||||
uses: andreaswilli/delete-release-assets-action@v2.0.0
|
||||
uses: 8Mi-Tech/delete-release-assets-action@main
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag: Prerelease-${{ github.ref_name }}
|
||||
|
@ -246,18 +246,14 @@ jobs:
|
|||
Release created at ${{ env.BUILDTIME }}
|
||||
Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version
|
||||
<br>
|
||||
### release version
|
||||
`default(not specified in file name)`: compiled with GOAMD64=v3
|
||||
`cgo`: support lwip tun stack, compiled with GOAMD64=v1
|
||||
`compatible`: compiled with GOAMD64=v1
|
||||
Check details between different architectural levels [here](https://github.com/golang/go/wiki/MinimumRequirements#amd64).
|
||||
[我应该下载哪个文件? / Which file should I download?](https://github.com/MetaCubeX/Clash.Meta/wiki/FAQ)
|
||||
[查看文档 / Docs](https://metacubex.github.io/Meta-Docs/)
|
||||
EOF
|
||||
|
||||
- name: Upload Prerelease
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: ${{ success() }}
|
||||
with:
|
||||
tag: ${{ github.ref_name }}
|
||||
tag_name: Prerelease-${{ github.ref_name }}
|
||||
files: |
|
||||
bin/*
|
||||
|
@ -284,7 +280,6 @@ jobs:
|
|||
uses: softprops/action-gh-release@v1
|
||||
if: ${{ success() }}
|
||||
with:
|
||||
tag: ${{ github.ref_name }}
|
||||
tag_name: ${{ github.ref_name }}
|
||||
files: bin/*
|
||||
generate_release_notes: true
|
||||
|
@ -309,10 +304,10 @@ jobs:
|
|||
working-directory: bin
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Setup Docker buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
version: latest
|
||||
|
||||
|
@ -320,7 +315,7 @@ jobs:
|
|||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v3
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_ACCOUNT }}/${{secrets.DOCKERHUB_REPO}}
|
||||
- name: Show files
|
||||
|
@ -329,7 +324,7 @@ jobs:
|
|||
ls bin/
|
||||
- name: Log into registry
|
||||
if: github.event_name != 'pull_request'
|
||||
uses: docker/login-action@v1
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
|
@ -339,7 +334,7 @@ jobs:
|
|||
# https://github.com/docker/build-push-action
|
||||
- name: Build and push Docker image
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
|
|
|
@ -16,6 +16,12 @@ func WithInName(name string) Addition {
|
|||
}
|
||||
}
|
||||
|
||||
func WithInUser(user string) Addition {
|
||||
return func(metadata *C.Metadata) {
|
||||
metadata.InUser = user
|
||||
}
|
||||
}
|
||||
|
||||
func WithSpecialRules(specialRules string) Addition {
|
||||
return func(metadata *C.Metadata) {
|
||||
metadata.SpecialRules = specialRules
|
||||
|
|
|
@ -30,21 +30,18 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad
|
|||
return context.NewConnContext(conn, metadata)
|
||||
}
|
||||
|
||||
func NewInner(conn net.Conn, dst string, host string) *context.ConnContext {
|
||||
func NewInner(conn net.Conn, address string) *context.ConnContext {
|
||||
metadata := &C.Metadata{}
|
||||
metadata.NetWork = C.TCP
|
||||
metadata.Type = C.INNER
|
||||
metadata.DNSMode = C.DNSNormal
|
||||
metadata.Host = host
|
||||
metadata.Process = C.ClashName
|
||||
if h, port, err := net.SplitHostPort(dst); err == nil {
|
||||
if h, port, err := net.SplitHostPort(address); err == nil {
|
||||
metadata.DstPort = port
|
||||
if host == "" {
|
||||
if ip, err := netip.ParseAddr(h); err == nil {
|
||||
metadata.DstIP = ip
|
||||
} else {
|
||||
metadata.Host = h
|
||||
}
|
||||
if ip, err := netip.ParseAddr(h); err == nil {
|
||||
metadata.DstIP = ip
|
||||
} else {
|
||||
metadata.Host = h
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ func (b *Base) Type() C.AdapterType {
|
|||
return b.tp
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (b *Base) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
return c, C.ErrNotSupport
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
|
|||
}
|
||||
|
||||
type packetConn struct {
|
||||
net.PacketConn
|
||||
N.EnhancePacketConn
|
||||
chain C.Chain
|
||||
adapterName string
|
||||
connID string
|
||||
|
@ -242,15 +242,28 @@ func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
|
|||
}
|
||||
|
||||
func (c *packetConn) LocalAddr() net.Addr {
|
||||
lAddr := c.PacketConn.LocalAddr()
|
||||
lAddr := c.EnhancePacketConn.LocalAddr()
|
||||
return N.NewCustomAddr(c.adapterName, c.connID, lAddr) // make quic-go's connMultiplexer happy
|
||||
}
|
||||
|
||||
func (c *packetConn) Upstream() any {
|
||||
return c.EnhancePacketConn
|
||||
}
|
||||
|
||||
func (c *packetConn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *packetConn) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
|
||||
epc := N.NewEnhancePacketConn(pc)
|
||||
if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn
|
||||
pc = N.NewDeadlinePacketConn(pc) // most conn from outbound can't handle readDeadline correctly
|
||||
epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly
|
||||
}
|
||||
return &packetConn{pc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())}
|
||||
return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())}
|
||||
}
|
||||
|
||||
func parseRemoteDestination(addr string) string {
|
||||
|
|
|
@ -3,8 +3,6 @@ package outbound
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
@ -39,11 +37,7 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newPacketConn(&directPacketConn{pc}, d), nil
|
||||
}
|
||||
|
||||
type directPacketConn struct {
|
||||
net.PacketConn
|
||||
return newPacketConn(pc, d), nil
|
||||
}
|
||||
|
||||
func NewDirect() *Direct {
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
|
@ -41,12 +40,10 @@ type HttpOption struct {
|
|||
Headers map[string]string `proxy:"headers,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (h *Http) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (h *Http) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
if h.tlsConfig != nil {
|
||||
cc := tls.Client(c, h.tlsConfig)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
err := cc.HandshakeContext(ctx)
|
||||
c = cc
|
||||
if err != nil {
|
||||
|
@ -83,7 +80,7 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = h.StreamConn(c, metadata)
|
||||
c, err = h.StreamConnContext(ctx, c, metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -98,34 +95,36 @@ func (h *Http) SupportWithDialer() C.NetWork {
|
|||
|
||||
func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error {
|
||||
addr := metadata.RemoteAddress()
|
||||
req := &http.Request{
|
||||
Method: http.MethodConnect,
|
||||
URL: &url.URL{
|
||||
Host: addr,
|
||||
},
|
||||
Host: addr,
|
||||
Header: http.Header{
|
||||
"Proxy-Connection": []string{"Keep-Alive"},
|
||||
},
|
||||
HeaderString := "CONNECT " + addr + " HTTP/1.1\r\n"
|
||||
tempHeaders := map[string]string{
|
||||
"Host": addr,
|
||||
"User-Agent": "Go-http-client/1.1",
|
||||
"Proxy-Connection": "Keep-Alive",
|
||||
}
|
||||
|
||||
//增加headers
|
||||
if len(h.option.Headers) != 0 {
|
||||
for key, value := range h.option.Headers {
|
||||
req.Header.Add(key, value)
|
||||
}
|
||||
for key, value := range h.option.Headers {
|
||||
tempHeaders[key] = value
|
||||
}
|
||||
|
||||
if h.user != "" && h.pass != "" {
|
||||
auth := h.user + ":" + h.pass
|
||||
req.Header.Add("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
|
||||
tempHeaders["Proxy-Authorization"] = "Basic " + base64.StdEncoding.EncodeToString([]byte(auth))
|
||||
}
|
||||
|
||||
if err := req.Write(rw); err != nil {
|
||||
for key, value := range tempHeaders {
|
||||
HeaderString += key + ": " + value + "\r\n"
|
||||
}
|
||||
|
||||
HeaderString += "\r\n"
|
||||
|
||||
_, err := rw.Write([]byte(HeaderString))
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
resp, err := http.ReadResponse(bufio.NewReader(rw), req)
|
||||
resp, err := http.ReadResponse(bufio.NewReader(rw), nil)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -318,6 +318,16 @@ func (c *hyPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func (c *hyPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
b, addrStr, err := c.UDPConn.ReadFrom()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data = b
|
||||
addr = M.ParseSocksaddr(addrStr).UDPAddr()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
err = c.UDPConn.WriteTo(p, M.SocksaddrFromNet(addr).String())
|
||||
if err != nil {
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/structure"
|
||||
|
@ -17,13 +16,10 @@ import (
|
|||
"github.com/Dreamacro/clash/transport/restls"
|
||||
obfs "github.com/Dreamacro/clash/transport/simple-obfs"
|
||||
shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls"
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
|
||||
|
||||
restlsC "github.com/3andne/restls-client-go"
|
||||
shadowsocks "github.com/metacubex/sing-shadowsocks"
|
||||
"github.com/metacubex/sing-shadowsocks/shadowimpl"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"github.com/metacubex/sing-shadowsocks2"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
"github.com/sagernet/sing/common/uot"
|
||||
)
|
||||
|
@ -87,14 +83,7 @@ type restlsOption struct {
|
|||
RestlsScript string `obfs:"restls-script,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// fix tls handshake not timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
return ss.StreamConnContext(ctx, c, metadata)
|
||||
}
|
||||
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
useEarly := false
|
||||
switch ss.obfsMode {
|
||||
|
@ -105,7 +94,7 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada
|
|||
c = obfs.NewHTTPObfs(c, ss.obfsOption.Host, port)
|
||||
case "websocket":
|
||||
var err error
|
||||
c, err = v2rayObfs.NewV2rayObfs(c, ss.v2rayOption)
|
||||
c, err = v2rayObfs.NewV2rayObfs(ctx, c, ss.v2rayOption)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
|
||||
}
|
||||
|
@ -196,7 +185,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pc = ss.method.DialPacketConn(bufio.NewBindPacketConn(pc, addr))
|
||||
pc = ss.method.DialPacketConn(N.NewBindPacketConn(pc, addr))
|
||||
return newPacketConn(pc, ss), nil
|
||||
}
|
||||
|
||||
|
@ -234,7 +223,9 @@ func (ss *ShadowSocks) SupportUOT() bool {
|
|||
|
||||
func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
||||
addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
|
||||
method, err := shadowimpl.FetchMethod(option.Cipher, option.Password, time.Now)
|
||||
method, err := shadowsocks.CreateMethod(context.Background(), option.Cipher, shadowsocks.MethodOptions{
|
||||
Password: option.Password,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("ss %s initialize error: %w", addr, err)
|
||||
}
|
||||
|
@ -312,7 +303,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||
switch option.UDPOverTCPVersion {
|
||||
case uot.Version, uot.LegacyVersion:
|
||||
case 0:
|
||||
option.UDPOverTCPVersion = uot.Version
|
||||
option.UDPOverTCPVersion = uot.LegacyVersion
|
||||
default:
|
||||
return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion)
|
||||
}
|
||||
|
@ -338,36 +329,3 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {
|
|||
restlsConfig: restlsConfig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ssPacketConn struct {
|
||||
net.PacketConn
|
||||
rAddr net.Addr
|
||||
}
|
||||
|
||||
func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return spc.PacketConn.WriteTo(packet[3:], spc.rAddr)
|
||||
}
|
||||
|
||||
func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, _, e := spc.PacketConn.ReadFrom(b)
|
||||
if e != nil {
|
||||
return 0, nil, e
|
||||
}
|
||||
|
||||
addr := socks5.SplitAddr(b[:n])
|
||||
if addr == nil {
|
||||
return 0, nil, errors.New("parse addr error")
|
||||
}
|
||||
|
||||
udpAddr := addr.UDPAddr()
|
||||
if udpAddr == nil {
|
||||
return 0, nil, errors.New("parse addr error")
|
||||
}
|
||||
|
||||
copy(b, b[len(addr):])
|
||||
return n - len(addr), udpAddr, e
|
||||
}
|
||||
|
|
|
@ -2,16 +2,19 @@ package outbound
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"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"
|
||||
)
|
||||
|
@ -38,8 +41,8 @@ type ShadowSocksROption struct {
|
|||
UDP bool `proxy:"udp,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (ssr *ShadowSocksR) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (ssr *ShadowSocksR) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
c = ssr.obfs.StreamConn(c)
|
||||
c = ssr.cipher.StreamConn(c)
|
||||
var (
|
||||
|
@ -83,7 +86,7 @@ func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dia
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = ssr.StreamConn(c, metadata)
|
||||
c, err = ssr.StreamConnContext(ctx, c, metadata)
|
||||
return NewConn(c, ssr), err
|
||||
}
|
||||
|
||||
|
@ -110,9 +113,9 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pc = ssr.cipher.PacketConn(pc)
|
||||
pc = ssr.protocol.PacketConn(pc)
|
||||
return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ssr), nil
|
||||
epc := ssr.cipher.PacketConn(N.NewEnhancePacketConn(pc))
|
||||
epc = ssr.protocol.PacketConn(epc)
|
||||
return newPacketConn(&ssrPacketConn{EnhancePacketConn: epc, rAddr: addr}, ssr), nil
|
||||
}
|
||||
|
||||
// SupportWithDialer implements C.ProxyAdapter
|
||||
|
@ -188,3 +191,62 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) {
|
|||
protocol: protocol,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ssrPacketConn struct {
|
||||
N.EnhancePacketConn
|
||||
rAddr net.Addr
|
||||
}
|
||||
|
||||
func (spc *ssrPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return spc.EnhancePacketConn.WriteTo(packet[3:], spc.rAddr)
|
||||
}
|
||||
|
||||
func (spc *ssrPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, _, e := spc.EnhancePacketConn.ReadFrom(b)
|
||||
if e != nil {
|
||||
return 0, nil, e
|
||||
}
|
||||
|
||||
addr := socks5.SplitAddr(b[:n])
|
||||
if addr == nil {
|
||||
return 0, nil, errors.New("parse addr error")
|
||||
}
|
||||
|
||||
udpAddr := addr.UDPAddr()
|
||||
if udpAddr == nil {
|
||||
return 0, nil, errors.New("parse addr error")
|
||||
}
|
||||
|
||||
copy(b, b[len(addr):])
|
||||
return n - len(addr), udpAddr, e
|
||||
}
|
||||
|
||||
func (spc *ssrPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
data, put, _, err = spc.EnhancePacketConn.WaitReadFrom()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
_addr := socks5.SplitAddr(data)
|
||||
if _addr == nil {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
return nil, nil, nil, errors.New("parse addr error")
|
||||
}
|
||||
|
||||
addr = _addr.UDPAddr()
|
||||
if addr == nil {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
return nil, nil, nil, errors.New("parse addr error")
|
||||
}
|
||||
|
||||
data = data[len(_addr):]
|
||||
return
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
|
|||
if pc == nil {
|
||||
return nil, E.New("packetConn is nil")
|
||||
}
|
||||
return newPacketConn(CN.NewRefPacketConn(pc, s), s.ProxyAdapter), nil
|
||||
return newPacketConn(CN.NewRefPacketConn(CN.NewThreadSafePacketConn(pc), s), s.ProxyAdapter), nil
|
||||
}
|
||||
|
||||
func (s *SingMux) SupportUDP() bool {
|
||||
|
|
|
@ -52,8 +52,8 @@ func streamConn(c net.Conn, option streamOption) *snell.Snell {
|
|||
return snell.StreamConn(c, option.psk, option.version)
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (s *Snell) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})
|
||||
if metadata.NetWork == C.UDP {
|
||||
err := snell.WriteUDPHeader(c, s.version)
|
||||
|
@ -101,7 +101,7 @@ func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = s.StreamConn(c, metadata)
|
||||
c, err = s.StreamConnContext(ctx, c, metadata)
|
||||
return NewConn(c, s), err
|
||||
}
|
||||
|
||||
|
|
|
@ -39,12 +39,10 @@ type Socks5Option struct {
|
|||
Fingerprint string `proxy:"fingerprint,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (ss *Socks5) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (ss *Socks5) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
if ss.tls {
|
||||
cc := tls.Client(c, ss.tlsConfig)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
err := cc.HandshakeContext(ctx)
|
||||
c = cc
|
||||
if err != nil {
|
||||
|
@ -88,7 +86,7 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = ss.StreamConn(c, metadata)
|
||||
c, err = ss.StreamConnContext(ctx, c, metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ type TrojanOption struct {
|
|||
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
|
||||
}
|
||||
|
||||
func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) {
|
||||
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{
|
||||
|
@ -71,14 +71,14 @@ func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) {
|
|||
wsOpts.Headers = header
|
||||
}
|
||||
|
||||
return t.instance.StreamWebsocketConn(c, wsOpts)
|
||||
return t.instance.StreamWebsocketConn(ctx, c, wsOpts)
|
||||
}
|
||||
|
||||
return t.instance.StreamConn(c)
|
||||
return t.instance.StreamConn(ctx, c)
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
var err error
|
||||
|
||||
if tlsC.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 {
|
||||
|
@ -88,7 +88,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error)
|
|||
if t.transport != nil {
|
||||
c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig, t.realityConfig)
|
||||
} else {
|
||||
c, err = t.plainStream(c)
|
||||
c, err = t.plainStream(ctx, c)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -151,7 +151,7 @@ func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, met
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = t.StreamConn(c, metadata)
|
||||
c, err = t.StreamConnContext(ctx, c, metadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
tcpKeepAlive(c)
|
||||
c, err = t.plainStream(c)
|
||||
c, err = t.plainStream(ctx, c)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/Dreamacro/clash/common/convert"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/component/dialer"
|
||||
"github.com/Dreamacro/clash/component/proxydialer"
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
|
@ -74,7 +75,7 @@ type VlessOption struct {
|
|||
ClientFingerprint string `proxy:"client-fingerprint,omitempty"`
|
||||
}
|
||||
|
||||
func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
var err error
|
||||
|
||||
if tlsC.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 {
|
||||
|
@ -128,10 +129,10 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
convert.SetUserAgent(wsOpts.Headers)
|
||||
}
|
||||
}
|
||||
c, err = vmess.StreamWebsocketConn(c, wsOpts)
|
||||
c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts)
|
||||
case "http":
|
||||
// readability first, so just copy default TLS logic
|
||||
c, err = v.streamTLSOrXTLSConn(c, false)
|
||||
c, err = v.streamTLSOrXTLSConn(ctx, c, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -146,7 +147,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
|
||||
c = vmess.StreamHTTPConn(c, httpOpts)
|
||||
case "h2":
|
||||
c, err = v.streamTLSOrXTLSConn(c, true)
|
||||
c, err = v.streamTLSOrXTLSConn(ctx, c, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -162,7 +163,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
default:
|
||||
// default tcp network
|
||||
// handle TLS And XTLS
|
||||
c, err = v.streamTLSOrXTLSConn(c, false)
|
||||
c, err = v.streamTLSOrXTLSConn(ctx, c, false)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -200,7 +201,7 @@ func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err
|
|||
return
|
||||
}
|
||||
|
||||
func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) {
|
||||
func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) {
|
||||
host, _, _ := net.SplitHostPort(v.addr)
|
||||
|
||||
if v.isLegacyXTLSEnabled() && !isH2 {
|
||||
|
@ -214,7 +215,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
|
|||
xtlsOpts.Host = v.option.ServerName
|
||||
}
|
||||
|
||||
return vless.StreamXTLSConn(conn, &xtlsOpts)
|
||||
return vless.StreamXTLSConn(ctx, conn, &xtlsOpts)
|
||||
|
||||
} else if v.option.TLS {
|
||||
tlsOpts := vmess.TLSConfig{
|
||||
|
@ -233,7 +234,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error)
|
|||
tlsOpts.Host = v.option.ServerName
|
||||
}
|
||||
|
||||
return vmess.StreamTLSConn(conn, &tlsOpts)
|
||||
return vmess.StreamTLSConn(ctx, conn, &tlsOpts)
|
||||
}
|
||||
|
||||
return conn, nil
|
||||
|
@ -282,7 +283,7 @@ func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = v.StreamConn(c, metadata)
|
||||
c, err = v.StreamConnContext(ctx, c, metadata)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
|
||||
}
|
||||
|
@ -347,7 +348,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = v.StreamConn(c, metadata)
|
||||
c, err = v.StreamConnContext(ctx, c, metadata)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("new vless client error: %v", err)
|
||||
}
|
||||
|
@ -372,15 +373,15 @@ func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada
|
|||
}
|
||||
|
||||
if v.option.XUDP {
|
||||
return newPacketConn(&threadSafePacketConn{
|
||||
PacketConn: vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())),
|
||||
}, v), nil
|
||||
return newPacketConn(N.NewThreadSafePacketConn(
|
||||
vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())),
|
||||
), v), nil
|
||||
} else if v.option.PacketAddr {
|
||||
return newPacketConn(&threadSafePacketConn{
|
||||
PacketConn: packetaddr.NewConn(&vlessPacketConn{
|
||||
return newPacketConn(N.NewThreadSafePacketConn(
|
||||
packetaddr.NewConn(&vlessPacketConn{
|
||||
Conn: c, rAddr: metadata.UDPAddr(),
|
||||
}, M.SocksaddrFromNet(metadata.UDPAddr())),
|
||||
}, v), nil
|
||||
), v), nil
|
||||
}
|
||||
return newPacketConn(&vlessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil
|
||||
}
|
||||
|
@ -595,15 +596,19 @@ func NewVless(option VlessOption) (*Vless, error) {
|
|||
Host: v.option.ServerName,
|
||||
ClientFingerprint: v.option.ClientFingerprint,
|
||||
}
|
||||
tlsConfig := tlsC.GetGlobalTLSConfig(&tls.Config{
|
||||
InsecureSkipVerify: v.option.SkipCertVerify,
|
||||
ServerName: v.option.ServerName,
|
||||
})
|
||||
|
||||
if v.option.ServerName == "" {
|
||||
host, _, _ := net.SplitHostPort(v.addr)
|
||||
tlsConfig.ServerName = host
|
||||
gunConfig.Host = host
|
||||
if option.ServerName == "" {
|
||||
gunConfig.Host = v.addr
|
||||
}
|
||||
var tlsConfig *tls.Config
|
||||
if option.TLS {
|
||||
tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{
|
||||
InsecureSkipVerify: v.option.SkipCertVerify,
|
||||
ServerName: v.option.ServerName,
|
||||
})
|
||||
if option.ServerName == "" {
|
||||
host, _, _ := net.SplitHostPort(v.addr)
|
||||
tlsConfig.ServerName = host
|
||||
}
|
||||
}
|
||||
|
||||
v.gunTLSConfig = tlsConfig
|
||||
|
|
|
@ -89,8 +89,8 @@ type WSOptions struct {
|
|||
EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"`
|
||||
}
|
||||
|
||||
// StreamConn implements C.ProxyAdapter
|
||||
func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
// StreamConnContext implements C.ProxyAdapter
|
||||
func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
var err error
|
||||
|
||||
if tlsC.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) {
|
||||
|
@ -138,7 +138,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
wsOpts.TLSConfig.ServerName = host
|
||||
}
|
||||
}
|
||||
c, err = clashVMess.StreamWebsocketConn(c, wsOpts)
|
||||
c, err = clashVMess.StreamWebsocketConn(ctx, c, wsOpts)
|
||||
case "http":
|
||||
// readability first, so just copy default TLS logic
|
||||
if v.option.TLS {
|
||||
|
@ -153,7 +153,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
if v.option.ServerName != "" {
|
||||
tlsOpts.Host = v.option.ServerName
|
||||
}
|
||||
c, err = clashVMess.StreamTLSConn(c, tlsOpts)
|
||||
c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
tlsOpts.Host = v.option.ServerName
|
||||
}
|
||||
|
||||
c, err = clashVMess.StreamTLSConn(c, &tlsOpts)
|
||||
c, err = clashVMess.StreamTLSConn(ctx, c, &tlsOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -210,7 +210,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
|||
tlsOpts.Host = v.option.ServerName
|
||||
}
|
||||
|
||||
c, err = clashVMess.StreamTLSConn(c, tlsOpts)
|
||||
c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = v.StreamConn(c, metadata)
|
||||
c, err = v.StreamConnContext(ctx, c, metadata)
|
||||
return NewConn(c, v), err
|
||||
}
|
||||
|
||||
|
@ -355,7 +355,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
|
|||
safeConnClose(c, err)
|
||||
}(c)
|
||||
|
||||
c, err = v.StreamConn(c, metadata)
|
||||
c, err = v.StreamConnContext(ctx, c, metadata)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("new vmess client error: %v", err)
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada
|
|||
}
|
||||
|
||||
if pc, ok := c.(net.PacketConn); ok {
|
||||
return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil
|
||||
return newPacketConn(N.NewThreadSafePacketConn(pc), v), nil
|
||||
}
|
||||
return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil
|
||||
}
|
||||
|
@ -413,13 +413,6 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
|||
option.PacketAddr = false
|
||||
}
|
||||
|
||||
switch option.Network {
|
||||
case "h2", "grpc":
|
||||
if !option.TLS {
|
||||
option.TLS = true
|
||||
}
|
||||
}
|
||||
|
||||
v := &Vmess{
|
||||
Base: &Base{
|
||||
name: option.Name,
|
||||
|
@ -464,15 +457,19 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
|||
Host: v.option.ServerName,
|
||||
ClientFingerprint: v.option.ClientFingerprint,
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: v.option.SkipCertVerify,
|
||||
ServerName: v.option.ServerName,
|
||||
if option.ServerName == "" {
|
||||
gunConfig.Host = v.addr
|
||||
}
|
||||
|
||||
if v.option.ServerName == "" {
|
||||
host, _, _ := net.SplitHostPort(v.addr)
|
||||
tlsConfig.ServerName = host
|
||||
gunConfig.Host = host
|
||||
var tlsConfig *tls.Config
|
||||
if option.TLS {
|
||||
tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{
|
||||
InsecureSkipVerify: v.option.SkipCertVerify,
|
||||
ServerName: v.option.ServerName,
|
||||
})
|
||||
if option.ServerName == "" {
|
||||
host, _, _ := net.SplitHostPort(v.addr)
|
||||
tlsConfig.ServerName = host
|
||||
}
|
||||
}
|
||||
|
||||
v.gunTLSConfig = tlsConfig
|
||||
|
@ -489,17 +486,6 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
|||
return v, nil
|
||||
}
|
||||
|
||||
type threadSafePacketConn struct {
|
||||
net.PacketConn
|
||||
access sync.Mutex
|
||||
}
|
||||
|
||||
func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
return c.PacketConn.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
type vmessPacketConn struct {
|
||||
net.Conn
|
||||
rAddr net.Addr
|
||||
|
|
|
@ -67,7 +67,7 @@ type WireGuardPeerOption struct {
|
|||
PublicKey string `proxy:"public-key,omitempty"`
|
||||
PreSharedKey string `proxy:"pre-shared-key,omitempty"`
|
||||
Reserved []uint8 `proxy:"reserved,omitempty"`
|
||||
AllowedIPs []string `proxy:"allowed_ips,omitempty"`
|
||||
AllowedIPs []string `proxy:"allowed-ips,omitempty"`
|
||||
}
|
||||
|
||||
type wgSingDialer struct {
|
||||
|
@ -499,9 +499,9 @@ func (r *refProxyAdapter) MarshalJSON() ([]byte, error) {
|
|||
return nil, C.ErrNotSupport
|
||||
}
|
||||
|
||||
func (r *refProxyAdapter) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
func (r *refProxyAdapter) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) {
|
||||
if r.proxyAdapter != nil {
|
||||
return r.proxyAdapter.StreamConn(c, metadata)
|
||||
return r.proxyAdapter.StreamConnContext(ctx, c, metadata)
|
||||
}
|
||||
return nil, C.ErrNotSupport
|
||||
}
|
||||
|
|
|
@ -130,10 +130,6 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
|
|||
}
|
||||
}
|
||||
|
||||
if len(proxies) == 0 {
|
||||
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
|
||||
}
|
||||
|
||||
if len(gb.providers) > 1 && len(gb.filterRegs) > 1 {
|
||||
var newProxies []C.Proxy
|
||||
proxiesSet := map[string]struct{}{}
|
||||
|
@ -189,6 +185,10 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy {
|
|||
proxies = newProxies
|
||||
}
|
||||
|
||||
if len(proxies) == 0 {
|
||||
return append(proxies, tunnel.Proxies()["COMPATIBLE"])
|
||||
}
|
||||
|
||||
return proxies
|
||||
}
|
||||
|
||||
|
|
|
@ -3,34 +3,43 @@ package net
|
|||
import "net"
|
||||
|
||||
type bindPacketConn struct {
|
||||
net.PacketConn
|
||||
EnhancePacketConn
|
||||
rAddr net.Addr
|
||||
}
|
||||
|
||||
func (wpc *bindPacketConn) Read(b []byte) (n int, err error) {
|
||||
n, _, err = wpc.PacketConn.ReadFrom(b)
|
||||
func (c *bindPacketConn) Read(b []byte) (n int, err error) {
|
||||
n, _, err = c.EnhancePacketConn.ReadFrom(b)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (wpc *bindPacketConn) Write(b []byte) (n int, err error) {
|
||||
return wpc.PacketConn.WriteTo(b, wpc.rAddr)
|
||||
func (c *bindPacketConn) WaitRead() (data []byte, put func(), err error) {
|
||||
data, put, _, err = c.EnhancePacketConn.WaitReadFrom()
|
||||
return
|
||||
}
|
||||
|
||||
func (wpc *bindPacketConn) RemoteAddr() net.Addr {
|
||||
return wpc.rAddr
|
||||
func (c *bindPacketConn) Write(b []byte) (n int, err error) {
|
||||
return c.EnhancePacketConn.WriteTo(b, c.rAddr)
|
||||
}
|
||||
|
||||
func (wpc *bindPacketConn) LocalAddr() net.Addr {
|
||||
if wpc.PacketConn.LocalAddr() == nil {
|
||||
func (c *bindPacketConn) RemoteAddr() net.Addr {
|
||||
return c.rAddr
|
||||
}
|
||||
|
||||
func (c *bindPacketConn) LocalAddr() net.Addr {
|
||||
if c.EnhancePacketConn.LocalAddr() == nil {
|
||||
return &net.UDPAddr{IP: net.IPv4zero, Port: 0}
|
||||
} else {
|
||||
return wpc.PacketConn.LocalAddr()
|
||||
return c.EnhancePacketConn.LocalAddr()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *bindPacketConn) Upstream() any {
|
||||
return c.EnhancePacketConn
|
||||
}
|
||||
|
||||
func NewBindPacketConn(pc net.PacketConn, rAddr net.Addr) net.Conn {
|
||||
return &bindPacketConn{
|
||||
PacketConn: pc,
|
||||
rAddr: rAddr,
|
||||
EnhancePacketConn: NewEnhancePacketConn(pc),
|
||||
rAddr: rAddr,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ func (c *BufferedConn) Buffered() int {
|
|||
}
|
||||
|
||||
func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) {
|
||||
if c.r.Buffered() > 0 {
|
||||
if c.r != nil && c.r.Buffered() > 0 {
|
||||
_, err = buffer.ReadOnceFrom(c.r)
|
||||
return
|
||||
}
|
||||
|
@ -70,10 +70,11 @@ func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) {
|
|||
}
|
||||
|
||||
func (c *BufferedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.Copy
|
||||
if c.r.Buffered() > 0 {
|
||||
if c.r != nil && c.r.Buffered() > 0 {
|
||||
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)
|
||||
}
|
||||
return nil
|
||||
|
@ -84,7 +85,7 @@ func (c *BufferedConn) Upstream() any {
|
|||
}
|
||||
|
||||
func (c *BufferedConn) ReaderReplaceable() bool {
|
||||
if c.r.Buffered() > 0 {
|
||||
if c.r != nil && c.r.Buffered() > 0 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
154
common/net/deadline/packet.go
Normal file
154
common/net/deadline/packet.go
Normal file
|
@ -0,0 +1,154 @@
|
|||
package deadline
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/Dreamacro/clash/common/atomic"
|
||||
"github.com/Dreamacro/clash/common/net/packet"
|
||||
)
|
||||
|
||||
type readResult struct {
|
||||
data []byte
|
||||
addr net.Addr
|
||||
err error
|
||||
}
|
||||
|
||||
type NetPacketConn struct {
|
||||
net.PacketConn
|
||||
deadline atomic.TypedValue[time.Time]
|
||||
pipeDeadline pipeDeadline
|
||||
disablePipe atomic.Bool
|
||||
inRead atomic.Bool
|
||||
resultCh chan any
|
||||
}
|
||||
|
||||
func NewNetPacketConn(pc net.PacketConn) net.PacketConn {
|
||||
npc := &NetPacketConn{
|
||||
PacketConn: pc,
|
||||
pipeDeadline: makePipeDeadline(),
|
||||
resultCh: make(chan any, 1),
|
||||
}
|
||||
npc.resultCh <- nil
|
||||
if enhancePC, isEnhance := pc.(packet.EnhancePacketConn); isEnhance {
|
||||
epc := &EnhancePacketConn{
|
||||
NetPacketConn: npc,
|
||||
enhancePacketConn: enhancePacketConn{
|
||||
netPacketConn: npc,
|
||||
enhancePacketConn: enhancePC,
|
||||
},
|
||||
}
|
||||
if singPC, isSingPC := pc.(packet.SingPacketConn); isSingPC {
|
||||
return &EnhanceSingPacketConn{
|
||||
EnhancePacketConn: epc,
|
||||
singPacketConn: singPacketConn{
|
||||
netPacketConn: npc,
|
||||
singPacketConn: singPC,
|
||||
},
|
||||
}
|
||||
}
|
||||
return epc
|
||||
}
|
||||
if singPC, isSingPC := pc.(packet.SingPacketConn); isSingPC {
|
||||
return &SingPacketConn{
|
||||
NetPacketConn: npc,
|
||||
singPacketConn: singPacketConn{
|
||||
netPacketConn: npc,
|
||||
singPacketConn: singPC,
|
||||
},
|
||||
}
|
||||
}
|
||||
return npc
|
||||
}
|
||||
|
||||
func (c *NetPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
FOR:
|
||||
for {
|
||||
select {
|
||||
case result := <-c.resultCh:
|
||||
if result != nil {
|
||||
if result, ok := result.(*readResult); ok {
|
||||
n = copy(p, result.data)
|
||||
addr = result.addr
|
||||
err = result.err
|
||||
c.resultCh <- nil // finish cache read
|
||||
return
|
||||
}
|
||||
c.resultCh <- result // another type of read
|
||||
runtime.Gosched() // allowing other goroutines to run
|
||||
continue FOR
|
||||
} else {
|
||||
c.resultCh <- nil
|
||||
break FOR
|
||||
}
|
||||
case <-c.pipeDeadline.wait():
|
||||
return 0, nil, os.ErrDeadlineExceeded
|
||||
}
|
||||
}
|
||||
|
||||
if c.disablePipe.Load() {
|
||||
return c.PacketConn.ReadFrom(p)
|
||||
} else if c.deadline.Load().IsZero() {
|
||||
c.inRead.Store(true)
|
||||
defer c.inRead.Store(false)
|
||||
n, addr, err = c.PacketConn.ReadFrom(p)
|
||||
return
|
||||
}
|
||||
|
||||
<-c.resultCh
|
||||
go c.pipeReadFrom(len(p))
|
||||
|
||||
return c.ReadFrom(p)
|
||||
}
|
||||
|
||||
func (c *NetPacketConn) pipeReadFrom(size int) {
|
||||
buffer := make([]byte, size)
|
||||
n, addr, err := c.PacketConn.ReadFrom(buffer)
|
||||
buffer = buffer[:n]
|
||||
result := &readResult{}
|
||||
result.data = buffer
|
||||
result.addr = addr
|
||||
result.err = err
|
||||
c.resultCh <- result
|
||||
}
|
||||
|
||||
func (c *NetPacketConn) SetReadDeadline(t time.Time) error {
|
||||
if c.disablePipe.Load() {
|
||||
return c.PacketConn.SetReadDeadline(t)
|
||||
} else if c.inRead.Load() {
|
||||
c.disablePipe.Store(true)
|
||||
return c.PacketConn.SetReadDeadline(t)
|
||||
}
|
||||
c.deadline.Store(t)
|
||||
c.pipeDeadline.set(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *NetPacketConn) 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 *NetPacketConn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *NetPacketConn) Upstream() any {
|
||||
return c.PacketConn
|
||||
}
|
||||
|
||||
func (c *NetPacketConn) NeedAdditionalReadDeadline() bool {
|
||||
return false
|
||||
}
|
83
common/net/deadline/packet_enhance.go
Normal file
83
common/net/deadline/packet_enhance.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package deadline
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/Dreamacro/clash/common/net/packet"
|
||||
)
|
||||
|
||||
type EnhancePacketConn struct {
|
||||
*NetPacketConn
|
||||
enhancePacketConn
|
||||
}
|
||||
|
||||
var _ packet.EnhancePacketConn = (*EnhancePacketConn)(nil)
|
||||
|
||||
func NewEnhancePacketConn(pc packet.EnhancePacketConn) packet.EnhancePacketConn {
|
||||
return NewNetPacketConn(pc).(packet.EnhancePacketConn)
|
||||
}
|
||||
|
||||
type enhanceReadResult struct {
|
||||
data []byte
|
||||
put func()
|
||||
addr net.Addr
|
||||
err error
|
||||
}
|
||||
|
||||
type enhancePacketConn struct {
|
||||
netPacketConn *NetPacketConn
|
||||
enhancePacketConn packet.EnhancePacketConn
|
||||
}
|
||||
|
||||
func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
FOR:
|
||||
for {
|
||||
select {
|
||||
case result := <-c.netPacketConn.resultCh:
|
||||
if result != nil {
|
||||
if result, ok := result.(*enhanceReadResult); ok {
|
||||
data = result.data
|
||||
put = result.put
|
||||
addr = result.addr
|
||||
err = result.err
|
||||
c.netPacketConn.resultCh <- nil // finish cache read
|
||||
return
|
||||
}
|
||||
c.netPacketConn.resultCh <- result // another type of read
|
||||
runtime.Gosched() // allowing other goroutines to run
|
||||
continue FOR
|
||||
} else {
|
||||
c.netPacketConn.resultCh <- nil
|
||||
break FOR
|
||||
}
|
||||
case <-c.netPacketConn.pipeDeadline.wait():
|
||||
return nil, nil, nil, os.ErrDeadlineExceeded
|
||||
}
|
||||
}
|
||||
|
||||
if c.netPacketConn.disablePipe.Load() {
|
||||
return c.enhancePacketConn.WaitReadFrom()
|
||||
} else if c.netPacketConn.deadline.Load().IsZero() {
|
||||
c.netPacketConn.inRead.Store(true)
|
||||
defer c.netPacketConn.inRead.Store(false)
|
||||
data, put, addr, err = c.enhancePacketConn.WaitReadFrom()
|
||||
return
|
||||
}
|
||||
|
||||
<-c.netPacketConn.resultCh
|
||||
go c.pipeWaitReadFrom()
|
||||
|
||||
return c.WaitReadFrom()
|
||||
}
|
||||
|
||||
func (c *enhancePacketConn) pipeWaitReadFrom() {
|
||||
data, put, addr, err := c.enhancePacketConn.WaitReadFrom()
|
||||
result := &enhanceReadResult{}
|
||||
result.data = data
|
||||
result.put = put
|
||||
result.addr = addr
|
||||
result.err = err
|
||||
c.netPacketConn.resultCh <- result
|
||||
}
|
177
common/net/deadline/packet_sing.go
Normal file
177
common/net/deadline/packet_sing.go
Normal file
|
@ -0,0 +1,177 @@
|
|||
package deadline
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/Dreamacro/clash/common/net/packet"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
type SingPacketConn struct {
|
||||
*NetPacketConn
|
||||
singPacketConn
|
||||
}
|
||||
|
||||
var _ packet.SingPacketConn = (*SingPacketConn)(nil)
|
||||
|
||||
func NewSingPacketConn(pc packet.SingPacketConn) packet.SingPacketConn {
|
||||
return NewNetPacketConn(pc).(packet.SingPacketConn)
|
||||
}
|
||||
|
||||
type EnhanceSingPacketConn struct {
|
||||
*EnhancePacketConn
|
||||
singPacketConn
|
||||
}
|
||||
|
||||
func NewEnhanceSingPacketConn(pc packet.EnhanceSingPacketConn) packet.EnhanceSingPacketConn {
|
||||
return NewNetPacketConn(pc).(packet.EnhanceSingPacketConn)
|
||||
}
|
||||
|
||||
var _ packet.EnhanceSingPacketConn = (*EnhanceSingPacketConn)(nil)
|
||||
|
||||
type singReadResult struct {
|
||||
buffer *buf.Buffer
|
||||
destination M.Socksaddr
|
||||
err error
|
||||
}
|
||||
|
||||
type singPacketConn struct {
|
||||
netPacketConn *NetPacketConn
|
||||
singPacketConn packet.SingPacketConn
|
||||
}
|
||||
|
||||
func (c *singPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
|
||||
FOR:
|
||||
for {
|
||||
select {
|
||||
case result := <-c.netPacketConn.resultCh:
|
||||
if result != nil {
|
||||
if result, ok := result.(*singReadResult); ok {
|
||||
destination = result.destination
|
||||
err = result.err
|
||||
n, _ := buffer.Write(result.buffer.Bytes())
|
||||
result.buffer.Advance(n)
|
||||
if result.buffer.IsEmpty() {
|
||||
result.buffer.Release()
|
||||
}
|
||||
c.netPacketConn.resultCh <- nil // finish cache read
|
||||
return
|
||||
}
|
||||
c.netPacketConn.resultCh <- result // another type of read
|
||||
runtime.Gosched() // allowing other goroutines to run
|
||||
continue FOR
|
||||
} else {
|
||||
c.netPacketConn.resultCh <- nil
|
||||
break FOR
|
||||
}
|
||||
case <-c.netPacketConn.pipeDeadline.wait():
|
||||
return M.Socksaddr{}, os.ErrDeadlineExceeded
|
||||
}
|
||||
}
|
||||
|
||||
if c.netPacketConn.disablePipe.Load() {
|
||||
return c.singPacketConn.ReadPacket(buffer)
|
||||
} else if c.netPacketConn.deadline.Load().IsZero() {
|
||||
c.netPacketConn.inRead.Store(true)
|
||||
defer c.netPacketConn.inRead.Store(false)
|
||||
destination, err = c.singPacketConn.ReadPacket(buffer)
|
||||
return
|
||||
}
|
||||
|
||||
<-c.netPacketConn.resultCh
|
||||
go c.pipeReadPacket(buffer.FreeLen())
|
||||
|
||||
return c.ReadPacket(buffer)
|
||||
}
|
||||
|
||||
func (c *singPacketConn) pipeReadPacket(pLen int) {
|
||||
buffer := buf.NewSize(pLen)
|
||||
destination, err := c.singPacketConn.ReadPacket(buffer)
|
||||
result := &singReadResult{}
|
||||
result.destination = destination
|
||||
result.err = err
|
||||
c.netPacketConn.resultCh <- result
|
||||
}
|
||||
|
||||
func (c *singPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||
return c.singPacketConn.WritePacket(buffer, destination)
|
||||
}
|
||||
|
||||
func (c *singPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) {
|
||||
prw, isReadWaiter := bufio.CreatePacketReadWaiter(c.singPacketConn)
|
||||
if isReadWaiter {
|
||||
return &singPacketReadWaiter{
|
||||
netPacketConn: c.netPacketConn,
|
||||
packetReadWaiter: prw,
|
||||
}, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
var _ N.PacketReadWaiter = (*singPacketReadWaiter)(nil)
|
||||
|
||||
type singPacketReadWaiter struct {
|
||||
netPacketConn *NetPacketConn
|
||||
packetReadWaiter N.PacketReadWaiter
|
||||
}
|
||||
|
||||
type singWaitReadResult singReadResult
|
||||
|
||||
func (c *singPacketReadWaiter) InitializeReadWaiter(newBuffer func() *buf.Buffer) {
|
||||
c.packetReadWaiter.InitializeReadWaiter(newBuffer)
|
||||
}
|
||||
|
||||
func (c *singPacketReadWaiter) WaitReadPacket() (destination M.Socksaddr, err error) {
|
||||
FOR:
|
||||
for {
|
||||
select {
|
||||
case result := <-c.netPacketConn.resultCh:
|
||||
if result != nil {
|
||||
if result, ok := result.(*singWaitReadResult); ok {
|
||||
destination = result.destination
|
||||
err = result.err
|
||||
c.netPacketConn.resultCh <- nil // finish cache read
|
||||
return
|
||||
}
|
||||
c.netPacketConn.resultCh <- result // another type of read
|
||||
runtime.Gosched() // allowing other goroutines to run
|
||||
continue FOR
|
||||
} else {
|
||||
c.netPacketConn.resultCh <- nil
|
||||
break FOR
|
||||
}
|
||||
case <-c.netPacketConn.pipeDeadline.wait():
|
||||
return M.Socksaddr{}, os.ErrDeadlineExceeded
|
||||
}
|
||||
}
|
||||
|
||||
if c.netPacketConn.disablePipe.Load() {
|
||||
return c.packetReadWaiter.WaitReadPacket()
|
||||
} else if c.netPacketConn.deadline.Load().IsZero() {
|
||||
c.netPacketConn.inRead.Store(true)
|
||||
defer c.netPacketConn.inRead.Store(false)
|
||||
destination, err = c.packetReadWaiter.WaitReadPacket()
|
||||
return
|
||||
}
|
||||
|
||||
<-c.netPacketConn.resultCh
|
||||
go c.pipeWaitReadPacket()
|
||||
|
||||
return c.WaitReadPacket()
|
||||
}
|
||||
|
||||
func (c *singPacketReadWaiter) pipeWaitReadPacket() {
|
||||
destination, err := c.packetReadWaiter.WaitReadPacket()
|
||||
result := &singWaitReadResult{}
|
||||
result.destination = destination
|
||||
result.err = err
|
||||
c.netPacketConn.resultCh <- result
|
||||
}
|
||||
|
||||
func (c *singPacketReadWaiter) Upstream() any {
|
||||
return c.packetReadWaiter
|
||||
}
|
84
common/net/deadline/pipe.go
Normal file
84
common/net/deadline/pipe.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2010 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 deadline
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// pipeDeadline is an abstraction for handling timeouts.
|
||||
type pipeDeadline struct {
|
||||
mu sync.Mutex // Guards timer and cancel
|
||||
timer *time.Timer
|
||||
cancel chan struct{} // Must be non-nil
|
||||
}
|
||||
|
||||
func makePipeDeadline() pipeDeadline {
|
||||
return pipeDeadline{cancel: make(chan struct{})}
|
||||
}
|
||||
|
||||
// set sets the point in time when the deadline will time out.
|
||||
// A timeout event is signaled by closing the channel returned by waiter.
|
||||
// Once a timeout has occurred, the deadline can be refreshed by specifying a
|
||||
// t value in the future.
|
||||
//
|
||||
// A zero value for t prevents timeout.
|
||||
func (d *pipeDeadline) set(t time.Time) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
if d.timer != nil && !d.timer.Stop() {
|
||||
<-d.cancel // Wait for the timer callback to finish and close cancel
|
||||
}
|
||||
d.timer = nil
|
||||
|
||||
// Time is zero, then there is no deadline.
|
||||
closed := isClosedChan(d.cancel)
|
||||
if t.IsZero() {
|
||||
if closed {
|
||||
d.cancel = make(chan struct{})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Time in the future, setup a timer to cancel in the future.
|
||||
if dur := time.Until(t); dur > 0 {
|
||||
if closed {
|
||||
d.cancel = make(chan struct{})
|
||||
}
|
||||
d.timer = time.AfterFunc(dur, func() {
|
||||
close(d.cancel)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Time in the past, so close immediately.
|
||||
if !closed {
|
||||
close(d.cancel)
|
||||
}
|
||||
}
|
||||
|
||||
// wait returns a channel that is closed when the deadline is exceeded.
|
||||
func (d *pipeDeadline) wait() chan struct{} {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
return d.cancel
|
||||
}
|
||||
|
||||
func isClosedChan(c <-chan struct{}) bool {
|
||||
select {
|
||||
case <-c:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func makeFilledChan() chan struct{} {
|
||||
ch := make(chan struct{}, 1)
|
||||
ch <- struct{}{}
|
||||
return ch
|
||||
}
|
18
common/net/packet.go
Normal file
18
common/net/packet.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"github.com/Dreamacro/clash/common/net/deadline"
|
||||
"github.com/Dreamacro/clash/common/net/packet"
|
||||
)
|
||||
|
||||
type EnhancePacketConn = packet.EnhancePacketConn
|
||||
type WaitReadFrom = packet.WaitReadFrom
|
||||
|
||||
var NewEnhancePacketConn = packet.NewEnhancePacketConn
|
||||
var NewThreadSafePacketConn = packet.NewThreadSafePacketConn
|
||||
var NewRefPacketConn = packet.NewRefPacketConn
|
||||
|
||||
var NewDeadlineNetPacketConn = deadline.NewNetPacketConn
|
||||
var NewDeadlineEnhancePacketConn = deadline.NewEnhancePacketConn
|
||||
var NewDeadlineSingPacketConn = deadline.NewSingPacketConn
|
||||
var NewDeadlineEnhanceSingPacketConn = deadline.NewEnhanceSingPacketConn
|
77
common/net/packet/packet.go
Normal file
77
common/net/packet/packet.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
type WaitReadFrom interface {
|
||||
WaitReadFrom() (data []byte, put func(), addr net.Addr, err error)
|
||||
}
|
||||
|
||||
type EnhancePacketConn interface {
|
||||
net.PacketConn
|
||||
WaitReadFrom
|
||||
}
|
||||
|
||||
func NewEnhancePacketConn(pc net.PacketConn) EnhancePacketConn {
|
||||
if udpConn, isUDPConn := pc.(*net.UDPConn); isUDPConn {
|
||||
return &enhanceUDPConn{UDPConn: udpConn}
|
||||
}
|
||||
if enhancePC, isEnhancePC := pc.(EnhancePacketConn); isEnhancePC {
|
||||
return enhancePC
|
||||
}
|
||||
if singPC, isSingPC := pc.(SingPacketConn); isSingPC {
|
||||
return newEnhanceSingPacketConn(singPC)
|
||||
}
|
||||
return &enhancePacketConn{PacketConn: pc}
|
||||
}
|
||||
|
||||
type enhancePacketConn struct {
|
||||
net.PacketConn
|
||||
}
|
||||
|
||||
func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
return waitReadFrom(c.PacketConn)
|
||||
}
|
||||
|
||||
func (c *enhancePacketConn) Upstream() any {
|
||||
return c.PacketConn
|
||||
}
|
||||
|
||||
func (c *enhancePacketConn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *enhancePacketConn) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *enhanceUDPConn) Upstream() any {
|
||||
return c.UDPConn
|
||||
}
|
||||
|
||||
func (c *enhanceUDPConn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *enhanceUDPConn) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func waitReadFrom(pc net.PacketConn) (data []byte, put func(), addr net.Addr, err error) {
|
||||
readBuf := pool.Get(pool.UDPBufferSize)
|
||||
put = func() {
|
||||
_ = pool.Put(readBuf)
|
||||
}
|
||||
var readN int
|
||||
readN, addr, err = pc.ReadFrom(readBuf)
|
||||
if readN > 0 {
|
||||
data = readBuf[:readN]
|
||||
} else {
|
||||
put()
|
||||
put = nil
|
||||
}
|
||||
return
|
||||
}
|
65
common/net/packet/packet_posix.go
Normal file
65
common/net/packet/packet_posix.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
//go:build !windows
|
||||
|
||||
package packet
|
||||
|
||||
import (
|
||||
"net"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
type enhanceUDPConn struct {
|
||||
*net.UDPConn
|
||||
rawConn syscall.RawConn
|
||||
}
|
||||
|
||||
func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
if c.rawConn == nil {
|
||||
c.rawConn, _ = c.UDPConn.SyscallConn()
|
||||
}
|
||||
var readErr error
|
||||
err = c.rawConn.Read(func(fd uintptr) (done bool) {
|
||||
readBuf := pool.Get(pool.UDPBufferSize)
|
||||
put = func() {
|
||||
_ = pool.Put(readBuf)
|
||||
}
|
||||
var readFrom syscall.Sockaddr
|
||||
var readN int
|
||||
readN, _, _, readFrom, readErr = syscall.Recvmsg(int(fd), readBuf, nil, 0)
|
||||
if readN > 0 {
|
||||
data = readBuf[:readN]
|
||||
} else {
|
||||
put()
|
||||
put = nil
|
||||
data = nil
|
||||
}
|
||||
if readErr == syscall.EAGAIN {
|
||||
return false
|
||||
}
|
||||
if readFrom != nil {
|
||||
switch from := readFrom.(type) {
|
||||
case *syscall.SockaddrInet4:
|
||||
ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes
|
||||
addr = &net.UDPAddr{IP: ip[:], Port: from.Port}
|
||||
case *syscall.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
|
||||
//}
|
||||
return true
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if readErr != nil {
|
||||
err = readErr
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
79
common/net/packet/packet_sing.go
Normal file
79
common/net/packet/packet_sing.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
type SingPacketConn = N.NetPacketConn
|
||||
|
||||
type EnhanceSingPacketConn interface {
|
||||
SingPacketConn
|
||||
EnhancePacketConn
|
||||
}
|
||||
|
||||
type enhanceSingPacketConn struct {
|
||||
SingPacketConn
|
||||
packetReadWaiter N.PacketReadWaiter
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
if c.packetReadWaiter != nil {
|
||||
c.packetReadWaiter.InitializeReadWaiter(newBuffer)
|
||||
defer c.packetReadWaiter.InitializeReadWaiter(nil)
|
||||
dest, err = c.packetReadWaiter.WaitReadPacket()
|
||||
} else {
|
||||
dest, err = c.SingPacketConn.ReadPacket(newBuffer())
|
||||
}
|
||||
if dest.IsFqdn() {
|
||||
addr = dest
|
||||
} else {
|
||||
addr = dest.UDPAddr()
|
||||
}
|
||||
if err != nil {
|
||||
if buff != nil {
|
||||
buff.Release()
|
||||
}
|
||||
return
|
||||
}
|
||||
if buff == nil {
|
||||
return
|
||||
}
|
||||
if buff.IsEmpty() {
|
||||
buff.Release()
|
||||
return
|
||||
}
|
||||
data = buff.Bytes()
|
||||
put = buff.Release
|
||||
return
|
||||
}
|
||||
|
||||
func (c *enhanceSingPacketConn) Upstream() any {
|
||||
return c.SingPacketConn
|
||||
}
|
||||
|
||||
func (c *enhanceSingPacketConn) WriterReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *enhanceSingPacketConn) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func newEnhanceSingPacketConn(conn SingPacketConn) *enhanceSingPacketConn {
|
||||
epc := &enhanceSingPacketConn{SingPacketConn: conn}
|
||||
if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn); isReadWaiter {
|
||||
epc.packetReadWaiter = readWaiter
|
||||
}
|
||||
return epc
|
||||
}
|
15
common/net/packet/packet_windows.go
Normal file
15
common/net/packet/packet_windows.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
//go:build windows
|
||||
|
||||
package packet
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
type enhanceUDPConn struct {
|
||||
*net.UDPConn
|
||||
}
|
||||
|
||||
func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
return waitReadFrom(c.UDPConn)
|
||||
}
|
75
common/net/packet/ref.go
Normal file
75
common/net/packet/ref.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"net"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
type refPacketConn struct {
|
||||
pc EnhancePacketConn
|
||||
ref any
|
||||
}
|
||||
|
||||
func (c *refPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.WaitReadFrom()
|
||||
}
|
||||
|
||||
func (c *refPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.ReadFrom(p)
|
||||
}
|
||||
|
||||
func (c *refPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (c *refPacketConn) Close() error {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.Close()
|
||||
}
|
||||
|
||||
func (c *refPacketConn) LocalAddr() net.Addr {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.LocalAddr()
|
||||
}
|
||||
|
||||
func (c *refPacketConn) SetDeadline(t time.Time) error {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (c *refPacketConn) SetReadDeadline(t time.Time) error {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (c *refPacketConn) SetWriteDeadline(t time.Time) error {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.pc.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func (c *refPacketConn) Upstream() any {
|
||||
return c.pc
|
||||
}
|
||||
|
||||
func (c *refPacketConn) ReaderReplaceable() bool { // Relay() will handle reference
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *refPacketConn) WriterReplaceable() bool { // Relay() will handle reference
|
||||
return true
|
||||
}
|
||||
|
||||
func NewRefPacketConn(pc net.PacketConn, ref any) EnhancePacketConn {
|
||||
rPC := &refPacketConn{pc: NewEnhancePacketConn(pc), ref: ref}
|
||||
if singPC, isSingPC := pc.(SingPacketConn); isSingPC {
|
||||
return &refSingPacketConn{
|
||||
refPacketConn: rPC,
|
||||
singPacketConn: singPC,
|
||||
}
|
||||
}
|
||||
return rPC
|
||||
}
|
26
common/net/packet/ref_sing.go
Normal file
26
common/net/packet/ref_sing.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
type refSingPacketConn struct {
|
||||
*refPacketConn
|
||||
singPacketConn SingPacketConn
|
||||
}
|
||||
|
||||
var _ N.NetPacketConn = (*refSingPacketConn)(nil)
|
||||
|
||||
func (c *refSingPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.singPacketConn.WritePacket(buffer, destination)
|
||||
}
|
||||
|
||||
func (c *refSingPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
|
||||
defer runtime.KeepAlive(c.ref)
|
||||
return c.singPacketConn.ReadPacket(buffer)
|
||||
}
|
36
common/net/packet/thread.go
Normal file
36
common/net/packet/thread.go
Normal file
|
@ -0,0 +1,36 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"net"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type threadSafePacketConn struct {
|
||||
EnhancePacketConn
|
||||
access sync.Mutex
|
||||
}
|
||||
|
||||
func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
return c.EnhancePacketConn.WriteTo(b, addr)
|
||||
}
|
||||
|
||||
func (c *threadSafePacketConn) Upstream() any {
|
||||
return c.EnhancePacketConn
|
||||
}
|
||||
|
||||
func (c *threadSafePacketConn) ReaderReplaceable() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func NewThreadSafePacketConn(pc net.PacketConn) EnhancePacketConn {
|
||||
tsPC := &threadSafePacketConn{EnhancePacketConn: NewEnhancePacketConn(pc)}
|
||||
if singPC, isSingPC := pc.(SingPacketConn); isSingPC {
|
||||
return &threadSafeSingPacketConn{
|
||||
threadSafePacketConn: tsPC,
|
||||
singPacketConn: singPC,
|
||||
}
|
||||
}
|
||||
return tsPC
|
||||
}
|
24
common/net/packet/thread_sing.go
Normal file
24
common/net/packet/thread_sing.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package packet
|
||||
|
||||
import (
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
type threadSafeSingPacketConn struct {
|
||||
*threadSafePacketConn
|
||||
singPacketConn SingPacketConn
|
||||
}
|
||||
|
||||
var _ N.NetPacketConn = (*threadSafeSingPacketConn)(nil)
|
||||
|
||||
func (c *threadSafeSingPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||
c.access.Lock()
|
||||
defer c.access.Unlock()
|
||||
return c.singPacketConn.WritePacket(buffer, destination)
|
||||
}
|
||||
|
||||
func (c *threadSafeSingPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) {
|
||||
return c.singPacketConn.ReadPacket(buffer)
|
||||
}
|
|
@ -80,47 +80,3 @@ var _ ExtendedConn = (*refConn)(nil)
|
|||
func NewRefConn(conn net.Conn, ref any) net.Conn {
|
||||
return &refConn{conn: NewExtendedConn(conn), ref: ref}
|
||||
}
|
||||
|
||||
type refPacketConn struct {
|
||||
pc net.PacketConn
|
||||
ref any
|
||||
}
|
||||
|
||||
func (pc *refPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
|
||||
defer runtime.KeepAlive(pc.ref)
|
||||
return pc.pc.ReadFrom(p)
|
||||
}
|
||||
|
||||
func (pc *refPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
defer runtime.KeepAlive(pc.ref)
|
||||
return pc.pc.WriteTo(p, addr)
|
||||
}
|
||||
|
||||
func (pc *refPacketConn) Close() error {
|
||||
defer runtime.KeepAlive(pc.ref)
|
||||
return pc.pc.Close()
|
||||
}
|
||||
|
||||
func (pc *refPacketConn) LocalAddr() net.Addr {
|
||||
defer runtime.KeepAlive(pc.ref)
|
||||
return pc.pc.LocalAddr()
|
||||
}
|
||||
|
||||
func (pc *refPacketConn) SetDeadline(t time.Time) error {
|
||||
defer runtime.KeepAlive(pc.ref)
|
||||
return pc.pc.SetDeadline(t)
|
||||
}
|
||||
|
||||
func (pc *refPacketConn) SetReadDeadline(t time.Time) error {
|
||||
defer runtime.KeepAlive(pc.ref)
|
||||
return pc.pc.SetReadDeadline(t)
|
||||
}
|
||||
|
||||
func (pc *refPacketConn) SetWriteDeadline(t time.Time) error {
|
||||
defer runtime.KeepAlive(pc.ref)
|
||||
return pc.pc.SetWriteDeadline(t)
|
||||
}
|
||||
|
||||
func NewRefPacketConn(pc net.PacketConn, ref any) net.PacketConn {
|
||||
return &refPacketConn{pc: pc, ref: ref}
|
||||
}
|
||||
|
|
|
@ -23,10 +23,6 @@ func NewDeadlineConn(conn net.Conn) ExtendedConn {
|
|||
return deadline.NewFallbackConn(conn)
|
||||
}
|
||||
|
||||
func NewDeadlinePacketConn(pc net.PacketConn) net.PacketConn {
|
||||
return deadline.NewFallbackPacketConn(bufio.NewPacketConn(pc))
|
||||
}
|
||||
|
||||
func NeedHandshake(conn any) bool {
|
||||
if earlyConn, isEarlyConn := common.Cast[network.EarlyConn](conn); isEarlyConn && earlyConn.NeedHandshake() {
|
||||
return true
|
||||
|
|
|
@ -18,10 +18,11 @@ type tfoConn struct {
|
|||
}
|
||||
|
||||
func (c *tfoConn) Dial(earlyData []byte) (err error) {
|
||||
c.Conn, err = c.dialFn(c.ctx, earlyData)
|
||||
conn, err := c.dialFn(c.ctx, earlyData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c.Conn = conn
|
||||
c.dialed <- true
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -234,26 +234,26 @@ tail:
|
|||
case s == 0:
|
||||
case s < 4:
|
||||
h ^= uint64(*(*byte)(p))
|
||||
h ^= uint64(*(*byte)(add(p, s>>1))) << 8
|
||||
h ^= uint64(*(*byte)(add(p, s-1))) << 16
|
||||
h ^= uint64(*(*byte)(unsafe.Add(p, s>>1))) << 8
|
||||
h ^= uint64(*(*byte)(unsafe.Add(p, s-1))) << 16
|
||||
h = rotl31(h*m1) * m2
|
||||
case s <= 8:
|
||||
h ^= uint64(readUnaligned32(p))
|
||||
h ^= uint64(readUnaligned32(add(p, s-4))) << 32
|
||||
h ^= uint64(readUnaligned32(unsafe.Add(p, s-4))) << 32
|
||||
h = rotl31(h*m1) * m2
|
||||
case s <= 16:
|
||||
h ^= readUnaligned64(p)
|
||||
h = rotl31(h*m1) * m2
|
||||
h ^= readUnaligned64(add(p, s-8))
|
||||
h ^= readUnaligned64(unsafe.Add(p, s-8))
|
||||
h = rotl31(h*m1) * m2
|
||||
case s <= 32:
|
||||
h ^= readUnaligned64(p)
|
||||
h = rotl31(h*m1) * m2
|
||||
h ^= readUnaligned64(add(p, 8))
|
||||
h ^= readUnaligned64(unsafe.Add(p, 8))
|
||||
h = rotl31(h*m1) * m2
|
||||
h ^= readUnaligned64(add(p, s-16))
|
||||
h ^= readUnaligned64(unsafe.Add(p, s-16))
|
||||
h = rotl31(h*m1) * m2
|
||||
h ^= readUnaligned64(add(p, s-8))
|
||||
h ^= readUnaligned64(unsafe.Add(p, s-8))
|
||||
h = rotl31(h*m1) * m2
|
||||
default:
|
||||
v1 := h
|
||||
|
@ -263,16 +263,16 @@ tail:
|
|||
for s >= 32 {
|
||||
v1 ^= readUnaligned64(p)
|
||||
v1 = rotl31(v1*m1) * m2
|
||||
p = add(p, 8)
|
||||
p = unsafe.Add(p, 8)
|
||||
v2 ^= readUnaligned64(p)
|
||||
v2 = rotl31(v2*m2) * m3
|
||||
p = add(p, 8)
|
||||
p = unsafe.Add(p, 8)
|
||||
v3 ^= readUnaligned64(p)
|
||||
v3 = rotl31(v3*m3) * m4
|
||||
p = add(p, 8)
|
||||
p = unsafe.Add(p, 8)
|
||||
v4 ^= readUnaligned64(p)
|
||||
v4 = rotl31(v4*m4) * m1
|
||||
p = add(p, 8)
|
||||
p = unsafe.Add(p, 8)
|
||||
s -= 32
|
||||
}
|
||||
h = v1 ^ v2 ^ v3 ^ v4
|
||||
|
@ -285,10 +285,6 @@ tail:
|
|||
return uintptr(h)
|
||||
}
|
||||
|
||||
func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
|
||||
return unsafe.Pointer(uintptr(p) + x)
|
||||
}
|
||||
|
||||
func readUnaligned32(p unsafe.Pointer) uint32 {
|
||||
q := (*[4]byte)(p)
|
||||
return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24
|
||||
|
|
|
@ -53,8 +53,12 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st
|
|||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
DialContext: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
conn := inner.HandleTcp(address, "")
|
||||
return conn, nil
|
||||
if conn, err := inner.HandleTcp(address); err == nil {
|
||||
return conn, nil
|
||||
} else {
|
||||
d := net.Dialer{}
|
||||
return d.DialContext(ctx, network, address)
|
||||
}
|
||||
},
|
||||
TLSClientConfig: tls.GetDefaultTLSConfig(),
|
||||
}
|
||||
|
|
|
@ -71,7 +71,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(address); err != nil {
|
||||
if err := currentMeta.SetRemoteAddress(rAddrPort.String()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.listenPacket(ctx, currentMeta)
|
||||
|
|
|
@ -33,10 +33,22 @@ func AddCertificate(certificate string) error {
|
|||
}
|
||||
}
|
||||
|
||||
func initializeCertPool() {
|
||||
var err error
|
||||
certPool, err = x509.SystemCertPool()
|
||||
if err != nil {
|
||||
certPool = x509.NewCertPool()
|
||||
}
|
||||
for _, cert := range trustCerts {
|
||||
certPool.AddCert(cert)
|
||||
}
|
||||
}
|
||||
|
||||
func ResetCertificate() {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
trustCerts = nil
|
||||
initializeCertPool()
|
||||
}
|
||||
|
||||
func getCertPool() *x509.CertPool {
|
||||
|
@ -49,12 +61,7 @@ func getCertPool() *x509.CertPool {
|
|||
if certPool != nil {
|
||||
return certPool
|
||||
}
|
||||
certPool, err := x509.SystemCertPool()
|
||||
if err == nil {
|
||||
for _, cert := range trustCerts {
|
||||
certPool.AddCert(cert)
|
||||
}
|
||||
}
|
||||
initializeCertPool()
|
||||
}
|
||||
return certPool
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ var pOffset = utils.MustOK(reflect.TypeOf((*utls.UConn)(nil)).Elem().FieldByName
|
|||
|
||||
func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
//p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates")
|
||||
certs := *(*[]*x509.Certificate)(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + pOffset))
|
||||
certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset))
|
||||
if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok {
|
||||
h := hmac.New(sha512.New, c.authKey)
|
||||
h.Write(pub)
|
||||
|
|
|
@ -841,7 +841,7 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) {
|
|||
} else {
|
||||
ips := make([]netip.Addr, 0)
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback()&&!ipnet.IP.IsLinkLocalUnicast() {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() {
|
||||
if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil {
|
||||
ips = append(ips, ip)
|
||||
}
|
||||
|
@ -938,6 +938,8 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error)
|
|||
case "quic":
|
||||
addr, err = hostWithDefaultPort(u.Host, "853")
|
||||
dnsNetType = "quic" // DNS over QUIC
|
||||
case "system":
|
||||
dnsNetType = "system" // System DNS
|
||||
default:
|
||||
return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme)
|
||||
}
|
||||
|
@ -972,6 +974,10 @@ func parsePureDNSServer(server string) string {
|
|||
return "udp://" + server
|
||||
}
|
||||
|
||||
if server == "system" {
|
||||
return "system://"
|
||||
}
|
||||
|
||||
if ip, err := netip.ParseAddr(server); err != nil {
|
||||
if strings.Contains(server, "://") {
|
||||
return server
|
||||
|
@ -1142,6 +1148,9 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul
|
|||
}
|
||||
// check default nameserver is pure ip addr
|
||||
for _, ns := range dnsCfg.DefaultNameserver {
|
||||
if ns.Net == "system" {
|
||||
continue
|
||||
}
|
||||
host, _, err := net.SplitHostPort(ns.Addr)
|
||||
if err != nil || net.ParseIP(host) == nil {
|
||||
u, err := url.Parse(ns.Addr)
|
||||
|
|
|
@ -81,7 +81,7 @@ type Conn interface {
|
|||
}
|
||||
|
||||
type PacketConn interface {
|
||||
net.PacketConn
|
||||
N.EnhancePacketConn
|
||||
Connection
|
||||
// Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed
|
||||
// WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error)
|
||||
|
@ -106,11 +106,11 @@ type ProxyAdapter interface {
|
|||
//
|
||||
// Examples:
|
||||
// conn, _ := net.DialContext(context.Background(), "tcp", "host:port")
|
||||
// conn, _ = adapter.StreamConn(conn, metadata)
|
||||
// conn, _ = adapter.StreamConnContext(context.Background(), conn, metadata)
|
||||
//
|
||||
// It returns a C.Conn with protocol which start with
|
||||
// a new session (if any)
|
||||
StreamConn(c net.Conn, metadata *Metadata) (net.Conn, error)
|
||||
StreamConnContext(ctx context.Context, c net.Conn, metadata *Metadata) (net.Conn, error)
|
||||
|
||||
// DialContext return a C.Conn with protocol which
|
||||
// contains multiplexing-related reuse logic (if any)
|
||||
|
|
|
@ -133,6 +133,7 @@ type Metadata struct {
|
|||
InIP netip.Addr `json:"inboundIP"`
|
||||
InPort string `json:"inboundPort"`
|
||||
InName string `json:"inboundName"`
|
||||
InUser string `json:"inboundUser"`
|
||||
Host string `json:"host"`
|
||||
DNSMode DNSMode `json:"dnsMode"`
|
||||
Uid uint32 `json:"uid"`
|
||||
|
@ -205,15 +206,16 @@ func (m *Metadata) Pure() *Metadata {
|
|||
return m
|
||||
}
|
||||
|
||||
func (m *Metadata) AddrPort() netip.AddrPort {
|
||||
port, _ := strconv.ParseUint(m.DstPort, 10, 16)
|
||||
return netip.AddrPortFrom(m.DstIP.Unmap(), uint16(port))
|
||||
}
|
||||
|
||||
func (m *Metadata) UDPAddr() *net.UDPAddr {
|
||||
if m.NetWork != UDP || !m.DstIP.IsValid() {
|
||||
return nil
|
||||
}
|
||||
port, _ := strconv.ParseUint(m.DstPort, 10, 16)
|
||||
return &net.UDPAddr{
|
||||
IP: m.DstIP.AsSlice(),
|
||||
Port: int(port),
|
||||
}
|
||||
return net.UDPAddrFromAddrPort(m.AddrPort())
|
||||
}
|
||||
|
||||
func (m *Metadata) String() string {
|
||||
|
|
|
@ -14,12 +14,14 @@ const (
|
|||
SrcPort
|
||||
DstPort
|
||||
InPort
|
||||
InUser
|
||||
InName
|
||||
InType
|
||||
Process
|
||||
ProcessPath
|
||||
RuleSet
|
||||
Network
|
||||
Uid
|
||||
INTYPE
|
||||
SubRules
|
||||
MATCH
|
||||
AND
|
||||
|
@ -55,6 +57,12 @@ func (rt RuleType) String() string {
|
|||
return "DstPort"
|
||||
case InPort:
|
||||
return "InPort"
|
||||
case InUser:
|
||||
return "InUser"
|
||||
case InName:
|
||||
return "InName"
|
||||
case InType:
|
||||
return "InType"
|
||||
case Process:
|
||||
return "Process"
|
||||
case ProcessPath:
|
||||
|
@ -67,8 +75,6 @@ func (rt RuleType) String() string {
|
|||
return "Network"
|
||||
case Uid:
|
||||
return "Uid"
|
||||
case INTYPE:
|
||||
return "InType"
|
||||
case SubRules:
|
||||
return "SubRules"
|
||||
case AND:
|
||||
|
|
23
dns/system.go
Normal file
23
dns/system.go
Normal file
|
@ -0,0 +1,23 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func loadSystemResolver() (clients []dnsClient, err error) {
|
||||
nameservers, err := dnsReadConfig()
|
||||
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
|
||||
}
|
27
dns/system_posix.go
Normal file
27
dns/system_posix.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
//go:build !windows
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
// nameserver xxx.xxx.xxx.xxx
|
||||
nameserverPattern = regexp.MustCompile(`nameserver\s+(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`)
|
||||
)
|
||||
|
||||
func dnsReadConfig() (servers []string, err error) {
|
||||
content, err := os.ReadFile("/etc/resolv.conf")
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed to read /etc/resolv.conf: %w", err)
|
||||
return
|
||||
}
|
||||
for _, line := range nameserverPattern.FindAllStringSubmatch(string(content), -1) {
|
||||
addr := line[1]
|
||||
servers = append(servers, addr)
|
||||
}
|
||||
return
|
||||
}
|
77
dns/system_windows.go
Normal file
77
dns/system_windows.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
//go:build windows
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func dnsReadConfig() (servers []string, err error) {
|
||||
aas, err := adapterAddresses()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, aa := range aas {
|
||||
for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next {
|
||||
sa, err := dns.Address.Sockaddr.Sockaddr()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
var ip net.IP
|
||||
switch sa := sa.(type) {
|
||||
case *syscall.SockaddrInet4:
|
||||
ip = net.IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
|
||||
case *syscall.SockaddrInet6:
|
||||
ip = make(net.IP, net.IPv6len)
|
||||
copy(ip, sa.Addr[:])
|
||||
if ip[0] == 0xfe && ip[1] == 0xc0 {
|
||||
// Ignore these fec0/10 ones. Windows seems to
|
||||
// populate them as defaults on its misc rando
|
||||
// interfaces.
|
||||
continue
|
||||
}
|
||||
//continue
|
||||
default:
|
||||
// Unexpected type.
|
||||
continue
|
||||
}
|
||||
servers = append(servers, ip.String())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// adapterAddresses returns a list of IP adapter and address
|
||||
// structures. The structure contains an IP adapter and flattened
|
||||
// multiple IP addresses including unicast, anycast and multicast
|
||||
// addresses.
|
||||
func adapterAddresses() ([]*windows.IpAdapterAddresses, error) {
|
||||
var b []byte
|
||||
l := uint32(15000) // recommended initial size
|
||||
for {
|
||||
b = make([]byte, l)
|
||||
err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l)
|
||||
if err == nil {
|
||||
if l == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
break
|
||||
}
|
||||
if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
|
||||
return nil, os.NewSyscallError("getadaptersaddresses", err)
|
||||
}
|
||||
if l <= uint32(len(b)) {
|
||||
return nil, os.NewSyscallError("getadaptersaddresses", err)
|
||||
}
|
||||
}
|
||||
var aas []*windows.IpAdapterAddresses
|
||||
for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next {
|
||||
aas = append(aas, aa)
|
||||
}
|
||||
return aas, nil
|
||||
}
|
12
dns/util.go
12
dns/util.go
|
@ -79,6 +79,18 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
|
|||
case "dhcp":
|
||||
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...)
|
||||
continue
|
||||
case "quic":
|
||||
if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil {
|
||||
ret = append(ret, doq)
|
||||
|
|
|
@ -77,32 +77,32 @@ tun:
|
|||
# auto-detect-interface: true # 自动识别出口网卡
|
||||
# auto-route: true # 配置路由表
|
||||
# mtu: 9000 # 最大传输单元
|
||||
# strict_route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问
|
||||
inet4_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由
|
||||
# strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问
|
||||
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_uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route
|
||||
# endpoint-independent-nat: false # 启用独立于端点的 NAT
|
||||
# include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route
|
||||
# - 0
|
||||
# include_uid_range: # 限制被路由的的用户范围
|
||||
# include-uid-range: # 限制被路由的的用户范围
|
||||
# - 1000-99999
|
||||
# exclude_uid: # 排除路由的的用户
|
||||
# exclude-uid: # 排除路由的的用户
|
||||
#- 1000
|
||||
# exclude_uid_range: # 排除路由的的用户范围
|
||||
# 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
|
||||
|
||||
#ebpf配置
|
||||
|
@ -177,6 +177,7 @@ dns:
|
|||
- 8.8.8.8
|
||||
- tls://1.12.12.12:853
|
||||
- tls://223.5.5.5:853
|
||||
- system # append DNS server from system configuration. If not found, it would print an error log and skip.
|
||||
enhanced-mode: fake-ip # or redir-host
|
||||
|
||||
fake-ip-range: 198.18.0.1/16 # fake-ip 池设置
|
||||
|
|
56
go.mod
56
go.mod
|
@ -5,9 +5,9 @@ go 1.19
|
|||
require (
|
||||
github.com/3andne/restls-client-go v0.1.4
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da
|
||||
github.com/cilium/ebpf v0.9.3
|
||||
github.com/cilium/ebpf v0.10.0
|
||||
github.com/coreos/go-iptables v0.6.0
|
||||
github.com/dlclark/regexp2 v1.7.0
|
||||
github.com/dlclark/regexp2 v1.9.0
|
||||
github.com/go-chi/chi/v5 v5.0.8
|
||||
github.com/go-chi/cors v1.2.1
|
||||
github.com/go-chi/render v1.0.2
|
||||
|
@ -17,38 +17,40 @@ require (
|
|||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16
|
||||
github.com/jpillora/backoff v1.0.0
|
||||
github.com/klauspost/cpuid/v2 v2.0.12
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40
|
||||
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba
|
||||
github.com/metacubex/sing-tun v0.1.4
|
||||
github.com/mdlayher/netlink v1.7.2
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c
|
||||
github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca
|
||||
github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a
|
||||
github.com/miekg/dns v1.1.53
|
||||
github.com/mroth/weightedrand/v2 v2.0.0
|
||||
github.com/miekg/dns v1.1.54
|
||||
github.com/mroth/weightedrand/v2 v2.0.1
|
||||
github.com/openacid/low v0.1.21
|
||||
github.com/oschwald/geoip2-golang v1.8.0
|
||||
github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97
|
||||
github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9
|
||||
github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e
|
||||
github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c
|
||||
github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77
|
||||
github.com/samber/lo v1.38.1
|
||||
github.com/shirou/gopsutil/v3 v3.23.3
|
||||
github.com/shirou/gopsutil/v3 v3.23.4
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837
|
||||
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3
|
||||
github.com/zhangyunhao116/fastrand v0.3.0
|
||||
go.etcd.io/bbolt v1.3.6
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
golang.org/x/crypto v0.8.0
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||
golang.org/x/net v0.9.0
|
||||
golang.org/x/sync v0.1.0
|
||||
golang.org/x/sys v0.7.0
|
||||
google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d
|
||||
golang.org/x/crypto v0.9.0
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
|
||||
golang.org/x/net v0.10.0
|
||||
golang.org/x/sync v0.2.0
|
||||
golang.org/x/sys v0.8.0
|
||||
google.golang.org/protobuf v1.30.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
lukechampine.com/blake3 v1.1.7
|
||||
)
|
||||
|
@ -67,17 +69,15 @@ require (
|
|||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/google/btree v1.0.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
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/mdlayher/socket v0.4.0 // indirect
|
||||
github.com/mdlayher/socket v0.4.1 // indirect
|
||||
github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||
|
@ -89,6 +89,7 @@ require (
|
|||
github.com/quic-go/qtls-go1-20 v0.1.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
|
||||
github.com/shoenig/go-m1cpu v0.1.5 // indirect
|
||||
github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect
|
||||
github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect
|
||||
|
@ -96,12 +97,15 @@ require (
|
|||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
github.com/vishvananda/netns v0.0.4 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
)
|
||||
|
||||
replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b
|
||||
|
||||
replace github.com/sagernet/sing-vmess => github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899
|
||||
|
|
120
go.sum
120
go.sum
|
@ -14,15 +14,15 @@ 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.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc=
|
||||
github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A=
|
||||
github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ=
|
||||
github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE=
|
||||
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
||||
github.com/coreos/go-iptables v0.6.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/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo=
|
||||
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI=
|
||||
github.com/dlclark/regexp2 v1.9.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
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=
|
||||
|
@ -32,7 +32,7 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBE
|
|||
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/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
|
||||
|
@ -52,8 +52,8 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev
|
|||
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.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
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=
|
||||
|
@ -82,34 +82,36 @@ github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9
|
|||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
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=
|
||||
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/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 h1:HSkXG1bE/qcRuuPlZ2Jyf0Od8HLxOowi7CzKQqNtWn4=
|
||||
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7/go.mod h1:1ztDZHGbU5MjN5lNZpkpG8ygndjjWzcojp/H7r6l6QQ=
|
||||
github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw=
|
||||
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
|
||||
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=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM=
|
||||
github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE=
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIayTGGgRl6PuVqo2Bpo6+x3LqDDyqrYDDXw=
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba h1:He8YwyK600lHAS1xxNsP4k/jnZ8zqQ34XjCGn925+Yk=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s=
|
||||
github.com/metacubex/sing-tun v0.1.4 h1:OQDBNHjuPKrOprCiK+sLt97YQ0K6b9ZWmJB6z51ibZQ=
|
||||
github.com/metacubex/sing-tun v0.1.4/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc=
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 h1:E/sNW9tugFjoBjAkth89MHlKHRaMdo43tGQ3MOPVayQ=
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA=
|
||||
github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b h1:Bw4j3ktf5vivi5qm/ZQGtyRAgybRKSGJaMV1t3rtC+I=
|
||||
github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:LpVNvlW/xE+mR8z76xJeYZlYznZXEmU4TeWeuygYdJg=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca h1:10qc50Q1hHrfGO4NjEJpIAgHX63Y256tHE0dFCTN8J4=
|
||||
github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak=
|
||||
github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e h1:7QlJQl4S3F3YXn48fYxjymMw8HkXg9bl++hLi4ZRyCY=
|
||||
github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e/go.mod h1:u9onX49LZPYuIPQ7SdM64Gnins8y5wg4Cn6ZYRSxWHU=
|
||||
github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 h1:iRfcuztp7REfmOyasSlCL/pqNWfUDMTJ2CwbGpxpeks=
|
||||
github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899/go.mod h1:RSt9rxGHllLdc5JUebkQwaqyWLx09Lqya37DlBe8CP8=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY=
|
||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo=
|
||||
github.com/mroth/weightedrand/v2 v2.0.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI=
|
||||
github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA=
|
||||
github.com/mroth/weightedrand/v2 v2.0.1/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU=
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4=
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||
|
@ -138,21 +140,15 @@ github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1T
|
|||
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+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=
|
||||
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 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.5-0.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLTKIfBCJGQPm2ww7pNxn566C6TrHdA=
|
||||
github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e h1:t8nuY9plpHEzlnPxOpuv64jhjz3teIvccu3YMFX4fJI=
|
||||
github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI=
|
||||
github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc=
|
||||
github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI=
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4=
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI=
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U=
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U=
|
||||
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/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||
|
@ -163,9 +159,10 @@ github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2d
|
|||
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/shirou/gopsutil/v3 v3.23.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE=
|
||||
github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU=
|
||||
github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ=
|
||||
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.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o=
|
||||
github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8=
|
||||
github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ=
|
||||
github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ=
|
||||
github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c=
|
||||
|
@ -195,10 +192,10 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm
|
|||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
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/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/xtls/go v0.0.0-20220914232946-0441cf4cf837 h1:AHhUwwFJGl27E46OpdJHplZkK09m7aETNBNzhT6t15M=
|
||||
github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY=
|
||||
github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8=
|
||||
github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM=
|
||||
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM=
|
||||
github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
|
@ -206,16 +203,16 @@ 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.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
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.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME=
|
||||
go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
|
||||
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.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
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=
|
||||
|
@ -224,39 +221,35 @@ golang.org/x/mod v0.8.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.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20200923182605-d9f96fdee20d/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.2.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.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||
golang.org/x/sys v0.8.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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
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=
|
||||
|
@ -268,11 +261,10 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T
|
|||
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.28.2-0.20230118093459-a9481185b34d h1:qp0AnQCvRCMlu9jBjtdbTaaEmThIgZOrbVyDEOcmKhQ=
|
||||
google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
|
|
|
@ -30,8 +30,9 @@ func upgrade(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
err = updater.Update(execPath)
|
||||
if err != nil {
|
||||
log.Warnln("%s", err)
|
||||
render.Status(r, http.StatusInternalServerError)
|
||||
render.JSON(w, r, newError(fmt.Sprintf("Upgrade: %s", err)))
|
||||
render.JSON(w, r, newError(fmt.Sprintf("%s", err)))
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -17,15 +18,16 @@ import (
|
|||
clashHttp "github.com/Dreamacro/clash/component/http"
|
||||
"github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/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.
|
||||
var (
|
||||
goarch string
|
||||
goos string
|
||||
goarm string
|
||||
gomips string
|
||||
goarm string
|
||||
gomips string
|
||||
amd64Compatible string
|
||||
|
||||
workDir string
|
||||
|
||||
|
@ -45,6 +47,12 @@ var (
|
|||
latestVersion string
|
||||
)
|
||||
|
||||
func init() {
|
||||
if runtime.GOARCH == "amd64" && cpuid.CPU.X64Level() < 3 {
|
||||
amd64Compatible = "-compatible"
|
||||
}
|
||||
}
|
||||
|
||||
type updateError struct {
|
||||
Message string
|
||||
}
|
||||
|
@ -59,8 +67,6 @@ func Update(execPath string) (err error) {
|
|||
mu.Lock()
|
||||
defer mu.Unlock()
|
||||
|
||||
goos = runtime.GOOS
|
||||
goarch = runtime.GOARCH
|
||||
latestVersion, err = getLatestVersion()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -69,7 +75,7 @@ func Update(execPath string) (err error) {
|
|||
log.Infoln("current version %s, latest version %s", constant.Version, latestVersion)
|
||||
|
||||
if latestVersion == constant.Version {
|
||||
err := &updateError{Message: "Already using latest version"}
|
||||
err := &updateError{Message: "already using latest version"}
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -128,12 +134,10 @@ func prepare(exePath string) (err error) {
|
|||
//log.Infoln(packageName)
|
||||
backupDir = filepath.Join(workDir, "meta-backup")
|
||||
|
||||
if goos == "windows" && goarch == "amd64" {
|
||||
updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible.exe"
|
||||
} else if goos == "linux" && goarch == "amd64" {
|
||||
updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible"
|
||||
if runtime.GOOS == "windows" {
|
||||
updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + ".exe"
|
||||
} else {
|
||||
updateExeName = "clash.meta" + "-" + goos + "-" + goarch
|
||||
updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible
|
||||
}
|
||||
|
||||
log.Infoln("updateExeName: %s ", updateExeName)
|
||||
|
@ -198,7 +202,7 @@ func replace() error {
|
|||
var err error
|
||||
|
||||
log.Infoln("replacing: %s to %s", updateExeName, currentExeName)
|
||||
if goos == "windows" {
|
||||
if runtime.GOOS == "windows" {
|
||||
// rename fails with "File in use" error
|
||||
err = copyFile(updateExeName, currentExeName)
|
||||
} else {
|
||||
|
@ -430,17 +434,19 @@ func getLatestVersion() (version string, err error) {
|
|||
func updateDownloadURL() {
|
||||
var middle string
|
||||
|
||||
if goarch == "arm" && goarm != "" {
|
||||
middle = fmt.Sprintf("-%s-%sv%s-%s", goos, goarch, goarm, latestVersion)
|
||||
} else if isMIPS(goarch) && gomips != "" {
|
||||
middle = fmt.Sprintf("-%s-%s-%s-%s", goos, goarch, gomips, latestVersion)
|
||||
} else if goarch == "amd64" && (goos == "windows" || goos == "linux") {
|
||||
middle = fmt.Sprintf("-%s-%s-compatible-%s", goos, goarch, latestVersion)
|
||||
if runtime.GOARCH == "arm" && probeGoARM() {
|
||||
//-linux-armv7-alpha-e552b54.gz
|
||||
middle = fmt.Sprintf("-%s-%s%s-%s", runtime.GOOS, runtime.GOARCH, goarm, latestVersion)
|
||||
} else if runtime.GOARCH == "arm64" {
|
||||
//-linux-arm64-alpha-e552b54.gz
|
||||
middle = fmt.Sprintf("-%s-%s-%s", runtime.GOOS, runtime.GOARCH, latestVersion)
|
||||
} else if isMIPS(runtime.GOARCH) && gomips != "" {
|
||||
middle = fmt.Sprintf("-%s-%s-%s-%s", runtime.GOOS, runtime.GOARCH, gomips, latestVersion)
|
||||
} else {
|
||||
middle = fmt.Sprintf("-%s-%s-%s", goos, goarch, latestVersion)
|
||||
middle = fmt.Sprintf("-%s-%s%s-%s", runtime.GOOS, runtime.GOARCH, amd64Compatible, latestVersion)
|
||||
}
|
||||
|
||||
if goos == "windows" {
|
||||
if runtime.GOOS == "windows" {
|
||||
middle += ".zip"
|
||||
} else {
|
||||
middle += ".gz"
|
||||
|
@ -462,3 +468,22 @@ func isMIPS(arch string) (ok bool) {
|
|||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// linux only
|
||||
func probeGoARM() (ok bool) {
|
||||
cmd := exec.Command("cat", "/proc/cpuinfo")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Errorln("probe goarm error:%s", err)
|
||||
return false
|
||||
}
|
||||
cpuInfo := string(output)
|
||||
if strings.Contains(cpuInfo, "vfpv3") || strings.Contains(cpuInfo, "vfpv4") {
|
||||
goarm = "v7"
|
||||
} else if strings.Contains(cpuInfo, "vfp") {
|
||||
goarm = "v6"
|
||||
} else {
|
||||
goarm = "v5"
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package inner
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"net"
|
||||
)
|
||||
|
||||
var tcpIn chan<- C.ConnContext
|
||||
|
@ -12,9 +14,13 @@ func New(in chan<- C.ConnContext) {
|
|||
tcpIn = in
|
||||
}
|
||||
|
||||
func HandleTcp(dst string, host string) net.Conn {
|
||||
func HandleTcp(address string) (conn net.Conn, err error) {
|
||||
if tcpIn == nil {
|
||||
return nil, errors.New("tcp uninitialized")
|
||||
}
|
||||
// executor Parsed
|
||||
conn1, conn2 := net.Pipe()
|
||||
context := inbound.NewInner(conn2, dst, host)
|
||||
context := inbound.NewInner(conn2, address)
|
||||
tcpIn <- context
|
||||
return conn1
|
||||
return conn1, nil
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions
|
|||
conn = l.pickCipher.StreamConn(conn)
|
||||
conn = N.NewDeadlineConn(conn) // embed ss can't handle readDeadline correctly
|
||||
|
||||
target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen))
|
||||
target, err := socks5.ReadAddr0(conn)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/sockopt"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
@ -29,19 +29,20 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD
|
|||
}
|
||||
|
||||
sl := &UDPListener{l, false}
|
||||
conn := pickCipher.PacketConn(l)
|
||||
conn := pickCipher.PacketConn(N.NewEnhancePacketConn(l))
|
||||
go func() {
|
||||
for {
|
||||
buf := pool.Get(pool.RelayBufferSize)
|
||||
n, remoteAddr, err := conn.ReadFrom(buf)
|
||||
data, put, remoteAddr, err := conn.WaitReadFrom()
|
||||
if err != nil {
|
||||
pool.Put(buf)
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
if sl.closed {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
handleSocksUDP(conn, in, buf[:n], remoteAddr)
|
||||
handleSocksUDP(conn, in, data, put, remoteAddr)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -57,11 +58,13 @@ func (l *UDPListener) LocalAddr() net.Addr {
|
|||
return l.packetConn.LocalAddr()
|
||||
}
|
||||
|
||||
func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr) {
|
||||
func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr) {
|
||||
tgtAddr := socks5.SplitAddr(buf)
|
||||
if tgtAddr == nil {
|
||||
// Unresolved UDP packet, return buffer to the pool
|
||||
pool.Put(buf)
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
return
|
||||
}
|
||||
target := socks5.ParseAddr(tgtAddr.String())
|
||||
|
@ -71,7 +74,7 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, ad
|
|||
pc: pc,
|
||||
rAddr: addr,
|
||||
payload: payload,
|
||||
bufRef: buf,
|
||||
put: put,
|
||||
}
|
||||
select {
|
||||
case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS):
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"net"
|
||||
"net/url"
|
||||
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
"github.com/Dreamacro/clash/transport/socks5"
|
||||
)
|
||||
|
||||
|
@ -14,7 +13,7 @@ type packet struct {
|
|||
pc net.PacketConn
|
||||
rAddr net.Addr
|
||||
payload []byte
|
||||
bufRef []byte
|
||||
put func()
|
||||
}
|
||||
|
||||
func (c *packet) Data() []byte {
|
||||
|
@ -37,7 +36,9 @@ func (c *packet) LocalAddr() net.Addr {
|
|||
}
|
||||
|
||||
func (c *packet) Drop() {
|
||||
pool.Put(c.bufRef)
|
||||
if c.put != nil {
|
||||
c.put()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *packet) InAddr() net.Addr {
|
||||
|
|
|
@ -2,8 +2,11 @@ package sing
|
|||
|
||||
import (
|
||||
"context"
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/Dreamacro/clash/adapter/inbound"
|
||||
|
||||
"github.com/sagernet/sing/common/auth"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
@ -22,3 +25,20 @@ func getAdditions(ctx context.Context) []inbound.Addition {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func combineAdditions(ctx context.Context, additions []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 = append(additions, inbound.WithInUser(user))
|
||||
}
|
||||
return additions
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package sing
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"golang.org/x/exp/slices"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sync"
|
||||
|
@ -18,6 +17,7 @@ import (
|
|||
mux "github.com/sagernet/sing-mux"
|
||||
vmess "github.com/sagernet/sing-vmess"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"github.com/sagernet/sing/common/bufio/deadline"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
|
@ -57,6 +57,14 @@ 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,
|
||||
|
@ -65,11 +73,6 @@ func UpstreamMetadata(metadata M.Metadata) M.Metadata {
|
|||
}
|
||||
|
||||
func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
|
||||
additions := h.Additions
|
||||
if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 {
|
||||
additions = slices.Clone(additions)
|
||||
additions = append(additions, ctxAdditions...)
|
||||
}
|
||||
switch metadata.Destination.Fqdn {
|
||||
case mux.Destination.Fqdn:
|
||||
return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata))
|
||||
|
@ -94,15 +97,13 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta
|
|||
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, additions...)
|
||||
h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, combineAdditions(ctx, h.Additions)...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error {
|
||||
additions := h.Additions
|
||||
if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 {
|
||||
additions = slices.Clone(additions)
|
||||
additions = append(additions, ctxAdditions...)
|
||||
if deadline.NeedAdditionalReadDeadline(conn) {
|
||||
conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline
|
||||
}
|
||||
defer func() { _ = conn.Close() }()
|
||||
mutex := sync.Mutex{}
|
||||
|
@ -112,11 +113,30 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.
|
|||
defer mutex.Unlock()
|
||||
conn2 = nil
|
||||
}()
|
||||
var buff *buf.Buffer
|
||||
newBuffer := func() *buf.Buffer {
|
||||
buff = buf.NewPacket() // do not use stack buffer
|
||||
return buff
|
||||
}
|
||||
readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn)
|
||||
if isReadWaiter {
|
||||
readWaiter.InitializeReadWaiter(newBuffer)
|
||||
}
|
||||
for {
|
||||
buff := buf.NewPacket() // do not use stack buffer
|
||||
dest, err := conn.ReadPacket(buff)
|
||||
var (
|
||||
dest M.Socksaddr
|
||||
err error
|
||||
)
|
||||
buff = nil // clear last loop status, avoid repeat release
|
||||
if isReadWaiter {
|
||||
dest, err = readWaiter.WaitReadPacket()
|
||||
} else {
|
||||
dest, err = conn.ReadPacket(newBuffer())
|
||||
}
|
||||
if err != nil {
|
||||
buff.Release()
|
||||
if buff != nil {
|
||||
buff.Release()
|
||||
}
|
||||
if ShouldIgnorePacketError(err) {
|
||||
break
|
||||
}
|
||||
|
@ -131,7 +151,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.
|
|||
buff: buff,
|
||||
}
|
||||
select {
|
||||
case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...):
|
||||
case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...):
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
"github.com/sagernet/sing/common/metadata"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
)
|
||||
|
||||
type Listener struct {
|
||||
|
@ -92,19 +92,38 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C
|
|||
|
||||
go func() {
|
||||
conn := bufio.NewPacketConn(ul)
|
||||
var buff *buf.Buffer
|
||||
newBuffer := func() *buf.Buffer {
|
||||
buff = buf.NewPacket() // do not use stack buffer
|
||||
return buff
|
||||
}
|
||||
readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn)
|
||||
if isReadWaiter {
|
||||
readWaiter.InitializeReadWaiter(newBuffer)
|
||||
}
|
||||
for {
|
||||
buff := buf.NewPacket()
|
||||
remoteAddr, err := conn.ReadPacket(buff)
|
||||
var (
|
||||
dest M.Socksaddr
|
||||
err error
|
||||
)
|
||||
buff = nil // clear last loop status, avoid repeat release
|
||||
if isReadWaiter {
|
||||
dest, err = readWaiter.WaitReadPacket()
|
||||
} else {
|
||||
dest, err = conn.ReadPacket(newBuffer())
|
||||
}
|
||||
if err != nil {
|
||||
buff.Release()
|
||||
if buff != nil {
|
||||
buff.Release()
|
||||
}
|
||||
if sl.closed {
|
||||
break
|
||||
}
|
||||
continue
|
||||
}
|
||||
_ = sl.service.NewPacket(context.TODO(), conn, buff, metadata.Metadata{
|
||||
_ = sl.service.NewPacket(context.TODO(), conn, buff, M.Metadata{
|
||||
Protocol: "shadowsocks",
|
||||
Source: remoteAddr,
|
||||
Source: dest,
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
@ -170,9 +189,9 @@ func (l *Listener) AddrList() (addrList []net.Addr) {
|
|||
|
||||
func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) {
|
||||
ctx := sing.WithAdditions(context.TODO(), additions...)
|
||||
err := l.service.NewConnection(ctx, conn, metadata.Metadata{
|
||||
err := l.service.NewConnection(ctx, conn, M.Metadata{
|
||||
Protocol: "shadowsocks",
|
||||
Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()),
|
||||
Source: M.ParseSocksaddr(conn.RemoteAddr().String()),
|
||||
})
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
D "github.com/miekg/dns"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
@ -108,20 +109,40 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.
|
|||
defer mutex.Unlock()
|
||||
conn2 = nil
|
||||
}()
|
||||
for {
|
||||
|
||||
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)
|
||||
buff = buf.NewSize(2 * 1024)
|
||||
return buff
|
||||
}
|
||||
readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn)
|
||||
if isReadWaiter {
|
||||
readWaiter.InitializeReadWaiter(newBuffer)
|
||||
}
|
||||
for {
|
||||
var (
|
||||
dest M.Socksaddr
|
||||
err error
|
||||
)
|
||||
_ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout))
|
||||
dest, err := conn.ReadPacket(buff)
|
||||
buff = nil // clear last loop status, avoid repeat release
|
||||
if isReadWaiter {
|
||||
dest, err = readWaiter.WaitReadPacket()
|
||||
} else {
|
||||
dest, err = conn.ReadPacket(newBuffer())
|
||||
}
|
||||
if err != nil {
|
||||
buff.Release()
|
||||
if buff != nil {
|
||||
buff.Release()
|
||||
}
|
||||
if sing.ShouldIgnorePacketError(err) {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
go func(buff *buf.Buffer) {
|
||||
ctx, cancel := context.WithTimeout(ctx, DefaultDnsRelayTimeout)
|
||||
defer cancel()
|
||||
inData := buff.Bytes()
|
||||
|
@ -146,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
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT
|
|||
}()
|
||||
conn, err := listenLocalConn(rAddr, lAddr, in, natTable)
|
||||
if err != nil {
|
||||
log.Errorln("listenLocalConn failed with error: %s, packet loss", err.Error())
|
||||
log.Errorln("listenLocalConn failed with error: %s, packet loss (rAddr[%T]=%s lAddr[%T]=%s)", err.Error(), rAddr, remote, lAddr, local)
|
||||
return nil, err
|
||||
}
|
||||
natTable.AddLocalConn(local, remote, conn)
|
||||
|
|
49
rules/common/in_name.go
Normal file
49
rules/common/in_name.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InName struct {
|
||||
*Base
|
||||
names []string
|
||||
adapter string
|
||||
payload string
|
||||
}
|
||||
|
||||
func (u *InName) Match(metadata *C.Metadata) (bool, string) {
|
||||
for _, name := range u.names {
|
||||
if metadata.InName == name {
|
||||
return true, u.adapter
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (u *InName) RuleType() C.RuleType {
|
||||
return C.InName
|
||||
}
|
||||
|
||||
func (u *InName) Adapter() string {
|
||||
return u.adapter
|
||||
}
|
||||
|
||||
func (u *InName) Payload() string {
|
||||
return u.payload
|
||||
}
|
||||
|
||||
func NewInName(iNames, adapter string) (*InName, error) {
|
||||
names := strings.Split(iNames, "/")
|
||||
if len(names) == 0 {
|
||||
return nil, fmt.Errorf("in name couldn't be empty")
|
||||
}
|
||||
|
||||
return &InName{
|
||||
Base: &Base{},
|
||||
names: names,
|
||||
adapter: adapter,
|
||||
payload: iNames,
|
||||
}, nil
|
||||
}
|
|
@ -23,7 +23,7 @@ func (u *InType) Match(metadata *C.Metadata) (bool, string) {
|
|||
}
|
||||
|
||||
func (u *InType) RuleType() C.RuleType {
|
||||
return C.INTYPE
|
||||
return C.InType
|
||||
}
|
||||
|
||||
func (u *InType) Adapter() string {
|
||||
|
@ -37,7 +37,7 @@ func (u *InType) Payload() string {
|
|||
func NewInType(iTypes, adapter string) (*InType, error) {
|
||||
types := strings.Split(iTypes, "/")
|
||||
if len(types) == 0 {
|
||||
return nil, fmt.Errorf("in type could be empty")
|
||||
return nil, fmt.Errorf("in type couldn't be empty")
|
||||
}
|
||||
|
||||
tps, err := parseInTypes(types)
|
||||
|
|
49
rules/common/in_user.go
Normal file
49
rules/common/in_user.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type InUser struct {
|
||||
*Base
|
||||
users []string
|
||||
adapter string
|
||||
payload string
|
||||
}
|
||||
|
||||
func (u *InUser) Match(metadata *C.Metadata) (bool, string) {
|
||||
for _, user := range u.users {
|
||||
if metadata.InUser == user {
|
||||
return true, u.adapter
|
||||
}
|
||||
}
|
||||
return false, ""
|
||||
}
|
||||
|
||||
func (u *InUser) RuleType() C.RuleType {
|
||||
return C.InUser
|
||||
}
|
||||
|
||||
func (u *InUser) Adapter() string {
|
||||
return u.adapter
|
||||
}
|
||||
|
||||
func (u *InUser) Payload() string {
|
||||
return u.payload
|
||||
}
|
||||
|
||||
func NewInUser(iUsers, adapter string) (*InUser, error) {
|
||||
users := strings.Split(iUsers, "/")
|
||||
if len(users) == 0 {
|
||||
return nil, fmt.Errorf("in user couldn't be empty")
|
||||
}
|
||||
|
||||
return &InUser{
|
||||
Base: &Base{},
|
||||
users: users,
|
||||
adapter: adapter,
|
||||
payload: iUsers,
|
||||
}, nil
|
||||
}
|
|
@ -47,6 +47,10 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string]
|
|||
parsed, parseErr = RC.NewUid(payload, target)
|
||||
case "IN-TYPE":
|
||||
parsed, parseErr = RC.NewInType(payload, target)
|
||||
case "IN-USER":
|
||||
parsed, parseErr = RC.NewInUser(payload, target)
|
||||
case "IN-NAME":
|
||||
parsed, parseErr = RC.NewInName(payload, target)
|
||||
case "SUB-RULE":
|
||||
parsed, parseErr = logic.NewSubRule(payload, target, subRules, ParseRule)
|
||||
case "AND":
|
||||
|
|
95
test/go.mod
95
test/go.mod
|
@ -6,26 +6,34 @@ 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.50
|
||||
github.com/stretchr/testify v1.8.1
|
||||
golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e
|
||||
github.com/miekg/dns v1.1.53
|
||||
github.com/stretchr/testify v1.8.2
|
||||
golang.org/x/net v0.9.0
|
||||
)
|
||||
|
||||
replace github.com/Dreamacro/clash => ../
|
||||
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/3andne/restls-client-go v0.1.4 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.0 // indirect
|
||||
github.com/RyuaNerin/go-krypto v1.0.2 // indirect
|
||||
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.9.3 // indirect
|
||||
github.com/coreos/go-iptables v0.6.0 // indirect
|
||||
github.com/database64128/tfo-go/v2 v2.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
||||
github.com/docker/distribution v2.8.1+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
|
||||
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/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/gofrs/uuid v4.3.1+incompatible // 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.0.1 // indirect
|
||||
|
@ -33,53 +41,74 @@ require (
|
|||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c // indirect
|
||||
github.com/josharian/native v1.0.0 // indirect
|
||||
github.com/hashicorp/yamux v0.1.1 // indirect
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 // indirect
|
||||
github.com/josharian/native v1.1.0 // indirect
|
||||
github.com/jpillora/backoff v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect
|
||||
github.com/marten-seemann/qpack v0.3.0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
|
||||
github.com/mdlayher/netlink v1.7.0 // indirect
|
||||
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 // indirect
|
||||
github.com/mdlayher/socket v0.4.0 // indirect
|
||||
github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.1.0 // indirect
|
||||
github.com/metacubex/sing-tun v0.1.0 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c // indirect
|
||||
github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 // indirect
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba // indirect
|
||||
github.com/metacubex/sing-tun v0.1.4 // indirect
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a // indirect
|
||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/mroth/weightedrand/v2 v2.0.0 // indirect
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 // indirect
|
||||
github.com/openacid/low v0.1.21 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/oschwald/geoip2-golang v1.8.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.10.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // 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-19 v0.2.1 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1 // 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.1.0 // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.0 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c // indirect
|
||||
github.com/samber/lo v1.35.0 // indirect
|
||||
github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a // indirect
|
||||
github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e // indirect
|
||||
github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 // indirect
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // indirect
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect
|
||||
github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect
|
||||
github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect
|
||||
github.com/samber/lo v1.38.1 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.4 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.5 // indirect
|
||||
github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect
|
||||
github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect
|
||||
github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||
github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // 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.6 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a // indirect
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/crypto v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
|
||||
golang.org/x/mod v0.8.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/text v0.9.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
|
||||
golang.org/x/tools v0.6.0 // indirect
|
||||
google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gotest.tools/v3 v3.4.0 // indirect
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
)
|
||||
|
|
261
test/go.sum
261
test/go.sum
|
@ -1,8 +1,17 @@
|
|||
github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU=
|
||||
github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
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/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/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
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=
|
||||
|
@ -10,8 +19,6 @@ github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc=
|
|||
github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A=
|
||||
github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk=
|
||||
github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q=
|
||||
github.com/database64128/tfo-go/v2 v2.0.2 h1:5rGgkJeLEKlNaqredfrPQNLnctn1b+1fq/8tdKdOzJg=
|
||||
github.com/database64128/tfo-go/v2 v2.0.2/go.mod h1:FDdt4JaAsRU66wsYHxSVytYimPkKIHupVsxM+5DhvjY=
|
||||
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=
|
||||
|
@ -25,94 +32,100 @@ 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/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc=
|
||||
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/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/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
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-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI=
|
||||
github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
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.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo=
|
||||
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
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/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis=
|
||||
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-20221001123530-5308ebe5334c h1:OCFM4+DXTWfNlyeoddrTwdup/ztkGSyAMR2UGcPckNQ=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
|
||||
github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk=
|
||||
github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 h1:+aAGyK41KRn8jbF2Q7PLL0Sxwg6dShGcQSeCC7nZQ8E=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI=
|
||||
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=
|
||||
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 v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok=
|
||||
github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
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.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw=
|
||||
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
|
||||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
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/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE=
|
||||
github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI=
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE=
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI=
|
||||
github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y=
|
||||
github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA=
|
||||
github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M=
|
||||
github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY=
|
||||
github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o=
|
||||
github.com/mdlayher/netlink v1.7.0 h1:ZNGI4V7i1fJ94DPYtWhI/R85i/Q7ZxnuhUJQcJMoodI=
|
||||
github.com/mdlayher/netlink v1.7.0/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ=
|
||||
github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg=
|
||||
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 h1:HSkXG1bE/qcRuuPlZ2Jyf0Od8HLxOowi7CzKQqNtWn4=
|
||||
github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7/go.mod h1:1ztDZHGbU5MjN5lNZpkpG8ygndjjWzcojp/H7r6l6QQ=
|
||||
github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw=
|
||||
github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc=
|
||||
github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e h1:RnfC6+sShJ3biU2Q2wuh4FxZ8/3fp1QG+1zAfswVehA=
|
||||
github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e/go.mod h1:7NPWVTLiX2Ss9q9gBNZaNHsPqZ3Tg/ApyrXxxUYbl78=
|
||||
github.com/metacubex/sing-shadowsocks v0.1.0 h1:uGBtNkpy4QFlofaNkJf+iFegeLU11VzTUlkC46FHF8A=
|
||||
github.com/metacubex/sing-shadowsocks v0.1.0/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ=
|
||||
github.com/metacubex/sing-tun v0.1.0 h1:iQj0+0WjJynSKAtfv87wOZlVKWl3w9RvkOSkVe9zuMg=
|
||||
github.com/metacubex/sing-tun v0.1.0/go.mod h1:l4JyI6RTrlHLQz5vSakg+wxA+LwGVI0Mz5ZtlOv67dA=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c h1:VHtXDny/TNOF7YDT9d9Qkr+x6K1O4cejXLlyPUXDeXQ=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c/go.mod h1:fULJ451x1/XlpIhl+Oo+EPGKla9tFZaqT5dKLrZ+NvM=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM=
|
||||
github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE=
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIayTGGgRl6PuVqo2Bpo6+x3LqDDyqrYDDXw=
|
||||
github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba h1:He8YwyK600lHAS1xxNsP4k/jnZ8zqQ34XjCGn925+Yk=
|
||||
github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s=
|
||||
github.com/metacubex/sing-tun v0.1.4 h1:OQDBNHjuPKrOprCiK+sLt97YQ0K6b9ZWmJB6z51ibZQ=
|
||||
github.com/metacubex/sing-tun v0.1.4/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco=
|
||||
github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY=
|
||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c h1:RC8WMpjonrBfyAh6VN/POIPtYD5tRAq0qMqCRjQNK+g=
|
||||
github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c/go.mod h1:9OcmHNQQUTbk4XCffrLgN1NEKc2mh5u++biHVrvHsSU=
|
||||
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.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo=
|
||||
github.com/mroth/weightedrand/v2 v2.0.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4=
|
||||
github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI=
|
||||
github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
|
||||
github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q=
|
||||
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=
|
||||
github.com/openacid/must v0.1.3/go.mod h1:luPiXCuJlEo3UUFQngVQokV0MPGryeYvtCbQPs3U1+I=
|
||||
github.com/openacid/testkeys v0.1.6/go.mod h1:MfA7cACzBpbiwekivj8StqX0WIRmqlMsci1c37CA3Do=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
|
||||
|
@ -121,45 +134,78 @@ github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6
|
|||
github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw=
|
||||
github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg=
|
||||
github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0=
|
||||
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
|
||||
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
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/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-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A=
|
||||
github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk=
|
||||
github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM=
|
||||
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
|
||||
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34=
|
||||
github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g=
|
||||
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 v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY=
|
||||
github.com/sagernet/sing v0.1.0 h1:FGmaP2BVPYO2IyC/3R1DaQa/zr+kOKHRgWqrmOF+Gu8=
|
||||
github.com/sagernet/sing v0.1.0/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4=
|
||||
github.com/sagernet/sing-vmess v0.1.0 h1:x0tYBJRbVi7zVXpMEW45eApGpXIDs9ub3raglouAKMo=
|
||||
github.com/sagernet/sing-vmess v0.1.0/go.mod h1:4lwj6EHrUlgRnKhbmtboGbt+wtl5+tHMv96Ez8LZArw=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c h1:qP3ZOHnjZalvqbjundbXiv/YrNlo3HOgrKc+S1QGs0U=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI=
|
||||
github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0=
|
||||
github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk=
|
||||
github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a h1:s2kkd/eR3mWGkYioknxhgQzG8uft4VRx9skhqxxeyVQ=
|
||||
github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
|
||||
github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e h1:t8nuY9plpHEzlnPxOpuv64jhjz3teIvccu3YMFX4fJI=
|
||||
github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 h1:0Dc1t9ao9EyvRil6l/950PLwND1qO1rgnxwbcctE8KE=
|
||||
github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9/go.mod h1:Dpib342FFR68SZ3CSRYxk/zWbanAqRBrCxoLuda5I0A=
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4=
|
||||
github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI=
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U=
|
||||
github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U=
|
||||
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/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE=
|
||||
github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg=
|
||||
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-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo=
|
||||
github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o=
|
||||
github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8=
|
||||
github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ=
|
||||
github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ=
|
||||
github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c=
|
||||
github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8=
|
||||
github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM=
|
||||
github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk=
|
||||
github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c/go.mod h1:NV/a66PhhWYVmUMaotlXJ8fIEFB98u+c8l/CQIEFLrU=
|
||||
github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIFG3i4Gi093BQITvwH9znsz2VUZmnmwHvpIo=
|
||||
github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
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=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA=
|
||||
github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
|
||||
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
|
||||
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
|
||||
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
|
||||
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/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/xtls/go v0.0.0-20220914232946-0441cf4cf837 h1:AHhUwwFJGl27E46OpdJHplZkK09m7aETNBNzhT6t15M=
|
||||
|
@ -167,40 +213,35 @@ github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8x
|
|||
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.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||
github.com/yusufpapurcu/wmi v1.2.2/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.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
||||
go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
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.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
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.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
|
||||
golang.org/x/mod v0.8.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-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/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-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e h1:IVOjWZQH/57UDcpX19vSmMz8w3ohroOMWohn8qWpRkg=
|
||||
golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
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=
|
||||
|
@ -208,60 +249,47 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/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-20210423082822-04245dca01da/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-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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.2.1-0.20221110211117-d684c6f88669 h1:pvmSpBoSG0gD2LLPAX15QHPig8xsbU0tu1sSAmResqk=
|
||||
golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/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-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-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.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d h1:qp0AnQCvRCMlu9jBjtdbTaaEmThIgZOrbVyDEOcmKhQ=
|
||||
google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d/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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
@ -269,8 +297,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||
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=
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4=
|
||||
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM=
|
||||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
||||
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||
|
|
|
@ -199,9 +199,12 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wrap.remoteAddr = pconn.RemoteAddr()
|
||||
|
||||
if tlsConfig == nil {
|
||||
return pconn, nil
|
||||
}
|
||||
|
||||
if len(Fingerprint) != 0 {
|
||||
if realityConfig == nil {
|
||||
if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"sort"
|
||||
"strings"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/transport/shadowsocks/shadowaead"
|
||||
"github.com/Dreamacro/clash/transport/shadowsocks/shadowstream"
|
||||
)
|
||||
|
@ -21,7 +22,7 @@ type StreamConnCipher interface {
|
|||
}
|
||||
|
||||
type PacketConnCipher interface {
|
||||
PacketConn(net.PacketConn) net.PacketConn
|
||||
PacketConn(N.EnhancePacketConn) N.EnhancePacketConn
|
||||
}
|
||||
|
||||
// ErrCipherNotSupported occurs when a cipher is not supported (likely because of security concerns).
|
||||
|
@ -128,7 +129,7 @@ type AeadCipher struct {
|
|||
}
|
||||
|
||||
func (aead *AeadCipher) StreamConn(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) }
|
||||
func (aead *AeadCipher) PacketConn(c net.PacketConn) net.PacketConn {
|
||||
func (aead *AeadCipher) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn {
|
||||
return shadowaead.NewPacketConn(c, aead)
|
||||
}
|
||||
|
||||
|
@ -139,7 +140,7 @@ type StreamCipher struct {
|
|||
}
|
||||
|
||||
func (ciph *StreamCipher) StreamConn(c net.Conn) net.Conn { return shadowstream.NewConn(c, ciph) }
|
||||
func (ciph *StreamCipher) PacketConn(c net.PacketConn) net.PacketConn {
|
||||
func (ciph *StreamCipher) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn {
|
||||
return shadowstream.NewPacketConn(c, ciph)
|
||||
}
|
||||
|
||||
|
@ -147,8 +148,8 @@ func (ciph *StreamCipher) PacketConn(c net.PacketConn) net.PacketConn {
|
|||
|
||||
type dummy struct{}
|
||||
|
||||
func (dummy) StreamConn(c net.Conn) net.Conn { return c }
|
||||
func (dummy) PacketConn(c net.PacketConn) net.PacketConn { return c }
|
||||
func (dummy) StreamConn(c net.Conn) net.Conn { return c }
|
||||
func (dummy) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c }
|
||||
|
||||
// key-derivation function from original Shadowsocks
|
||||
func Kdf(password string, keyLen int) []byte {
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
|
@ -57,15 +58,15 @@ func Unpack(dst, pkt []byte, ciph Cipher) ([]byte, error) {
|
|||
}
|
||||
|
||||
type PacketConn struct {
|
||||
net.PacketConn
|
||||
N.EnhancePacketConn
|
||||
Cipher
|
||||
}
|
||||
|
||||
const maxPacketSize = 64 * 1024
|
||||
|
||||
// NewPacketConn wraps a net.PacketConn with cipher
|
||||
func NewPacketConn(c net.PacketConn, ciph Cipher) *PacketConn {
|
||||
return &PacketConn{PacketConn: c, Cipher: ciph}
|
||||
// NewPacketConn wraps an N.EnhancePacketConn with cipher
|
||||
func NewPacketConn(c N.EnhancePacketConn, ciph Cipher) *PacketConn {
|
||||
return &PacketConn{EnhancePacketConn: c, Cipher: ciph}
|
||||
}
|
||||
|
||||
// WriteTo encrypts b and write to addr using the embedded PacketConn.
|
||||
|
@ -76,13 +77,13 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_, err = c.PacketConn.WriteTo(buf, addr)
|
||||
_, err = c.EnhancePacketConn.WriteTo(buf, addr)
|
||||
return len(b), err
|
||||
}
|
||||
|
||||
// ReadFrom reads from the embedded PacketConn and decrypts into b.
|
||||
func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, addr, err := c.PacketConn.ReadFrom(b)
|
||||
n, addr, err := c.EnhancePacketConn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
@ -93,3 +94,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||
copy(b, bb)
|
||||
return len(bb), addr, err
|
||||
}
|
||||
|
||||
func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
data, put, addr, err = c.EnhancePacketConn.WaitReadFrom()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data, err = Unpack(data[c.Cipher.SaltSize():], data, c)
|
||||
if err != nil {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
data = nil
|
||||
put = nil
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
|
@ -43,13 +44,13 @@ func Unpack(dst, pkt []byte, s Cipher) ([]byte, error) {
|
|||
}
|
||||
|
||||
type PacketConn struct {
|
||||
net.PacketConn
|
||||
N.EnhancePacketConn
|
||||
Cipher
|
||||
}
|
||||
|
||||
// NewPacketConn wraps a net.PacketConn with stream cipher encryption/decryption.
|
||||
func NewPacketConn(c net.PacketConn, ciph Cipher) *PacketConn {
|
||||
return &PacketConn{PacketConn: c, Cipher: ciph}
|
||||
// NewPacketConn wraps an N.EnhancePacketConn with stream cipher encryption/decryption.
|
||||
func NewPacketConn(c N.EnhancePacketConn, ciph Cipher) *PacketConn {
|
||||
return &PacketConn{EnhancePacketConn: c, Cipher: ciph}
|
||||
}
|
||||
|
||||
const maxPacketSize = 64 * 1024
|
||||
|
@ -61,12 +62,12 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_, err = c.PacketConn.WriteTo(buf, addr)
|
||||
_, err = c.EnhancePacketConn.WriteTo(buf, addr)
|
||||
return len(b), err
|
||||
}
|
||||
|
||||
func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, addr, err := c.PacketConn.ReadFrom(b)
|
||||
n, addr, err := c.EnhancePacketConn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
@ -77,3 +78,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||
copy(b, bb)
|
||||
return len(bb), addr, err
|
||||
}
|
||||
|
||||
func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
data, put, addr, err = c.EnhancePacketConn.WaitReadFrom()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data, err = Unpack(data[c.IVSize():], data, c)
|
||||
if err != nil {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
data = nil
|
||||
put = nil
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -299,6 +299,50 @@ func ReadAddr(r io.Reader, b []byte) (Addr, error) {
|
|||
return nil, ErrAddressNotSupported
|
||||
}
|
||||
|
||||
func ReadAddr0(r io.Reader) (Addr, error) {
|
||||
aType, err := ReadByte(r) // read 1st byte for address type
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch aType {
|
||||
case AtypDomainName:
|
||||
var domainLength byte
|
||||
domainLength, err = ReadByte(r) // read 2nd byte for domain length
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b := make([]byte, 1+1+uint16(domainLength)+2)
|
||||
_, err = io.ReadFull(r, b[2:])
|
||||
b[0] = aType
|
||||
b[1] = domainLength
|
||||
return b, err
|
||||
case AtypIPv4:
|
||||
var b [1 + net.IPv4len + 2]byte
|
||||
_, err = io.ReadFull(r, b[1:])
|
||||
b[0] = aType
|
||||
return b[:], err
|
||||
case AtypIPv6:
|
||||
var b [1 + net.IPv6len + 2]byte
|
||||
_, err = io.ReadFull(r, b[1:])
|
||||
b[0] = aType
|
||||
return b[:], err
|
||||
}
|
||||
|
||||
return nil, ErrAddressNotSupported
|
||||
}
|
||||
|
||||
func ReadByte(reader io.Reader) (byte, error) {
|
||||
if br, isBr := reader.(io.ByteReader); isBr {
|
||||
return br.ReadByte()
|
||||
}
|
||||
var b [1]byte
|
||||
if _, err := io.ReadFull(reader, b[:]); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return b[0], nil
|
||||
}
|
||||
|
||||
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
|
||||
func SplitAddr(b []byte) Addr {
|
||||
addrLen := 1
|
||||
|
|
|
@ -8,6 +8,7 @@ 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"
|
||||
|
@ -82,13 +83,13 @@ func (a *authAES128) StreamConn(c net.Conn, iv []byte) net.Conn {
|
|||
return &Conn{Conn: c, Protocol: p}
|
||||
}
|
||||
|
||||
func (a *authAES128) PacketConn(c net.PacketConn) net.PacketConn {
|
||||
func (a *authAES128) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn {
|
||||
p := &authAES128{
|
||||
Base: a.Base,
|
||||
authAES128Function: a.authAES128Function,
|
||||
userData: a.userData,
|
||||
}
|
||||
return &PacketConn{PacketConn: c, Protocol: p}
|
||||
return &PacketConn{EnhancePacketConn: c, Protocol: p}
|
||||
}
|
||||
|
||||
func (a *authAES128) Decode(dst, src *bytes.Buffer) error {
|
||||
|
|
|
@ -11,6 +11,7 @@ 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"
|
||||
|
@ -83,13 +84,13 @@ func (a *authChainA) StreamConn(c net.Conn, iv []byte) net.Conn {
|
|||
return &Conn{Conn: c, Protocol: p}
|
||||
}
|
||||
|
||||
func (a *authChainA) PacketConn(c net.PacketConn) net.PacketConn {
|
||||
func (a *authChainA) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn {
|
||||
p := &authChainA{
|
||||
Base: a.Base,
|
||||
salt: a.salt,
|
||||
userData: a.userData,
|
||||
}
|
||||
return &PacketConn{PacketConn: c, Protocol: p}
|
||||
return &PacketConn{EnhancePacketConn: c, Protocol: p}
|
||||
}
|
||||
|
||||
func (a *authChainA) Decode(dst, src *bytes.Buffer) error {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"hash/crc32"
|
||||
"net"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
"github.com/Dreamacro/clash/transport/ssr/tools"
|
||||
|
||||
|
@ -35,7 +36,7 @@ func (a *authSHA1V4) StreamConn(c net.Conn, iv []byte) net.Conn {
|
|||
return &Conn{Conn: c, Protocol: p}
|
||||
}
|
||||
|
||||
func (a *authSHA1V4) PacketConn(c net.PacketConn) net.PacketConn {
|
||||
func (a *authSHA1V4) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn {
|
||||
return c
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ package protocol
|
|||
import (
|
||||
"bytes"
|
||||
"net"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
)
|
||||
|
||||
type origin struct{}
|
||||
|
@ -13,7 +15,7 @@ func newOrigin(b *Base) Protocol { return &origin{} }
|
|||
|
||||
func (o *origin) StreamConn(c net.Conn, iv []byte) net.Conn { return c }
|
||||
|
||||
func (o *origin) PacketConn(c net.PacketConn) net.PacketConn { return c }
|
||||
func (o *origin) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c }
|
||||
|
||||
func (o *origin) Decode(dst, src *bytes.Buffer) error {
|
||||
dst.ReadFrom(src)
|
||||
|
|
|
@ -3,11 +3,12 @@ package protocol
|
|||
import (
|
||||
"net"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
)
|
||||
|
||||
type PacketConn struct {
|
||||
net.PacketConn
|
||||
N.EnhancePacketConn
|
||||
Protocol
|
||||
}
|
||||
|
||||
|
@ -18,12 +19,12 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
_, err = c.PacketConn.WriteTo(buf.Bytes(), addr)
|
||||
_, err = c.EnhancePacketConn.WriteTo(buf.Bytes(), addr)
|
||||
return len(b), err
|
||||
}
|
||||
|
||||
func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, addr, err := c.PacketConn.ReadFrom(b)
|
||||
n, addr, err := c.EnhancePacketConn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return n, addr, err
|
||||
}
|
||||
|
@ -34,3 +35,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||
copy(b, decoded)
|
||||
return len(decoded), addr, nil
|
||||
}
|
||||
|
||||
func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
data, put, addr, err = c.EnhancePacketConn.WaitReadFrom()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data, err = c.DecodePacket(data)
|
||||
if err != nil {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
data = nil
|
||||
put = nil
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import (
|
|||
"fmt"
|
||||
"net"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
|
||||
"github.com/zhangyunhao116/fastrand"
|
||||
)
|
||||
|
||||
|
@ -22,7 +24,7 @@ var (
|
|||
|
||||
type Protocol interface {
|
||||
StreamConn(net.Conn, []byte) net.Conn
|
||||
PacketConn(net.PacketConn) net.PacketConn
|
||||
PacketConn(N.EnhancePacketConn) N.EnhancePacketConn
|
||||
Decode(dst, src *bytes.Buffer) error
|
||||
Encode(buf *bytes.Buffer, b []byte) error
|
||||
DecodePacket([]byte) ([]byte, error)
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"net/http"
|
||||
"sync"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
|
@ -70,7 +71,7 @@ type Trojan struct {
|
|||
hexPassword []byte
|
||||
}
|
||||
|
||||
func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
|
||||
func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error) {
|
||||
alpn := defaultALPN
|
||||
if len(t.option.ALPN) != 0 {
|
||||
alpn = t.option.ALPN
|
||||
|
@ -149,7 +150,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
|
||||
func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) {
|
||||
alpn := defaultWebsocketALPN
|
||||
if len(t.option.ALPN) != 0 {
|
||||
alpn = t.option.ALPN
|
||||
|
@ -162,7 +163,7 @@ func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption)
|
|||
ServerName: t.option.ServerName,
|
||||
}
|
||||
|
||||
return vmess.StreamWebsocketConn(conn, &vmess.WebsocketConfig{
|
||||
return vmess.StreamWebsocketConn(ctx, conn, &vmess.WebsocketConfig{
|
||||
Host: wsOptions.Host,
|
||||
Port: wsOptions.Port,
|
||||
Path: wsOptions.Path,
|
||||
|
@ -303,6 +304,8 @@ func New(option *Option) *Trojan {
|
|||
return &Trojan{option, hexSha224([]byte(option.Password))}
|
||||
}
|
||||
|
||||
var _ N.EnhancePacketConn = (*PacketConn)(nil)
|
||||
|
||||
type PacketConn struct {
|
||||
net.Conn
|
||||
remain int
|
||||
|
@ -350,6 +353,49 @@ func (pc *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||
return n, addr, nil
|
||||
}
|
||||
|
||||
func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
pc.mux.Lock()
|
||||
defer pc.mux.Unlock()
|
||||
|
||||
destination, err := socks5.ReadAddr0(pc.Conn)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
addr = destination.UDPAddr()
|
||||
|
||||
data = pool.Get(pool.UDPBufferSize)
|
||||
put = func() {
|
||||
_ = pool.Put(data)
|
||||
}
|
||||
|
||||
_, err = io.ReadFull(pc.Conn, data[:2+2]) // u16be length + CR LF
|
||||
if err != nil {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
length := binary.BigEndian.Uint16(data)
|
||||
|
||||
if length > 0 {
|
||||
data = data[:length]
|
||||
_, err = io.ReadFull(pc.Conn, data)
|
||||
if err != nil {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
} else {
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
return nil, nil, addr, nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func hexSha224(data []byte) []byte {
|
||||
buf := make([]byte, 56)
|
||||
hash := sha256.New224()
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Dreamacro/clash/common/buf"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
|
@ -289,7 +290,8 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta
|
|||
return nil, err
|
||||
}
|
||||
|
||||
conn := &earlyConn{BufferedConn: N.NewBufferedConn(stream), RequestTimeout: t.RequestTimeout}
|
||||
bufConn := N.NewBufferedConn(stream)
|
||||
conn := &earlyConn{ExtendedConn: bufConn, bufConn: bufConn, RequestTimeout: t.RequestTimeout}
|
||||
if !t.FastOpen {
|
||||
err = conn.Response()
|
||||
if err != nil {
|
||||
|
@ -300,9 +302,10 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta
|
|||
}
|
||||
|
||||
type earlyConn struct {
|
||||
*N.BufferedConn
|
||||
resOnce sync.Once
|
||||
resErr error
|
||||
N.ExtendedConn // only expose standard N.ExtendedConn function to outside
|
||||
bufConn *N.BufferedConn
|
||||
resOnce sync.Once
|
||||
resErr error
|
||||
|
||||
RequestTimeout time.Duration
|
||||
}
|
||||
|
@ -311,7 +314,7 @@ func (conn *earlyConn) response() error {
|
|||
if conn.RequestTimeout > 0 {
|
||||
_ = conn.SetReadDeadline(time.Now().Add(conn.RequestTimeout))
|
||||
}
|
||||
response, err := ReadResponse(conn)
|
||||
response, err := ReadResponse(conn.bufConn)
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
return err
|
||||
|
@ -336,7 +339,7 @@ func (conn *earlyConn) Read(b []byte) (n int, err error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return conn.BufferedConn.Read(b)
|
||||
return conn.bufConn.Read(b)
|
||||
}
|
||||
|
||||
func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) {
|
||||
|
@ -344,7 +347,19 @@ func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.BufferedConn.ReadBuffer(buffer)
|
||||
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
|
||||
}
|
||||
|
||||
func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) {
|
||||
|
|
|
@ -17,17 +17,12 @@ const (
|
|||
InitialMaxDatagramSize = 1252
|
||||
InitialPacketSizeIPv4 = 1252
|
||||
InitialPacketSizeIPv6 = 1232
|
||||
InitialCongestionWindow = 10
|
||||
InitialCongestionWindow = 32
|
||||
DefaultBBRMaxCongestionWindow = 10000
|
||||
)
|
||||
|
||||
const (
|
||||
initialMinCongestionWindow = 4
|
||||
minInitialPacketSize = 1200
|
||||
)
|
||||
|
||||
func GetInitialPacketSize(addr net.Addr) congestion.ByteCount {
|
||||
maxSize := congestion.ByteCount(minInitialPacketSize)
|
||||
maxSize := congestion.ByteCount(1200)
|
||||
// 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 {
|
||||
|
@ -37,7 +32,7 @@ func GetInitialPacketSize(addr net.Addr) congestion.ByteCount {
|
|||
maxSize = InitialPacketSizeIPv6
|
||||
}
|
||||
}
|
||||
return maxSize
|
||||
return congestion.ByteCount(maxSize)
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -45,8 +40,8 @@ var (
|
|||
// Default initial rtt used before any samples are received.
|
||||
InitialRtt = 100 * time.Millisecond
|
||||
|
||||
// The gain used for the STARTUP, equal to 2/ln(2).
|
||||
DefaultHighGain = 2.89
|
||||
// The gain used for the STARTUP, equal to 4*ln(2).
|
||||
DefaultHighGain = 2.77
|
||||
|
||||
// The gain used in STARTUP after loss has been detected.
|
||||
// 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth
|
||||
|
@ -281,7 +276,7 @@ func (b *bbrSender) maxCongestionWindow() congestion.ByteCount {
|
|||
}
|
||||
|
||||
func (b *bbrSender) minCongestionWindow() congestion.ByteCount {
|
||||
return b.maxDatagramSize * initialMinCongestionWindow
|
||||
return b.maxDatagramSize * b.initialCongestionWindow
|
||||
}
|
||||
|
||||
func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) {
|
||||
|
|
|
@ -197,6 +197,21 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err
|
|||
return
|
||||
}
|
||||
|
||||
func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
if q.inputConn != nil {
|
||||
var packet Packet
|
||||
packet, err = ReadPacket(q.inputConn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data = packet.DATA
|
||||
addr = packet.ADDR.UDPAddr()
|
||||
} else {
|
||||
err = net.ErrClosed
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
|
||||
if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize {
|
||||
return 0, quic.ErrMessageTooLarge(q.maxUdpRelayPacketSize)
|
||||
|
|
|
@ -465,6 +465,11 @@ func NewAddress(metadata *C.Metadata) Address {
|
|||
}
|
||||
|
||||
func NewAddressNetAddr(addr net.Addr) (Address, error) {
|
||||
if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok {
|
||||
if addrPort := addr.AddrPort(); addrPort.IsValid() { // sing's M.Socksaddr maybe return an invalid AddrPort if it's a DomainName
|
||||
return NewAddressAddrPort(addrPort), nil
|
||||
}
|
||||
}
|
||||
addrStr := addr.String()
|
||||
if addrPort, err := netip.ParseAddrPort(addrStr); err == nil {
|
||||
return NewAddressAddrPort(addrPort), nil
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package obfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -22,7 +23,7 @@ type Option struct {
|
|||
}
|
||||
|
||||
// NewV2rayObfs return a HTTPObfs
|
||||
func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) {
|
||||
func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, error) {
|
||||
header := http.Header{}
|
||||
for k, v := range option.Headers {
|
||||
header.Add(k, v)
|
||||
|
@ -57,7 +58,7 @@ func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) {
|
|||
}
|
||||
|
||||
var err error
|
||||
conn, err = vmess.StreamWebsocketConn(conn, config)
|
||||
conn, err = vmess.StreamWebsocketConn(ctx, conn, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1,25 +1,18 @@
|
|||
package vless
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
gotls "crypto/tls"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"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/Dreamacro/clash/transport/vless/vision"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
utls "github.com/sagernet/utls"
|
||||
xtls "github.com/xtls/go"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
@ -36,33 +29,10 @@ type Conn struct {
|
|||
handshakeMutex sync.Mutex
|
||||
needHandshake bool
|
||||
err error
|
||||
|
||||
tlsConn net.Conn
|
||||
input *bytes.Reader
|
||||
rawInput *bytes.Buffer
|
||||
|
||||
packetsToFilter int
|
||||
isTLS bool
|
||||
isTLS12orAbove bool
|
||||
enableXTLS bool
|
||||
cipher uint16
|
||||
remainingServerHello uint16
|
||||
readRemainingContent int
|
||||
readRemainingPadding int
|
||||
readProcess bool
|
||||
readFilterUUID bool
|
||||
readLastCommand byte
|
||||
writeFilterApplicationData bool
|
||||
writeDirect bool
|
||||
}
|
||||
|
||||
func (vc *Conn) Read(b []byte) (int, error) {
|
||||
if vc.received {
|
||||
if vc.readProcess {
|
||||
buffer := buf.With(b)
|
||||
err := vc.ReadBuffer(buffer)
|
||||
return buffer.Len(), err
|
||||
}
|
||||
return vc.ExtendedReader.Read(b)
|
||||
}
|
||||
|
||||
|
@ -70,106 +40,11 @@ func (vc *Conn) Read(b []byte) (int, error) {
|
|||
return 0, err
|
||||
}
|
||||
vc.received = true
|
||||
return vc.Read(b)
|
||||
return vc.ExtendedReader.Read(b)
|
||||
}
|
||||
|
||||
func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
||||
if vc.received {
|
||||
toRead := buffer.FreeBytes()
|
||||
if vc.readRemainingContent > 0 {
|
||||
if vc.readRemainingContent < buffer.FreeLen() {
|
||||
toRead = toRead[:vc.readRemainingContent]
|
||||
}
|
||||
n, err := vc.ExtendedReader.Read(toRead)
|
||||
buffer.Truncate(n)
|
||||
vc.readRemainingContent -= n
|
||||
vc.FilterTLS(toRead)
|
||||
return err
|
||||
}
|
||||
if vc.readRemainingPadding > 0 {
|
||||
_, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vc.readRemainingPadding = 0
|
||||
}
|
||||
if vc.readProcess {
|
||||
switch vc.readLastCommand {
|
||||
case commandPaddingContinue:
|
||||
//if vc.isTLS || vc.packetsToFilter > 0 {
|
||||
headerUUIDLen := 0
|
||||
if vc.readFilterUUID {
|
||||
headerUUIDLen = uuid.Size
|
||||
}
|
||||
var header []byte
|
||||
if need := headerUUIDLen + paddingHeaderLen; buffer.FreeLen() < need {
|
||||
header = make([]byte, need)
|
||||
} else {
|
||||
header = buffer.FreeBytes()[:need]
|
||||
}
|
||||
_, err := io.ReadFull(vc.ExtendedReader, header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pos := 0
|
||||
if vc.readFilterUUID {
|
||||
vc.readFilterUUID = false
|
||||
pos = uuid.Size
|
||||
if subtle.ConstantTimeCompare(vc.id.Bytes(), header[:uuid.Size]) != 1 {
|
||||
err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s",
|
||||
uuid.FromBytesOrNil(header[:uuid.Size]).String())
|
||||
log.Errorln(err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
vc.readLastCommand = header[pos]
|
||||
vc.readRemainingContent = int(binary.BigEndian.Uint16(header[pos+1:]))
|
||||
vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[pos+3:]))
|
||||
log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d",
|
||||
vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding)
|
||||
return vc.ReadBuffer(buffer)
|
||||
//}
|
||||
case commandPaddingEnd:
|
||||
vc.readProcess = false
|
||||
return vc.ReadBuffer(buffer)
|
||||
case commandPaddingDirect:
|
||||
needReturn := false
|
||||
if vc.input != nil {
|
||||
_, err := buffer.ReadFrom(vc.input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if vc.input.Len() == 0 {
|
||||
needReturn = true
|
||||
vc.input = nil
|
||||
} else { // buffer is full
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if vc.rawInput != nil {
|
||||
_, err := buffer.ReadFrom(vc.rawInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needReturn = true
|
||||
if vc.rawInput.Len() == 0 {
|
||||
vc.rawInput = nil
|
||||
}
|
||||
}
|
||||
if vc.input == nil && vc.rawInput == nil {
|
||||
vc.readProcess = false
|
||||
vc.ExtendedReader = N.NewExtendedReader(vc.Conn)
|
||||
log.Debugln("XTLS Vision direct read start")
|
||||
}
|
||||
if needReturn {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand)
|
||||
log.Debugln(err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return vc.ExtendedReader.ReadBuffer(buffer)
|
||||
}
|
||||
|
||||
|
@ -177,7 +52,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
|||
return err
|
||||
}
|
||||
vc.received = true
|
||||
return vc.ReadBuffer(buffer)
|
||||
return vc.ExtendedReader.ReadBuffer(buffer)
|
||||
}
|
||||
|
||||
func (vc *Conn) Write(p []byte) (int, error) {
|
||||
|
@ -200,18 +75,6 @@ func (vc *Conn) Write(p []byte) (int, error) {
|
|||
vc.handshakeMutex.Unlock()
|
||||
}
|
||||
|
||||
if vc.writeFilterApplicationData {
|
||||
_buffer := buf.StackNew()
|
||||
defer buf.KeepAlive(_buffer)
|
||||
buffer := buf.Dup(_buffer)
|
||||
defer buffer.Release()
|
||||
buffer.Write(p)
|
||||
err := vc.WriteBuffer(buffer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
return vc.ExtendedWriter.Write(p)
|
||||
}
|
||||
|
||||
|
@ -232,63 +95,6 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error {
|
|||
vc.handshakeMutex.Unlock()
|
||||
}
|
||||
|
||||
if vc.writeFilterApplicationData {
|
||||
buffer2 := ReshapeBuffer(buffer)
|
||||
defer buffer2.Release()
|
||||
vc.FilterTLS(buffer.Bytes())
|
||||
command := commandPaddingContinue
|
||||
if !vc.isTLS {
|
||||
command = commandPaddingEnd
|
||||
|
||||
// disable XTLS
|
||||
//vc.readProcess = false
|
||||
vc.writeFilterApplicationData = false
|
||||
vc.packetsToFilter = 0
|
||||
} else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
|
||||
command = commandPaddingEnd
|
||||
if vc.enableXTLS {
|
||||
command = commandPaddingDirect
|
||||
vc.writeDirect = true
|
||||
}
|
||||
vc.writeFilterApplicationData = false
|
||||
}
|
||||
ApplyPadding(buffer, command, nil, vc.isTLS)
|
||||
err := vc.ExtendedWriter.WriteBuffer(buffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if vc.writeDirect {
|
||||
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
||||
log.Debugln("XTLS Vision direct write start")
|
||||
//time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
if buffer2 != nil {
|
||||
if vc.writeDirect || !vc.isTLS {
|
||||
return vc.ExtendedWriter.WriteBuffer(buffer2)
|
||||
}
|
||||
vc.FilterTLS(buffer2.Bytes())
|
||||
command = commandPaddingContinue
|
||||
if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
|
||||
command = commandPaddingEnd
|
||||
if vc.enableXTLS {
|
||||
command = commandPaddingDirect
|
||||
vc.writeDirect = true
|
||||
}
|
||||
vc.writeFilterApplicationData = false
|
||||
}
|
||||
ApplyPadding(buffer2, command, nil, vc.isTLS)
|
||||
err = vc.ExtendedWriter.WriteBuffer(buffer2)
|
||||
if vc.writeDirect {
|
||||
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
||||
log.Debugln("XTLS Vision direct write start")
|
||||
//time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
/*if vc.writeDirect {
|
||||
log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len())
|
||||
}*/
|
||||
return vc.ExtendedWriter.WriteBuffer(buffer)
|
||||
}
|
||||
|
||||
|
@ -300,10 +106,9 @@ func (vc *Conn) sendRequest(p []byte) bool {
|
|||
return true
|
||||
}
|
||||
}
|
||||
isVision := vc.IsXTLSVisionEnabled()
|
||||
|
||||
var buffer *buf.Buffer
|
||||
if isVision {
|
||||
if vc.IsXTLSVisionEnabled() {
|
||||
_buffer := buf.StackNew()
|
||||
defer buf.KeepAlive(_buffer)
|
||||
buffer = buf.Dup(_buffer)
|
||||
|
@ -350,50 +155,14 @@ func (vc *Conn) sendRequest(p []byte) bool {
|
|||
)
|
||||
}
|
||||
|
||||
if isVision && !vc.dst.UDP && !vc.dst.Mux {
|
||||
if len(p) == 0 {
|
||||
WriteWithPadding(buffer, nil, commandPaddingContinue, vc.id, vc.isTLS)
|
||||
} else {
|
||||
vc.FilterTLS(p)
|
||||
//if vc.isTLS {
|
||||
WriteWithPadding(buffer, p, commandPaddingContinue, vc.id, vc.isTLS)
|
||||
//} else {
|
||||
// buf.Must(buf.Error(buffer.Write(p)))
|
||||
//
|
||||
// // disable XTLS
|
||||
// vc.readProcess = false
|
||||
// vc.writeFilterApplicationData = false
|
||||
// vc.packetsToFilter = 0
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
buf.Must(buf.Error(buffer.Write(p)))
|
||||
}
|
||||
buf.Must(buf.Error(buffer.Write(p)))
|
||||
|
||||
_, vc.err = vc.ExtendedWriter.Write(buffer.Bytes())
|
||||
if vc.err != nil {
|
||||
return true
|
||||
}
|
||||
if isVision {
|
||||
switch underlying := vc.tlsConn.(type) {
|
||||
case *gotls.Conn:
|
||||
if underlying.ConnectionState().Version != gotls.VersionTLS13 {
|
||||
vc.err = ErrNotTLS13
|
||||
}
|
||||
case *utls.UConn:
|
||||
if underlying.ConnectionState().Version != utls.VersionTLS13 {
|
||||
vc.err = ErrNotTLS13
|
||||
}
|
||||
default:
|
||||
vc.err = fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, vc.addons.Flow)
|
||||
}
|
||||
vc.tlsConn = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (vc *Conn) recvResponse() error {
|
||||
var buffer [1]byte
|
||||
var buffer [2]byte
|
||||
_, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:])
|
||||
if vc.err != nil {
|
||||
return vc.err
|
||||
|
@ -403,12 +172,7 @@ func (vc *Conn) recvResponse() error {
|
|||
return errors.New("unexpected response version")
|
||||
}
|
||||
|
||||
_, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:])
|
||||
if vc.err != nil {
|
||||
return vc.err
|
||||
}
|
||||
|
||||
length := int64(buffer[0])
|
||||
length := int64(buffer[1])
|
||||
if length != 0 { // addon data length > 0
|
||||
io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard
|
||||
}
|
||||
|
@ -416,18 +180,8 @@ func (vc *Conn) recvResponse() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (vc *Conn) FrontHeadroom() int {
|
||||
if vc.IsXTLSVisionEnabled() {
|
||||
return paddingHeaderLen
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (vc *Conn) Upstream() any {
|
||||
if vc.tlsConn == nil {
|
||||
return vc.Conn
|
||||
}
|
||||
return vc.tlsConn
|
||||
return vc.Conn
|
||||
}
|
||||
|
||||
func (vc *Conn) NeedHandshake() bool {
|
||||
|
@ -439,7 +193,7 @@ func (vc *Conn) IsXTLSVisionEnabled() bool {
|
|||
}
|
||||
|
||||
// newConn return a Conn instance
|
||||
func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) {
|
||||
func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) {
|
||||
c := &Conn{
|
||||
ExtendedReader: N.NewExtendedReader(conn),
|
||||
ExtendedWriter: N.NewExtendedWriter(conn),
|
||||
|
@ -468,43 +222,12 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) {
|
|||
return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow)
|
||||
}
|
||||
case XRV:
|
||||
c.packetsToFilter = 6
|
||||
c.readProcess = true
|
||||
c.readFilterUUID = true
|
||||
c.writeFilterApplicationData = true
|
||||
c.addons = client.Addons
|
||||
var t reflect.Type
|
||||
var p uintptr
|
||||
switch underlying := conn.(type) {
|
||||
case *gotls.Conn:
|
||||
//log.Debugln("type tls")
|
||||
c.Conn = underlying.NetConn()
|
||||
c.tlsConn = underlying
|
||||
t = reflect.TypeOf(underlying).Elem()
|
||||
p = uintptr(unsafe.Pointer(underlying))
|
||||
case *utls.UConn:
|
||||
//log.Debugln("type *utls.UConn")
|
||||
c.Conn = underlying.NetConn()
|
||||
c.tlsConn = underlying
|
||||
t = reflect.TypeOf(underlying.Conn).Elem()
|
||||
p = uintptr(unsafe.Pointer(underlying.Conn))
|
||||
case *tlsC.UConn:
|
||||
//log.Debugln("type *tlsC.UConn")
|
||||
c.Conn = underlying.NetConn()
|
||||
c.tlsConn = underlying.UConn
|
||||
t = reflect.TypeOf(underlying.Conn).Elem()
|
||||
//log.Debugln("t:%v", t)
|
||||
p = uintptr(unsafe.Pointer(underlying.Conn))
|
||||
default:
|
||||
return nil, fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, client.Addons.Flow)
|
||||
visionConn, err := vision.NewConn(c, c.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i, _ := t.FieldByName("input")
|
||||
r, _ := t.FieldByName("rawInput")
|
||||
c.input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset))
|
||||
c.rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset))
|
||||
//if _, ok := c.Conn.(*net.TCPConn); !ok {
|
||||
// log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn)
|
||||
//}
|
||||
c.addons = client.Addons
|
||||
return visionConn, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
304
transport/vless/vision/conn.go
Normal file
304
transport/vless/vision/conn.go
Normal file
|
@ -0,0 +1,304 @@
|
|||
package vision
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/subtle"
|
||||
gotls "crypto/tls"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
|
||||
"github.com/Dreamacro/clash/common/buf"
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
utls "github.com/sagernet/utls"
|
||||
)
|
||||
|
||||
var (
|
||||
_ N.ExtendedConn = (*Conn)(nil)
|
||||
)
|
||||
|
||||
type Conn struct {
|
||||
net.Conn
|
||||
N.ExtendedReader
|
||||
N.ExtendedWriter
|
||||
upstream net.Conn
|
||||
userUUID *uuid.UUID
|
||||
|
||||
tlsConn net.Conn
|
||||
input *bytes.Reader
|
||||
rawInput *bytes.Buffer
|
||||
|
||||
needHandshake bool
|
||||
packetsToFilter int
|
||||
isTLS bool
|
||||
isTLS12orAbove bool
|
||||
enableXTLS bool
|
||||
cipher uint16
|
||||
remainingServerHello uint16
|
||||
readRemainingContent int
|
||||
readRemainingPadding int
|
||||
readProcess bool
|
||||
readFilterUUID bool
|
||||
readLastCommand byte
|
||||
writeFilterApplicationData bool
|
||||
writeDirect bool
|
||||
}
|
||||
|
||||
func (vc *Conn) Read(b []byte) (int, error) {
|
||||
if vc.readProcess {
|
||||
buffer := buf.With(b)
|
||||
err := vc.ReadBuffer(buffer)
|
||||
return buffer.Len(), err
|
||||
}
|
||||
return vc.ExtendedReader.Read(b)
|
||||
}
|
||||
|
||||
func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error {
|
||||
toRead := buffer.FreeBytes()
|
||||
if vc.readRemainingContent > 0 {
|
||||
if vc.readRemainingContent < buffer.FreeLen() {
|
||||
toRead = toRead[:vc.readRemainingContent]
|
||||
}
|
||||
n, err := vc.ExtendedReader.Read(toRead)
|
||||
buffer.Truncate(n)
|
||||
vc.readRemainingContent -= n
|
||||
vc.FilterTLS(toRead)
|
||||
return err
|
||||
}
|
||||
if vc.readRemainingPadding > 0 {
|
||||
_, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
vc.readRemainingPadding = 0
|
||||
}
|
||||
if vc.readProcess {
|
||||
switch vc.readLastCommand {
|
||||
case commandPaddingContinue:
|
||||
//if vc.isTLS || vc.packetsToFilter > 0 {
|
||||
headerUUIDLen := 0
|
||||
if vc.readFilterUUID {
|
||||
headerUUIDLen = uuid.Size
|
||||
}
|
||||
var header []byte
|
||||
if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need {
|
||||
header = make([]byte, need)
|
||||
} else {
|
||||
header = buffer.FreeBytes()[:need]
|
||||
}
|
||||
_, err := io.ReadFull(vc.ExtendedReader, header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if vc.readFilterUUID {
|
||||
vc.readFilterUUID = false
|
||||
if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 {
|
||||
err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s",
|
||||
uuid.FromBytesOrNil(header[:uuid.Size]).String())
|
||||
log.Errorln(err.Error())
|
||||
return err
|
||||
}
|
||||
header = header[uuid.Size:]
|
||||
}
|
||||
vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[3:]))
|
||||
vc.readRemainingContent = int(binary.BigEndian.Uint16(header[1:]))
|
||||
vc.readLastCommand = header[0]
|
||||
log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d",
|
||||
vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding)
|
||||
return vc.ReadBuffer(buffer)
|
||||
//}
|
||||
case commandPaddingEnd:
|
||||
vc.readProcess = false
|
||||
return vc.ReadBuffer(buffer)
|
||||
case commandPaddingDirect:
|
||||
needReturn := false
|
||||
if vc.input != nil {
|
||||
_, err := buffer.ReadFrom(vc.input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if vc.input.Len() == 0 {
|
||||
needReturn = true
|
||||
vc.input = nil
|
||||
} else { // buffer is full
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if vc.rawInput != nil {
|
||||
_, err := buffer.ReadFrom(vc.rawInput)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
needReturn = true
|
||||
if vc.rawInput.Len() == 0 {
|
||||
vc.rawInput = nil
|
||||
}
|
||||
}
|
||||
if vc.input == nil && vc.rawInput == nil {
|
||||
vc.readProcess = false
|
||||
vc.ExtendedReader = N.NewExtendedReader(vc.Conn)
|
||||
log.Debugln("XTLS Vision direct read start")
|
||||
}
|
||||
if needReturn {
|
||||
return nil
|
||||
}
|
||||
default:
|
||||
err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand)
|
||||
log.Debugln(err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return vc.ExtendedReader.ReadBuffer(buffer)
|
||||
}
|
||||
|
||||
func (vc *Conn) Write(p []byte) (int, error) {
|
||||
if vc.writeFilterApplicationData {
|
||||
_buffer := buf.StackNew()
|
||||
defer buf.KeepAlive(_buffer)
|
||||
buffer := buf.Dup(_buffer)
|
||||
defer buffer.Release()
|
||||
buffer.Write(p)
|
||||
err := vc.WriteBuffer(buffer)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
return vc.ExtendedWriter.Write(p)
|
||||
}
|
||||
|
||||
func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) {
|
||||
if vc.needHandshake {
|
||||
vc.needHandshake = false
|
||||
if buffer.IsEmpty() {
|
||||
ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, false)
|
||||
} else {
|
||||
vc.FilterTLS(buffer.Bytes())
|
||||
ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, vc.isTLS)
|
||||
}
|
||||
err = vc.ExtendedWriter.WriteBuffer(buffer)
|
||||
if err != nil {
|
||||
buffer.Release()
|
||||
return err
|
||||
}
|
||||
switch underlying := vc.tlsConn.(type) {
|
||||
case *gotls.Conn:
|
||||
if underlying.ConnectionState().Version != gotls.VersionTLS13 {
|
||||
buffer.Release()
|
||||
return ErrNotTLS13
|
||||
}
|
||||
case *utls.UConn:
|
||||
if underlying.ConnectionState().Version != utls.VersionTLS13 {
|
||||
buffer.Release()
|
||||
return ErrNotTLS13
|
||||
}
|
||||
}
|
||||
vc.tlsConn = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
if vc.writeFilterApplicationData {
|
||||
buffer2 := ReshapeBuffer(buffer)
|
||||
defer buffer2.Release()
|
||||
vc.FilterTLS(buffer.Bytes())
|
||||
command := commandPaddingContinue
|
||||
if !vc.isTLS {
|
||||
command = commandPaddingEnd
|
||||
|
||||
// disable XTLS
|
||||
//vc.readProcess = false
|
||||
vc.writeFilterApplicationData = false
|
||||
vc.packetsToFilter = 0
|
||||
} else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
|
||||
command = commandPaddingEnd
|
||||
if vc.enableXTLS {
|
||||
command = commandPaddingDirect
|
||||
vc.writeDirect = true
|
||||
}
|
||||
vc.writeFilterApplicationData = false
|
||||
}
|
||||
ApplyPadding(buffer, command, nil, vc.isTLS)
|
||||
err = vc.ExtendedWriter.WriteBuffer(buffer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if vc.writeDirect {
|
||||
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
||||
log.Debugln("XTLS Vision direct write start")
|
||||
//time.Sleep(5 * time.Millisecond)
|
||||
}
|
||||
if buffer2 != nil {
|
||||
if vc.writeDirect || !vc.isTLS {
|
||||
return vc.ExtendedWriter.WriteBuffer(buffer2)
|
||||
}
|
||||
vc.FilterTLS(buffer2.Bytes())
|
||||
command = commandPaddingContinue
|
||||
if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 {
|
||||
command = commandPaddingEnd
|
||||
if vc.enableXTLS {
|
||||
command = commandPaddingDirect
|
||||
vc.writeDirect = true
|
||||
}
|
||||
vc.writeFilterApplicationData = false
|
||||
}
|
||||
ApplyPadding(buffer2, command, nil, vc.isTLS)
|
||||
err = vc.ExtendedWriter.WriteBuffer(buffer2)
|
||||
if vc.writeDirect {
|
||||
vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn)
|
||||
log.Debugln("XTLS Vision direct write start")
|
||||
//time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
/*if vc.writeDirect {
|
||||
log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len())
|
||||
}*/
|
||||
return vc.ExtendedWriter.WriteBuffer(buffer)
|
||||
}
|
||||
|
||||
func (vc *Conn) FrontHeadroom() int {
|
||||
if vc.readFilterUUID {
|
||||
return PaddingHeaderLen
|
||||
}
|
||||
return PaddingHeaderLen - uuid.Size
|
||||
}
|
||||
|
||||
func (vc *Conn) NeedHandshake() bool {
|
||||
return vc.needHandshake
|
||||
}
|
||||
|
||||
func (vc *Conn) Upstream() any {
|
||||
if vc.writeDirect ||
|
||||
vc.readLastCommand == commandPaddingDirect {
|
||||
return vc.Conn
|
||||
}
|
||||
return vc.upstream
|
||||
}
|
||||
|
||||
func (vc *Conn) ReaderPossiblyReplaceable() bool {
|
||||
return vc.readProcess
|
||||
}
|
||||
|
||||
func (vc *Conn) ReaderReplaceable() bool {
|
||||
if !vc.readProcess &&
|
||||
vc.readLastCommand == commandPaddingDirect {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (vc *Conn) WriterPossiblyReplaceable() bool {
|
||||
return vc.writeFilterApplicationData
|
||||
}
|
||||
|
||||
func (vc *Conn) WriterReplaceable() bool {
|
||||
if vc.writeDirect {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package vless
|
||||
package vision
|
||||
|
||||
import (
|
||||
"bytes"
|
|
@ -1,4 +1,4 @@
|
|||
package vless
|
||||
package vision
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
@ -12,7 +12,7 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
paddingHeaderLen = 1 + 2 + 2 // =5
|
||||
PaddingHeaderLen = uuid.Size + 1 + 2 + 2 // =21
|
||||
|
||||
commandPaddingContinue byte = 0x00
|
||||
commandPaddingEnd byte = 0x01
|
||||
|
@ -67,7 +67,7 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding
|
|||
}
|
||||
|
||||
func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer {
|
||||
if buffer.Len() <= buf.BufferSize-paddingHeaderLen {
|
||||
if buffer.Len() <= buf.BufferSize-PaddingHeaderLen {
|
||||
return nil
|
||||
}
|
||||
cutAt := bytes.LastIndex(buffer.Bytes(), tlsApplicationDataStart)
|
70
transport/vless/vision/vision.go
Normal file
70
transport/vless/vision/vision.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
// Package vision implements VLESS flow `xtls-rprx-vision` introduced by Xray-core.
|
||||
package vision
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
gotls "crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||
|
||||
"github.com/gofrs/uuid/v5"
|
||||
"github.com/sagernet/sing/common"
|
||||
utls "github.com/sagernet/utls"
|
||||
)
|
||||
|
||||
var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection")
|
||||
|
||||
type connWithUpstream interface {
|
||||
net.Conn
|
||||
common.WithUpstream
|
||||
}
|
||||
|
||||
func NewConn(conn connWithUpstream, userUUID *uuid.UUID) (*Conn, error) {
|
||||
c := &Conn{
|
||||
ExtendedReader: N.NewExtendedReader(conn),
|
||||
ExtendedWriter: N.NewExtendedWriter(conn),
|
||||
upstream: conn,
|
||||
userUUID: userUUID,
|
||||
packetsToFilter: 6,
|
||||
needHandshake: true,
|
||||
readProcess: true,
|
||||
readFilterUUID: true,
|
||||
writeFilterApplicationData: true,
|
||||
}
|
||||
var t reflect.Type
|
||||
var p unsafe.Pointer
|
||||
switch underlying := conn.Upstream().(type) {
|
||||
case *gotls.Conn:
|
||||
//log.Debugln("type tls")
|
||||
c.Conn = underlying.NetConn()
|
||||
c.tlsConn = underlying
|
||||
t = reflect.TypeOf(underlying).Elem()
|
||||
p = unsafe.Pointer(underlying)
|
||||
case *utls.UConn:
|
||||
//log.Debugln("type *utls.UConn")
|
||||
c.Conn = underlying.NetConn()
|
||||
c.tlsConn = underlying
|
||||
t = reflect.TypeOf(underlying.Conn).Elem()
|
||||
p = unsafe.Pointer(underlying.Conn)
|
||||
case *tlsC.UConn:
|
||||
//log.Debugln("type *tlsC.UConn")
|
||||
c.Conn = underlying.NetConn()
|
||||
c.tlsConn = underlying.UConn
|
||||
t = reflect.TypeOf(underlying.Conn).Elem()
|
||||
//log.Debugln("t:%v", t)
|
||||
p = unsafe.Pointer(underlying.Conn)
|
||||
default:
|
||||
return nil, fmt.Errorf(`failed to use vision, maybe "security" is not "tls" or "utls"`)
|
||||
}
|
||||
i, _ := t.FieldByName("input")
|
||||
r, _ := t.FieldByName("rawInput")
|
||||
c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset))
|
||||
c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset))
|
||||
return c, nil
|
||||
}
|
|
@ -2,18 +2,12 @@ package vless
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
xtls "github.com/xtls/go"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection")
|
||||
)
|
||||
|
||||
type XTLSConfig struct {
|
||||
Host string
|
||||
SkipCertVerify bool
|
||||
|
@ -21,7 +15,7 @@ type XTLSConfig struct {
|
|||
NextProtos []string
|
||||
}
|
||||
|
||||
func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) {
|
||||
func StreamXTLSConn(ctx context.Context, conn net.Conn, cfg *XTLSConfig) (net.Conn, error) {
|
||||
xtlsConfig := &xtls.Config{
|
||||
ServerName: cfg.Host,
|
||||
InsecureSkipVerify: cfg.SkipCertVerify,
|
||||
|
@ -38,9 +32,6 @@ func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) {
|
|||
|
||||
xtlsConn := xtls.Client(conn, xtlsConfig)
|
||||
|
||||
// fix xtls handshake not timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
err := xtlsConn.HandshakeContext(ctx)
|
||||
return xtlsConn, err
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"net"
|
||||
|
||||
tlsC "github.com/Dreamacro/clash/component/tls"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
)
|
||||
|
||||
type TLSConfig struct {
|
||||
|
@ -19,7 +18,7 @@ type TLSConfig struct {
|
|||
Reality *tlsC.RealityConfig
|
||||
}
|
||||
|
||||
func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
||||
func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
||||
tlsConfig := &tls.Config{
|
||||
ServerName: cfg.Host,
|
||||
InsecureSkipVerify: cfg.SkipCertVerify,
|
||||
|
@ -39,15 +38,10 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
|||
if cfg.Reality == nil {
|
||||
utlsConn, valid := GetUTLSConn(conn, cfg.ClientFingerprint, tlsConfig)
|
||||
if valid {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx)
|
||||
return utlsConn, err
|
||||
}
|
||||
} else {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
return tlsC.GetRealityConn(ctx, conn, cfg.ClientFingerprint, tlsConfig, cfg.Reality)
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +51,6 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) {
|
|||
|
||||
tlsConn := tls.Client(conn, tlsConfig)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout)
|
||||
defer cancel()
|
||||
|
||||
err := tlsConn.HandshakeContext(ctx)
|
||||
return tlsConn, err
|
||||
}
|
||||
|
|
|
@ -194,17 +194,17 @@ func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error {
|
|||
|
||||
earlyDataBuf := bytes.NewBuffer(earlyData)
|
||||
if _, err := base64EarlyDataEncoder.Write(earlyDataBuf.Next(wsedc.config.MaxEarlyData)); err != nil {
|
||||
return errors.New("failed to encode early data: " + err.Error())
|
||||
return fmt.Errorf("failed to encode early data: %w", err)
|
||||
}
|
||||
|
||||
if errc := base64EarlyDataEncoder.Close(); errc != nil {
|
||||
return errors.New("failed to encode early data tail: " + errc.Error())
|
||||
return fmt.Errorf("failed to encode early data tail: %w", errc)
|
||||
}
|
||||
|
||||
var err error
|
||||
if wsedc.Conn, err = streamWebsocketConn(wsedc.underlay, wsedc.config, base64DataBuf); err != nil {
|
||||
if wsedc.Conn, err = streamWebsocketConn(wsedc.ctx, wsedc.underlay, wsedc.config, base64DataBuf); err != nil {
|
||||
wsedc.Close()
|
||||
return errors.New("failed to dial WebSocket: " + err.Error())
|
||||
return fmt.Errorf("failed to dial WebSocket: %w", err)
|
||||
}
|
||||
|
||||
wsedc.dialed <- true
|
||||
|
@ -340,7 +340,7 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co
|
|||
return N.NewDeadlineConn(conn), nil
|
||||
}
|
||||
|
||||
func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) {
|
||||
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) {
|
||||
|
@ -396,13 +396,13 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf
|
|||
}
|
||||
}
|
||||
|
||||
wsConn, resp, err := dialer.Dial(uri.String(), headers)
|
||||
wsConn, resp, err := dialer.DialContext(ctx, uri.String(), headers)
|
||||
if err != nil {
|
||||
reason := err.Error()
|
||||
reason := err
|
||||
if resp != nil {
|
||||
reason = resp.Status
|
||||
reason = errors.New(resp.Status)
|
||||
}
|
||||
return nil, fmt.Errorf("dial %s error: %s", uri.Host, reason)
|
||||
return nil, fmt.Errorf("dial %s error: %w", uri.Host, reason)
|
||||
}
|
||||
|
||||
conn = &websocketConn{
|
||||
|
@ -417,7 +417,7 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf
|
|||
return N.NewDeadlineConn(conn), nil
|
||||
}
|
||||
|
||||
func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
|
||||
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") != "" {
|
||||
if ed, err := strconv.Atoi(q.Get("ed")); err == nil {
|
||||
|
@ -434,5 +434,5 @@ func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) {
|
|||
return streamWebsocketWithEarlyDataConn(conn, c)
|
||||
}
|
||||
|
||||
return streamWebsocketConn(conn, c, nil)
|
||||
return streamWebsocketConn(ctx, conn, c, nil)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"time"
|
||||
|
||||
N "github.com/Dreamacro/clash/common/net"
|
||||
"github.com/Dreamacro/clash/common/pool"
|
||||
C "github.com/Dreamacro/clash/constant"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
)
|
||||
|
@ -27,34 +26,43 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, fAddr netip.Addr) {
|
||||
buf := pool.Get(pool.UDPBufferSize)
|
||||
func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oAddrPort netip.AddrPort, fAddr netip.Addr) {
|
||||
defer func() {
|
||||
_ = pc.Close()
|
||||
closeAllLocalCoon(key)
|
||||
natTable.Delete(key)
|
||||
_ = pool.Put(buf)
|
||||
}()
|
||||
|
||||
for {
|
||||
_ = pc.SetReadDeadline(time.Now().Add(udpTimeout))
|
||||
n, from, err := pc.ReadFrom(buf)
|
||||
data, put, from, err := pc.WaitReadFrom()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fromUDPAddr := from.(*net.UDPAddr)
|
||||
_fromUDPAddr := *fromUDPAddr
|
||||
fromUDPAddr = &_fromUDPAddr // make a copy
|
||||
if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok {
|
||||
if fAddr.IsValid() && (oAddr.Unmap() == fromAddr.Unmap()) {
|
||||
fromUDPAddr.IP = fAddr.Unmap().AsSlice()
|
||||
} else {
|
||||
fromUDPAddr.IP = fromAddr.Unmap().AsSlice()
|
||||
fromUDPAddr, isUDPAddr := from.(*net.UDPAddr)
|
||||
if isUDPAddr {
|
||||
_fromUDPAddr := *fromUDPAddr
|
||||
fromUDPAddr = &_fromUDPAddr // make a copy
|
||||
if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok {
|
||||
fromAddr = fromAddr.Unmap()
|
||||
if fAddr.IsValid() && (oAddrPort.Addr() == fromAddr) { // oAddrPort was Unmapped
|
||||
fromAddr = fAddr.Unmap()
|
||||
}
|
||||
fromUDPAddr.IP = fromAddr.AsSlice()
|
||||
if fromAddr.Is4() {
|
||||
fromUDPAddr.Zone = "" // only ipv6 can have the zone
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fromUDPAddr = net.UDPAddrFromAddrPort(oAddrPort) // oAddrPort was Unmapped
|
||||
log.Warnln("server return a [%T](%s) which isn't a *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server", from, from, oAddrPort)
|
||||
}
|
||||
|
||||
_, err = packet.WriteBack(buf[:n], fromUDPAddr)
|
||||
_, err = packet.WriteBack(data, fromUDPAddr)
|
||||
if put != nil {
|
||||
put()
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -186,6 +186,16 @@ func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||
return n, addr, err
|
||||
}
|
||||
|
||||
func (ut *udpTracker) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) {
|
||||
data, put, addr, err = ut.PacketConn.WaitReadFrom()
|
||||
download := int64(len(data))
|
||||
if ut.pushToManager {
|
||||
ut.manager.PushDownloaded(download)
|
||||
}
|
||||
ut.DownloadTotal.Add(download)
|
||||
return
|
||||
}
|
||||
|
||||
func (ut *udpTracker) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||
n, err := ut.PacketConn.WriteTo(b, addr)
|
||||
upload := int64(n)
|
||||
|
@ -201,6 +211,10 @@ func (ut *udpTracker) Close() error {
|
|||
return ut.PacketConn.Close()
|
||||
}
|
||||
|
||||
func (ut *udpTracker) Upstream() any {
|
||||
return ut.PacketConn
|
||||
}
|
||||
|
||||
func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker {
|
||||
metadata.RemoteDst = parseRemoteDestination(nil, conn)
|
||||
|
||||
|
|
|
@ -383,10 +383,10 @@ func handleUDPConn(packet C.PacketAdapter) {
|
|||
log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress())
|
||||
}
|
||||
|
||||
oAddr := metadata.DstIP
|
||||
oAddrPort := metadata.AddrPort()
|
||||
natTable.Set(key, pc)
|
||||
|
||||
go handleUDPToLocal(packet, pc, key, oAddr, fAddr)
|
||||
go handleUDPToLocal(packet, pc, key, oAddrPort, fAddr)
|
||||
|
||||
handle()
|
||||
}()
|
||||
|
|
Loading…
Reference in a new issue