socks/socks4.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
}