google / gopacket

Provides packet processing capabilities for Go
BSD 3-Clause "New" or "Revised" License
6.32k stars 1.13k forks source link

Duplicate packets from afpacket.TPacket.ZeroCopyReadPacketData() #917

Open fdevibe opened 2 years ago

fdevibe commented 2 years ago

afpacket.TPacket.ZeroCopyReadPacketData() seems to return duplicate packets. When running in a loop, the function returns twice (iterating the loop twice) for each packet.

By modifying the example in examples/afpacket/afpacket.go with the following patch:

--- main.go.orig    2021-10-27 08:55:43.527613441 +0200
+++ main.go 2021-10-27 08:59:59.462272193 +0200
@@ -176,6 +176,11 @@
        }
        bytes += uint64(len(data))
        packets++
+       packet := gopacket.NewPacket(data, layers.LayerTypeEthernet, gopacket.Default)
+       tcpLayer := packet.Layer(layers.LayerTypeTCP)
+       tcp, _ := tcpLayer.(*layers.TCP)
+       payload := tcp.Payload
+       log.Printf("Payload: '%s'\n", payload)
        if *count%*verbose == 0 {
            _, afpacketStats, err := afpacketHandle.SocketStats()
            if err != nil {

and then running a netcat server:

$ nc -4lp 4321
foo

with a netcat client:

$ nc -t 127.0.0.1 4321
foo

I get the following output

$ sudo ./afpacket -f "dst host 127.0.0.1 and dst port 4321" -s -1 -i lo -log_every 1
2021/10/27 09:00:17 Starting on interface "lo"
2021/10/27 09:00:24 Payload: 'foo
'
2021/10/27 09:00:24 Read in 70 bytes in 1 packets
2021/10/27 09:00:24 Stats {received dropped queue-freeze}: {2 0 1}
2021/10/27 09:00:24 Payload: 'foo
'
2021/10/27 09:00:24 Read in 140 bytes in 2 packets
2021/10/27 09:00:24 Stats {received dropped queue-freeze}: {2 0 1}

So it seems like

data, _, err := source.ZeroCopyReadPacketData()

will actually return the packet data twice, source here being a afpacket.TPacket.

Running

$ sudo tcpdump -i lo dst port 4321

at the same time shows only one packet:

09:00:23.945888 IP localhost.58110 > localhost.rwhois: Flags [P.], seq 12:16, ack 1, win 512, options [nop,nop,TS val 2938365429 ecr 2937467628], length 4

System:

$ go version
go version go1.15.15 linux/amd64
$ uname -a
Linux x1c 5.14.2-arch1-2 #1 SMP PREEMPT Thu, 09 Sep 2021 09:42:35 +0000 x86_64 GNU/Linux
jschwinger233 commented 2 years ago

Same issue here. And here is my demonstration code:

package main

import (
    "log"
    "strings"

    "github.com/google/gopacket"
    "github.com/google/gopacket/layers"
    "github.com/google/gopacket/pcapgo"
)

func main() {
    handler, err := pcapgo.NewEthernetHandle("lo")
    if err != nil {
        log.Fatalf("failed to new handler: %+v", err)
    }
    packetSource := gopacket.NewPacketSource(handler, layers.LayerTypeEthernet)
    for packet := range packetSource.Packets() {
        appLayer := packet.ApplicationLayer()
        if appLayer == nil {
            continue
        }
        payload := string(appLayer.Payload())
        if strings.Contains(payload, "GET / ") {
            println(payload)
        }
    }
}
gao114882 commented 2 years ago

I have Same issue, do you fixed this?

gao114882 commented 2 years ago

this issue is only found in 127.0.0.1 , eth0 hasn't this satuation.

mosajjal commented 2 years ago

if the connection is localhost to localhost, doesn't that mean that it would be the expected behavior to see the same packet twice? once in "source" and one in "dest"?