mirror of
https://github.com/soypat/lneto.git
synced 2026-09-04 05:49:02 +00:00
Error rewrites (#43)
* pcap: reuse Frame memory * slog: reduce heap allocations of addresses; also prevent heap alloc of dhcp options in pcap * dns: heapless improvement; add StackAsync buffer for more heapless operation; start thinking of errors * errors: begin standardise errors in lneto * errors: finish standardization of errors * fix merge issues * add more lneto errors to rest of package * format errors.go
This commit is contained in:
+13
-5
@@ -1,6 +1,10 @@
|
|||||||
package arp
|
package arp
|
||||||
|
|
||||||
import "errors"
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
|
)
|
||||||
|
|
||||||
//go:generate stringer -type=Operation -linecomment -output stringers.go .
|
//go:generate stringer -type=Operation -linecomment -output stringers.go .
|
||||||
|
|
||||||
@@ -11,10 +15,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errARPBufferFull = errors.New("ARP client need handling:too many ops pending")
|
errQueryPending = errors.New("arp: query pending")
|
||||||
errShortARP = errors.New("packet too short to be ARP")
|
errQueryNotFound = errors.New("arp: query not found")
|
||||||
errARPUnsupported = errors.New("ARP not supported")
|
|
||||||
errLargeSizes = errors.New("size of ARP protocol+hardware is unusually large")
|
// errGeneric aliases for common ARP errors.
|
||||||
|
errARPBufferFull = lneto.ErrBufferFull
|
||||||
|
errShortARP = lneto.ErrShortBuffer
|
||||||
|
errARPUnsupported = lneto.ErrUnsupported
|
||||||
|
errLargeSizes = lneto.ErrPacketDrop
|
||||||
)
|
)
|
||||||
|
|
||||||
// Operation represents the type of ARP packet, either request or reply/response.
|
// Operation represents the type of ARP packet, either request or reply/response.
|
||||||
|
|||||||
+1
-2
@@ -2,7 +2,6 @@ package arp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@@ -17,7 +16,7 @@ import (
|
|||||||
// with payload/options of frames to avoid panics.
|
// with payload/options of frames to avoid panics.
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < sizeHeaderv4 {
|
if len(buf) < sizeHeaderv4 {
|
||||||
return Frame{buf: nil}, errors.New("ARP packet too short")
|
return Frame{buf: nil}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-14
@@ -1,7 +1,6 @@
|
|||||||
package arp
|
package arp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
@@ -36,7 +35,7 @@ func (h *Handler) ConnectionID() *uint64 { return &h.connID }
|
|||||||
|
|
||||||
func (h *Handler) UpdateProtoAddr(protoAddr []byte) error {
|
func (h *Handler) UpdateProtoAddr(protoAddr []byte) error {
|
||||||
if len(protoAddr) != len(h.ourProtoAddr) {
|
if len(protoAddr) != len(h.ourProtoAddr) {
|
||||||
return errors.New("mismatch ARP proto size")
|
return lneto.ErrMismatchLen
|
||||||
}
|
}
|
||||||
copy(h.ourProtoAddr, protoAddr)
|
copy(h.ourProtoAddr, protoAddr)
|
||||||
return nil
|
return nil
|
||||||
@@ -45,9 +44,9 @@ func (h *Handler) UpdateProtoAddr(protoAddr []byte) error {
|
|||||||
func (h *Handler) Reset(cfg HandlerConfig) error {
|
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 lneto.ErrInvalidConfig
|
||||||
} 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 lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
*h = Handler{
|
*h = Handler{
|
||||||
connID: h.connID + 1,
|
connID: h.connID + 1,
|
||||||
@@ -102,16 +101,16 @@ func (h *Handler) QueryResult(protoAddr []byte) (hwAddr []byte, err error) {
|
|||||||
for i := range h.queries {
|
for i := range h.queries {
|
||||||
if internal.BytesEqual(protoAddr, h.queries[i].protoaddr) {
|
if internal.BytesEqual(protoAddr, h.queries[i].protoaddr) {
|
||||||
if !h.queries[i].querysent {
|
if !h.queries[i].querysent {
|
||||||
return nil, errors.New("query not yet sent")
|
return nil, errQueryPending
|
||||||
}
|
}
|
||||||
mac := h.queries[i].response()
|
mac := h.queries[i].response()
|
||||||
if mac == nil {
|
if mac == nil {
|
||||||
return nil, errors.New("no response yet")
|
return nil, errQueryPending
|
||||||
}
|
}
|
||||||
return mac, nil
|
return mac, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errors.New("query not exist or dropped")
|
return nil, errQueryNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) DiscardQuery(protoAddr []byte) error {
|
func (h *Handler) DiscardQuery(protoAddr []byte) error {
|
||||||
@@ -122,7 +121,7 @@ func (h *Handler) DiscardQuery(protoAddr []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return errors.New("query not found")
|
return errQueryNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) compactQueries() {
|
func (h *Handler) compactQueries() {
|
||||||
@@ -150,15 +149,15 @@ func (h *Handler) StartQuery(dstHWAddr, proto []byte) error {
|
|||||||
if len(h.queries) == cap(h.queries) {
|
if len(h.queries) == cap(h.queries) {
|
||||||
h.compactQueries()
|
h.compactQueries()
|
||||||
if len(h.queries) == cap(h.queries) {
|
if len(h.queries) == cap(h.queries) {
|
||||||
return errors.New("too many ongoing queries")
|
return lneto.ErrBufferFull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(proto) != len(h.ourProtoAddr) {
|
if len(proto) != len(h.ourProtoAddr) {
|
||||||
return errors.New("bad protocol address length")
|
return lneto.ErrMismatchLen
|
||||||
} else if dstHWAddr != nil && len(dstHWAddr) != len(h.ourHWAddr) {
|
} else if dstHWAddr != nil && len(dstHWAddr) != len(h.ourHWAddr) {
|
||||||
return errors.New("mismatch hardware size")
|
return lneto.ErrMismatchLen
|
||||||
} else if dstHWAddr != nil && !internal.IsZeroed(dstHWAddr...) {
|
} else if dstHWAddr != nil && !internal.IsZeroed(dstHWAddr...) {
|
||||||
return errors.New("write-to buffer must be zeroed out")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
h.queries = h.queries[:len(h.queries)+1]
|
h.queries = h.queries[:len(h.queries)+1]
|
||||||
q := &h.queries[len(h.queries)-1]
|
q := &h.queries[len(h.queries)-1]
|
||||||
@@ -230,11 +229,11 @@ func (h *Handler) Demux(ethFrame []byte, frameOffset int) error {
|
|||||||
}
|
}
|
||||||
htype, hlen := afrm.Hardware()
|
htype, hlen := afrm.Hardware()
|
||||||
if htype != h.htype || int(hlen) != len(h.ourHWAddr) {
|
if htype != h.htype || int(hlen) != len(h.ourHWAddr) {
|
||||||
return errors.New("bad ARP hardware")
|
return lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
protoType, protoLen := afrm.Protocol()
|
protoType, protoLen := afrm.Protocol()
|
||||||
if protoType != h.protoType || int(protoLen) != len(h.ourProtoAddr) {
|
if protoType != h.protoType || int(protoLen) != len(h.ourProtoAddr) {
|
||||||
return errors.New("bad ARP proto")
|
return lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
switch afrm.Operation() {
|
switch afrm.Operation() {
|
||||||
case OpRequest:
|
case OpRequest:
|
||||||
|
|||||||
+12
-12
@@ -2,8 +2,6 @@ package dhcpv4
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
@@ -80,13 +78,13 @@ func (c *Client) Reset() {
|
|||||||
|
|
||||||
func (c *Client) BeginRequest(xid uint32, cfg RequestConfig) error {
|
func (c *Client) BeginRequest(xid uint32, cfg RequestConfig) error {
|
||||||
if len(cfg.Hostname) > 36 {
|
if len(cfg.Hostname) > 36 {
|
||||||
return errors.New("requested hostname too long")
|
return lneto.ErrInvalidConfig
|
||||||
} else if c.state != StateInit && c.state != 0 {
|
} else if c.state != StateInit && c.state != 0 {
|
||||||
return errors.New("dhcp client must be closed/Init before new request")
|
return lneto.ErrInvalidConfig
|
||||||
} else if xid == 0 {
|
} else if xid == 0 {
|
||||||
return errors.New("zero xid")
|
return lneto.ErrInvalidConfig
|
||||||
} else if len(cfg.ClientID) > 32 {
|
} else if len(cfg.ClientID) > 32 {
|
||||||
return errors.New("client ID too long")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
c.reset(xid)
|
c.reset(xid)
|
||||||
c.state = StateInit
|
c.state = StateInit
|
||||||
@@ -143,7 +141,7 @@ func (c *Client) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int)
|
|||||||
}
|
}
|
||||||
opts := frm.OptionsPayload()
|
opts := frm.OptionsPayload()
|
||||||
if len(opts) < 255 {
|
if len(opts) < 255 {
|
||||||
return 0, errors.New("too short packet for options")
|
return 0, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
var nextState ClientState
|
var nextState ClientState
|
||||||
@@ -181,7 +179,8 @@ func (c *Client) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int)
|
|||||||
nextState = StateRequesting
|
nextState = StateRequesting
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0, errors.New("unhandled state" + c.state.String())
|
internal.LogAttrs(nil, slog.LevelError, "dhcpv4:unhandled-state", slog.String("state", c.state.String()))
|
||||||
|
return 0, lneto.ErrBug
|
||||||
}
|
}
|
||||||
n, _ := EncodeOption(opts[numOpts:], OptClientIdentifier, c.clientID...)
|
n, _ := EncodeOption(opts[numOpts:], OptClientIdentifier, c.clientID...)
|
||||||
numOpts += n
|
numOpts += n
|
||||||
@@ -210,13 +209,13 @@ func (c *Client) Demux(carrierData []byte, frameOffset int) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else if frm.XID() != c.currentXID {
|
} else if frm.XID() != c.currentXID {
|
||||||
return errors.New("dhcpv4 unexpected transaction ID")
|
return lneto.ErrMismatch
|
||||||
} else if frm.MagicCookie() != MagicCookie {
|
} else if frm.MagicCookie() != MagicCookie {
|
||||||
return errors.New("dhcpv4 bad magic cookie")
|
return lneto.ErrInvalidField
|
||||||
}
|
}
|
||||||
msgType := c.getMessageType(frm)
|
msgType := c.getMessageType(frm)
|
||||||
if msgType == MsgNack {
|
if msgType == MsgNack {
|
||||||
return errors.New("dhcp nack received")
|
return lneto.ErrPacketDrop
|
||||||
}
|
}
|
||||||
|
|
||||||
msgOK := msgType == MsgOffer || msgType == MsgAck
|
msgOK := msgType == MsgOffer || msgType == MsgAck
|
||||||
@@ -243,7 +242,8 @@ func (c *Client) Demux(carrierData []byte, frameOffset int) error {
|
|||||||
c.state = StateBound
|
c.state = StateBound
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("dhcpv4 unexpected state in recv %s", c.state.String())
|
internal.LogAttrs(nil, slog.LevelError, "dhcpv4:unexpected-recv-state", slog.String("state", c.state.String()))
|
||||||
|
return lneto.ErrBug
|
||||||
}
|
}
|
||||||
if frameOffset > 28 && c.svIPtos == 0 {
|
if frameOffset > 28 && c.svIPtos == 0 {
|
||||||
ifrm, _ := ipv4.NewFrame(carrierData)
|
ifrm, _ := ipv4.NewFrame(carrierData)
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
package dhcpv4
|
package dhcpv4
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate stringer -type=OptNum,Op,MessageType,ClientState -linecomment -output stringers.go
|
//go:generate stringer -type=OptNum,Op,MessageType,ClientState -linecomment -output stringers.go
|
||||||
@@ -52,9 +53,9 @@ func EncodeOption32(dst []byte, opt OptNum, v uint32) (int, error) {
|
|||||||
|
|
||||||
func EncodeOption(dst []byte, opt OptNum, data ...byte) (int, error) {
|
func EncodeOption(dst []byte, opt OptNum, data ...byte) (int, error) {
|
||||||
if len(data) > 255 {
|
if len(data) > 255 {
|
||||||
return 0, errors.New("DHCPv4 option data too long (>255)")
|
return 0, lneto.ErrInvalidLengthField
|
||||||
} else if len(dst) < 2+len(data) {
|
} else if len(dst) < 2+len(data) {
|
||||||
return 0, errors.New("DHCP option buffer too short")
|
return 0, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
_ = dst[2+len(data)]
|
_ = dst[2+len(data)]
|
||||||
dst[0] = byte(opt)
|
dst[0] = byte(opt)
|
||||||
|
|||||||
+5
-13
@@ -2,7 +2,6 @@ package dhcpv4
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
@@ -27,7 +26,7 @@ const (
|
|||||||
// An error is returned if the buffer size is smaller than 240.
|
// An error is returned if the buffer size is smaller than 240.
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < OptionsOffset {
|
if len(buf) < OptionsOffset {
|
||||||
return Frame{}, errSmallFrame
|
return Frame{}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
@@ -126,9 +125,9 @@ func (frm Frame) ForEachOption(fn func(off int, opt OptNum, data []byte) error)
|
|||||||
// Parse DHCP options.
|
// Parse DHCP options.
|
||||||
ptr := OptionsOffset
|
ptr := OptionsOffset
|
||||||
if ptr > len(frm.buf) {
|
if ptr > len(frm.buf) {
|
||||||
return errSmallFrame
|
return lneto.ErrShortBuffer
|
||||||
} else if len(frm.buf[ptr:]) == 0 {
|
} else if len(frm.buf[ptr:]) == 0 {
|
||||||
return errNoOptions
|
return lneto.ErrInvalidField
|
||||||
}
|
}
|
||||||
callback := fn != nil
|
callback := fn != nil
|
||||||
for ptr+1 < len(frm.buf) {
|
for ptr+1 < len(frm.buf) {
|
||||||
@@ -141,7 +140,7 @@ func (frm Frame) ForEachOption(fn func(off int, opt OptNum, data []byte) error)
|
|||||||
}
|
}
|
||||||
optlen := int(frm.buf[ptr+1])
|
optlen := int(frm.buf[ptr+1])
|
||||||
if ptr+2+optlen > len(frm.buf) {
|
if ptr+2+optlen > len(frm.buf) {
|
||||||
return errDHCPBadOption
|
return lneto.ErrInvalidLengthField
|
||||||
}
|
}
|
||||||
if callback {
|
if callback {
|
||||||
optionData := frm.buf[ptr+2 : ptr+2+optlen]
|
optionData := frm.buf[ptr+2 : ptr+2+optlen]
|
||||||
@@ -158,16 +157,9 @@ func (frm Frame) ForEachOption(fn func(off int, opt OptNum, data []byte) error)
|
|||||||
// Validation API.
|
// Validation API.
|
||||||
//
|
//
|
||||||
|
|
||||||
var (
|
|
||||||
errSmallFrame = errors.New("DHCPv4: frame size <240")
|
|
||||||
errDHCPBadOption = errors.New("DHCPv4: opt length exceeds payload")
|
|
||||||
errNoOptions = errors.New("DHCPv4: no options")
|
|
||||||
errOptionNotFit = errors.New("DHCPv4: options dont fit")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (frm Frame) ValidateSize(vld *lneto.Validator) {
|
func (frm Frame) ValidateSize(vld *lneto.Validator) {
|
||||||
err := frm.ForEachOption(nil) // Does all necessary validation.
|
err := frm.ForEachOption(nil) // Does all necessary validation.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
vld.AddError(errDHCPBadOption)
|
vld.AddError(lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/soypat/lneto/internal"
|
"github.com/soypat/lneto/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errOptionNotFit = errors.New("DHCPv4: options dont fit")
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
connID uint64
|
connID uint64
|
||||||
nextAddr netip.Addr
|
nextAddr netip.Addr
|
||||||
|
|||||||
+5
-4
@@ -1,12 +1,12 @@
|
|||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"log/slog"
|
||||||
"fmt"
|
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
|
"github.com/soypat/lneto/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@@ -34,7 +34,7 @@ func (sudp *Client) ConnectionID() *uint64 { return &sudp.connID }
|
|||||||
func (c *Client) StartResolve(localPort, txid uint16, cfg ResolveConfig) error {
|
func (c *Client) StartResolve(localPort, 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 lneto.ErrBufferFull
|
||||||
}
|
}
|
||||||
c.reset(localPort, txid, dnsSendQuery, cfg.EnableRecursion)
|
c.reset(localPort, txid, dnsSendQuery, cfg.EnableRecursion)
|
||||||
c.msg.LimitResourceDecoding(uint16(nd), uint16(nd), 0, 0)
|
c.msg.LimitResourceDecoding(uint16(nd), uint16(nd), 0, 0)
|
||||||
@@ -61,7 +61,8 @@ func (c *Client) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int)
|
|||||||
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, fmt.Errorf("unexpected write %d v %d", len(data), msglen)
|
internal.LogAttrs(nil, slog.LevelError, "dns:unexpected-write", slog.Int("got", len(data)), slog.Int("want", int(msglen)))
|
||||||
|
return 0, lneto.ErrBug
|
||||||
}
|
}
|
||||||
c.state = dnsAwaitResponse
|
c.state = dnsAwaitResponse
|
||||||
// Unset don't frag since DNS requests go through LOTS of nodes.
|
// Unset don't frag since DNS requests go through LOTS of nodes.
|
||||||
|
|||||||
+27
-23
@@ -3,35 +3,39 @@ package dns
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate stringer -type=Type,Class,RCode,OpCode -linecomment -output stringers.go .
|
//go:generate stringer -type=Type,Class,RCode,OpCode -linecomment -output stringers.go .
|
||||||
|
|
||||||
// common errors. Taken from golang.org/x/net/dns/dnsmessage module.
|
// common errors. Taken from golang.org/x/net/dns/dnsmessage module.
|
||||||
var (
|
var (
|
||||||
errNoResponse = errors.New("no DNS response")
|
errNoResponse = errors.New("no DNS response")
|
||||||
errNameTooLong = errors.New("DNS name exceeds maximum length")
|
errNameTooLong = errors.New("DNS name exceeds maximum length")
|
||||||
errNoNullTerm = errors.New("DNS name missing null terminator")
|
errNoNullTerm = errors.New("DNS name missing null terminator")
|
||||||
errCalcLen = errors.New("DNS calculated name label length exceeds remaining buffer length")
|
errCalcLen = errors.New("DNS calculated name label length exceeds remaining buffer length")
|
||||||
errCantAddLabel = errors.New("long/empty/zterm/escape DNS label or not enough space")
|
errCantAddLabel = errors.New("long/empty/zterm/escape DNS label or not enough space")
|
||||||
errBaseLen = errors.New("DNS frame length too short")
|
errBaseLen = lneto.ErrShortBuffer
|
||||||
errReserved = errors.New("segment prefix is reserved")
|
errReserved = errors.New("segment prefix is reserved")
|
||||||
errTooManyPtr = errors.New("too many pointers (>10)")
|
errTooManyPtr = errors.New("too many pointers (>10)")
|
||||||
errInvalidPtr = errors.New("invalid pointer")
|
errInvalidPtr = errors.New("invalid pointer")
|
||||||
errInvalidName = errors.New("invalid dns name")
|
errInvalidName = errors.New("invalid dns name")
|
||||||
errNilResouceBody = errors.New("nil resource body")
|
errNilResouceBody = errors.New("nil resource body")
|
||||||
errResourceLen = errors.New("insufficient data for resource body length")
|
errResourceLen = errors.New("insufficient data for resource body length")
|
||||||
errSegTooLong = errors.New("segment length too long")
|
errSegTooLong = errors.New("segment length too long")
|
||||||
errZeroSegLen = errors.New("zero length segment")
|
errZeroSegLen = errors.New("zero length segment")
|
||||||
errResTooLong = errors.New("resource length too long")
|
errResTooLong = errors.New("resource length too long")
|
||||||
errTooManyQuestions = errors.New("too many Questions")
|
|
||||||
errTooManyAnswers = errors.New("too many Answers")
|
errTooManyQuestions = lneto.ErrBufferFull
|
||||||
errTooManyAuthorities = errors.New("too many Authorities")
|
errTooManyAnswers = lneto.ErrBufferFull
|
||||||
errTooManyAdditionals = errors.New("too many Additionals")
|
errTooManyAuthorities = lneto.ErrBufferFull
|
||||||
errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)")
|
errTooManyAdditionals = lneto.ErrBufferFull
|
||||||
errStringTooLong = errors.New("character string exceeds maximum length (255)")
|
|
||||||
errCompressedSRV = errors.New("compressed name in SRV resource data")
|
errNonCanonicalName = errors.New("name is not in canonical format (it must end with a .)")
|
||||||
errEmptyDomainName = errors.New("empty domain name")
|
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
|
// Frame encapsulates the raw data of a DNS packet
|
||||||
|
|||||||
@@ -1,30 +1,25 @@
|
|||||||
package lneto
|
package lneto
|
||||||
|
|
||||||
// type ErrorPacketDrop struct {
|
|
||||||
// Message string
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var genericErrPacketDrop = &ErrorPacketDrop{Message: ErrPacketDrop.Error()}
|
|
||||||
|
|
||||||
// // ErrGenericPacketDrop returns the generic packet drop error. It performs no allocations.
|
|
||||||
// func ErrGenericPacketDrop() error {
|
|
||||||
// return genericErrPacketDrop
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (err *ErrorPacketDrop) Error() string {
|
|
||||||
// return err.Message
|
|
||||||
// }
|
|
||||||
|
|
||||||
type errGeneric uint8
|
type errGeneric uint8
|
||||||
|
|
||||||
// Generic errors common to internet functioning.
|
// Generic errors common to internet functioning.
|
||||||
const (
|
const (
|
||||||
_ errGeneric = iota // non-initialized err
|
_ errGeneric = iota // non-initialized err
|
||||||
ErrBug // lneto-bug(use build tag "debugheaplog")
|
ErrBug // lneto-bug(use build tag "debugheaplog")
|
||||||
ErrPacketDrop // packet dropped
|
ErrPacketDrop // packet dropped
|
||||||
ErrBadCRC // incorrect checksum
|
ErrBadCRC // incorrect checksum
|
||||||
ErrZeroSource // zero source(port/addr)
|
ErrZeroSource // zero source(port/addr)
|
||||||
ErrZeroDestination // zero destination(port/addr)
|
ErrZeroDestination // zero destination(port/addr)
|
||||||
|
ErrShortBuffer // short buffer
|
||||||
|
ErrBufferFull // buffer full
|
||||||
|
ErrInvalidAddr // invalid address
|
||||||
|
ErrUnsupported // unsupported
|
||||||
|
ErrMismatch // mismatch
|
||||||
|
ErrMismatchLen // mismatched length
|
||||||
|
ErrInvalidConfig // invalid configuration
|
||||||
|
ErrInvalidField // invalid field
|
||||||
|
ErrInvalidLengthField // invalid length field
|
||||||
|
ErrExhausted // resource exhausted
|
||||||
)
|
)
|
||||||
|
|
||||||
func (err errGeneric) Error() string {
|
func (err errGeneric) Error() string {
|
||||||
|
|||||||
+3
-9
@@ -2,7 +2,6 @@ package ethernet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
@@ -13,7 +12,7 @@ import (
|
|||||||
// with payload/options of frames to avoid panics.
|
// with payload/options of frames to avoid panics.
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < sizeHeaderNoVLAN {
|
if len(buf) < sizeHeaderNoVLAN {
|
||||||
return Frame{buf: nil}, errShort
|
return Frame{buf: nil}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
@@ -115,19 +114,14 @@ func (frm Frame) ClearHeader() {
|
|||||||
// Validation API.
|
// Validation API.
|
||||||
//
|
//
|
||||||
|
|
||||||
var (
|
|
||||||
errShort = errors.New("ethernet: too short")
|
|
||||||
errShortVLAN = errors.New("ethernet: short VLAN")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||||
func (efrm Frame) ValidateSize(v *lneto.Validator) {
|
func (efrm Frame) ValidateSize(v *lneto.Validator) {
|
||||||
sz := efrm.EtherTypeOrSize()
|
sz := efrm.EtherTypeOrSize()
|
||||||
if sz.IsSize() && len(efrm.buf) < int(sz) {
|
if sz.IsSize() && len(efrm.buf) < int(sz) {
|
||||||
v.AddError(errShort)
|
v.AddError(lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
if sz == TypeVLAN && len(efrm.buf) < 18 {
|
if sz == TypeVLAN && len(efrm.buf) < 18 {
|
||||||
v.AddError(errShortVLAN)
|
v.AddError(lneto.ErrShortBuffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-9
@@ -2,12 +2,8 @@ package internal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
"github.com/soypat/lneto"
|
||||||
errUnsupportedIP = errors.New("unsupported IP version")
|
|
||||||
errInvalidIPVersionToSetAddr = errors.New("invalid ip version to setDstAddr")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetIPAddr(buf []byte) (src, dst []byte, id, ipEndOff uint16, err error) {
|
func GetIPAddr(buf []byte) (src, dst []byte, id, ipEndOff uint16, err error) {
|
||||||
@@ -25,7 +21,7 @@ func GetIPAddr(buf []byte) (src, dst []byte, id, ipEndOff uint16, err error) {
|
|||||||
dst = buf[24:40]
|
dst = buf[24:40]
|
||||||
ipEndOff = 40
|
ipEndOff = 40
|
||||||
default:
|
default:
|
||||||
err = errUnsupportedIP
|
err = lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
return src, dst, id, ipEndOff, err
|
return src, dst, id, ipEndOff, err
|
||||||
}
|
}
|
||||||
@@ -44,13 +40,13 @@ func SetIPAddrs(buf []byte, id uint16, src, dst []byte) (err error) {
|
|||||||
srcaddr = buf[8:24]
|
srcaddr = buf[8:24]
|
||||||
dstaddr = buf[24:40]
|
dstaddr = buf[24:40]
|
||||||
default:
|
default:
|
||||||
return errUnsupportedIP
|
return lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
if src != nil && len(srcaddr) != len(src) {
|
if src != nil && len(srcaddr) != len(src) {
|
||||||
return errors.New("mismatched length of ip src addr")
|
return lneto.ErrMismatchLen
|
||||||
}
|
}
|
||||||
if dst != nil && len(dstaddr) != len(dst) {
|
if dst != nil && len(dstaddr) != len(dst) {
|
||||||
return errors.New("mismatched length of ip dst addr")
|
return lneto.ErrMismatchLen
|
||||||
}
|
}
|
||||||
copy(srcaddr, src)
|
copy(srcaddr, src)
|
||||||
copy(dstaddr, dst)
|
copy(dstaddr, dst)
|
||||||
|
|||||||
+10
-5
@@ -6,11 +6,16 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrRingBufferFull = errors.New("lneto/ring: buffer full")
|
ErrRingBufferFull = lneto.ErrBufferFull
|
||||||
errRingNoData = errors.New("lneto/ring: empty write")
|
errRingNoData = errors.New("lneto/ring: empty write")
|
||||||
|
errInvalidDiscard = errors.New("lneto/ring: invalid discard amount")
|
||||||
|
errDiscardExceeds = errors.New("lneto/ring: discard exceeds length")
|
||||||
|
errOffsetOverflow = errors.New("lneto/ring: offset too large (32 bit overflow)")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Ring implements basic Ring buffer functionality.
|
// Ring implements basic Ring buffer functionality.
|
||||||
@@ -92,12 +97,12 @@ func (r *Ring) Write(b []byte) (int, error) {
|
|||||||
// This method panics if amount of bytes is more than buffered (see [Ring.Buffered]).
|
// This method panics if amount of bytes is more than buffered (see [Ring.Buffered]).
|
||||||
func (r *Ring) ReadDiscard(n int) error {
|
func (r *Ring) ReadDiscard(n int) error {
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
return errors.New("invalid discard amount")
|
return errInvalidDiscard
|
||||||
}
|
}
|
||||||
buffered := r.Buffered()
|
buffered := r.Buffered()
|
||||||
switch {
|
switch {
|
||||||
case n > buffered:
|
case n > buffered:
|
||||||
return errors.New("discard exceeds length")
|
return errDiscardExceeds
|
||||||
case n == buffered:
|
case n == buffered:
|
||||||
r.Reset()
|
r.Reset()
|
||||||
case n+r.Off > len(r.Buf):
|
case n+r.Off > len(r.Buf):
|
||||||
@@ -111,7 +116,7 @@ func (r *Ring) ReadDiscard(n int) error {
|
|||||||
// ReadAt reads data at an offset from start of readable data but does not advance read pointer. [io.EOF] returned when no data available.
|
// ReadAt reads data at an offset from start of readable data but does not advance read pointer. [io.EOF] returned when no data available.
|
||||||
func (r *Ring) ReadAt(p []byte, off64 int64) (int, error) {
|
func (r *Ring) ReadAt(p []byte, off64 int64) (int, error) {
|
||||||
if math.MaxInt != math.MaxInt64 && off64+int64(len(p)) > math.MaxInt32 {
|
if math.MaxInt != math.MaxInt64 && off64+int64(len(p)) > math.MaxInt32 {
|
||||||
return 0, errors.New("offset too large (32 bit overflow)") // Check only compiles for 32-bit platforms.
|
return 0, errOffsetOverflow // Check only compiles for 32-bit platforms.
|
||||||
}
|
}
|
||||||
off := int(off64)
|
off := int(off64)
|
||||||
if off+len(p) > r.Buffered() {
|
if off+len(p) > r.Buffered() {
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ func (h *handlers) prepAdd() error {
|
|||||||
if h.full() {
|
if h.full() {
|
||||||
h.compact()
|
h.compact()
|
||||||
if h.full() {
|
if h.full() {
|
||||||
return errNodesFull
|
return lneto.ErrBufferFull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -200,11 +200,7 @@ func (h *handlers) encapsulateAny(buf []byte, offsetIP, offsetThisFrame int) (_
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errZeroMaxNodesArg = errors.New("zero max nodes arg")
|
|
||||||
errZeroPort = errors.New("port must be greater than zero")
|
|
||||||
errInvalidProto = errors.New("invalid protocol")
|
|
||||||
errProtoRegistered = errors.New("protocol already registered")
|
errProtoRegistered = errors.New("protocol already registered")
|
||||||
errNodesFull = errors.New("no more room for new nodes")
|
|
||||||
_ = net.ErrClosed
|
_ = net.ErrClosed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+26
-25
@@ -28,6 +28,9 @@ const unknownPayloadProto = "payload?"
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
ErrFieldByClassNotFound = errors.New("pcap: field by class not found")
|
ErrFieldByClassNotFound = errors.New("pcap: field by class not found")
|
||||||
|
ErrLimitExceeded = errors.New("pcap: limit exceeded")
|
||||||
|
errNotByteAligned = errors.New("must be parsed at byte boundary")
|
||||||
|
errInvalidFieldIdx = errors.New("invalid field index")
|
||||||
)
|
)
|
||||||
|
|
||||||
type PacketBreakdown struct {
|
type PacketBreakdown struct {
|
||||||
@@ -61,13 +64,11 @@ func (pc *PacketBreakdown) initFrames() []Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pc *PacketBreakdown) CaptureEthernet(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureEthernet(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
debuglog("pcap:eth:start")
|
|
||||||
if dst == nil {
|
if dst == nil {
|
||||||
dst = pc.initFrames()
|
dst = pc.initFrames()
|
||||||
debuglog("pcap:eth:initframes")
|
|
||||||
}
|
}
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("ethernet must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
efrm, err := ethernet.NewFrame(pkt[bitOffset/8:])
|
efrm, err := ethernet.NewFrame(pkt[bitOffset/8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -110,7 +111,7 @@ func (pc *PacketBreakdown) CaptureEthernet(dst []Frame, pkt []byte, bitOffset in
|
|||||||
func (pc *PacketBreakdown) CaptureARP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureARP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
debuglog("pcap:arp:start")
|
debuglog("pcap:arp:start")
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("ARP must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
afrm, err := arp.NewFrame(pkt[bitOffset/8:])
|
afrm, err := arp.NewFrame(pkt[bitOffset/8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -157,7 +158,7 @@ func (pc *PacketBreakdown) CaptureARP(dst []Frame, pkt []byte, bitOffset int) ([
|
|||||||
func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
debuglog("pcap:ipv6:start")
|
debuglog("pcap:ipv6:start")
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("IPv6 must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
ifrm6, err := ipv6.NewFrame(pkt[bitOffset/8:])
|
ifrm6, err := ipv6.NewFrame(pkt[bitOffset/8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -201,7 +202,7 @@ func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) (
|
|||||||
func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
debuglog("pcap:ipv4:start")
|
debuglog("pcap:ipv4:start")
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("IPv4 must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
ifrm4, err := ipv4.NewFrame(pkt[bitOffset/8:])
|
ifrm4, err := ipv4.NewFrame(pkt[bitOffset/8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -301,7 +302,7 @@ func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt
|
|||||||
func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
debuglog("pcap:tcp:start")
|
debuglog("pcap:tcp:start")
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("TCP must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
tfrm, err := tcp.NewFrame(pkt[bitOffset/8:])
|
tfrm, err := tcp.NewFrame(pkt[bitOffset/8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -339,7 +340,7 @@ func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([
|
|||||||
func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
debuglog("pcap:udp:start")
|
debuglog("pcap:udp:start")
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("UDP must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
ufrm, err := udp.NewFrame(pkt[bitOffset/8:])
|
ufrm, err := udp.NewFrame(pkt[bitOffset/8:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -372,7 +373,7 @@ func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([
|
|||||||
func (pc *PacketBreakdown) CaptureICMPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureICMPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
debuglog("pcap:icmp:start")
|
debuglog("pcap:icmp:start")
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("ICMPv4 must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
icmpData := pkt[bitOffset/8:]
|
icmpData := pkt[bitOffset/8:]
|
||||||
ifrm, err := icmpv4.NewFrame(icmpData)
|
ifrm, err := icmpv4.NewFrame(icmpData)
|
||||||
@@ -432,7 +433,7 @@ func (pc *PacketBreakdown) CaptureICMPv4(dst []Frame, pkt []byte, bitOffset int)
|
|||||||
|
|
||||||
func (pc *PacketBreakdown) CaptureDNS(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureDNS(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("DNS must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
dnsData := pkt[bitOffset/8:]
|
dnsData := pkt[bitOffset/8:]
|
||||||
pc.dmsg.LimitResourceDecoding(20, 20, 20, 20)
|
pc.dmsg.LimitResourceDecoding(20, 20, 20, 20)
|
||||||
@@ -442,9 +443,9 @@ func (pc *PacketBreakdown) CaptureDNS(dst []Frame, pkt []byte, bitOffset int) ([
|
|||||||
}
|
}
|
||||||
finfo := reclaimFrame(&dst, "DNS", bitOffset, nil)
|
finfo := reclaimFrame(&dst, "DNS", bitOffset, nil)
|
||||||
if incomplete {
|
if incomplete {
|
||||||
finfo.Errors = append(finfo.Errors, errors.New("pcap: could not parse all DNS resources; add higher limit"))
|
finfo.Errors = append(finfo.Errors, ErrLimitExceeded)
|
||||||
}
|
}
|
||||||
finfo.Fields = append(finfo.Fields, FrameField{
|
finfo.Fields = append(finfo.Fields[:0], FrameField{
|
||||||
Name: "Data",
|
Name: "Data",
|
||||||
FrameBitOffset: 0,
|
FrameBitOffset: 0,
|
||||||
BitLength: int(off) * octet,
|
BitLength: int(off) * octet,
|
||||||
@@ -454,7 +455,7 @@ func (pc *PacketBreakdown) CaptureDNS(dst []Frame, pkt []byte, bitOffset int) ([
|
|||||||
|
|
||||||
func (pc *PacketBreakdown) CaptureNTP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureNTP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("NTP must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
ntpData := pkt[bitOffset/8:]
|
ntpData := pkt[bitOffset/8:]
|
||||||
_, err := ntp.NewFrame(ntpData)
|
_, err := ntp.NewFrame(ntpData)
|
||||||
@@ -467,7 +468,7 @@ func (pc *PacketBreakdown) CaptureNTP(dst []Frame, pkt []byte, bitOffset int) ([
|
|||||||
|
|
||||||
func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("DHCP must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
dhcpData := pkt[bitOffset/8:]
|
dhcpData := pkt[bitOffset/8:]
|
||||||
dfrm, err := dhcpv4.NewFrame(dhcpData)
|
dfrm, err := dhcpv4.NewFrame(dhcpData)
|
||||||
@@ -477,7 +478,7 @@ func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int)
|
|||||||
finfo := reclaimFrame(&dst, "DHCPv4", bitOffset, baseDHCPv4Fields[:])
|
finfo := reclaimFrame(&dst, "DHCPv4", bitOffset, baseDHCPv4Fields[:])
|
||||||
magic := dfrm.MagicCookie()
|
magic := dfrm.MagicCookie()
|
||||||
if magic != dhcpv4.MagicCookie {
|
if magic != dhcpv4.MagicCookie {
|
||||||
finfo.Errors = append(finfo.Errors, errors.New("incorrect DHCPv4 magic cookie"))
|
finfo.Errors = append(finfo.Errors, lneto.ErrInvalidField)
|
||||||
}
|
}
|
||||||
options := dfrm.OptionsPayload()
|
options := dfrm.OptionsPayload()
|
||||||
|
|
||||||
@@ -491,7 +492,7 @@ func (pc *PacketBreakdown) CaptureDHCPv4(dst []Frame, pkt []byte, bitOffset int)
|
|||||||
}
|
}
|
||||||
err = dfrm.ForEachOption(func(optoff int, opt dhcpv4.OptNum, data []byte) error {
|
err = dfrm.ForEachOption(func(optoff int, opt dhcpv4.OptNum, data []byte) error {
|
||||||
if len(optfield.SubFields) >= pc.SubfieldLimit {
|
if len(optfield.SubFields) >= pc.SubfieldLimit {
|
||||||
return errors.New("option cap limit surpassed for DHCP")
|
return ErrLimitExceeded
|
||||||
}
|
}
|
||||||
// optoff points to start of length and num bytes, skip over them with FrameBitOffset.
|
// optoff points to start of length and num bytes, skip over them with FrameBitOffset.
|
||||||
field := FrameField{Name: opt.String(), FrameBitOffset: (optoff + 2) * octet, BitLength: len(data) * octet}
|
field := FrameField{Name: opt.String(), FrameBitOffset: (optoff + 2) * octet, BitLength: len(data) * octet}
|
||||||
@@ -585,7 +586,7 @@ func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) (
|
|||||||
debuglog("pcap:http:start")
|
debuglog("pcap:http:start")
|
||||||
const httpProtocol = "HTTP"
|
const httpProtocol = "HTTP"
|
||||||
if bitOffset%8 != 0 {
|
if bitOffset%8 != 0 {
|
||||||
return dst, errors.New("HTTP must be parsed at byte boundary")
|
return dst, errNotByteAligned
|
||||||
}
|
}
|
||||||
const asResponse = true
|
const asResponse = true
|
||||||
const asRequest = false
|
const asRequest = false
|
||||||
@@ -668,7 +669,7 @@ func (frm Frame) FieldByClass(c FieldClass) (int, error) {
|
|||||||
}
|
}
|
||||||
if field.Name == "" { // Prioritize "canonical" fields with no name.
|
if field.Name == "" { // Prioritize "canonical" fields with no name.
|
||||||
if selected >= 0 && frm.Fields[selected].Name == "" {
|
if selected >= 0 && frm.Fields[selected].Name == "" {
|
||||||
return -1, errors.New("multiple class fields with no name")
|
return -1, lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
selected = i
|
selected = i
|
||||||
} else if selected >= 0 {
|
} else if selected >= 0 {
|
||||||
@@ -681,7 +682,7 @@ func (frm Frame) FieldByClass(c FieldClass) (int, error) {
|
|||||||
return -1, ErrFieldByClassNotFound
|
return -1, ErrFieldByClassNotFound
|
||||||
}
|
}
|
||||||
if multiple && frm.Fields[selected].Name != "" {
|
if multiple && frm.Fields[selected].Name != "" {
|
||||||
return -1, errors.New("multiple classes found and none have empty name")
|
return -1, lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
return selected, nil
|
return selected, nil
|
||||||
}
|
}
|
||||||
@@ -690,7 +691,7 @@ func (frm Frame) FieldByClass(c FieldClass) (int, error) {
|
|||||||
func (frm Frame) FieldAsUint(fieldIdx int, pkt []byte) (uint64, error) {
|
func (frm Frame) FieldAsUint(fieldIdx int, pkt []byte) (uint64, error) {
|
||||||
const badUint64 = math.MaxUint64
|
const badUint64 = math.MaxUint64
|
||||||
if fieldIdx < 0 || fieldIdx >= len(frm.Fields) {
|
if fieldIdx < 0 || fieldIdx >= len(frm.Fields) {
|
||||||
return badUint64, errors.New("invalid field index")
|
return badUint64, errInvalidFieldIdx
|
||||||
}
|
}
|
||||||
field := frm.Fields[fieldIdx]
|
field := frm.Fields[fieldIdx]
|
||||||
return fieldAsUint(pkt, frm.PacketBitOffset+field.FrameBitOffset, field.BitLength, field.Flags.IsRightAligned())
|
return fieldAsUint(pkt, frm.PacketBitOffset+field.FrameBitOffset, field.BitLength, field.Flags.IsRightAligned())
|
||||||
@@ -699,7 +700,7 @@ func (frm Frame) FieldAsUint(fieldIdx int, pkt []byte) (uint64, error) {
|
|||||||
// AppendField appends the binary on-the-wire representation of the field and aligns the field so it starts at the first bit of appended data.
|
// AppendField appends the binary on-the-wire representation of the field and aligns the field so it starts at the first bit of appended data.
|
||||||
func (frm Frame) AppendField(dst []byte, fieldIdx int, pkt []byte) ([]byte, error) {
|
func (frm Frame) AppendField(dst []byte, fieldIdx int, pkt []byte) ([]byte, error) {
|
||||||
if fieldIdx < 0 || fieldIdx >= len(frm.Fields) {
|
if fieldIdx < 0 || fieldIdx >= len(frm.Fields) {
|
||||||
return dst, errors.New("invalid field index")
|
return dst, errInvalidFieldIdx
|
||||||
}
|
}
|
||||||
field := frm.Fields[fieldIdx]
|
field := frm.Fields[fieldIdx]
|
||||||
return appendField(dst, pkt, frm.PacketBitOffset+field.FrameBitOffset, field.BitLength, field.Flags.IsRightAligned())
|
return appendField(dst, pkt, frm.PacketBitOffset+field.FrameBitOffset, field.BitLength, field.Flags.IsRightAligned())
|
||||||
@@ -709,7 +710,7 @@ func fieldAsUint(pkt []byte, fieldBitStart, bitlen int, rightAligned bool) (uint
|
|||||||
const badUint64 = math.MaxUint64
|
const badUint64 = math.MaxUint64
|
||||||
octets := (bitlen + 7) / 8
|
octets := (bitlen + 7) / 8
|
||||||
if octets > 8 {
|
if octets > 8 {
|
||||||
return badUint64, errors.New("field too long to be represented by uint64")
|
return badUint64, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
var buf [8]byte
|
var buf [8]byte
|
||||||
_, err := appendField(buf[8-octets:8-octets], pkt, fieldBitStart, bitlen, rightAligned)
|
_, err := appendField(buf[8-octets:8-octets], pkt, fieldBitStart, bitlen, rightAligned)
|
||||||
@@ -725,13 +726,13 @@ func appendField(dst, pkt []byte, fieldBitStart, bitlen int, rightAligned bool)
|
|||||||
octets := (bitlen + 7) / 8 // total octets needed to represent field.
|
octets := (bitlen + 7) / 8 // total octets needed to represent field.
|
||||||
octetsStart := fieldBitStart / 8
|
octetsStart := fieldBitStart / 8
|
||||||
if octets+octetsStart > len(pkt) {
|
if octets+octetsStart > len(pkt) {
|
||||||
return dst, errors.New("buffer overflow")
|
return dst, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
firstBitOffset := fieldBitStart % 8
|
firstBitOffset := fieldBitStart % 8
|
||||||
lastOctetExcessBits := fieldBitEnd % 8
|
lastOctetExcessBits := fieldBitEnd % 8
|
||||||
if firstBitOffset == 0 {
|
if firstBitOffset == 0 {
|
||||||
if rightAligned {
|
if rightAligned {
|
||||||
return dst, errors.New("invalid right aligned set for fully aligned field")
|
return dst, lneto.ErrBug
|
||||||
}
|
}
|
||||||
// Optimized path: field starts at byte boundary.
|
// Optimized path: field starts at byte boundary.
|
||||||
dst = append(dst, pkt[octetsStart:octetsStart+octets]...)
|
dst = append(dst, pkt[octetsStart:octetsStart+octets]...)
|
||||||
@@ -752,7 +753,7 @@ func appendField(dst, pkt []byte, fieldBitStart, bitlen int, rightAligned bool)
|
|||||||
// Right aligned with trailing bits. i.e: IPv6 Traffic Class.
|
// Right aligned with trailing bits. i.e: IPv6 Traffic Class.
|
||||||
// Field spans an extra byte, so need octets+1 bytes from packet.
|
// Field spans an extra byte, so need octets+1 bytes from packet.
|
||||||
if octets+octetsStart+1 > len(pkt) {
|
if octets+octetsStart+1 > len(pkt) {
|
||||||
return dst, errors.New("buffer overflow")
|
return dst, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
for i := 0; i < octets; i++ {
|
for i := 0; i < octets; i++ {
|
||||||
b := (pkt[octetsStart+i] & mask) << (8 - firstBitOffset)
|
b := (pkt[octetsStart+i] & mask) << (8 - firstBitOffset)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package pcap
|
|||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"math"
|
"math"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -13,6 +12,7 @@ import (
|
|||||||
_ "time"
|
_ "time"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
"github.com/soypat/lneto/ethernet"
|
"github.com/soypat/lneto/ethernet"
|
||||||
"github.com/soypat/lneto/ntp"
|
"github.com/soypat/lneto/ntp"
|
||||||
"github.com/soypat/lneto/tcp"
|
"github.com/soypat/lneto/tcp"
|
||||||
@@ -162,7 +162,7 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p
|
|||||||
// inspired by [time.RFC3339]
|
// inspired by [time.RFC3339]
|
||||||
const littlerfc3339 = "2006-01-02T15:04:05.9999"
|
const littlerfc3339 = "2006-01-02T15:04:05.9999"
|
||||||
if len(f.buf) != 8 {
|
if len(f.buf) != 8 {
|
||||||
return dst, errors.New("only timestamp8 supported")
|
return dst, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
ts := ntp.TimestampFromUint64(binary.BigEndian.Uint64(f.buf))
|
ts := ntp.TimestampFromUint64(binary.BigEndian.Uint64(f.buf))
|
||||||
dst = ts.Time().AppendFormat(dst, littlerfc3339)
|
dst = ts.Time().AppendFormat(dst, littlerfc3339)
|
||||||
@@ -223,7 +223,7 @@ func (f *Formatter) fieldAsUint(pkt []byte, fieldBitStart, bitlen int, rightAlig
|
|||||||
const badUint64 = math.MaxUint64
|
const badUint64 = math.MaxUint64
|
||||||
octets := (bitlen + 7) / 8
|
octets := (bitlen + 7) / 8
|
||||||
if octets > 8 {
|
if octets > 8 {
|
||||||
return badUint64, errors.New("field too long to be represented by uint64")
|
return badUint64, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
f.uintBuf = [8]byte{}
|
f.uintBuf = [8]byte{}
|
||||||
_, err := appendField(f.uintBuf[8-octets:8-octets], pkt, fieldBitStart, bitlen, rightAligned)
|
_, err := appendField(f.uintBuf[8-octets:8-octets], pkt, fieldBitStart, bitlen, rightAligned)
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package internet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
@@ -76,11 +75,11 @@ func (ls *StackEthernet) Reset6(mac, gateway [6]byte, mtu, maxNodes int) error {
|
|||||||
// The connection ID is incremented on each call to invalidate existing connections.
|
// The connection ID is incremented on each call to invalidate existing connections.
|
||||||
func (ls *StackEthernet) Configure(cfg StackEthernetConfig) error {
|
func (ls *StackEthernet) Configure(cfg StackEthernetConfig) error {
|
||||||
if cfg.MTU > (math.MaxUint16-ethernet.MaxOverheadSize) || cfg.MTU < 256 {
|
if cfg.MTU > (math.MaxUint16-ethernet.MaxOverheadSize) || cfg.MTU < 256 {
|
||||||
return errors.New("invalid MTU")
|
return lneto.ErrInvalidConfig
|
||||||
} else if cfg.MaxNodes <= 0 {
|
} else if cfg.MaxNodes <= 0 {
|
||||||
return errZeroMaxNodesArg
|
return lneto.ErrInvalidConfig
|
||||||
} else if cfg.AppendCRC32 && cfg.CRC32Update == nil {
|
} else if cfg.AppendCRC32 && cfg.CRC32Update == nil {
|
||||||
return errors.New("need CRC32Update to append ethernet CRC")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
ls.handlers.reset("StackEthernet", cfg.MaxNodes)
|
ls.handlers.reset("StackEthernet", cfg.MaxNodes)
|
||||||
*ls = StackEthernet{
|
*ls = StackEthernet{
|
||||||
@@ -107,7 +106,7 @@ func (ls *StackEthernet) Protocol() uint64 { return 1 }
|
|||||||
func (ls *StackEthernet) Register(h StackNode) error {
|
func (ls *StackEthernet) Register(h StackNode) error {
|
||||||
proto := h.Protocol()
|
proto := h.Protocol()
|
||||||
if proto > math.MaxUint16 || proto <= 1500 {
|
if proto > math.MaxUint16 || proto <= 1500 {
|
||||||
return errInvalidProto
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
return ls.handlers.registerByProto(nodeFromStackNode(h, 0, proto, nil))
|
return ls.handlers.registerByProto(nodeFromStackNode(h, 0, proto, nil))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package internet
|
package internet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@@ -26,7 +25,7 @@ type StackIP struct {
|
|||||||
|
|
||||||
func (sb *StackIP) Reset(addr netip.Addr, maxNodes int) error {
|
func (sb *StackIP) Reset(addr netip.Addr, maxNodes int) error {
|
||||||
if maxNodes <= 0 {
|
if maxNodes <= 0 {
|
||||||
return errZeroMaxNodesArg
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
err := sb.SetAddr(addr)
|
err := sb.SetAddr(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -44,9 +43,9 @@ func (sb *StackIP) Reset(addr netip.Addr, maxNodes int) error {
|
|||||||
|
|
||||||
func (sb *StackIP) SetAddr(addr netip.Addr) error {
|
func (sb *StackIP) SetAddr(addr netip.Addr) error {
|
||||||
if !addr.IsValid() {
|
if !addr.IsValid() {
|
||||||
return errors.New("invalid IP")
|
return lneto.ErrInvalidAddr
|
||||||
} else if !addr.Is4() {
|
} else if !addr.Is4() {
|
||||||
return errors.New("require IPv4")
|
return lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
sb.ip = addr.As4()
|
sb.ip = addr.As4()
|
||||||
return nil
|
return nil
|
||||||
@@ -200,7 +199,7 @@ func (sb *StackIP) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int
|
|||||||
func (sb *StackIP) Register(h StackNode) error {
|
func (sb *StackIP) Register(h StackNode) error {
|
||||||
proto := h.Protocol()
|
proto := h.Protocol()
|
||||||
if proto > 255 {
|
if proto > 255 {
|
||||||
return errInvalidProto
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
return sb.handlers.registerByPortProto(nodeFromStackNode(h, h.LocalPort(), proto, nil))
|
return sb.handlers.registerByPortProto(nodeFromStackNode(h, h.LocalPort(), proto, nil))
|
||||||
}
|
}
|
||||||
@@ -208,7 +207,7 @@ func (sb *StackIP) Register(h StackNode) error {
|
|||||||
func (sb *StackIP) recvicmp(icmpData []byte) error {
|
func (sb *StackIP) recvicmp(icmpData []byte) error {
|
||||||
var crc lneto.CRC791
|
var crc lneto.CRC791
|
||||||
if crc.PayloadSum16(icmpData) != 0 {
|
if crc.PayloadSum16(icmpData) != 0 {
|
||||||
return errors.New("ICMP CRC mismatch")
|
return lneto.ErrBadCRC
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package internet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
"math"
|
||||||
@@ -33,9 +32,9 @@ func (ps *StackPorts) ResetTCP(maxNodes int) error {
|
|||||||
|
|
||||||
func (ps *StackPorts) Reset(protocol uint64, dstPortOffset uint16, maxNodes int) error {
|
func (ps *StackPorts) Reset(protocol uint64, dstPortOffset uint16, maxNodes int) error {
|
||||||
if protocol > math.MaxUint16 {
|
if protocol > math.MaxUint16 {
|
||||||
return errInvalidProto
|
return lneto.ErrInvalidConfig
|
||||||
} else if maxNodes <= 0 {
|
} else if maxNodes <= 0 {
|
||||||
return errZeroMaxNodesArg
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
ps.handlers.reset("StackPorts(proto="+strconv.Itoa(int(protocol))+")", maxNodes)
|
ps.handlers.reset("StackPorts(proto="+strconv.Itoa(int(protocol))+")", maxNodes)
|
||||||
*ps = StackPorts{
|
*ps = StackPorts{
|
||||||
@@ -92,9 +91,9 @@ func (ps *StackPorts) Register(h StackNode) error {
|
|||||||
port := h.LocalPort()
|
port := h.LocalPort()
|
||||||
proto := h.Protocol()
|
proto := h.Protocol()
|
||||||
if port <= 0 {
|
if port <= 0 {
|
||||||
return errZeroPort
|
return lneto.ErrZeroSource
|
||||||
} else if proto != uint64(ps.protocol) {
|
} else if proto != uint64(ps.protocol) {
|
||||||
return errInvalidProto
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
return ps.handlers.registerByPortProto(nodeFromStackNode(h, port, proto, nil))
|
return ps.handlers.registerByPortProto(nodeFromStackNode(h, port, proto, nil))
|
||||||
}
|
}
|
||||||
@@ -110,11 +109,11 @@ func (mfsp *StackPortsMACFiltered) Register(h StackNode, addr []byte) error {
|
|||||||
port := h.LocalPort()
|
port := h.LocalPort()
|
||||||
proto := h.Protocol()
|
proto := h.Protocol()
|
||||||
if port <= 0 {
|
if port <= 0 {
|
||||||
return errZeroPort
|
return lneto.ErrZeroSource
|
||||||
} else if proto != uint64(mfsp.sp.protocol) {
|
} else if proto != uint64(mfsp.sp.protocol) {
|
||||||
return errInvalidProto
|
return lneto.ErrInvalidConfig
|
||||||
} else if addr != nil && len(addr) != 6 {
|
} else if addr != nil && len(addr) != 6 {
|
||||||
return errors.New("invalid MAC")
|
return lneto.ErrInvalidAddr
|
||||||
}
|
}
|
||||||
return mfsp.sp.handlers.registerByPortProto(nodeFromStackNode(h, port, proto, addr))
|
return mfsp.sp.handlers.registerByPortProto(nodeFromStackNode(h, port, proto, addr))
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-15
@@ -2,7 +2,6 @@ package ipv4
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
|
|
||||||
@@ -15,7 +14,7 @@ import (
|
|||||||
// with payload/options of frames to avoid panics.
|
// with payload/options of frames to avoid panics.
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < sizeHeader {
|
if len(buf) < sizeHeader {
|
||||||
return Frame{buf: nil}, errors.New("ipv4: short buffer")
|
return Frame{buf: nil}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
@@ -191,27 +190,19 @@ func (ifrm Frame) ClearHeader() {
|
|||||||
// Validation API.
|
// Validation API.
|
||||||
//
|
//
|
||||||
|
|
||||||
var (
|
|
||||||
errBadTL = errors.New("ipv4: bad total length")
|
|
||||||
errShort = errors.New("ipv4: short data")
|
|
||||||
errBadIHL = errors.New("ipv4: bad IHL")
|
|
||||||
errBadVersion = errors.New("ipv4: bad version")
|
|
||||||
errEvil = errors.New("ipv4: evil packet")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||||
func (ifrm Frame) ValidateSize(v *lneto.Validator) {
|
func (ifrm Frame) ValidateSize(v *lneto.Validator) {
|
||||||
ihl := ifrm.ihl()
|
ihl := ifrm.ihl()
|
||||||
tl := ifrm.TotalLength()
|
tl := ifrm.TotalLength()
|
||||||
if tl < sizeHeader {
|
if tl < sizeHeader {
|
||||||
v.AddError(errBadTL)
|
v.AddError(lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
if int(tl) > len(ifrm.RawData()) {
|
if int(tl) > len(ifrm.RawData()) {
|
||||||
v.AddError(errShort)
|
v.AddError(lneto.ErrShortBuffer)
|
||||||
}
|
}
|
||||||
if ihl < 5 || uint16(ihl)*4 > tl {
|
if ihl < 5 || uint16(ihl)*4 > tl {
|
||||||
v.AddError(errBadIHL)
|
v.AddError(lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,10 +211,10 @@ func (ifrm Frame) ValidateExceptCRC(v *lneto.Validator) {
|
|||||||
ifrm.ValidateSize(v)
|
ifrm.ValidateSize(v)
|
||||||
flags := ifrm.Flags()
|
flags := ifrm.Flags()
|
||||||
if ifrm.version() != 4 {
|
if ifrm.version() != 4 {
|
||||||
v.AddError(errBadVersion)
|
v.AddError(lneto.ErrInvalidField)
|
||||||
}
|
}
|
||||||
if v.Flags()&lneto.ValidateEvilBit != 0 && flags.IsEvil() {
|
if v.Flags()&lneto.ValidateEvilBit != 0 && flags.IsEvil() {
|
||||||
v.AddError(errEvil)
|
v.AddError(lneto.ErrPacketDrop)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ package icmpv4
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Type uint8
|
type Type uint8
|
||||||
@@ -52,13 +53,9 @@ const (
|
|||||||
CodeRedirectToSAndHost // redirect for ToS+host
|
CodeRedirectToSAndHost // redirect for ToS+host
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errShortFrame = errors.New("icmpv4: short frame")
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < 8 {
|
if len(buf) < 8 {
|
||||||
return Frame{}, errShortFrame
|
return Frame{}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-7
@@ -2,7 +2,6 @@ package ipv6
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
@@ -13,7 +12,7 @@ import (
|
|||||||
// with payload/options of frames to avoid panics.
|
// with payload/options of frames to avoid panics.
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < sizeHeader {
|
if len(buf) < sizeHeader {
|
||||||
return Frame{buf: nil}, errShortBuf
|
return Frame{buf: nil}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
@@ -119,16 +118,12 @@ func (i6frm Frame) ClearHeader() {
|
|||||||
// Validate API.
|
// Validate API.
|
||||||
//
|
//
|
||||||
|
|
||||||
var (
|
|
||||||
errShortFrame = errors.New("ipv6: short frame")
|
|
||||||
errShortBuf = errors.New("ipv6: short buffer for frame")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||||
func (i6frm Frame) ValidateSize(v *lneto.Validator) {
|
func (i6frm Frame) ValidateSize(v *lneto.Validator) {
|
||||||
tl := i6frm.PayloadLength()
|
tl := i6frm.PayloadLength()
|
||||||
if int(tl)+sizeHeader > len(i6frm.RawData()) {
|
if int(tl)+sizeHeader > len(i6frm.RawData()) {
|
||||||
v.AddError(errShortFrame)
|
v.AddError(lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -1,8 +1,9 @@
|
|||||||
package ntp
|
package ntp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type state uint8
|
type state uint8
|
||||||
@@ -100,7 +101,7 @@ func (c *Client) Demux(carrierData []byte, frameOffset int) error {
|
|||||||
xmt := frm.TransmitTime()
|
xmt := frm.TransmitTime()
|
||||||
orig := frm.OriginTime()
|
orig := frm.OriginTime()
|
||||||
if xmt == orig || orig != c.t[0] {
|
if xmt == orig || orig != c.t[0] {
|
||||||
return errors.New("bogus NTP packet")
|
return lneto.ErrPacketDrop
|
||||||
}
|
}
|
||||||
|
|
||||||
txelapsed := c.now().Sub(c.start)
|
txelapsed := c.now().Sub(c.start)
|
||||||
|
|||||||
+6
-5
@@ -3,11 +3,12 @@ package ntp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"math"
|
"math"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NTP Global Parameters.
|
// NTP Global Parameters.
|
||||||
@@ -26,7 +27,7 @@ const (
|
|||||||
|
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < SizeHeader {
|
if len(buf) < SizeHeader {
|
||||||
return Frame{buf: nil}, errors.New("NTP frame too short")
|
return Frame{buf: nil}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
@@ -189,12 +190,12 @@ func TimestampFromUint64(ts uint64) Timestamp {
|
|||||||
func TimestampFromTime(t time.Time) (Timestamp, error) {
|
func TimestampFromTime(t time.Time) (Timestamp, error) {
|
||||||
t = t.UTC()
|
t = t.UTC()
|
||||||
if t.Before(baseTime) {
|
if t.Before(baseTime) {
|
||||||
return Timestamp{}, errors.New("ntp.TimestampFromTime: time is before baseTime")
|
return Timestamp{}, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
off := t.Sub(baseTime)
|
off := t.Sub(baseTime)
|
||||||
sec := uint64(off / time.Second)
|
sec := uint64(off / time.Second)
|
||||||
if sec > math.MaxUint32 {
|
if sec > math.MaxUint32 {
|
||||||
return Timestamp{}, errors.New("ntp.TimestampFromTime: time is too large")
|
return Timestamp{}, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
fra := uint64(off%time.Second) * math.MaxUint32 / uint64(time.Second)
|
fra := uint64(off%time.Second) * math.MaxUint32 / uint64(time.Second)
|
||||||
return Timestamp{
|
return Timestamp{
|
||||||
@@ -254,7 +255,7 @@ func (d Date) Time() (time.Time, error) {
|
|||||||
}
|
}
|
||||||
hi, seclo := bits.Mul64(uint64(sec), uint64(time.Second))
|
hi, seclo := bits.Mul64(uint64(sec), uint64(time.Second))
|
||||||
if hi != 0 || seclo > math.MaxInt64-uint64(time.Second)-1 {
|
if hi != 0 || seclo > math.MaxInt64-uint64(time.Second)-1 {
|
||||||
return time.Time{}, errors.New("ntp.Date.Time overflow")
|
return time.Time{}, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
off := time.Duration(seclo)
|
off := time.Duration(seclo)
|
||||||
off += time.Second * time.Duration(d.frac>>32) / math.MaxUint32
|
off += time.Second * time.Duration(d.frac>>32) / math.MaxUint32
|
||||||
|
|||||||
+6
-6
@@ -9,6 +9,8 @@ package phy
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MDIOBus is a HAL for MDIO bus access supporting both Clause 22 and Clause 45 devices.
|
// MDIOBus is a HAL for MDIO bus access supporting both Clause 22 and Clause 45 devices.
|
||||||
@@ -33,7 +35,7 @@ func FindClause22PHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
|
|||||||
const maxAddr = 31
|
const maxAddr = 31
|
||||||
const regBasicStatus = 0x01
|
const regBasicStatus = 0x01
|
||||||
if len(dst) < 32 {
|
if len(dst) < 32 {
|
||||||
return -1, errors.New("require buffer length 32 for FindPHYs")
|
return -1, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
n = 0
|
n = 0
|
||||||
for addr := uint8(0); addr <= maxAddr; addr++ {
|
for addr := uint8(0); addr <= maxAddr; addr++ {
|
||||||
@@ -56,9 +58,7 @@ func FindClause22PHYs(mdio MDIOBus, dst []uint8) (n int, err error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var errInvalidPhyAddr error = lneto.ErrInvalidAddr
|
||||||
errInvalidPhyAddr = errors.New("invalid phy addr")
|
|
||||||
)
|
|
||||||
|
|
||||||
type Device struct {
|
type Device struct {
|
||||||
mdio MDIOBus
|
mdio MDIOBus
|
||||||
@@ -73,7 +73,7 @@ func (phy *Device) ConfigureAs22(mdio MDIOBus, phyAddr uint8) error {
|
|||||||
return errInvalidPhyAddr
|
return errInvalidPhyAddr
|
||||||
|
|
||||||
} else if mdio == nil {
|
} else if mdio == nil {
|
||||||
return errors.New("nil mdio bus")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
phy.mdio = mdio
|
phy.mdio = mdio
|
||||||
phy.phyaddr = phyAddr
|
phy.phyaddr = phyAddr
|
||||||
@@ -176,7 +176,7 @@ func (phy *Device) SetupForced(mode LinkMode) error {
|
|||||||
case 10:
|
case 10:
|
||||||
// No speed bits = 10Mbps
|
// No speed bits = 10Mbps
|
||||||
default:
|
default:
|
||||||
return errors.New("unsupported forced link mode")
|
return lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
if mode.IsFullDuplex() {
|
if mode.IsFullDuplex() {
|
||||||
ctl |= BMCRFullDuplex
|
ctl |= BMCRFullDuplex
|
||||||
|
|||||||
+12
-2
@@ -199,11 +199,21 @@ func _() {
|
|||||||
_ = x[ErrBadCRC-3]
|
_ = x[ErrBadCRC-3]
|
||||||
_ = x[ErrZeroSource-4]
|
_ = x[ErrZeroSource-4]
|
||||||
_ = x[ErrZeroDestination-5]
|
_ = x[ErrZeroDestination-5]
|
||||||
|
_ = x[ErrShortBuffer-6]
|
||||||
|
_ = x[ErrBufferFull-7]
|
||||||
|
_ = x[ErrInvalidAddr-8]
|
||||||
|
_ = x[ErrUnsupported-9]
|
||||||
|
_ = x[ErrMismatch-10]
|
||||||
|
_ = x[ErrMismatchLen-11]
|
||||||
|
_ = x[ErrInvalidConfig-12]
|
||||||
|
_ = x[ErrInvalidField-13]
|
||||||
|
_ = x[ErrInvalidLengthField-14]
|
||||||
|
_ = x[ErrExhausted-15]
|
||||||
}
|
}
|
||||||
|
|
||||||
const _errGeneric_name = "lneto-bug(use build tag \"debugheaplog\")packet droppedincorrect checksumzero source(port/addr)zero destination(port/addr)"
|
const _errGeneric_name = "lneto-bug(use build tag \"debugheaplog\")packet droppedincorrect checksumzero source(port/addr)zero destination(port/addr)short bufferbuffer fullinvalid addressunsupportedmismatchmismatched lengthinvalid configurationinvalid fieldinvalid length fieldresource exhausted"
|
||||||
|
|
||||||
var _errGeneric_index = [...]uint8{0, 39, 53, 71, 93, 120}
|
var _errGeneric_index = [...]uint16{0, 39, 53, 71, 93, 120, 132, 143, 158, 169, 177, 194, 215, 228, 248, 266}
|
||||||
|
|
||||||
func (i errGeneric) String() string {
|
func (i errGeneric) String() string {
|
||||||
i -= 1
|
i -= 1
|
||||||
|
|||||||
+6
-10
@@ -15,12 +15,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
errDeadlineExceeded = os.ErrDeadlineExceeded
|
errDeadlineExceeded = os.ErrDeadlineExceeded
|
||||||
errNoRemoteAddr = errors.New("tcp: no remote address established")
|
errNoRemoteAddr = errors.New("tcp: no remote address established")
|
||||||
errInvalidIP = errors.New("tcp: invalid IP")
|
|
||||||
errMismatchedIPVersion = errors.New("mismatched IP version")
|
|
||||||
errBadDemuxOffset = errors.New("bad offset in TCPConn.Recv")
|
|
||||||
errIPAddrMismatch = errors.New("IP addr mismatch on TCPConn")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Conn builds on the [Handler] abstraction and adds IP header knowledge, time management, and familiar user facing API
|
// Conn builds on the [Handler] abstraction and adds IP header knowledge, time management, and familiar user facing API
|
||||||
@@ -135,7 +131,7 @@ func (conn *Conn) OpenActive(localPort uint16, remote netip.AddrPort, iss Value)
|
|||||||
conn.mu.Lock()
|
conn.mu.Lock()
|
||||||
defer conn.mu.Unlock()
|
defer conn.mu.Unlock()
|
||||||
if !remote.IsValid() {
|
if !remote.IsValid() {
|
||||||
return errInvalidIP
|
return lneto.ErrInvalidAddr
|
||||||
}
|
}
|
||||||
rport := remote.Port()
|
rport := remote.Port()
|
||||||
err := conn.h.OpenActive(localPort, rport, iss)
|
err := conn.h.OpenActive(localPort, rport, iss)
|
||||||
@@ -330,14 +326,14 @@ func (conn *Conn) Demux(buf []byte, off int) (err error) {
|
|||||||
conn.mu.Lock()
|
conn.mu.Lock()
|
||||||
defer conn.mu.Unlock()
|
defer conn.mu.Unlock()
|
||||||
if off >= len(buf) {
|
if off >= len(buf) {
|
||||||
return errBadDemuxOffset
|
return lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
raddr, _, id, _, err := internal.GetIPAddr(buf[:off])
|
raddr, _, id, _, err := internal.GetIPAddr(buf[:off])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if conn.isRaddrSet() && !internal.BytesEqual(conn.remoteAddr, raddr) {
|
if conn.isRaddrSet() && !internal.BytesEqual(conn.remoteAddr, raddr) {
|
||||||
return errIPAddrMismatch
|
return lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
conn.trace("tcpconn.Recv", slog.Uint64("lport", uint64(conn.h.LocalPort())), slog.Uint64("rport", uint64(conn.h.remotePort)))
|
conn.trace("tcpconn.Recv", slog.Uint64("lport", uint64(conn.h.LocalPort())), slog.Uint64("rport", uint64(conn.h.remotePort)))
|
||||||
err = conn.h.Recv(buf[off:])
|
err = conn.h.Recv(buf[off:])
|
||||||
@@ -365,7 +361,7 @@ func (conn *Conn) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else if len(raddr) != len(conn.remoteAddr) {
|
} else if len(raddr) != len(conn.remoteAddr) {
|
||||||
return 0, errMismatchedIPVersion
|
return 0, lneto.ErrMismatchLen
|
||||||
}
|
}
|
||||||
n, err = conn.h.Send(carrierData[offsetToFrame:])
|
n, err = conn.h.Send(carrierData[offsetToFrame:])
|
||||||
if err != nil || n == 0 {
|
if err != nil || n == 0 {
|
||||||
|
|||||||
+12
-12
@@ -6,24 +6,24 @@ import (
|
|||||||
"math/bits"
|
"math/bits"
|
||||||
"strconv"
|
"strconv"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate stringer -type=State,OptionKind -linecomment -output stringers.go .
|
//go:generate stringer -type=State,OptionKind -linecomment -output stringers.go .
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// errDropSegment is a flag that signals to drop a segment silently.
|
errDropSegment error = lneto.ErrPacketDrop
|
||||||
errDropSegment = errors.New("drop segment")
|
errWindowTooLarge = errors.New("invalid window size > 2**16")
|
||||||
errWindowTooLarge = errors.New("invalid window size > 2**16")
|
|
||||||
|
|
||||||
errBufferTooSmall = errors.New("tcp buffer too small")
|
errBufferTooSmall error = lneto.ErrShortBuffer
|
||||||
errNeedClosedTCBToOpen = errors.New("need closed TCB to call open")
|
errNeedClosedTCBToOpen = errors.New("need closed TCB to call open")
|
||||||
errInvalidState = errors.New("invalid state")
|
errInvalidState = errors.New("invalid state")
|
||||||
errConnNotExist = errors.New("connection does not exist")
|
errConnNotExist = errors.New("connection does not exist")
|
||||||
errConnectionClosing = errors.New("connection closing")
|
errConnectionClosing = errors.New("connection closing")
|
||||||
errExpectedSYN = errors.New("seqs:expected SYN")
|
errExpectedSYN = errors.New("seqs:expected SYN")
|
||||||
errBadSegack = errors.New("seqs:bad segack")
|
errBadSegack = errors.New("seqs:bad segack")
|
||||||
errFinwaitExpectedACK = errors.New("seqs:finwait1 expected ACK")
|
errFinwaitExpectedACK = errors.New("seqs:finwait1 expected ACK")
|
||||||
errFinwaitExpectedFinack = errors.New("seqs:finwait2 expected FINACK")
|
|
||||||
|
|
||||||
errWindowOverflow = newRejectErr("wnd > 2**16")
|
errWindowOverflow = newRejectErr("wnd > 2**16")
|
||||||
errSeqNotInWindow = newRejectErr("seq not in snd/rcv.wnd")
|
errSeqNotInWindow = newRejectErr("seq not in snd/rcv.wnd")
|
||||||
|
|||||||
+5
-13
@@ -2,7 +2,6 @@ package tcp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
@@ -19,7 +18,7 @@ const (
|
|||||||
// with payload/options of frames to avoid panics.
|
// with payload/options of frames to avoid panics.
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < sizeHeaderTCP {
|
if len(buf) < sizeHeaderTCP {
|
||||||
return Frame{buf: nil}, errors.New("TCP packet too short")
|
return Frame{buf: nil}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
@@ -178,13 +177,6 @@ func (tfrm Frame) String() string {
|
|||||||
// Validation API
|
// Validation API
|
||||||
//
|
//
|
||||||
|
|
||||||
var (
|
|
||||||
errShortTCP = errors.New("TCP offset exceeds frame")
|
|
||||||
errBadTCPOff = errors.New("TCP offset invalid")
|
|
||||||
errEvilPacket = errors.New("evil packet")
|
|
||||||
errZeroDstPort = errors.New("TCP zero destination port")
|
|
||||||
errZeroSrcPort = errors.New("TCP zero source port")
|
|
||||||
)
|
|
||||||
|
|
||||||
// func (tfrm Frame) Validate(v *lneto.Validator) {
|
// func (tfrm Frame) Validate(v *lneto.Validator) {
|
||||||
// tfrm.ValidateSize(v)
|
// tfrm.ValidateSize(v)
|
||||||
@@ -196,19 +188,19 @@ var (
|
|||||||
func (tfrm Frame) ValidateSize(v *lneto.Validator) {
|
func (tfrm Frame) ValidateSize(v *lneto.Validator) {
|
||||||
off := tfrm.HeaderLength()
|
off := tfrm.HeaderLength()
|
||||||
if off < sizeHeaderTCP {
|
if off < sizeHeaderTCP {
|
||||||
v.AddBitPosErr(12*8, 4, errBadTCPOff)
|
v.AddBitPosErr(12*8, 4, lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
if off > len(tfrm.RawData()) {
|
if off > len(tfrm.RawData()) {
|
||||||
v.AddBitPosErr(12*8, 4, errShortTCP)
|
v.AddBitPosErr(12*8, 4, lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tfrm Frame) ValidateExceptCRC(v *lneto.Validator) {
|
func (tfrm Frame) ValidateExceptCRC(v *lneto.Validator) {
|
||||||
tfrm.ValidateSize(v)
|
tfrm.ValidateSize(v)
|
||||||
if tfrm.DestinationPort() == 0 {
|
if tfrm.DestinationPort() == 0 {
|
||||||
v.AddBitPosErr(2*8, 16, errZeroDstPort)
|
v.AddBitPosErr(2*8, 16, lneto.ErrZeroDestination)
|
||||||
}
|
}
|
||||||
if tfrm.SourcePort() == 0 {
|
if tfrm.SourcePort() == 0 {
|
||||||
v.AddBitPosErr(0, 16, errZeroSrcPort)
|
v.AddBitPosErr(0, 16, lneto.ErrZeroSource)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-11
@@ -1,7 +1,6 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
@@ -11,11 +10,6 @@ import (
|
|||||||
"github.com/soypat/lneto/internal"
|
"github.com/soypat/lneto/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errMismatchedSrcPort = errors.New("source port mismatch")
|
|
||||||
errMismatchedDstPort = errors.New("destination port mismatch")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Handler is a low level TCP handling data structure. It implements logic
|
// Handler is a low level TCP handling data structure. It implements logic
|
||||||
// related to data buffering, frame sequencing and connection state handling.
|
// related to data buffering, frame sequencing and connection state handling.
|
||||||
// Does NOT implement IP related logic, so no CRC calculation/validation or pseudo header logic.
|
// Does NOT implement IP related logic, so no CRC calculation/validation or pseudo header logic.
|
||||||
@@ -56,10 +50,10 @@ func (h *Handler) State() State { return h.scb.State() }
|
|||||||
// If the argument buffer is nil then the respective currently set buffer will be reused.
|
// If the argument buffer is nil then the respective currently set buffer will be reused.
|
||||||
func (h *Handler) SetBuffers(txbuf, rxbuf []byte, packets int) error {
|
func (h *Handler) SetBuffers(txbuf, rxbuf []byte, packets int) error {
|
||||||
if h.bufRx.Buf == nil && (len(rxbuf) < minBufferSize || len(txbuf) < minBufferSize) {
|
if h.bufRx.Buf == nil && (len(rxbuf) < minBufferSize || len(txbuf) < minBufferSize) {
|
||||||
return errors.New("tcp: short buffer")
|
return lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
if !h.scb.State().IsClosed() {
|
if !h.scb.State().IsClosed() {
|
||||||
return errors.New("tcp.Handler must be closed before setting buffers")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
if rxbuf != nil {
|
if rxbuf != nil {
|
||||||
h.bufRx.Buf = rxbuf
|
h.bufRx.Buf = rxbuf
|
||||||
@@ -156,15 +150,15 @@ func (h *Handler) Recv(incomingPacket []byte) error {
|
|||||||
|
|
||||||
remotePort := tfrm.SourcePort()
|
remotePort := tfrm.SourcePort()
|
||||||
if h.remotePort != 0 && remotePort != h.remotePort {
|
if h.remotePort != 0 && remotePort != h.remotePort {
|
||||||
return errMismatchedSrcPort
|
return lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
dstPort := tfrm.DestinationPort()
|
dstPort := tfrm.DestinationPort()
|
||||||
if h.localPort != dstPort {
|
if h.localPort != dstPort {
|
||||||
return errMismatchedDstPort
|
return lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
payload := tfrm.Payload()
|
payload := tfrm.Payload()
|
||||||
if len(payload) > h.bufRx.Free() {
|
if len(payload) > h.bufRx.Free() {
|
||||||
return errors.New("rx buffer full")
|
return lneto.ErrBufferFull
|
||||||
}
|
}
|
||||||
segIncoming := tfrm.Segment(len(payload))
|
segIncoming := tfrm.Segment(len(payload))
|
||||||
if h.scb.IncomingIsKeepalive(segIncoming) {
|
if h.scb.IncomingIsKeepalive(segIncoming) {
|
||||||
|
|||||||
+5
-6
@@ -1,7 +1,6 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -70,7 +69,7 @@ func (listener *Listener) Close() error {
|
|||||||
listener.mu.Lock()
|
listener.mu.Lock()
|
||||||
defer listener.mu.Unlock()
|
defer listener.mu.Unlock()
|
||||||
if listener.isClosed() {
|
if listener.isClosed() {
|
||||||
return errors.New("already closed")
|
return net.ErrClosed
|
||||||
}
|
}
|
||||||
listener.debug("listener:reset", slog.Uint64("port", uint64(listener.port)))
|
listener.debug("listener:reset", slog.Uint64("port", uint64(listener.port)))
|
||||||
listener.connID++
|
listener.connID++
|
||||||
@@ -80,9 +79,9 @@ func (listener *Listener) Close() error {
|
|||||||
|
|
||||||
func (listener *Listener) Reset(port uint16, pool pool) error {
|
func (listener *Listener) Reset(port uint16, pool pool) error {
|
||||||
if port == 0 {
|
if port == 0 {
|
||||||
return errZeroDstPort
|
return lneto.ErrZeroSource
|
||||||
} else if pool == nil {
|
} else if pool == nil {
|
||||||
return errors.New("nil TCP pool")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
listener.mu.Lock()
|
listener.mu.Lock()
|
||||||
defer listener.mu.Unlock()
|
defer listener.mu.Unlock()
|
||||||
@@ -126,7 +125,7 @@ func (listener *Listener) TryAccept() (*Conn, any, error) {
|
|||||||
listener.incoming[i] = handler{} // discard from ready.
|
listener.incoming[i] = handler{} // discard from ready.
|
||||||
return conn, userData, nil
|
return conn, userData, nil
|
||||||
}
|
}
|
||||||
return nil, nil, errors.New("no conns available")
|
return nil, nil, lneto.ErrExhausted
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encapsulate implements [StackNode].
|
// Encapsulate implements [StackNode].
|
||||||
@@ -199,7 +198,7 @@ func (listener *Listener) Demux(carrierData []byte, tcpFrameOffset int) error {
|
|||||||
}
|
}
|
||||||
dst := tfrm.DestinationPort()
|
dst := tfrm.DestinationPort()
|
||||||
if dst != listener.port {
|
if dst != listener.port {
|
||||||
return errors.New("not our port")
|
return lneto.ErrMismatch
|
||||||
}
|
}
|
||||||
src := tfrm.SourcePort()
|
src := tfrm.SourcePort()
|
||||||
|
|
||||||
|
|||||||
+8
-8
@@ -1,9 +1,9 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OptionKind uint8
|
type OptionKind uint8
|
||||||
@@ -88,11 +88,11 @@ func (op OptionCodec) PutOption32(dst []byte, kind OptionKind, v uint32) (int, e
|
|||||||
func (op OptionCodec) PutOption(dst []byte, kind OptionKind, data ...byte) (int, error) {
|
func (op OptionCodec) PutOption(dst []byte, kind OptionKind, data ...byte) (int, error) {
|
||||||
putSize := 2 + len(data)
|
putSize := 2 + len(data)
|
||||||
if len(dst) < putSize {
|
if len(dst) < putSize {
|
||||||
return -1, errBufferTooSmall
|
return -1, lneto.ErrShortBuffer
|
||||||
} else if putSize > 255 {
|
} else if putSize > 255 {
|
||||||
return -1, errors.New("option data too large")
|
return -1, lneto.ErrInvalidLengthField
|
||||||
} else if kind == OptNop || kind == OptEnd {
|
} else if kind == OptNop || kind == OptEnd {
|
||||||
return -1, errors.New("cant put Nop or End option type")
|
return -1, lneto.ErrInvalidField
|
||||||
}
|
}
|
||||||
dst[0] = byte(kind)
|
dst[0] = byte(kind)
|
||||||
dst[1] = byte(putSize)
|
dst[1] = byte(putSize)
|
||||||
@@ -111,13 +111,13 @@ func (op OptionCodec) ForEachOption(opts []byte, fn func(OptionKind, []byte) err
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if len(opts[off:]) < 1 {
|
if len(opts[off:]) < 1 {
|
||||||
return errors.New("short TCP options")
|
return lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
size := int(opts[off]) // Total option length including kind and length bytes.
|
size := int(opts[off]) // Total option length including kind and length bytes.
|
||||||
off++
|
off++
|
||||||
dataLen := size - 2 // Data bytes after kind and length.
|
dataLen := size - 2 // Data bytes after kind and length.
|
||||||
if dataLen < 0 || len(opts[off:]) < dataLen {
|
if dataLen < 0 || len(opts[off:]) < dataLen {
|
||||||
return fmt.Errorf("option %q length %d exceeds buffer size %d", kind.String(), size, len(opts[off:]))
|
return lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
if !skipSizeValidation {
|
if !skipSizeValidation {
|
||||||
@@ -133,7 +133,7 @@ func (op OptionCodec) ForEachOption(opts []byte, fn func(OptionKind, []byte) err
|
|||||||
expectSize = 2
|
expectSize = 2
|
||||||
}
|
}
|
||||||
if expectSize != -1 && size != expectSize {
|
if expectSize != -1 && size != expectSize {
|
||||||
return fmt.Errorf("bad TCP option %q size want %d got %d", kind.String(), expectSize, size)
|
return lneto.ErrInvalidLengthField
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !(skipObsolete && kind.IsObsolete()) {
|
if !(skipObsolete && kind.IsObsolete()) {
|
||||||
|
|||||||
+4
-5
@@ -2,8 +2,9 @@ package tcp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Embed low 5 bits of counter into cookie for efficient validation.
|
// Embed low 5 bits of counter into cookie for efficient validation.
|
||||||
@@ -45,15 +46,13 @@ type SYNCookieConfig struct {
|
|||||||
MaxCounterDelta uint32
|
MaxCounterDelta uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var errInvalidCookie error = lneto.ErrMismatch
|
||||||
errInvalidCookie = errors.New("tcp: invalid SYN cookie")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Reset initializes or reinitializes the SYNCookie with the given configuration.
|
// Reset initializes or reinitializes the SYNCookie with the given configuration.
|
||||||
// The counter is preserved across resets to maintain cookie validity during secret rotation.
|
// The counter is preserved across resets to maintain cookie validity during secret rotation.
|
||||||
func (sc *SYNCookieJar) Reset(config SYNCookieConfig) error {
|
func (sc *SYNCookieJar) Reset(config SYNCookieConfig) error {
|
||||||
if config.Rand == nil {
|
if config.Rand == nil {
|
||||||
return errors.New("need rand function")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
_, err := io.ReadFull(config.Rand, sc.secret[:])
|
_, err := io.ReadFull(config.Rand, sc.secret[:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+9
-16
@@ -1,20 +1,12 @@
|
|||||||
package tcp
|
package tcp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"log/slog"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
"github.com/soypat/lneto/internal"
|
"github.com/soypat/lneto/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
errPacketQueueFull = errors.New("packet queue full")
|
|
||||||
errQueuedPacketsLEZ = errors.New("queued packets <=0")
|
|
||||||
errInvalidBufSize = errors.New("invalid buffer size")
|
|
||||||
errSeqLessThanLast = errors.New("sequence number less than last sequence number")
|
|
||||||
errNoPacketToAck = errors.New("no packet to ack")
|
|
||||||
errAckUnsent = errors.New("ack of unsent packet")
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// this must be at least 2 for buffer to work.
|
// this must be at least 2 for buffer to work.
|
||||||
minBufferSize = 2
|
minBufferSize = 2
|
||||||
@@ -60,9 +52,9 @@ type ringidx struct {
|
|||||||
func (rtx *ringTx) Reset(buf []byte, maxqueuedPackets int, iss Value) error {
|
func (rtx *ringTx) Reset(buf []byte, maxqueuedPackets int, iss Value) error {
|
||||||
buf = buf[:len(buf):len(buf)] // safely omit capacity section.
|
buf = buf[:len(buf):len(buf)] // safely omit capacity section.
|
||||||
if maxqueuedPackets <= 0 {
|
if maxqueuedPackets <= 0 {
|
||||||
return errQueuedPacketsLEZ
|
return lneto.ErrInvalidConfig
|
||||||
} else if len(buf) < minBufferSize || len(buf) < maxqueuedPackets {
|
} else if len(buf) < minBufferSize || len(buf) < maxqueuedPackets {
|
||||||
return errInvalidBufSize
|
return lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
|
|
||||||
*rtx = ringTx{
|
*rtx = ringTx{
|
||||||
@@ -127,11 +119,12 @@ func (rtx *ringTx) Write(b []byte) (n int, err error) {
|
|||||||
func (rtx *ringTx) MakePacket(b []byte, currentSeq Value) (int, error) {
|
func (rtx *ringTx) MakePacket(b []byte, currentSeq Value) (int, error) {
|
||||||
free := rtx.slist.Free()
|
free := rtx.slist.Free()
|
||||||
if free == 0 {
|
if free == 0 {
|
||||||
return 0, errPacketQueueFull
|
return 0, lneto.ErrBufferFull
|
||||||
}
|
}
|
||||||
endSeq, ok := rtx.sentEndSeq()
|
endSeq, ok := rtx.sentEndSeq()
|
||||||
if ok && currentSeq.LessThan(endSeq) {
|
if ok && currentSeq.LessThan(endSeq) {
|
||||||
return 0, errSeqLessThanLast
|
internal.LogAttrs(nil, slog.LevelError, "txqueue:seq<endseq", slog.Uint64("seq", uint64(currentSeq)), slog.Uint64("endseq", uint64(endSeq)))
|
||||||
|
return 0, lneto.ErrBug
|
||||||
}
|
}
|
||||||
// Reading unsent ring consumes unsent and converts it to "sent".
|
// Reading unsent ring consumes unsent and converts it to "sent".
|
||||||
unsent, _ := rtx.unsentRing()
|
unsent, _ := rtx.unsentRing()
|
||||||
@@ -321,11 +314,11 @@ func (sl *sentlist) AddPacket(datalen, off, bufsize int, seq Value) *ringidx {
|
|||||||
func (sl *sentlist) RecvAck(ack Value, bufsize int) error {
|
func (sl *sentlist) RecvAck(ack Value, bufsize int) error {
|
||||||
newest := sl.Newest()
|
newest := sl.Newest()
|
||||||
if newest == nil {
|
if newest == nil {
|
||||||
return errNoPacketToAck
|
return lneto.ErrPacketDrop
|
||||||
}
|
}
|
||||||
endseq := newest.endSeq()
|
endseq := newest.endSeq()
|
||||||
if endseq.LessThan(ack) {
|
if endseq.LessThan(ack) {
|
||||||
return errAckUnsent
|
return lneto.ErrPacketDrop
|
||||||
}
|
}
|
||||||
// Mark fully acked.
|
// Mark fully acked.
|
||||||
for i := 0; i < len(sl.pkts); i++ {
|
for i := 0; i < len(sl.pkts); i++ {
|
||||||
|
|||||||
+3
-9
@@ -2,7 +2,6 @@ package udp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"github.com/soypat/lneto"
|
"github.com/soypat/lneto"
|
||||||
)
|
)
|
||||||
@@ -13,7 +12,7 @@ import (
|
|||||||
// with payload/options of frames to avoid panics.
|
// with payload/options of frames to avoid panics.
|
||||||
func NewFrame(buf []byte) (Frame, error) {
|
func NewFrame(buf []byte) (Frame, error) {
|
||||||
if len(buf) < sizeHeader {
|
if len(buf) < sizeHeader {
|
||||||
return Frame{buf: buf}, errors.New("UDP packet too short")
|
return Frame{buf: buf}, lneto.ErrShortBuffer
|
||||||
}
|
}
|
||||||
return Frame{buf: buf}, nil
|
return Frame{buf: buf}, nil
|
||||||
}
|
}
|
||||||
@@ -90,19 +89,14 @@ func (frm Frame) ClearHeader() {
|
|||||||
// Validation API.
|
// Validation API.
|
||||||
//
|
//
|
||||||
|
|
||||||
var (
|
|
||||||
errBadLen = errors.New("udp: bad UDP length")
|
|
||||||
errShort = errors.New("udp: short buffer")
|
|
||||||
)
|
|
||||||
|
|
||||||
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
// ValidateSize checks the frame's size fields and compares with the actual buffer
|
||||||
// the frame. It returns a non-nil error on finding an inconsistency.
|
// the frame. It returns a non-nil error on finding an inconsistency.
|
||||||
func (ufrm Frame) ValidateSize(v *lneto.Validator) {
|
func (ufrm Frame) ValidateSize(v *lneto.Validator) {
|
||||||
ul := ufrm.Length()
|
ul := ufrm.Length()
|
||||||
if ul < sizeHeader {
|
if ul < sizeHeader {
|
||||||
v.AddError(errBadLen)
|
v.AddError(lneto.ErrInvalidLengthField)
|
||||||
}
|
}
|
||||||
if int(ul) > len(ufrm.RawData()) {
|
if int(ul) > len(ufrm.RawData()) {
|
||||||
v.AddError(errShort)
|
v.AddError(lneto.ErrShortBuffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-10
@@ -99,13 +99,13 @@ func (s *StackAsync) Reset(cfg StackConfig) error {
|
|||||||
addr := cfg.StaticAddress
|
addr := cfg.StaticAddress
|
||||||
s.prng = uint32(cfg.RandSeed)
|
s.prng = uint32(cfg.RandSeed)
|
||||||
if s.prng == 0 {
|
if s.prng == 0 {
|
||||||
return errors.New("zero random seed")
|
return lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
s.hostname = cfg.Hostname
|
s.hostname = cfg.Hostname
|
||||||
if !addr.IsValid() {
|
if !addr.IsValid() {
|
||||||
addr = netip.AddrFrom4([4]byte{}) // If static not set DHCP will be performed and address will be zero.
|
addr = netip.AddrFrom4([4]byte{}) // If static not set DHCP will be performed and address will be zero.
|
||||||
} else if addr.Is6() {
|
} else if addr.Is6() {
|
||||||
return errors.New("IPv6 unsupported as of yet")
|
return lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
const linkNodes = 2 // ARP and IP nodes
|
const linkNodes = 2 // ARP and IP nodes
|
||||||
ecfg := internet.StackEthernetConfig{
|
ecfg := internet.StackEthernetConfig{
|
||||||
@@ -171,13 +171,11 @@ func (s *StackAsync) Reset(cfg StackConfig) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var errInvalidIPAddr = errors.New("invaldi IP address")
|
|
||||||
|
|
||||||
func (s *StackAsync) resetARP() error {
|
func (s *StackAsync) resetARP() error {
|
||||||
mac := s.link.HardwareAddr6()
|
mac := s.link.HardwareAddr6()
|
||||||
addr := s.ip.Addr()
|
addr := s.ip.Addr()
|
||||||
if !addr.IsValid() {
|
if !addr.IsValid() {
|
||||||
return errInvalidIPAddr
|
return lneto.ErrInvalidAddr
|
||||||
}
|
}
|
||||||
proto := ethernet.TypeIPv4
|
proto := ethernet.TypeIPv4
|
||||||
if addr.Is6() {
|
if addr.Is6() {
|
||||||
@@ -384,7 +382,7 @@ func (s *StackAsync) ResultLookupIP(host string) ([]netip.Addr, bool, error) {
|
|||||||
} else if len(data) == 16 {
|
} else if len(data) == 16 {
|
||||||
addrs = append(addrs, netip.AddrFrom16([16]byte(data)))
|
addrs = append(addrs, netip.AddrFrom16([16]byte(data)))
|
||||||
} else {
|
} else {
|
||||||
err = errors.New("bogus IP")
|
err = lneto.ErrInvalidAddr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil && len(addrs) == 0 {
|
if err == nil && len(addrs) == 0 {
|
||||||
@@ -441,7 +439,7 @@ func (s *StackAsync) StartResolveHardwareAddress6(ip netip.Addr) error {
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if !ip.Is4() {
|
if !ip.Is4() {
|
||||||
return errors.New("unsupported or invalid IP address")
|
return lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
addr := ip.As4()
|
addr := ip.As4()
|
||||||
return s.arp.StartQuery(nil, addr[:])
|
return s.arp.StartQuery(nil, addr[:])
|
||||||
@@ -452,7 +450,7 @@ func (s *StackAsync) ResultResolveHardwareAddress6(ip netip.Addr) (hw [6]byte, e
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if !ip.Is4() {
|
if !ip.Is4() {
|
||||||
return hw, errors.New("unsupported or invalid IP address")
|
return hw, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
addr := ip.As4()
|
addr := ip.As4()
|
||||||
hwslice, err := s.arp.QueryResult(addr[:])
|
hwslice, err := s.arp.QueryResult(addr[:])
|
||||||
@@ -469,7 +467,7 @@ func (s *StackAsync) DiscardResolveHardwareAddress6(ip netip.Addr) error {
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
if !ip.Is4() {
|
if !ip.Is4() {
|
||||||
return errors.New("unsupported or invalid IP address")
|
return lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
addr := ip.As4()
|
addr := ip.As4()
|
||||||
return s.arp.DiscardQuery(addr[:])
|
return s.arp.DiscardQuery(addr[:])
|
||||||
@@ -526,7 +524,7 @@ func (stack *StackAsync) AssimilateDHCPResults(results *DHCPResults) error {
|
|||||||
}
|
}
|
||||||
if len(results.DNSServers) > 0 {
|
if len(results.DNSServers) > 0 {
|
||||||
if !results.DNSServers[0].IsValid() || !results.DNSServers[0].Is4() {
|
if !results.DNSServers[0].IsValid() || !results.DNSServers[0].Is4() {
|
||||||
return errors.New("bad DNS server address, IPv6 or invalid")
|
return lneto.ErrInvalidAddr
|
||||||
}
|
}
|
||||||
stack.dnssv = results.DNSServers[0]
|
stack.dnssv = results.DNSServers[0]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@ package xnet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
"github.com/soypat/lneto/tcp"
|
"github.com/soypat/lneto/tcp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ func (s StackBerkeley) Socket(ctx context.Context, network string, family, sotyp
|
|||||||
switch family {
|
switch family {
|
||||||
case syscall.AF_INET:
|
case syscall.AF_INET:
|
||||||
default:
|
default:
|
||||||
return nil, errors.New("unsupported address family")
|
return nil, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
var local, remote netip.AddrPort
|
var local, remote netip.AddrPort
|
||||||
if laddr != nil {
|
if laddr != nil {
|
||||||
@@ -54,10 +54,10 @@ func (s StackBerkeley) Socket(ctx context.Context, network string, family, sotyp
|
|||||||
|
|
||||||
switch network {
|
switch network {
|
||||||
case "udp", "udp4":
|
case "udp", "udp4":
|
||||||
return nil, errors.New("udp not yet supported")
|
return nil, lneto.ErrUnsupported
|
||||||
case "tcp", "tcp4":
|
case "tcp", "tcp4":
|
||||||
if sotype != sockSTREAM {
|
if sotype != sockSTREAM {
|
||||||
return nil, errors.New("unsupported socket type")
|
return nil, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
if raddr != nil {
|
if raddr != nil {
|
||||||
@@ -106,7 +106,7 @@ func (s StackBerkeley) Socket(ctx context.Context, network string, family, sotyp
|
|||||||
return &l, nil
|
return &l, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, errors.New("unsupported network")
|
return nil, lneto.ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
type tcplistener struct {
|
type tcplistener struct {
|
||||||
|
|||||||
+2
-2
@@ -2,11 +2,11 @@ package xnet
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/soypat/lneto"
|
||||||
"github.com/soypat/lneto/tcp"
|
"github.com/soypat/lneto/tcp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ type TCPPoolConfig struct {
|
|||||||
|
|
||||||
func NewTCPPool(cfg TCPPoolConfig) (*TCPPool, error) {
|
func NewTCPPool(cfg TCPPoolConfig) (*TCPPool, error) {
|
||||||
if cfg.EstablishedTimeout <= 0 || cfg.ClosingTimeout <= 0 {
|
if cfg.EstablishedTimeout <= 0 || cfg.ClosingTimeout <= 0 {
|
||||||
return nil, errors.New("invalid timeout")
|
return nil, lneto.ErrInvalidConfig
|
||||||
}
|
}
|
||||||
n := cfg.PoolSize
|
n := cfg.PoolSize
|
||||||
pool := &TCPPool{
|
pool := &TCPPool{
|
||||||
|
|||||||
Reference in New Issue
Block a user