├── .github ├── update_dependencies.sh └── workflows │ ├── debug.yml │ └── lint.yml ├── .gitignore ├── .golangci.yml ├── LICENSE ├── Makefile ├── README.md ├── cipher ├── errors.go ├── method.go ├── method_none.go ├── method_none_wait.go └── method_registry.go ├── go.mod ├── go.sum ├── internal ├── legacykey │ └── key.go └── shadowio │ ├── common.go │ ├── reader.go │ └── writer.go ├── shadowaead ├── method.go ├── method_wait.go └── protocol.go ├── shadowaead_2022 ├── method.go ├── method_wait.go ├── protocol.go ├── slidingwindow.go ├── xor.go └── xor_go119.go ├── shadowsocks.go └── shadowstream └── method.go /.github/update_dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PROJECTS=$(dirname "$0")/../.. 4 | 5 | go get -x github.com/sagernet/sing@$(git -C $PROJECTS/sing rev-parse HEAD) 6 | go mod tidy 7 | -------------------------------------------------------------------------------- /.github/workflows/debug.yml: -------------------------------------------------------------------------------- 1 | name: Debug build 2 | 3 | on: 4 | push: 5 | branches: 6 | - dev 7 | paths-ignore: 8 | - '**.md' 9 | - '.github/**' 10 | - '!.github/workflows/debug.yml' 11 | pull_request: 12 | branches: 13 | - dev 14 | 15 | jobs: 16 | build: 17 | name: Debug build 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v3 22 | with: 23 | fetch-depth: 0 24 | - name: Get latest go version 25 | id: version 26 | run: | 27 | echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') 28 | - name: Setup Go 29 | uses: actions/setup-go@v3 30 | with: 31 | go-version: ${{ steps.version.outputs.go_version }} 32 | - name: Add cache to Go proxy 33 | run: | 34 | version=`git rev-parse HEAD` 35 | mkdir build 36 | pushd build 37 | go mod init build 38 | go get -v github.com/sagernet/sing-shadowsocks2@$version 39 | popd 40 | continue-on-error: true 41 | - name: Build 42 | run: | 43 | make test 44 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: 6 | - dev 7 | paths-ignore: 8 | - '**.md' 9 | - '.github/**' 10 | - '!.github/workflows/lint.yml' 11 | pull_request: 12 | branches: 13 | - dev 14 | 15 | jobs: 16 | build: 17 | name: Build 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v3 22 | with: 23 | fetch-depth: 0 24 | - name: Get latest go version 25 | id: version 26 | run: | 27 | echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') 28 | - name: Setup Go 29 | uses: actions/setup-go@v3 30 | with: 31 | go-version: ${{ steps.version.outputs.go_version }} 32 | - name: Cache go module 33 | uses: actions/cache@v3 34 | with: 35 | path: | 36 | ~/go/pkg/mod 37 | key: go-${{ hashFiles('**/go.sum') }} 38 | - name: golangci-lint 39 | uses: golangci/golangci-lint-action@v3 40 | with: 41 | version: latest -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /vendor/ 3 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | disable-all: true 3 | enable: 4 | - gofumpt 5 | - govet 6 | - gci 7 | - staticcheck 8 | 9 | linters-settings: 10 | gci: 11 | custom-order: true 12 | sections: 13 | - standard 14 | - prefix(github.com/sagernet/) 15 | - default 16 | staticcheck: 17 | go: '1.20' 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2022 by nekohasekai 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | fmt: 2 | @gofumpt -l -w . 3 | @gofmt -s -w . 4 | @gci write --custom-order -s standard -s "prefix(github.com/sagernet/)" -s "default" . 5 | 6 | fmt_install: 7 | go install -v mvdan.cc/gofumpt@latest 8 | go install -v github.com/daixiang0/gci@latest 9 | 10 | lint: 11 | GOOS=linux golangci-lint run ./... 12 | GOOS=android golangci-lint run ./... 13 | GOOS=windows golangci-lint run ./... 14 | GOOS=darwin golangci-lint run ./... 15 | GOOS=freebsd golangci-lint run ./... 16 | 17 | lint_install: 18 | go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest 19 | 20 | test: 21 | go test -v ./... -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sing-shadowsocks2 2 | 3 | Yet another shadowsocks implementation. 4 | 5 | TODO: 6 | 7 | * [x] Client 8 | * [ ] Server 9 | -------------------------------------------------------------------------------- /cipher/errors.go: -------------------------------------------------------------------------------- 1 | package cipher 2 | 3 | import E "github.com/sagernet/sing/common/exceptions" 4 | 5 | var ( 6 | ErrMissingPassword = E.New("missing password") 7 | ErrPacketTooShort = E.New("packet too short") 8 | ) 9 | -------------------------------------------------------------------------------- /cipher/method.go: -------------------------------------------------------------------------------- 1 | package cipher 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | M "github.com/sagernet/sing/common/metadata" 8 | N "github.com/sagernet/sing/common/network" 9 | ) 10 | 11 | type Method interface { 12 | DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) 13 | DialEarlyConn(conn net.Conn, destination M.Socksaddr) net.Conn 14 | DialPacketConn(conn net.Conn) N.NetPacketConn 15 | } 16 | 17 | type MethodOptions struct { 18 | Password string 19 | Key []byte 20 | KeyList [][]byte 21 | } 22 | 23 | type MethodCreator func(ctx context.Context, methodName string, options MethodOptions) (Method, error) 24 | -------------------------------------------------------------------------------- /cipher/method_none.go: -------------------------------------------------------------------------------- 1 | package cipher 2 | 3 | import ( 4 | "context" 5 | "net" 6 | 7 | "github.com/sagernet/sing/common" 8 | "github.com/sagernet/sing/common/buf" 9 | "github.com/sagernet/sing/common/bufio" 10 | M "github.com/sagernet/sing/common/metadata" 11 | N "github.com/sagernet/sing/common/network" 12 | ) 13 | 14 | const MethodNone = "none" 15 | 16 | func init() { 17 | RegisterMethod([]string{MethodNone}, func(ctx context.Context, method string, options MethodOptions) (Method, error) { 18 | return &noneMethod{}, nil 19 | }) 20 | } 21 | 22 | var _ Method = (*noneMethod)(nil) 23 | 24 | type noneMethod struct{} 25 | 26 | func (m *noneMethod) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) { 27 | err := M.SocksaddrSerializer.WriteAddrPort(conn, destination) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return conn, nil 32 | } 33 | 34 | func (m *noneMethod) DialEarlyConn(conn net.Conn, destination M.Socksaddr) net.Conn { 35 | return &noneConn{ 36 | ExtendedConn: bufio.NewExtendedConn(conn), 37 | destination: destination, 38 | } 39 | } 40 | 41 | func (m *noneMethod) DialPacketConn(conn net.Conn) N.NetPacketConn { 42 | extendedConn := bufio.NewExtendedConn(conn) 43 | return &nonePacketConn{extendedConn, extendedConn} 44 | } 45 | 46 | var ( 47 | _ N.ExtendedConn = (*noneConn)(nil) 48 | _ N.FrontHeadroom = (*noneConn)(nil) 49 | _ N.ReaderWithUpstream = (*noneConn)(nil) 50 | _ N.WriterWithUpstream = (*noneConn)(nil) 51 | _ common.WithUpstream = (*noneConn)(nil) 52 | ) 53 | 54 | type noneConn struct { 55 | N.ExtendedConn 56 | destination M.Socksaddr 57 | requestWritten bool 58 | } 59 | 60 | func (c *noneConn) Write(p []byte) (n int, err error) { 61 | if !c.requestWritten { 62 | buffer := buf.NewSize(M.SocksaddrSerializer.AddrPortLen(c.destination) + len(p)) 63 | defer buffer.Release() 64 | err = M.SocksaddrSerializer.WriteAddrPort(buffer, c.destination) 65 | if err != nil { 66 | return 67 | } 68 | common.Must1(buffer.Write(p)) 69 | _, err = c.ExtendedConn.Write(buffer.Bytes()) 70 | if err != nil { 71 | return 72 | } 73 | c.requestWritten = true 74 | n = len(p) 75 | return 76 | } 77 | return c.ExtendedConn.Write(p) 78 | } 79 | 80 | func (c *noneConn) WriteBuffer(buffer *buf.Buffer) error { 81 | if !c.requestWritten { 82 | header := buf.With(buffer.ExtendHeader(M.SocksaddrSerializer.AddrPortLen(c.destination))) 83 | err := M.SocksaddrSerializer.WriteAddrPort(header, c.destination) 84 | if err != nil { 85 | return err 86 | } 87 | c.requestWritten = true 88 | } 89 | return c.ExtendedConn.WriteBuffer(buffer) 90 | } 91 | 92 | func (c *noneConn) FrontHeadroom() int { 93 | return M.MaxSocksaddrLength 94 | } 95 | 96 | func (c *noneConn) ReaderReplaceable() bool { 97 | return true 98 | } 99 | 100 | func (c *noneConn) WriterReplaceable() bool { 101 | return c.requestWritten 102 | } 103 | 104 | func (c *noneConn) Upstream() any { 105 | return c.ExtendedConn 106 | } 107 | 108 | var ( 109 | _ N.NetPacketConn = (*nonePacketConn)(nil) 110 | _ N.FrontHeadroom = (*nonePacketConn)(nil) 111 | _ common.WithUpstream = (*nonePacketConn)(nil) 112 | ) 113 | 114 | type nonePacketConn struct { 115 | N.AbstractConn 116 | conn N.ExtendedConn 117 | } 118 | 119 | func (c *nonePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 120 | n, err = c.conn.Read(p) 121 | if err != nil { 122 | return 123 | } 124 | buffer := buf.As(p[:n]) 125 | destination, err := M.SocksaddrSerializer.ReadAddrPort(buffer) 126 | if err != nil { 127 | return 128 | } 129 | if destination.IsFqdn() { 130 | addr = destination 131 | } else { 132 | addr = destination.UDPAddr() 133 | } 134 | n = copy(p, buffer.Bytes()) 135 | return 136 | } 137 | 138 | func (c *nonePacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 139 | destination := M.SocksaddrFromNet(addr) 140 | buffer := buf.NewSize(M.SocksaddrSerializer.AddrPortLen(destination) + len(p)) 141 | defer buffer.Release() 142 | err = M.SocksaddrSerializer.WriteAddrPort(buffer, destination) 143 | if err != nil { 144 | return 145 | } 146 | common.Must1(buffer.Write(p)) 147 | _, err = c.conn.Write(buffer.Bytes()) 148 | if err != nil { 149 | return 150 | } 151 | n = len(p) 152 | return 153 | } 154 | 155 | func (c *nonePacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { 156 | err = c.conn.ReadBuffer(buffer) 157 | if err != nil { 158 | return 159 | } 160 | return M.SocksaddrSerializer.ReadAddrPort(buffer) 161 | } 162 | 163 | func (c *nonePacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { 164 | header := buf.With(buffer.ExtendHeader(M.SocksaddrSerializer.AddrPortLen(destination))) 165 | err := M.SocksaddrSerializer.WriteAddrPort(header, destination) 166 | if err != nil { 167 | return err 168 | } 169 | return c.conn.WriteBuffer(buffer) 170 | } 171 | 172 | func (c *nonePacketConn) FrontHeadroom() int { 173 | return M.MaxSocksaddrLength 174 | } 175 | 176 | func (c *nonePacketConn) Upstream() any { 177 | return c.conn 178 | } 179 | -------------------------------------------------------------------------------- /cipher/method_none_wait.go: -------------------------------------------------------------------------------- 1 | package cipher 2 | 3 | import ( 4 | "github.com/sagernet/sing/common/buf" 5 | "github.com/sagernet/sing/common/bufio" 6 | M "github.com/sagernet/sing/common/metadata" 7 | N "github.com/sagernet/sing/common/network" 8 | ) 9 | 10 | var _ N.PacketReadWaitCreator = (*nonePacketConn)(nil) 11 | 12 | func (c *nonePacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) { 13 | readWaiter, isReadWaiter := bufio.CreateReadWaiter(c.conn) 14 | if !isReadWaiter { 15 | return nil, false 16 | } 17 | return &nonePacketReadWaiter{readWaiter}, true 18 | } 19 | 20 | var _ N.PacketReadWaiter = (*nonePacketReadWaiter)(nil) 21 | 22 | type nonePacketReadWaiter struct { 23 | readWaiter N.ReadWaiter 24 | } 25 | 26 | func (w *nonePacketReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { 27 | return w.readWaiter.InitializeReadWaiter(options) 28 | } 29 | 30 | func (w *nonePacketReadWaiter) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { 31 | buffer, err = w.readWaiter.WaitReadBuffer() 32 | if err != nil { 33 | return 34 | } 35 | destination, err = M.SocksaddrSerializer.ReadAddrPort(buffer) 36 | if err != nil { 37 | buffer.Release() 38 | return nil, M.Socksaddr{}, err 39 | } 40 | return 41 | } 42 | -------------------------------------------------------------------------------- /cipher/method_registry.go: -------------------------------------------------------------------------------- 1 | package cipher 2 | 3 | import ( 4 | "context" 5 | 6 | E "github.com/sagernet/sing/common/exceptions" 7 | ) 8 | 9 | var methodRegistry map[string]MethodCreator 10 | 11 | func RegisterMethod(methods []string, creator MethodCreator) { 12 | if methodRegistry == nil { 13 | methodRegistry = make(map[string]MethodCreator) 14 | } 15 | for _, method := range methods { 16 | methodRegistry[method] = creator 17 | } 18 | } 19 | 20 | func CreateMethod(ctx context.Context, methodName string, options MethodOptions) (Method, error) { 21 | if methodRegistry == nil { 22 | methodRegistry = make(map[string]MethodCreator) 23 | } 24 | creator, ok := methodRegistry[methodName] 25 | if !ok { 26 | return nil, E.New("unknown method: ", methodName) 27 | } 28 | return creator(ctx, methodName, options) 29 | } 30 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/sagernet/sing-shadowsocks2 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/sagernet/sing v0.3.0 7 | golang.org/x/crypto v0.17.0 8 | lukechampine.com/blake3 v1.2.1 9 | ) 10 | 11 | require ( 12 | github.com/klauspost/cpuid/v2 v2.0.9 // indirect 13 | golang.org/x/sys v0.15.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= 3 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 4 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 5 | github.com/sagernet/sing v0.3.0 h1:PIDVFZHnQAAYRL1UYqNM+0k5s8f/tb1lUW6UDcQiOc8= 6 | github.com/sagernet/sing v0.3.0/go.mod h1:9pfuAH6mZfgnz/YjP6xu5sxx882rfyjpcrTdUpd6w3g= 7 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 8 | golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= 9 | golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 10 | golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= 11 | golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 12 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 13 | lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= 14 | lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= 15 | -------------------------------------------------------------------------------- /internal/legacykey/key.go: -------------------------------------------------------------------------------- 1 | package legacykey 2 | 3 | import ( 4 | "crypto/md5" 5 | "crypto/sha1" 6 | "io" 7 | 8 | "github.com/sagernet/sing/common" 9 | 10 | "golang.org/x/crypto/hkdf" 11 | ) 12 | 13 | func Key(password []byte, keySize int) []byte { 14 | var b, prev []byte 15 | h := md5.New() 16 | for len(b) < keySize { 17 | h.Write(prev) 18 | h.Write(password) 19 | b = h.Sum(b) 20 | prev = b[len(b)-h.Size():] 21 | h.Reset() 22 | } 23 | return b[:keySize] 24 | } 25 | 26 | func Kdf(key, iv, out []byte) { 27 | kdf := hkdf.New(sha1.New, key, iv, []byte("ss-subkey")) 28 | common.Must1(io.ReadFull(kdf, out)) 29 | } 30 | -------------------------------------------------------------------------------- /internal/shadowio/common.go: -------------------------------------------------------------------------------- 1 | package shadowio 2 | 3 | func increaseNonce(nonce []byte) { 4 | for i := range nonce { 5 | nonce[i]++ 6 | if nonce[i] != 0 { 7 | return 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /internal/shadowio/reader.go: -------------------------------------------------------------------------------- 1 | package shadowio 2 | 3 | import ( 4 | "crypto/cipher" 5 | "encoding/binary" 6 | "io" 7 | 8 | "github.com/sagernet/sing/common/buf" 9 | N "github.com/sagernet/sing/common/network" 10 | ) 11 | 12 | const PacketLengthBufferSize = 2 13 | 14 | const ( 15 | // Overhead 16 | // crypto/cipher.gcmTagSize 17 | // golang.org/x/crypto/chacha20poly1305.Overhead 18 | Overhead = 16 19 | ) 20 | 21 | var ( 22 | _ N.ExtendedReader = (*Reader)(nil) 23 | _ N.ReadWaiter = (*Reader)(nil) 24 | ) 25 | 26 | type Reader struct { 27 | reader io.Reader 28 | cipher cipher.AEAD 29 | nonce []byte 30 | cache *buf.Buffer 31 | readWaitOptions N.ReadWaitOptions 32 | } 33 | 34 | func NewReader(upstream io.Reader, cipher cipher.AEAD) *Reader { 35 | return &Reader{ 36 | reader: upstream, 37 | cipher: cipher, 38 | nonce: make([]byte, cipher.NonceSize()), 39 | } 40 | } 41 | 42 | func (r *Reader) ReadFixedBuffer(pLen int) (*buf.Buffer, error) { 43 | buffer := buf.NewSize(pLen + Overhead) 44 | _, err := buffer.ReadFullFrom(r.reader, buffer.FreeLen()) 45 | if err != nil { 46 | buffer.Release() 47 | return nil, err 48 | } 49 | err = r.Decrypt(buffer.Index(0), buffer.Bytes()) 50 | if err != nil { 51 | buffer.Release() 52 | return nil, err 53 | } 54 | buffer.Truncate(pLen) 55 | r.cache = buffer 56 | return buffer, nil 57 | } 58 | 59 | func (r *Reader) Decrypt(destination []byte, source []byte) error { 60 | _, err := r.cipher.Open(destination[:0], r.nonce, source, nil) 61 | if err != nil { 62 | return err 63 | } 64 | increaseNonce(r.nonce) 65 | return nil 66 | } 67 | 68 | func (r *Reader) Read(p []byte) (n int, err error) { 69 | for { 70 | if r.cache != nil { 71 | if r.cache.IsEmpty() { 72 | r.cache.Release() 73 | r.cache = nil 74 | } else { 75 | n = copy(p, r.cache.Bytes()) 76 | if n > 0 { 77 | r.cache.Advance(n) 78 | return 79 | } 80 | } 81 | } 82 | r.cache, err = r.readBuffer() 83 | if err != nil { 84 | return 85 | } 86 | } 87 | } 88 | 89 | func (r *Reader) ReadBuffer(buffer *buf.Buffer) error { 90 | var err error 91 | for { 92 | if r.cache != nil { 93 | if r.cache.IsEmpty() { 94 | r.cache.Release() 95 | r.cache = nil 96 | } else { 97 | n := copy(buffer.FreeBytes(), r.cache.Bytes()) 98 | if n > 0 { 99 | buffer.Truncate(n) 100 | r.cache.Advance(n) 101 | return nil 102 | } 103 | } 104 | } 105 | r.cache, err = r.readBuffer() 106 | if err != nil { 107 | return err 108 | } 109 | } 110 | } 111 | 112 | func (r *Reader) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { 113 | r.readWaitOptions = options 114 | return options.NeedHeadroom() 115 | } 116 | 117 | func (r *Reader) WaitReadBuffer() (buffer *buf.Buffer, err error) { 118 | if r.readWaitOptions.NeedHeadroom() { 119 | for { 120 | if r.cache != nil { 121 | if r.cache.IsEmpty() { 122 | r.cache.Release() 123 | r.cache = nil 124 | } else { 125 | buffer = r.readWaitOptions.NewBuffer() 126 | var n int 127 | n, err = buffer.Write(r.cache.Bytes()) 128 | if err != nil { 129 | buffer.Release() 130 | return 131 | } 132 | buffer.Truncate(n) 133 | r.cache.Advance(n) 134 | r.readWaitOptions.PostReturn(buffer) 135 | return 136 | } 137 | } 138 | r.cache, err = r.readBuffer() 139 | if err != nil { 140 | return 141 | } 142 | } 143 | } else { 144 | cache := r.cache 145 | if cache != nil { 146 | r.cache = nil 147 | return cache, nil 148 | } 149 | return r.readBuffer() 150 | } 151 | } 152 | 153 | func (r *Reader) readBuffer() (*buf.Buffer, error) { 154 | buffer := buf.NewSize(PacketLengthBufferSize + Overhead) 155 | _, err := buffer.ReadFullFrom(r.reader, buffer.FreeLen()) 156 | if err != nil { 157 | buffer.Release() 158 | return nil, err 159 | } 160 | _, err = r.cipher.Open(buffer.Index(0), r.nonce, buffer.Bytes(), nil) 161 | if err != nil { 162 | buffer.Release() 163 | return nil, err 164 | } 165 | increaseNonce(r.nonce) 166 | length := int(binary.BigEndian.Uint16(buffer.To(PacketLengthBufferSize))) 167 | buffer.Release() 168 | buffer = buf.NewSize(length + Overhead) 169 | _, err = buffer.ReadFullFrom(r.reader, buffer.FreeLen()) 170 | if err != nil { 171 | buffer.Release() 172 | return nil, err 173 | } 174 | _, err = r.cipher.Open(buffer.Index(0), r.nonce, buffer.Bytes(), nil) 175 | if err != nil { 176 | buffer.Release() 177 | return nil, err 178 | } 179 | increaseNonce(r.nonce) 180 | buffer.Truncate(length) 181 | return buffer, nil 182 | } 183 | -------------------------------------------------------------------------------- /internal/shadowio/writer.go: -------------------------------------------------------------------------------- 1 | package shadowio 2 | 3 | import ( 4 | "crypto/cipher" 5 | "encoding/binary" 6 | "io" 7 | "sync" 8 | 9 | "github.com/sagernet/sing/common" 10 | "github.com/sagernet/sing/common/buf" 11 | "github.com/sagernet/sing/common/bufio" 12 | N "github.com/sagernet/sing/common/network" 13 | ) 14 | 15 | type Writer struct { 16 | WriterInterface 17 | writer N.ExtendedWriter 18 | cipher cipher.AEAD 19 | maxPacketSize int 20 | nonce []byte 21 | access sync.Mutex 22 | } 23 | 24 | func NewWriter(writer io.Writer, cipher cipher.AEAD, nonce []byte, maxPacketSize int) *Writer { 25 | if len(nonce) == 0 { 26 | nonce = make([]byte, cipher.NonceSize()) 27 | } 28 | return &Writer{ 29 | writer: bufio.NewExtendedWriter(writer), 30 | cipher: cipher, 31 | nonce: nonce, 32 | maxPacketSize: maxPacketSize, 33 | } 34 | } 35 | 36 | func (w *Writer) Encrypt(destination []byte, source []byte) { 37 | w.cipher.Seal(destination, w.nonce, source, nil) 38 | increaseNonce(w.nonce) 39 | } 40 | 41 | func (w *Writer) Write(p []byte) (n int, err error) { 42 | if len(p) == 0 { 43 | return 44 | } 45 | w.access.Lock() 46 | defer w.access.Unlock() 47 | for pLen := len(p); pLen > 0; { 48 | var data []byte 49 | if pLen > w.maxPacketSize { 50 | data = p[:w.maxPacketSize] 51 | p = p[w.maxPacketSize:] 52 | pLen -= w.maxPacketSize 53 | } else { 54 | data = p 55 | pLen = 0 56 | } 57 | bufferSize := PacketLengthBufferSize + 2*Overhead + len(data) 58 | buffer := buf.NewSize(bufferSize) 59 | common.Must(binary.Write(buffer, binary.BigEndian, uint16(len(data)))) 60 | w.cipher.Seal(buffer.Index(0), w.nonce, buffer.To(PacketLengthBufferSize), nil) 61 | increaseNonce(w.nonce) 62 | buffer.Extend(Overhead) 63 | w.cipher.Seal(buffer.Index(buffer.Len()), w.nonce, data, nil) 64 | buffer.Extend(len(data) + Overhead) 65 | increaseNonce(w.nonce) 66 | _, err = w.writer.Write(buffer.Bytes()) 67 | buffer.Release() 68 | if err != nil { 69 | return 70 | } 71 | n += len(data) 72 | } 73 | return 74 | } 75 | 76 | func (w *Writer) WriteBuffer(buffer *buf.Buffer) error { 77 | if buffer.Len() > w.maxPacketSize { 78 | defer buffer.Release() 79 | return common.Error(w.Write(buffer.Bytes())) 80 | } 81 | pLen := buffer.Len() 82 | headerOffset := PacketLengthBufferSize + Overhead 83 | header := buffer.ExtendHeader(headerOffset) 84 | binary.BigEndian.PutUint16(header, uint16(pLen)) 85 | w.cipher.Seal(header[:0], w.nonce, header[:PacketLengthBufferSize], nil) 86 | increaseNonce(w.nonce) 87 | w.cipher.Seal(buffer.Index(headerOffset), w.nonce, buffer.From(headerOffset), nil) 88 | increaseNonce(w.nonce) 89 | buffer.Extend(Overhead) 90 | return w.writer.WriteBuffer(buffer) 91 | } 92 | 93 | func (w *Writer) TakeNonce() []byte { 94 | return w.nonce 95 | } 96 | 97 | func (w *Writer) Upstream() any { 98 | return w.writer 99 | } 100 | 101 | type WriterInterface struct{} 102 | 103 | func (w *WriterInterface) FrontHeadroom() int { 104 | return PacketLengthBufferSize + Overhead 105 | } 106 | 107 | func (w *WriterInterface) RearHeadroom() int { 108 | return Overhead 109 | } 110 | -------------------------------------------------------------------------------- /shadowaead/method.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "context" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "net" 8 | 9 | C "github.com/sagernet/sing-shadowsocks2/cipher" 10 | "github.com/sagernet/sing-shadowsocks2/internal/legacykey" 11 | "github.com/sagernet/sing-shadowsocks2/internal/shadowio" 12 | "github.com/sagernet/sing/common" 13 | "github.com/sagernet/sing/common/buf" 14 | "github.com/sagernet/sing/common/bufio" 15 | E "github.com/sagernet/sing/common/exceptions" 16 | M "github.com/sagernet/sing/common/metadata" 17 | N "github.com/sagernet/sing/common/network" 18 | "github.com/sagernet/sing/common/rw" 19 | 20 | "golang.org/x/crypto/chacha20poly1305" 21 | ) 22 | 23 | var MethodList = []string{ 24 | "aes-128-gcm", 25 | "aes-192-gcm", 26 | "aes-256-gcm", 27 | "chacha20-ietf-poly1305", 28 | "xchacha20-ietf-poly1305", 29 | } 30 | 31 | func init() { 32 | C.RegisterMethod(MethodList, func(ctx context.Context, methodName string, options C.MethodOptions) (C.Method, error) { 33 | return NewMethod(ctx, methodName, options) 34 | }) 35 | } 36 | 37 | type Method struct { 38 | keySaltLength int 39 | constructor func(key []byte) (cipher.AEAD, error) 40 | key []byte 41 | } 42 | 43 | func NewMethod(ctx context.Context, methodName string, options C.MethodOptions) (*Method, error) { 44 | m := &Method{} 45 | switch methodName { 46 | case "aes-128-gcm": 47 | m.keySaltLength = 16 48 | m.constructor = aeadCipher(aes.NewCipher, cipher.NewGCM) 49 | case "aes-192-gcm": 50 | m.keySaltLength = 24 51 | m.constructor = aeadCipher(aes.NewCipher, cipher.NewGCM) 52 | case "aes-256-gcm": 53 | m.keySaltLength = 32 54 | m.constructor = aeadCipher(aes.NewCipher, cipher.NewGCM) 55 | case "chacha20-ietf-poly1305": 56 | m.keySaltLength = 32 57 | m.constructor = chacha20poly1305.New 58 | case "xchacha20-ietf-poly1305": 59 | m.keySaltLength = 32 60 | m.constructor = chacha20poly1305.NewX 61 | } 62 | if len(options.Key) == m.keySaltLength { 63 | m.key = options.Key 64 | } else if len(options.Key) > 0 { 65 | return nil, E.New("bad key length, required ", m.keySaltLength, ", got ", len(options.Key)) 66 | } else if options.Password == "" { 67 | return nil, C.ErrMissingPassword 68 | } else { 69 | m.key = legacykey.Key([]byte(options.Password), m.keySaltLength) 70 | } 71 | return m, nil 72 | } 73 | 74 | func aeadCipher(block func(key []byte) (cipher.Block, error), aead func(block cipher.Block) (cipher.AEAD, error)) func(key []byte) (cipher.AEAD, error) { 75 | return func(key []byte) (cipher.AEAD, error) { 76 | b, err := block(key) 77 | if err != nil { 78 | return nil, err 79 | } 80 | return aead(b) 81 | } 82 | } 83 | 84 | func (m *Method) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) { 85 | ssConn := &clientConn{ 86 | Conn: conn, 87 | method: m, 88 | destination: destination, 89 | } 90 | return ssConn, ssConn.writeRequest(nil) 91 | } 92 | 93 | func (m *Method) DialEarlyConn(conn net.Conn, destination M.Socksaddr) net.Conn { 94 | return &clientConn{ 95 | Conn: conn, 96 | method: m, 97 | destination: destination, 98 | } 99 | } 100 | 101 | func (m *Method) DialPacketConn(conn net.Conn) N.NetPacketConn { 102 | return &clientPacketConn{ 103 | AbstractConn: conn, 104 | reader: bufio.NewExtendedReader(conn), 105 | writer: bufio.NewExtendedWriter(conn), 106 | method: m, 107 | } 108 | } 109 | 110 | var _ N.ExtendedConn = (*clientConn)(nil) 111 | 112 | type clientConn struct { 113 | net.Conn 114 | method *Method 115 | destination M.Socksaddr 116 | reader *shadowio.Reader 117 | readWaitOptions N.ReadWaitOptions 118 | writer *shadowio.Writer 119 | shadowio.WriterInterface 120 | } 121 | 122 | func (c *clientConn) writeRequest(payload []byte) error { 123 | requestBuffer := buf.New() 124 | requestBuffer.WriteRandom(c.method.keySaltLength) 125 | key := make([]byte, c.method.keySaltLength) 126 | legacykey.Kdf(c.method.key, requestBuffer.Bytes(), key) 127 | writeCipher, err := c.method.constructor(key) 128 | if err != nil { 129 | return err 130 | } 131 | bufferedRequestWriter := bufio.NewBufferedWriter(c.Conn, requestBuffer) 132 | requestContentWriter := shadowio.NewWriter(bufferedRequestWriter, writeCipher, nil, MaxPacketSize) 133 | bufferedRequestContentWriter := bufio.NewBufferedWriter(requestContentWriter, buf.New()) 134 | err = M.SocksaddrSerializer.WriteAddrPort(bufferedRequestContentWriter, c.destination) 135 | if err != nil { 136 | return err 137 | } 138 | _, err = bufferedRequestContentWriter.Write(payload) 139 | if err != nil { 140 | return err 141 | } 142 | err = bufferedRequestContentWriter.Fallthrough() 143 | if err != nil { 144 | return err 145 | } 146 | err = bufferedRequestWriter.Fallthrough() 147 | if err != nil { 148 | return err 149 | } 150 | c.writer = shadowio.NewWriter(c.Conn, writeCipher, requestContentWriter.TakeNonce(), MaxPacketSize) 151 | return nil 152 | } 153 | 154 | func (c *clientConn) readResponse() error { 155 | buffer := buf.NewSize(c.method.keySaltLength) 156 | defer buffer.Release() 157 | _, err := buffer.ReadFullFrom(c.Conn, c.method.keySaltLength) 158 | if err != nil { 159 | return err 160 | } 161 | legacykey.Kdf(c.method.key, buffer.Bytes(), buffer.Bytes()) 162 | readCipher, err := c.method.constructor(buffer.Bytes()) 163 | if err != nil { 164 | return err 165 | } 166 | reader := shadowio.NewReader(c.Conn, readCipher) 167 | reader.InitializeReadWaiter(c.readWaitOptions) 168 | c.reader = reader 169 | return nil 170 | } 171 | 172 | func (c *clientConn) Read(p []byte) (n int, err error) { 173 | if c.reader == nil { 174 | err = c.readResponse() 175 | if err != nil { 176 | return 177 | } 178 | } 179 | return c.reader.Read(p) 180 | } 181 | 182 | func (c *clientConn) ReadBuffer(buffer *buf.Buffer) error { 183 | if c.reader == nil { 184 | err := c.readResponse() 185 | if err != nil { 186 | return err 187 | } 188 | } 189 | return c.reader.ReadBuffer(buffer) 190 | } 191 | 192 | func (c *clientConn) Write(p []byte) (n int, err error) { 193 | if c.writer == nil { 194 | err = c.writeRequest(p) 195 | if err == nil { 196 | n = len(p) 197 | } 198 | return 199 | } 200 | return c.writer.Write(p) 201 | } 202 | 203 | func (c *clientConn) WriteBuffer(buffer *buf.Buffer) error { 204 | if c.writer == nil { 205 | defer buffer.Release() 206 | return c.writeRequest(buffer.Bytes()) 207 | } 208 | return c.writer.WriteBuffer(buffer) 209 | } 210 | 211 | func (c *clientConn) NeedHandshake() bool { 212 | return c.writer == nil 213 | } 214 | 215 | func (c *clientConn) Upstream() any { 216 | return c.Conn 217 | } 218 | 219 | func (c *clientConn) WriterMTU() int { 220 | return MaxPacketSize 221 | } 222 | 223 | type clientPacketConn struct { 224 | N.AbstractConn 225 | reader N.ExtendedReader 226 | writer N.ExtendedWriter 227 | method *Method 228 | } 229 | 230 | func (c *clientPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { 231 | err = c.reader.ReadBuffer(buffer) 232 | if err != nil { 233 | return 234 | } 235 | return c.readPacket(buffer) 236 | } 237 | 238 | func (c *clientPacketConn) readPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { 239 | if buffer.Len() < c.method.keySaltLength { 240 | return M.Socksaddr{}, C.ErrPacketTooShort 241 | } 242 | key := buf.NewSize(c.method.keySaltLength) 243 | legacykey.Kdf(c.method.key, buffer.To(c.method.keySaltLength), key.Extend(c.method.keySaltLength)) 244 | readCipher, err := c.method.constructor(key.Bytes()) 245 | key.Release() 246 | if err != nil { 247 | return 248 | } 249 | packet, err := readCipher.Open(buffer.Index(c.method.keySaltLength), rw.ZeroBytes[:readCipher.NonceSize()], buffer.From(c.method.keySaltLength), nil) 250 | if err != nil { 251 | return 252 | } 253 | buffer.Advance(c.method.keySaltLength) 254 | buffer.Truncate(len(packet)) 255 | if err != nil { 256 | return 257 | } 258 | destination, err = M.SocksaddrSerializer.ReadAddrPort(buffer) 259 | if err != nil { 260 | return 261 | } 262 | return destination.Unwrap(), nil 263 | } 264 | 265 | func (c *clientPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { 266 | header := buf.With(buffer.ExtendHeader(c.method.keySaltLength + M.SocksaddrSerializer.AddrPortLen(destination))) 267 | header.WriteRandom(c.method.keySaltLength) 268 | err := M.SocksaddrSerializer.WriteAddrPort(header, destination) 269 | if err != nil { 270 | return err 271 | } 272 | key := buf.NewSize(c.method.keySaltLength) 273 | legacykey.Kdf(c.method.key, header.To(c.method.keySaltLength), key.Extend(c.method.keySaltLength)) 274 | writeCipher, err := c.method.constructor(key.Bytes()) 275 | key.Release() 276 | if err != nil { 277 | return err 278 | } 279 | writeCipher.Seal(buffer.Index(c.method.keySaltLength), rw.ZeroBytes[:writeCipher.NonceSize()], buffer.From(c.method.keySaltLength), nil) 280 | buffer.Extend(shadowio.Overhead) 281 | return c.writer.WriteBuffer(buffer) 282 | } 283 | 284 | func (c *clientPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 285 | n, err = c.reader.Read(p) 286 | if err != nil { 287 | return 288 | } 289 | if n < c.method.keySaltLength { 290 | err = C.ErrPacketTooShort 291 | return 292 | } 293 | key := buf.NewSize(c.method.keySaltLength) 294 | legacykey.Kdf(c.method.key, p[:c.method.keySaltLength], key.Extend(c.method.keySaltLength)) 295 | readCipher, err := c.method.constructor(key.Bytes()) 296 | key.Release() 297 | if err != nil { 298 | return 299 | } 300 | packet, err := readCipher.Open(p[c.method.keySaltLength:c.method.keySaltLength], rw.ZeroBytes[:readCipher.NonceSize()], p[c.method.keySaltLength:n], nil) 301 | if err != nil { 302 | return 303 | } 304 | packetContent := buf.As(packet) 305 | destination, err := M.SocksaddrSerializer.ReadAddrPort(packetContent) 306 | if err != nil { 307 | return 308 | } 309 | if !destination.IsFqdn() { 310 | addr = destination.UDPAddr() 311 | } else { 312 | addr = destination 313 | } 314 | n = copy(p, packetContent.Bytes()) 315 | return 316 | } 317 | 318 | func (c *clientPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 319 | destination := M.SocksaddrFromNet(addr) 320 | buffer := buf.NewSize(c.method.keySaltLength + M.SocksaddrSerializer.AddrPortLen(destination) + len(p) + shadowio.Overhead) 321 | defer buffer.Release() 322 | buffer.WriteRandom(c.method.keySaltLength) 323 | err = M.SocksaddrSerializer.WriteAddrPort(buffer, destination) 324 | if err != nil { 325 | return 326 | } 327 | common.Must1(buffer.Write(p)) 328 | key := buf.NewSize(c.method.keySaltLength) 329 | legacykey.Kdf(c.method.key, buffer.To(c.method.keySaltLength), key.Extend(c.method.keySaltLength)) 330 | writeCipher, err := c.method.constructor(key.Bytes()) 331 | key.Release() 332 | if err != nil { 333 | return 334 | } 335 | writeCipher.Seal(buffer.Index(c.method.keySaltLength), rw.ZeroBytes[:writeCipher.NonceSize()], buffer.From(c.method.keySaltLength), nil) 336 | buffer.Extend(shadowio.Overhead) 337 | _, err = c.writer.Write(buffer.Bytes()) 338 | if err != nil { 339 | return 340 | } 341 | return len(p), nil 342 | } 343 | 344 | func (c *clientPacketConn) FrontHeadroom() int { 345 | return c.method.keySaltLength + M.MaxSocksaddrLength 346 | } 347 | 348 | func (c *clientPacketConn) RearHeadroom() int { 349 | return shadowio.Overhead 350 | } 351 | 352 | func (c *clientPacketConn) ReaderMTU() int { 353 | return MaxPacketSize 354 | } 355 | 356 | func (c *clientPacketConn) WriterMTU() int { 357 | return MaxPacketSize 358 | } 359 | 360 | func (c *clientPacketConn) Upstream() any { 361 | return c.AbstractConn 362 | } 363 | -------------------------------------------------------------------------------- /shadowaead/method_wait.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "github.com/sagernet/sing/common/buf" 5 | "github.com/sagernet/sing/common/bufio" 6 | M "github.com/sagernet/sing/common/metadata" 7 | N "github.com/sagernet/sing/common/network" 8 | ) 9 | 10 | var _ N.ReadWaiter = (*clientConn)(nil) 11 | 12 | func (c *clientConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { 13 | if c.reader == nil { 14 | c.readWaitOptions = options 15 | return options.NeedHeadroom() 16 | } 17 | return c.reader.InitializeReadWaiter(options) 18 | } 19 | 20 | func (c *clientConn) WaitReadBuffer() (buffer *buf.Buffer, err error) { 21 | if c.reader == nil { 22 | err = c.readResponse() 23 | if err != nil { 24 | return 25 | } 26 | } 27 | return c.reader.WaitReadBuffer() 28 | } 29 | 30 | var _ N.PacketReadWaitCreator = (*clientPacketConn)(nil) 31 | 32 | func (c *clientPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) { 33 | readWaiter, isReadWaiter := bufio.CreateReadWaiter(c.reader) 34 | if !isReadWaiter { 35 | return nil, false 36 | } 37 | return &clientPacketReadWaiter{c, readWaiter}, true 38 | } 39 | 40 | var _ N.PacketReadWaiter = (*clientPacketReadWaiter)(nil) 41 | 42 | type clientPacketReadWaiter struct { 43 | *clientPacketConn 44 | readWaiter N.ReadWaiter 45 | } 46 | 47 | func (w *clientPacketReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { 48 | return w.readWaiter.InitializeReadWaiter(options) 49 | } 50 | 51 | func (w *clientPacketReadWaiter) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { 52 | buffer, err = w.readWaiter.WaitReadBuffer() 53 | if err != nil { 54 | return 55 | } 56 | destination, err = w.readPacket(buffer) 57 | if err != nil { 58 | buffer.Release() 59 | return nil, M.Socksaddr{}, err 60 | } 61 | return 62 | } 63 | -------------------------------------------------------------------------------- /shadowaead/protocol.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | const MaxPacketSize = 16*1024 - 1 4 | -------------------------------------------------------------------------------- /shadowaead_2022/method.go: -------------------------------------------------------------------------------- 1 | package shadowaead_2022 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/aes" 7 | "crypto/cipher" 8 | "crypto/rand" 9 | "encoding/base64" 10 | "encoding/binary" 11 | "math" 12 | mRand "math/rand" 13 | "net" 14 | "os" 15 | "strings" 16 | "time" 17 | 18 | C "github.com/sagernet/sing-shadowsocks2/cipher" 19 | "github.com/sagernet/sing-shadowsocks2/internal/shadowio" 20 | "github.com/sagernet/sing/common" 21 | "github.com/sagernet/sing/common/buf" 22 | "github.com/sagernet/sing/common/bufio" 23 | E "github.com/sagernet/sing/common/exceptions" 24 | M "github.com/sagernet/sing/common/metadata" 25 | N "github.com/sagernet/sing/common/network" 26 | "github.com/sagernet/sing/common/ntp" 27 | 28 | "golang.org/x/crypto/chacha20poly1305" 29 | "lukechampine.com/blake3" 30 | ) 31 | 32 | var MethodList = []string{ 33 | "2022-blake3-aes-128-gcm", 34 | "2022-blake3-aes-256-gcm", 35 | "2022-blake3-chacha20-poly1305", 36 | } 37 | 38 | func init() { 39 | C.RegisterMethod(MethodList, NewMethod) 40 | } 41 | 42 | type Method struct { 43 | keySaltLength int 44 | timeFunc func() time.Time 45 | constructor func(key []byte) (cipher.AEAD, error) 46 | blockConstructor func(key []byte) (cipher.Block, error) 47 | udpCipher cipher.AEAD 48 | udpBlockEncryptCipher cipher.Block 49 | udpBlockDecryptCipher cipher.Block 50 | pskList [][]byte 51 | pskHash []byte 52 | } 53 | 54 | func NewMethod(ctx context.Context, methodName string, options C.MethodOptions) (C.Method, error) { 55 | m := &Method{ 56 | timeFunc: ntp.TimeFuncFromContext(ctx), 57 | pskList: options.KeyList, 58 | } 59 | if options.Password != "" { 60 | var pskList [][]byte 61 | keyStrList := strings.Split(options.Password, ":") 62 | pskList = make([][]byte, len(keyStrList)) 63 | for i, keyStr := range keyStrList { 64 | kb, err := base64.StdEncoding.DecodeString(keyStr) 65 | if err != nil { 66 | return nil, E.Cause(err, "decode key") 67 | } 68 | pskList[i] = kb 69 | } 70 | m.pskList = pskList 71 | } 72 | switch methodName { 73 | case "2022-blake3-aes-128-gcm": 74 | m.keySaltLength = 16 75 | m.constructor = aeadCipher(aes.NewCipher, cipher.NewGCM) 76 | m.blockConstructor = aes.NewCipher 77 | case "2022-blake3-aes-256-gcm": 78 | m.keySaltLength = 32 79 | m.constructor = aeadCipher(aes.NewCipher, cipher.NewGCM) 80 | m.blockConstructor = aes.NewCipher 81 | case "2022-blake3-chacha20-poly1305": 82 | if len(m.pskList) > 1 { 83 | return nil, ErrNoEIH 84 | } 85 | m.keySaltLength = 32 86 | m.constructor = chacha20poly1305.New 87 | default: 88 | return nil, os.ErrInvalid 89 | } 90 | if len(m.pskList) == 0 { 91 | return nil, C.ErrMissingPassword 92 | } 93 | for _, key := range m.pskList { 94 | if len(key) != m.keySaltLength { 95 | return nil, E.New("bad key length, required ", m.keySaltLength, ", got ", len(key)) 96 | } 97 | } 98 | if len(m.pskList) > 1 { 99 | pskHash := make([]byte, (len(m.pskList)-1)*aes.BlockSize) 100 | for i, key := range m.pskList { 101 | if i == 0 { 102 | continue 103 | } 104 | keyHash := blake3.Sum512(key) 105 | copy(pskHash[aes.BlockSize*(i-1):aes.BlockSize*i], keyHash[:aes.BlockSize]) 106 | } 107 | m.pskHash = pskHash 108 | } 109 | var err error 110 | switch methodName { 111 | case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm": 112 | m.udpBlockEncryptCipher, err = aes.NewCipher(m.pskList[0]) 113 | if err != nil { 114 | return nil, err 115 | } 116 | m.udpBlockDecryptCipher, err = aes.NewCipher(m.pskList[len(m.pskList)-1]) 117 | if err != nil { 118 | return nil, err 119 | } 120 | case "2022-blake3-chacha20-poly1305": 121 | m.udpCipher, err = chacha20poly1305.NewX(m.pskList[0]) 122 | if err != nil { 123 | return nil, err 124 | } 125 | } 126 | return m, nil 127 | } 128 | 129 | func (m *Method) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) { 130 | shadowsocksConn := &clientConn{ 131 | Conn: conn, 132 | method: m, 133 | destination: destination, 134 | } 135 | return shadowsocksConn, shadowsocksConn.writeRequest(nil) 136 | } 137 | 138 | func (m *Method) DialEarlyConn(conn net.Conn, destination M.Socksaddr) net.Conn { 139 | return &clientConn{ 140 | Conn: conn, 141 | method: m, 142 | destination: destination, 143 | } 144 | } 145 | 146 | func (m *Method) DialPacketConn(conn net.Conn) N.NetPacketConn { 147 | return &clientPacketConn{ 148 | AbstractConn: conn, 149 | reader: bufio.NewExtendedReader(conn), 150 | writer: bufio.NewExtendedWriter(conn), 151 | method: m, 152 | session: m.newUDPSession(), 153 | } 154 | } 155 | 156 | func (m *Method) time() time.Time { 157 | if m.timeFunc != nil { 158 | return m.timeFunc() 159 | } else { 160 | return time.Now() 161 | } 162 | } 163 | 164 | type clientConn struct { 165 | net.Conn 166 | method *Method 167 | destination M.Socksaddr 168 | requestSalt []byte 169 | reader *shadowio.Reader 170 | readWaitOptions N.ReadWaitOptions 171 | writer *shadowio.Writer 172 | shadowio.WriterInterface 173 | } 174 | 175 | func (c *clientConn) writeRequest(payload []byte) error { 176 | requestSalt := make([]byte, c.method.keySaltLength) 177 | requestBuffer := buf.New() 178 | defer requestBuffer.Release() 179 | requestBuffer.WriteRandom(c.method.keySaltLength) 180 | copy(requestSalt, requestBuffer.Bytes()) 181 | key := SessionKey(c.method.pskList[len(c.method.pskList)-1], requestSalt, c.method.keySaltLength) 182 | writeCipher, err := c.method.constructor(key) 183 | if err != nil { 184 | return err 185 | } 186 | writer := shadowio.NewWriter( 187 | c.Conn, 188 | writeCipher, 189 | nil, 190 | buf.BufferSize-shadowio.PacketLengthBufferSize-shadowio.Overhead*2, 191 | ) 192 | err = c.method.writeExtendedIdentityHeaders(requestBuffer, requestBuffer.To(c.method.keySaltLength)) 193 | if err != nil { 194 | return err 195 | } 196 | fixedLengthBuffer := buf.With(requestBuffer.Extend(RequestHeaderFixedChunkLength + shadowio.Overhead)) 197 | common.Must(fixedLengthBuffer.WriteByte(HeaderTypeClient)) 198 | common.Must(binary.Write(fixedLengthBuffer, binary.BigEndian, uint64(c.method.time().Unix()))) 199 | variableLengthHeaderLen := M.SocksaddrSerializer.AddrPortLen(c.destination) + 2 200 | var paddingLen int 201 | if len(payload) < MaxPaddingLength { 202 | paddingLen = mRand.Intn(MaxPaddingLength) + 1 203 | } 204 | variableLengthHeaderLen += paddingLen 205 | maxPayloadLen := requestBuffer.FreeLen() - (variableLengthHeaderLen + shadowio.Overhead) 206 | payloadLen := len(payload) 207 | if payloadLen > maxPayloadLen { 208 | payloadLen = maxPayloadLen 209 | } 210 | variableLengthHeaderLen += payloadLen 211 | common.Must(binary.Write(fixedLengthBuffer, binary.BigEndian, uint16(variableLengthHeaderLen))) 212 | writer.Encrypt(fixedLengthBuffer.Index(0), fixedLengthBuffer.Bytes()) 213 | fixedLengthBuffer.Extend(shadowio.Overhead) 214 | 215 | variableLengthBuffer := buf.With(requestBuffer.Extend(variableLengthHeaderLen + shadowio.Overhead)) 216 | err = M.SocksaddrSerializer.WriteAddrPort(variableLengthBuffer, c.destination) 217 | if err != nil { 218 | return err 219 | } 220 | common.Must(binary.Write(variableLengthBuffer, binary.BigEndian, uint16(paddingLen))) 221 | if paddingLen > 0 { 222 | variableLengthBuffer.Extend(paddingLen) 223 | } 224 | if payloadLen > 0 { 225 | common.Must1(variableLengthBuffer.Write(payload[:payloadLen])) 226 | } 227 | writer.Encrypt(variableLengthBuffer.Index(0), variableLengthBuffer.Bytes()) 228 | variableLengthBuffer.Extend(shadowio.Overhead) 229 | _, err = c.Conn.Write(requestBuffer.Bytes()) 230 | if err != nil { 231 | return err 232 | } 233 | if len(payload) > payloadLen { 234 | _, err = writer.Write(payload[payloadLen:]) 235 | if err != nil { 236 | return err 237 | } 238 | } 239 | c.requestSalt = requestSalt 240 | c.writer = writer 241 | return nil 242 | } 243 | 244 | func (m *Method) writeExtendedIdentityHeaders(request *buf.Buffer, salt []byte) error { 245 | pskLen := len(m.pskList) 246 | if pskLen < 2 { 247 | return nil 248 | } 249 | for i, psk := range m.pskList { 250 | keyMaterial := make([]byte, m.keySaltLength*2) 251 | copy(keyMaterial, psk) 252 | copy(keyMaterial[m.keySaltLength:], salt) 253 | identitySubkey := make([]byte, m.keySaltLength) 254 | blake3.DeriveKey(identitySubkey, "shadowsocks 2022 identity subkey", keyMaterial) 255 | pskHash := m.pskHash[aes.BlockSize*i : aes.BlockSize*(i+1)] 256 | header := request.Extend(16) 257 | b, err := m.blockConstructor(identitySubkey) 258 | if err != nil { 259 | return err 260 | } 261 | b.Encrypt(header, pskHash) 262 | if i == pskLen-2 { 263 | break 264 | } 265 | } 266 | return nil 267 | } 268 | 269 | func (c *clientConn) readResponse() error { 270 | salt := buf.NewSize(c.method.keySaltLength) 271 | defer salt.Release() 272 | _, err := salt.ReadFullFrom(c.Conn, c.method.keySaltLength) 273 | if err != nil { 274 | return err 275 | } 276 | key := SessionKey(c.method.pskList[len(c.method.pskList)-1], salt.Bytes(), c.method.keySaltLength) 277 | readCipher, err := c.method.constructor(key) 278 | if err != nil { 279 | return err 280 | } 281 | reader := shadowio.NewReader(c.Conn, readCipher) 282 | fixedResponseBuffer, err := reader.ReadFixedBuffer(1 + 8 + c.method.keySaltLength + 2) 283 | if err != nil { 284 | return err 285 | } 286 | headerType := common.Must1(fixedResponseBuffer.ReadByte()) 287 | if headerType != HeaderTypeServer { 288 | return E.Extend(ErrBadHeaderType, "expected ", HeaderTypeServer, ", got ", headerType) 289 | } 290 | var epoch uint64 291 | common.Must(binary.Read(fixedResponseBuffer, binary.BigEndian, &epoch)) 292 | diff := int(math.Abs(float64(c.method.time().Unix() - int64(epoch)))) 293 | if diff > 30 { 294 | return E.Extend(ErrBadTimestamp, "received ", epoch, ", diff ", diff, "s") 295 | } 296 | responseSalt := common.Must1(fixedResponseBuffer.ReadBytes(c.method.keySaltLength)) 297 | if !bytes.Equal(responseSalt, c.requestSalt) { 298 | return ErrBadRequestSalt 299 | } 300 | var length uint16 301 | common.Must(binary.Read(reader, binary.BigEndian, &length)) 302 | _, err = reader.ReadFixedBuffer(int(length)) 303 | if err != nil { 304 | return err 305 | } 306 | reader.InitializeReadWaiter(c.readWaitOptions) 307 | c.reader = reader 308 | return nil 309 | } 310 | 311 | func (c *clientConn) Read(p []byte) (n int, err error) { 312 | if c.reader == nil { 313 | if err = c.readResponse(); err != nil { 314 | return 315 | } 316 | } 317 | return c.reader.Read(p) 318 | } 319 | 320 | func (c *clientConn) ReadBuffer(buffer *buf.Buffer) error { 321 | if c.reader == nil { 322 | err := c.readResponse() 323 | if err != nil { 324 | return err 325 | } 326 | } 327 | return c.reader.ReadBuffer(buffer) 328 | } 329 | 330 | func (c *clientConn) Write(p []byte) (n int, err error) { 331 | if c.writer == nil { 332 | err = c.writeRequest(p) 333 | if err == nil { 334 | n = len(p) 335 | } 336 | return 337 | } 338 | return c.writer.Write(p) 339 | } 340 | 341 | func (c *clientConn) WriteBuffer(buffer *buf.Buffer) error { 342 | if c.writer == nil { 343 | defer buffer.Release() 344 | return c.writeRequest(buffer.Bytes()) 345 | } 346 | return c.writer.WriteBuffer(buffer) 347 | } 348 | 349 | func (c *clientConn) NeedHandshake() bool { 350 | return c.writer == nil 351 | } 352 | 353 | func (c *clientConn) Upstream() any { 354 | return c.Conn 355 | } 356 | 357 | func (c *clientConn) Close() error { 358 | return common.Close( 359 | c.Conn, 360 | common.PtrOrNil(c.reader), 361 | common.PtrOrNil(c.writer), 362 | ) 363 | } 364 | 365 | type clientPacketConn struct { 366 | N.AbstractConn 367 | reader N.ExtendedReader 368 | writer N.ExtendedWriter 369 | method *Method 370 | session *udpSession 371 | } 372 | 373 | func (m *Method) newUDPSession() *udpSession { 374 | session := &udpSession{} 375 | if m.udpCipher != nil { 376 | session.rng = Blake3KeyedHash(rand.Reader) 377 | common.Must(binary.Read(session.rng, binary.BigEndian, &session.sessionId)) 378 | } else { 379 | common.Must(binary.Read(rand.Reader, binary.BigEndian, &session.sessionId)) 380 | } 381 | session.packetId-- 382 | if m.udpCipher == nil { 383 | sessionId := make([]byte, 8) 384 | binary.BigEndian.PutUint64(sessionId, session.sessionId) 385 | key := SessionKey(m.pskList[len(m.pskList)-1], sessionId, m.keySaltLength) 386 | var err error 387 | session.cipher, err = m.constructor(key) 388 | if err != nil { 389 | return nil 390 | } 391 | } 392 | return session 393 | } 394 | 395 | func (c *clientPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { 396 | var hdrLen int 397 | if c.method.udpCipher != nil { 398 | hdrLen = PacketNonceSize 399 | } 400 | 401 | var paddingLen int 402 | if destination.Port == 53 && buffer.Len() < MaxPaddingLength { 403 | paddingLen = mRand.Intn(MaxPaddingLength-buffer.Len()) + 1 404 | } 405 | 406 | hdrLen += 16 // packet header 407 | pskLen := len(c.method.pskList) 408 | if c.method.udpCipher == nil && pskLen > 1 { 409 | hdrLen += (pskLen - 1) * aes.BlockSize 410 | } 411 | hdrLen += 1 // header type 412 | hdrLen += 8 // timestamp 413 | hdrLen += 2 // padding length 414 | hdrLen += paddingLen 415 | hdrLen += M.SocksaddrSerializer.AddrPortLen(destination) 416 | header := buf.With(buffer.ExtendHeader(hdrLen)) 417 | 418 | var dataIndex int 419 | if c.method.udpCipher != nil { 420 | common.Must1(header.ReadFullFrom(c.session.rng, PacketNonceSize)) 421 | if pskLen > 1 { 422 | panic("unsupported chacha extended header") 423 | } 424 | dataIndex = PacketNonceSize 425 | } else { 426 | dataIndex = aes.BlockSize 427 | } 428 | 429 | common.Must( 430 | binary.Write(header, binary.BigEndian, c.session.sessionId), 431 | binary.Write(header, binary.BigEndian, c.session.nextPacketId()), 432 | ) 433 | 434 | if c.method.udpCipher == nil && pskLen > 1 { 435 | for i, psk := range c.method.pskList { 436 | dataIndex += aes.BlockSize 437 | pskHash := c.method.pskHash[aes.BlockSize*i : aes.BlockSize*(i+1)] 438 | 439 | identityHeader := header.Extend(aes.BlockSize) 440 | xorWords(identityHeader, pskHash, header.To(aes.BlockSize)) 441 | b, err := c.method.blockConstructor(psk) 442 | if err != nil { 443 | return err 444 | } 445 | b.Encrypt(identityHeader, identityHeader) 446 | 447 | if i == pskLen-2 { 448 | break 449 | } 450 | } 451 | } 452 | common.Must( 453 | header.WriteByte(HeaderTypeClient), 454 | binary.Write(header, binary.BigEndian, uint64(c.method.time().Unix())), 455 | binary.Write(header, binary.BigEndian, uint16(paddingLen)), // padding length 456 | ) 457 | 458 | if paddingLen > 0 { 459 | header.Extend(paddingLen) 460 | } 461 | 462 | err := M.SocksaddrSerializer.WriteAddrPort(header, destination) 463 | if err != nil { 464 | return err 465 | } 466 | if c.method.udpCipher != nil { 467 | c.method.udpCipher.Seal(buffer.Index(dataIndex), buffer.To(dataIndex), buffer.From(dataIndex), nil) 468 | buffer.Extend(shadowio.Overhead) 469 | } else { 470 | packetHeader := buffer.To(aes.BlockSize) 471 | c.session.cipher.Seal(buffer.Index(dataIndex), packetHeader[4:16], buffer.From(dataIndex), nil) 472 | buffer.Extend(shadowio.Overhead) 473 | c.method.udpBlockEncryptCipher.Encrypt(packetHeader, packetHeader) 474 | } 475 | return c.writer.WriteBuffer(buffer) 476 | } 477 | 478 | func (c *clientPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { 479 | err = c.reader.ReadBuffer(buffer) 480 | if err != nil { 481 | return 482 | } 483 | return c.readPacket(buffer) 484 | } 485 | 486 | func (c *clientPacketConn) readPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { 487 | var packetHeader []byte 488 | if c.method.udpCipher != nil { 489 | if buffer.Len() < PacketNonceSize+PacketMinimalHeaderSize { 490 | return M.Socksaddr{}, C.ErrPacketTooShort 491 | } 492 | _, err = c.method.udpCipher.Open(buffer.Index(PacketNonceSize), buffer.To(PacketNonceSize), buffer.From(PacketNonceSize), nil) 493 | if err != nil { 494 | return M.Socksaddr{}, E.Cause(err, "decrypt packet") 495 | } 496 | buffer.Advance(PacketNonceSize) 497 | buffer.Truncate(buffer.Len() - shadowio.Overhead) 498 | } else { 499 | if buffer.Len() < PacketMinimalHeaderSize { 500 | return M.Socksaddr{}, C.ErrPacketTooShort 501 | } 502 | packetHeader = buffer.To(aes.BlockSize) 503 | c.method.udpBlockDecryptCipher.Decrypt(packetHeader, packetHeader) 504 | } 505 | 506 | var sessionId, packetId uint64 507 | err = binary.Read(buffer, binary.BigEndian, &sessionId) 508 | if err != nil { 509 | return M.Socksaddr{}, err 510 | } 511 | err = binary.Read(buffer, binary.BigEndian, &packetId) 512 | if err != nil { 513 | return M.Socksaddr{}, err 514 | } 515 | 516 | if sessionId == c.session.remoteSessionId { 517 | if !c.session.window.Check(packetId) { 518 | return M.Socksaddr{}, ErrPacketIdNotUnique 519 | } 520 | } else if sessionId == c.session.lastRemoteSessionId { 521 | if !c.session.lastWindow.Check(packetId) { 522 | return M.Socksaddr{}, ErrPacketIdNotUnique 523 | } 524 | } 525 | 526 | var remoteCipher cipher.AEAD 527 | if packetHeader != nil { 528 | if sessionId == c.session.remoteSessionId { 529 | remoteCipher = c.session.remoteCipher 530 | } else if sessionId == c.session.lastRemoteSessionId { 531 | remoteCipher = c.session.lastRemoteCipher 532 | } else { 533 | key := SessionKey(c.method.pskList[len(c.method.pskList)-1], packetHeader[:8], c.method.keySaltLength) 534 | remoteCipher, err = c.method.constructor(key) 535 | if err != nil { 536 | return M.Socksaddr{}, err 537 | } 538 | } 539 | _, err = remoteCipher.Open(buffer.Index(0), packetHeader[4:16], buffer.Bytes(), nil) 540 | if err != nil { 541 | return M.Socksaddr{}, E.Cause(err, "decrypt packet") 542 | } 543 | buffer.Truncate(buffer.Len() - shadowio.Overhead) 544 | } 545 | 546 | var headerType byte 547 | headerType, err = buffer.ReadByte() 548 | if err != nil { 549 | return M.Socksaddr{}, err 550 | } 551 | if headerType != HeaderTypeServer { 552 | return M.Socksaddr{}, E.Extend(ErrBadHeaderType, "expected ", HeaderTypeServer, ", got ", headerType) 553 | } 554 | 555 | var epoch uint64 556 | err = binary.Read(buffer, binary.BigEndian, &epoch) 557 | if err != nil { 558 | return M.Socksaddr{}, err 559 | } 560 | 561 | diff := int(math.Abs(float64(c.method.time().Unix() - int64(epoch)))) 562 | if diff > 30 { 563 | return M.Socksaddr{}, E.Extend(ErrBadTimestamp, "received ", epoch, ", diff ", diff, "s") 564 | } 565 | 566 | if sessionId == c.session.remoteSessionId { 567 | c.session.window.Add(packetId) 568 | } else if sessionId == c.session.lastRemoteSessionId { 569 | c.session.lastWindow.Add(packetId) 570 | c.session.lastRemoteSeen = c.method.time().Unix() 571 | } else { 572 | if c.session.remoteSessionId != 0 { 573 | if c.method.time().Unix()-c.session.lastRemoteSeen < 60 { 574 | return M.Socksaddr{}, ErrTooManyServerSessions 575 | } else { 576 | c.session.lastRemoteSessionId = c.session.remoteSessionId 577 | c.session.lastWindow = c.session.window 578 | c.session.lastRemoteSeen = c.method.time().Unix() 579 | c.session.lastRemoteCipher = c.session.remoteCipher 580 | c.session.window = SlidingWindow{} 581 | } 582 | } 583 | c.session.remoteSessionId = sessionId 584 | c.session.remoteCipher = remoteCipher 585 | c.session.window.Add(packetId) 586 | } 587 | 588 | var clientSessionId uint64 589 | err = binary.Read(buffer, binary.BigEndian, &clientSessionId) 590 | if err != nil { 591 | return M.Socksaddr{}, err 592 | } 593 | 594 | if clientSessionId != c.session.sessionId { 595 | return M.Socksaddr{}, ErrBadClientSessionId 596 | } 597 | 598 | var paddingLen uint16 599 | err = binary.Read(buffer, binary.BigEndian, &paddingLen) 600 | if err != nil { 601 | return M.Socksaddr{}, E.Cause(err, "read padding length") 602 | } 603 | buffer.Advance(int(paddingLen)) 604 | 605 | destination, err = M.SocksaddrSerializer.ReadAddrPort(buffer) 606 | if err != nil { 607 | return 608 | } 609 | return destination.Unwrap(), nil 610 | } 611 | 612 | func (c *clientPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 613 | n, err = c.reader.Read(p) 614 | if err != nil { 615 | return 616 | } 617 | buffer := buf.As(p[:n]) 618 | destination, err := c.readPacket(buffer) 619 | if destination.IsFqdn() { 620 | addr = destination 621 | } else { 622 | addr = destination.UDPAddr() 623 | } 624 | n = copy(p, buffer.Bytes()) 625 | return 626 | } 627 | 628 | func (c *clientPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 629 | destination := M.SocksaddrFromNet(addr) 630 | var overHead int 631 | if c.method.udpCipher != nil { 632 | overHead = PacketNonceSize + shadowio.Overhead 633 | } else { 634 | overHead = shadowio.Overhead 635 | } 636 | overHead += 16 // packet header 637 | pskLen := len(c.method.pskList) 638 | if c.method.udpCipher == nil && pskLen > 1 { 639 | overHead += (pskLen - 1) * aes.BlockSize 640 | } 641 | var paddingLen int 642 | if destination.Port == 53 && len(p) < MaxPaddingLength { 643 | paddingLen = mRand.Intn(MaxPaddingLength-len(p)) + 1 644 | } 645 | overHead += 1 // header type 646 | overHead += 8 // timestamp 647 | overHead += 2 // padding length 648 | overHead += paddingLen 649 | overHead += M.SocksaddrSerializer.AddrPortLen(destination) 650 | 651 | buffer := buf.NewSize(overHead + len(p)) 652 | defer buffer.Release() 653 | 654 | var dataIndex int 655 | if c.method.udpCipher != nil { 656 | common.Must1(buffer.ReadFullFrom(c.session.rng, PacketNonceSize)) 657 | if pskLen > 1 { 658 | panic("unsupported chacha extended header") 659 | } 660 | dataIndex = PacketNonceSize 661 | } else { 662 | dataIndex = aes.BlockSize 663 | } 664 | 665 | common.Must( 666 | binary.Write(buffer, binary.BigEndian, c.session.sessionId), 667 | binary.Write(buffer, binary.BigEndian, c.session.nextPacketId()), 668 | ) 669 | 670 | if c.method.udpCipher == nil && pskLen > 1 { 671 | for i, psk := range c.method.pskList { 672 | dataIndex += aes.BlockSize 673 | pskHash := c.method.pskHash[aes.BlockSize*i : aes.BlockSize*(i+1)] 674 | 675 | identityHeader := buffer.Extend(aes.BlockSize) 676 | xorWords(identityHeader, pskHash, buffer.To(aes.BlockSize)) 677 | b, err := c.method.blockConstructor(psk) 678 | if err != nil { 679 | return 0, err 680 | } 681 | b.Encrypt(identityHeader, identityHeader) 682 | 683 | if i == pskLen-2 { 684 | break 685 | } 686 | } 687 | } 688 | common.Must( 689 | buffer.WriteByte(HeaderTypeClient), 690 | binary.Write(buffer, binary.BigEndian, uint64(c.method.time().Unix())), 691 | binary.Write(buffer, binary.BigEndian, uint16(paddingLen)), // padding length 692 | ) 693 | 694 | if paddingLen > 0 { 695 | buffer.Extend(paddingLen) 696 | } 697 | 698 | err = M.SocksaddrSerializer.WriteAddrPort(buffer, destination) 699 | if err != nil { 700 | return 701 | } 702 | common.Must1(buffer.Write(p)) 703 | if c.method.udpCipher != nil { 704 | c.method.udpCipher.Seal(buffer.Index(dataIndex), buffer.To(dataIndex), buffer.From(dataIndex), nil) 705 | buffer.Extend(shadowio.Overhead) 706 | } else { 707 | packetHeader := buffer.To(aes.BlockSize) 708 | c.session.cipher.Seal(buffer.Index(dataIndex), packetHeader[4:16], buffer.From(dataIndex), nil) 709 | buffer.Extend(shadowio.Overhead) 710 | c.method.udpBlockEncryptCipher.Encrypt(packetHeader, packetHeader) 711 | } 712 | err = common.Error(c.writer.Write(buffer.Bytes())) 713 | if err != nil { 714 | return 715 | } 716 | return len(p), nil 717 | } 718 | 719 | func (c *clientPacketConn) FrontHeadroom() int { 720 | var overHead int 721 | if c.method.udpCipher != nil { 722 | overHead = PacketNonceSize + shadowio.Overhead 723 | } else { 724 | overHead = shadowio.Overhead 725 | } 726 | overHead += 16 // packet header 727 | pskLen := len(c.method.pskList) 728 | if c.method.udpCipher == nil && pskLen > 1 { 729 | overHead += (pskLen - 1) * aes.BlockSize 730 | } 731 | overHead += 1 // header type 732 | overHead += 8 // timestamp 733 | overHead += 2 // padding length 734 | overHead += MaxPaddingLength 735 | overHead += M.MaxSocksaddrLength 736 | return overHead 737 | } 738 | 739 | func (c *clientPacketConn) RearHeadroom() int { 740 | return shadowio.Overhead 741 | } 742 | 743 | func (c *clientPacketConn) Upstream() any { 744 | return c.AbstractConn 745 | } 746 | 747 | func (c *clientPacketConn) Close() error { 748 | return c.AbstractConn.Close() 749 | } 750 | -------------------------------------------------------------------------------- /shadowaead_2022/method_wait.go: -------------------------------------------------------------------------------- 1 | package shadowaead_2022 2 | 3 | import ( 4 | "github.com/sagernet/sing/common/buf" 5 | "github.com/sagernet/sing/common/bufio" 6 | M "github.com/sagernet/sing/common/metadata" 7 | N "github.com/sagernet/sing/common/network" 8 | ) 9 | 10 | var _ N.ReadWaiter = (*clientConn)(nil) 11 | 12 | func (c *clientConn) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { 13 | if c.reader == nil { 14 | c.readWaitOptions = options 15 | return options.NeedHeadroom() 16 | } 17 | return c.reader.InitializeReadWaiter(options) 18 | } 19 | 20 | func (c *clientConn) WaitReadBuffer() (buffer *buf.Buffer, err error) { 21 | if c.reader == nil { 22 | err = c.readResponse() 23 | if err != nil { 24 | return 25 | } 26 | } 27 | return c.reader.WaitReadBuffer() 28 | } 29 | 30 | var _ N.PacketReadWaitCreator = (*clientPacketConn)(nil) 31 | 32 | func (c *clientPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) { 33 | readWaiter, isReadWaiter := bufio.CreateReadWaiter(c.reader) 34 | if !isReadWaiter { 35 | return nil, false 36 | } 37 | return &clientPacketReadWaiter{c, readWaiter}, true 38 | } 39 | 40 | var _ N.PacketReadWaiter = (*clientPacketReadWaiter)(nil) 41 | 42 | type clientPacketReadWaiter struct { 43 | *clientPacketConn 44 | readWaiter N.ReadWaiter 45 | } 46 | 47 | func (w *clientPacketReadWaiter) InitializeReadWaiter(options N.ReadWaitOptions) (needCopy bool) { 48 | return w.readWaiter.InitializeReadWaiter(options) 49 | } 50 | 51 | func (w *clientPacketReadWaiter) WaitReadPacket() (buffer *buf.Buffer, destination M.Socksaddr, err error) { 52 | buffer, err = w.readWaiter.WaitReadBuffer() 53 | if err != nil { 54 | return 55 | } 56 | destination, err = w.readPacket(buffer) 57 | if err != nil { 58 | buffer.Release() 59 | return nil, M.Socksaddr{}, err 60 | } 61 | return 62 | } 63 | -------------------------------------------------------------------------------- /shadowaead_2022/protocol.go: -------------------------------------------------------------------------------- 1 | package shadowaead_2022 2 | 3 | import ( 4 | "crypto/cipher" 5 | "crypto/sha256" 6 | "io" 7 | "sync/atomic" 8 | 9 | "github.com/sagernet/sing/common" 10 | E "github.com/sagernet/sing/common/exceptions" 11 | "github.com/sagernet/sing/common/random" 12 | 13 | "lukechampine.com/blake3" 14 | ) 15 | 16 | const ( 17 | HeaderTypeClient = 0 18 | HeaderTypeServer = 1 19 | MaxPaddingLength = 900 20 | PacketNonceSize = 24 21 | RequestHeaderFixedChunkLength = 1 + 8 + 2 22 | PacketMinimalHeaderSize = 30 23 | ) 24 | 25 | var ( 26 | ErrNoEIH = E.New("Shadowsocks 2022 EIH support only available in AES ciphers") 27 | ErrBadHeaderType = E.New("bad header type") 28 | ErrBadTimestamp = E.New("bad timestamp") 29 | ErrBadRequestSalt = E.New("bad request salt") 30 | ErrSaltNotUnique = E.New("salt not unique") 31 | ErrBadClientSessionId = E.New("bad client session id") 32 | ErrPacketIdNotUnique = E.New("packet id not unique") 33 | ErrTooManyServerSessions = E.New("server session changed more than once during the last minute") 34 | ) 35 | 36 | func init() { 37 | random.InitializeSeed() 38 | } 39 | 40 | func Key(key []byte, keyLength int) []byte { 41 | psk := sha256.Sum256(key) 42 | return psk[:keyLength] 43 | } 44 | 45 | func SessionKey(psk []byte, salt []byte, keyLength int) []byte { 46 | sessionKey := make([]byte, len(psk)+len(salt)) 47 | copy(sessionKey, psk) 48 | copy(sessionKey[len(psk):], salt) 49 | outKey := make([]byte, keyLength) 50 | blake3.DeriveKey(outKey, "shadowsocks 2022 session subkey", sessionKey) 51 | return outKey 52 | } 53 | 54 | func aeadCipher(block func(key []byte) (cipher.Block, error), aead func(block cipher.Block) (cipher.AEAD, error)) func(key []byte) (cipher.AEAD, error) { 55 | return func(key []byte) (cipher.AEAD, error) { 56 | b, err := block(key) 57 | if err != nil { 58 | return nil, err 59 | } 60 | return aead(b) 61 | } 62 | } 63 | 64 | type udpSession struct { 65 | sessionId uint64 66 | packetId uint64 67 | remoteSessionId uint64 68 | lastRemoteSessionId uint64 69 | lastRemoteSeen int64 70 | cipher cipher.AEAD 71 | remoteCipher cipher.AEAD 72 | lastRemoteCipher cipher.AEAD 73 | window SlidingWindow 74 | lastWindow SlidingWindow 75 | rng io.Reader 76 | } 77 | 78 | func (s *udpSession) nextPacketId() uint64 { 79 | return atomic.AddUint64(&s.packetId, 1) 80 | } 81 | 82 | func Blake3KeyedHash(reader io.Reader) io.Reader { 83 | key := make([]byte, 32) 84 | common.Must1(io.ReadFull(reader, key)) 85 | h := blake3.New(1024, key) 86 | return h.XOF() 87 | } 88 | -------------------------------------------------------------------------------- /shadowaead_2022/slidingwindow.go: -------------------------------------------------------------------------------- 1 | package shadowaead_2022 2 | 3 | const ( 4 | swBlockBitLog = 6 // 1<<6 == 64 bits 5 | swBlockBits = 1 << swBlockBitLog // must be power of 2 6 | swRingBlocks = 1 << 7 // must be power of 2 7 | swBlockMask = swRingBlocks - 1 8 | swBitMask = swBlockBits - 1 9 | swSize = (swRingBlocks - 1) * swBlockBits 10 | ) 11 | 12 | // SlidingWindow maintains a sliding window of uint64 counters. 13 | type SlidingWindow struct { 14 | last uint64 15 | ring [swRingBlocks]uint64 16 | } 17 | 18 | // Reset resets the filter to its initial state. 19 | func (f *SlidingWindow) Reset() { 20 | f.last = 0 21 | f.ring[0] = 0 22 | } 23 | 24 | // Check checks whether counter can be accepted by the sliding window filter. 25 | func (f *SlidingWindow) Check(counter uint64) bool { 26 | switch { 27 | case counter > f.last: // ahead of window 28 | return true 29 | case f.last-counter > swSize: // behind window 30 | return false 31 | } 32 | 33 | // In window. Check bit. 34 | blockIndex := counter >> swBlockBitLog & swBlockMask 35 | bitIndex := counter & swBitMask 36 | return f.ring[blockIndex]>>bitIndex&1 == 0 37 | } 38 | 39 | // Add adds counter to the sliding window without checking if the counter is valid. 40 | // Call Check beforehand to make sure the counter is valid. 41 | func (f *SlidingWindow) Add(counter uint64) { 42 | blockIndex := counter >> swBlockBitLog 43 | 44 | // Check if counter is ahead of window. 45 | if counter > f.last { 46 | lastBlockIndex := f.last >> swBlockBitLog 47 | diff := int(blockIndex - lastBlockIndex) 48 | if diff > swRingBlocks { 49 | diff = swRingBlocks 50 | } 51 | 52 | for i := 0; i < diff; i++ { 53 | lastBlockIndex = (lastBlockIndex + 1) & swBlockMask 54 | f.ring[lastBlockIndex] = 0 55 | } 56 | 57 | f.last = counter 58 | } 59 | 60 | blockIndex &= swBlockMask 61 | bitIndex := counter & swBitMask 62 | f.ring[blockIndex] |= 1 << bitIndex 63 | } 64 | -------------------------------------------------------------------------------- /shadowaead_2022/xor.go: -------------------------------------------------------------------------------- 1 | //go:build go1.20 2 | 3 | package shadowaead_2022 4 | 5 | import "crypto/subtle" 6 | 7 | var xorWords = subtle.XORBytes 8 | -------------------------------------------------------------------------------- /shadowaead_2022/xor_go119.go: -------------------------------------------------------------------------------- 1 | //go:build !go1.20 2 | 3 | package shadowaead_2022 4 | 5 | import _ "unsafe" 6 | 7 | //go:linkname xorWords crypto/cipher.xorWords 8 | //go:noescape 9 | func xorWords(dst, a, b []byte) 10 | -------------------------------------------------------------------------------- /shadowsocks.go: -------------------------------------------------------------------------------- 1 | package shadowsocks 2 | 3 | import ( 4 | "context" 5 | 6 | C "github.com/sagernet/sing-shadowsocks2/cipher" 7 | _ "github.com/sagernet/sing-shadowsocks2/shadowaead" 8 | _ "github.com/sagernet/sing-shadowsocks2/shadowaead_2022" 9 | _ "github.com/sagernet/sing-shadowsocks2/shadowstream" 10 | ) 11 | 12 | type ( 13 | Method = C.Method 14 | MethodOptions = C.MethodOptions 15 | ) 16 | 17 | func CreateMethod(ctx context.Context, method string, options MethodOptions) (Method, error) { 18 | return C.CreateMethod(ctx, method, options) 19 | } 20 | -------------------------------------------------------------------------------- /shadowstream/method.go: -------------------------------------------------------------------------------- 1 | package shadowstream 2 | 3 | import ( 4 | "context" 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/md5" 8 | "crypto/rc4" 9 | "net" 10 | "os" 11 | 12 | C "github.com/sagernet/sing-shadowsocks2/cipher" 13 | "github.com/sagernet/sing-shadowsocks2/internal/legacykey" 14 | "github.com/sagernet/sing/common" 15 | "github.com/sagernet/sing/common/buf" 16 | "github.com/sagernet/sing/common/bufio" 17 | E "github.com/sagernet/sing/common/exceptions" 18 | M "github.com/sagernet/sing/common/metadata" 19 | N "github.com/sagernet/sing/common/network" 20 | 21 | "golang.org/x/crypto/chacha20" 22 | ) 23 | 24 | var MethodList = []string{ 25 | "aes-128-ctr", 26 | "aes-192-ctr", 27 | "aes-256-ctr", 28 | "aes-128-cfb", 29 | "aes-192-cfb", 30 | "aes-256-cfb", 31 | "rc4-md5", 32 | "chacha20-ietf", 33 | "xchacha20", 34 | } 35 | 36 | func init() { 37 | C.RegisterMethod(MethodList, NewMethod) 38 | } 39 | 40 | type Method struct { 41 | keyLength int 42 | saltLength int 43 | encryptConstructor func(key []byte, salt []byte) (cipher.Stream, error) 44 | decryptConstructor func(key []byte, salt []byte) (cipher.Stream, error) 45 | key []byte 46 | } 47 | 48 | func NewMethod(ctx context.Context, methodName string, options C.MethodOptions) (C.Method, error) { 49 | m := &Method{} 50 | switch methodName { 51 | case "aes-128-ctr": 52 | m.keyLength = 16 53 | m.saltLength = aes.BlockSize 54 | m.encryptConstructor = blockStream(aes.NewCipher, cipher.NewCTR) 55 | m.decryptConstructor = blockStream(aes.NewCipher, cipher.NewCTR) 56 | case "aes-192-ctr": 57 | m.keyLength = 24 58 | m.saltLength = aes.BlockSize 59 | m.encryptConstructor = blockStream(aes.NewCipher, cipher.NewCTR) 60 | m.decryptConstructor = blockStream(aes.NewCipher, cipher.NewCTR) 61 | case "aes-256-ctr": 62 | m.keyLength = 32 63 | m.saltLength = aes.BlockSize 64 | m.encryptConstructor = blockStream(aes.NewCipher, cipher.NewCTR) 65 | m.decryptConstructor = blockStream(aes.NewCipher, cipher.NewCTR) 66 | case "aes-128-cfb": 67 | m.keyLength = 16 68 | m.saltLength = aes.BlockSize 69 | m.encryptConstructor = blockStream(aes.NewCipher, cipher.NewCFBEncrypter) 70 | m.decryptConstructor = blockStream(aes.NewCipher, cipher.NewCFBDecrypter) 71 | case "aes-192-cfb": 72 | m.keyLength = 24 73 | m.saltLength = aes.BlockSize 74 | m.encryptConstructor = blockStream(aes.NewCipher, cipher.NewCFBEncrypter) 75 | m.decryptConstructor = blockStream(aes.NewCipher, cipher.NewCFBDecrypter) 76 | case "aes-256-cfb": 77 | m.keyLength = 32 78 | m.saltLength = aes.BlockSize 79 | m.encryptConstructor = blockStream(aes.NewCipher, cipher.NewCFBEncrypter) 80 | m.decryptConstructor = blockStream(aes.NewCipher, cipher.NewCFBDecrypter) 81 | case "rc4-md5": 82 | m.keyLength = 16 83 | m.saltLength = 16 84 | m.encryptConstructor = func(key []byte, salt []byte) (cipher.Stream, error) { 85 | h := md5.New() 86 | h.Write(key) 87 | h.Write(salt) 88 | return rc4.NewCipher(h.Sum(nil)) 89 | } 90 | m.decryptConstructor = func(key []byte, salt []byte) (cipher.Stream, error) { 91 | h := md5.New() 92 | h.Write(key) 93 | h.Write(salt) 94 | return rc4.NewCipher(h.Sum(nil)) 95 | } 96 | case "chacha20-ietf": 97 | m.keyLength = chacha20.KeySize 98 | m.saltLength = chacha20.NonceSize 99 | m.encryptConstructor = func(key []byte, salt []byte) (cipher.Stream, error) { 100 | return chacha20.NewUnauthenticatedCipher(key, salt) 101 | } 102 | m.decryptConstructor = func(key []byte, salt []byte) (cipher.Stream, error) { 103 | return chacha20.NewUnauthenticatedCipher(key, salt) 104 | } 105 | case "xchacha20": 106 | m.keyLength = chacha20.KeySize 107 | m.saltLength = chacha20.NonceSizeX 108 | m.encryptConstructor = func(key []byte, salt []byte) (cipher.Stream, error) { 109 | return chacha20.NewUnauthenticatedCipher(key, salt) 110 | } 111 | m.decryptConstructor = func(key []byte, salt []byte) (cipher.Stream, error) { 112 | return chacha20.NewUnauthenticatedCipher(key, salt) 113 | } 114 | default: 115 | return nil, os.ErrInvalid 116 | } 117 | if len(options.Key) == m.keyLength { 118 | m.key = options.Key 119 | } else if len(options.Key) > 0 { 120 | return nil, E.New("bad key length, required ", m.keyLength, ", got ", len(options.Key)) 121 | } else if options.Password != "" { 122 | m.key = legacykey.Key([]byte(options.Password), m.keyLength) 123 | } else { 124 | return nil, C.ErrMissingPassword 125 | } 126 | return m, nil 127 | } 128 | 129 | func blockStream(blockCreator func(key []byte) (cipher.Block, error), streamCreator func(block cipher.Block, iv []byte) cipher.Stream) func([]byte, []byte) (cipher.Stream, error) { 130 | return func(key []byte, iv []byte) (cipher.Stream, error) { 131 | block, err := blockCreator(key) 132 | if err != nil { 133 | return nil, err 134 | } 135 | return streamCreator(block, iv), err 136 | } 137 | } 138 | 139 | func (m *Method) DialConn(conn net.Conn, destination M.Socksaddr) (net.Conn, error) { 140 | ssConn := &clientConn{ 141 | ExtendedConn: bufio.NewExtendedConn(conn), 142 | method: m, 143 | destination: destination, 144 | } 145 | return ssConn, common.Error(ssConn.Write(nil)) 146 | } 147 | 148 | func (m *Method) DialEarlyConn(conn net.Conn, destination M.Socksaddr) net.Conn { 149 | return &clientConn{ 150 | ExtendedConn: bufio.NewExtendedConn(conn), 151 | method: m, 152 | destination: destination, 153 | } 154 | } 155 | 156 | func (m *Method) DialPacketConn(conn net.Conn) N.NetPacketConn { 157 | return &clientPacketConn{ 158 | ExtendedConn: bufio.NewExtendedConn(conn), 159 | method: m, 160 | } 161 | } 162 | 163 | type clientConn struct { 164 | N.ExtendedConn 165 | method *Method 166 | destination M.Socksaddr 167 | readStream cipher.Stream 168 | writeStream cipher.Stream 169 | } 170 | 171 | func (c *clientConn) readResponse() error { 172 | saltBuffer := buf.NewSize(c.method.saltLength) 173 | defer saltBuffer.Release() 174 | _, err := saltBuffer.ReadFullFrom(c.ExtendedConn, c.method.saltLength) 175 | if err != nil { 176 | return err 177 | } 178 | c.readStream, err = c.method.decryptConstructor(c.method.key, saltBuffer.Bytes()) 179 | return err 180 | } 181 | 182 | func (c *clientConn) Read(p []byte) (n int, err error) { 183 | if c.readStream == nil { 184 | err = c.readResponse() 185 | if err != nil { 186 | return 187 | } 188 | } 189 | n, err = c.ExtendedConn.Read(p) 190 | if err != nil { 191 | return 192 | } 193 | c.readStream.XORKeyStream(p[:n], p[:n]) 194 | return 195 | } 196 | 197 | func (c *clientConn) Write(p []byte) (n int, err error) { 198 | if c.writeStream == nil { 199 | buffer := buf.NewSize(c.method.saltLength + M.SocksaddrSerializer.AddrPortLen(c.destination) + len(p)) 200 | defer buffer.Release() 201 | buffer.WriteRandom(c.method.saltLength) 202 | err = M.SocksaddrSerializer.WriteAddrPort(buffer, c.destination) 203 | if err != nil { 204 | return 205 | } 206 | common.Must1(buffer.Write(p)) 207 | c.writeStream, err = c.method.encryptConstructor(c.method.key, buffer.To(c.method.saltLength)) 208 | if err != nil { 209 | return 210 | } 211 | c.writeStream.XORKeyStream(buffer.From(c.method.saltLength), buffer.From(c.method.saltLength)) 212 | _, err = c.ExtendedConn.Write(buffer.Bytes()) 213 | if err == nil { 214 | n = len(p) 215 | } 216 | return 217 | } 218 | c.writeStream.XORKeyStream(p, p) 219 | return c.ExtendedConn.Write(p) 220 | } 221 | 222 | func (c *clientConn) ReadBuffer(buffer *buf.Buffer) error { 223 | if c.readStream == nil { 224 | err := c.readResponse() 225 | if err != nil { 226 | return err 227 | } 228 | } 229 | err := c.ExtendedConn.ReadBuffer(buffer) 230 | if err != nil { 231 | return err 232 | } 233 | c.readStream.XORKeyStream(buffer.Bytes(), buffer.Bytes()) 234 | return nil 235 | } 236 | 237 | func (c *clientConn) WriteBuffer(buffer *buf.Buffer) error { 238 | if c.writeStream == nil { 239 | header := buf.With(buffer.ExtendHeader(c.method.saltLength + M.SocksaddrSerializer.AddrPortLen(c.destination))) 240 | header.WriteRandom(c.method.saltLength) 241 | err := M.SocksaddrSerializer.WriteAddrPort(header, c.destination) 242 | if err != nil { 243 | return err 244 | } 245 | c.writeStream, err = c.method.encryptConstructor(c.method.key, header.To(c.method.saltLength)) 246 | if err != nil { 247 | return err 248 | } 249 | c.writeStream.XORKeyStream(buffer.From(c.method.saltLength), buffer.From(c.method.saltLength)) 250 | } else { 251 | c.writeStream.XORKeyStream(buffer.Bytes(), buffer.Bytes()) 252 | } 253 | return c.ExtendedConn.WriteBuffer(buffer) 254 | } 255 | 256 | func (c *clientConn) FrontHeadroom() int { 257 | if c.writeStream == nil { 258 | return c.method.saltLength + M.SocksaddrSerializer.AddrPortLen(c.destination) 259 | } 260 | return 0 261 | } 262 | 263 | func (c *clientConn) NeedHandshake() bool { 264 | return c.writeStream == nil 265 | } 266 | 267 | func (c *clientConn) Upstream() any { 268 | return c.ExtendedConn 269 | } 270 | 271 | type clientPacketConn struct { 272 | N.ExtendedConn 273 | method *Method 274 | } 275 | 276 | func (c *clientPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { 277 | err = c.ReadBuffer(buffer) 278 | if err != nil { 279 | return 280 | } 281 | stream, err := c.method.decryptConstructor(c.method.key, buffer.To(c.method.saltLength)) 282 | if err != nil { 283 | return 284 | } 285 | stream.XORKeyStream(buffer.From(c.method.saltLength), buffer.From(c.method.saltLength)) 286 | buffer.Advance(c.method.saltLength) 287 | destination, err = M.SocksaddrSerializer.ReadAddrPort(buffer) 288 | if err != nil { 289 | return 290 | } 291 | return destination.Unwrap(), nil 292 | } 293 | 294 | func (c *clientPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { 295 | header := buf.With(buffer.ExtendHeader(c.method.saltLength + M.SocksaddrSerializer.AddrPortLen(destination))) 296 | header.WriteRandom(c.method.saltLength) 297 | err := M.SocksaddrSerializer.WriteAddrPort(header, destination) 298 | if err != nil { 299 | return err 300 | } 301 | stream, err := c.method.encryptConstructor(c.method.key, buffer.To(c.method.saltLength)) 302 | if err != nil { 303 | return err 304 | } 305 | stream.XORKeyStream(buffer.From(c.method.saltLength), buffer.From(c.method.saltLength)) 306 | return c.ExtendedConn.WriteBuffer(buffer) 307 | } 308 | 309 | func (c *clientPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { 310 | n, err = c.ExtendedConn.Read(p) 311 | if err != nil { 312 | return 313 | } 314 | stream, err := c.method.decryptConstructor(c.method.key, p[:c.method.saltLength]) 315 | if err != nil { 316 | return 317 | } 318 | buffer := buf.As(p[c.method.saltLength:n]) 319 | stream.XORKeyStream(buffer.Bytes(), buffer.Bytes()) 320 | destination, err := M.SocksaddrSerializer.ReadAddrPort(buffer) 321 | if err != nil { 322 | return 323 | } 324 | if destination.IsFqdn() { 325 | addr = destination 326 | } else { 327 | addr = destination.UDPAddr() 328 | } 329 | n = copy(p, buffer.Bytes()) 330 | return 331 | } 332 | 333 | func (c *clientPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { 334 | destination := M.SocksaddrFromNet(addr) 335 | buffer := buf.NewSize(c.method.saltLength + M.SocksaddrSerializer.AddrPortLen(destination) + len(p)) 336 | defer buffer.Release() 337 | buffer.WriteRandom(c.method.saltLength) 338 | err = M.SocksaddrSerializer.WriteAddrPort(buffer, destination) 339 | if err != nil { 340 | return 341 | } 342 | stream, err := c.method.encryptConstructor(c.method.key, buffer.To(c.method.saltLength)) 343 | if err != nil { 344 | return 345 | } 346 | stream.XORKeyStream(buffer.From(c.method.saltLength), buffer.From(c.method.saltLength)) 347 | stream.XORKeyStream(buffer.Extend(len(p)), p) 348 | _, err = c.ExtendedConn.Write(buffer.Bytes()) 349 | if err == nil { 350 | n = len(p) 351 | } 352 | return 353 | } 354 | 355 | func (c *clientPacketConn) FrontHeadroom() int { 356 | return c.method.saltLength + M.MaxSocksaddrLength 357 | } 358 | 359 | func (c *clientPacketConn) Upstream() any { 360 | return c.ExtendedConn 361 | } 362 | --------------------------------------------------------------------------------