65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
package socks
|
|
|
|
import (
|
|
"errors"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
func (cfg *config) dialSocks4(targetAddr string) (_ net.Conn, err error) {
|
|
socksType := cfg.Proto
|
|
|
|
conn, err := cfg.internalDial()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// connection request
|
|
host, port, err := splitHostPort(targetAddr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ip := net.IPv4(0, 0, 0, 1).To4()
|
|
if socksType == SOCKS4 {
|
|
ip, err = lookupIPv4(host)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
req := []byte{
|
|
4, // version number
|
|
1, // command CONNECT
|
|
byte(port >> 8), // higher byte of destination port
|
|
byte(port), // lower byte of destination port (big endian)
|
|
ip[0], ip[1], ip[2], ip[3], // special invalid IP address to indicate the host name is provided
|
|
0, // user id is empty, anonymous proxy only
|
|
}
|
|
if socksType == SOCKS4A {
|
|
req = append(req, []byte(host+"\x00")...)
|
|
}
|
|
|
|
resp, err := cfg.sendReceive(conn, req)
|
|
if err != nil {
|
|
return nil, err
|
|
} else if len(resp) != 8 {
|
|
return nil, errors.New("server does not respond properly")
|
|
}
|
|
switch resp[1] {
|
|
case 90:
|
|
// request granted
|
|
case 91:
|
|
return nil, errors.New("socks connection request rejected or failed")
|
|
case 92:
|
|
return nil, errors.New("socks connection request rejected because SOCKS server cannot connect to identd on the client")
|
|
case 93:
|
|
return nil, errors.New("socks connection request rejected because the client program and identd report different user-ids")
|
|
default:
|
|
return nil, errors.New("socks connection request failed, unknown error")
|
|
}
|
|
// clear the deadline before returning
|
|
if err := conn.SetDeadline(time.Time{}); err != nil {
|
|
return nil, err
|
|
}
|
|
return conn, nil
|
|
}
|