mirror of
https://github.com/soypat/lneto.git
synced 2026-08-10 09:53:44 +00:00
dhcp working!
This commit is contained in:
+25
-22
@@ -19,6 +19,7 @@ type Client struct {
|
||||
hostname []byte
|
||||
dns [][4]byte
|
||||
|
||||
svIPtos ipv4.ToS
|
||||
tRenew uint32
|
||||
tRebind uint32
|
||||
tIPLease uint32
|
||||
@@ -73,26 +74,16 @@ func (c *Client) setIP(b []byte, frameOffset int) {
|
||||
ifrm, _ := ipv4.NewFrame(b)
|
||||
ifrm.SetID((uint16(c.currentXID) ^ uint16(c.currentXID>>16)) + uint16(c.state))
|
||||
if c.state > StateInit {
|
||||
// TODO(soypat): Document why disabling ToS used by DHCP server may cause Request to fail.
|
||||
// Apparently server sets ToS=192. Uncommenting this line causes DHCP to fail on my setup.
|
||||
// If left fixed at 192, DHCP does not work.
|
||||
// If left fixed at 0, DHCP does not work.
|
||||
// Apparently ToS is a function of which state of DHCP one is in. Not sure why code below works.
|
||||
// Note: Not exactly needed for all servers.
|
||||
const ecnmask = 0b1100_0000
|
||||
ifrm.SetToS(ecnmask)
|
||||
// Match server ToS since some routers drop DHCP requests if no ToS set apparently?
|
||||
ifrm.SetToS(c.svIPtos)
|
||||
}
|
||||
src := ifrm.SourceAddr()
|
||||
for i := range src {
|
||||
src[i] = 0
|
||||
}
|
||||
dst := ifrm.DestinationAddr()[:]
|
||||
if c.svip == ([4]byte{}) {
|
||||
for i := range dst {
|
||||
dst[i] = 255
|
||||
}
|
||||
} else {
|
||||
copy(dst, c.svip[:])
|
||||
for i := range dst {
|
||||
dst[i] = 255
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +94,8 @@ func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error)
|
||||
return 0, nil // No offer received yet.
|
||||
} else if c.state == StateBound {
|
||||
return 0, nil // Done!
|
||||
} else if c.state == StateRequesting {
|
||||
return 0, nil // Currently awaiting ACK.
|
||||
}
|
||||
dst := carrierFrame[frameOffset:]
|
||||
frm, err := NewFrame(dst)
|
||||
@@ -149,7 +142,7 @@ func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error)
|
||||
nextState = StateRequesting
|
||||
|
||||
default:
|
||||
return 0, errors.New("unhandled state")
|
||||
return 0, errors.New("unhandled state" + c.state.String())
|
||||
}
|
||||
n, _ := EncodeOption(opts[numOpts:], OptClientIdentifier, c.clientMAC[:]...)
|
||||
numOpts += n
|
||||
@@ -166,10 +159,11 @@ func (c *Client) Encapsulate(carrierFrame []byte, frameOffset int) (int, error)
|
||||
c.setHeader(frm)
|
||||
c.setIP(carrierFrame, frameOffset)
|
||||
c.state = nextState
|
||||
return optionsOffset + numOpts, nil
|
||||
return OptionsOffset + numOpts, nil
|
||||
}
|
||||
|
||||
func (c *Client) Demux(carrierData []byte, frameOffset int) error {
|
||||
fmt.Println("DEMUX DHCP")
|
||||
if c.isClosed() {
|
||||
return net.ErrClosed
|
||||
}
|
||||
@@ -212,13 +206,17 @@ func (c *Client) Demux(carrierData []byte, frameOffset int) error {
|
||||
default:
|
||||
return fmt.Errorf("dcpv4 unexpected state in recv %s", c.state.String())
|
||||
}
|
||||
if frameOffset > 28 && c.svIPtos == 0 {
|
||||
ifrm, _ := ipv4.NewFrame(carrierData)
|
||||
c.svIPtos = ifrm.ToS()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) getMessageType(frm Frame) MessageType {
|
||||
c.auxbuf[0] = 255
|
||||
ptrMsgType := &c.auxbuf[0]
|
||||
frm.ForEachOption(func(opt OptNum, data []byte) error {
|
||||
frm.ForEachOption(func(_ int, opt OptNum, data []byte) error {
|
||||
if len(data) == 1 {
|
||||
*ptrMsgType = data[0]
|
||||
return io.EOF
|
||||
@@ -229,7 +227,7 @@ func (c *Client) getMessageType(frm Frame) MessageType {
|
||||
}
|
||||
|
||||
func (c *Client) setOptions(frm Frame) error {
|
||||
return frm.ForEachOption(func(opt OptNum, data []byte) error {
|
||||
err := frm.ForEachOption(func(_ int, opt OptNum, data []byte) error {
|
||||
switch opt {
|
||||
case OptRenewTimeValue:
|
||||
c.tRenew = maybeU32(data)
|
||||
@@ -237,7 +235,6 @@ func (c *Client) setOptions(frm Frame) error {
|
||||
c.tIPLease = maybeU32(data)
|
||||
case OptRebindingTimeValue:
|
||||
c.tRebind = maybeU32(data)
|
||||
|
||||
case OptServerIdentification:
|
||||
c.svip = maybe4byte(data)
|
||||
case OptRouter:
|
||||
@@ -261,6 +258,7 @@ func (c *Client) setOptions(frm Frame) error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Client) isClosed() bool { return c.state == 0 || c.currentXID == 0 }
|
||||
@@ -272,16 +270,21 @@ func (c *Client) setHeader(frm Frame) {
|
||||
frm.SetHardware(1, 6, 0)
|
||||
frm.SetSecs(1)
|
||||
if c.state.HasIP() {
|
||||
copy(frm.CIAddr()[:], c.offer[:])
|
||||
*frm.CIAddr() = c.offer
|
||||
}
|
||||
if c.state == StateInit {
|
||||
siaddr := frm.SIAddr()[:]
|
||||
for i := range siaddr {
|
||||
siaddr[i] = 255
|
||||
}
|
||||
} else {
|
||||
if c.siip == [4]byte{} {
|
||||
*frm.SIAddr() = c.svip
|
||||
} else {
|
||||
*frm.SIAddr() = c.siip
|
||||
}
|
||||
}
|
||||
|
||||
copy(frm.YIAddr()[:], c.offer[:])
|
||||
*frm.YIAddr() = c.offer
|
||||
copy(frm.CHAddrAs6()[:], c.clientMAC[:])
|
||||
frm.SetMagicCookie(MagicCookie)
|
||||
}
|
||||
|
||||
+27
-13
@@ -98,13 +98,18 @@ func TestExample(t *testing.T) {
|
||||
Hostname: clientHostname,
|
||||
})
|
||||
buf := make([]byte, 2048)
|
||||
buf2 := make([]byte, len(buf))
|
||||
n, err := cl.Encapsulate(buf, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n <= 0 {
|
||||
t.Fatal("no data sent out by client after starting request")
|
||||
}
|
||||
|
||||
n, err = cl.Encapsulate(buf2, 0)
|
||||
if err != nil {
|
||||
t.Error("client encaps double tap after discover:", err)
|
||||
}
|
||||
// Fabricate server OFFER response.
|
||||
dfrm, _ := NewFrame(buf)
|
||||
dfrm.ClearHeader()
|
||||
dfrm.SetOp(OpReply)
|
||||
@@ -116,27 +121,36 @@ func TestExample(t *testing.T) {
|
||||
copy(dfrm.CHAddr()[:], clientHwaddr[:])
|
||||
dfrm.SetMagicCookie(MagicCookie)
|
||||
ntot := 0
|
||||
nopt, _ := EncodeOption(buf[optionsOffset+ntot:], OptMessageType, byte(MsgOffer))
|
||||
nopt, _ := EncodeOption(buf[OptionsOffset+ntot:], OptMessageType, byte(MsgOffer))
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptServerIdentification, serverIP[:]...)
|
||||
nopt, _ = EncodeOption(buf[OptionsOffset+ntot:], OptServerIdentification, serverIP[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption32(buf[optionsOffset+ntot:], OptServerIdentification, offerLease)
|
||||
nopt, _ = EncodeOption32(buf[OptionsOffset+ntot:], OptServerIdentification, offerLease)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptSubnetMask, subnetMask[:]...)
|
||||
nopt, _ = EncodeOption(buf[OptionsOffset+ntot:], OptSubnetMask, subnetMask[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptRouter, routerAddr[:]...)
|
||||
nopt, _ = EncodeOption(buf[OptionsOffset+ntot:], OptRouter, routerAddr[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptDNSServers, dnsAddr[:]...)
|
||||
nopt, _ = EncodeOption(buf[OptionsOffset+ntot:], OptDNSServers, dnsAddr[:]...)
|
||||
ntot += nopt
|
||||
nopt, _ = EncodeOption(buf[optionsOffset+ntot:], OptEnd, dnsAddr[:]...)
|
||||
nopt, _ = EncodeOption(buf[OptionsOffset+ntot:], OptEnd, dnsAddr[:]...)
|
||||
ntot += nopt
|
||||
|
||||
err = cl.Demux(buf[:optionsOffset+ntot], 0)
|
||||
err = cl.Demux(buf[:OptionsOffset+ntot], 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// frame := buf[:optionsOffset]
|
||||
// frame = AppendOption(frame, OptMessageType, byte(MsgOffer))
|
||||
// frame = AppendOption(frame, OptServerIdentification, serverIP[:]...)
|
||||
// frame = AppendOption(frame, OptIPAddressLeaseTime, serverIP[:]...)
|
||||
|
||||
n, err = cl.Encapsulate(buf[:], 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
} else if n <= 0 {
|
||||
t.Fatal("no data written from client in response to offer")
|
||||
}
|
||||
n, err = cl.Encapsulate(buf[:], 0)
|
||||
if err != nil {
|
||||
t.Error("encapsulate double tap after request:", err)
|
||||
} else if n > 0 {
|
||||
t.Error("encapsulate double tap got data!", n)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-7
@@ -17,7 +17,7 @@ const (
|
||||
// Expected Magic Cookie value.
|
||||
MagicCookie uint32 = 0x63825363
|
||||
// DHCP Options offset measured from the start of the UDP payload.
|
||||
optionsOffset = magicCookieOffset + 4
|
||||
OptionsOffset = magicCookieOffset + 4
|
||||
|
||||
DefaultClientPort = 68
|
||||
DefaultServerPort = 67
|
||||
@@ -26,12 +26,16 @@ const (
|
||||
// NewFrame returns a new DHCPv4 Frame with data set to buf.
|
||||
// An error is returned if the buffer size is smaller than 240.
|
||||
func NewFrame(buf []byte) (Frame, error) {
|
||||
if len(buf) < optionsOffset {
|
||||
if len(buf) < OptionsOffset {
|
||||
return Frame{}, errSmallFrame
|
||||
}
|
||||
return Frame{buf: buf}, nil
|
||||
}
|
||||
|
||||
func PayloadIsDHCPv4(payload []byte) bool {
|
||||
return len(payload) >= OptionsOffset && binary.BigEndian.Uint32(payload[magicCookieOffset:]) == MagicCookie
|
||||
}
|
||||
|
||||
// Frame encapsulates the raw data of a DHCP packet
|
||||
// and provides methods for manipulating, validating and
|
||||
// retrieving fields and payload data. See [RFC2131].
|
||||
@@ -43,7 +47,7 @@ type Frame struct {
|
||||
|
||||
// OptionsPayload returns the options portion of the DHCP frame. May be zero lengthed.
|
||||
func (frm Frame) OptionsPayload() []byte {
|
||||
return frm.buf[optionsOffset:]
|
||||
return frm.buf[OptionsOffset:]
|
||||
}
|
||||
|
||||
func (frm Frame) Op() Op { return Op(frm.buf[0]) }
|
||||
@@ -111,16 +115,16 @@ func (frm Frame) SetMagicCookie(cookie uint32) {
|
||||
|
||||
// ClearHeader zeros out the header contents.
|
||||
func (frm Frame) ClearHeader() {
|
||||
for i := range frm.buf[:optionsOffset] {
|
||||
for i := range frm.buf[:OptionsOffset] {
|
||||
frm.buf[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// ForEachOption iterates over all DHCPv4 options returning an error on a malformed option or when user provided callback returns an error.
|
||||
// If the user provided callback is nil then only option buffer validation is performed.
|
||||
func (frm Frame) ForEachOption(fn func(op OptNum, data []byte) error) error {
|
||||
func (frm Frame) ForEachOption(fn func(off int, op OptNum, data []byte) error) error {
|
||||
// Parse DHCP options.
|
||||
ptr := optionsOffset
|
||||
ptr := OptionsOffset
|
||||
if ptr > len(frm.buf) {
|
||||
return errSmallFrame
|
||||
} else if len(frm.buf[ptr:]) == 0 {
|
||||
@@ -141,7 +145,7 @@ func (frm Frame) ForEachOption(fn func(op OptNum, data []byte) error) error {
|
||||
optlen := frm.buf[ptr+1]
|
||||
if callback {
|
||||
optionData := frm.buf[ptr+2 : ptr+2+int(optlen)]
|
||||
if err := fn(optnum, optionData); err != nil {
|
||||
if err := fn(ptr, optnum, optionData); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -77,7 +77,7 @@ func (sv *Server) Demux(carrierData []byte, frameOffset int) error {
|
||||
var reqlist []byte
|
||||
var reqAddr []byte
|
||||
var hostname []byte
|
||||
err = dfrm.ForEachOption(func(op OptNum, data []byte) error {
|
||||
err = dfrm.ForEachOption(func(off int, op OptNum, data []byte) error {
|
||||
switch op {
|
||||
case OptMessageType:
|
||||
if len(data) == 1 {
|
||||
@@ -231,7 +231,7 @@ func (sv *Server) Encapsulate(carrierData []byte, frameOffset int) (int, error)
|
||||
// Set server state.
|
||||
sv.hosts[clientID] = client
|
||||
sv.pending--
|
||||
return optionsOffset + nopt, nil
|
||||
return OptionsOffset + nopt, nil
|
||||
}
|
||||
|
||||
func (sv *Server) getClient(clientID [36]byte) (serverEntry, bool) {
|
||||
|
||||
+27
-17
@@ -6,6 +6,7 @@ import (
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
@@ -89,7 +90,7 @@ func run() (err error) {
|
||||
}
|
||||
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))
|
||||
err = stack.Reset(brHW, netip.AddrFrom4([4]byte{}), uint16(mtu))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -97,9 +98,7 @@ func run() (err error) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var shark pcap.PacketBreakdown
|
||||
buf := make([]byte, mtu)
|
||||
var iframes []pcap.Frame
|
||||
lastAction := time.Now()
|
||||
dnsOngoing := false
|
||||
for {
|
||||
@@ -126,12 +125,6 @@ func run() (err error) {
|
||||
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 := iface.Write(buf[:nwrite])
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -145,12 +138,6 @@ func run() (err error) {
|
||||
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)
|
||||
@@ -174,14 +161,36 @@ type Stack struct {
|
||||
dhcp dhcpv4.Client
|
||||
dns dns.Client
|
||||
lookup dns.Message
|
||||
|
||||
// Packet capture and top level filtering.
|
||||
shark pcap.PacketBreakdown
|
||||
aux []pcap.Frame
|
||||
}
|
||||
|
||||
func (s *Stack) Demux(b []byte, _ int) error {
|
||||
func (s *Stack) Demux(b []byte, _ int) (err error) {
|
||||
s.aux, err = s.shark.CaptureEthernet(s.aux[:0], b, 0)
|
||||
if s.aux[len(s.aux)-1].Protocol != "DHCPv4" {
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Println("IN", s.aux, err.Error())
|
||||
} else {
|
||||
fmt.Println("IN", s.aux)
|
||||
}
|
||||
return s.link.Demux(b, 0)
|
||||
}
|
||||
|
||||
func (s *Stack) Encapsulate(b []byte, _ int) (int, error) {
|
||||
return s.link.Encapsulate(b, 0)
|
||||
n, err := s.link.Encapsulate(b, 0)
|
||||
if n > 0 {
|
||||
iframes, errpcap := s.shark.CaptureEthernet(s.aux[:0], b[:n], 0)
|
||||
if errpcap != nil {
|
||||
fmt.Println("OU", iframes, errpcap.Error())
|
||||
} else {
|
||||
fmt.Println("OU", iframes)
|
||||
}
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (s *Stack) Reset(mac [6]byte, addr netip.Addr, mtu uint16) error {
|
||||
@@ -227,6 +236,7 @@ func (s *Stack) Reset(mac [6]byte, addr netip.Addr, mtu uint16) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.ip.SetLogger(slog.Default())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+126
-2
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user