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 }