Compare commits

...

10 commits
v0.2.2 ... dev

Author SHA1 Message Date
世界
33d53914d7
Update dependencies 2024-07-05 09:04:03 +08:00
wwqgtxx
54dd1546c6
Cleanup unneeded deadline 2024-07-05 09:00:19 +08:00
wwqgtxx
e3930e4fe3
Fix AEAD multi-user service not working with packet 2024-07-05 08:59:46 +08:00
世界
a9d165b21b
Fix buffer usage 2023-12-08 18:16:57 +08:00
世界
fed8d42732
Update dependencies 2023-12-08 18:16:57 +08:00
世界
f86df97602
Add service.NewConnection0 stub func 2023-12-08 18:16:44 +08:00
世界
0c1612d823
Update dependencies 2023-09-20 22:16:53 +08:00
世界
126234728c
Fix WriteAddrPort usage 2023-09-07 08:56:10 +08:00
世界
a446ff2f57
Update dependencies 2023-07-23 14:10:01 +08:00
世界
b044960bd3
Remove stack buffer usage 2023-07-03 21:13:47 +08:00
16 changed files with 227 additions and 262 deletions

View file

@ -1,43 +0,0 @@
name: Debug build
on:
push:
branches:
- dev
paths-ignore:
- '**.md'
- '.github/**'
- '!.github/workflows/debug.yml'
pull_request:
branches:
- dev
jobs:
build:
name: Debug build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get latest go version
id: version
run: |
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')
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: ${{ steps.version.outputs.go_version }}
- name: Add cache to Go proxy
run: |
version=`git rev-parse HEAD`
mkdir build
pushd build
go mod init build
go get -v github.com/sagernet/sing-shadowsocks@$version
popd
continue-on-error: true
- name: Build
run: |
make test

View file

@ -1,8 +1,9 @@
name: Lint
name: lint
on:
push:
branches:
- main
- dev
paths-ignore:
- '**.md'
@ -10,6 +11,7 @@ on:
- '!.github/workflows/lint.yml'
pull_request:
branches:
- main
- dev
jobs:
@ -18,24 +20,20 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get latest go version
id: version
run: |
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')
- name: Setup Go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: ${{ steps.version.outputs.go_version }}
go-version: ^1.22
- name: Cache go module
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: |
~/go/pkg/mod
key: go-${{ hashFiles('**/go.sum') }}
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@v6
with:
version: latest

112
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,112 @@
name: test
on:
push:
branches:
- main
- dev
paths-ignore:
- '**.md'
- '.github/**'
- '!.github/workflows/debug.yml'
pull_request:
branches:
- main
- dev
jobs:
build:
name: Linux
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.22
- name: Build
run: |
make test
build_go118:
name: Linux (Go 1.18)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.18
continue-on-error: true
- name: Build
run: |
make test
build_go120:
name: Linux (Go 1.20)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.20
continue-on-error: true
- name: Build
run: |
make test
build_go121:
name: Linux (Go 1.21)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ~1.21
continue-on-error: true
- name: Build
run: |
make test
build_windows:
name: Windows
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.22
continue-on-error: true
- name: Build
run: |
make test
build_darwin:
name: macOS
runs-on: macos-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: ^1.22
continue-on-error: true
- name: Build
run: |
make test

View file

@ -13,5 +13,3 @@ linters-settings:
- standard
- prefix(github.com/sagernet/)
- default
staticcheck:
go: '1.20'

View file

@ -1,7 +1,7 @@
fmt:
@gofumpt -l -w .
@gofmt -s -w .
@gci write --custom-order -s "standard,prefix(github.com/sagernet/),default" .
@gci write --custom-order -s standard -s "prefix(github.com/sagernet/)" -s "default" .
fmt_install:
go install -v mvdan.cc/gofumpt@latest

8
go.mod
View file

@ -3,12 +3,12 @@ module github.com/sagernet/sing-shadowsocks
go 1.18
require (
github.com/sagernet/sing v0.2.5
golang.org/x/crypto v0.10.0
lukechampine.com/blake3 v1.2.1
github.com/sagernet/sing v0.4.1
golang.org/x/crypto v0.23.0
lukechampine.com/blake3 v1.3.0
)
require (
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/sys v0.21.0 // indirect
)

22
go.sum
View file

@ -1,10 +1,16 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE=
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
github.com/sagernet/sing v0.2.5 h1:N8sUluR8GZvR9DqUiH3FA3vBb4m/EDdOVTYUrDzJvmY=
github.com/sagernet/sing v0.2.5/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI=
lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk=
github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE=
lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k=

17
none.go
View file

@ -2,13 +2,11 @@ package shadowsocks
import (
"context"
"io"
"net"
"net/netip"
"github.com/sagernet/sing/common"
"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"
"github.com/sagernet/sing/common/udpnat"
@ -96,17 +94,6 @@ func (c *noneConn) FrontHeadroom() int {
return 0
}
func (c *noneConn) ReadFrom(r io.Reader) (n int64, err error) {
if !c.handshake {
return bufio.ReadFrom0(c, r)
}
return bufio.Copy(c.Conn, r)
}
func (c *noneConn) WriteTo(w io.Writer) (n int64, err error) {
return bufio.Copy(w, c.Conn)
}
func (c *noneConn) RemoteAddr() net.Addr {
return c.destination.TCPAddr()
}
@ -166,9 +153,7 @@ func (c *nonePacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
func (c *nonePacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
destination := M.SocksaddrFromNet(addr)
_buffer := buf.StackNewSize(M.SocksaddrSerializer.AddrPortLen(destination) + len(p))
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
buffer := buf.NewSize(M.SocksaddrSerializer.AddrPortLen(destination) + len(p))
defer buffer.Release()
err = M.SocksaddrSerializer.WriteAddrPort(buffer, destination)
if err != nil {

View file

@ -10,7 +10,6 @@ import (
"github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing/common"
"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"
"github.com/sagernet/sing/common/rw"
@ -118,19 +117,15 @@ type clientConn struct {
}
func (c *clientConn) writeRequest(payload []byte) error {
_salt := buf.StackNewSize(c.keySaltLength)
defer common.KeepAlive(_salt)
salt := common.Dup(_salt)
salt := buf.NewSize(c.keySaltLength)
defer salt.Release()
salt.WriteRandom(c.keySaltLength)
_key := buf.StackNewSize(c.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(c.keySaltLength)
Kdf(c.key, salt.Bytes(), key)
writeCipher, err := c.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return err
}
@ -166,17 +161,13 @@ func (c *clientConn) writeRequest(payload []byte) error {
}
func (c *clientConn) readResponse() error {
_salt := buf.StackNewSize(c.keySaltLength)
defer common.KeepAlive(_salt)
salt := common.Dup(_salt)
salt := buf.NewSize(c.keySaltLength)
defer salt.Release()
_, err := salt.ReadFullFrom(c.Conn, c.keySaltLength)
if err != nil {
return err
}
_key := buf.StackNewSize(c.keySaltLength)
defer common.KeepAlive(_key)
key := common.Dup(_key)
key := buf.NewSize(c.keySaltLength)
defer key.Release()
Kdf(c.key, salt.Bytes(), key)
readCipher, err := c.constructor(key.Bytes())
@ -220,13 +211,6 @@ func (c *clientConn) Write(p []byte) (n int, err error) {
return c.writer.Write(p)
}
func (c *clientConn) ReadFrom(r io.Reader) (n int64, err error) {
if c.writer == nil {
return bufio.ReadFrom0(c, r)
}
return c.writer.ReadFrom(r)
}
func (c *clientConn) NeedHandshake() bool {
return c.writer == nil
}
@ -248,13 +232,14 @@ func (c *clientPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksad
defer buffer.Release()
header := buf.With(buffer.ExtendHeader(c.keySaltLength + M.SocksaddrSerializer.AddrPortLen(destination)))
header.WriteRandom(c.keySaltLength)
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
_key := buf.StackNewSize(c.keySaltLength)
key := common.Dup(_key)
err := M.SocksaddrSerializer.WriteAddrPort(header, destination)
if err != nil {
return err
}
key := buf.NewSize(c.keySaltLength)
Kdf(c.key, buffer.To(c.keySaltLength), key)
writeCipher, err := c.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return err
}
@ -272,12 +257,10 @@ func (c *clientPacketConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
if buffer.Len() < c.keySaltLength {
return M.Socksaddr{}, io.ErrShortBuffer
}
_key := buf.StackNewSize(c.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(c.keySaltLength)
Kdf(c.key, buffer.To(c.keySaltLength), key)
readCipher, err := c.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return M.Socksaddr{}, err
}
@ -310,9 +293,8 @@ func (c *clientPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
func (c *clientPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
destination := M.SocksaddrFromNet(addr)
_buffer := buf.StackNewSize(c.keySaltLength + M.SocksaddrSerializer.AddrPortLen(destination) + len(p) + Overhead)
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
buffer := buf.NewSize(c.keySaltLength + M.SocksaddrSerializer.AddrPortLen(destination) + len(p) + Overhead)
defer buffer.Release()
buffer.Resize(c.keySaltLength+M.SocksaddrSerializer.AddrPortLen(destination), 0)
common.Must1(buffer.Write(p))
err = c.WritePacket(buffer, destination)

View file

@ -11,7 +11,6 @@ import (
"github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@ -60,9 +59,7 @@ func (s *Service) NewConnection(ctx context.Context, conn net.Conn, metadata M.M
}
func (s *Service) newConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
_header := buf.StackNewSize(s.keySaltLength + PacketLengthBufferSize + Overhead)
defer common.KeepAlive(_header)
header := common.Dup(_header)
header := buf.NewSize(s.keySaltLength + PacketLengthBufferSize + Overhead)
defer header.Release()
_, err := header.ReadFullFrom(conn, header.FreeLen())
@ -72,12 +69,10 @@ func (s *Service) newConnection(ctx context.Context, conn net.Conn, metadata M.M
return ErrBadHeader
}
_key := buf.StackNewSize(s.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(s.keySaltLength)
Kdf(s.key, header.To(s.keySaltLength), key)
readCipher, err := s.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return err
}
@ -116,20 +111,16 @@ type serverConn struct {
}
func (c *serverConn) writeResponse(payload []byte) (n int, err error) {
_salt := buf.StackNewSize(c.keySaltLength)
salt := common.Dup(_salt)
salt := buf.NewSize(c.keySaltLength)
salt.WriteRandom(c.keySaltLength)
_key := buf.StackNewSize(c.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(c.keySaltLength)
Kdf(c.key, salt.Bytes(), key)
writeCipher, err := c.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
salt.Release()
common.KeepAlive(_salt)
return
}
writer := NewWriter(c.Conn, writeCipher, MaxPacketSize)
@ -137,7 +128,6 @@ func (c *serverConn) writeResponse(payload []byte) (n int, err error) {
header := writer.Buffer()
common.Must1(header.Write(salt.Bytes()))
salt.Release()
common.KeepAlive(_salt)
bufferedWriter := writer.BufferedWriter(header.Len())
if len(payload) > 0 {
@ -173,13 +163,6 @@ func (c *serverConn) Write(p []byte) (n int, err error) {
return c.writeResponse(p)
}
func (c *serverConn) ReadFrom(r io.Reader) (n int64, err error) {
if c.writer == nil {
return bufio.ReadFrom0(c, r)
}
return c.writer.ReadFrom(r)
}
func (c *serverConn) WriteTo(w io.Writer) (n int64, err error) {
return c.reader.WriteTo(w)
}
@ -211,12 +194,10 @@ func (s *Service) newPacket(ctx context.Context, conn N.PacketConn, buffer *buf.
if buffer.Len() < s.keySaltLength {
return io.ErrShortBuffer
}
_key := buf.StackNewSize(s.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(s.keySaltLength)
Kdf(s.key, buffer.To(s.keySaltLength), key)
readCipher, err := s.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return err
}
@ -254,12 +235,10 @@ func (w *serverPacketWriter) WritePacket(buffer *buf.Buffer, destination M.Socks
buffer.Release()
return err
}
_key := buf.StackNewSize(w.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(w.keySaltLength)
Kdf(w.key, buffer.To(w.keySaltLength), key)
writeCipher, err := w.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return err
}

View file

@ -8,10 +8,8 @@ import (
"net/netip"
"github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio/deadline"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
@ -85,9 +83,7 @@ func (s *MultiService[U]) newConnection(ctx context.Context, conn net.Conn, meta
if method == nil {
return shadowsocks.ErrNoUsers
}
_header := buf.StackNewSize(method.keySaltLength + PacketLengthBufferSize + Overhead)
defer common.KeepAlive(_header)
header := common.Dup(_header)
header := buf.NewSize(method.keySaltLength + PacketLengthBufferSize + Overhead)
defer header.Release()
_, err := header.ReadFullFrom(conn, header.FreeLen())
@ -100,12 +96,10 @@ func (s *MultiService[U]) newConnection(ctx context.Context, conn net.Conn, meta
var reader *Reader
var readCipher cipher.AEAD
for u, m := range s.methodMap {
_key := buf.StackNewSize(method.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(method.keySaltLength)
Kdf(m.key, header.To(m.keySaltLength), key)
readCipher, err = m.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return err
}
@ -131,11 +125,11 @@ func (s *MultiService[U]) newConnection(ctx context.Context, conn net.Conn, meta
metadata.Protocol = "shadowsocks"
metadata.Destination = destination
return s.handler.NewConnection(auth.ContextWithUser(ctx, user), deadline.NewConn(&serverConn{
return s.handler.NewConnection(auth.ContextWithUser(ctx, user), &serverConn{
Method: method,
Conn: conn,
reader: reader,
}), metadata)
}, metadata)
}
func (s *MultiService[U]) WriteIsThreadUnsafe() {
@ -164,24 +158,24 @@ func (s *MultiService[U]) newPacket(ctx context.Context, conn N.PacketConn, buff
}
var readCipher cipher.AEAD
var err error
decrypted := make([]byte, 0, buffer.Len())
for u, m := range s.methodMap {
_key := buf.StackNewSize(m.keySaltLength)
key := common.Dup(_key)
key := buf.NewSize(m.keySaltLength)
Kdf(m.key, buffer.To(m.keySaltLength), key)
readCipher, err = m.constructor(key.Bytes())
key.Release()
common.KeepAlive(_key)
if err != nil {
return err
}
var packet []byte
packet, err = readCipher.Open(buffer.Index(m.keySaltLength), rw.ZeroBytes[:readCipher.NonceSize()], buffer.From(m.keySaltLength), nil)
packet, err = readCipher.Open(decrypted, rw.ZeroBytes[:readCipher.NonceSize()], buffer.From(m.keySaltLength), nil)
if err != nil {
continue
}
buffer.Advance(m.keySaltLength)
buffer.Truncate(len(packet))
copy(buffer.Bytes(), packet)
user, method = u, m
break

View file

@ -156,10 +156,10 @@ func Key(key []byte, keyLength int) []byte {
}
func SessionKey(psk []byte, salt []byte, keyLength int) []byte {
sessionKey := buf.Make(len(psk) + len(salt))
sessionKey := make([]byte, len(psk)+len(salt))
copy(sessionKey, psk)
copy(sessionKey[len(psk):], salt)
outKey := buf.Make(keyLength)
outKey := make([]byte, keyLength)
blake3.DeriveKey(outKey, "shadowsocks 2022 session subkey", sessionKey)
return outKey
}
@ -236,11 +236,10 @@ func (m *Method) writeExtendedIdentityHeaders(request *buf.Buffer, salt []byte)
return nil
}
for i, psk := range m.pskList {
keyMaterial := buf.Make(m.keySaltLength * 2)
keyMaterial := make([]byte, m.keySaltLength*2)
copy(keyMaterial, psk)
copy(keyMaterial[m.keySaltLength:], salt)
_identitySubkey := buf.StackNewSize(m.keySaltLength)
identitySubkey := common.Dup(_identitySubkey)
identitySubkey := buf.NewSize(m.keySaltLength)
identitySubkey.Extend(identitySubkey.FreeLen())
blake3.DeriveKey(identitySubkey.Bytes(), "shadowsocks 2022 identity subkey", keyMaterial)
@ -253,7 +252,6 @@ func (m *Method) writeExtendedIdentityHeaders(request *buf.Buffer, salt []byte)
}
b.Encrypt(header, pskHash)
identitySubkey.Release()
common.KeepAlive(_identitySubkey)
if i == pskLen-2 {
break
}
@ -266,7 +264,7 @@ func (c *clientConn) writeRequest(payload []byte) error {
common.Must1(io.ReadFull(rand.Reader, salt))
key := SessionKey(c.pskList[len(c.pskList)-1], salt, c.keySaltLength)
writeCipher, err := c.constructor(common.Dup(key))
writeCipher, err := c.constructor(key)
if err != nil {
return err
}
@ -275,7 +273,6 @@ func (c *clientConn) writeRequest(payload []byte) error {
writeCipher,
MaxPacketSize,
)
common.KeepAlive(key)
header := writer.Buffer()
header.Write(salt)
@ -286,7 +283,7 @@ func (c *clientConn) writeRequest(payload []byte) error {
}
var _fixedLengthBuffer [RequestHeaderFixedChunkLength]byte
fixedLengthBuffer := buf.With(common.Dup(_fixedLengthBuffer[:]))
fixedLengthBuffer := buf.With(_fixedLengthBuffer[:])
common.Must(fixedLengthBuffer.WriteByte(HeaderTypeClient))
common.Must(binary.Write(fixedLengthBuffer, binary.BigEndian, uint64(c.time().Unix())))
var paddingLen int
@ -297,12 +294,13 @@ func (c *clientConn) writeRequest(payload []byte) error {
payloadLen := len(payload)
variableLengthHeaderLen += payloadLen
common.Must(binary.Write(fixedLengthBuffer, binary.BigEndian, uint16(variableLengthHeaderLen)))
writer.WriteChunk(header, fixedLengthBuffer.Slice())
common.KeepAlive(_fixedLengthBuffer)
writer.WriteChunk(header, fixedLengthBuffer.Bytes())
_variableLengthBuffer := buf.StackNewSize(variableLengthHeaderLen)
variableLengthBuffer := common.Dup(_variableLengthBuffer)
common.Must(M.SocksaddrSerializer.WriteAddrPort(variableLengthBuffer, c.destination))
variableLengthBuffer := buf.NewSize(variableLengthHeaderLen)
err = M.SocksaddrSerializer.WriteAddrPort(variableLengthBuffer, c.destination)
if err != nil {
return err
}
common.Must(binary.Write(variableLengthBuffer, binary.BigEndian, uint16(paddingLen)))
if paddingLen > 0 {
variableLengthBuffer.Extend(paddingLen)
@ -310,8 +308,7 @@ func (c *clientConn) writeRequest(payload []byte) error {
if payloadLen > 0 {
common.Must1(variableLengthBuffer.Write(payload[:payloadLen]))
}
writer.WriteChunk(header, variableLengthBuffer.Slice())
common.KeepAlive(_variableLengthBuffer)
writer.WriteChunk(header, variableLengthBuffer.Bytes())
variableLengthBuffer.Release()
err = writer.BufferedWriter(header.Len()).Flush()
@ -329,22 +326,18 @@ func (c *clientConn) readResponse() error {
return nil
}
_salt := buf.StackNewSize(c.keySaltLength)
salt := common.Dup(_salt)
salt := buf.NewSize(c.keySaltLength)
_, err := salt.ReadFullFrom(c.Conn, salt.FreeLen())
if err != nil {
salt.Release()
common.KeepAlive(_salt)
return err
}
key := SessionKey(c.pskList[len(c.pskList)-1], salt.Bytes(), c.keySaltLength)
salt.Release()
common.KeepAlive(_salt)
readCipher, err := c.constructor(common.Dup(key))
readCipher, err := c.constructor(key)
if err != nil {
return err
}
@ -353,7 +346,6 @@ func (c *clientConn) readResponse() error {
readCipher,
MaxPacketSize,
)
common.KeepAlive(key)
err = reader.ReadWithLength(uint16(1 + 8 + c.keySaltLength + 2))
if err != nil {
@ -379,8 +371,7 @@ func (c *clientConn) readResponse() error {
return E.Extend(ErrBadTimestamp, "received ", epoch, ", diff ", diff, "s")
}
_requestSalt := buf.StackNewSize(c.keySaltLength)
requestSalt := common.Dup(_requestSalt)
requestSalt := buf.NewSize(c.keySaltLength)
_, err = requestSalt.ReadFullFrom(reader, requestSalt.FreeLen())
if err != nil {
return err
@ -390,7 +381,6 @@ func (c *clientConn) readResponse() error {
return ErrBadRequestSalt
}
requestSalt.Release()
common.KeepAlive(_requestSalt)
c.requestSalt = nil
var length uint16
@ -449,13 +439,6 @@ func (c *clientConn) WriteVectorised(buffers []*buf.Buffer) error {
return c.writer.WriteVectorised(buffers[1:])
}
func (c *clientConn) ReadFrom(r io.Reader) (n int64, err error) {
if c.writer == nil {
return bufio.ReadFrom0(c, r)
}
return bufio.Copy(c.writer, r)
}
func (c *clientConn) NeedHandshake() bool {
return c.writer == nil
}
@ -620,11 +603,10 @@ func (c *clientPacketConn) ReadPacket(buffer *buf.Buffer) (M.Socksaddr, error) {
remoteCipher = c.session.lastRemoteCipher
} else {
key := SessionKey(c.pskList[len(c.pskList)-1], packetHeader[:8], c.keySaltLength)
remoteCipher, err = c.constructor(common.Dup(key))
remoteCipher, err = c.constructor(key)
if err != nil {
return M.Socksaddr{}, err
}
common.KeepAlive(key)
}
_, err = remoteCipher.Open(buffer.Index(0), packetHeader[4:16], buffer.Bytes(), nil)
if err != nil {
@ -737,9 +719,7 @@ func (c *clientPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
overHead += paddingLen
overHead += M.SocksaddrSerializer.AddrPortLen(destination)
_buffer := buf.StackNewSize(overHead + len(p))
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
buffer := buf.NewSize(overHead + len(p))
defer buffer.Release()
var dataIndex int
@ -863,11 +843,10 @@ func (m *Method) newUDPSession() *udpSession {
binary.BigEndian.PutUint64(sessionId, session.sessionId)
key := SessionKey(m.pskList[len(m.pskList)-1], sessionId, m.keySaltLength)
var err error
session.cipher, err = m.constructor(common.Dup(key))
session.cipher, err = m.constructor(key)
if err != nil {
return nil
}
common.KeepAlive(key)
}
return session
}

View file

@ -11,7 +11,6 @@ import (
"github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/auth"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
@ -153,9 +152,7 @@ func (s *RelayService[U]) NewConnection(ctx context.Context, conn net.Conn, meta
}
func (s *RelayService[U]) newConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
_requestHeader := buf.StackNew()
defer common.KeepAlive(_requestHeader)
requestHeader := common.Dup(_requestHeader)
requestHeader := buf.New()
defer requestHeader.Release()
n, err := requestHeader.ReadOnceFrom(conn)
if err != nil {
@ -165,19 +162,17 @@ func (s *RelayService[U]) newConnection(ctx context.Context, conn net.Conn, meta
}
requestSalt := requestHeader.To(s.keySaltLength)
var _eiHeader [aes.BlockSize]byte
eiHeader := common.Dup(_eiHeader[:])
eiHeader := _eiHeader[:]
copy(eiHeader, requestHeader.Range(s.keySaltLength, s.keySaltLength+aes.BlockSize))
keyMaterial := buf.Make(s.keySaltLength * 2)
keyMaterial := make([]byte, s.keySaltLength*2)
copy(keyMaterial, s.iPSK)
copy(keyMaterial[s.keySaltLength:], requestSalt)
_identitySubkey := buf.StackNewSize(s.keySaltLength)
identitySubkey := common.Dup(_identitySubkey)
identitySubkey := buf.NewSize(s.keySaltLength)
identitySubkey.Extend(identitySubkey.FreeLen())
blake3.DeriveKey(identitySubkey.Bytes(), "shadowsocks 2022 identity subkey", keyMaterial)
b, err := s.blockConstructor(identitySubkey.Bytes())
identitySubkey.Release()
common.KeepAlive(_identitySubkey)
if err != nil {
return err
}
@ -189,7 +184,6 @@ func (s *RelayService[U]) newConnection(ctx context.Context, conn net.Conn, meta
} else {
return E.New("invalid request")
}
common.KeepAlive(_eiHeader)
copy(requestHeader.Range(aes.BlockSize, aes.BlockSize+s.keySaltLength), requestHeader.To(s.keySaltLength))
requestHeader.Advance(aes.BlockSize)
@ -218,7 +212,7 @@ func (s *RelayService[U]) newPacket(ctx context.Context, conn N.PacketConn, buff
sessionId := binary.BigEndian.Uint64(packetHeader)
var _eiHeader [aes.BlockSize]byte
eiHeader := common.Dup(_eiHeader[:])
eiHeader := _eiHeader[:]
s.udpBlockCipher.Decrypt(eiHeader, buffer.Range(aes.BlockSize, 2*aes.BlockSize))
xorWords(eiHeader, eiHeader, packetHeader)

View file

@ -20,7 +20,6 @@ import (
"github.com/sagernet/sing-shadowsocks/shadowaead"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/cache"
E "github.com/sagernet/sing/common/exceptions"
M "github.com/sagernet/sing/common/metadata"
@ -32,8 +31,9 @@ import (
)
var (
ErrNoPadding = E.New("bad request: missing payload or padding")
ErrBadPadding = E.New("bad request: damaged padding")
ErrInvalidRequest = E.New("invalid request")
ErrNoPadding = E.New("bad request: missing payload or padding")
ErrBadPadding = E.New("bad request: damaged padding")
)
var _ shadowsocks.Service = (*Service)(nil)
@ -162,7 +162,7 @@ func (s *Service) newConnection(ctx context.Context, conn net.Conn, metadata M.M
}
requestKey := SessionKey(s.psk, requestSalt, s.keySaltLength)
readCipher, err := s.constructor(common.Dup(requestKey))
readCipher, err := s.constructor(requestKey)
if err != nil {
return err
}
@ -171,7 +171,6 @@ func (s *Service) newConnection(ctx context.Context, conn net.Conn, metadata M.M
readCipher,
MaxPacketSize,
)
common.KeepAlive(requestKey)
err = reader.ReadExternalChunk(header[s.keySaltLength:])
if err != nil {
@ -260,16 +259,13 @@ type serverConn struct {
}
func (c *serverConn) writeResponse(payload []byte) (n int, err error) {
_salt := buf.StackNewSize(c.keySaltLength)
salt := common.Dup(_salt)
salt := buf.NewSize(c.keySaltLength)
salt.WriteRandom(salt.FreeLen())
key := SessionKey(c.uPSK, salt.Bytes(), c.keySaltLength)
common.KeepAlive(_salt)
writeCipher, err := c.constructor(common.Dup(key))
writeCipher, err := c.constructor(key)
if err != nil {
salt.Release()
common.KeepAlive(_salt)
return
}
writer := shadowaead.NewWriter(
@ -277,26 +273,22 @@ func (c *serverConn) writeResponse(payload []byte) (n int, err error) {
writeCipher,
MaxPacketSize,
)
common.KeepAlive(key)
header := writer.Buffer()
header.Write(salt.Bytes())
salt.Release()
common.KeepAlive(_salt)
headerType := byte(HeaderTypeServer)
payloadLen := len(payload)
_headerFixedChunk := buf.StackNewSize(1 + 8 + c.keySaltLength + 2)
headerFixedChunk := common.Dup(_headerFixedChunk)
headerFixedChunk := buf.NewSize(1 + 8 + c.keySaltLength + 2)
common.Must(headerFixedChunk.WriteByte(headerType))
common.Must(binary.Write(headerFixedChunk, binary.BigEndian, uint64(c.time().Unix())))
common.Must1(headerFixedChunk.Write(c.requestSalt))
common.Must(binary.Write(headerFixedChunk, binary.BigEndian, uint16(payloadLen)))
writer.WriteChunk(header, headerFixedChunk.Slice())
writer.WriteChunk(header, headerFixedChunk.Bytes())
headerFixedChunk.Release()
common.KeepAlive(_headerFixedChunk)
c.requestSalt = nil
if payloadLen > 0 {
@ -362,17 +354,6 @@ func (c *serverConn) WriteVectorised(buffers []*buf.Buffer) error {
return c.writer.WriteVectorised(buffers[1:])
}
func (c *serverConn) ReadFrom(r io.Reader) (n int64, err error) {
if c.writer == nil {
return bufio.ReadFrom0(c, r)
}
return bufio.Copy(c.writer, r)
}
func (c *serverConn) WriteTo(w io.Writer) (n int64, err error) {
return bufio.Copy(w, c.reader)
}
func (c *serverConn) Close() error {
return common.Close(
c.Conn,
@ -435,11 +416,10 @@ func (s *Service) newPacket(ctx context.Context, conn N.PacketConn, buffer *buf.
session.remoteSessionId = sessionId
if packetHeader != nil {
key := SessionKey(s.psk, packetHeader[:8], s.keySaltLength)
session.remoteCipher, err = s.constructor(common.Dup(key))
session.remoteCipher, err = s.constructor(key)
if err != nil {
return err
}
common.KeepAlive(key)
}
}
goto process
@ -631,9 +611,8 @@ func (s *Service) newUDPSession() *serverUDPSession {
binary.BigEndian.PutUint64(sessionId, session.sessionId)
key := SessionKey(s.psk, sessionId, s.keySaltLength)
var err error
session.cipher, err = s.constructor(common.Dup(key))
session.cipher, err = s.constructor(key)
common.Must(err)
common.KeepAlive(key)
}
return session
}

View file

@ -7,6 +7,7 @@ import (
"crypto/rand"
"encoding/base64"
"encoding/binary"
"io"
"math"
"net"
"os"
@ -115,16 +116,24 @@ func (s *MultiService[U]) UpdateUsersWithPasswords(userList []U, passwordList []
}
func (s *MultiService[U]) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
err := s.newConnection(ctx, conn, metadata)
err := s.NewConnection0(ctx, conn, metadata, conn, nil)
if err != nil {
err = &shadowsocks.ServerConnError{Conn: conn, Source: metadata.Source, Cause: err}
}
return err
}
func (s *MultiService[U]) newConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
func (s *MultiService[U]) NewConnection0(ctx context.Context, conn net.Conn, metadata M.Metadata, handshakeReader io.Reader, handshakeSuccess func()) error {
requestHeader := make([]byte, s.keySaltLength+aes.BlockSize+shadowaead.Overhead+RequestHeaderFixedChunkLength)
n, err := conn.Read(requestHeader)
var (
n int
err error
)
if handshakeSuccess != nil {
n, err = io.ReadFull(handshakeReader, requestHeader)
} else {
n, err = handshakeReader.Read(requestHeader)
}
if err != nil {
return err
} else if n < len(requestHeader) {
@ -136,19 +145,17 @@ func (s *MultiService[U]) newConnection(ctx context.Context, conn net.Conn, meta
}
var _eiHeader [aes.BlockSize]byte
eiHeader := common.Dup(_eiHeader[:])
eiHeader := _eiHeader[:]
copy(eiHeader, requestHeader[s.keySaltLength:s.keySaltLength+aes.BlockSize])
keyMaterial := buf.Make(s.keySaltLength * 2)
keyMaterial := make([]byte, s.keySaltLength*2)
copy(keyMaterial, s.psk)
copy(keyMaterial[s.keySaltLength:], requestSalt)
_identitySubkey := buf.StackNewSize(s.keySaltLength)
identitySubkey := common.Dup(_identitySubkey)
identitySubkey := buf.NewSize(s.keySaltLength)
identitySubkey.Extend(identitySubkey.FreeLen())
blake3.DeriveKey(identitySubkey.Bytes(), "shadowsocks 2022 identity subkey", keyMaterial)
b, err := s.blockConstructor(identitySubkey.Bytes())
identitySubkey.Release()
common.KeepAlive(_identitySubkey)
if err != nil {
return err
}
@ -160,12 +167,15 @@ func (s *MultiService[U]) newConnection(ctx context.Context, conn net.Conn, meta
user = u
uPSK = s.uPSK[u]
} else {
return E.New("invalid request")
return ErrInvalidRequest
}
if handshakeSuccess != nil {
handshakeSuccess()
}
common.KeepAlive(_eiHeader)
requestKey := SessionKey(uPSK, requestSalt, s.keySaltLength)
readCipher, err := s.constructor(common.Dup(requestKey))
readCipher, err := s.constructor(requestKey)
if err != nil {
return err
}
@ -265,7 +275,7 @@ func (s *MultiService[U]) newPacket(ctx context.Context, conn N.PacketConn, buff
s.udpBlockCipher.Decrypt(packetHeader, packetHeader)
var _eiHeader [aes.BlockSize]byte
eiHeader := common.Dup(_eiHeader[:])
eiHeader := _eiHeader[:]
s.udpBlockCipher.Decrypt(eiHeader, buffer.Range(aes.BlockSize, 2*aes.BlockSize))
xorWords(eiHeader, eiHeader, packetHeader)
@ -296,11 +306,10 @@ func (s *MultiService[U]) newPacket(ctx context.Context, conn N.PacketConn, buff
if !loaded {
session.remoteSessionId = sessionId
key := SessionKey(uPSK, packetHeader[:8], s.keySaltLength)
session.remoteCipher, err = s.constructor(common.Dup(key))
session.remoteCipher, err = s.constructor(key)
if err != nil {
return err
}
common.KeepAlive(key)
}
goto process
@ -384,8 +393,7 @@ func (s *MultiService[U]) newUDPSession(uPSK []byte) *serverUDPSession {
binary.BigEndian.PutUint64(sessionId, session.sessionId)
key := SessionKey(uPSK, sessionId, s.keySaltLength)
var err error
session.cipher, err = s.constructor(common.Dup(key))
session.cipher, err = s.constructor(key)
common.Must(err)
common.KeepAlive(key)
return session
}

View file

@ -167,9 +167,7 @@ type clientConn struct {
}
func (c *clientConn) writeRequest() error {
_buffer := buf.StackNewSize(c.saltLength + M.SocksaddrSerializer.AddrPortLen(c.destination))
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
buffer := buf.NewSize(c.saltLength + M.SocksaddrSerializer.AddrPortLen(c.destination))
defer buffer.Release()
salt := buffer.Extend(c.saltLength)
@ -200,9 +198,7 @@ func (c *clientConn) readResponse() error {
if c.readStream != nil {
return nil
}
_salt := buf.Make(c.saltLength)
defer common.KeepAlive(_salt)
salt := common.Dup(_salt)
salt := make([]byte, c.saltLength)
_, err := io.ReadFull(c.Conn, salt)
if err != nil {
return err
@ -308,9 +304,7 @@ func (c *clientPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
func (c *clientPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
destination := M.SocksaddrFromNet(addr)
_buffer := buf.StackNewSize(c.saltLength + M.SocksaddrSerializer.AddrPortLen(destination) + len(p))
defer common.KeepAlive(_buffer)
buffer := common.Dup(_buffer)
buffer := buf.NewSize(c.saltLength + M.SocksaddrSerializer.AddrPortLen(destination) + len(p))
defer buffer.Release()
common.Must1(buffer.ReadFullFrom(rand.Reader, c.saltLength))
err = M.SocksaddrSerializer.WriteAddrPort(buffer, M.SocksaddrFromNet(addr))