gost_software/socks5.go
2015-03-27 17:36:23 +08:00

288 lines
5.3 KiB
Go

package main
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
//"log"
"net"
)
const (
Ver5 = 5
)
const (
MethodNoAuth uint8 = iota
MethodGSSAPI
MethodUserPass
// X'03' to X'7F' IANA ASSIGNED
// X'80' to X'FE' RESERVED FOR PRIVATE METHODS
MethodNoAcceptable = 0xFF
)
const (
CmdConnect uint8 = 1
CmdBind = 2
CmdUdp = 3
)
const (
AddrIPv4 uint8 = 1
AddrDomain = 3
AddrIPv6 = 4
)
const (
Succeeded uint8 = iota
Failure
NotAllowed
NetUnreachable
HostUnreachable
ConnRefused
TTLExpired
CmdUnsupported
AddrUnsupported
)
var (
ErrBadVersion = errors.New("Bad version")
ErrBadFormat = errors.New("Bad format")
ErrBadAddrType = errors.New("Bad address type")
ErrShortBuffer = errors.New("Short buffer")
)
/*
+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
*/
type Cmd struct {
Cmd uint8
AddrType uint8
Addr string
Port uint16
}
func NewCmd(cmd uint8, atype uint8, addr string, port uint16) *Cmd {
if len(addr) == 0 {
addr = "0.0.0.0"
}
return &Cmd{
Cmd: cmd,
AddrType: atype,
Addr: addr,
Port: port,
}
}
func ReadCmd(r io.Reader) (*Cmd, error) {
b := make([]byte, 256)
n, err := r.Read(b)
//log.Println(b[:n])
if err != nil {
//log.Println(err)
return nil, err
}
if n < 10 {
return nil, ErrBadFormat
}
if b[0] != Ver5 {
return nil, ErrBadVersion
}
cmd := &Cmd{
Cmd: b[1],
AddrType: b[3],
}
pos := 4
switch cmd.AddrType {
case AddrIPv4:
if n != 10 {
return nil, ErrBadFormat
}
cmd.Addr = net.IP(b[pos : pos+net.IPv4len]).String()
pos += net.IPv4len
case AddrIPv6:
if n != 22 {
return nil, ErrBadFormat
}
cmd.Addr = net.IP(b[pos : pos+net.IPv6len]).String()
pos += net.IPv6len
case AddrDomain:
length := int(b[pos])
if n != 4+1+length+2 {
return nil, ErrBadFormat
}
pos++
cmd.Addr = string(b[pos : pos+length])
pos += length
default:
pos += 4
}
cmd.Port = binary.BigEndian.Uint16(b[pos:])
return cmd, nil
}
func (cmd *Cmd) Write(w io.Writer) (err error) {
b := make([]byte, 256)
b[0] = Ver5
b[1] = cmd.Cmd
b[3] = cmd.AddrType
pos := 4
switch cmd.AddrType {
case AddrIPv4:
pos += copy(b[pos:], net.ParseIP(cmd.Addr).To4())
case AddrDomain:
b[pos] = byte(len(cmd.Addr))
pos++
pos += copy(b[pos:], []byte(cmd.Addr))
case AddrIPv6:
pos += copy(b[pos:], net.ParseIP(cmd.Addr).To16())
}
binary.BigEndian.PutUint16(b[pos:], cmd.Port)
pos += 2
_, err = w.Write(b[:pos])
return
}
func (cmd *Cmd) String() string {
return fmt.Sprintf("5 %d 0 %d %s %d",
cmd.Cmd, cmd.AddrType, cmd.Addr, cmd.Port)
}
/*
+----+------+------+----------+----------+----------+
|RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA |
+----+------+------+----------+----------+----------+
| 2 | 1 | 1 | Variable | 2 | Variable |
+----+------+------+----------+----------+----------+
*/
type UdpPayload struct {
Rsv uint16
Frag uint8
AddrType uint8
Addr string
Port uint16
Data []byte
}
func NewUdpPayload(rsv uint16, atype uint8, addr string, port uint16, data []byte) *UdpPayload {
if len(addr) == 0 {
addr = "0.0.0.0"
}
return &UdpPayload{
Rsv: rsv,
AddrType: atype,
Addr: addr,
Port: port,
Data: data,
}
}
func ReadUdpPayload(r io.Reader) (*UdpPayload, error) {
buf := make([]byte, 65797)
n, err := io.ReadAtLeast(r, buf, 5)
//log.Println("r", buf[:n])
if err != nil {
return nil, err
}
up := &UdpPayload{
Rsv: binary.BigEndian.Uint16(buf[:2]),
Frag: buf[2],
AddrType: buf[3],
}
dataIndex := 0
switch up.AddrType {
case AddrIPv4:
dataIndex = 10
case AddrIPv6:
dataIndex = 22
case AddrDomain:
dataIndex = 7 + int(buf[4])
default:
return nil, ErrBadAddrType
}
dataLen := int(up.Rsv)
if n < dataIndex+dataLen {
if _, err := io.ReadFull(r, buf[n:dataIndex+dataLen]); err != nil {
return nil, err
}
}
pos := 4
switch up.AddrType {
case AddrIPv4:
up.Addr = net.IP(buf[pos : pos+net.IPv4len]).String()
pos += net.IPv4len
case AddrIPv6:
up.Addr = net.IP(buf[pos : pos+net.IPv6len]).String()
pos += net.IPv6len
case AddrDomain:
length := int(buf[pos])
pos++
up.Addr = string(buf[pos : pos+length])
pos += length
}
up.Port = binary.BigEndian.Uint16(buf[pos:])
//log.Println(up.Addr, up.Port)
if dataLen > 0 {
up.Data = buf[dataIndex : dataIndex+dataLen]
} else {
up.Data = buf[dataIndex:n]
}
return up, nil
}
func (up *UdpPayload) Write(w io.Writer) error {
buffer := &bytes.Buffer{}
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, up.Rsv)
buffer.Write(b)
buffer.WriteByte(up.Frag)
buffer.WriteByte(up.AddrType)
switch up.AddrType {
case AddrIPv4:
buffer.Write(net.ParseIP(up.Addr).To4())
case AddrDomain:
buffer.WriteByte(uint8(len(up.Addr)))
buffer.Write([]byte(up.Addr))
case AddrIPv6:
buffer.Write(net.ParseIP(up.Addr).To16())
}
binary.BigEndian.PutUint16(b, up.Port)
buffer.Write(b)
buffer.Write(up.Data)
_, err := w.Write(buffer.Bytes())
return err
}
func (up *UdpPayload) String() string {
return fmt.Sprintf("%d %d %d %s %d [%d]",
up.Rsv, up.Frag, up.AddrType, up.Addr, up.Port, len(up.Data))
}