fix httptap incorrectly capturing GRO frames

This commit is contained in:
soypat
2025-12-31 17:08:53 -03:00
parent 7369ec0b7e
commit 243d1a720d
4 changed files with 19 additions and 41 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ func (efrm Frame) Payload() []byte {
hl := efrm.HeaderLength()
et := efrm.EtherTypeOrSize()
if et.IsSize() {
return efrm.buf[hl:et]
return efrm.buf[hl : hl+int(et)]
}
return efrm.buf[hl:]
}
+7 -31
View File
@@ -5,17 +5,16 @@ import (
"flag"
"fmt"
"log"
"math"
"net"
"net/http"
"net/netip"
"strings"
"time"
"github.com/soypat/lneto"
"github.com/soypat/lneto/internal"
"github.com/soypat/lneto/internal/ltesto"
"github.com/soypat/lneto/internet/pcap"
"github.com/soypat/lneto/tcp"
)
func main() {
@@ -30,9 +29,14 @@ func main() {
func run() error {
var (
flagInterface = "tap0"
flagMinMTU = math.MaxUint16
)
flag.StringVar(&flagInterface, "i", flagInterface, "Interface to select. tap* creates a tap interface. Any other name will create a bridge to the name of the interface i.e: 'enp7s0', 'wlp8s0', 'lo'")
flag.IntVar(&flagMinMTU, "mtu", flagMinMTU, "Set the interface minimum MTU to use for buffer.")
flag.Parse()
if flagMinMTU < 1500 {
return errors.New("minimum MTU too small")
}
var (
flagNet = "192.168.10.1/24"
flagiface = "tap0"
@@ -57,7 +61,7 @@ func run() error {
iface = br
}
sv, err := ltesto.NewHTTPTapServer(iface, flagPacketQueueSize, flagPacketQueueSize)
sv, err := ltesto.NewHTTPTapServer(iface, flagMinMTU, flagPacketQueueSize, flagPacketQueueSize)
if err != nil {
return err
}
@@ -91,31 +95,3 @@ func run() error {
http.ListenAndServe(":7070", sv)
return errors.New("finished")
}
func getTCPData(frames []pcap.Frame, pkt []byte) (flags tcp.Flags, src, dst uint16) {
for i := range frames {
proto := frames[i].Protocol
if proto == lneto.IPProtoTCP {
return tcp.Flags(getFrameClassUint(frames[i], pkt, pcap.FieldClassFlags)),
uint16(getFrameClassUint(frames[i], pkt, pcap.FieldClassSrc)),
uint16(getFrameClassUint(frames[i], pkt, pcap.FieldClassDst))
} else if proto == lneto.IPProtoUDP {
return 0,
uint16(getFrameClassUint(frames[i], pkt, pcap.FieldClassSrc)),
uint16(getFrameClassUint(frames[i], pkt, pcap.FieldClassDst))
}
}
return 0, 0, 0
}
func getFrameClassUint(frame pcap.Frame, pkt []byte, class pcap.FieldClass) uint64 {
iflags, err := frame.FieldByClass(class)
if err != nil {
return 0
}
v, err := frame.FieldAsUint(iflags, pkt)
if err != nil {
return 0
}
return v
}
+8 -5
View File
@@ -1,11 +1,13 @@
package main
import (
"encoding/hex"
"errors"
"flag"
"fmt"
"log"
"log/slog"
"math"
"net"
"net/netip"
"os"
@@ -107,7 +109,7 @@ func run() (err error) {
// Loop goroutine.
go func() {
lastAction := time.Now()
buf := make([]byte, mtu)
buf := make([]byte, math.MaxUint16) // Generic-receive Offload (GRO) can aggregate packets.
var cap pcap.PacketBreakdown
var frames []pcap.Frame
pf := pcap.Formatter{
@@ -120,9 +122,11 @@ func run() (err error) {
}
frames, err = cap.CaptureEthernet(frames[:0], pkt, 0)
if err != nil {
pkt := hex.EncodeToString(pkt)
slog.Error(err.Error(), slog.Any("pkt", pkt))
return err
}
pfbuf = append(pfbuf[:0], context...)
pfbuf = fmt.Appendf(pfbuf[:0], "%-3s %3d", context, len(pkt))
pfbuf = append(pfbuf, ' ', '[')
pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt)
pfbuf = append(pfbuf, ']', '\n')
@@ -133,7 +137,6 @@ func run() (err error) {
return err
}
for {
clear(buf)
nwrite, err := stack.Encapsulate(buf[:], -1, 0)
if err != nil {
log.Println("ERR:ENCAPSULATE", err)
@@ -150,7 +153,7 @@ func run() (err error) {
}
}
clear(buf)
clear(buf[:nwrite])
nread, err := iface.Read(buf)
if err != nil {
log.Fatal("groutine read:", err)
@@ -165,7 +168,7 @@ func run() (err error) {
}
}
}
clear(buf[:nread])
if nread == 0 && nwrite == 0 && time.Since(lastAction) > 4*time.Second {
time.Sleep(5 * time.Millisecond)
} else {
+3 -4
View File
@@ -183,16 +183,15 @@ func (sv *HTTPTapServer) OnTransfer(cb func(channel int, pkt []byte)) {
sv.onTx = cb
}
func NewHTTPTapServer(iface Interface, queueOut, queueIn int) (*HTTPTapServer, error) {
func NewHTTPTapServer(iface Interface, minMTU, queueOut, queueIn int) (*HTTPTapServer, error) {
if iface == nil {
return nil, errors.New("nil interface argument to HTTP interface server")
}
mtu, err := iface.MTU()
if err != nil {
return nil, err
} else if mtu < minMTU {
return nil, errors.New("too small MTU")
}
bufferSize := max(mtu, minMTU)
netmask, err := iface.IPMask()
if err != nil {
return nil, err
@@ -202,7 +201,7 @@ func NewHTTPTapServer(iface Interface, queueOut, queueIn int) (*HTTPTapServer, e
taps := &HTTPTapServer{
router: sv,
tap: iface,
buf: make([]byte, mtu),
buf: make([]byte, bufferSize),
}
sv.HandleFunc("/send", func(w http.ResponseWriter, r *http.Request) {
retries := 10