goproxy/core/dst/packets.go
arraykeys@gmail.com 9a1f5de686 add core
2018-09-04 17:46:43 +08:00

156 lines
3.5 KiB
Go

// Copyright 2014 The DST Authors. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package dst
import (
"encoding/binary"
"fmt"
"net"
)
const dstHeaderLen = 12
type packetType int8
const (
typeHandshake packetType = 0x0
typeData = 0x1
typeAck = 0x2
typeNegAck = 0x3
typeShutdown = 0x4
)
func (t packetType) String() string {
switch t {
case typeData:
return "data"
case typeHandshake:
return "handshake"
case typeAck:
return "ack"
case typeNegAck:
return "negAck"
case typeShutdown:
return "shutdown"
default:
return "unknown"
}
}
type connectionID uint32
func (c connectionID) String() string {
return fmt.Sprintf("Ci%08x", uint32(c))
}
type sequenceNo uint32
func (s sequenceNo) String() string {
return fmt.Sprintf("Sq%d", uint32(s))
}
type timestamp uint32
func (t timestamp) String() string {
return fmt.Sprintf("Ts%d", uint32(t))
}
const (
flagRequest = 1 << 0 // This packet is a handshake request
flagResponse = 1 << 1 // This packet is a handshake response
flagCookie = 1 << 2 // This packet contains a coookie challenge
)
type header struct {
packetType packetType // 4 bits
flags uint8 // 4 bits
connID connectionID // 24 bits
sequenceNo sequenceNo
timestamp timestamp
}
func (h header) marshal(bs []byte) {
binary.BigEndian.PutUint32(bs, uint32(h.connID&0xffffff))
bs[0] = h.flags | uint8(h.packetType)<<4
binary.BigEndian.PutUint32(bs[4:], uint32(h.sequenceNo))
binary.BigEndian.PutUint32(bs[8:], uint32(h.timestamp))
}
func unmarshalHeader(bs []byte) header {
var h header
h.packetType = packetType(bs[0] >> 4)
h.flags = bs[0] & 0xf
h.connID = connectionID(binary.BigEndian.Uint32(bs) & 0xffffff)
h.sequenceNo = sequenceNo(binary.BigEndian.Uint32(bs[4:]))
h.timestamp = timestamp(binary.BigEndian.Uint32(bs[8:]))
return h
}
func (h header) String() string {
return fmt.Sprintf("header{type=%s flags=0x%x connID=%v seq=%v time=%v}", h.packetType, h.flags, h.connID, h.sequenceNo, h.timestamp)
}
type handshakeData struct {
packetSize uint32
connID connectionID
cookie uint32
}
func (h handshakeData) marshalInto(data []byte) {
binary.BigEndian.PutUint32(data[0:], h.packetSize)
binary.BigEndian.PutUint32(data[4:], uint32(h.connID))
binary.BigEndian.PutUint32(data[8:], h.cookie)
}
func (h handshakeData) marshal() []byte {
var data [12]byte
h.marshalInto(data[:])
return data[:]
}
func unmarshalHandshakeData(data []byte) handshakeData {
var h handshakeData
h.packetSize = binary.BigEndian.Uint32(data[0:])
h.connID = connectionID(binary.BigEndian.Uint32(data[4:]))
h.cookie = binary.BigEndian.Uint32(data[8:])
return h
}
func (h handshakeData) String() string {
return fmt.Sprintf("handshake{size=%d connID=%v cookie=0x%08x}", h.packetSize, h.connID, h.cookie)
}
type packet struct {
src connectionID
dst net.Addr
hdr header
data []byte
}
func (p packet) String() string {
var dst string
if p.dst != nil {
dst = "dst=" + p.dst.String() + " "
}
switch p.hdr.packetType {
case typeHandshake:
return fmt.Sprintf("%spacket{src=%v %v %v}", dst, p.src, p.hdr, unmarshalHandshakeData(p.data))
default:
return fmt.Sprintf("%spacket{src=%v %v data[:%d]}", dst, p.src, p.hdr, len(p.data))
}
}
func (p packet) LessSeq(seq sequenceNo) bool {
diff := seq - p.hdr.sequenceNo
if diff == 0 {
return false
}
return diff < 1<<31
}
func (a packet) Less(b packet) bool {
return a.LessSeq(b.hdr.sequenceNo)
}