diff --git a/afpacket/afpacket.go b/afpacket/afpacket.go index 6600ae25e..1e79fba60 100644 --- a/afpacket/afpacket.go +++ b/afpacket/afpacket.go @@ -57,6 +57,13 @@ type AncillaryVLAN struct { VLAN int } +// AncillaryPktType structures are used to pass the packet type +// as ancillary data via CaptureInfo. +type AncillaryPktType struct { + // The packet type provided by the kernel. + Type uint8 +} + // Stats is a set of counters detailing the work TPacket has done so far. type Stats struct { // Packets is the total number of packets returned to the caller. @@ -293,10 +300,11 @@ func (h *TPacket) releaseCurrentPacket() error { // to old bytes when using ZeroCopyReadPacketData... if you need to keep data past // the next time you call ZeroCopyReadPacketData, use ReadPacketData, which copies // the bytes into a new buffer for you. -// tp, _ := NewTPacket(...) -// data1, _, _ := tp.ZeroCopyReadPacketData() -// // do everything you want with data1 here, copying bytes out of it if you'd like to keep them around. -// data2, _, _ := tp.ZeroCopyReadPacketData() // invalidates bytes in data1 +// +// tp, _ := NewTPacket(...) +// data1, _, _ := tp.ZeroCopyReadPacketData() +// // do everything you want with data1 here, copying bytes out of it if you'd like to keep them around. +// data2, _, _ := tp.ZeroCopyReadPacketData() // invalidates bytes in data1 func (h *TPacket) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) { h.mu.Lock() retry: @@ -324,6 +332,9 @@ retry: if vlan >= 0 { ci.AncillaryData = append(ci.AncillaryData, AncillaryVLAN{vlan}) } + if h.opts.addPktType { + ci.AncillaryData = append(ci.AncillaryData, AncillaryPktType{h.current.getPktType()}) + } atomic.AddInt64(&h.stats.Packets, 1) h.headerNextNeeded = true h.mu.Unlock() diff --git a/afpacket/header.go b/afpacket/header.go index 61634e7ab..59652c9d1 100644 --- a/afpacket/header.go +++ b/afpacket/header.go @@ -4,6 +4,7 @@ // that can be found in the LICENSE file in the root of the source // tree. +//go:build linux // +build linux package afpacket @@ -45,6 +46,8 @@ type header interface { // getIfaceIndex returns the index of the network interface // where the packet was seen. The index can later be translated to a name. getIfaceIndex() int + // getPktType returns the packet type + getPktType() uint8 // getVLAN returns the VLAN of a packet if it was provided out-of-band getVLAN() int // next moves this header to point to the next packet it contains, @@ -103,6 +106,10 @@ func (h *v1header) getIfaceIndex() int { ll := (*C.struct_sockaddr_ll)(unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(tpAlign(int(C.sizeof_struct_tpacket_hdr))))) return int(ll.sll_ifindex) } +func (h *v1header) getPktType() uint8 { + ll := (*C.struct_sockaddr_ll)(unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(tpAlign(int(C.sizeof_struct_tpacket_hdr))))) + return uint8(ll.sll_pkttype) +} func (h *v1header) next() bool { return false } @@ -130,6 +137,10 @@ func (h *v2header) getIfaceIndex() int { ll := (*C.struct_sockaddr_ll)(unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(tpAlign(int(C.sizeof_struct_tpacket2_hdr))))) return int(ll.sll_ifindex) } +func (h *v2header) getPktType() uint8 { + ll := (*C.struct_sockaddr_ll)(unsafe.Pointer(uintptr(unsafe.Pointer(h)) + uintptr(tpAlign(int(C.sizeof_struct_tpacket2_hdr))))) + return uint8(ll.sll_pkttype) +} func (h *v2header) next() bool { return false } @@ -178,6 +189,10 @@ func (w *v3wrapper) getIfaceIndex() int { ll := (*C.struct_sockaddr_ll)(unsafe.Pointer(uintptr(unsafe.Pointer(w.packet)) + uintptr(tpAlign(int(C.sizeof_struct_tpacket3_hdr))))) return int(ll.sll_ifindex) } +func (w *v3wrapper) getPktType() uint8 { + ll := (*C.struct_sockaddr_ll)(unsafe.Pointer(uintptr(unsafe.Pointer(w.packet)) + uintptr(tpAlign(int(C.sizeof_struct_tpacket3_hdr))))) + return uint8(ll.sll_pkttype) +} func (w *v3wrapper) next() bool { w.used++ if w.used >= w.blockhdr.num_pkts { diff --git a/afpacket/options.go b/afpacket/options.go index 3e305c4d6..343c6bbb4 100644 --- a/afpacket/options.go +++ b/afpacket/options.go @@ -4,6 +4,7 @@ // that can be found in the LICENSE file in the root of the source // tree. +//go:build linux // +build linux package afpacket @@ -106,6 +107,10 @@ type OptPollTimeout time.Duration // be provided if available. type OptAddVLANHeader bool +// OptAddPktType enables extraction / population of the packet type as reported by the +// kernel via the AncillaryPktType struct in CaptureInfo.AncillaryData +type OptAddPktType bool + // Default constants used by options. const ( DefaultFrameSize = 4096 // Default value for OptFrameSize. @@ -121,6 +126,7 @@ type options struct { blockSize int numBlocks int addVLANHeader bool + addPktType bool blockTimeout time.Duration pollTimeout time.Duration version OptTPacketVersion @@ -160,6 +166,8 @@ func parseOptions(opts ...interface{}) (ret options, err error) { ret.socktype = v case OptAddVLANHeader: ret.addVLANHeader = bool(v) + case OptAddPktType: + ret.addPktType = bool(v) default: err = errors.New("unknown type in options") return