Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for (optional) population of packet type in afpacket via ancillary data #1168

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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