├── 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 | 
9 | 
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 | 
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 |
--------------------------------------------------------------------------------