mirror of
https://github.com/soypat/lneto.git
synced 2026-08-26 17:39:29 +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 {
|
type Handler struct {
|
||||||
connID uint64
|
connID uint64
|
||||||
ourHWAddr []byte
|
ourHWAddr []byte
|
||||||
ourProtoAddr []byte
|
ourProtoAddr []byte
|
||||||
htype uint16
|
htype uint16
|
||||||
protoType ethernet.Type
|
protoType ethernet.Type
|
||||||
pending [][sizeHeaderv6]byte
|
pendingResponse [][sizeHeaderv6]byte
|
||||||
queries []queryResult
|
queries []queryResult
|
||||||
}
|
}
|
||||||
|
|
||||||
type HandlerConfig struct {
|
type HandlerConfig struct {
|
||||||
@@ -27,29 +27,35 @@ type HandlerConfig struct {
|
|||||||
ProtocolType ethernet.Type
|
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 ||
|
if len(cfg.HardwareAddr) == 0 || len(cfg.HardwareAddr) > 255 ||
|
||||||
len(cfg.ProtocolAddr) == 0 || len(cfg.ProtocolAddr) > 255 {
|
len(cfg.ProtocolAddr) == 0 || len(cfg.ProtocolAddr) > 255 {
|
||||||
return errors.New("invalid Handler address config")
|
return errors.New("invalid Handler address config")
|
||||||
} else if cfg.MaxQueries <= 0 || cfg.MaxPending <= 0 {
|
} else if cfg.MaxQueries <= 0 || cfg.MaxPending <= 0 {
|
||||||
return errors.New("invalid Handler query or pending config")
|
return errors.New("invalid Handler query or pending config")
|
||||||
}
|
}
|
||||||
*c = Handler{
|
*h = Handler{
|
||||||
connID: c.connID + 1,
|
connID: h.connID + 1,
|
||||||
ourHWAddr: c.ourHWAddr[:0],
|
ourHWAddr: h.ourHWAddr[:0],
|
||||||
ourProtoAddr: c.ourProtoAddr[:0],
|
ourProtoAddr: h.ourProtoAddr[:0],
|
||||||
htype: cfg.HardwareType,
|
htype: cfg.HardwareType,
|
||||||
protoType: cfg.ProtocolType,
|
protoType: cfg.ProtocolType,
|
||||||
pending: c.pending[:0],
|
pendingResponse: h.pendingResponse[:0],
|
||||||
queries: c.queries[:0],
|
queries: h.queries[:0],
|
||||||
}
|
}
|
||||||
c.ourHWAddr = append(c.ourHWAddr, cfg.HardwareAddr...)
|
h.ourHWAddr = append(h.ourHWAddr, cfg.HardwareAddr...)
|
||||||
c.ourProtoAddr = append(c.ourProtoAddr, cfg.ProtocolAddr...)
|
h.ourProtoAddr = append(h.ourProtoAddr, cfg.ProtocolAddr...)
|
||||||
if cap(c.pending) < cfg.MaxPending {
|
if cap(h.pendingResponse) < cfg.MaxPending {
|
||||||
c.pending = make([][52]byte, cfg.MaxPending)[:0]
|
h.pendingResponse = make([][52]byte, cfg.MaxPending)[:0]
|
||||||
}
|
}
|
||||||
if cap(c.queries) < cfg.MaxQueries {
|
if cap(h.queries) < cfg.MaxQueries {
|
||||||
c.queries = make([]queryResult, cfg.MaxQueries)[:0]
|
h.queries = make([]queryResult, cfg.MaxQueries)[:0]
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -61,88 +67,91 @@ type queryResult struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AbortPending drops pending queries and incoming requests.
|
// AbortPending drops pending queries and incoming requests.
|
||||||
func (c *Handler) AbortPending() {
|
func (h *Handler) AbortPending() {
|
||||||
c.pending = c.pending[:0]
|
h.pendingResponse = h.pendingResponse[:0]
|
||||||
c.queries = c.queries[:0]
|
h.queries = h.queries[:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Handler) expectSize() int {
|
func (h *Handler) expectSize() int {
|
||||||
return sizeHeader + 2*len(c.ourHWAddr) + 2*len(c.ourProtoAddr)
|
return sizeHeader + 2*len(h.ourHWAddr) + 2*len(h.ourProtoAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Handler) ConnectionID() *uint64 {
|
func (h *Handler) QueryResult(protoAddr []byte) (hwAddr []byte, err error) {
|
||||||
return &c.connID
|
for i := range h.queries {
|
||||||
}
|
if bytes.Equal(protoAddr, h.queries[i].protoaddr) {
|
||||||
|
if !h.queries[i].querysent {
|
||||||
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 {
|
|
||||||
return nil, errors.New("query not yet sent")
|
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 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")
|
return nil, errors.New("query not exist or dropped")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Handler) StartQuery(proto []byte) error {
|
func (h *Handler) StartQuery(proto []byte) error {
|
||||||
if len(proto) != len(c.ourProtoAddr) {
|
if len(proto) != len(h.ourProtoAddr) {
|
||||||
return errors.New("bad protocol address length")
|
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")
|
return errors.New("too many ongoing queries")
|
||||||
}
|
}
|
||||||
c.queries = c.queries[:len(c.queries)+1]
|
h.queries = h.queries[:len(h.queries)+1]
|
||||||
q := &c.queries[len(c.queries)-1]
|
q := &h.queries[len(h.queries)-1]
|
||||||
q.hwaddr = q.hwaddr[:0]
|
q.hwaddr = q.hwaddr[:0]
|
||||||
q.querysent = false
|
q.querysent = false
|
||||||
q.protoaddr = append(q.protoaddr[:0], proto...)
|
q.protoaddr = append(q.protoaddr[:0], proto...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Handler) Send(b []byte) (int, error) {
|
func (h *Handler) Encapsulate(eth []byte, frameOffset int) (int, error) {
|
||||||
n := c.expectSize()
|
b := eth[frameOffset:]
|
||||||
|
n := h.expectSize()
|
||||||
if len(b) < n {
|
if len(b) < n {
|
||||||
return 0, errShortARP
|
return 0, errShortARP
|
||||||
}
|
}
|
||||||
if len(c.pending) > 0 {
|
if len(h.pendingResponse) > 0 {
|
||||||
// pop frame.
|
// pop frame.
|
||||||
afrm, _ := NewFrame(c.pending[len(c.pending)-1][:])
|
afrm, _ := NewFrame(h.pendingResponse[len(h.pendingResponse)-1][:])
|
||||||
c.pending = c.pending[:len(c.pending)-1]
|
h.pendingResponse = h.pendingResponse[:len(h.pendingResponse)-1]
|
||||||
afrm.SetOperation(OpReply)
|
afrm.SetOperation(OpReply)
|
||||||
afrm.SwapTargetSender()
|
afrm.SwapTargetSender()
|
||||||
hwsender, _ := afrm.Sender()
|
hwsender, _ := afrm.Sender()
|
||||||
copy(hwsender, c.ourHWAddr)
|
copy(hwsender, h.ourHWAddr)
|
||||||
n := copy(b, afrm.Clip().RawData())
|
n := copy(b, afrm.Clip().RawData())
|
||||||
|
tgt, _ := afrm.Target()
|
||||||
|
trySetEthernetDst(eth[:frameOffset], tgt)
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
for i := range c.queries {
|
for i := range h.queries {
|
||||||
if !c.queries[i].querysent {
|
if !h.queries[i].querysent {
|
||||||
c.queries[i].querysent = true
|
h.queries[i].querysent = true
|
||||||
afrm, _ := NewFrame(b)
|
afrm, _ := NewFrame(b)
|
||||||
afrm.SetHardware(c.htype, uint8(len(c.ourHWAddr)))
|
afrm.SetHardware(h.htype, uint8(len(h.ourHWAddr)))
|
||||||
afrm.SetProtocol(c.protoType, uint8(len(c.ourProtoAddr)))
|
afrm.SetProtocol(h.protoType, uint8(len(h.ourProtoAddr)))
|
||||||
afrm.SetOperation(OpRequest)
|
afrm.SetOperation(OpRequest)
|
||||||
hwSender, protoSender := afrm.Sender()
|
hwSender, protoSender := afrm.Sender()
|
||||||
copy(hwSender, c.ourHWAddr)
|
copy(hwSender, h.ourHWAddr)
|
||||||
copy(protoSender, c.ourProtoAddr)
|
copy(protoSender, h.ourProtoAddr)
|
||||||
hwTarget, protoTarget := afrm.Target()
|
hwTarget, protoTarget := afrm.Target()
|
||||||
copy(protoTarget, c.queries[i].protoaddr)
|
copy(protoTarget, h.queries[i].protoaddr)
|
||||||
for j := range hwTarget {
|
for j := range hwTarget {
|
||||||
hwTarget[j] = 0
|
hwTarget[j] = 0
|
||||||
}
|
}
|
||||||
|
broadcast := ethernet.BroadcastAddr()
|
||||||
|
trySetEthernetDst(eth[:frameOffset], broadcast[:])
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Handler) Recv(b []byte) error {
|
func (h *Handler) Demux(ethFrame []byte, frameOffset int) error {
|
||||||
if len(c.pending) == cap(c.pending) {
|
if len(h.pendingResponse) == cap(h.pendingResponse) {
|
||||||
return errARPBufferFull
|
return errARPBufferFull
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b := ethFrame[frameOffset:]
|
||||||
afrm, err := NewFrame(b)
|
afrm, err := NewFrame(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -153,27 +162,27 @@ func (c *Handler) Recv(b []byte) error {
|
|||||||
return vld.ErrPop()
|
return vld.ErrPop()
|
||||||
}
|
}
|
||||||
htype, hlen := afrm.Hardware()
|
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")
|
return errors.New("bad ARP hardware")
|
||||||
}
|
}
|
||||||
protoType, protoLen := afrm.Protocol()
|
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")
|
return errors.New("bad ARP proto")
|
||||||
}
|
}
|
||||||
switch afrm.Operation() {
|
switch afrm.Operation() {
|
||||||
case OpRequest:
|
case OpRequest:
|
||||||
_, protoaddr := afrm.Target()
|
_, protoaddr := afrm.Target()
|
||||||
if !bytes.Equal(protoaddr, c.ourProtoAddr) {
|
if !bytes.Equal(protoaddr, h.ourProtoAddr) {
|
||||||
return nil // Not for us.
|
return nil // Not for us.
|
||||||
}
|
}
|
||||||
c.pending = c.pending[:len(c.pending)+1] // Extend pending buffer.
|
h.pendingResponse = h.pendingResponse[:len(h.pendingResponse)+1] // Extend pending buffer.
|
||||||
copy(c.pending[len(c.pending)-1][:], afrm.buf) // Set pending buffer.
|
copy(h.pendingResponse[len(h.pendingResponse)-1][:], afrm.buf) // Set pending buffer.
|
||||||
|
|
||||||
case OpReply:
|
case OpReply:
|
||||||
hwaddr, protoaddr := afrm.Sender()
|
hwaddr, protoaddr := afrm.Sender()
|
||||||
for i := range c.queries {
|
for i := range h.queries {
|
||||||
if len(c.queries[i].hwaddr) == 0 && bytes.Equal(c.queries[i].protoaddr, protoaddr) {
|
if len(h.queries[i].hwaddr) == 0 && bytes.Equal(h.queries[i].protoaddr, protoaddr) {
|
||||||
c.queries[i].hwaddr = append(c.queries[i].hwaddr[:0], hwaddr...)
|
h.queries[i].hwaddr = append(h.queries[i].hwaddr[:0], hwaddr...)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,3 +192,9 @@ func (c *Handler) Recv(b []byte) error {
|
|||||||
}
|
}
|
||||||
return nil
|
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)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
var buf, discard [64]byte
|
var buf, discard [64]byte
|
||||||
n, err := c1.Send(buf[:])
|
n, err := c1.Encapsulate(buf[:], 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error on should be nop send:", err)
|
t.Fatal("error on should be nop send:", err)
|
||||||
} else if n > 0 {
|
} else if n > 0 {
|
||||||
t.Fatal("should not send if no query")
|
t.Fatal("should not send if no query")
|
||||||
}
|
}
|
||||||
n, err = c2.Send(buf[:])
|
n, err = c2.Encapsulate(buf[:], 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("error on should be nop send:", err)
|
t.Fatal("error on should be nop send:", err)
|
||||||
} else if n > 0 {
|
} else if n > 0 {
|
||||||
@@ -54,33 +54,33 @@ func TestHandler(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
n, err = c1.Send(buf[:]) // Send Request.
|
n, err = c1.Encapsulate(buf[:], 0) // Send Request.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if n == 0 {
|
} else if n == 0 {
|
||||||
t.Fatal("expected send of data after first query")
|
t.Fatal("expected send of data after first query")
|
||||||
}
|
}
|
||||||
validateARP(t, buf[:])
|
validateARP(t, buf[:])
|
||||||
err = c2.Recv(buf[:n]) // Receive request.
|
err = c2.Demux(buf[:n], 0) // Receive request.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err = c2.Send(buf[:]) // Send response.
|
n, err = c2.Encapsulate(buf[:], 0) // Send response.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if n == 0 {
|
} else if n == 0 {
|
||||||
t.Fatal("got no response to request")
|
t.Fatal("got no response to request")
|
||||||
}
|
}
|
||||||
validateARP(t, buf[:])
|
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 {
|
if err != nil {
|
||||||
t.Fatal("double tap send error:", err)
|
t.Fatal("double tap send error:", err)
|
||||||
} else if n > 0 {
|
} else if n > 0 {
|
||||||
t.Fatal("wanted no data sent after response sent")
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -90,13 +90,13 @@ func TestHandler(t *testing.T) {
|
|||||||
} else if !bytes.Equal(hwaddr, expectHWAddr) {
|
} else if !bytes.Equal(hwaddr, expectHWAddr) {
|
||||||
log.Fatalf("expected to get hwaddr %x!=%x", 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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if n > 0 {
|
} else if n > 0 {
|
||||||
t.Fatal("expected no data")
|
t.Fatal("expected no data")
|
||||||
}
|
}
|
||||||
n, err = c2.Send(buf[:])
|
n, err = c2.Encapsulate(buf[:], 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if n > 0 {
|
} else if n > 0 {
|
||||||
|
|||||||
+19
-12
@@ -8,6 +8,7 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"net"
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
"github.com/soypat/lneto/ipv4"
|
"github.com/soypat/lneto/ipv4"
|
||||||
@@ -17,7 +18,7 @@ type Client struct {
|
|||||||
connID uint64
|
connID uint64
|
||||||
reqHostname string
|
reqHostname string
|
||||||
hostname []byte
|
hostname []byte
|
||||||
dns [][4]byte
|
dns []netip.Addr
|
||||||
|
|
||||||
svIPtos ipv4.ToS
|
svIPtos ipv4.ToS
|
||||||
tRenew uint32
|
tRenew uint32
|
||||||
@@ -253,7 +254,7 @@ func (c *Client) setOptions(frm Frame) error {
|
|||||||
return nil // No DNS parsing if already got in previous exchange.
|
return nil // No DNS parsing if already got in previous exchange.
|
||||||
}
|
}
|
||||||
for i := 0; i < len(data); i += 4 {
|
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
|
return nil
|
||||||
@@ -301,16 +302,22 @@ func (c *Client) reset(xid uint32) {
|
|||||||
|
|
||||||
func (d *Client) State() ClientState { return d.state }
|
func (d *Client) State() ClientState { return d.state }
|
||||||
|
|
||||||
func (d *Client) BroadcastAddr() [4]byte { return d.broadcast }
|
func (d *Client) BroadcastAddr() [4]byte { return d.broadcast }
|
||||||
func (d *Client) AssignedAddr() [4]byte { return d.offer }
|
func (d *Client) AssignedAddr() [4]byte { return d.offer }
|
||||||
func (d *Client) ServerAddr() [4]byte { return d.svip }
|
func (d *Client) ServerAddr() [4]byte { return d.svip }
|
||||||
func (d *Client) RouterAddr() [4]byte { return d.router }
|
func (d *Client) RouterAddr() [4]byte { return d.router }
|
||||||
func (d *Client) GatewayAddr() [4]byte { return d.gateway }
|
func (d *Client) GatewayAddr() [4]byte { return d.gateway }
|
||||||
func (d *Client) RebindingSeconds() uint32 { return d.tRebind }
|
func (d *Client) RebindingSeconds() uint32 { return d.tRebind }
|
||||||
func (d *Client) RenewalSeconds() uint32 { return d.tRenew }
|
func (d *Client) RenewalSeconds() uint32 { return d.tRenew }
|
||||||
func (d *Client) IPLeaseSeconds() uint32 { return d.tIPLease }
|
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) 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 {
|
func (d *Client) CIDRBits() uint8 {
|
||||||
if d.subnet == [4]byte{} {
|
if d.subnet == [4]byte{} {
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
+7
-5
@@ -2,11 +2,11 @@ package dns
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
"github.com/soypat/lneto/internal"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@@ -29,12 +29,12 @@ func (sudp *Client) LocalPort() uint16 { return ClientPort }
|
|||||||
|
|
||||||
func (sudp *Client) ConnectionID() *uint64 { return &sudp.connID }
|
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)
|
nd := len(cfg.Questions)
|
||||||
if nd > math.MaxUint16 {
|
if nd > math.MaxUint16 {
|
||||||
return errors.New("overflow uint16 in DNS questions")
|
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.LimitResourceDecoding(uint16(nd), uint16(nd), 0, 0)
|
||||||
c.msg.AddQuestions(cfg.Questions)
|
c.msg.AddQuestions(cfg.Questions)
|
||||||
return nil
|
return nil
|
||||||
@@ -46,17 +46,19 @@ func (c *Client) Encapsulate(carrierData []byte, frameOffset int) (int, error) {
|
|||||||
} else if c.state != dnsSendQuery {
|
} else if c.state != dnsSendQuery {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := &c.msg
|
msg := &c.msg
|
||||||
frame := carrierData[frameOffset:]
|
frame := carrierData[frameOffset:]
|
||||||
msglen := msg.Len()
|
msglen := msg.Len()
|
||||||
if msglen > uint16(len(frame)) {
|
if msglen > uint16(len(frame)) {
|
||||||
return 0, errCalcLen
|
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 {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else if len(data) > int(msglen) {
|
} 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
|
c.state = dnsAwaitResponse
|
||||||
return len(data), nil
|
return len(data), nil
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ var (
|
|||||||
errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)")
|
errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)")
|
||||||
errStringTooLong = errors.New("character string exceeds maximum length (255)")
|
errStringTooLong = errors.New("character string exceeds maximum length (255)")
|
||||||
errCompressedSRV = errors.New("compressed name in SRV resource data")
|
errCompressedSRV = errors.New("compressed name in SRV resource data")
|
||||||
|
errEmptyDomainName = errors.New("empty domain name")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Frame encapsulates the raw data of a DNS packet
|
// Frame encapsulates the raw data of a DNS packet
|
||||||
|
|||||||
+6
-1
@@ -386,10 +386,15 @@ func MustNewName(s string) Name {
|
|||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var emptyDomain = []byte{0}
|
||||||
|
|
||||||
// NewName parses a domain name and returns a new Name.
|
// NewName parses a domain name and returns a new Name.
|
||||||
func NewName(domain string) (Name, error) {
|
func NewName(domain string) (Name, error) {
|
||||||
|
if domain == "" {
|
||||||
|
return Name{}, errEmptyDomainName
|
||||||
|
}
|
||||||
if len(domain) == 1 && domain[0] == '.' {
|
if len(domain) == 1 && domain[0] == '.' {
|
||||||
return Name{data: []byte{0}}, nil
|
return Name{data: emptyDomain}, nil
|
||||||
}
|
}
|
||||||
var name Name
|
var name Name
|
||||||
for len(domain) > 0 {
|
for len(domain) > 0 {
|
||||||
|
|||||||
+81
-17
@@ -10,6 +10,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -100,26 +101,49 @@ func run() (err error) {
|
|||||||
}
|
}
|
||||||
buf := make([]byte, mtu)
|
buf := make([]byte, mtu)
|
||||||
lastAction := time.Now()
|
lastAction := time.Now()
|
||||||
dnsOngoing := false
|
const (
|
||||||
|
stateDHCP = iota
|
||||||
|
stateInitARP
|
||||||
|
stateDNS
|
||||||
|
stateDone
|
||||||
|
)
|
||||||
|
state := stateDHCP
|
||||||
for {
|
for {
|
||||||
dhcpIsDone := stack.dhcp.State() == dhcpv4.StateBound
|
switch state {
|
||||||
if dhcpIsDone {
|
case stateDHCP:
|
||||||
if !dnsOngoing {
|
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)
|
err = stack.StartLookupIP(flagHostToResolve)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
dnsOngoing = true
|
}
|
||||||
} else {
|
|
||||||
addrs, err := stack.ResultLookupIP()
|
case stateDNS:
|
||||||
if err == nil {
|
addrs, err := stack.ResultLookupIP()
|
||||||
// END PROGRAM.
|
if err == nil {
|
||||||
fmt.Println(flagHostToResolve, "resolved to", addrs)
|
fmt.Println(flagHostToResolve, "resolved to", addrs)
|
||||||
return nil
|
return nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = dhcpIsDone
|
|
||||||
clear(buf)
|
clear(buf)
|
||||||
nwrite, err := stack.Encapsulate(buf[:], 0)
|
nwrite, err := stack.Encapsulate(buf[:], 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -148,6 +172,7 @@ func run() (err error) {
|
|||||||
time.Sleep(5 * time.Millisecond)
|
time.Sleep(5 * time.Millisecond)
|
||||||
} else {
|
} else {
|
||||||
lastAction = time.Now()
|
lastAction = time.Now()
|
||||||
|
runtime.Gosched()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -169,7 +194,11 @@ type Stack struct {
|
|||||||
|
|
||||||
func (s *Stack) Demux(b []byte, _ int) (err error) {
|
func (s *Stack) Demux(b []byte, _ int) (err error) {
|
||||||
s.aux, err = s.shark.CaptureEthernet(s.aux[:0], b, 0)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
if err != 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 {
|
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)
|
name, err := dns.NewName(host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = s.dns.StartResolve(dns.ResolveConfig{
|
err = s.dns.StartResolve(uint16(softRand), dns.ResolveConfig{
|
||||||
Questions: []dns.Question{
|
Questions: []dns.Question{
|
||||||
{
|
{
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -259,12 +292,12 @@ func (s *Stack) StartLookupIP(host string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
var u internet.StackUDPPort
|
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)
|
err = s.udps.Register(&u)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,8 +342,39 @@ func (s *Stack) BeginDHCPRequest(request [4]byte) error {
|
|||||||
return err
|
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) {
|
func clear(buf []byte) {
|
||||||
for i := range buf {
|
for i := range buf {
|
||||||
buf[i] = 0
|
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 {
|
func (as *ARPStack) Recv(EtherFrame []byte, arpOff int) error {
|
||||||
afrm, _ := arp.NewFrame(EtherFrame[arpOff:])
|
afrm, _ := arp.NewFrame(EtherFrame[arpOff:])
|
||||||
slog.Info("recv", slog.String("in", afrm.String()))
|
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) {
|
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 {
|
if err != nil || n == 0 {
|
||||||
return 0, err
|
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) ConnectionID() *uint64 { return narp.handler.ConnectionID() }
|
||||||
|
|
||||||
func (narp *NodeARP) Demux(EtherFrame []byte, arpOff int) error {
|
func (narp *NodeARP) Demux(EtherFrame []byte, arpOff int) error {
|
||||||
afrm, err := arp.NewFrame(EtherFrame[arpOff:])
|
return narp.handler.Demux(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:])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (narp *NodeARP) Encapsulate(EtherFrame []byte, arpOff int) (int, error) {
|
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 {
|
if err != nil || n == 0 {
|
||||||
return 0, err // end with error.
|
return 0, err // end with error.
|
||||||
}
|
}
|
||||||
afrm, _ := arp.NewFrame(EtherFrame[arpOff:])
|
afrm, _ := arp.NewFrame(EtherFrame[arpOff:])
|
||||||
hwaddr, _ := afrm.Target()
|
|
||||||
efrm, _ := ethernet.NewFrame(EtherFrame)
|
|
||||||
copy(efrm.DestinationHardwareAddr()[:], hwaddr)
|
|
||||||
slog.Info("handle", slog.String("out", afrm.String()))
|
slog.Info("handle", slog.String("out", afrm.String()))
|
||||||
return n, err
|
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"
|
"net"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
|
"github.com/soypat/lneto/internal"
|
||||||
"github.com/soypat/lneto/udp"
|
"github.com/soypat/lneto/udp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -71,6 +72,12 @@ func (sudp *StackUDPPort) Encapsulate(carrierData []byte, frameOffset int) (int,
|
|||||||
}
|
}
|
||||||
ufrm.SetSourcePort(sudp.h.port)
|
ufrm.SetSourcePort(sudp.h.port)
|
||||||
ufrm.SetDestinationPort(sudp.rmport)
|
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)
|
n, err := sudp.h.encapsulate(carrierData, frameOffset+8)
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user