mirror of
https://github.com/soypat/lneto.git
synced 2026-08-17 21:24:04 +00:00
huge tap/bridge overhaul; udp node; dhcp node; DHCP example
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/arp"
|
||||
"github.com/soypat/lneto/dhcpv4"
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/internal/ltesto"
|
||||
"github.com/soypat/lneto/internet"
|
||||
"github.com/soypat/lneto/internet/pcap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := run()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("success")
|
||||
}
|
||||
|
||||
func run() (err error) {
|
||||
br := ltesto.NewHTTPTapClient("http://127.0.0.1:7070")
|
||||
defer br.Close()
|
||||
|
||||
nicHW := br.HardwareAddr6()
|
||||
|
||||
brHW := nicHW
|
||||
brHW[5]++ // We'll be using a similar HW address but with NIC specific identifier modified.
|
||||
mtu := br.MTU()
|
||||
nicAddr := br.IPPrefix()
|
||||
|
||||
fmt.Println("NIC hardware address:", net.HardwareAddr(nicHW[:]).String(), "bridgeHW:", net.HardwareAddr(brHW[:]).String(), "mtu:", mtu, "addr:", nicAddr.String())
|
||||
var stack Stack
|
||||
err = stack.Reset(brHW, nicAddr.Addr().Next(), uint16(mtu))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = stack.BeginDHCPRequest()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var shark pcap.PacketBreakdown
|
||||
buf := make([]byte, mtu)
|
||||
var iframes []pcap.Frame
|
||||
lastAction := time.Now()
|
||||
for {
|
||||
clear(buf)
|
||||
nwrite, err := stack.Encapsulate(buf[:], 0)
|
||||
if err != nil {
|
||||
fmt.Println("ERR:ENCAPSULATE", err)
|
||||
} else if nwrite > 0 {
|
||||
iframes, err = shark.CaptureEthernet(iframes[:0], buf[:nwrite], 0)
|
||||
if err != nil {
|
||||
fmt.Println("OU", iframes, err.Error())
|
||||
} else {
|
||||
fmt.Println("OU", iframes)
|
||||
}
|
||||
n, err := br.Write(buf[:nwrite])
|
||||
if err != nil {
|
||||
return err
|
||||
} else if n != nwrite {
|
||||
return fmt.Errorf("mismatch written bytes %d!=%d", nwrite, n)
|
||||
}
|
||||
}
|
||||
|
||||
clear(buf)
|
||||
nread, err := br.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if nread > 0 {
|
||||
iframes, err = shark.CaptureEthernet(iframes[:0], buf[:nread], 0)
|
||||
if err != nil {
|
||||
fmt.Println("IN", iframes, err.Error())
|
||||
} else {
|
||||
fmt.Println("IN", iframes)
|
||||
}
|
||||
err = stack.Demux(buf[:nread], 0)
|
||||
if err != nil {
|
||||
fmt.Println("ERR:DEMUX", err)
|
||||
}
|
||||
}
|
||||
|
||||
if nread == 0 && nwrite == 0 && time.Since(lastAction) > 4*time.Second {
|
||||
time.Sleep(5 * time.Millisecond)
|
||||
} else {
|
||||
lastAction = time.Now()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Stack struct {
|
||||
link internet.StackEthernet
|
||||
ip internet.StackIP
|
||||
arp internet.NodeARP
|
||||
udps internet.StackPorts
|
||||
dhcp dhcpv4.Client
|
||||
}
|
||||
|
||||
func (s *Stack) Demux(b []byte, _ int) error {
|
||||
return s.link.Demux(b, 0)
|
||||
}
|
||||
|
||||
func (s *Stack) Encapsulate(b []byte, _ int) (int, error) {
|
||||
return s.link.Encapsulate(b, 0)
|
||||
}
|
||||
|
||||
func (s *Stack) Reset(mac [6]byte, addr netip.Addr, mtu uint16) error {
|
||||
err := s.link.Reset6(mac, ethernet.BroadcastAddr(), int(mtu))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.ip.Reset(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ipaddr := addr.AsSlice()
|
||||
proto := ethernet.TypeIPv4
|
||||
if addr.Is6() {
|
||||
proto = ethernet.TypeIPv6
|
||||
}
|
||||
err = s.arp.Reset(arp.HandlerConfig{
|
||||
HardwareAddr: mac[:],
|
||||
ProtocolAddr: ipaddr,
|
||||
MaxQueries: 3,
|
||||
MaxPending: 3,
|
||||
HardwareType: 1,
|
||||
ProtocolType: proto,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.udps.Reset(uint64(lneto.IPProtoUDP), 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Now setup stacks.
|
||||
err = s.link.Register(&s.arp) // ARP.
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.link.Register(&s.ip) // IPv4 | IPv6
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = s.ip.Register(&s.udps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Stack) BeginDHCPRequest() error {
|
||||
addr4 := s.ip.Addr().As4()
|
||||
var buf [4]byte
|
||||
rand.Read(buf[:])
|
||||
xid := binary.LittleEndian.Uint32(buf[:])
|
||||
err := s.dhcp.BeginRequest(xid, dhcpv4.RequestConfig{
|
||||
RequestedAddr: addr4,
|
||||
ClientHardwareAddr: s.link.HardwareAddr6(),
|
||||
Hostname: "lneto",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var u internet.StackUDPPort
|
||||
u.SetStackNode(&s.dhcp, dhcpv4.DefaultServerPort)
|
||||
err = s.udps.Register(&u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func clear(buf []byte) {
|
||||
for i := range buf {
|
||||
buf[i] = 0
|
||||
}
|
||||
}
|
||||
+41
-12
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
@@ -9,9 +10,11 @@ import (
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"runtime"
|
||||
"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"
|
||||
@@ -27,17 +30,35 @@ func main() {
|
||||
}
|
||||
|
||||
func run() error {
|
||||
var (
|
||||
flagInterface = "tap0"
|
||||
)
|
||||
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'")
|
||||
var (
|
||||
flagNet = "192.168.10.1/24"
|
||||
flagiface = "tap0"
|
||||
flagMTU = 1500
|
||||
flagPacketQueueSize = 2048
|
||||
)
|
||||
ip, err := netip.ParsePrefix(flagNet)
|
||||
if err != nil {
|
||||
return err
|
||||
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
|
||||
}
|
||||
sv, err := ltesto.NewHTTPTapServer(flagiface, ip, flagMTU, flagPacketQueueSize, flagPacketQueueSize)
|
||||
|
||||
sv, err := ltesto.NewHTTPTapServer(iface, flagPacketQueueSize, flagPacketQueueSize)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -48,8 +69,12 @@ func run() error {
|
||||
frames, err := cap.CaptureEthernet(nil, pkt, 0)
|
||||
if err == nil {
|
||||
flags, src, dst := getTCPData(frames, pkt)
|
||||
if flags != 0 {
|
||||
fmt.Println(channel, captime.Format("15:04:05.000"), frames, flags.String(), src, "->", dst)
|
||||
if src != 0 {
|
||||
if flags != 0 {
|
||||
fmt.Println(channel, captime.Format("15:04:05.000"), frames, flags.String(), src, "->", dst)
|
||||
} else {
|
||||
fmt.Println(channel, captime.Format("15:04:05.000"), frames, src, "->", dst)
|
||||
}
|
||||
} else {
|
||||
fmt.Println(channel, captime.Format("15:04:05.000"), frames)
|
||||
}
|
||||
@@ -86,12 +111,16 @@ func run() error {
|
||||
|
||||
func getTCPData(frames []pcap.Frame, pkt []byte) (flags tcp.Flags, src, dst uint16) {
|
||||
for i := range frames {
|
||||
if frames[i].Protocol != lneto.IPProtoTCP {
|
||||
continue
|
||||
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 tcp.Flags(getFrameClassUint(frames[i], pkt, pcap.FieldClassFlags)),
|
||||
uint16(getFrameClassUint(frames[i], pkt, pcap.FieldClassSrc)),
|
||||
uint16(getFrameClassUint(frames[i], pkt, pcap.FieldClassDst))
|
||||
}
|
||||
return 0, 0, 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user