major ARP Handler refactor; DNS improvements; bridge example rework

This commit is contained in:
soypat
2025-07-09 22:49:13 -03:00
parent 70731c2ffa
commit a257becf15
10 changed files with 223 additions and 127 deletions
+81 -66
View File
@@ -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)
}
}
+9 -9
View File
@@ -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 {
+19 -12
View File
@@ -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
+7 -5
View File
@@ -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
+1
View File
@@ -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
+6 -1
View File
@@ -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 {
+81 -17
View File
@@ -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
}
+2 -2
View File
@@ -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
}
+10 -15
View File
@@ -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)
}
+7
View File
@@ -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 {