go-socks5/header.go
mo 32060b0332 fix head bug
add udp experimental handle
2020-04-20 12:39:01 +08:00

122 lines
2.7 KiB
Go

package socks5
import (
"fmt"
"net"
"strconv"
)
const (
// protocol version
socks4Version = uint8(4)
socks5Version = uint8(5)
// request command
ConnectCommand = uint8(1)
BindCommand = uint8(2)
AssociateCommand = uint8(3) // udp associate
// address type
ipv4Address = uint8(1)
fqdnAddress = uint8(3) // domain
ipv6Address = uint8(4)
)
//
const (
successReply uint8 = iota
serverFailure
ruleFailure
networkUnreachable
hostUnreachable
connectionRefused
ttlExpired
commandNotSupported
addrTypeNotSupported
// 0x09 - 0xff unassigned
)
// head len defined
const (
// common fields
reqProtocolVersionBytePos = uint8(0) // proto version pos
reqCommandBytePos = uint8(1)
reqAddrBytePos = uint8(4)
reqStartLen = uint8(4)
headVERLen = 1
headCMDLen = 1
headRSVLen = 1
headATYPLen = 1
headPORTLen = 2
headFQDNAddrLen = 1
reqFQDNAddr = 249
)
// AddrSpec is used to return the target AddrSpec
// which may be specified as IPv4, IPv6, or a FQDN
type AddrSpec struct {
FQDN string
IP net.IP
Port int
}
func (a *AddrSpec) String() string {
if a.FQDN != "" {
return fmt.Sprintf("%s (%s):%d", a.FQDN, a.IP, a.Port)
}
return fmt.Sprintf("%s:%d", a.IP, a.Port)
}
// Address returns a string suitable to dial; prefer returning IP-based
// address, fallback to FQDN
func (a AddrSpec) Address() string {
if 0 != len(a.IP) {
return net.JoinHostPort(a.IP.String(), strconv.Itoa(a.Port))
}
return net.JoinHostPort(a.FQDN, strconv.Itoa(a.Port))
}
// Header represents the SOCKS5/SOCKS4 header, it contains everything that is not payload
type Header struct {
// Version of socks protocol for message
Version uint8
// Socks Command "connect","bind","associate"
Command uint8
// Reserved byte
Reserved uint8 // only socks5 support
// Address in socks message
Address AddrSpec
// private stuff set when Header parsed
addrType uint8
}
func (h Header) Bytes() (b []byte) {
b = append(b, h.Version)
b = append(b, h.Command)
hiPort, loPort := breakPort(h.Address.Port)
if h.Version == socks4Version {
b = append(b, hiPort, loPort)
b = append(b, h.Address.IP...)
} else if h.Version == socks5Version {
b = append(b, h.Reserved)
b = append(b, h.addrType)
if h.addrType == fqdnAddress {
b = append(b, byte(len(h.Address.FQDN)))
b = append(b, []byte(h.Address.FQDN)...)
} else if h.addrType == ipv4Address {
b = append(b, h.Address.IP.To4()...)
} else if h.addrType == ipv6Address {
b = append(b, h.Address.IP.To16()...)
}
b = append(b, hiPort, loPort)
}
return b
}
func buildPort(hi, lo byte) int {
return (int(hi) << 8) | int(lo)
}
func breakPort(port int) (hi, lo byte) {
return byte(port >> 8), byte(port)
}