mirror of
https://github.com/soypat/lneto.git
synced 2026-08-09 17:33:43 +00:00
major ARP Handler refactor; DNS improvements; bridge example rework
This commit is contained in:
+81
-66
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user