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  }