summaryrefslogtreecommitdiff
path: root/common/socks5/socks5.go
diff options
context:
space:
mode:
Diffstat (limited to 'common/socks5/socks5.go')
-rw-r--r--common/socks5/socks5.go39
1 files changed, 29 insertions, 10 deletions
diff --git a/common/socks5/socks5.go b/common/socks5/socks5.go
index 42b19eb..74e1175 100644
--- a/common/socks5/socks5.go
+++ b/common/socks5/socks5.go
@@ -40,6 +40,7 @@ package socks5
import (
"bufio"
"bytes"
+ "encoding/binary"
"fmt"
"io"
"net"
@@ -61,6 +62,7 @@ const (
authNoneRequired = 0x00
authUsernamePassword = 0x02
+ authPT2PrivateMethod = 0x80
authNoAcceptableMethods = 0xff
requestTimeout = 5 * time.Second
@@ -124,7 +126,7 @@ type Request struct {
// Handshake attempts to handle a incoming client handshake over the provided
// connection and receive the SOCKS5 request. The routine handles sending
// appropriate errors if applicable, but will not close the connection.
-func Handshake(conn net.Conn) (*Request, error) {
+func Handshake(conn net.Conn, needOptions bool) (*Request, error) {
// Arm the handshake timeout.
var err error
if err = conn.SetDeadline(time.Now().Add(requestTimeout)); err != nil {
@@ -144,7 +146,7 @@ func Handshake(conn net.Conn) (*Request, error) {
// Negotiate the protocol version and authentication method.
var method byte
- if method, err = req.negotiateAuth(); err != nil {
+ if method, err = req.negotiateAuth(needOptions); err != nil {
return nil, err
}
@@ -186,7 +188,7 @@ func (req *Request) Reply(code ReplyCode) error {
return req.flushBuffers()
}
-func (req *Request) negotiateAuth() (byte, error) {
+func (req *Request) negotiateAuth(needOptions bool) (byte, error) {
// The client sends a version identifier/selection message.
// uint8_t ver (0x05)
// uint8_t nmethods (>= 1).
@@ -209,11 +211,19 @@ func (req *Request) negotiateAuth() (byte, error) {
}
// Pick the best authentication method, prioritizing authenticating
- // over not if both options are present.
- if bytes.IndexByte(methods, authUsernamePassword) != -1 {
- method = authUsernamePassword
- } else if bytes.IndexByte(methods, authNoneRequired) != -1 {
- method = authNoneRequired
+ // over not if both options are present and SOCKS header options are needed.
+ if needOptions {
+ if bytes.IndexByte(methods, authPT2PrivateMethod) != -1 {
+ method = authPT2PrivateMethod
+ } else if bytes.IndexByte(methods, authNoneRequired) != -1 {
+ method = authNoneRequired
+ }
+ } else {
+ if bytes.IndexByte(methods, authNoneRequired) != -1 {
+ method = authNoneRequired
+ } else if bytes.IndexByte(methods, authPT2PrivateMethod) != -1 {
+ method = authPT2PrivateMethod
+ }
}
// The server sends a method selection message.
@@ -231,8 +241,8 @@ func (req *Request) authenticate(method byte) error {
switch method {
case authNoneRequired:
// No authentication required.
- case authUsernamePassword:
- if err := req.authRFC1929(); err != nil {
+ case authPT2PrivateMethod:
+ if err := req.authPT2(); err != nil {
return err
}
case authNoAcceptableMethods:
@@ -349,6 +359,15 @@ func (req *Request) readByteVerify(descr string, expected byte) error {
return nil
}
+func (req *Request) readUint32() (uint32, error) {
+ buffer, err := req.readBytes(4)
+ if err != nil {
+ return 0, err
+ }
+
+ return binary.BigEndian.Uint32(buffer), nil
+}
+
func (req *Request) readBytes(n int) ([]byte, error) {
b := make([]byte, n)
if _, err := io.ReadFull(req.rw, b); err != nil {