github.com/gopacket/gopacket@v1.1.0/afpacket/header.go (about) 1 // Copyright 2012 Google, Inc. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style license 4 // that can be found in the LICENSE file in the root of the source 5 // tree. 6 7 //go:build linux 8 // +build linux 9 10 package afpacket 11 12 import ( 13 "reflect" 14 "time" 15 "unsafe" 16 17 "golang.org/x/sys/unix" 18 ) 19 20 // Our model of handling all TPacket versions is a little hacky, to say the 21 // least. We use the header interface to handle interactions with the 22 // tpacket1/tpacket2 packet header AND the tpacket3 block header. The big 23 // difference is that tpacket3's block header implements the next() call to get 24 // the next packet within the block, while v1/v2 just always return false. 25 26 type header interface { 27 // getStatus returns the TPacket status of the current header. 28 getStatus() int 29 // clearStatus clears the status of the current header, releasing its 30 // underlying data back to the kernel for future use with new packets. 31 // Using the header after calling clearStatus is an error. clearStatus 32 // should only be called after next() returns false. 33 clearStatus() 34 // getTime returns the timestamp for the current packet pointed to by 35 // the header. 36 getTime() time.Time 37 // getData returns the packet data pointed to by the current header. 38 getData(opts *options) []byte 39 // getLength returns the total length of the packet. 40 getLength() int 41 // getIfaceIndex returns the index of the network interface 42 // where the packet was seen. The index can later be translated to a name. 43 getIfaceIndex() int 44 // getVLAN returns the VLAN of a packet if it was provided out-of-band 45 getVLAN() int 46 // next moves this header to point to the next packet it contains, 47 // returning true on success (in which case getTime and getData will 48 // return values for the new packet) or false if there are no more 49 // packets (in which case clearStatus should be called). 50 next() bool 51 } 52 53 const tpacketAlignment = uint(unix.TPACKET_ALIGNMENT) 54 55 func tpAlign(x int) int { 56 return int((uint(x) + tpacketAlignment - 1) &^ (tpacketAlignment - 1)) 57 } 58 59 type v1header struct { 60 tp_status uint64 61 tp_len uint32 62 tp_snaplen uint32 63 tp_mac uint16 64 tp_net uint16 65 tp_sec uint32 66 tp_usec uint32 67 _ [4]byte 68 } 69 type tpacket_bd_ts struct { 70 ts_sec uint32 71 anon0 [4]byte 72 } 73 74 type tpacket_hdr_v1 struct { 75 block_status uint32 76 num_pkts uint32 77 offset_to_first_pkt uint32 78 blk_len uint32 79 seq_num uint64 80 ts_first_pkt tpacket_bd_ts 81 ts_last_pkt tpacket_bd_ts 82 } 83 84 type v2header struct { 85 tp_status uint32 86 tp_len uint32 87 tp_snaplen uint32 88 tp_mac uint16 89 tp_net uint16 90 tp_sec uint32 91 tp_nsec uint32 92 tp_vlan_tci uint16 93 tp_vlan_tpid uint16 94 tp_padding [4]byte 95 } 96 97 type sockAddrLL struct { 98 sll_family uint16 99 sll_protocol uint16 100 sll_ifindex int32 101 sll_hatype uint16 102 sll_pkttype uint8 103 sll_halen uint8 104 sll_addr [8]byte 105 } 106 107 type tpacketHdrVarient1 struct { 108 rxHash uint32 109 vlanTCI uint32 110 vlanTPID uint16 111 _ [2]byte 112 } 113 114 type tpacketBlockDesc struct { 115 version uint32 116 offsetToPriv uint32 117 hdr [40]byte 118 } 119 120 type tpacket3_hdr struct { 121 tp_next_offset uint32 122 tp_sec uint32 123 tp_nsec uint32 124 tp_snaplen uint32 125 tp_len uint32 126 tp_status uint32 127 tp_mac uint16 128 tp_net uint16 129 anon0 [12]byte 130 tp_padding [8]byte 131 } 132 133 const ETH_ALEN = 0x6 134 const VLAN_HLEN = 0x4 135 const sizeof_struct_tpacket2_hdr = 0x20 136 const sizeof_struct_tpacket3_hdr = 0x30 137 const sizeof_struct_tpacket_hdr = 0x20 138 139 func makeSlice(start uintptr, length int) (data []byte) { 140 slice := (*reflect.SliceHeader)(unsafe.Pointer(&data)) 141 slice.Data = start 142 slice.Len = length 143 slice.Cap = length 144 return 145 } 146 147 func insertVlanHeader(data []byte, vlanTCI int, opts *options) []byte { 148 if vlanTCI == 0 || !opts.addVLANHeader { 149 return data 150 } 151 eth := make([]byte, 0, len(data)+VLAN_HLEN) 152 eth = append(eth, data[0:ETH_ALEN*2]...) 153 eth = append(eth, []byte{0x81, 0, byte((vlanTCI >> 8) & 0xff), byte(vlanTCI & 0xff)}...) 154 return append(eth, data[ETH_ALEN*2:]...) 155 } 156 157 func (h *v1header) getVLAN() int { 158 return -1 159 } 160 func (h *v1header) getStatus() int { 161 return int(h.tp_status) 162 } 163 func (h *v1header) clearStatus() { 164 h.tp_status = 0 165 } 166 func (h *v1header) getTime() time.Time { 167 return time.Unix(int64(h.tp_sec), int64(h.tp_usec)*1000) 168 } 169 func (h *v1header) getData(opts *options) []byte { 170 return makeSlice(uintptr(unsafe.Pointer(h))+uintptr(h.tp_mac), int(h.tp_snaplen)) 171 } 172 func (h *v1header) getLength() int { 173 return int(h.tp_len) 174 } 175 func (h *v1header) getIfaceIndex() int { 176 ll := (*sockAddrLL)(unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(tpAlign(int(sizeof_struct_tpacket_hdr))))) 177 return int(ll.sll_ifindex) 178 } 179 func (h *v1header) next() bool { 180 return false 181 } 182 183 func (h *v2header) getVLAN() int { 184 return -1 185 } 186 func (h *v2header) getStatus() int { 187 return int(h.tp_status) 188 } 189 func (h *v2header) clearStatus() { 190 h.tp_status = 0 191 } 192 func (h *v2header) getTime() time.Time { 193 return time.Unix(int64(h.tp_sec), int64(h.tp_nsec)) 194 } 195 func (h *v2header) getData(opts *options) []byte { 196 data := makeSlice(uintptr(unsafe.Pointer(h))+uintptr(h.tp_mac), int(h.tp_snaplen)) 197 return insertVlanHeader(data, int(h.tp_vlan_tci), opts) 198 } 199 func (h *v2header) getLength() int { 200 return int(h.tp_len) 201 } 202 func (h *v2header) getIfaceIndex() int { 203 ll := (*sockAddrLL)(unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(tpAlign(int(sizeof_struct_tpacket2_hdr))))) 204 return int(ll.sll_ifindex) 205 } 206 func (h *v2header) next() bool { 207 return false 208 } 209 210 type v3wrapper struct { 211 block *tpacketBlockDesc 212 blockhdr *tpacket_hdr_v1 213 packet *tpacket3_hdr 214 used uint32 215 } 216 217 func initV3Wrapper(block unsafe.Pointer) (w v3wrapper) { 218 w.block = (*tpacketBlockDesc)(block) 219 w.blockhdr = (*tpacket_hdr_v1)(unsafe.Pointer(&w.block.hdr[0])) 220 w.packet = (*tpacket3_hdr)(unsafe.Pointer(uintptr(block) + uintptr(w.blockhdr.offset_to_first_pkt))) 221 return 222 } 223 224 func (w *v3wrapper) getVLAN() int { 225 if w.packet.tp_status&unix.TP_STATUS_VLAN_VALID != 0 { 226 hv1 := (*tpacketHdrVarient1)(unsafe.Pointer(&w.packet.anon0[0])) 227 return int(hv1.vlanTCI & 0xfff) 228 } 229 return -1 230 } 231 232 func (w *v3wrapper) getStatus() int { 233 return int(w.blockhdr.block_status) 234 } 235 func (w *v3wrapper) clearStatus() { 236 w.blockhdr.block_status = 0 237 } 238 func (w *v3wrapper) getTime() time.Time { 239 return time.Unix(int64(w.packet.tp_sec), int64(w.packet.tp_nsec)) 240 } 241 func (w *v3wrapper) getData(opts *options) []byte { 242 data := makeSlice(uintptr(unsafe.Pointer(w.packet))+uintptr(w.packet.tp_mac), int(w.packet.tp_snaplen)) 243 244 hv1 := (*tpacketHdrVarient1)(unsafe.Pointer(&w.packet.anon0[0])) 245 return insertVlanHeader(data, int(hv1.vlanTCI), opts) 246 } 247 func (w *v3wrapper) getLength() int { 248 return int(w.packet.tp_len) 249 } 250 func (w *v3wrapper) getIfaceIndex() int { 251 ll := (*sockAddrLL)(unsafe.Pointer(uintptr(unsafe.Pointer(w.packet)) + uintptr(tpAlign(int(sizeof_struct_tpacket3_hdr))))) 252 return int(ll.sll_ifindex) 253 } 254 func (w *v3wrapper) next() bool { 255 w.used++ 256 if w.used >= w.blockhdr.num_pkts { 257 return false 258 } 259 260 next := uintptr(unsafe.Pointer(w.packet)) 261 if w.packet.tp_next_offset != 0 { 262 next += uintptr(w.packet.tp_next_offset) 263 } else { 264 next += uintptr(tpAlign(int(w.packet.tp_snaplen) + int(w.packet.tp_mac))) 265 } 266 w.packet = (*tpacket3_hdr)(unsafe.Pointer(next)) 267 return true 268 }