package xproto import ( "bytes" "crypto/md5" "errors" "fmt" "github.com/net-byte/vtun/common/config" "net" ) const ProtocolVersion = 1 const ClientSendPacketHeaderLength = 19 const ServerSendPacketHeaderLength = 3 const ClientHandshakePacketLength = 37 type ClientHandshakePacket struct { ProtocolVersion uint8 //1 byte Key *AuthKey //16 byte CIDRv4 net.IP //4 byte CIDRv6 net.IP //16 byte } func (p *ClientHandshakePacket) Bytes() []byte { data := make([]byte, ClientHandshakePacketLength) data[0] = p.ProtocolVersion copy(data[1:17], p.Key[:]) copy(data[17:21], p.CIDRv4.To4()[:]) copy(data[21:37], p.CIDRv6.To16()[:]) return data } func GenClientHandshakePacket(config config.Config) (*ClientHandshakePacket, error) { authKey := ParseAuthKeyFromString(config.Key) ipv4Addr, _, err := net.ParseCIDR(config.CIDR) if err != nil { return nil, err } ipv6Addr, _, err := net.ParseCIDR(config.CIDRv6) if err != nil { return nil, err } obj := &ClientHandshakePacket{ ProtocolVersion: ProtocolVersion, Key: authKey, CIDRv4: ipv4Addr, CIDRv6: ipv6Addr, } return obj, nil } func ParseClientHandshakePacket(data []byte) *ClientHandshakePacket { var obj = &ClientHandshakePacket{} var authKey AuthKey if len(data) != ClientHandshakePacketLength { return nil } obj.ProtocolVersion = data[0] copy(authKey[:], data[1:17]) obj.Key = &authKey obj.CIDRv4 = net.IP{data[17], data[18], data[19], data[20]} obj.CIDRv6 = net.IP{data[21], data[22], data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], data[34], data[35], data[36]} return obj } type ClientSendPacketHeader struct { ProtocolVersion uint8 //1 byte Key *AuthKey //16 byte Length int //2 byte, convert to [2]byte } func (p *ClientSendPacketHeader) Bytes() []byte { data := make([]byte, ClientSendPacketHeaderLength) data[0] = p.ProtocolVersion copy(data[1:17], p.Key[:]) data[17] = byte(p.Length >> 8 & 0xff) data[18] = byte(p.Length & 0xff) return data } func ParseClientSendPacketHeader(data []byte) *ClientSendPacketHeader { var obj = &ClientSendPacketHeader{} var authKey AuthKey if len(data) != ClientSendPacketHeaderLength { return nil } obj.ProtocolVersion = data[0] copy(authKey[:], data[1:17]) obj.Key = &authKey obj.Length = ((obj.Length & 0x00) | int(data[17])) << 8 obj.Length = obj.Length | int(data[18]) return obj } type ServerSendPacketHeader struct { ProtocolVersion uint8 //1 byte Length int //2 byte, convert to [2]byte } func (p *ServerSendPacketHeader) Bytes() []byte { data := make([]byte, ServerSendPacketHeaderLength) data[0] = p.ProtocolVersion data[1] = byte(p.Length >> 8 & 0xff) data[2] = byte(p.Length & 0xff) return data } func ParseServerSendPacketHeader(data []byte) *ServerSendPacketHeader { var obj = &ServerSendPacketHeader{} if len(data) != ServerSendPacketHeaderLength { return nil } obj.ProtocolVersion = data[0] obj.Length = ((obj.Length & 0x00) | int(data[1])) << 8 obj.Length = obj.Length | int(data[2]) return obj } const HeaderLength = 2 // ReadLength []byte length to int length func ReadLength(header []byte) int { length := 0 if len(header) >= 2 { length = ((length & 0x00) | int(header[0])) << 8 length = length | int(header[1]) } return length } func WriteLength(header []byte, length int) { if len(header) >= 2 { header[0] = byte(length >> 8 & 0xff) header[1] = byte(length & 0xff) } } func Copy(b []byte) []byte { c := make([]byte, len(b)) copy(c, b) return c } func Merge(a, b []byte) []byte { al := len(a) bl := len(b) c := make([]byte, len(a)+len(b)) copy(c[al:al+bl], b) copy(c[:al], a) return c } type AuthKey [16]byte // Bytes returns the bytes representation of this AuthKey. func (u *AuthKey) Bytes() []byte { return u[:] } // Equals returns true if this AuthKey equals another AuthKey by value. func (u *AuthKey) Equals(another *AuthKey) bool { if u == nil && another == nil { return true } if u == nil || another == nil { return false } return bytes.Equal(u.Bytes(), another.Bytes()) } // ParseBytes converts a AuthKey in byte form to object. func ParseBytes(b []byte) (AuthKey, error) { var authKey AuthKey if len(b) != 16 { return authKey, errors.New(fmt.Sprintf("invalid AuthKey: %v", b)) } copy(authKey[:], b) return authKey, nil } // ParseAuthKeyFromString converts a AuthKey in string form to object. func ParseAuthKeyFromString(str string) *AuthKey { var authKey AuthKey m := md5.New() m.Write([]byte(str)) r := m.Sum(nil) copy(authKey[:], r[:16]) return &authKey }