goproxy/utils/socks/structs.go
arraykeys@gmail.com 89be79b6c6 merge enterprise
2018-09-04 15:59:57 +08:00

357 lines
8.0 KiB
Go

package socks
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
"net"
"strconv"
)
type Request struct {
ver uint8
cmd uint8
reserve uint8
addressType uint8
dstAddr string
dstPort string
dstHost string
bytes []byte
rw io.ReadWriter
}
func NewRequest(rw io.ReadWriter, header ...[]byte) (req Request, err interface{}) {
var b = make([]byte, 1024)
var n int
req = Request{rw: rw}
if header != nil && len(header) == 1 && len(header[0]) > 1 {
b = header[0]
n = len(header[0])
} else {
n, err = rw.Read(b[:])
if err != nil {
err = fmt.Errorf("read req data fail,ERR: %s", err)
return
}
}
req.ver = uint8(b[0])
req.cmd = uint8(b[1])
req.reserve = uint8(b[2])
req.addressType = uint8(b[3])
if b[0] != 0x5 {
err = fmt.Errorf("sosck version supported")
req.TCPReply(REP_REQ_FAIL)
return
}
switch b[3] {
case 0x01: //IP V4
req.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
case 0x03: //域名
req.dstHost = string(b[5 : n-2]) //b[4]表示域名的长度
case 0x04: //IP V6
req.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
}
req.dstPort = strconv.Itoa(int(b[n-2])<<8 | int(b[n-1]))
req.dstAddr = net.JoinHostPort(req.dstHost, req.dstPort)
req.bytes = b[:n]
return
}
func (s *Request) Bytes() []byte {
return s.bytes
}
func (s *Request) Addr() string {
return s.dstAddr
}
func (s *Request) Host() string {
return s.dstHost
}
func (s *Request) Port() string {
return s.dstPort
}
func (s *Request) AType() uint8 {
return s.addressType
}
func (s *Request) CMD() uint8 {
return s.cmd
}
func (s *Request) TCPReply(rep uint8) (err error) {
_, err = s.rw.Write(s.NewReply(rep, "0.0.0.0:0"))
return
}
func (s *Request) UDPReply(rep uint8, addr string) (err error) {
_, err = s.rw.Write(s.NewReply(rep, addr))
return
}
func (s *Request) NewReply(rep uint8, addr string) []byte {
var response bytes.Buffer
host, port, _ := net.SplitHostPort(addr)
ip := net.ParseIP(host)
ipb := ip.To4()
atyp := ATYP_IPV4
ipv6 := ip.To16()
zeroiIPv6 := fmt.Sprintf("%d%d%d%d%d%d%d%d%d%d%d%d",
ipv6[0], ipv6[1], ipv6[2], ipv6[3],
ipv6[4], ipv6[5], ipv6[6], ipv6[7],
ipv6[8], ipv6[9], ipv6[10], ipv6[11],
)
if ipb == nil && ipv6 != nil && "0000000000255255" != zeroiIPv6 {
atyp = ATYP_IPV6
ipb = ip.To16()
}
porti, _ := strconv.Atoi(port)
portb := make([]byte, 2)
binary.BigEndian.PutUint16(portb, uint16(porti))
// log.Printf("atyp : %v", atyp)
// log.Printf("ip : %v", []byte(ip))
response.WriteByte(VERSION_V5)
response.WriteByte(rep)
response.WriteByte(RSV)
response.WriteByte(atyp)
response.Write(ipb)
response.Write(portb)
return response.Bytes()
}
type MethodsRequest struct {
ver uint8
methodsCount uint8
methods []uint8
bytes []byte
rw *io.ReadWriter
}
func NewMethodsRequest(r io.ReadWriter, header ...[]byte) (s MethodsRequest, err interface{}) {
defer func() {
if err == nil {
err = recover()
}
}()
s = MethodsRequest{}
s.rw = &r
var buf = make([]byte, 300)
var n int
if header != nil && len(header) == 1 && len(header[0]) > 1 {
buf = header[0]
n = len(header[0])
} else {
n, err = r.Read(buf)
if err != nil {
return
}
}
if buf[0] != 0x05 {
err = fmt.Errorf("socks version not supported")
return
}
if n != int(buf[1])+int(2) {
err = fmt.Errorf("socks methods data length error")
return
}
s.ver = buf[0]
s.methodsCount = buf[1]
s.methods = buf[2:n]
s.bytes = buf[:n]
return
}
func (s *MethodsRequest) Version() uint8 {
return s.ver
}
func (s *MethodsRequest) MethodsCount() uint8 {
return s.methodsCount
}
func (s *MethodsRequest) Methods() []uint8 {
return s.methods
}
func (s *MethodsRequest) Select(method uint8) bool {
for _, m := range s.methods {
if m == method {
return true
}
}
return false
}
func (s *MethodsRequest) Reply(method uint8) (err error) {
_, err = (*s.rw).Write([]byte{byte(VERSION_V5), byte(method)})
return
}
func (s *MethodsRequest) Bytes() []byte {
return s.bytes
}
func ParseUDPPacket(b []byte) (p UDPPacket, err error) {
p = UDPPacket{}
p.frag = uint8(b[2])
p.bytes = b
if p.frag != 0 {
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
return
}
portIndex := 0
p.atype = b[3]
switch p.atype {
case ATYP_IPV4: //IP V4
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
portIndex = 8
case ATYP_DOMAIN: //域名
domainLen := uint8(b[4])
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
portIndex = int(5 + domainLen)
case ATYP_IPV6: //IP V6
p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
portIndex = 20
}
p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
p.data = b[portIndex+2:]
p.header = b[:portIndex+2]
return
}
type UDPPacket struct {
rsv uint16
frag uint8
atype uint8
dstHost string
dstPort string
data []byte
header []byte
bytes []byte
}
func (s *UDPPacket) Header() []byte {
return s.header
}
func (s *UDPPacket) NewReply(data []byte) []byte {
var buf bytes.Buffer
buf.Write(s.header)
buf.Write(data)
return buf.Bytes()
}
func (s *UDPPacket) Host() string {
return s.dstHost
}
func (s *UDPPacket) Port() string {
return s.dstPort
}
func (s *UDPPacket) Data() []byte {
return s.data
}
type PacketUDP struct {
rsv uint16
frag uint8
atype uint8
dstHost string
dstPort string
data []byte
}
func NewPacketUDP() (p PacketUDP) {
return PacketUDP{}
}
func (p *PacketUDP) Build(destAddr string, data []byte) (err error) {
host, port, err := net.SplitHostPort(destAddr)
if err != nil {
return
}
p.rsv = 0
p.frag = 0
p.dstHost = host
p.dstPort = port
p.atype = ATYP_IPV4
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
p.atype = ATYP_IPV4
ip = ip4
} else {
p.atype = ATYP_IPV6
}
} else {
if len(host) > 255 {
err = errors.New("proxy: destination host name too long: " + host)
return
}
p.atype = ATYP_DOMAIN
}
p.data = data
return
}
func (p *PacketUDP) Parse(b []byte) (err error) {
if len(b) < 9 {
return fmt.Errorf("too short packet")
}
p.frag = uint8(b[2])
if p.frag != 0 {
err = fmt.Errorf("FRAG only support for 0 , %v ,%v", p.frag, b[:4])
return
}
portIndex := 0
p.atype = b[3]
switch p.atype {
case ATYP_IPV4: //IP V4
if len(b) < 11 {
return fmt.Errorf("too short packet")
}
p.dstHost = net.IPv4(b[4], b[5], b[6], b[7]).String()
portIndex = 8
case ATYP_DOMAIN: //域名
domainLen := uint8(b[4])
if len(b) < int(domainLen)+7 {
return fmt.Errorf("too short packet")
}
p.dstHost = string(b[5 : 5+domainLen]) //b[4]表示域名的长度
portIndex = int(5 + domainLen)
case ATYP_IPV6: //IP V6
if len(b) < 22 {
return fmt.Errorf("too short packet")
}
p.dstHost = net.IP{b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15], b[16], b[17], b[18], b[19]}.String()
portIndex = 20
}
p.dstPort = strconv.Itoa(int(b[portIndex])<<8 | int(b[portIndex+1]))
p.data = b[portIndex+2:]
return
}
func (p *PacketUDP) Header() []byte {
header := new(bytes.Buffer)
header.Write([]byte{0x00, 0x00, p.frag, p.atype})
if p.atype == ATYP_IPV4 {
ip := net.ParseIP(p.dstHost)
header.Write(ip.To4())
} else if p.atype == ATYP_IPV6 {
ip := net.ParseIP(p.dstHost)
header.Write(ip.To16())
} else if p.atype == ATYP_DOMAIN {
hBytes := []byte(p.dstHost)
header.WriteByte(byte(len(hBytes)))
header.Write(hBytes)
}
port, _ := strconv.ParseUint(p.dstPort, 10, 64)
portBytes := new(bytes.Buffer)
binary.Write(portBytes, binary.BigEndian, port)
header.Write(portBytes.Bytes()[portBytes.Len()-2:])
return header.Bytes()
}
func (p *PacketUDP) Bytes() []byte {
packBytes := new(bytes.Buffer)
packBytes.Write(p.Header())
packBytes.Write(p.data)
return packBytes.Bytes()
}
func (p *PacketUDP) Host() string {
return p.dstHost
}
func (p *PacketUDP) Addr() string {
return net.JoinHostPort(p.dstHost, p.dstPort)
}
func (p *PacketUDP) Port() string {
return p.dstPort
}
func (p *PacketUDP) Data() []byte {
return p.data
}