93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
|
package socks5
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"io"
|
||
|
"net"
|
||
|
"strconv"
|
||
|
)
|
||
|
|
||
|
// NewEmptyAddrReply returns reply with empty address and port
|
||
|
func NewEmptyAddrReply(status ReplyStatus, atyp ATYP) *Reply {
|
||
|
if atyp == ATYPIPv6 {
|
||
|
return NewReply(status, ATYPIPv6, []byte(net.IPv6zero), []byte{0x00, 0x00})
|
||
|
}
|
||
|
|
||
|
return NewReply(status, ATYPIPv4, []byte{0x00, 0x00, 0x00, 0x00}, []byte{0x00, 0x00})
|
||
|
}
|
||
|
|
||
|
// ReadAddress reads address from reader
|
||
|
func ReadAddress(r io.Reader, atyp ATYP) ([]byte, error) {
|
||
|
var addr []byte
|
||
|
|
||
|
//nolint:exhaustive
|
||
|
switch atyp {
|
||
|
case ATYPIPv4:
|
||
|
addr = make([]byte, 4)
|
||
|
if _, err := io.ReadFull(r, addr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
case ATYPIPv6:
|
||
|
addr = make([]byte, 16)
|
||
|
if _, err := io.ReadFull(r, addr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
case ATYPFQDN:
|
||
|
domainLen := make([]byte, 1)
|
||
|
if _, err := io.ReadFull(r, domainLen); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if domainLen[0] == 0 {
|
||
|
return nil, ErrBadRequest
|
||
|
}
|
||
|
|
||
|
addr = make([]byte, int(domainLen[0]))
|
||
|
if _, err := io.ReadFull(r, addr); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
addr = append(domainLen, addr...) //nolint:makezero
|
||
|
default:
|
||
|
return nil, ErrBadRequest
|
||
|
}
|
||
|
|
||
|
return addr, nil
|
||
|
}
|
||
|
|
||
|
// ParseAddress parses address from string
|
||
|
func ParseAddress(address string) (ATYP, []byte, []byte, error) {
|
||
|
host, port, err := net.SplitHostPort(address)
|
||
|
if err != nil {
|
||
|
return 0x00, []byte{}, []byte{}, err
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
atyp ATYP
|
||
|
addr []byte
|
||
|
)
|
||
|
|
||
|
ip := net.ParseIP(host)
|
||
|
if ip4 := ip.To4(); ip4 != nil {
|
||
|
atyp = ATYPIPv4
|
||
|
addr = []byte(ip4)
|
||
|
} else if ip6 := ip.To16(); ip6 != nil {
|
||
|
atyp = ATYPIPv6
|
||
|
addr = []byte(ip6)
|
||
|
} else {
|
||
|
atyp = ATYPFQDN
|
||
|
addr = []byte{byte(len(host))}
|
||
|
addr = append(addr, []byte(host)...)
|
||
|
}
|
||
|
|
||
|
portInt, err := strconv.Atoi(port)
|
||
|
if err != nil {
|
||
|
return 0x00, []byte{}, []byte{}, err
|
||
|
}
|
||
|
|
||
|
portBytes := make([]byte, 2)
|
||
|
binary.BigEndian.PutUint16(portBytes, uint16(portInt))
|
||
|
|
||
|
return atyp, addr, portBytes, nil
|
||
|
}
|