这里就主要介绍用户名、密码认证。 在客户端、服务端协商使用用户名密码认证后,客户端发出用户名密码:
| 鉴定协议版本 | 用户名长度 | 用户名 | 密码长度 | 密码 |
|---|---|---|---|---|
| 1 | 1 | 动态 | 1 | 动态 |
服务器鉴定后发出如下回应:
| 鉴定协议版本 | 鉴定状态 |
|---|---|
| 1 | 1 |
其中鉴定状态 0x00 表示成功,0x01 表示失败。
代码实现:
type Socks5Auth struct {
VER uint8
ULEN uint8
UNAME string
PLEN uint8
PASSWD string
}
func (s *Socks5Auth) authenticate(conn net.Conn) error {
b := make([]byte, 128)
n, err := conn.Read(b)
if err != nil{
log.Println(err)
return err
}
s.VER = b[0]
if s.VER != 5 {
return errors.New("该协议不是socks5协议")
}
s.ULEN = b[1]
s.UNAME = string(b[2:2+s.ULEN])
s.PLEN = b[2+s.ULEN+1]
s.PASSWD = string(b[n-int(s.PLEN):n])
log.Println(s.UNAME, s.PASSWD)
if username != s.UNAME || passwd != s.PASSWD {
return errors.New("账号密码错误")
}
/**
回应客户端,响应客户端连接成功
The server verifies the supplied UNAME and PASSWD, and sends the
following response:
+----+--------+
|VER | STATUS |
+----+--------+
| 1 | 1 |
+----+--------+
A STATUS field of X'00' indicates success. If the server returns a
`failure' (STATUS value other than X'00') status, it MUST close the
connection.
*/
resp := []byte{0x05, 0x00}
conn.Write(resp)
return nil
}
但其实,现在大家都习惯自己采用加密流的方式进行加密,很少采用用户名密码的形式进行加密,后面章节会介绍一种对SOCKS的混淆加密方式。
(3)请求信息
认证结束后客户端就可以发送请求信息。如果认证方法有特殊封装要求,请求必须按照方法所定义的方式进行封装解密,其原始格式如下:
| VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|---|---|---|---|---|---|
| 1 | 1 | 0x00 | 1 | 动态 | 2 |









