152 lines
3.3 KiB
Go
152 lines
3.3 KiB
Go
package socket5
|
|
|
|
import (
|
|
"io"
|
|
"net"
|
|
)
|
|
|
|
type ClientRequestMessage struct {
|
|
CMD Command
|
|
Address string
|
|
Port uint16
|
|
AddressType Command
|
|
}
|
|
|
|
type Command = byte
|
|
|
|
const (
|
|
IPV4_LENGHT = 4
|
|
IPV6_LENGHT = 6
|
|
PORT_LENGHT = 2
|
|
)
|
|
|
|
const (
|
|
CmdConnect Command = 0x01
|
|
CmdBind Command = 0x02
|
|
CmdUDP Command = 0x03
|
|
)
|
|
|
|
type AddressType = byte
|
|
|
|
const (
|
|
TypeIPV4 AddressType = 0x01
|
|
TypeDoMain AddressType = 0x03
|
|
TypeIPV6 AddressType = 0x04
|
|
)
|
|
|
|
func NewClientRequestMessage(conn net.Conn) (*ClientRequestMessage, error) {
|
|
// 版本 命令 reseved 地址类型
|
|
buf := make([]byte, 4)
|
|
if _, err := io.ReadFull(conn, buf); err != nil {
|
|
return nil, err
|
|
}
|
|
version, command, reserved, addType := buf[0], buf[1], buf[2], buf[3]
|
|
if version != SOCKET_5_VERSION {
|
|
return nil, ERROR_SOCKET_VERSION_SUPPORTED
|
|
}
|
|
|
|
if command != CmdConnect && command != CmdBind && command != CmdUDP {
|
|
return nil, ERROR_COMMAND_NOT_SUPPORTED
|
|
}
|
|
|
|
if reserved != ReservedFild {
|
|
return nil, ERROR_SOCKET_VERSION_SUPPORTED
|
|
}
|
|
|
|
if addType == TypeIPV4 || addType == TypeDoMain {
|
|
var message ClientRequestMessage
|
|
message.CMD = command
|
|
message.AddressType = addType
|
|
|
|
//fmt.Printf("请求地址类型为:%v\n", addType)
|
|
|
|
switch addType {
|
|
|
|
case TypeIPV6:
|
|
buf = make([]byte, IPV6_LENGHT)
|
|
if _, err := io.ReadFull(conn, buf); err != nil {
|
|
return nil, err
|
|
}
|
|
ip := net.ParseIP(string(buf))
|
|
message.Address = ip.String()
|
|
//fmt.Println("TypeIPV6 地址为:" + ip.String())
|
|
case TypeIPV4:
|
|
buf = make([]byte, IPV4_LENGHT)
|
|
if _, err := io.ReadFull(conn, buf); err != nil {
|
|
return nil, err
|
|
}
|
|
ip := net.IP(buf)
|
|
message.Address = ip.String()
|
|
//fmt.Println("TypeIPV4 地址为:" + ip.String())
|
|
case TypeDoMain:
|
|
|
|
if _, err := io.ReadFull(conn, buf[:1]); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
domain_length := buf[0]
|
|
if domain_length > IPV4_LENGHT {
|
|
buf = make([]byte, domain_length)
|
|
}
|
|
if _, err := io.ReadFull(conn, buf[:domain_length]); err != nil {
|
|
message.Address = string(buf[:domain_length])
|
|
}
|
|
|
|
//fmt.Println("TypeDoMain 地址为:" + message.Address)
|
|
}
|
|
|
|
//读取 端口
|
|
if _, err := io.ReadFull(conn, buf[:PORT_LENGHT]); err != nil {
|
|
return nil, err
|
|
}
|
|
message.Port = (uint16(buf[0]) << 8) + uint16(buf[1])
|
|
return &message, nil
|
|
} else {
|
|
return nil, ERRADDRESS_TYPE_NOT_SUPPORTED
|
|
}
|
|
}
|
|
|
|
type ReplyType = byte
|
|
|
|
const (
|
|
ReplySuccess ReplyType = iota
|
|
ReplyServerFailure
|
|
ReplyConnectionNotAllowed
|
|
ReplyNetworkUnreachable
|
|
ReplyHostUnreachable
|
|
ReplyConnectionRefused
|
|
ReplyTTLExpired
|
|
ReplyCommandNotSupported
|
|
ReplyAddressTypeNotSupported
|
|
)
|
|
|
|
func WriteRequestSuccessMessage(conn net.Conn, ip net.IP, port uint16) error {
|
|
|
|
addressType := TypeIPV4
|
|
if len(ip) == IPV6_LENGHT {
|
|
addressType = TypeIPV6
|
|
}
|
|
|
|
// Write version, reply success, reserved, address type
|
|
_, err := conn.Write([]byte{SOCKET_5_VERSION, ReplySuccess, ReservedFild, addressType})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// write bind IP(IPV4/IPV6)
|
|
if _, err := conn.Write(ip); err != nil {
|
|
return err
|
|
}
|
|
// write bind port
|
|
buf := make([]byte, 2)
|
|
buf[0] = byte(port >> 8)
|
|
buf[1] = byte(port - uint16(buf[0]))
|
|
_, err = conn.Write(buf)
|
|
return err
|
|
}
|
|
|
|
func WriteRequestFailureMessage(conn net.Conn, replyType ReplyType) error {
|
|
_, err := conn.Write([]byte{SOCKET_5_VERSION, replyType, ReservedFild, TypeIPV4, 0, 0, 0, 0, 0, 0})
|
|
return err
|
|
}
|