├── README.md ├── ssSocksClient ├── core │ ├── cipher.go │ ├── doc.go │ ├── packet.go │ └── stream.go ├── go.mod ├── go.sum ├── internal │ ├── bloomring.go │ ├── bloomring_test.go │ └── saltfilter.go ├── log.go ├── main.go ├── nfutil │ ├── nf_linux.go │ ├── socketcall_linux_386.go │ └── socketcall_linux_other.go ├── shadowaead │ ├── cipher.go │ ├── doc.go │ ├── packet.go │ └── stream.go ├── socks │ └── socks.go └── tcp.go └── ssSocksServer ├── bot.go ├── config.go ├── config.ini ├── core ├── cipher.go ├── doc.go ├── packet.go └── stream.go ├── go.mod ├── go.sum ├── internal ├── bloomring.go ├── bloomring_test.go └── saltfilter.go ├── main.go ├── shadowaead ├── cipher.go ├── doc.go ├── packet.go └── stream.go ├── socks └── socks.go └── tcp.go /README.md: -------------------------------------------------------------------------------- 1 | # ssSocks5 2 | 魔改shadowsocks,实现socks5内网穿透。 3 | ## 服务端ssSocksServer 4 | 5 | 配置文件固定为同目录的config.ini 6 | 配置文件中的BindAddr用于接收客户端的链接。
7 | 收到客户端请求后会以Socks5Addr为socks5端口,若收到多个客户端请求便会在Socks5Addr端口的基础上+1,遇到被占用的端口会跳过。
8 | ![image](https://github.com/djhons/ssSocks5/assets/102639729/74d7542a-df6c-46a4-8105-c032c1878f5d) 9 | ![image](https://github.com/djhons/ssSocks5/assets/102639729/4c58d741-e9a6-4e9c-ac5a-88a99967e4ae) 10 | 11 | 添加企业微信通知机器人 12 | ``` 13 | 代理掉辣,兄弟们别急。 14 | socks5:8.8.8.8:1445 15 | client:127.0.0.1:57018 16 | ``` 17 | ``` 18 | 新上线了一个socks5代理,兄弟们快冲。 19 | socks5:8.8.8.8:1445 20 | client:127.0.0.1:57018 21 | ``` 22 | 23 | ## 客户端ssSocksClient 24 | 25 | 运行在内网服务器上,使用-s参数指定带服务器地址。
26 | 例如:
27 | ![image](https://user-images.githubusercontent.com/102639729/188055910-5cf9478c-d4be-44ce-badd-2cd90a6e0e17.png) 28 | 可使用-r参数指定服务器断开连接后尝试的次数,使用-t指定每次尝试的间隔(单位分钟)。默认每10分钟尝试一次,10次后退出程序。 29 | 30 | ### ssSocksServer 31 | ``` 32 | ssSocksServer.exe: 33 | ``` 34 | ### ssSocksClient 35 | ``` 36 | Usage of ssSocksClient.exe: 37 | -r int 38 | Retry count, default 10 (default 10) 39 | -s string 40 | connect server addr 41 | -t int 42 | Time of each retry, 10 minutes by default (default 10) 43 | ``` 44 | -------------------------------------------------------------------------------- /ssSocksClient/core/cipher.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "crypto/md5" 5 | "errors" 6 | "net" 7 | "sort" 8 | "ssSocksClient/shadowaead" 9 | "strings" 10 | ) 11 | 12 | type Cipher interface { 13 | StreamConnCipher 14 | PacketConnCipher 15 | } 16 | 17 | type StreamConnCipher interface { 18 | StreamConn(net.Conn) net.Conn 19 | } 20 | 21 | type PacketConnCipher interface { 22 | PacketConn(net.PacketConn) net.PacketConn 23 | } 24 | 25 | // ErrCipherNotSupported occurs when a cipher is not supported (likely because of security concerns). 26 | var ErrCipherNotSupported = errors.New("cipher not supported") 27 | 28 | const ( 29 | aeadAes128Gcm = "AEAD_AES_128_GCM" 30 | aeadAes256Gcm = "AEAD_AES_256_GCM" 31 | aeadChacha20Poly1305 = "AEAD_CHACHA20_POLY1305" 32 | ) 33 | 34 | // List of AEAD ciphers: key size in bytes and constructor 35 | var aeadList = map[string]struct { 36 | KeySize int 37 | New func([]byte) (shadowaead.Cipher, error) 38 | }{ 39 | aeadAes128Gcm: {16, shadowaead.AESGCM}, 40 | aeadAes256Gcm: {32, shadowaead.AESGCM}, 41 | aeadChacha20Poly1305: {32, shadowaead.Chacha20Poly1305}, 42 | } 43 | 44 | // ListCipher returns a list of available cipher names sorted alphabetically. 45 | func ListCipher() []string { 46 | var l []string 47 | for k := range aeadList { 48 | l = append(l, k) 49 | } 50 | sort.Strings(l) 51 | return l 52 | } 53 | 54 | // PickCipher returns a Cipher of the given name. Derive key from password if given key is empty. 55 | func PickCipher(name string, key []byte, password string) (Cipher, error) { 56 | name = strings.ToUpper(name) 57 | 58 | switch name { 59 | case "DUMMY": 60 | return &dummy{}, nil 61 | case "CHACHA20-IETF-POLY1305": 62 | name = aeadChacha20Poly1305 63 | case "AES-128-GCM": 64 | name = aeadAes128Gcm 65 | case "AES-256-GCM": 66 | name = aeadAes256Gcm 67 | } 68 | 69 | if choice, ok := aeadList[name]; ok { 70 | if len(key) == 0 { 71 | key = kdf(password, choice.KeySize) 72 | } 73 | if len(key) != choice.KeySize { 74 | return nil, shadowaead.KeySizeError(choice.KeySize) 75 | } 76 | aead, err := choice.New(key) 77 | return &aeadCipher{aead}, err 78 | } 79 | 80 | return nil, ErrCipherNotSupported 81 | } 82 | 83 | type aeadCipher struct{ shadowaead.Cipher } 84 | 85 | func (aead *aeadCipher) StreamConn(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) } 86 | func (aead *aeadCipher) PacketConn(c net.PacketConn) net.PacketConn { 87 | return shadowaead.NewPacketConn(c, aead) 88 | } 89 | 90 | // dummy cipher does not encrypt 91 | type dummy struct{} 92 | 93 | func (dummy) StreamConn(c net.Conn) net.Conn { return c } 94 | func (dummy) PacketConn(c net.PacketConn) net.PacketConn { return c } 95 | 96 | // key-derivation function from original Shadowsocks 97 | func kdf(password string, keyLen int) []byte { 98 | var b, prev []byte 99 | h := md5.New() 100 | for len(b) < keyLen { 101 | h.Write(prev) 102 | h.Write([]byte(password)) 103 | b = h.Sum(b) 104 | prev = b[len(b)-h.Size():] 105 | h.Reset() 106 | } 107 | return b[:keyLen] 108 | } 109 | -------------------------------------------------------------------------------- /ssSocksClient/core/doc.go: -------------------------------------------------------------------------------- 1 | // Package core implements essential parts of Shadowsocks 2 | package core 3 | -------------------------------------------------------------------------------- /ssSocksClient/core/packet.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "net" 4 | 5 | func ListenPacket(network, address string, ciph PacketConnCipher) (net.PacketConn, error) { 6 | c, err := net.ListenPacket(network, address) 7 | return ciph.PacketConn(c), err 8 | } 9 | -------------------------------------------------------------------------------- /ssSocksClient/core/stream.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "net" 4 | 5 | type listener struct { 6 | net.Listener 7 | StreamConnCipher 8 | } 9 | 10 | func Listen(network, address string, ciph StreamConnCipher) (net.Listener, error) { 11 | l, err := net.Listen(network, address) 12 | return &listener{l, ciph}, err 13 | } 14 | 15 | func (l *listener) Accept() (net.Conn, error) { 16 | c, err := l.Listener.Accept() 17 | return l.StreamConn(c), err 18 | } 19 | 20 | func Dial(network, address string, ciph StreamConnCipher) (net.Conn, error) { 21 | c, err := net.Dial(network, address) 22 | return ciph.StreamConn(c), err 23 | } 24 | -------------------------------------------------------------------------------- /ssSocksClient/go.mod: -------------------------------------------------------------------------------- 1 | module ssSocksClient 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/hashicorp/yamux v0.1.1 7 | github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 8 | github.com/shadowsocks/go-shadowsocks2 v0.1.5 9 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 10 | ) 11 | 12 | require golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect 13 | -------------------------------------------------------------------------------- /ssSocksClient/go.sum: -------------------------------------------------------------------------------- 1 | github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= 2 | github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= 3 | github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= 4 | github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= 5 | github.com/shadowsocks/go-shadowsocks2 v0.1.5 h1:PDSQv9y2S85Fl7VBeOMF9StzeXZyK1HakRm86CUbr28= 6 | github.com/shadowsocks/go-shadowsocks2 v0.1.5/go.mod h1:AGGpIoek4HRno4xzyFiAtLHkOpcoznZEkAccaI/rplM= 7 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 8 | golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 9 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= 10 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 11 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 12 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 13 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 14 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 15 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 16 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 17 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= 18 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 19 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 20 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 21 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 22 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 23 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 24 | -------------------------------------------------------------------------------- /ssSocksClient/internal/bloomring.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "hash/fnv" 5 | "sync" 6 | 7 | "github.com/riobard/go-bloom" 8 | ) 9 | 10 | // simply use Double FNV here as our Bloom Filter hash 11 | func doubleFNV(b []byte) (uint64, uint64) { 12 | hx := fnv.New64() 13 | hx.Write(b) 14 | x := hx.Sum64() 15 | hy := fnv.New64a() 16 | hy.Write(b) 17 | y := hy.Sum64() 18 | return x, y 19 | } 20 | 21 | type BloomRing struct { 22 | slotCapacity int 23 | slotPosition int 24 | slotCount int 25 | entryCounter int 26 | slots []bloom.Filter 27 | mutex sync.RWMutex 28 | } 29 | 30 | func NewBloomRing(slot, capacity int, falsePositiveRate float64) *BloomRing { 31 | // Calculate entries for each slot 32 | r := &BloomRing{ 33 | slotCapacity: capacity / slot, 34 | slotCount: slot, 35 | slots: make([]bloom.Filter, slot), 36 | } 37 | for i := 0; i < slot; i++ { 38 | r.slots[i] = bloom.New(r.slotCapacity, falsePositiveRate, doubleFNV) 39 | } 40 | return r 41 | } 42 | 43 | func (r *BloomRing) Add(b []byte) { 44 | if r == nil { 45 | return 46 | } 47 | r.mutex.Lock() 48 | defer r.mutex.Unlock() 49 | r.add(b) 50 | } 51 | 52 | func (r *BloomRing) add(b []byte) { 53 | slot := r.slots[r.slotPosition] 54 | if r.entryCounter > r.slotCapacity { 55 | // Move to next slot and reset 56 | r.slotPosition = (r.slotPosition + 1) % r.slotCount 57 | slot = r.slots[r.slotPosition] 58 | slot.Reset() 59 | r.entryCounter = 0 60 | } 61 | r.entryCounter++ 62 | slot.Add(b) 63 | } 64 | 65 | func (r *BloomRing) Test(b []byte) bool { 66 | if r == nil { 67 | return false 68 | } 69 | r.mutex.RLock() 70 | defer r.mutex.RUnlock() 71 | test := r.test(b) 72 | return test 73 | } 74 | 75 | func (r *BloomRing) test(b []byte) bool { 76 | for _, s := range r.slots { 77 | if s.Test(b) { 78 | return true 79 | } 80 | } 81 | return false 82 | } 83 | 84 | func (r *BloomRing) Check(b []byte) bool { 85 | r.mutex.Lock() 86 | defer r.mutex.Unlock() 87 | if r.Test(b) { 88 | return true 89 | } 90 | r.Add(b) 91 | return false 92 | } 93 | -------------------------------------------------------------------------------- /ssSocksClient/internal/bloomring_test.go: -------------------------------------------------------------------------------- 1 | package internal_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | 8 | "github.com/shadowsocks/go-shadowsocks2/internal" 9 | ) 10 | 11 | var ( 12 | bloomRingInstance *internal.BloomRing 13 | ) 14 | 15 | func TestMain(m *testing.M) { 16 | bloomRingInstance = internal.NewBloomRing(internal.DefaultSFSlot, int(internal.DefaultSFCapacity), 17 | internal.DefaultSFFPR) 18 | os.Exit(m.Run()) 19 | } 20 | 21 | func TestBloomRing_Add(t *testing.T) { 22 | defer func() { 23 | if any := recover(); any != nil { 24 | t.Fatalf("Should not got panic while adding item: %v", any) 25 | } 26 | }() 27 | bloomRingInstance.Add(make([]byte, 16)) 28 | } 29 | 30 | func TestBloomRing_NilAdd(t *testing.T) { 31 | defer func() { 32 | if any := recover(); any != nil { 33 | t.Fatalf("Should not got panic while adding item: %v", any) 34 | } 35 | }() 36 | var nilRing *internal.BloomRing 37 | nilRing.Add(make([]byte, 16)) 38 | } 39 | 40 | func TestBloomRing_Test(t *testing.T) { 41 | buf := []byte("shadowsocks") 42 | bloomRingInstance.Add(buf) 43 | if !bloomRingInstance.Test(buf) { 44 | t.Fatal("Test on filter missing") 45 | } 46 | } 47 | 48 | func TestBloomRing_NilTestIsFalse(t *testing.T) { 49 | var nilRing *internal.BloomRing 50 | if nilRing.Test([]byte("shadowsocks")) { 51 | t.Fatal("Test should return false for nil BloomRing") 52 | } 53 | } 54 | 55 | func BenchmarkBloomRing(b *testing.B) { 56 | // Generate test samples with different length 57 | samples := make([][]byte, internal.DefaultSFCapacity-internal.DefaultSFSlot) 58 | var checkPoints [][]byte 59 | for i := 0; i < len(samples); i++ { 60 | samples[i] = []byte(fmt.Sprint(i)) 61 | if i%1000 == 0 { 62 | checkPoints = append(checkPoints, samples[i]) 63 | } 64 | } 65 | b.Logf("Generated %d samples and %d check points", len(samples), len(checkPoints)) 66 | for i := 1; i < 16; i++ { 67 | b.Run(fmt.Sprintf("Slot%d", i), benchmarkBloomRing(samples, checkPoints, i)) 68 | } 69 | } 70 | 71 | func benchmarkBloomRing(samples, checkPoints [][]byte, slot int) func(*testing.B) { 72 | filter := internal.NewBloomRing(slot, int(internal.DefaultSFCapacity), internal.DefaultSFFPR) 73 | for _, sample := range samples { 74 | filter.Add(sample) 75 | } 76 | return func(b *testing.B) { 77 | b.ResetTimer() 78 | b.ReportAllocs() 79 | for i := 0; i < b.N; i++ { 80 | for _, cp := range checkPoints { 81 | filter.Test(cp) 82 | } 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ssSocksClient/internal/saltfilter.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "sync" 8 | ) 9 | 10 | // Those suggest value are all set according to 11 | // https://github.com/shadowsocks/shadowsocks-org/issues/44#issuecomment-281021054 12 | // Due to this package contains various internal implementation so const named with DefaultBR prefix 13 | const ( 14 | DefaultSFCapacity = 1e6 15 | // FalsePositiveRate 16 | DefaultSFFPR = 1e-6 17 | DefaultSFSlot = 10 18 | ) 19 | 20 | const EnvironmentPrefix = "SHADOWSOCKS_" 21 | 22 | // A shared instance used for checking salt repeat 23 | var saltfilter *BloomRing 24 | 25 | // Used to initialize the saltfilter singleton only once. 26 | var initSaltfilterOnce sync.Once 27 | 28 | // GetSaltFilterSingleton returns the BloomRing singleton, 29 | // initializing it on first call. 30 | func getSaltFilterSingleton() *BloomRing { 31 | initSaltfilterOnce.Do(func() { 32 | var ( 33 | finalCapacity = DefaultSFCapacity 34 | finalFPR = DefaultSFFPR 35 | finalSlot = float64(DefaultSFSlot) 36 | ) 37 | for _, opt := range []struct { 38 | ENVName string 39 | Target *float64 40 | }{ 41 | { 42 | ENVName: "CAPACITY", 43 | Target: &finalCapacity, 44 | }, 45 | { 46 | ENVName: "FPR", 47 | Target: &finalFPR, 48 | }, 49 | { 50 | ENVName: "SLOT", 51 | Target: &finalSlot, 52 | }, 53 | } { 54 | envKey := EnvironmentPrefix + "SF_" + opt.ENVName 55 | env := os.Getenv(envKey) 56 | if env != "" { 57 | p, err := strconv.ParseFloat(env, 64) 58 | if err != nil { 59 | panic(fmt.Sprintf("Invalid envrionment `%s` setting in saltfilter: %s", envKey, env)) 60 | } 61 | *opt.Target = p 62 | } 63 | } 64 | // Support disable saltfilter by given a negative capacity 65 | if finalCapacity <= 0 { 66 | return 67 | } 68 | saltfilter = NewBloomRing(int(finalSlot), int(finalCapacity), finalFPR) 69 | }) 70 | return saltfilter 71 | } 72 | 73 | // TestSalt returns true if salt is repeated 74 | func TestSalt(b []byte) bool { 75 | return getSaltFilterSingleton().Test(b) 76 | } 77 | 78 | // AddSalt salt to filter 79 | func AddSalt(b []byte) { 80 | getSaltFilterSingleton().Add(b) 81 | } 82 | 83 | func CheckSalt(b []byte) bool { 84 | return getSaltFilterSingleton().Test(b) 85 | } 86 | -------------------------------------------------------------------------------- /ssSocksClient/log.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | ) 8 | 9 | var logger = log.New(os.Stderr, "", log.Lshortfile|log.LstdFlags) 10 | 11 | func logf(f string, v ...interface{}) { 12 | logger.Output(2, fmt.Sprintf(f, v...)) 13 | } 14 | 15 | type logHelper struct { 16 | prefix string 17 | } 18 | 19 | func (l *logHelper) Write(p []byte) (n int, err error) { 20 | logger.Printf("%s%s\n", l.prefix, p) 21 | return len(p), nil 22 | } 23 | 24 | func newLogHelper(prefix string) *logHelper { 25 | return &logHelper{prefix} 26 | } 27 | -------------------------------------------------------------------------------- /ssSocksClient/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "ssSocksClient/core" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | var flags struct { 12 | ConnectAddr string 13 | Retry int 14 | RetryTime int 15 | } 16 | flag.StringVar(&flags.ConnectAddr, "s", "", "connect server addr") 17 | flag.IntVar(&flags.Retry, "r", 10, "Retry count, default 10") 18 | flag.IntVar(&flags.RetryTime, "t", 10, "Time of each retry, 10 minutes by default") 19 | flag.Parse() 20 | ciph, err := core.PickCipher("aes-128-gcm", nil, "Ng&t0qawhHo45672") 21 | if err != nil { 22 | log.Fatal(err) 23 | } 24 | retryed := 0 25 | for { 26 | err := tcpRemote(flags.ConnectAddr, ciph.StreamConn, &retryed) 27 | if err != nil { 28 | retryed++ 29 | time.Sleep(time.Duration(flags.RetryTime) * time.Minute) 30 | } 31 | if retryed > flags.Retry { 32 | break 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /ssSocksClient/nfutil/nf_linux.go: -------------------------------------------------------------------------------- 1 | package nfutil 2 | 3 | import ( 4 | "net" 5 | "syscall" 6 | "unsafe" 7 | ) 8 | 9 | // Get the original destination of a TCP connection redirected by Netfilter. 10 | func GetOrigDst(c *net.TCPConn, ipv6 bool) (*net.TCPAddr, error) { 11 | rc, err := c.SyscallConn() 12 | if err != nil { 13 | return nil, err 14 | } 15 | var addr *net.TCPAddr 16 | rc.Control(func(fd uintptr) { 17 | if ipv6 { 18 | addr, err = ipv6_getorigdst(fd) 19 | } else { 20 | addr, err = getorigdst(fd) 21 | } 22 | }) 23 | return addr, err 24 | } 25 | 26 | // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c 27 | func getorigdst(fd uintptr) (*net.TCPAddr, error) { 28 | const _SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv4.h 29 | var raw syscall.RawSockaddrInet4 30 | siz := unsafe.Sizeof(raw) 31 | if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IP, _SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { 32 | return nil, err 33 | } 34 | var addr net.TCPAddr 35 | addr.IP = raw.Addr[:] 36 | port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian 37 | addr.Port = int(port[0])<<8 | int(port[1]) 38 | return &addr, nil 39 | } 40 | 41 | // Call ipv6_getorigdst() from linux/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c 42 | // NOTE: I haven't tried yet but it should work since Linux 3.8. 43 | func ipv6_getorigdst(fd uintptr) (*net.TCPAddr, error) { 44 | const _IP6T_SO_ORIGINAL_DST = 80 // from linux/include/uapi/linux/netfilter_ipv6/ip6_tables.h 45 | var raw syscall.RawSockaddrInet6 46 | siz := unsafe.Sizeof(raw) 47 | if err := socketcall(GETSOCKOPT, fd, syscall.IPPROTO_IPV6, _IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0); err != nil { 48 | return nil, err 49 | } 50 | var addr net.TCPAddr 51 | addr.IP = raw.Addr[:] 52 | port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // raw.Port is big-endian 53 | addr.Port = int(port[0])<<8 | int(port[1]) 54 | return &addr, nil 55 | } 56 | -------------------------------------------------------------------------------- /ssSocksClient/nfutil/socketcall_linux_386.go: -------------------------------------------------------------------------------- 1 | package nfutil 2 | 3 | import ( 4 | "syscall" 5 | "unsafe" 6 | ) 7 | 8 | const GETSOCKOPT = 15 // https://golang.org/src/syscall/syscall_linux_386.go#L183 9 | 10 | func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { 11 | var a [6]uintptr 12 | a[0], a[1], a[2], a[3], a[4], a[5] = a0, a1, a2, a3, a4, a5 13 | if _, _, errno := syscall.Syscall6(syscall.SYS_SOCKETCALL, call, uintptr(unsafe.Pointer(&a)), 0, 0, 0, 0); errno != 0 { 14 | return errno 15 | } 16 | return nil 17 | } 18 | -------------------------------------------------------------------------------- /ssSocksClient/nfutil/socketcall_linux_other.go: -------------------------------------------------------------------------------- 1 | // +build linux,!386 2 | 3 | package nfutil 4 | 5 | import "syscall" 6 | 7 | const GETSOCKOPT = syscall.SYS_GETSOCKOPT 8 | 9 | func socketcall(call, a0, a1, a2, a3, a4, a5 uintptr) error { 10 | if _, _, errno := syscall.Syscall6(call, a0, a1, a2, a3, a4, a5); errno != 0 { 11 | return errno 12 | } 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /ssSocksClient/shadowaead/cipher.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/sha1" 7 | "errors" 8 | "io" 9 | "strconv" 10 | 11 | "golang.org/x/crypto/chacha20poly1305" 12 | "golang.org/x/crypto/hkdf" 13 | ) 14 | 15 | // ErrRepeatedSalt means detected a reused salt 16 | var ErrRepeatedSalt = errors.New("repeated salt detected") 17 | 18 | type Cipher interface { 19 | KeySize() int 20 | SaltSize() int 21 | Encrypter(salt []byte) (cipher.AEAD, error) 22 | Decrypter(salt []byte) (cipher.AEAD, error) 23 | } 24 | 25 | type KeySizeError int 26 | 27 | func (e KeySizeError) Error() string { 28 | return "key size error: need " + strconv.Itoa(int(e)) + " bytes" 29 | } 30 | 31 | func hkdfSHA1(secret, salt, info, outkey []byte) { 32 | r := hkdf.New(sha1.New, secret, salt, info) 33 | if _, err := io.ReadFull(r, outkey); err != nil { 34 | panic(err) // should never happen 35 | } 36 | } 37 | 38 | type metaCipher struct { 39 | psk []byte 40 | makeAEAD func(key []byte) (cipher.AEAD, error) 41 | } 42 | 43 | func (a *metaCipher) KeySize() int { return len(a.psk) } 44 | func (a *metaCipher) SaltSize() int { 45 | if ks := a.KeySize(); ks > 16 { 46 | return ks 47 | } 48 | return 16 49 | } 50 | func (a *metaCipher) Encrypter(salt []byte) (cipher.AEAD, error) { 51 | subkey := make([]byte, a.KeySize()) 52 | hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey) 53 | return a.makeAEAD(subkey) 54 | } 55 | func (a *metaCipher) Decrypter(salt []byte) (cipher.AEAD, error) { 56 | subkey := make([]byte, a.KeySize()) 57 | hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey) 58 | return a.makeAEAD(subkey) 59 | } 60 | 61 | func aesGCM(key []byte) (cipher.AEAD, error) { 62 | blk, err := aes.NewCipher(key) 63 | if err != nil { 64 | return nil, err 65 | } 66 | return cipher.NewGCM(blk) 67 | } 68 | 69 | // AESGCM creates a new Cipher with a pre-shared key. len(psk) must be 70 | // one of 16, 24, or 32 to select AES-128/196/256-GCM. 71 | func AESGCM(psk []byte) (Cipher, error) { 72 | switch l := len(psk); l { 73 | case 16, 24, 32: // AES 128/196/256 74 | default: 75 | return nil, aes.KeySizeError(l) 76 | } 77 | return &metaCipher{psk: psk, makeAEAD: aesGCM}, nil 78 | } 79 | 80 | // Chacha20Poly1305 creates a new Cipher with a pre-shared key. len(psk) 81 | // must be 32. 82 | func Chacha20Poly1305(psk []byte) (Cipher, error) { 83 | if len(psk) != chacha20poly1305.KeySize { 84 | return nil, KeySizeError(chacha20poly1305.KeySize) 85 | } 86 | return &metaCipher{psk: psk, makeAEAD: chacha20poly1305.New}, nil 87 | } 88 | -------------------------------------------------------------------------------- /ssSocksClient/shadowaead/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package shadowaead implements a simple AEAD-protected secure protocol. 3 | 4 | In general, there are two types of connections: stream-oriented and packet-oriented. 5 | Stream-oriented connections (e.g. TCP) assume reliable and orderly delivery of bytes. 6 | Packet-oriented connections (e.g. UDP) assume unreliable and out-of-order delivery of packets, 7 | where each packet is either delivered intact or lost. 8 | 9 | An encrypted stream starts with a random salt to derive a session key, followed by any number of 10 | encrypted records. Each encrypted record has the following structure: 11 | 12 | [encrypted payload length] 13 | [payload length tag] 14 | [encrypted payload] 15 | [payload tag] 16 | 17 | Payload length is 2-byte unsigned big-endian integer capped at 0x3FFF (16383). 18 | The higher 2 bits are reserved and must be set to zero. The first AEAD encrypt/decrypt 19 | operation uses a counting nonce starting from 0. After each encrypt/decrypt operation, 20 | the nonce is incremented by one as if it were an unsigned little-endian integer. 21 | 22 | 23 | Each encrypted packet transmitted on a packet-oriented connection has the following structure: 24 | 25 | [random salt] 26 | [encrypted payload] 27 | [payload tag] 28 | 29 | The salt is used to derive a subkey to initiate an AEAD. Packets are encrypted/decrypted independently 30 | using zero nonce. 31 | 32 | In both stream-oriented and packet-oriented connections, length of nonce and tag varies 33 | depending on which AEAD is used. Salt should be at least 16-byte long. 34 | */ 35 | package shadowaead 36 | -------------------------------------------------------------------------------- /ssSocksClient/shadowaead/packet.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "crypto/rand" 5 | "errors" 6 | "io" 7 | "net" 8 | "sync" 9 | 10 | "ssSocksClient/internal" 11 | ) 12 | 13 | // ErrShortPacket means that the packet is too short for a valid encrypted packet. 14 | var ErrShortPacket = errors.New("short packet") 15 | 16 | var _zerononce [128]byte // read-only. 128 bytes is more than enough. 17 | 18 | // Pack encrypts plaintext using Cipher with a randomly generated salt and 19 | // returns a slice of dst containing the encrypted packet and any error occurred. 20 | // Ensure len(dst) >= ciph.SaltSize() + len(plaintext) + aead.Overhead(). 21 | func Pack(dst, plaintext []byte, ciph Cipher) ([]byte, error) { 22 | saltSize := ciph.SaltSize() 23 | salt := dst[:saltSize] 24 | if _, err := io.ReadFull(rand.Reader, salt); err != nil { 25 | return nil, err 26 | } 27 | 28 | aead, err := ciph.Encrypter(salt) 29 | if err != nil { 30 | return nil, err 31 | } 32 | internal.AddSalt(salt) 33 | 34 | if len(dst) < saltSize+len(plaintext)+aead.Overhead() { 35 | return nil, io.ErrShortBuffer 36 | } 37 | b := aead.Seal(dst[saltSize:saltSize], _zerononce[:aead.NonceSize()], plaintext, nil) 38 | return dst[:saltSize+len(b)], nil 39 | } 40 | 41 | // Unpack decrypts pkt using Cipher and returns a slice of dst containing the decrypted payload and any error occurred. 42 | // Ensure len(dst) >= len(pkt) - aead.SaltSize() - aead.Overhead(). 43 | func Unpack(dst, pkt []byte, ciph Cipher) ([]byte, error) { 44 | saltSize := ciph.SaltSize() 45 | if len(pkt) < saltSize { 46 | return nil, ErrShortPacket 47 | } 48 | salt := pkt[:saltSize] 49 | aead, err := ciph.Decrypter(salt) 50 | if err != nil { 51 | return nil, err 52 | } 53 | if internal.CheckSalt(salt) { 54 | return nil, ErrRepeatedSalt 55 | } 56 | if len(pkt) < saltSize+aead.Overhead() { 57 | return nil, ErrShortPacket 58 | } 59 | if saltSize+len(dst)+aead.Overhead() < len(pkt) { 60 | return nil, io.ErrShortBuffer 61 | } 62 | b, err := aead.Open(dst[:0], _zerononce[:aead.NonceSize()], pkt[saltSize:], nil) 63 | return b, err 64 | } 65 | 66 | type packetConn struct { 67 | net.PacketConn 68 | Cipher 69 | sync.Mutex 70 | buf []byte // write lock 71 | } 72 | 73 | // NewPacketConn wraps a net.PacketConn with cipher 74 | func NewPacketConn(c net.PacketConn, ciph Cipher) net.PacketConn { 75 | const maxPacketSize = 64 * 1024 76 | return &packetConn{PacketConn: c, Cipher: ciph, buf: make([]byte, maxPacketSize)} 77 | } 78 | 79 | // WriteTo encrypts b and write to addr using the embedded PacketConn. 80 | func (c *packetConn) WriteTo(b []byte, addr net.Addr) (int, error) { 81 | c.Lock() 82 | defer c.Unlock() 83 | buf, err := Pack(c.buf, b, c) 84 | if err != nil { 85 | return 0, err 86 | } 87 | _, err = c.PacketConn.WriteTo(buf, addr) 88 | return len(b), err 89 | } 90 | 91 | // ReadFrom reads from the embedded PacketConn and decrypts into b. 92 | func (c *packetConn) ReadFrom(b []byte) (int, net.Addr, error) { 93 | n, addr, err := c.PacketConn.ReadFrom(b) 94 | if err != nil { 95 | return n, addr, err 96 | } 97 | bb, err := Unpack(b[c.Cipher.SaltSize():], b[:n], c) 98 | if err != nil { 99 | return n, addr, err 100 | } 101 | copy(b, bb) 102 | return len(bb), addr, err 103 | } 104 | -------------------------------------------------------------------------------- /ssSocksClient/shadowaead/stream.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "bytes" 5 | "crypto/cipher" 6 | "crypto/rand" 7 | "io" 8 | "net" 9 | "ssSocksClient/internal" 10 | ) 11 | 12 | // payloadSizeMask is the maximum size of payload in bytes. 13 | const payloadSizeMask = 0x3FFF // 16*1024 - 1 14 | 15 | type writer struct { 16 | io.Writer 17 | cipher.AEAD 18 | nonce []byte 19 | buf []byte 20 | } 21 | 22 | // NewWriter wraps an io.Writer with AEAD encryption. 23 | func NewWriter(w io.Writer, aead cipher.AEAD) io.Writer { return newWriter(w, aead) } 24 | 25 | func newWriter(w io.Writer, aead cipher.AEAD) *writer { 26 | return &writer{ 27 | Writer: w, 28 | AEAD: aead, 29 | buf: make([]byte, 2+aead.Overhead()+payloadSizeMask+aead.Overhead()), 30 | nonce: make([]byte, aead.NonceSize()), 31 | } 32 | } 33 | 34 | // Write encrypts b and writes to the embedded io.Writer. 35 | func (w *writer) Write(b []byte) (int, error) { 36 | n, err := w.ReadFrom(bytes.NewBuffer(b)) 37 | return int(n), err 38 | } 39 | 40 | // ReadFrom reads from the given io.Reader until EOF or error, encrypts and 41 | // writes to the embedded io.Writer. Returns number of bytes read from r and 42 | // any error encountered. 43 | func (w *writer) ReadFrom(r io.Reader) (n int64, err error) { 44 | for { 45 | buf := w.buf 46 | payloadBuf := buf[2+w.Overhead() : 2+w.Overhead()+payloadSizeMask] 47 | nr, er := r.Read(payloadBuf) 48 | 49 | if nr > 0 { 50 | n += int64(nr) 51 | buf = buf[:2+w.Overhead()+nr+w.Overhead()] 52 | payloadBuf = payloadBuf[:nr] 53 | buf[0], buf[1] = byte(nr>>8), byte(nr) // big-endian payload size 54 | w.Seal(buf[:0], w.nonce, buf[:2], nil) 55 | increment(w.nonce) 56 | 57 | w.Seal(payloadBuf[:0], w.nonce, payloadBuf, nil) 58 | increment(w.nonce) 59 | 60 | _, ew := w.Writer.Write(buf) 61 | if ew != nil { 62 | err = ew 63 | break 64 | } 65 | } 66 | 67 | if er != nil { 68 | if er != io.EOF { // ignore EOF as per io.ReaderFrom contract 69 | err = er 70 | } 71 | break 72 | } 73 | } 74 | 75 | return n, err 76 | } 77 | 78 | type reader struct { 79 | io.Reader 80 | cipher.AEAD 81 | nonce []byte 82 | buf []byte 83 | leftover []byte 84 | } 85 | 86 | // NewReader wraps an io.Reader with AEAD decryption. 87 | func NewReader(r io.Reader, aead cipher.AEAD) io.Reader { return newReader(r, aead) } 88 | 89 | func newReader(r io.Reader, aead cipher.AEAD) *reader { 90 | return &reader{ 91 | Reader: r, 92 | AEAD: aead, 93 | buf: make([]byte, payloadSizeMask+aead.Overhead()), 94 | nonce: make([]byte, aead.NonceSize()), 95 | } 96 | } 97 | 98 | // read and decrypt a record into the internal buffer. Return decrypted payload length and any error encountered. 99 | func (r *reader) read() (int, error) { 100 | // decrypt payload size 101 | buf := r.buf[:2+r.Overhead()] 102 | _, err := io.ReadFull(r.Reader, buf) 103 | if err != nil { 104 | return 0, err 105 | } 106 | 107 | _, err = r.Open(buf[:0], r.nonce, buf, nil) 108 | increment(r.nonce) 109 | if err != nil { 110 | return 0, err 111 | } 112 | 113 | size := (int(buf[0])<<8 + int(buf[1])) & payloadSizeMask 114 | 115 | // decrypt payload 116 | buf = r.buf[:size+r.Overhead()] 117 | _, err = io.ReadFull(r.Reader, buf) 118 | if err != nil { 119 | return 0, err 120 | } 121 | 122 | _, err = r.Open(buf[:0], r.nonce, buf, nil) 123 | increment(r.nonce) 124 | if err != nil { 125 | return 0, err 126 | } 127 | 128 | return size, nil 129 | } 130 | 131 | // Read reads from the embedded io.Reader, decrypts and writes to b. 132 | func (r *reader) Read(b []byte) (int, error) { 133 | // copy decrypted bytes (if any) from previous record first 134 | if len(r.leftover) > 0 { 135 | n := copy(b, r.leftover) 136 | r.leftover = r.leftover[n:] 137 | return n, nil 138 | } 139 | 140 | n, err := r.read() 141 | m := copy(b, r.buf[:n]) 142 | if m < n { // insufficient len(b), keep leftover for next read 143 | r.leftover = r.buf[m:n] 144 | } 145 | return m, err 146 | } 147 | 148 | // WriteTo reads from the embedded io.Reader, decrypts and writes to w until 149 | // there's no more data to write or when an error occurs. Return number of 150 | // bytes written to w and any error encountered. 151 | func (r *reader) WriteTo(w io.Writer) (n int64, err error) { 152 | // write decrypted bytes left over from previous record 153 | for len(r.leftover) > 0 { 154 | nw, ew := w.Write(r.leftover) 155 | r.leftover = r.leftover[nw:] 156 | n += int64(nw) 157 | if ew != nil { 158 | return n, ew 159 | } 160 | } 161 | 162 | for { 163 | nr, er := r.read() 164 | if nr > 0 { 165 | nw, ew := w.Write(r.buf[:nr]) 166 | n += int64(nw) 167 | 168 | if ew != nil { 169 | err = ew 170 | break 171 | } 172 | } 173 | 174 | if er != nil { 175 | if er != io.EOF { // ignore EOF as per io.Copy contract (using src.WriteTo shortcut) 176 | err = er 177 | } 178 | break 179 | } 180 | } 181 | 182 | return n, err 183 | } 184 | 185 | // increment little-endian encoded unsigned integer b. Wrap around on overflow. 186 | func increment(b []byte) { 187 | for i := range b { 188 | b[i]++ 189 | if b[i] != 0 { 190 | return 191 | } 192 | } 193 | } 194 | 195 | type streamConn struct { 196 | net.Conn 197 | Cipher 198 | r *reader 199 | w *writer 200 | } 201 | 202 | func (c *streamConn) initReader() error { 203 | salt := make([]byte, c.SaltSize()) 204 | if _, err := io.ReadFull(c.Conn, salt); err != nil { 205 | return err 206 | } 207 | aead, err := c.Decrypter(salt) 208 | if err != nil { 209 | return err 210 | } 211 | 212 | if internal.CheckSalt(salt) { 213 | return ErrRepeatedSalt 214 | } 215 | 216 | c.r = newReader(c.Conn, aead) 217 | return nil 218 | } 219 | 220 | func (c *streamConn) Read(b []byte) (int, error) { 221 | if c.r == nil { 222 | if err := c.initReader(); err != nil { 223 | return 0, err 224 | } 225 | } 226 | return c.r.Read(b) 227 | } 228 | 229 | func (c *streamConn) WriteTo(w io.Writer) (int64, error) { 230 | if c.r == nil { 231 | if err := c.initReader(); err != nil { 232 | return 0, err 233 | } 234 | } 235 | return c.r.WriteTo(w) 236 | } 237 | 238 | func (c *streamConn) initWriter() error { 239 | salt := make([]byte, c.SaltSize()) 240 | if _, err := io.ReadFull(rand.Reader, salt); err != nil { 241 | return err 242 | } 243 | aead, err := c.Encrypter(salt) 244 | if err != nil { 245 | return err 246 | } 247 | _, err = c.Conn.Write(salt) 248 | if err != nil { 249 | return err 250 | } 251 | internal.AddSalt(salt) 252 | c.w = newWriter(c.Conn, aead) 253 | return nil 254 | } 255 | 256 | func (c *streamConn) Write(b []byte) (int, error) { 257 | if c.w == nil { 258 | if err := c.initWriter(); err != nil { 259 | return 0, err 260 | } 261 | } 262 | return c.w.Write(b) 263 | } 264 | 265 | func (c *streamConn) ReadFrom(r io.Reader) (int64, error) { 266 | if c.w == nil { 267 | if err := c.initWriter(); err != nil { 268 | return 0, err 269 | } 270 | } 271 | return c.w.ReadFrom(r) 272 | } 273 | 274 | // NewConn wraps a stream-oriented net.Conn with cipher. 275 | func NewConn(c net.Conn, ciph Cipher) net.Conn { return &streamConn{Conn: c, Cipher: ciph} } 276 | -------------------------------------------------------------------------------- /ssSocksClient/socks/socks.go: -------------------------------------------------------------------------------- 1 | // Package socks implements essential parts of SOCKS protocol. 2 | package socks 3 | 4 | import ( 5 | "io" 6 | "net" 7 | "strconv" 8 | ) 9 | 10 | // UDPEnabled is the toggle for UDP support 11 | var UDPEnabled = false 12 | 13 | // SOCKS request commands as defined in RFC 1928 section 4. 14 | const ( 15 | CmdConnect = 1 16 | CmdBind = 2 17 | CmdUDPAssociate = 3 18 | ) 19 | 20 | // SOCKS address types as defined in RFC 1928 section 5. 21 | const ( 22 | AtypIPv4 = 1 23 | AtypDomainName = 3 24 | AtypIPv6 = 4 25 | ) 26 | 27 | // Error represents a SOCKS error 28 | type Error byte 29 | 30 | func (err Error) Error() string { 31 | return "SOCKS error: " + strconv.Itoa(int(err)) 32 | } 33 | 34 | // SOCKS errors as defined in RFC 1928 section 6. 35 | const ( 36 | ErrGeneralFailure = Error(1) 37 | ErrConnectionNotAllowed = Error(2) 38 | ErrNetworkUnreachable = Error(3) 39 | ErrHostUnreachable = Error(4) 40 | ErrConnectionRefused = Error(5) 41 | ErrTTLExpired = Error(6) 42 | ErrCommandNotSupported = Error(7) 43 | ErrAddressNotSupported = Error(8) 44 | InfoUDPAssociate = Error(9) 45 | ) 46 | 47 | // MaxAddrLen is the maximum size of SOCKS address in bytes. 48 | const MaxAddrLen = 1 + 1 + 255 + 2 49 | 50 | // Addr represents a SOCKS address as defined in RFC 1928 section 5. 51 | type Addr []byte 52 | 53 | // String serializes SOCKS address a to string form. 54 | func (a Addr) String() string { 55 | var host, port string 56 | 57 | switch a[0] { // address type 58 | case AtypDomainName: 59 | host = string(a[2 : 2+int(a[1])]) 60 | port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1])) 61 | case AtypIPv4: 62 | host = net.IP(a[1 : 1+net.IPv4len]).String() 63 | port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1])) 64 | case AtypIPv6: 65 | host = net.IP(a[1 : 1+net.IPv6len]).String() 66 | port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1])) 67 | } 68 | 69 | return net.JoinHostPort(host, port) 70 | } 71 | 72 | func readAddr(r io.Reader, b []byte) (Addr, error) { 73 | if len(b) < MaxAddrLen { 74 | return nil, io.ErrShortBuffer 75 | } 76 | _, err := io.ReadFull(r, b[:1]) // read 1st byte for address type 77 | if err != nil { 78 | return nil, err 79 | } 80 | 81 | switch b[0] { 82 | case AtypDomainName: 83 | _, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length 84 | if err != nil { 85 | return nil, err 86 | } 87 | _, err = io.ReadFull(r, b[2:2+int(b[1])+2]) 88 | return b[:1+1+int(b[1])+2], err 89 | case AtypIPv4: 90 | _, err = io.ReadFull(r, b[1:1+net.IPv4len+2]) 91 | return b[:1+net.IPv4len+2], err 92 | case AtypIPv6: 93 | _, err = io.ReadFull(r, b[1:1+net.IPv6len+2]) 94 | return b[:1+net.IPv6len+2], err 95 | } 96 | 97 | return nil, ErrAddressNotSupported 98 | } 99 | 100 | // ReadAddr reads just enough bytes from r to get a valid Addr. 101 | func ReadAddr(r io.Reader) (Addr, error) { 102 | return readAddr(r, make([]byte, MaxAddrLen)) 103 | } 104 | 105 | // SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed. 106 | func SplitAddr(b []byte) Addr { 107 | addrLen := 1 108 | if len(b) < addrLen { 109 | return nil 110 | } 111 | 112 | switch b[0] { 113 | case AtypDomainName: 114 | if len(b) < 2 { 115 | return nil 116 | } 117 | addrLen = 1 + 1 + int(b[1]) + 2 118 | case AtypIPv4: 119 | addrLen = 1 + net.IPv4len + 2 120 | case AtypIPv6: 121 | addrLen = 1 + net.IPv6len + 2 122 | default: 123 | return nil 124 | 125 | } 126 | 127 | if len(b) < addrLen { 128 | return nil 129 | } 130 | 131 | return b[:addrLen] 132 | } 133 | 134 | // ParseAddr parses the address in string s. Returns nil if failed. 135 | func ParseAddr(s string) Addr { 136 | var addr Addr 137 | host, port, err := net.SplitHostPort(s) 138 | if err != nil { 139 | return nil 140 | } 141 | if ip := net.ParseIP(host); ip != nil { 142 | if ip4 := ip.To4(); ip4 != nil { 143 | addr = make([]byte, 1+net.IPv4len+2) 144 | addr[0] = AtypIPv4 145 | copy(addr[1:], ip4) 146 | } else { 147 | addr = make([]byte, 1+net.IPv6len+2) 148 | addr[0] = AtypIPv6 149 | copy(addr[1:], ip) 150 | } 151 | } else { 152 | if len(host) > 255 { 153 | return nil 154 | } 155 | addr = make([]byte, 1+1+len(host)+2) 156 | addr[0] = AtypDomainName 157 | addr[1] = byte(len(host)) 158 | copy(addr[2:], host) 159 | } 160 | 161 | portnum, err := strconv.ParseUint(port, 10, 16) 162 | if err != nil { 163 | return nil 164 | } 165 | 166 | addr[len(addr)-2], addr[len(addr)-1] = byte(portnum>>8), byte(portnum) 167 | 168 | return addr 169 | } 170 | 171 | // Handshake fast-tracks SOCKS initialization to get target address to connect. 172 | func Handshake(rw io.ReadWriter) (Addr, error) { 173 | // Read RFC 1928 for request and reply structure and sizes. 174 | buf := make([]byte, MaxAddrLen) 175 | // read VER, NMETHODS, METHODS 176 | if _, err := io.ReadFull(rw, buf[:2]); err != nil { 177 | return nil, err 178 | } 179 | nmethods := buf[1] 180 | if _, err := io.ReadFull(rw, buf[:nmethods]); err != nil { 181 | return nil, err 182 | } 183 | // write VER METHOD 184 | if _, err := rw.Write([]byte{5, 0}); err != nil { 185 | return nil, err 186 | } 187 | // read VER CMD RSV ATYP DST.ADDR DST.PORT 188 | if _, err := io.ReadFull(rw, buf[:3]); err != nil { 189 | return nil, err 190 | } 191 | cmd := buf[1] 192 | addr, err := readAddr(rw, buf) 193 | if err != nil { 194 | return nil, err 195 | } 196 | switch cmd { 197 | case CmdConnect: 198 | _, err = rw.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0}) // SOCKS v5, reply succeeded 199 | case CmdUDPAssociate: 200 | if !UDPEnabled { 201 | return nil, ErrCommandNotSupported 202 | } 203 | listenAddr := ParseAddr(rw.(net.Conn).LocalAddr().String()) 204 | _, err = rw.Write(append([]byte{5, 0, 0}, listenAddr...)) // SOCKS v5, reply succeeded 205 | if err != nil { 206 | return nil, ErrCommandNotSupported 207 | } 208 | err = InfoUDPAssociate 209 | default: 210 | return nil, ErrCommandNotSupported 211 | } 212 | 213 | return addr, err // skip VER, CMD, RSV fields 214 | } 215 | -------------------------------------------------------------------------------- /ssSocksClient/tcp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "github.com/hashicorp/yamux" 6 | "io" 7 | "io/ioutil" 8 | "net" 9 | "os" 10 | "ssSocksClient/socks" 11 | "sync" 12 | "time" 13 | ) 14 | 15 | var session *yamux.Session 16 | 17 | func tcpRemote(addr string, shadow func(net.Conn) net.Conn, retryed *int) error { 18 | l, err := net.Dial("tcp", addr) 19 | if err != nil { 20 | logf("failed to connect on %s: %v", addr, err) 21 | return err 22 | } 23 | logf("connected") 24 | *retryed = 0 25 | session, err = yamux.Server(l, nil) 26 | defer session.Close() 27 | defer l.Close() 28 | for { 29 | c, err := session.Accept() 30 | if err != nil { 31 | logf("[X] Disconnected and reconnecting %s", err.Error()) 32 | return err 33 | } 34 | go func() { 35 | defer c.Close() 36 | sc := shadow(c) 37 | tgt, err := socks.ReadAddr(sc) 38 | if err != nil { 39 | _, _ = io.Copy(ioutil.Discard, c) 40 | return 41 | } 42 | rc, err := net.Dial("tcp", tgt.String()) 43 | if err != nil { 44 | return 45 | } 46 | defer rc.Close() 47 | if err = relay(sc, rc); err != nil { 48 | } 49 | }() 50 | } 51 | } 52 | func relay(left, right net.Conn) error { 53 | var err, err1 error 54 | var wg sync.WaitGroup 55 | var wait = 5 * time.Second 56 | wg.Add(1) 57 | go func() { 58 | defer wg.Done() 59 | _, err1 = io.Copy(right, left) 60 | right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right 61 | }() 62 | _, err = io.Copy(left, right) 63 | left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left 64 | wg.Wait() 65 | if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+ 66 | return err1 67 | } 68 | if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { 69 | return err 70 | } 71 | return nil 72 | } 73 | -------------------------------------------------------------------------------- /ssSocksServer/bot.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | "time" 9 | ) 10 | 11 | func bot(config Config, socks5 string, remoteAddr string, status bool) { 12 | socks5 = publicIp() + socks5[4:] 13 | switch config.BotType { 14 | case "wchatWork": 15 | fmt.Println("[+] send bot", socks5, remoteAddr) 16 | wchatWork(config.BotKey, socks5, remoteAddr, status) 17 | default: 18 | return 19 | } 20 | } 21 | func publicIp() string { 22 | client := http.Client{ 23 | Timeout: 3 * time.Second, 24 | } 25 | 26 | resp, err := client.Get("https://api.ipify.org?format=text") 27 | if err != nil { 28 | return "0.0.0.0" 29 | } 30 | defer resp.Body.Close() 31 | 32 | ip, err := ioutil.ReadAll(resp.Body) 33 | if err != nil { 34 | return "0.0.0.0" 35 | } 36 | return string(ip) 37 | } 38 | func wchatWork(key string, socks5 string, remoteAddr string, status bool) bool { 39 | url := "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=" + key 40 | data := "" 41 | if status { 42 | data = "{ \"msgtype\": \"markdown\", \"markdown\": { \"content\": \"新上线了一个socks5代理,兄弟们快冲。\\n >socks5:" + socks5 + " \\n>client:" + remoteAddr + "\" } }" 43 | } else { 44 | data = "{ \"msgtype\": \"markdown\", \"markdown\": { \"content\": \"代理掉辣,兄弟们别急。\\n >socks5:" + socks5 + " \\n>client:" + remoteAddr + "\" } }" 45 | } 46 | return postApi(url, data, "application/json") 47 | } 48 | 49 | func postApi(url string, data string, contentType string) bool { 50 | // 将JSON数据转换为字节数组 51 | jsonData := []byte(data) 52 | // 创建一个带有超时设置的HTTP客户端 53 | client := &http.Client{ 54 | Timeout: 10 * time.Second, // 设置超时时间为10秒 55 | } 56 | 57 | // 创建POST请求 58 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) 59 | if err != nil { 60 | fmt.Println("Failed to create request:", err) 61 | return false 62 | } 63 | req.Header.Set("Content-Type", contentType) 64 | 65 | // 发送请求并获取响应 66 | resp, err := client.Do(req) 67 | if err != nil { 68 | fmt.Println("HTTP request failed:", err) 69 | return false 70 | } 71 | defer resp.Body.Close() 72 | 73 | // 处理响应 74 | if resp.StatusCode == http.StatusOK { 75 | return true 76 | // 在这里处理成功的响应 77 | } else { 78 | fmt.Println("POST request failed with status code:", resp.StatusCode) 79 | return false 80 | // 在这里处理失败的响应 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /ssSocksServer/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "gopkg.in/ini.v1" 7 | "os" 8 | "regexp" 9 | ) 10 | 11 | type Config struct { 12 | BindAddr string 13 | BlockMode string 14 | BlockKey string 15 | Socks5Addr string 16 | DeleteMe bool 17 | BotKey string 18 | BotType string 19 | } 20 | 21 | func readConfig(configFile string) (config Config, err error) { 22 | cfg, err := ini.Load(configFile) 23 | if err != nil { 24 | fmt.Println("无法加载配置文件:", err) 25 | return config, err 26 | } 27 | 28 | // 解析配置文件中的数据 29 | config = Config{} 30 | err = cfg.Section("").MapTo(&config) 31 | if config.DeleteMe { 32 | os.Remove(configFile) 33 | } 34 | if err != nil { 35 | fmt.Println("无法解析配置文件:", err) 36 | return config, err 37 | } 38 | // 校验地址是否ip+端口的形式 39 | if !isValidIpPort(config.BindAddr) { 40 | fmt.Println("BindAddr不符合要求,格式为ip加端口") 41 | return config, errors.New("BindAddr不符合要求") 42 | } 43 | if !isValidIpPort(config.Socks5Addr) { 44 | fmt.Println("Socks5Addr不符合要求,格式为ip加端口") 45 | return config, errors.New("Socks5Addr不符合要求") 46 | } 47 | // 检查ApiKey长度是否符合要求 48 | if len(config.BlockKey) != 16 { 49 | fmt.Println("BlockKey长度不符合要求,只能16位") 50 | return config, errors.New("BlockKey长度不符合要求") 51 | } 52 | return config, nil 53 | } 54 | 55 | // 校验地址是否ip+端口的形式 56 | func isValidIpPort(address string) bool { 57 | 58 | // 使用正则表达式验证字符串格式 59 | pattern := `^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d):(\d{0,4}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])$` 60 | match, _ := regexp.MatchString(pattern, address) 61 | return match 62 | } 63 | -------------------------------------------------------------------------------- /ssSocksServer/config.ini: -------------------------------------------------------------------------------- 1 | BindAddr = 0.0.0.0:8080 ;客户端连接的端口 2 | BlockMode = aes-128-gcm ;shadowsockes的加密模式 3 | BlockKey = Ng&t0qawhHo45672 ;加密密钥,只能16位 4 | Socks5Addr = 0.0.0.0:1445 ;socks5 的起始监听端口 5 | DeleteMe = false ;是否自动删除配置文件 6 | BotType = wchatWork ;企业微信(wchatWork),留空则表示不使用机器人 7 | BotKey=exxxf-ddbbb-nnnd-94uuu4-3oooa0400 8 | 9 | -------------------------------------------------------------------------------- /ssSocksServer/core/cipher.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "crypto/md5" 5 | "errors" 6 | "net" 7 | "sort" 8 | "strings" 9 | 10 | "ssSocksServer/shadowaead" 11 | ) 12 | 13 | type Cipher interface { 14 | StreamConnCipher 15 | PacketConnCipher 16 | } 17 | 18 | type StreamConnCipher interface { 19 | StreamConn(net.Conn) net.Conn 20 | } 21 | 22 | type PacketConnCipher interface { 23 | PacketConn(net.PacketConn) net.PacketConn 24 | } 25 | 26 | // ErrCipherNotSupported occurs when a cipher is not supported (likely because of security concerns). 27 | var ErrCipherNotSupported = errors.New("cipher not supported") 28 | 29 | const ( 30 | aeadAes128Gcm = "AEAD_AES_128_GCM" 31 | aeadAes256Gcm = "AEAD_AES_256_GCM" 32 | aeadChacha20Poly1305 = "AEAD_CHACHA20_POLY1305" 33 | ) 34 | 35 | // List of AEAD ciphers: key size in bytes and constructor 36 | var aeadList = map[string]struct { 37 | KeySize int 38 | New func([]byte) (shadowaead.Cipher, error) 39 | }{ 40 | aeadAes128Gcm: {16, shadowaead.AESGCM}, 41 | aeadAes256Gcm: {32, shadowaead.AESGCM}, 42 | aeadChacha20Poly1305: {32, shadowaead.Chacha20Poly1305}, 43 | } 44 | 45 | // ListCipher returns a list of available cipher names sorted alphabetically. 46 | func ListCipher() []string { 47 | var l []string 48 | for k := range aeadList { 49 | l = append(l, k) 50 | } 51 | sort.Strings(l) 52 | return l 53 | } 54 | 55 | // PickCipher returns a Cipher of the given name. Derive key from password if given key is empty. 56 | func PickCipher(name string, key []byte, password string) (Cipher, error) { 57 | name = strings.ToUpper(name) 58 | 59 | switch name { 60 | case "DUMMY": 61 | return &dummy{}, nil 62 | case "CHACHA20-IETF-POLY1305": 63 | name = aeadChacha20Poly1305 64 | case "AES-128-GCM": 65 | name = aeadAes128Gcm 66 | case "AES-256-GCM": 67 | name = aeadAes256Gcm 68 | } 69 | 70 | if choice, ok := aeadList[name]; ok { 71 | if len(key) == 0 { 72 | key = kdf(password, choice.KeySize) 73 | } 74 | if len(key) != choice.KeySize { 75 | return nil, shadowaead.KeySizeError(choice.KeySize) 76 | } 77 | aead, err := choice.New(key) 78 | return &aeadCipher{aead}, err 79 | } 80 | 81 | return nil, ErrCipherNotSupported 82 | } 83 | 84 | type aeadCipher struct{ shadowaead.Cipher } 85 | 86 | func (aead *aeadCipher) StreamConn(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) } 87 | func (aead *aeadCipher) PacketConn(c net.PacketConn) net.PacketConn { 88 | return shadowaead.NewPacketConn(c, aead) 89 | } 90 | 91 | // dummy cipher does not encrypt 92 | type dummy struct{} 93 | 94 | func (dummy) StreamConn(c net.Conn) net.Conn { return c } 95 | func (dummy) PacketConn(c net.PacketConn) net.PacketConn { return c } 96 | 97 | // key-derivation function from original Shadowsocks 98 | func kdf(password string, keyLen int) []byte { 99 | var b, prev []byte 100 | h := md5.New() 101 | for len(b) < keyLen { 102 | h.Write(prev) 103 | h.Write([]byte(password)) 104 | b = h.Sum(b) 105 | prev = b[len(b)-h.Size():] 106 | h.Reset() 107 | } 108 | return b[:keyLen] 109 | } 110 | -------------------------------------------------------------------------------- /ssSocksServer/core/doc.go: -------------------------------------------------------------------------------- 1 | // Package core implements essential parts of Shadowsocks 2 | package core 3 | -------------------------------------------------------------------------------- /ssSocksServer/core/packet.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "net" 4 | 5 | func ListenPacket(network, address string, ciph PacketConnCipher) (net.PacketConn, error) { 6 | c, err := net.ListenPacket(network, address) 7 | return ciph.PacketConn(c), err 8 | } 9 | -------------------------------------------------------------------------------- /ssSocksServer/core/stream.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "net" 4 | 5 | type listener struct { 6 | net.Listener 7 | StreamConnCipher 8 | } 9 | 10 | func Listen(network, address string, ciph StreamConnCipher) (net.Listener, error) { 11 | l, err := net.Listen(network, address) 12 | return &listener{l, ciph}, err 13 | } 14 | 15 | func (l *listener) Accept() (net.Conn, error) { 16 | c, err := l.Listener.Accept() 17 | return l.StreamConn(c), err 18 | } 19 | 20 | func Dial(network, address string, ciph StreamConnCipher) (net.Conn, error) { 21 | c, err := net.Dial(network, address) 22 | return ciph.StreamConn(c), err 23 | } 24 | -------------------------------------------------------------------------------- /ssSocksServer/go.mod: -------------------------------------------------------------------------------- 1 | module ssSocksServer 2 | 3 | go 1.21 4 | 5 | require ( 6 | github.com/hashicorp/yamux v0.1.1 7 | github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 8 | golang.org/x/crypto v0.14.0 9 | gopkg.in/ini.v1 v1.67.0 10 | ) 11 | 12 | require ( 13 | github.com/stretchr/testify v1.8.4 // indirect 14 | golang.org/x/sys v0.13.0 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /ssSocksServer/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= 4 | github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= 8 | github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= 9 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 10 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 11 | golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= 12 | golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= 13 | golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= 14 | golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 15 | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= 16 | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 17 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 18 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 19 | -------------------------------------------------------------------------------- /ssSocksServer/internal/bloomring.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "github.com/riobard/go-bloom" 5 | "hash/fnv" 6 | "sync" 7 | ) 8 | 9 | // simply use Double FNV here as our Bloom Filter hash 10 | func doubleFNV(b []byte) (uint64, uint64) { 11 | hx := fnv.New64() 12 | hx.Write(b) 13 | x := hx.Sum64() 14 | hy := fnv.New64a() 15 | hy.Write(b) 16 | y := hy.Sum64() 17 | return x, y 18 | } 19 | 20 | type BloomRing struct { 21 | slotCapacity int 22 | slotPosition int 23 | slotCount int 24 | entryCounter int 25 | slots []bloom.Filter 26 | mutex sync.RWMutex 27 | } 28 | 29 | func NewBloomRing(slot, capacity int, falsePositiveRate float64) *BloomRing { 30 | // Calculate entries for each slot 31 | r := &BloomRing{ 32 | slotCapacity: capacity / slot, 33 | slotCount: slot, 34 | slots: make([]bloom.Filter, slot), 35 | } 36 | for i := 0; i < slot; i++ { 37 | r.slots[i] = bloom.New(r.slotCapacity, falsePositiveRate, doubleFNV) 38 | } 39 | return r 40 | } 41 | 42 | func (r *BloomRing) Add(b []byte) { 43 | if r == nil { 44 | return 45 | } 46 | r.mutex.Lock() 47 | defer r.mutex.Unlock() 48 | r.add(b) 49 | } 50 | 51 | func (r *BloomRing) add(b []byte) { 52 | slot := r.slots[r.slotPosition] 53 | if r.entryCounter > r.slotCapacity { 54 | // Move to next slot and reset 55 | r.slotPosition = (r.slotPosition + 1) % r.slotCount 56 | slot = r.slots[r.slotPosition] 57 | slot.Reset() 58 | r.entryCounter = 0 59 | } 60 | r.entryCounter++ 61 | slot.Add(b) 62 | } 63 | 64 | func (r *BloomRing) Test(b []byte) bool { 65 | if r == nil { 66 | return false 67 | } 68 | r.mutex.RLock() 69 | defer r.mutex.RUnlock() 70 | test := r.test(b) 71 | return test 72 | } 73 | 74 | func (r *BloomRing) test(b []byte) bool { 75 | for _, s := range r.slots { 76 | if s.Test(b) { 77 | return true 78 | } 79 | } 80 | return false 81 | } 82 | 83 | func (r *BloomRing) Check(b []byte) bool { 84 | r.mutex.Lock() 85 | defer r.mutex.Unlock() 86 | if r.Test(b) { 87 | return true 88 | } 89 | r.Add(b) 90 | return false 91 | } 92 | -------------------------------------------------------------------------------- /ssSocksServer/internal/bloomring_test.go: -------------------------------------------------------------------------------- 1 | package internal_test 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "testing" 7 | ) 8 | 9 | var ( 10 | bloomRingInstance *BloomRing 11 | ) 12 | 13 | func TestMain(m *testing.M) { 14 | bloomRingInstance = NewBloomRing(DefaultSFSlot, int(DefaultSFCapacity), 15 | DefaultSFFPR) 16 | os.Exit(m.Run()) 17 | } 18 | 19 | func TestBloomRing_Add(t *testing.T) { 20 | defer func() { 21 | if any := recover(); any != nil { 22 | t.Fatalf("Should not got panic while adding item: %v", any) 23 | } 24 | }() 25 | bloomRingInstance.Add(make([]byte, 16)) 26 | } 27 | 28 | func TestBloomRing_NilAdd(t *testing.T) { 29 | defer func() { 30 | if any := recover(); any != nil { 31 | t.Fatalf("Should not got panic while adding item: %v", any) 32 | } 33 | }() 34 | var nilRing *BloomRing 35 | nilRing.Add(make([]byte, 16)) 36 | } 37 | 38 | func TestBloomRing_Test(t *testing.T) { 39 | buf := []byte("shadowsocks") 40 | bloomRingInstance.Add(buf) 41 | if !bloomRingInstance.Test(buf) { 42 | t.Fatal("Test on filter missing") 43 | } 44 | } 45 | 46 | func TestBloomRing_NilTestIsFalse(t *testing.T) { 47 | var nilRing *BloomRing 48 | if nilRing.Test([]byte("shadowsocks")) { 49 | t.Fatal("Test should return false for nil BloomRing") 50 | } 51 | } 52 | 53 | func BenchmarkBloomRing(b *testing.B) { 54 | // Generate test samples with different length 55 | samples := make([][]byte, DefaultSFCapacity-DefaultSFSlot) 56 | var checkPoints [][]byte 57 | for i := 0; i < len(samples); i++ { 58 | samples[i] = []byte(fmt.Sprint(i)) 59 | if i%1000 == 0 { 60 | checkPoints = append(checkPoints, samples[i]) 61 | } 62 | } 63 | b.Logf("Generated %d samples and %d check points", len(samples), len(checkPoints)) 64 | for i := 1; i < 16; i++ { 65 | b.Run(fmt.Sprintf("Slot%d", i), benchmarkBloomRing(samples, checkPoints, i)) 66 | } 67 | } 68 | 69 | func benchmarkBloomRing(samples, checkPoints [][]byte, slot int) func(*testing.B) { 70 | filter := NewBloomRing(slot, int(DefaultSFCapacity), DefaultSFFPR) 71 | for _, sample := range samples { 72 | filter.Add(sample) 73 | } 74 | return func(b *testing.B) { 75 | b.ResetTimer() 76 | b.ReportAllocs() 77 | for i := 0; i < b.N; i++ { 78 | for _, cp := range checkPoints { 79 | filter.Test(cp) 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ssSocksServer/internal/saltfilter.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "strconv" 7 | "sync" 8 | ) 9 | 10 | // Those suggest value are all set according to 11 | // https://github.com/shadowsocks/shadowsocks-org/issues/44#issuecomment-281021054 12 | // Due to this package contains various internal implementation so const named with DefaultBR prefix 13 | const ( 14 | DefaultSFCapacity = 1e6 15 | // FalsePositiveRate 16 | DefaultSFFPR = 1e-6 17 | DefaultSFSlot = 10 18 | ) 19 | 20 | const EnvironmentPrefix = "SHADOWSOCKS_" 21 | 22 | // A shared instance used for checking salt repeat 23 | var saltfilter *BloomRing 24 | 25 | // Used to initialize the saltfilter singleton only once. 26 | var initSaltfilterOnce sync.Once 27 | 28 | // GetSaltFilterSingleton returns the BloomRing singleton, 29 | // initializing it on first call. 30 | func getSaltFilterSingleton() *BloomRing { 31 | initSaltfilterOnce.Do(func() { 32 | var ( 33 | finalCapacity = DefaultSFCapacity 34 | finalFPR = DefaultSFFPR 35 | finalSlot = float64(DefaultSFSlot) 36 | ) 37 | for _, opt := range []struct { 38 | ENVName string 39 | Target *float64 40 | }{ 41 | { 42 | ENVName: "CAPACITY", 43 | Target: &finalCapacity, 44 | }, 45 | { 46 | ENVName: "FPR", 47 | Target: &finalFPR, 48 | }, 49 | { 50 | ENVName: "SLOT", 51 | Target: &finalSlot, 52 | }, 53 | } { 54 | envKey := EnvironmentPrefix + "SF_" + opt.ENVName 55 | env := os.Getenv(envKey) 56 | if env != "" { 57 | p, err := strconv.ParseFloat(env, 64) 58 | if err != nil { 59 | panic(fmt.Sprintf("Invalid envrionment `%s` setting in saltfilter: %s", envKey, env)) 60 | } 61 | *opt.Target = p 62 | } 63 | } 64 | // Support disable saltfilter by given a negative capacity 65 | if finalCapacity <= 0 { 66 | return 67 | } 68 | saltfilter = NewBloomRing(int(finalSlot), int(finalCapacity), finalFPR) 69 | }) 70 | return saltfilter 71 | } 72 | 73 | // TestSalt returns true if salt is repeated 74 | func TestSalt(b []byte) bool { 75 | return getSaltFilterSingleton().Test(b) 76 | } 77 | 78 | // AddSalt salt to filter 79 | func AddSalt(b []byte) { 80 | getSaltFilterSingleton().Add(b) 81 | } 82 | 83 | func CheckSalt(b []byte) bool { 84 | return getSaltFilterSingleton().Test(b) 85 | } 86 | -------------------------------------------------------------------------------- /ssSocksServer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "ssSocksServer/core" 6 | ) 7 | 8 | func main() { 9 | // 加载配置文件 10 | config, err := readConfig("config.ini") 11 | if err != nil { 12 | return 13 | } 14 | ciph, err := core.PickCipher(config.BlockMode, nil, config.BlockKey) 15 | if err != nil { 16 | log.Fatal(err) 17 | } 18 | Run(config, ciph.StreamConn) 19 | } 20 | -------------------------------------------------------------------------------- /ssSocksServer/shadowaead/cipher.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/sha1" 7 | "errors" 8 | "io" 9 | "strconv" 10 | 11 | "golang.org/x/crypto/chacha20poly1305" 12 | "golang.org/x/crypto/hkdf" 13 | ) 14 | 15 | // ErrRepeatedSalt means detected a reused salt 16 | var ErrRepeatedSalt = errors.New("repeated salt detected") 17 | 18 | type Cipher interface { 19 | KeySize() int 20 | SaltSize() int 21 | Encrypter(salt []byte) (cipher.AEAD, error) 22 | Decrypter(salt []byte) (cipher.AEAD, error) 23 | } 24 | 25 | type KeySizeError int 26 | 27 | func (e KeySizeError) Error() string { 28 | return "key size error: need " + strconv.Itoa(int(e)) + " bytes" 29 | } 30 | 31 | func hkdfSHA1(secret, salt, info, outkey []byte) { 32 | r := hkdf.New(sha1.New, secret, salt, info) 33 | if _, err := io.ReadFull(r, outkey); err != nil { 34 | panic(err) // should never happen 35 | } 36 | } 37 | 38 | type metaCipher struct { 39 | psk []byte 40 | makeAEAD func(key []byte) (cipher.AEAD, error) 41 | } 42 | 43 | func (a *metaCipher) KeySize() int { return len(a.psk) } 44 | func (a *metaCipher) SaltSize() int { 45 | if ks := a.KeySize(); ks > 16 { 46 | return ks 47 | } 48 | return 16 49 | } 50 | func (a *metaCipher) Encrypter(salt []byte) (cipher.AEAD, error) { 51 | subkey := make([]byte, a.KeySize()) 52 | hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey) 53 | return a.makeAEAD(subkey) 54 | } 55 | func (a *metaCipher) Decrypter(salt []byte) (cipher.AEAD, error) { 56 | subkey := make([]byte, a.KeySize()) 57 | hkdfSHA1(a.psk, salt, []byte("ss-subkey"), subkey) 58 | return a.makeAEAD(subkey) 59 | } 60 | 61 | func aesGCM(key []byte) (cipher.AEAD, error) { 62 | blk, err := aes.NewCipher(key) 63 | if err != nil { 64 | return nil, err 65 | } 66 | return cipher.NewGCM(blk) 67 | } 68 | 69 | // AESGCM creates a new Cipher with a pre-shared key. len(psk) must be 70 | // one of 16, 24, or 32 to select AES-128/196/256-GCM. 71 | func AESGCM(psk []byte) (Cipher, error) { 72 | switch l := len(psk); l { 73 | case 16, 24, 32: // AES 128/196/256 74 | default: 75 | return nil, aes.KeySizeError(l) 76 | } 77 | return &metaCipher{psk: psk, makeAEAD: aesGCM}, nil 78 | } 79 | 80 | // Chacha20Poly1305 creates a new Cipher with a pre-shared key. len(psk) 81 | // must be 32. 82 | func Chacha20Poly1305(psk []byte) (Cipher, error) { 83 | if len(psk) != chacha20poly1305.KeySize { 84 | return nil, KeySizeError(chacha20poly1305.KeySize) 85 | } 86 | return &metaCipher{psk: psk, makeAEAD: chacha20poly1305.New}, nil 87 | } 88 | -------------------------------------------------------------------------------- /ssSocksServer/shadowaead/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package shadowaead implements a simple AEAD-protected secure protocol. 3 | 4 | In general, there are two types of connections: stream-oriented and packet-oriented. 5 | Stream-oriented connections (e.g. TCP) assume reliable and orderly delivery of bytes. 6 | Packet-oriented connections (e.g. UDP) assume unreliable and out-of-order delivery of packets, 7 | where each packet is either delivered intact or lost. 8 | 9 | An encrypted stream starts with a random salt to derive a session key, followed by any number of 10 | encrypted records. Each encrypted record has the following structure: 11 | 12 | [encrypted payload length] 13 | [payload length tag] 14 | [encrypted payload] 15 | [payload tag] 16 | 17 | Payload length is 2-byte unsigned big-endian integer capped at 0x3FFF (16383). 18 | The higher 2 bits are reserved and must be set to zero. The first AEAD encrypt/decrypt 19 | operation uses a counting nonce starting from 0. After each encrypt/decrypt operation, 20 | the nonce is incremented by one as if it were an unsigned little-endian integer. 21 | 22 | 23 | Each encrypted packet transmitted on a packet-oriented connection has the following structure: 24 | 25 | [random salt] 26 | [encrypted payload] 27 | [payload tag] 28 | 29 | The salt is used to derive a subkey to initiate an AEAD. Packets are encrypted/decrypted independently 30 | using zero nonce. 31 | 32 | In both stream-oriented and packet-oriented connections, length of nonce and tag varies 33 | depending on which AEAD is used. Salt should be at least 16-byte long. 34 | */ 35 | package shadowaead 36 | -------------------------------------------------------------------------------- /ssSocksServer/shadowaead/packet.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "crypto/rand" 5 | "errors" 6 | "io" 7 | "net" 8 | "sync" 9 | 10 | "ssSocksServer/internal" 11 | ) 12 | 13 | // ErrShortPacket means that the packet is too short for a valid encrypted packet. 14 | var ErrShortPacket = errors.New("short packet") 15 | 16 | var _zerononce [128]byte // read-only. 128 bytes is more than enough. 17 | 18 | // Pack encrypts plaintext using Cipher with a randomly generated salt and 19 | // returns a slice of dst containing the encrypted packet and any error occurred. 20 | // Ensure len(dst) >= ciph.SaltSize() + len(plaintext) + aead.Overhead(). 21 | func Pack(dst, plaintext []byte, ciph Cipher) ([]byte, error) { 22 | saltSize := ciph.SaltSize() 23 | salt := dst[:saltSize] 24 | if _, err := io.ReadFull(rand.Reader, salt); err != nil { 25 | return nil, err 26 | } 27 | 28 | aead, err := ciph.Encrypter(salt) 29 | if err != nil { 30 | return nil, err 31 | } 32 | internal.AddSalt(salt) 33 | 34 | if len(dst) < saltSize+len(plaintext)+aead.Overhead() { 35 | return nil, io.ErrShortBuffer 36 | } 37 | b := aead.Seal(dst[saltSize:saltSize], _zerononce[:aead.NonceSize()], plaintext, nil) 38 | return dst[:saltSize+len(b)], nil 39 | } 40 | 41 | // Unpack decrypts pkt using Cipher and returns a slice of dst containing the decrypted payload and any error occurred. 42 | // Ensure len(dst) >= len(pkt) - aead.SaltSize() - aead.Overhead(). 43 | func Unpack(dst, pkt []byte, ciph Cipher) ([]byte, error) { 44 | saltSize := ciph.SaltSize() 45 | if len(pkt) < saltSize { 46 | return nil, ErrShortPacket 47 | } 48 | salt := pkt[:saltSize] 49 | aead, err := ciph.Decrypter(salt) 50 | if err != nil { 51 | return nil, err 52 | } 53 | if internal.CheckSalt(salt) { 54 | return nil, ErrRepeatedSalt 55 | } 56 | if len(pkt) < saltSize+aead.Overhead() { 57 | return nil, ErrShortPacket 58 | } 59 | if saltSize+len(dst)+aead.Overhead() < len(pkt) { 60 | return nil, io.ErrShortBuffer 61 | } 62 | b, err := aead.Open(dst[:0], _zerononce[:aead.NonceSize()], pkt[saltSize:], nil) 63 | return b, err 64 | } 65 | 66 | type packetConn struct { 67 | net.PacketConn 68 | Cipher 69 | sync.Mutex 70 | buf []byte // write lock 71 | } 72 | 73 | // NewPacketConn wraps a net.PacketConn with cipher 74 | func NewPacketConn(c net.PacketConn, ciph Cipher) net.PacketConn { 75 | const maxPacketSize = 64 * 1024 76 | return &packetConn{PacketConn: c, Cipher: ciph, buf: make([]byte, maxPacketSize)} 77 | } 78 | 79 | // WriteTo encrypts b and write to addr using the embedded PacketConn. 80 | func (c *packetConn) WriteTo(b []byte, addr net.Addr) (int, error) { 81 | c.Lock() 82 | defer c.Unlock() 83 | buf, err := Pack(c.buf, b, c) 84 | if err != nil { 85 | return 0, err 86 | } 87 | _, err = c.PacketConn.WriteTo(buf, addr) 88 | return len(b), err 89 | } 90 | 91 | // ReadFrom reads from the embedded PacketConn and decrypts into b. 92 | func (c *packetConn) ReadFrom(b []byte) (int, net.Addr, error) { 93 | n, addr, err := c.PacketConn.ReadFrom(b) 94 | if err != nil { 95 | return n, addr, err 96 | } 97 | bb, err := Unpack(b[c.Cipher.SaltSize():], b[:n], c) 98 | if err != nil { 99 | return n, addr, err 100 | } 101 | copy(b, bb) 102 | return len(bb), addr, err 103 | } 104 | -------------------------------------------------------------------------------- /ssSocksServer/shadowaead/stream.go: -------------------------------------------------------------------------------- 1 | package shadowaead 2 | 3 | import ( 4 | "bytes" 5 | "crypto/cipher" 6 | "crypto/rand" 7 | "io" 8 | "net" 9 | 10 | "ssSocksServer/internal" 11 | ) 12 | 13 | // payloadSizeMask is the maximum size of payload in bytes. 14 | const payloadSizeMask = 0x3FFF // 16*1024 - 1 15 | 16 | type writer struct { 17 | io.Writer 18 | cipher.AEAD 19 | nonce []byte 20 | buf []byte 21 | } 22 | 23 | // NewWriter wraps an io.Writer with AEAD encryption. 24 | func NewWriter(w io.Writer, aead cipher.AEAD) io.Writer { return newWriter(w, aead) } 25 | 26 | func newWriter(w io.Writer, aead cipher.AEAD) *writer { 27 | return &writer{ 28 | Writer: w, 29 | AEAD: aead, 30 | buf: make([]byte, 2+aead.Overhead()+payloadSizeMask+aead.Overhead()), 31 | nonce: make([]byte, aead.NonceSize()), 32 | } 33 | } 34 | 35 | // Write encrypts b and writes to the embedded io.Writer. 36 | func (w *writer) Write(b []byte) (int, error) { 37 | n, err := w.ReadFrom(bytes.NewBuffer(b)) 38 | return int(n), err 39 | } 40 | 41 | // ReadFrom reads from the given io.Reader until EOF or error, encrypts and 42 | // writes to the embedded io.Writer. Returns number of bytes read from r and 43 | // any error encountered. 44 | func (w *writer) ReadFrom(r io.Reader) (n int64, err error) { 45 | for { 46 | buf := w.buf 47 | payloadBuf := buf[2+w.Overhead() : 2+w.Overhead()+payloadSizeMask] 48 | nr, er := r.Read(payloadBuf) 49 | 50 | if nr > 0 { 51 | n += int64(nr) 52 | buf = buf[:2+w.Overhead()+nr+w.Overhead()] 53 | payloadBuf = payloadBuf[:nr] 54 | buf[0], buf[1] = byte(nr>>8), byte(nr) // big-endian payload size 55 | w.Seal(buf[:0], w.nonce, buf[:2], nil) 56 | increment(w.nonce) 57 | 58 | w.Seal(payloadBuf[:0], w.nonce, payloadBuf, nil) 59 | increment(w.nonce) 60 | 61 | _, ew := w.Writer.Write(buf) 62 | if ew != nil { 63 | err = ew 64 | break 65 | } 66 | } 67 | 68 | if er != nil { 69 | if er != io.EOF { // ignore EOF as per io.ReaderFrom contract 70 | err = er 71 | } 72 | break 73 | } 74 | } 75 | 76 | return n, err 77 | } 78 | 79 | type reader struct { 80 | io.Reader 81 | cipher.AEAD 82 | nonce []byte 83 | buf []byte 84 | leftover []byte 85 | } 86 | 87 | // NewReader wraps an io.Reader with AEAD decryption. 88 | func NewReader(r io.Reader, aead cipher.AEAD) io.Reader { return newReader(r, aead) } 89 | 90 | func newReader(r io.Reader, aead cipher.AEAD) *reader { 91 | return &reader{ 92 | Reader: r, 93 | AEAD: aead, 94 | buf: make([]byte, payloadSizeMask+aead.Overhead()), 95 | nonce: make([]byte, aead.NonceSize()), 96 | } 97 | } 98 | 99 | // read and decrypt a record into the internal buffer. Return decrypted payload length and any error encountered. 100 | func (r *reader) read() (int, error) { 101 | // decrypt payload size 102 | buf := r.buf[:2+r.Overhead()] 103 | _, err := io.ReadFull(r.Reader, buf) 104 | if err != nil { 105 | return 0, err 106 | } 107 | 108 | _, err = r.Open(buf[:0], r.nonce, buf, nil) 109 | increment(r.nonce) 110 | if err != nil { 111 | return 0, err 112 | } 113 | 114 | size := (int(buf[0])<<8 + int(buf[1])) & payloadSizeMask 115 | 116 | // decrypt payload 117 | buf = r.buf[:size+r.Overhead()] 118 | _, err = io.ReadFull(r.Reader, buf) 119 | if err != nil { 120 | return 0, err 121 | } 122 | 123 | _, err = r.Open(buf[:0], r.nonce, buf, nil) 124 | increment(r.nonce) 125 | if err != nil { 126 | return 0, err 127 | } 128 | 129 | return size, nil 130 | } 131 | 132 | // Read reads from the embedded io.Reader, decrypts and writes to b. 133 | func (r *reader) Read(b []byte) (int, error) { 134 | // copy decrypted bytes (if any) from previous record first 135 | if len(r.leftover) > 0 { 136 | n := copy(b, r.leftover) 137 | r.leftover = r.leftover[n:] 138 | return n, nil 139 | } 140 | 141 | n, err := r.read() 142 | m := copy(b, r.buf[:n]) 143 | if m < n { // insufficient len(b), keep leftover for next read 144 | r.leftover = r.buf[m:n] 145 | } 146 | return m, err 147 | } 148 | 149 | // WriteTo reads from the embedded io.Reader, decrypts and writes to w until 150 | // there's no more data to write or when an error occurs. Return number of 151 | // bytes written to w and any error encountered. 152 | func (r *reader) WriteTo(w io.Writer) (n int64, err error) { 153 | // write decrypted bytes left over from previous record 154 | for len(r.leftover) > 0 { 155 | nw, ew := w.Write(r.leftover) 156 | r.leftover = r.leftover[nw:] 157 | n += int64(nw) 158 | if ew != nil { 159 | return n, ew 160 | } 161 | } 162 | 163 | for { 164 | nr, er := r.read() 165 | if nr > 0 { 166 | nw, ew := w.Write(r.buf[:nr]) 167 | n += int64(nw) 168 | 169 | if ew != nil { 170 | err = ew 171 | break 172 | } 173 | } 174 | 175 | if er != nil { 176 | if er != io.EOF { // ignore EOF as per io.Copy contract (using src.WriteTo shortcut) 177 | err = er 178 | } 179 | break 180 | } 181 | } 182 | 183 | return n, err 184 | } 185 | 186 | // increment little-endian encoded unsigned integer b. Wrap around on overflow. 187 | func increment(b []byte) { 188 | for i := range b { 189 | b[i]++ 190 | if b[i] != 0 { 191 | return 192 | } 193 | } 194 | } 195 | 196 | type streamConn struct { 197 | net.Conn 198 | Cipher 199 | r *reader 200 | w *writer 201 | } 202 | 203 | func (c *streamConn) initReader() error { 204 | salt := make([]byte, c.SaltSize()) 205 | if _, err := io.ReadFull(c.Conn, salt); err != nil { 206 | return err 207 | } 208 | aead, err := c.Decrypter(salt) 209 | if err != nil { 210 | return err 211 | } 212 | 213 | if internal.CheckSalt(salt) { 214 | return ErrRepeatedSalt 215 | } 216 | 217 | c.r = newReader(c.Conn, aead) 218 | return nil 219 | } 220 | 221 | func (c *streamConn) Read(b []byte) (int, error) { 222 | if c.r == nil { 223 | if err := c.initReader(); err != nil { 224 | return 0, err 225 | } 226 | } 227 | return c.r.Read(b) 228 | } 229 | 230 | func (c *streamConn) WriteTo(w io.Writer) (int64, error) { 231 | if c.r == nil { 232 | if err := c.initReader(); err != nil { 233 | return 0, err 234 | } 235 | } 236 | return c.r.WriteTo(w) 237 | } 238 | 239 | func (c *streamConn) initWriter() error { 240 | salt := make([]byte, c.SaltSize()) 241 | if _, err := io.ReadFull(rand.Reader, salt); err != nil { 242 | return err 243 | } 244 | aead, err := c.Encrypter(salt) 245 | if err != nil { 246 | return err 247 | } 248 | _, err = c.Conn.Write(salt) 249 | if err != nil { 250 | return err 251 | } 252 | internal.AddSalt(salt) 253 | c.w = newWriter(c.Conn, aead) 254 | return nil 255 | } 256 | 257 | func (c *streamConn) Write(b []byte) (int, error) { 258 | if c.w == nil { 259 | if err := c.initWriter(); err != nil { 260 | return 0, err 261 | } 262 | } 263 | return c.w.Write(b) 264 | } 265 | 266 | func (c *streamConn) ReadFrom(r io.Reader) (int64, error) { 267 | if c.w == nil { 268 | if err := c.initWriter(); err != nil { 269 | return 0, err 270 | } 271 | } 272 | return c.w.ReadFrom(r) 273 | } 274 | 275 | // NewConn wraps a stream-oriented net.Conn with cipher. 276 | func NewConn(c net.Conn, ciph Cipher) net.Conn { return &streamConn{Conn: c, Cipher: ciph} } 277 | -------------------------------------------------------------------------------- /ssSocksServer/socks/socks.go: -------------------------------------------------------------------------------- 1 | // Package socks implements essential parts of SOCKS protocol. 2 | package socks 3 | 4 | import ( 5 | "io" 6 | "net" 7 | "strconv" 8 | ) 9 | 10 | // UDPEnabled is the toggle for UDP support 11 | var UDPEnabled = false 12 | 13 | // SOCKS request commands as defined in RFC 1928 section 4. 14 | const ( 15 | CmdConnect = 1 16 | CmdBind = 2 17 | CmdUDPAssociate = 3 18 | ) 19 | 20 | // SOCKS address types as defined in RFC 1928 section 5. 21 | const ( 22 | AtypIPv4 = 1 23 | AtypDomainName = 3 24 | AtypIPv6 = 4 25 | ) 26 | 27 | // Error represents a SOCKS error 28 | type Error byte 29 | 30 | func (err Error) Error() string { 31 | return "SOCKS error: " + strconv.Itoa(int(err)) 32 | } 33 | 34 | // SOCKS errors as defined in RFC 1928 section 6. 35 | const ( 36 | ErrGeneralFailure = Error(1) 37 | ErrConnectionNotAllowed = Error(2) 38 | ErrNetworkUnreachable = Error(3) 39 | ErrHostUnreachable = Error(4) 40 | ErrConnectionRefused = Error(5) 41 | ErrTTLExpired = Error(6) 42 | ErrCommandNotSupported = Error(7) 43 | ErrAddressNotSupported = Error(8) 44 | InfoUDPAssociate = Error(9) 45 | ) 46 | 47 | // MaxAddrLen is the maximum size of SOCKS address in bytes. 48 | const MaxAddrLen = 1 + 1 + 255 + 2 49 | 50 | // Addr represents a SOCKS address as defined in RFC 1928 section 5. 51 | type Addr []byte 52 | 53 | // String serializes SOCKS address a to string form. 54 | func (a Addr) String() string { 55 | var host, port string 56 | 57 | switch a[0] { // address type 58 | case AtypDomainName: 59 | host = string(a[2 : 2+int(a[1])]) 60 | port = strconv.Itoa((int(a[2+int(a[1])]) << 8) | int(a[2+int(a[1])+1])) 61 | case AtypIPv4: 62 | host = net.IP(a[1 : 1+net.IPv4len]).String() 63 | port = strconv.Itoa((int(a[1+net.IPv4len]) << 8) | int(a[1+net.IPv4len+1])) 64 | case AtypIPv6: 65 | host = net.IP(a[1 : 1+net.IPv6len]).String() 66 | port = strconv.Itoa((int(a[1+net.IPv6len]) << 8) | int(a[1+net.IPv6len+1])) 67 | } 68 | 69 | return net.JoinHostPort(host, port) 70 | } 71 | 72 | func readAddr(r io.Reader, b []byte) (Addr, error) { 73 | if len(b) < MaxAddrLen { 74 | return nil, io.ErrShortBuffer 75 | } 76 | _, err := io.ReadFull(r, b[:1]) // read 1st byte for address type 77 | if err != nil { 78 | return nil, err 79 | } 80 | 81 | switch b[0] { 82 | case AtypDomainName: 83 | _, err = io.ReadFull(r, b[1:2]) // read 2nd byte for domain length 84 | if err != nil { 85 | return nil, err 86 | } 87 | _, err = io.ReadFull(r, b[2:2+int(b[1])+2]) 88 | return b[:1+1+int(b[1])+2], err 89 | case AtypIPv4: 90 | _, err = io.ReadFull(r, b[1:1+net.IPv4len+2]) 91 | return b[:1+net.IPv4len+2], err 92 | case AtypIPv6: 93 | _, err = io.ReadFull(r, b[1:1+net.IPv6len+2]) 94 | return b[:1+net.IPv6len+2], err 95 | } 96 | 97 | return nil, ErrAddressNotSupported 98 | } 99 | 100 | // ReadAddr reads just enough bytes from r to get a valid Addr. 101 | func ReadAddr(r io.Reader) (Addr, error) { 102 | return readAddr(r, make([]byte, MaxAddrLen)) 103 | } 104 | 105 | // SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed. 106 | func SplitAddr(b []byte) Addr { 107 | addrLen := 1 108 | if len(b) < addrLen { 109 | return nil 110 | } 111 | 112 | switch b[0] { 113 | case AtypDomainName: 114 | if len(b) < 2 { 115 | return nil 116 | } 117 | addrLen = 1 + 1 + int(b[1]) + 2 118 | case AtypIPv4: 119 | addrLen = 1 + net.IPv4len + 2 120 | case AtypIPv6: 121 | addrLen = 1 + net.IPv6len + 2 122 | default: 123 | return nil 124 | 125 | } 126 | 127 | if len(b) < addrLen { 128 | return nil 129 | } 130 | 131 | return b[:addrLen] 132 | } 133 | 134 | // ParseAddr parses the address in string s. Returns nil if failed. 135 | func ParseAddr(s string) Addr { 136 | var addr Addr 137 | host, port, err := net.SplitHostPort(s) 138 | if err != nil { 139 | return nil 140 | } 141 | if ip := net.ParseIP(host); ip != nil { 142 | if ip4 := ip.To4(); ip4 != nil { 143 | addr = make([]byte, 1+net.IPv4len+2) 144 | addr[0] = AtypIPv4 145 | copy(addr[1:], ip4) 146 | } else { 147 | addr = make([]byte, 1+net.IPv6len+2) 148 | addr[0] = AtypIPv6 149 | copy(addr[1:], ip) 150 | } 151 | } else { 152 | if len(host) > 255 { 153 | return nil 154 | } 155 | addr = make([]byte, 1+1+len(host)+2) 156 | addr[0] = AtypDomainName 157 | addr[1] = byte(len(host)) 158 | copy(addr[2:], host) 159 | } 160 | 161 | portnum, err := strconv.ParseUint(port, 10, 16) 162 | if err != nil { 163 | return nil 164 | } 165 | 166 | addr[len(addr)-2], addr[len(addr)-1] = byte(portnum>>8), byte(portnum) 167 | 168 | return addr 169 | } 170 | 171 | // Handshake fast-tracks SOCKS initialization to get target address to connect. 172 | func Handshake(rw io.ReadWriter) (Addr, error) { 173 | // Read RFC 1928 for request and reply structure and sizes. 174 | buf := make([]byte, MaxAddrLen) 175 | // read VER, NMETHODS, METHODS 176 | if _, err := io.ReadFull(rw, buf[:2]); err != nil { 177 | return nil, err 178 | } 179 | nmethods := buf[1] 180 | if _, err := io.ReadFull(rw, buf[:nmethods]); err != nil { 181 | return nil, err 182 | } 183 | // write VER METHOD 184 | if _, err := rw.Write([]byte{5, 0}); err != nil { 185 | return nil, err 186 | } 187 | // read VER CMD RSV ATYP DST.ADDR DST.PORT 188 | if _, err := io.ReadFull(rw, buf[:3]); err != nil { 189 | return nil, err 190 | } 191 | cmd := buf[1] 192 | addr, err := readAddr(rw, buf) 193 | if err != nil { 194 | return nil, err 195 | } 196 | switch cmd { 197 | case CmdConnect: 198 | _, err = rw.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0}) // SOCKS v5, reply succeeded 199 | case CmdUDPAssociate: 200 | if !UDPEnabled { 201 | return nil, ErrCommandNotSupported 202 | } 203 | listenAddr := ParseAddr(rw.(net.Conn).LocalAddr().String()) 204 | _, err = rw.Write(append([]byte{5, 0, 0}, listenAddr...)) // SOCKS v5, reply succeeded 205 | if err != nil { 206 | return nil, ErrCommandNotSupported 207 | } 208 | err = InfoUDPAssociate 209 | default: 210 | return nil, ErrCommandNotSupported 211 | } 212 | 213 | return addr, err // skip VER, CMD, RSV fields 214 | } 215 | -------------------------------------------------------------------------------- /ssSocksServer/tcp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/hashicorp/yamux" 7 | "io" 8 | "net" 9 | "os" 10 | "ssSocksServer/socks" 11 | "sync" 12 | "time" 13 | ) 14 | 15 | func Run(config Config, shadow func(net.Conn) net.Conn) { 16 | l, err := net.Listen("tcp", config.BindAddr) 17 | if err != nil { 18 | fmt.Println("[-] failed to listen on ", config.BindAddr) 19 | return 20 | } 21 | fmt.Println("[+] listening TCP on ", config.BindAddr) 22 | for { 23 | c, err := l.Accept() 24 | if err != nil { 25 | fmt.Println("[-] failed to accept", err) 26 | continue 27 | } 28 | fmt.Println("[+] received a client ", c.RemoteAddr()) 29 | go createTunnel(config, c, shadow, func(c net.Conn) (socks.Addr, error) { return socks.Handshake(c) }) 30 | } 31 | } 32 | 33 | func createTunnel(config Config, c net.Conn, shadow func(net.Conn) net.Conn, getAddr func(net.Conn) (socks.Addr, error)) { 34 | var session *yamux.Session 35 | session, err := yamux.Client(c, nil) 36 | if err != nil { 37 | fmt.Println("[-] error tcp.go") 38 | return 39 | } 40 | cratePort := *cratePort(config.Socks5Addr) 41 | go bot(config, cratePort.Addr().String(), c.RemoteAddr().String(), true) 42 | go func() { 43 | for { 44 | if session.IsClosed() { 45 | fmt.Println("[-] 连接已断开", cratePort.Addr(), c.RemoteAddr()) 46 | cratePort.Close() 47 | bot(config, cratePort.Addr().String(), c.RemoteAddr().String(), false) 48 | return 49 | } 50 | } 51 | }() 52 | for { 53 | if session.IsClosed() { 54 | return 55 | } 56 | myConn, _ := cratePort.Accept() 57 | go func() { 58 | stream, err := session.Open() 59 | if err != nil { 60 | return 61 | } 62 | tgt, err := getAddr(myConn) 63 | if err != nil { 64 | fmt.Println("[-] failed to open socksAddr ") 65 | return 66 | } 67 | stream = shadow(stream) 68 | if _, err = stream.Write(tgt); err != nil { 69 | return 70 | } 71 | 72 | fmt.Println("[*] proxy ", c.RemoteAddr(), " <-> <->", tgt) 73 | if err = relay(stream, myConn); err != nil { 74 | return 75 | } 76 | return 77 | }() 78 | } 79 | } 80 | func cratePort(socksAddr string) *net.Listener { 81 | attackerPort, err := net.Listen("tcp", socksAddr) 82 | if err != nil { 83 | for { 84 | fmt.Println("[-] "+socksAddr, "被占用") 85 | addr, err := net.ResolveTCPAddr("tcp", socksAddr) 86 | if err != nil { 87 | fmt.Println("Socks5Addr解析地址错误:") 88 | return nil 89 | } 90 | addr.Port++ 91 | socksAddr = addr.String() 92 | if !isValidIpPort(socksAddr) { 93 | return nil 94 | } 95 | attackerPort, err = net.Listen("tcp", socksAddr) 96 | if err == nil { 97 | break 98 | } 99 | } 100 | } 101 | fmt.Println("[+] socks5 address is ", socksAddr) 102 | return &attackerPort 103 | } 104 | func relay(left, right net.Conn) error { 105 | var err, err1 error 106 | var wg sync.WaitGroup 107 | var wait = 5 * time.Second 108 | wg.Add(1) 109 | go func() { 110 | defer wg.Done() 111 | _, err1 = io.Copy(right, left) 112 | right.SetReadDeadline(time.Now().Add(wait)) // unblock read on right 113 | }() 114 | _, err = io.Copy(left, right) 115 | left.SetReadDeadline(time.Now().Add(wait)) // unblock read on left 116 | wg.Wait() 117 | if err1 != nil && !errors.Is(err1, os.ErrDeadlineExceeded) { // requires Go 1.15+ 118 | return err1 119 | } 120 | if err != nil && !errors.Is(err, os.ErrDeadlineExceeded) { 121 | return err 122 | } 123 | return nil 124 | } 125 | --------------------------------------------------------------------------------