forked from shadowsocks/shadowsocks-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconn.go
128 lines (113 loc) · 2.72 KB
/
conn.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
122
123
124
125
126
127
128
package shadowsocks
import (
"encoding/binary"
"fmt"
"io"
"net"
"strconv"
)
type Conn struct {
net.Conn
*Cipher
readBuf []byte
writeBuf []byte
}
func NewConn(c net.Conn, cipher *Cipher) *Conn {
return &Conn{
Conn: c,
Cipher: cipher,
readBuf: leakyBuf.Get(),
writeBuf: leakyBuf.Get()}
}
func (c *Conn) Close() error {
leakyBuf.Put(c.readBuf)
leakyBuf.Put(c.writeBuf)
return c.Conn.Close()
}
func RawAddr(addr string) (buf []byte, err error) {
host, portStr, err := net.SplitHostPort(addr)
if err != nil {
return nil, fmt.Errorf("shadowsocks: address error %s %v", addr, err)
}
port, err := strconv.Atoi(portStr)
if err != nil {
return nil, fmt.Errorf("shadowsocks: invalid port %s", addr)
}
hostLen := len(host)
l := 1 + 1 + hostLen + 2 // addrType + lenByte + address + port
buf = make([]byte, l)
buf[0] = 3 // 3 means the address is domain name
buf[1] = byte(hostLen) // host address length followed by host address
copy(buf[2:], host)
binary.BigEndian.PutUint16(buf[2+hostLen:2+hostLen+2], uint16(port))
return
}
// This is intended for use by users implementing a local socks proxy.
// rawaddr shoud contain part of the data in socks request, starting from the
// ATYP field. (Refer to rfc1928 for more information.)
func DialWithRawAddr(rawaddr []byte, server string, cipher *Cipher) (c *Conn, err error) {
conn, err := net.Dial("tcp", server)
if err != nil {
return
}
c = NewConn(conn, cipher)
if _, err = c.Write(rawaddr); err != nil {
c.Close()
return nil, err
}
return
}
// addr should be in the form of host:port
func Dial(addr, server string, cipher *Cipher) (c *Conn, err error) {
ra, err := RawAddr(addr)
if err != nil {
return
}
return DialWithRawAddr(ra, server, cipher)
}
func (c *Conn) Read(b []byte) (n int, err error) {
if c.dec == nil {
iv := make([]byte, c.info.ivLen)
if _, err = io.ReadFull(c.Conn, iv); err != nil {
return
}
if err = c.initDecrypt(iv); err != nil {
return
}
}
cipherData := c.readBuf
if len(b) > len(cipherData) {
cipherData = make([]byte, len(b))
} else {
cipherData = cipherData[:len(b)]
}
n, err = c.Conn.Read(cipherData)
if n > 0 {
c.decrypt(b[0:n], cipherData[0:n])
}
return
}
func (c *Conn) Write(b []byte) (n int, err error) {
var iv []byte
if c.enc == nil {
iv, err = c.initEncrypt()
if err != nil {
return
}
}
cipherData := c.writeBuf
dataSize := len(b) + len(iv)
if dataSize > len(cipherData) {
cipherData = make([]byte, dataSize)
} else {
cipherData = cipherData[:dataSize]
}
if iv != nil {
// Put initialization vector in buffer, do a single write to send both
// iv and data.
copy(cipherData, iv)
}
c.encrypt(cipherData[len(iv):], b)
n, err = c.Conn.Write(cipherData)
return
}