From 059f761856bca9afe82ef2db01b757b85a32dc37 Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Wed, 17 Jun 2026 16:42:38 -0300 Subject: [PATCH] CapturePrinter expose Ethernet and IP printers --- examples/min-working-example/main-mwe.go | 4 ++-- x/xnet/pcap-printer.go | 29 ++++++++++++++++++++++-- x/xnet/xnet_debug_pcap.go | 2 +- x/xnet/xnet_fuzz_test.go | 12 +++++----- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/examples/min-working-example/main-mwe.go b/examples/min-working-example/main-mwe.go index ea8fb19..722e6c6 100644 --- a/examples/min-working-example/main-mwe.go +++ b/examples/min-working-example/main-mwe.go @@ -148,7 +148,7 @@ func stackLoop(ctx context.Context, stack *xnet.StackAsync) { fmt.Println("encaps err:", err) } else if nwrite > 0 { network.SendEth(buf[:nwrite]) - cap.PrintPacket("OUT", buf[:nwrite]) + cap.PrintEthernet("OUT", buf[:nwrite]) } nread, err := network.RecvEth(buf[:]) if err != nil { @@ -158,7 +158,7 @@ func stackLoop(ctx context.Context, stack *xnet.StackAsync) { if err != nil && err != lneto.ErrPacketDrop { fmt.Println("demux err:", err) } else { - cap.PrintPacket("IN ", buf[:nread]) + cap.PrintEthernet("IN ", buf[:nread]) } } if nwrite == 0 && nread == 0 { diff --git a/x/xnet/pcap-printer.go b/x/xnet/pcap-printer.go index 5517782..f8a774c 100644 --- a/x/xnet/pcap-printer.go +++ b/x/xnet/pcap-printer.go @@ -5,6 +5,7 @@ import ( "strconv" "time" + "github.com/soypat/lneto" "github.com/soypat/lneto/internet/pcap" ) @@ -50,7 +51,20 @@ func (stack *CapturePrinter) Formatter() *pcap.Formatter { return &stack.pfmt } -func (stack *CapturePrinter) PrintPacket(prefix string, pkt []byte) { +// PrintIP formats and writes a breakdown of the IPv4 or IPv6 packet, prefixed by prefix. +func (stack *CapturePrinter) PrintIP(prefix string, ipPkt []byte) { + stack.printPacket(prefix, true, ipPkt) +} + +// PrintEthernet formats and writes a breakdown of the Ethernet frame, prefixed by prefix. +func (stack *CapturePrinter) PrintEthernet(prefix string, ethPkt []byte) { + stack.printPacket(prefix, false, ethPkt) +} + +func (stack *CapturePrinter) printPacket(prefix string, ip bool, pkt []byte) { + if len(pkt) == 0 { + return + } fmtbuf := stack.fmtPcapBuf[:0] useTimestamps := stack.printTimestamps() var captime time.Time @@ -58,7 +72,18 @@ func (stack *CapturePrinter) PrintPacket(prefix string, pkt []byte) { captime = stack.now() } var err error - stack.frms, err = stack.cap.CaptureEthernet(stack.frms[:0], pkt, 0) + if ip { + switch pkt[0] >> 4 { + case 4: + stack.frms, err = stack.cap.CaptureIPv4(stack.frms[:0], pkt, 0) + case 6: + stack.frms, err = stack.cap.CaptureIPv6(stack.frms[:0], pkt, 0) + default: + err = lneto.ErrUnsupported + } + } else { + stack.frms, err = stack.cap.CaptureEthernet(stack.frms[:0], pkt, 0) + } if err == nil { if useTimestamps { diff := captime.Sub(stack.origin) diff --git a/x/xnet/xnet_debug_pcap.go b/x/xnet/xnet_debug_pcap.go index c3e3df1..48d5ac5 100644 --- a/x/xnet/xnet_debug_pcap.go +++ b/x/xnet/xnet_debug_pcap.go @@ -13,5 +13,5 @@ func init() { } func debugPacket(msg string, b []byte) { - _pcap.PrintPacket(msg, b) + _pcap.PrintEthernet(msg, b) } diff --git a/x/xnet/xnet_fuzz_test.go b/x/xnet/xnet_fuzz_test.go index 43bce85..827f169 100644 --- a/x/xnet/xnet_fuzz_test.go +++ b/x/xnet/xnet_fuzz_test.go @@ -503,7 +503,7 @@ func testStackSeeded(t *testing.T, seed1, seed2 int64) { betsAreOff = true } if verbose { - fzppr.PrintPacket(first.Hostname(), buf[:n]) + fzppr.PrintEthernet(first.Hostname(), buf[:n]) } err = second.IngressEthernet(buf[:n]) if err != nil && !betsAreOff && err != lneto.ErrPacketDrop && err != lneto.ErrExhausted { @@ -524,7 +524,7 @@ func testStackSeeded(t *testing.T, seed1, seed2 int64) { betsAreOff = true } if verbose { - fzppr.PrintPacket(second.Hostname(), buf[:n]) + fzppr.PrintEthernet(second.Hostname(), buf[:n]) } err = first.IngressEthernet(buf[:n]) if err != nil && !betsAreOff && err != lneto.ErrPacketDrop && err != lneto.ErrExhausted { @@ -542,21 +542,21 @@ func testStackSeeded(t *testing.T, seed1, seed2 int64) { limit := d == drainLimit-1 n, err := first.EgressEthernet(buf[:]) if (err != nil || n > 0) && limit { - fzppr.PrintPacket(first.Hostname(), buf[:n]) + fzppr.PrintEthernet(first.Hostname(), buf[:n]) t.Fatal(i, "stuck in data/error loop:", err) } else if n > 0 { if verbose { - fzppr.PrintPacket(first.Hostname(), buf[:n]) + fzppr.PrintEthernet(first.Hostname(), buf[:n]) } second.IngressEthernet(buf[:n]) } n, err = second.EgressEthernet(buf[:]) if (err != nil || n > 0) && limit { - fzppr.PrintPacket("(2) ", buf[:n]) + fzppr.PrintEthernet("(2) ", buf[:n]) t.Fatal(i, "stuck in data/error loop:", err) } else if n > 0 { if verbose { - fzppr.PrintPacket(second.Hostname(), buf[:n]) + fzppr.PrintEthernet(second.Hostname(), buf[:n]) } first.IngressEthernet(buf[:n]) }