forked from xjasonlyu/tun2socks
-
Notifications
You must be signed in to change notification settings - Fork 0
/
shadowsocks.go
121 lines (97 loc) · 2.65 KB
/
shadowsocks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package proxy
import (
"context"
"errors"
"fmt"
"net"
"github.com/Dreamacro/go-shadowsocks2/core"
"github.com/feng905/tun2socks/v2/dialer"
M "github.com/feng905/tun2socks/v2/metadata"
"github.com/feng905/tun2socks/v2/proxy/proto"
obfs "github.com/feng905/tun2socks/v2/transport/simple-obfs"
"github.com/feng905/tun2socks/v2/transport/socks5"
)
var _ Proxy = (*Shadowsocks)(nil)
type Shadowsocks struct {
*Base
cipher core.Cipher
// simple-obfs plugin
obfsMode, obfsHost string
}
func NewShadowsocks(addr, method, password, obfsMode, obfsHost string) (*Shadowsocks, error) {
cipher, err := core.PickCipher(method, nil, password)
if err != nil {
return nil, fmt.Errorf("ss initialize: %w", err)
}
return &Shadowsocks{
Base: &Base{
addr: addr,
proto: proto.Shadowsocks,
},
cipher: cipher,
obfsMode: obfsMode,
obfsHost: obfsHost,
}, nil
}
func (ss *Shadowsocks) DialContext(ctx context.Context, metadata *M.Metadata) (c net.Conn, err error) {
c, err = dialer.DialContext(ctx, "tcp", ss.Addr())
if err != nil {
return nil, fmt.Errorf("connect to %s: %w", ss.Addr(), err)
}
setKeepAlive(c)
defer safeConnClose(c, err)
switch ss.obfsMode {
case "tls":
c = obfs.NewTLSObfs(c, ss.obfsHost)
case "http":
_, port, _ := net.SplitHostPort(ss.addr)
c = obfs.NewHTTPObfs(c, ss.obfsHost, port)
}
c = ss.cipher.StreamConn(c)
_, err = c.Write(serializeSocksAddr(metadata))
return
}
func (ss *Shadowsocks) DialUDP(*M.Metadata) (net.PacketConn, error) {
pc, err := dialer.ListenPacket("udp", "")
if err != nil {
return nil, fmt.Errorf("listen packet: %w", err)
}
udpAddr, err := net.ResolveUDPAddr("udp", ss.Addr())
if err != nil {
return nil, fmt.Errorf("resolve udp address %s: %w", ss.Addr(), err)
}
pc = ss.cipher.PacketConn(pc)
return &ssPacketConn{PacketConn: pc, rAddr: udpAddr}, nil
}
type ssPacketConn struct {
net.PacketConn
rAddr net.Addr
}
func (pc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
var packet []byte
if ma, ok := addr.(*M.Addr); ok {
packet, err = socks5.EncodeUDPPacket(serializeSocksAddr(ma.Metadata()), b)
} else {
packet, err = socks5.EncodeUDPPacket(socks5.ParseAddr(addr), b)
}
if err != nil {
return
}
return pc.PacketConn.WriteTo(packet[3:], pc.rAddr)
}
func (pc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
n, _, err := pc.PacketConn.ReadFrom(b)
if err != nil {
return 0, nil, err
}
addr := socks5.SplitAddr(b[:n])
if addr == nil {
return 0, nil, errors.New("parse addr error")
}
udpAddr := addr.UDPAddr()
if udpAddr == nil {
return 0, nil, errors.New("parse addr error")
}
copy(b, b[len(addr):])
return n - len(addr), udpAddr, err
}