sing/protocol/socks/handshake.go
2022-01-29 03:25:38 +08:00

106 lines
2.5 KiB
Go

package socks
import (
"io"
"sing/common"
"sing/common/exceptions"
"sing/common/socksaddr"
)
func ClientHandshake(conn io.ReadWriter, version byte, command byte, addr socksaddr.Addr, port uint16, username string, password string) (*Response, error) {
var method byte
if common.IsBlank(username) {
method = AuthTypeNotRequired
} else {
method = AuthTypeUsernamePassword
}
err := WriteAuthRequest(conn, &AuthRequest{
Version: version,
Methods: []byte{method},
})
if err != nil {
return nil, err
}
authResponse, err := ReadAuthResponse(conn)
if err != nil {
return nil, err
}
if authResponse.Method != method {
return nil, exceptions.New("not requested method, request ", method, ", return ", method)
}
if method == AuthTypeUsernamePassword {
err = WriteUsernamePasswordAuthRequest(conn, &UsernamePasswordAuthRequest{
Username: username,
Password: password,
})
if err != nil {
return nil, err
}
usernamePasswordResponse, err := ReadUsernamePasswordAuthResponse(conn)
if err != nil {
return nil, err
}
if usernamePasswordResponse.Status == UsernamePasswordStatusFailure {
return nil, &UsernamePasswordAuthFailureException{}
}
}
err = WriteRequest(conn, &Request{
Version: version,
Command: command,
Addr: addr,
Port: port,
})
if err != nil {
return nil, err
}
return ReadResponse(conn)
}
func ClientFastHandshake(writer io.Writer, version byte, command byte, addr socksaddr.Addr, port uint16, username string, password string) error {
var method byte
if common.IsBlank(username) {
method = AuthTypeNotRequired
} else {
method = AuthTypeUsernamePassword
}
err := WriteAuthRequest(writer, &AuthRequest{
Version: version,
Methods: []byte{method},
})
if err != nil {
return err
}
if method == AuthTypeUsernamePassword {
err = WriteUsernamePasswordAuthRequest(writer, &UsernamePasswordAuthRequest{
Username: username,
Password: password,
})
if err != nil {
return err
}
}
return WriteRequest(writer, &Request{
Version: version,
Command: command,
Addr: addr,
Port: port,
})
}
func ClientFastHandshakeFinish(reader io.Reader) (*Response, error) {
response, err := ReadAuthResponse(reader)
if err != nil {
return nil, err
}
if response.Method == AuthTypeUsernamePassword {
usernamePasswordResponse, err := ReadUsernamePasswordAuthResponse(reader)
if err != nil {
return nil, err
}
if usernamePasswordResponse.Status == UsernamePasswordStatusFailure {
return nil, &UsernamePasswordAuthFailureException{}
}
}
return ReadResponse(reader)
}