diff --git a/arp/handler.go b/arp/handler.go index 46753e0..e761ad1 100644 --- a/arp/handler.go +++ b/arp/handler.go @@ -9,13 +9,13 @@ import ( ) type Handler struct { - connID uint64 - ourHWAddr []byte - ourProtoAddr []byte - htype uint16 - protoType ethernet.Type - pending [][sizeHeaderv6]byte - queries []queryResult + connID uint64 + ourHWAddr []byte + ourProtoAddr []byte + htype uint16 + protoType ethernet.Type + pendingResponse [][sizeHeaderv6]byte + queries []queryResult } type HandlerConfig struct { @@ -27,29 +27,35 @@ type HandlerConfig struct { ProtocolType ethernet.Type } -func (c *Handler) Reset(cfg HandlerConfig) error { +func (h *Handler) LocalPort() uint16 { return 0 } + +func (h *Handler) Protocol() uint64 { return uint64(ethernet.TypeARP) } + +func (h *Handler) ConnectionID() *uint64 { return &h.connID } + +func (h *Handler) Reset(cfg HandlerConfig) error { if len(cfg.HardwareAddr) == 0 || len(cfg.HardwareAddr) > 255 || len(cfg.ProtocolAddr) == 0 || len(cfg.ProtocolAddr) > 255 { return errors.New("invalid Handler address config") } else if cfg.MaxQueries <= 0 || cfg.MaxPending <= 0 { return errors.New("invalid Handler query or pending config") } - *c = Handler{ - connID: c.connID + 1, - ourHWAddr: c.ourHWAddr[:0], - ourProtoAddr: c.ourProtoAddr[:0], - htype: cfg.HardwareType, - protoType: cfg.ProtocolType, - pending: c.pending[:0], - queries: c.queries[:0], + *h = Handler{ + connID: h.connID + 1, + ourHWAddr: h.ourHWAddr[:0], + ourProtoAddr: h.ourProtoAddr[:0], + htype: cfg.HardwareType, + protoType: cfg.ProtocolType, + pendingResponse: h.pendingResponse[:0], + queries: h.queries[:0], } - c.ourHWAddr = append(c.ourHWAddr, cfg.HardwareAddr...) - c.ourProtoAddr = append(c.ourProtoAddr, cfg.ProtocolAddr...) - if cap(c.pending) < cfg.MaxPending { - c.pending = make([][52]byte, cfg.MaxPending)[:0] + h.ourHWAddr = append(h.ourHWAddr, cfg.HardwareAddr...) + h.ourProtoAddr = append(h.ourProtoAddr, cfg.ProtocolAddr...) + if cap(h.pendingResponse) < cfg.MaxPending { + h.pendingResponse = make([][52]byte, cfg.MaxPending)[:0] } - if cap(c.queries) < cfg.MaxQueries { - c.queries = make([]queryResult, cfg.MaxQueries)[:0] + if cap(h.queries) < cfg.MaxQueries { + h.queries = make([]queryResult, cfg.MaxQueries)[:0] } return nil } @@ -61,88 +67,91 @@ type queryResult struct { } // AbortPending drops pending queries and incoming requests. -func (c *Handler) AbortPending() { - c.pending = c.pending[:0] - c.queries = c.queries[:0] +func (h *Handler) AbortPending() { + h.pendingResponse = h.pendingResponse[:0] + h.queries = h.queries[:0] } -func (c *Handler) expectSize() int { - return sizeHeader + 2*len(c.ourHWAddr) + 2*len(c.ourProtoAddr) +func (h *Handler) expectSize() int { + return sizeHeader + 2*len(h.ourHWAddr) + 2*len(h.ourProtoAddr) } -func (c *Handler) ConnectionID() *uint64 { - return &c.connID -} - -func (c *Handler) QueryResult(protoAddr []byte) (hwAddr []byte, err error) { - for i := range c.queries { - if bytes.Equal(protoAddr, c.queries[i].protoaddr) { - if !c.queries[i].querysent { +func (h *Handler) QueryResult(protoAddr []byte) (hwAddr []byte, err error) { + for i := range h.queries { + if bytes.Equal(protoAddr, h.queries[i].protoaddr) { + if !h.queries[i].querysent { return nil, errors.New("query not yet sent") - } else if len(c.queries[i].hwaddr) == 0 { + } else if len(h.queries[i].hwaddr) == 0 { return nil, errors.New("no response yet") } - return c.queries[i].hwaddr, nil + return h.queries[i].hwaddr, nil } } return nil, errors.New("query not exist or dropped") } -func (c *Handler) StartQuery(proto []byte) error { - if len(proto) != len(c.ourProtoAddr) { +func (h *Handler) StartQuery(proto []byte) error { + if len(proto) != len(h.ourProtoAddr) { return errors.New("bad protocol address length") - } else if len(c.queries) == cap(c.queries) { + } else if len(h.queries) == cap(h.queries) { return errors.New("too many ongoing queries") } - c.queries = c.queries[:len(c.queries)+1] - q := &c.queries[len(c.queries)-1] + h.queries = h.queries[:len(h.queries)+1] + q := &h.queries[len(h.queries)-1] q.hwaddr = q.hwaddr[:0] q.querysent = false q.protoaddr = append(q.protoaddr[:0], proto...) return nil } -func (c *Handler) Send(b []byte) (int, error) { - n := c.expectSize() +func (h *Handler) Encapsulate(eth []byte, frameOffset int) (int, error) { + b := eth[frameOffset:] + n := h.expectSize() if len(b) < n { return 0, errShortARP } - if len(c.pending) > 0 { + if len(h.pendingResponse) > 0 { // pop frame. - afrm, _ := NewFrame(c.pending[len(c.pending)-1][:]) - c.pending = c.pending[:len(c.pending)-1] + afrm, _ := NewFrame(h.pendingResponse[len(h.pendingResponse)-1][:]) + h.pendingResponse = h.pendingResponse[:len(h.pendingResponse)-1] afrm.SetOperation(OpReply) afrm.SwapTargetSender() hwsender, _ := afrm.Sender() - copy(hwsender, c.ourHWAddr) + copy(hwsender, h.ourHWAddr) n := copy(b, afrm.Clip().RawData()) + tgt, _ := afrm.Target() + trySetEthernetDst(eth[:frameOffset], tgt) return n, nil } - for i := range c.queries { - if !c.queries[i].querysent { - c.queries[i].querysent = true + for i := range h.queries { + if !h.queries[i].querysent { + h.queries[i].querysent = true afrm, _ := NewFrame(b) - afrm.SetHardware(c.htype, uint8(len(c.ourHWAddr))) - afrm.SetProtocol(c.protoType, uint8(len(c.ourProtoAddr))) + afrm.SetHardware(h.htype, uint8(len(h.ourHWAddr))) + afrm.SetProtocol(h.protoType, uint8(len(h.ourProtoAddr))) afrm.SetOperation(OpRequest) hwSender, protoSender := afrm.Sender() - copy(hwSender, c.ourHWAddr) - copy(protoSender, c.ourProtoAddr) + copy(hwSender, h.ourHWAddr) + copy(protoSender, h.ourProtoAddr) hwTarget, protoTarget := afrm.Target() - copy(protoTarget, c.queries[i].protoaddr) + copy(protoTarget, h.queries[i].protoaddr) for j := range hwTarget { hwTarget[j] = 0 } + broadcast := ethernet.BroadcastAddr() + trySetEthernetDst(eth[:frameOffset], broadcast[:]) return n, nil } } return 0, nil } -func (c *Handler) Recv(b []byte) error { - if len(c.pending) == cap(c.pending) { +func (h *Handler) Demux(ethFrame []byte, frameOffset int) error { + if len(h.pendingResponse) == cap(h.pendingResponse) { return errARPBufferFull } + + b := ethFrame[frameOffset:] afrm, err := NewFrame(b) if err != nil { return err @@ -153,27 +162,27 @@ func (c *Handler) Recv(b []byte) error { return vld.ErrPop() } htype, hlen := afrm.Hardware() - if htype != c.htype || int(hlen) != len(c.ourHWAddr) { + if htype != h.htype || int(hlen) != len(h.ourHWAddr) { return errors.New("bad ARP hardware") } protoType, protoLen := afrm.Protocol() - if protoType != c.protoType || int(protoLen) != len(c.ourProtoAddr) { + if protoType != h.protoType || int(protoLen) != len(h.ourProtoAddr) { return errors.New("bad ARP proto") } switch afrm.Operation() { case OpRequest: _, protoaddr := afrm.Target() - if !bytes.Equal(protoaddr, c.ourProtoAddr) { + if !bytes.Equal(protoaddr, h.ourProtoAddr) { return nil // Not for us. } - c.pending = c.pending[:len(c.pending)+1] // Extend pending buffer. - copy(c.pending[len(c.pending)-1][:], afrm.buf) // Set pending buffer. + h.pendingResponse = h.pendingResponse[:len(h.pendingResponse)+1] // Extend pending buffer. + copy(h.pendingResponse[len(h.pendingResponse)-1][:], afrm.buf) // Set pending buffer. case OpReply: hwaddr, protoaddr := afrm.Sender() - for i := range c.queries { - if len(c.queries[i].hwaddr) == 0 && bytes.Equal(c.queries[i].protoaddr, protoaddr) { - c.queries[i].hwaddr = append(c.queries[i].hwaddr[:0], hwaddr...) + for i := range h.queries { + if len(h.queries[i].hwaddr) == 0 && bytes.Equal(h.queries[i].protoaddr, protoaddr) { + h.queries[i].hwaddr = append(h.queries[i].hwaddr[:0], hwaddr...) return nil } } @@ -183,3 +192,9 @@ func (c *Handler) Recv(b []byte) error { } return nil } + +func trySetEthernetDst(ethFrame []byte, dst []byte) { + if len(ethFrame) > 14 { + copy(ethFrame[:6], dst) + } +} diff --git a/arp/handler_test.go b/arp/handler_test.go index d97ef6c..6b10a33 100644 --- a/arp/handler_test.go +++ b/arp/handler_test.go @@ -34,13 +34,13 @@ func TestHandler(t *testing.T) { t.Fatal(err) } var buf, discard [64]byte - n, err := c1.Send(buf[:]) + n, err := c1.Encapsulate(buf[:], 0) if err != nil { t.Fatal("error on should be nop send:", err) } else if n > 0 { t.Fatal("should not send if no query") } - n, err = c2.Send(buf[:]) + n, err = c2.Encapsulate(buf[:], 0) if err != nil { t.Fatal("error on should be nop send:", err) } else if n > 0 { @@ -54,33 +54,33 @@ func TestHandler(t *testing.T) { if err != nil { t.Fatal(err) } - n, err = c1.Send(buf[:]) // Send Request. + n, err = c1.Encapsulate(buf[:], 0) // Send Request. if err != nil { t.Fatal(err) } else if n == 0 { t.Fatal("expected send of data after first query") } validateARP(t, buf[:]) - err = c2.Recv(buf[:n]) // Receive request. + err = c2.Demux(buf[:n], 0) // Receive request. if err != nil { t.Fatal(err) } - n, err = c2.Send(buf[:]) // Send response. + n, err = c2.Encapsulate(buf[:], 0) // Send response. if err != nil { t.Fatal(err) } else if n == 0 { t.Fatal("got no response to request") } validateARP(t, buf[:]) - n, err = c2.Send(discard[:]) // Double tap check, should send nothing. + n, err = c2.Encapsulate(discard[:], 0) // Double tap check, should send nothing. if err != nil { t.Fatal("double tap send error:", err) } else if n > 0 { t.Fatal("wanted no data sent after response sent") } - err = c1.Recv(buf[:]) // Receive response. + err = c1.Demux(buf[:], 0) // Receive response. if err != nil { t.Fatal(err) } @@ -90,13 +90,13 @@ func TestHandler(t *testing.T) { } else if !bytes.Equal(hwaddr, expectHWAddr) { log.Fatalf("expected to get hwaddr %x!=%x", hwaddr, expectHWAddr) } - n, err = c1.Send(buf[:]) + n, err = c1.Encapsulate(buf[:], 0) if err != nil { t.Fatal(err) } else if n > 0 { t.Fatal("expected no data") } - n, err = c2.Send(buf[:]) + n, err = c2.Encapsulate(buf[:], 0) if err != nil { t.Fatal(err) } else if n > 0 { diff --git a/dhcpv4/client.go b/dhcpv4/client.go index 2572657..7d14553 100644 --- a/dhcpv4/client.go +++ b/dhcpv4/client.go @@ -8,6 +8,7 @@ import ( "math" "math/bits" "net" + "net/netip" "github.com/soypat/lneto" "github.com/soypat/lneto/ipv4" @@ -17,7 +18,7 @@ type Client struct { connID uint64 reqHostname string hostname []byte - dns [][4]byte + dns []netip.Addr svIPtos ipv4.ToS tRenew uint32 @@ -253,7 +254,7 @@ func (c *Client) setOptions(frm Frame) error { return nil // No DNS parsing if already got in previous exchange. } for i := 0; i < len(data); i += 4 { - c.dns = append(c.dns, [4]byte(data[i:i+4])) + c.dns = append(c.dns, netip.AddrFrom4([4]byte(data[i:i+4]))) } } return nil @@ -301,16 +302,22 @@ func (c *Client) reset(xid uint32) { func (d *Client) State() ClientState { return d.state } -func (d *Client) BroadcastAddr() [4]byte { return d.broadcast } -func (d *Client) AssignedAddr() [4]byte { return d.offer } -func (d *Client) ServerAddr() [4]byte { return d.svip } -func (d *Client) RouterAddr() [4]byte { return d.router } -func (d *Client) GatewayAddr() [4]byte { return d.gateway } -func (d *Client) RebindingSeconds() uint32 { return d.tRebind } -func (d *Client) RenewalSeconds() uint32 { return d.tRenew } -func (d *Client) IPLeaseSeconds() uint32 { return d.tIPLease } -func (d *Client) AppendDNSServers(dst [][4]byte) [][4]byte { return append(dst, d.dns...) } - +func (d *Client) BroadcastAddr() [4]byte { return d.broadcast } +func (d *Client) AssignedAddr() [4]byte { return d.offer } +func (d *Client) ServerAddr() [4]byte { return d.svip } +func (d *Client) RouterAddr() [4]byte { return d.router } +func (d *Client) GatewayAddr() [4]byte { return d.gateway } +func (d *Client) RebindingSeconds() uint32 { return d.tRebind } +func (d *Client) RenewalSeconds() uint32 { return d.tRenew } +func (d *Client) IPLeaseSeconds() uint32 { return d.tIPLease } +func (d *Client) AppendDNSServers(dst []netip.Addr) []netip.Addr { return append(dst, d.dns...) } +func (d *Client) NumDNSServers() int { return len(d.dns) } +func (d *Client) DNSServerFirst() netip.Addr { + if len(d.dns) < 1 { + return netip.Addr{} + } + return d.dns[0] +} func (d *Client) CIDRBits() uint8 { if d.subnet == [4]byte{} { return 0 diff --git a/dns/client.go b/dns/client.go index f49513c..c8eda70 100644 --- a/dns/client.go +++ b/dns/client.go @@ -2,11 +2,11 @@ package dns import ( "errors" + "fmt" "math" "net" "github.com/soypat/lneto" - "github.com/soypat/lneto/internal" ) type Client struct { @@ -29,12 +29,12 @@ func (sudp *Client) LocalPort() uint16 { return ClientPort } func (sudp *Client) ConnectionID() *uint64 { return &sudp.connID } -func (c *Client) StartResolve(cfg ResolveConfig) error { +func (c *Client) StartResolve(txid uint16, cfg ResolveConfig) error { nd := len(cfg.Questions) if nd > math.MaxUint16 { return errors.New("overflow uint16 in DNS questions") } - c.reset(internal.Prand16(c.txid^uint16(c.connID)), dnsSendQuery, cfg.EnableRecursion) + c.reset(txid, dnsSendQuery, cfg.EnableRecursion) c.msg.LimitResourceDecoding(uint16(nd), uint16(nd), 0, 0) c.msg.AddQuestions(cfg.Questions) return nil @@ -46,17 +46,19 @@ func (c *Client) Encapsulate(carrierData []byte, frameOffset int) (int, error) { } else if c.state != dnsSendQuery { return 0, nil } + msg := &c.msg frame := carrierData[frameOffset:] msglen := msg.Len() if msglen > uint16(len(frame)) { return 0, errCalcLen } - data, err := msg.AppendTo(frame, c.txid, NewClientHeaderFlags(OpCodeQuery, c.enableRecursion)) + + data, err := msg.AppendTo(frame[:0], c.txid, NewClientHeaderFlags(OpCodeQuery, c.enableRecursion)) if err != nil { return 0, err } else if len(data) > int(msglen) { - return 0, errors.New("unexpected write") + return 0, fmt.Errorf("unexpected write %d v %d", len(data), msglen) } c.state = dnsAwaitResponse return len(data), nil diff --git a/dns/definitions.go b/dns/definitions.go index 080fc8e..380b7bf 100644 --- a/dns/definitions.go +++ b/dns/definitions.go @@ -31,6 +31,7 @@ var ( errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)") errStringTooLong = errors.New("character string exceeds maximum length (255)") errCompressedSRV = errors.New("compressed name in SRV resource data") + errEmptyDomainName = errors.New("empty domain name") ) // Frame encapsulates the raw data of a DNS packet diff --git a/dns/dns.go b/dns/dns.go index 318149e..c5e99dc 100644 --- a/dns/dns.go +++ b/dns/dns.go @@ -386,10 +386,15 @@ func MustNewName(s string) Name { return name } +var emptyDomain = []byte{0} + // NewName parses a domain name and returns a new Name. func NewName(domain string) (Name, error) { + if domain == "" { + return Name{}, errEmptyDomainName + } if len(domain) == 1 && domain[0] == '.' { - return Name{data: []byte{0}}, nil + return Name{data: emptyDomain}, nil } var name Name for len(domain) > 0 { diff --git a/examples/bridge/main.go b/examples/bridge/main.go index 1274a6a..97114cb 100644 --- a/examples/bridge/main.go +++ b/examples/bridge/main.go @@ -10,6 +10,7 @@ import ( "net" "net/netip" "os" + "runtime" "strconv" "strings" "time" @@ -100,26 +101,49 @@ func run() (err error) { } buf := make([]byte, mtu) lastAction := time.Now() - dnsOngoing := false + const ( + stateDHCP = iota + stateInitARP + stateDNS + stateDone + ) + state := stateDHCP for { - dhcpIsDone := stack.dhcp.State() == dhcpv4.StateBound - if dhcpIsDone { - if !dnsOngoing { + switch state { + case stateDHCP: + dhcpIsDone := stack.dhcp.State() == dhcpv4.StateBound + if dhcpIsDone { + state = stateInitARP + err = stack.ip.SetAddr(netip.AddrFrom4(stack.dhcp.AssignedAddr())) + if err != nil { + return err + } + err = stack.StartResolveHardwareAddress6(netip.AddrFrom4(stack.dhcp.RouterAddr())) + if err != nil { + return err + } + } + + case stateInitARP: + router := stack.dhcp.RouterAddr() + hw, err := stack.ResultResolveHardwareAddress6(netip.AddrFrom4(router)) + if err == nil { + state = stateDNS + stack.link.SetGateway6(hw) err = stack.StartLookupIP(flagHostToResolve) if err != nil { return err } - dnsOngoing = true - } else { - addrs, err := stack.ResultLookupIP() - if err == nil { - // END PROGRAM. - fmt.Println(flagHostToResolve, "resolved to", addrs) - return nil - } + } + + case stateDNS: + addrs, err := stack.ResultLookupIP() + if err == nil { + fmt.Println(flagHostToResolve, "resolved to", addrs) + return nil } } - _ = dhcpIsDone + clear(buf) nwrite, err := stack.Encapsulate(buf[:], 0) if err != nil { @@ -148,6 +172,7 @@ func run() (err error) { time.Sleep(5 * time.Millisecond) } else { lastAction = time.Now() + runtime.Gosched() } } return nil @@ -169,7 +194,11 @@ type Stack struct { 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" { + baseFrame := s.aux[len(s.aux)-1] + isOK := baseFrame.Protocol == "DHCPv4" || + (baseFrame.Protocol == lneto.IPProtoUDP && getField(baseFrame, b, pcap.FieldClassDst) == 53) || + baseFrame.Protocol == ethernet.TypeARP + if !isOK { return nil } if err != nil { @@ -241,11 +270,15 @@ func (s *Stack) Reset(mac [6]byte, addr netip.Addr, mtu uint16) error { } func (s *Stack) StartLookupIP(host string) error { + dnsSrvs := s.dhcp.DNSServerFirst() + if !dnsSrvs.IsValid() { + return errors.New("no valid DNS server") + } name, err := dns.NewName(host) if err != nil { return err } - err = s.dns.StartResolve(dns.ResolveConfig{ + err = s.dns.StartResolve(uint16(softRand), dns.ResolveConfig{ Questions: []dns.Question{ { Name: name, @@ -259,12 +292,12 @@ func (s *Stack) StartLookupIP(host string) error { return err } var u internet.StackUDPPort - u.SetStackNode(&s.dns, nil, dns.ServerPort) + dns4 := dnsSrvs.As4() + u.SetStackNode(&s.dns, dns4[:], dns.ServerPort) err = s.udps.Register(&u) if err != nil { return err } - return err return nil } @@ -309,8 +342,39 @@ func (s *Stack) BeginDHCPRequest(request [4]byte) error { return err } +func (s *Stack) StartResolveHardwareAddress6(ip netip.Addr) error { + if !ip.Is4() { + return errors.New("unsupported or invalid IP address") + } + addr := ip.As4() + return s.arp.StartQuery(addr[:]) +} + +func (s *Stack) ResultResolveHardwareAddress6(ip netip.Addr) (hw [6]byte, err error) { + if !ip.Is4() { + return hw, errors.New("unsupported or invalid IP address") + } + addr := ip.As4() + hwslice, err := s.arp.QueryResult(addr[:]) + if err != nil { + return hw, err + } else if len(hwslice) != 6 { + panic("unreachable slice hw leng") + } + return [6]byte(hwslice), nil +} + func clear(buf []byte) { for i := range buf { buf[i] = 0 } } + +func getField(frame pcap.Frame, pkt []byte, class pcap.FieldClass) uint64 { + idx, err := frame.FieldByClass(class) + if err != nil { + return 0 + } + v, _ := frame.FieldAsUint(idx, pkt) + return v +} diff --git a/examples/stackbasic/main.go b/examples/stackbasic/main.go index a554215..9ddd2b0 100644 --- a/examples/stackbasic/main.go +++ b/examples/stackbasic/main.go @@ -319,11 +319,11 @@ func (as *ARPStack) Protocol() uint32 { return uint32(ethernet.TypeARP) } func (as *ARPStack) Recv(EtherFrame []byte, arpOff int) error { afrm, _ := arp.NewFrame(EtherFrame[arpOff:]) slog.Info("recv", slog.String("in", afrm.String())) - return as.handler.Recv(EtherFrame[arpOff:]) + return as.handler.Demux(EtherFrame, arpOff) } func (as *ARPStack) Handle(EtherFrame []byte, arpOff int) (int, error) { - n, err := as.handler.Send(EtherFrame[arpOff:]) + n, err := as.handler.Encapsulate(EtherFrame, arpOff) if err != nil || n == 0 { return 0, err } diff --git a/internet/node-arp.go b/internet/node-arp.go index 6efd061..d0afdec 100644 --- a/internet/node-arp.go +++ b/internet/node-arp.go @@ -24,28 +24,23 @@ func (narp *NodeARP) Protocol() uint64 { return uint64(ethernet.TypeARP) } func (narp *NodeARP) ConnectionID() *uint64 { return narp.handler.ConnectionID() } func (narp *NodeARP) Demux(EtherFrame []byte, arpOff int) error { - afrm, err := arp.NewFrame(EtherFrame[arpOff:]) - if err != nil { - slog.Error("bad-ARP", slog.String("err", err.Error())) - return nil - } - afrm.ValidateSize(&narp.vld) - if narp.vld.HasError() { - slog.Error("invalid-ARP", slog.String("err", narp.vld.ErrPop().Error())) - return nil - } - return narp.handler.Recv(EtherFrame[arpOff:]) + return narp.handler.Demux(EtherFrame, arpOff) } func (narp *NodeARP) Encapsulate(EtherFrame []byte, arpOff int) (int, error) { - n, err := narp.handler.Send(EtherFrame[arpOff:]) + n, err := narp.handler.Encapsulate(EtherFrame, arpOff) if err != nil || n == 0 { return 0, err // end with error. } afrm, _ := arp.NewFrame(EtherFrame[arpOff:]) - hwaddr, _ := afrm.Target() - efrm, _ := ethernet.NewFrame(EtherFrame) - copy(efrm.DestinationHardwareAddr()[:], hwaddr) slog.Info("handle", slog.String("out", afrm.String())) return n, err } + +func (narp *NodeARP) StartQuery(proto []byte) error { + return narp.handler.StartQuery(proto) +} + +func (narp *NodeARP) QueryResult(proto []byte) ([]byte, error) { + return narp.handler.QueryResult(proto) +} diff --git a/internet/stack-udpport.go b/internet/stack-udpport.go index ecf2730..7b8f20b 100644 --- a/internet/stack-udpport.go +++ b/internet/stack-udpport.go @@ -5,6 +5,7 @@ import ( "net" "github.com/soypat/lneto" + "github.com/soypat/lneto/internal" "github.com/soypat/lneto/udp" ) @@ -71,6 +72,12 @@ func (sudp *StackUDPPort) Encapsulate(carrierData []byte, frameOffset int) (int, } ufrm.SetSourcePort(sudp.h.port) ufrm.SetDestinationPort(sudp.rmport) + if len(sudp.raddr) > 0 && frameOffset >= 20 { + err = internal.SetIPAddrs(carrierData, 0, nil, sudp.raddr) + if err != nil { + return 0, err + } + } n, err := sudp.h.encapsulate(carrierData, frameOffset+8) if n == 0 { if err != nil {