Files
lneto/examples/httptap/main.go
T
Pat Whittingslow a2970b923d add ipv6 to xnet.StackAsync (#107)
* add ipv6 to xnet.StackAsync

* dns improvements

* improve DNS workings of StackAsync

* add tentative ICMPv6

* work on prefixes and fix some small bugs, plan UDP/TCP6

* fix bugs in StackAsync and ipv4.Prefix.Contains

* update arpsubtable

* completely remove legacy internet.StackIP for StackIPv4/v6

* ipv4/ipv6 tcp/udp

* add TCP6/UDP6 dialing APIs

* add xnet.Stack6 interface

* more ipv6 integration into StackAsync; various tweaks to lneto and documentation+TODOs

* add stack6 tests

* replace netip.Prefix with ipv4.Prefix where it makes sense
2026-05-13 15:31:18 -03:00

124 lines
3.1 KiB
Go

//go:build !tinygo && linux
package main
import (
"errors"
"flag"
"fmt"
"log"
"math"
"net"
"net/http"
"net/netip"
"strconv"
"strings"
"time"
"github.com/soypat/lneto/internal"
"github.com/soypat/lneto/internal/ltesto"
"github.com/soypat/lneto/internet/pcap"
"github.com/soypat/lneto/ipv4"
)
func main() {
err := run()
if err != nil {
log.Fatalln("failed:", err)
}
fmt.Println("finished")
}
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"
flagPacketQueueSize = 2048
)
var iface ltesto.Interface
if strings.HasPrefix(flagInterface, "tap") {
pfx, err := netip.ParsePrefix(flagNet)
if err != nil {
return err
}
tap, err := internal.NewTap(flagiface, pfx)
if err != nil {
return err
}
iface = tap
} else {
br, err := internal.NewBridge(flagInterface)
if err != nil {
return err
}
iface = br
}
// Wrap interface with DHCP server interceptor.
hwaddr, err := iface.HardwareAddress6()
if err != nil {
return err
}
ipMask, err := iface.IPMask()
if err != nil {
return err
}
svIP := ipMask.Addr().As4()
subnet := ipv4.PrefixFromNetip(ipMask)
iface, err = newDHCPInterceptor(iface, svIP, hwaddr, subnet.Masked())
if err != nil {
return fmt.Errorf("DHCP interceptor: %w", err)
}
sv, err := ltesto.NewHTTPTapServer(iface, flagMinMTU, flagPacketQueueSize, flagPacketQueueSize)
if err != nil {
return err
}
defer sv.Close()
var cap pcap.PacketBreakdown
cap.SubfieldLimit = 30 // For big DNS or DHCP.
pf := pcap.Formatter{
FilterClasses: []pcap.FieldClass{pcap.FieldClassDst, pcap.FieldClassSrc, pcap.FieldClassSize, pcap.FieldClassFlags, pcap.FieldClassDNSName},
}
var pfbuf []byte
sv.OnTransfer(func(channel int, pkt []byte) {
channelstr := "OS"
if channel != 0 {
channelstr = strconv.Itoa(channel) // Will not allocate for values 99 and under (stdlib).
}
captime := time.Now()
frames, err := cap.CaptureEthernet(nil, pkt, 0)
if err == nil {
pfbuf = append(pfbuf[:0], '[')
pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt)
pfbuf = append(pfbuf, ']')
if err != nil {
fmt.Printf("%-2s %s !err:%s\n", channelstr, captime.Format("15:04:05.000"), err)
} else {
fmt.Printf("%-2s %s %s\n", channelstr, captime.Format("15:04:05.000"), pfbuf)
}
} else {
fmt.Printf("%-2s %s %s %v %s\n", channelstr, captime.Format("15:04:05.000"), "cap ERR", frames, err.Error())
}
})
hwaddr, err = sv.HardwareAddress6()
if err != nil {
return err
}
fmt.Println("listening on http://127.0.0.1:7070/recv and http://127.0.0.1:7070/send on hwaddr:", net.HardwareAddr(hwaddr[:]).String())
http.ListenAndServe(":7070", sv)
return errors.New("finished")
}