fangdingjun 8 years ago
commit 14c964c1c2

@ -1,6 +1,7 @@
package socks
import (
"errors"
"fmt"
"io"
"log"
@ -24,6 +25,16 @@ byte | 0 | 1 |
|0x05| auth|
username/password auth request
byte | 0 | 1 | | 1 byte | |
|0x01|username_len| username | password_len | password |
username/password auth reponse
byte | 0 | 1 |
|0x01|status|
request
byte | 0 | 1 | 2 | 3 | 4 | .. | n-2 | n-1| n |
@ -34,6 +45,9 @@ byte |0 | 1 | 2 | 3 | 4 | .. | n-2 | n-1 | n |
|0x05|status|0x00|addrtype| addr | port |
*/
var Socks5AuthRequired bool
type socks5Conn struct {
//addr string
clientConn net.Conn
@ -70,14 +84,93 @@ func (s5 *socks5Conn) handshake() error {
l := int(buf[0]) + 1
if n < l {
// read remains data
_, err := io.ReadFull(s5.clientConn, buf[n:l])
if n1, err := io.ReadFull(s5.clientConn, buf[n:l]); err != nil {
return err
} else {
n += n1
}
}
if !Socks5AuthRequired {
// no auth required
s5.clientConn.Write([]byte{0x05, 0x00})
return nil
}
hasPassAuth := false
var passAuth byte = 0x02
// check auth method
// only password(0x02) supported
for i := 1; i < n; i++ {
if buf[i] == passAuth {
hasPassAuth = true
break
}
}
if !hasPassAuth {
s5.clientConn.Write([]byte{0x05, 0xff})
return errors.New("no supported auth method")
}
err = s5.passwordAuth()
return err
}
func (s5 *socks5Conn) passwordAuth() error {
buf := make([]byte, 32)
// username/password required
s5.clientConn.Write([]byte{0x05, 0x02})
n, err := io.ReadAtLeast(s5.clientConn, buf, 2)
if err != nil {
return err
}
//log.Printf("%+v", buf[:n])
// check auth version
if buf[0] != 0x01 {
return errors.New("unsupported auth version")
}
username_len := int(buf[1])
p0 := 2
p1 := p0 + username_len
if n < p1 {
n1, err := s5.clientConn.Read(buf[n:])
if err != nil {
return err
}
n += n1
}
username := buf[p0:p1]
password_len := int(buf[p1])
p3 := p1 + 1
p4 := p3 + password_len
if n < p4 {
n1, err := s5.clientConn.Read(buf[n:])
if err != nil {
return err
}
n += n1
}
// no auth required
s5.clientConn.Write([]byte{0x05, 0x00})
password := buf[p3:p4]
log.Printf("get username: %s, password: %s", username, password)
if string(username) == "" && string(password) == "" {
s5.clientConn.Write([]byte{0x01, 0x01})
} else {
s5.clientConn.Write([]byte{0x01, 0x00})
}
return nil
}

Loading…
Cancel
Save