github.com/AntonOrnatskyi/goproxy@v0.0.0-20190205095733-4526a9fa18b4/core/dst/packets.go (about) 1 // Copyright 2014 The DST Authors. All rights reserved. 2 // Use of this source code is governed by an MIT-style 3 // license that can be found in the LICENSE file. 4 5 package dst 6 7 import ( 8 "encoding/binary" 9 "fmt" 10 "net" 11 ) 12 13 const dstHeaderLen = 12 14 15 type packetType int8 16 17 const ( 18 typeHandshake packetType = 0x0 19 typeData = 0x1 20 typeAck = 0x2 21 typeNegAck = 0x3 22 typeShutdown = 0x4 23 ) 24 25 func (t packetType) String() string { 26 switch t { 27 case typeData: 28 return "data" 29 case typeHandshake: 30 return "handshake" 31 case typeAck: 32 return "ack" 33 case typeNegAck: 34 return "negAck" 35 case typeShutdown: 36 return "shutdown" 37 default: 38 return "unknown" 39 } 40 } 41 42 type connectionID uint32 43 44 func (c connectionID) String() string { 45 return fmt.Sprintf("Ci%08x", uint32(c)) 46 } 47 48 type sequenceNo uint32 49 50 func (s sequenceNo) String() string { 51 return fmt.Sprintf("Sq%d", uint32(s)) 52 } 53 54 type timestamp uint32 55 56 func (t timestamp) String() string { 57 return fmt.Sprintf("Ts%d", uint32(t)) 58 } 59 60 const ( 61 flagRequest = 1 << 0 // This packet is a handshake request 62 flagResponse = 1 << 1 // This packet is a handshake response 63 flagCookie = 1 << 2 // This packet contains a coookie challenge 64 ) 65 66 type header struct { 67 packetType packetType // 4 bits 68 flags uint8 // 4 bits 69 connID connectionID // 24 bits 70 sequenceNo sequenceNo 71 timestamp timestamp 72 } 73 74 func (h header) marshal(bs []byte) { 75 binary.BigEndian.PutUint32(bs, uint32(h.connID&0xffffff)) 76 bs[0] = h.flags | uint8(h.packetType)<<4 77 binary.BigEndian.PutUint32(bs[4:], uint32(h.sequenceNo)) 78 binary.BigEndian.PutUint32(bs[8:], uint32(h.timestamp)) 79 } 80 81 func unmarshalHeader(bs []byte) header { 82 var h header 83 h.packetType = packetType(bs[0] >> 4) 84 h.flags = bs[0] & 0xf 85 h.connID = connectionID(binary.BigEndian.Uint32(bs) & 0xffffff) 86 h.sequenceNo = sequenceNo(binary.BigEndian.Uint32(bs[4:])) 87 h.timestamp = timestamp(binary.BigEndian.Uint32(bs[8:])) 88 return h 89 } 90 91 func (h header) String() string { 92 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) 93 } 94 95 type handshakeData struct { 96 packetSize uint32 97 connID connectionID 98 cookie uint32 99 } 100 101 func (h handshakeData) marshalInto(data []byte) { 102 binary.BigEndian.PutUint32(data[0:], h.packetSize) 103 binary.BigEndian.PutUint32(data[4:], uint32(h.connID)) 104 binary.BigEndian.PutUint32(data[8:], h.cookie) 105 } 106 107 func (h handshakeData) marshal() []byte { 108 var data [12]byte 109 h.marshalInto(data[:]) 110 return data[:] 111 } 112 113 func unmarshalHandshakeData(data []byte) handshakeData { 114 var h handshakeData 115 h.packetSize = binary.BigEndian.Uint32(data[0:]) 116 h.connID = connectionID(binary.BigEndian.Uint32(data[4:])) 117 h.cookie = binary.BigEndian.Uint32(data[8:]) 118 return h 119 } 120 121 func (h handshakeData) String() string { 122 return fmt.Sprintf("handshake{size=%d connID=%v cookie=0x%08x}", h.packetSize, h.connID, h.cookie) 123 } 124 125 type packet struct { 126 src connectionID 127 dst net.Addr 128 hdr header 129 data []byte 130 } 131 132 func (p packet) String() string { 133 var dst string 134 if p.dst != nil { 135 dst = "dst=" + p.dst.String() + " " 136 } 137 switch p.hdr.packetType { 138 case typeHandshake: 139 return fmt.Sprintf("%spacket{src=%v %v %v}", dst, p.src, p.hdr, unmarshalHandshakeData(p.data)) 140 default: 141 return fmt.Sprintf("%spacket{src=%v %v data[:%d]}", dst, p.src, p.hdr, len(p.data)) 142 } 143 } 144 145 func (p packet) LessSeq(seq sequenceNo) bool { 146 diff := seq - p.hdr.sequenceNo 147 if diff == 0 { 148 return false 149 } 150 return diff < 1<<31 151 } 152 153 func (a packet) Less(b packet) bool { 154 return a.LessSeq(b.hdr.sequenceNo) 155 }