Skip to content

Commit

Permalink
Add support for (optional) population of packet type in afpacket via …
Browse files Browse the repository at this point in the history
…ancillary data (#1)
  • Loading branch information
hmahmood authored Jun 26, 2024
1 parent 32ee382 commit 4ac4cee
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 4 deletions.
19 changes: 15 additions & 4 deletions afpacket/afpacket.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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()
Expand Down
15 changes: 15 additions & 0 deletions afpacket/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 8 additions & 0 deletions afpacket/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -121,6 +126,7 @@ type options struct {
blockSize int
numBlocks int
addVLANHeader bool
addPktType bool
blockTimeout time.Duration
pollTimeout time.Duration
version OptTPacketVersion
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 4ac4cee

Please sign in to comment.