Skip to content

Commit 3334af5

Browse files
authored
Merge pull request #52 from damoye/master
More robust SOCKS handshaking.
2 parents 4ad831b + 1df584a commit 3334af5

File tree

1 file changed

+28
-22
lines changed

1 file changed

+28
-22
lines changed

socks/socks.go

+28-22
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,6 @@ const (
4343
// MaxAddrLen is the maximum size of SOCKS address in bytes.
4444
const MaxAddrLen = 1 + 1 + 255 + 2
4545

46-
// MaxReqLen is the maximum size of SOCKS request in bytes.
47-
const MaxReqLen = 1 + 1 + 1 + MaxAddrLen
48-
4946
// Addr represents a SOCKS address as defined in RFC 1928 section 5.
5047
type Addr []byte
5148

@@ -68,9 +65,10 @@ func (a Addr) String() string {
6865
return net.JoinHostPort(host, port)
6966
}
7067

71-
// ReadAddr reads just enough bytes from r to get a valid Addr.
72-
func ReadAddr(r io.Reader) (Addr, error) {
73-
b := make([]byte, MaxAddrLen)
68+
func readAddr(r io.Reader, b []byte) (Addr, error) {
69+
if len(b) < MaxAddrLen {
70+
return nil, io.ErrShortBuffer
71+
}
7472
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
7573
if err != nil {
7674
return nil, err
@@ -95,6 +93,11 @@ func ReadAddr(r io.Reader) (Addr, error) {
9593
return nil, ErrAddressNotSupported
9694
}
9795

96+
// ReadAddr reads just enough bytes from r to get a valid Addr.
97+
func ReadAddr(r io.Reader) (Addr, error) {
98+
return readAddr(r, make([]byte, MaxAddrLen))
99+
}
100+
98101
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
99102
func SplitAddr(b []byte) Addr {
100103
addrLen := 1
@@ -163,29 +166,32 @@ func ParseAddr(s string) Addr {
163166

164167
// Handshake fast-tracks SOCKS initialization to get target address to connect.
165168
func Handshake(rw io.ReadWriter) (Addr, error) {
166-
// Read RFC 1928 section 4 for request and reply structure and sizes
167-
buf := make([]byte, MaxReqLen)
168-
169-
_, err := rw.Read(buf) // SOCKS version and auth methods
170-
if err != nil {
169+
// Read RFC 1928 for request and reply structure and sizes.
170+
buf := make([]byte, MaxAddrLen)
171+
// read VER, NMETHODS, METHODS
172+
if _, err := io.ReadFull(rw, buf[:2]); err != nil {
171173
return nil, err
172174
}
173-
174-
_, err = rw.Write([]byte{5, 0}) // SOCKS v5, no auth required
175-
if err != nil {
175+
nmethods := buf[1]
176+
if _, err := io.ReadFull(rw, buf[:nmethods]); err != nil {
176177
return nil, err
177178
}
178-
179-
n, err := rw.Read(buf) // SOCKS request: VER, CMD, RSV, Addr
180-
if err != nil {
179+
// write VER METHOD
180+
if _, err := rw.Write([]byte{5, 0}); err != nil {
181+
return nil, err
182+
}
183+
// read VER CMD RSV ATYP DST.ADDR DST.PORT
184+
if _, err := io.ReadFull(rw, buf[:3]); err != nil {
181185
return nil, err
182186
}
183-
buf = buf[:n]
184-
185187
if buf[1] != CmdConnect {
186188
return nil, ErrCommandNotSupported
187189
}
188-
189-
_, err = rw.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0}) // SOCKS v5, reply succeeded
190-
return buf[3:], err // skip VER, CMD, RSV fields
190+
addr, err := readAddr(rw, buf)
191+
if err != nil {
192+
return nil, err
193+
}
194+
// write VER REP RSV ATYP BND.ADDR BND.PORT
195+
_, err = rw.Write([]byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0})
196+
return addr, err
191197
}

0 commit comments

Comments
 (0)