mirror of
https://github.com/soypat/lneto.git
synced 2026-08-25 17:09:05 +00:00
fix httptap incorrectly capturing GRO frames
This commit is contained in:
+1
-1
@@ -44,7 +44,7 @@ func (efrm Frame) Payload() []byte {
|
|||||||
hl := efrm.HeaderLength()
|
hl := efrm.HeaderLength()
|
||||||
et := efrm.EtherTypeOrSize()
|
et := efrm.EtherTypeOrSize()
|
||||||
if et.IsSize() {
|
if et.IsSize() {
|
||||||
return efrm.buf[hl:et]
|
return efrm.buf[hl : hl+int(et)]
|
||||||
}
|
}
|
||||||
return efrm.buf[hl:]
|
return efrm.buf[hl:]
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-31
@@ -5,17 +5,16 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
|
||||||
"github.com/soypat/lneto/internal"
|
"github.com/soypat/lneto/internal"
|
||||||
"github.com/soypat/lneto/internal/ltesto"
|
"github.com/soypat/lneto/internal/ltesto"
|
||||||
"github.com/soypat/lneto/internet/pcap"
|
"github.com/soypat/lneto/internet/pcap"
|
||||||
"github.com/soypat/lneto/tcp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -30,9 +29,14 @@ func main() {
|
|||||||
func run() error {
|
func run() error {
|
||||||
var (
|
var (
|
||||||
flagInterface = "tap0"
|
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.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()
|
flag.Parse()
|
||||||
|
if flagMinMTU < 1500 {
|
||||||
|
return errors.New("minimum MTU too small")
|
||||||
|
}
|
||||||
var (
|
var (
|
||||||
flagNet = "192.168.10.1/24"
|
flagNet = "192.168.10.1/24"
|
||||||
flagiface = "tap0"
|
flagiface = "tap0"
|
||||||
@@ -57,7 +61,7 @@ func run() error {
|
|||||||
iface = br
|
iface = br
|
||||||
}
|
}
|
||||||
|
|
||||||
sv, err := ltesto.NewHTTPTapServer(iface, flagPacketQueueSize, flagPacketQueueSize)
|
sv, err := ltesto.NewHTTPTapServer(iface, flagMinMTU, flagPacketQueueSize, flagPacketQueueSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -91,31 +95,3 @@ func run() error {
|
|||||||
http.ListenAndServe(":7070", sv)
|
http.ListenAndServe(":7070", sv)
|
||||||
return errors.New("finished")
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
@@ -107,7 +109,7 @@ func run() (err error) {
|
|||||||
// Loop goroutine.
|
// Loop goroutine.
|
||||||
go func() {
|
go func() {
|
||||||
lastAction := time.Now()
|
lastAction := time.Now()
|
||||||
buf := make([]byte, mtu)
|
buf := make([]byte, math.MaxUint16) // Generic-receive Offload (GRO) can aggregate packets.
|
||||||
var cap pcap.PacketBreakdown
|
var cap pcap.PacketBreakdown
|
||||||
var frames []pcap.Frame
|
var frames []pcap.Frame
|
||||||
pf := pcap.Formatter{
|
pf := pcap.Formatter{
|
||||||
@@ -120,9 +122,11 @@ func run() (err error) {
|
|||||||
}
|
}
|
||||||
frames, err = cap.CaptureEthernet(frames[:0], pkt, 0)
|
frames, err = cap.CaptureEthernet(frames[:0], pkt, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
pkt := hex.EncodeToString(pkt)
|
||||||
|
slog.Error(err.Error(), slog.Any("pkt", pkt))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
pfbuf = append(pfbuf[:0], context...)
|
pfbuf = fmt.Appendf(pfbuf[:0], "%-3s %3d", context, len(pkt))
|
||||||
pfbuf = append(pfbuf, ' ', '[')
|
pfbuf = append(pfbuf, ' ', '[')
|
||||||
pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt)
|
pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt)
|
||||||
pfbuf = append(pfbuf, ']', '\n')
|
pfbuf = append(pfbuf, ']', '\n')
|
||||||
@@ -133,7 +137,6 @@ func run() (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for {
|
for {
|
||||||
clear(buf)
|
|
||||||
nwrite, err := stack.Encapsulate(buf[:], -1, 0)
|
nwrite, err := stack.Encapsulate(buf[:], -1, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("ERR:ENCAPSULATE", err)
|
log.Println("ERR:ENCAPSULATE", err)
|
||||||
@@ -150,7 +153,7 @@ func run() (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clear(buf)
|
clear(buf[:nwrite])
|
||||||
nread, err := iface.Read(buf)
|
nread, err := iface.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("groutine read:", err)
|
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 {
|
if nread == 0 && nwrite == 0 && time.Since(lastAction) > 4*time.Second {
|
||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -183,16 +183,15 @@ func (sv *HTTPTapServer) OnTransfer(cb func(channel int, pkt []byte)) {
|
|||||||
sv.onTx = cb
|
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 {
|
if iface == nil {
|
||||||
return nil, errors.New("nil interface argument to HTTP interface server")
|
return nil, errors.New("nil interface argument to HTTP interface server")
|
||||||
}
|
}
|
||||||
mtu, err := iface.MTU()
|
mtu, err := iface.MTU()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if mtu < minMTU {
|
|
||||||
return nil, errors.New("too small MTU")
|
|
||||||
}
|
}
|
||||||
|
bufferSize := max(mtu, minMTU)
|
||||||
netmask, err := iface.IPMask()
|
netmask, err := iface.IPMask()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -202,7 +201,7 @@ func NewHTTPTapServer(iface Interface, queueOut, queueIn int) (*HTTPTapServer, e
|
|||||||
taps := &HTTPTapServer{
|
taps := &HTTPTapServer{
|
||||||
router: sv,
|
router: sv,
|
||||||
tap: iface,
|
tap: iface,
|
||||||
buf: make([]byte, mtu),
|
buf: make([]byte, bufferSize),
|
||||||
}
|
}
|
||||||
sv.HandleFunc("/send", func(w http.ResponseWriter, r *http.Request) {
|
sv.HandleFunc("/send", func(w http.ResponseWriter, r *http.Request) {
|
||||||
retries := 10
|
retries := 10
|
||||||
|
|||||||
Reference in New Issue
Block a user