dhcp working!

This commit is contained in:
soypat
2025-07-09 16:54:48 -03:00
parent 9c0e250cf6
commit 489e9951fa
10 changed files with 228 additions and 69 deletions
+126 -2
View File
@@ -9,6 +9,7 @@ import (
"github.com/soypat/lneto"
"github.com/soypat/lneto/arp"
"github.com/soypat/lneto/dhcpv4"
"github.com/soypat/lneto/ethernet"
"github.com/soypat/lneto/http/httpraw"
"github.com/soypat/lneto/ipv4"
@@ -238,7 +239,6 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
}
}
return pc.captureIPProto(proto, dst, pkt, end, protoErrs...)
}
func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt []byte, bitOffset int, ipProtoErrs ...error) (_ []Frame, err error) {
@@ -321,7 +321,49 @@ func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([
finfo.Fields = append(finfo.Fields, baseUDPFields[:]...)
dst = append(dst, finfo)
end := bitOffset + 8*octet
dst = append(dst, remainingFrameInfo(unknownPayloadProto, FieldClassPayload, end, octet*len(pkt)))
payload := ufrm.Payload()
if dhcpv4.PayloadIsDHCPv4(payload) {
return pc.CaptureDHCPv4(dst, pkt, end)
} else {
dst = append(dst, remainingFrameInfo(unknownPayloadProto, FieldClassPayload, end, octet*len(pkt)))
}
return dst, nil
}
func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
if bitOffset%8 != 0 {
return nil, errors.New("DHCP must be parsed at byte boundary")
}
dhcpData := pkt[bitOffset/8:]
dfrm, err := dhcpv4.NewFrame(dhcpData)
if err != nil {
return nil, err
}
finfo := Frame{
Protocol: "DHCPv4",
PacketBitOffset: bitOffset,
}
magic := dfrm.MagicCookie()
if magic != dhcpv4.MagicCookie {
finfo.Errors = append(finfo.Errors, errors.New("incorrect DHCPv4 magic cookie"))
}
finfo.Fields = append(finfo.Fields, baseDHCPv4Fields[:]...)
options := dfrm.OptionsPayload()
if len(options) > 0 {
err = dfrm.ForEachOption(func(optoff int, op dhcpv4.OptNum, data []byte) error {
finfo.Fields = append(finfo.Fields, FrameField{
Name: op.String(),
Class: FieldClassOptions,
FrameBitOffset: optoff * octet,
BitLength: (2 + len(data)) * octet,
})
return nil
})
if err != nil {
finfo.Errors = append(finfo.Errors, err)
}
}
dst = append(dst, finfo)
return dst, nil
}
@@ -547,6 +589,7 @@ const (
FieldClassOptions // options
FieldClassPayload // payload
FieldClassText // text
FieldClassAddress // address
)
const octet = 8
@@ -799,6 +842,87 @@ var baseUDPFields = [...]FrameField{
},
}
var baseDHCPv4Fields = [...]FrameField{
{
Name: "Opcode",
Class: FieldClassType,
FrameBitOffset: 0,
BitLength: 1 * octet,
},
{
Name: "Hardware Address Type",
Class: FieldClassProto,
FrameBitOffset: 1 * octet,
BitLength: 1 * octet,
},
{
Name: "Hardware Address Length",
Class: FieldClassSize,
FrameBitOffset: 2 * octet,
BitLength: 1 * octet,
},
{
Name: "Hops",
Class: fieldClassUndefined,
FrameBitOffset: 3 * octet,
BitLength: 1 * octet,
},
{
Name: "Transaction ID",
Class: FieldClassID,
FrameBitOffset: 4 * octet,
BitLength: 4 * octet,
},
{
Name: "Start Time",
Class: fieldClassUndefined,
FrameBitOffset: 8 * octet,
BitLength: 2 * octet,
},
{
Name: "Flags",
Class: FieldClassFlags,
FrameBitOffset: 10 * octet,
BitLength: 2 * octet,
},
{
Name: "Client Address",
Class: FieldClassAddress,
FrameBitOffset: 12 * octet,
BitLength: 4 * octet,
},
{
Name: "Offered Address",
Class: FieldClassAddress,
FrameBitOffset: 16 * octet,
BitLength: 4 * octet,
},
{
Name: "Server Next Address",
Class: FieldClassAddress,
FrameBitOffset: 20 * octet,
BitLength: 4 * octet,
},
{
Name: "Relay Agent Address",
Class: FieldClassAddress,
FrameBitOffset: 24 * octet,
BitLength: 4 * octet,
},
{
Name: "Client Hardware Address",
Class: FieldClassAddress,
FrameBitOffset: 28 * octet,
BitLength: 16 * octet,
},
{
Name: "BOOTP",
Class: FieldClassAddress,
FrameBitOffset: (28 + 16) * octet,
BitLength: (dhcpv4.OptionsOffset - (28 + 16)) * octet,
},
}
func remainingFrameInfo(proto any, class FieldClass, pktBitOffset, pktBitLen int) Frame {
return Frame{
Protocol: proto,
+1 -1
View File
@@ -100,7 +100,7 @@ func (ls *StackEthernet) Demux(carrierData []byte, frameOffset int) (err error)
}
DROP:
ls.info("LinkStack:drop-packet", slog.String("dsthw", net.HardwareAddr(dstaddr[:]).String()), slog.String("ethertype", efrm.EtherTypeOrSize().String()))
return nil
return errors.New("drop packet")
}
func (ls *StackEthernet) Encapsulate(carrierData []byte, frameOffset int) (n int, err error) {
+7 -3
View File
@@ -64,6 +64,10 @@ func (sb *StackIP) Addr() netip.Addr {
return netip.AddrFrom4(sb.ip)
}
func (sb *StackIP) SetLogger(logger *slog.Logger) {
sb.logger.log = logger
}
func (sb *StackIP) Demux(carrierData []byte, offset int) error {
sb.info("StackIP.Demux:start")
frame := carrierData[offset:] // we don't care about carrier data in IP.
@@ -72,8 +76,8 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error {
return err
}
dst := ifrm.DestinationAddr()
if *dst != sb.ip {
return nil // Not meant for us.
if sb.ip != ([4]byte{}) && *dst != sb.ip {
return errors.New("not meant for us") // Not meant for us.
}
sb.validator.ResetErr()
@@ -155,7 +159,7 @@ func (sb *StackIP) Encapsulate(carrierData []byte, frameOffset int) (int, error)
println("NODE REMOVED", proto.String(), h.port)
h.destroy()
}
sb.error("StackIP:handle", slog.String("proto", proto.String()), slog.String("err", err.Error()))
sb.error("StackIP:encapsulate", slog.String("proto", proto.String()), slog.String("err", err.Error()))
continue
} else if n == 0 {
continue
+1 -1
View File
@@ -74,7 +74,7 @@ func (sudp *StackUDPPort) Encapsulate(carrierData []byte, frameOffset int) (int,
n, err := sudp.h.encapsulate(carrierData, frameOffset+8)
if n == 0 {
if err != nil {
slog.Error("stackudp:demux", slog.String("err", err.Error()))
slog.Error("stackudp:encapsulate", slog.String("err", err.Error()))
}
return 0, err
}
+1 -1
View File
@@ -46,7 +46,7 @@ func expectExchange(t *testing.T, from, to *StackIP, buf []byte) {
t.Helper()
n, err := from.Encapsulate(buf, 0)
if err != nil {
t.Error("expectExchange:Handle:", err)
t.Error("expectExchange:encapsulate:", err)
} else if n == 0 {
t.Error("expected data exchange")
return