mirror of
https://github.com/soypat/lneto.git
synced 2026-08-21 23:19:03 +00:00
StackNode refactor: add offsetToIP argument to Encapsulate
This commit is contained in:
+13
-8
@@ -11,18 +11,21 @@ import (
|
||||
// StackNode is an abstraction of a packet exchanging protocol controller. This is the building block for all protocols,
|
||||
// from Ethernet to IP to TCP, practically any protocol can be expressed as a StackNode and function completely.
|
||||
type StackNode interface {
|
||||
// Encapsulate writes the stack node's frame into carrierData[frameOffset:]
|
||||
// Encapsulate writes the stack node's frame into carrierData[offsetToFrame:]
|
||||
// along with any other frame or payload the stack node encapsulates.
|
||||
// The returned integer is amount of bytes written such that carrierData[frameOffset:frameOffset+n]
|
||||
// contains written data. Data inside carrierData[:frameOffset] usually contains data necessary for
|
||||
// The returned integer is amount of bytes written such that carrierData[offsetToFrame:offsetToFrame+n]
|
||||
// contains written data. Data inside carrierData[:offsetToFrame] usually contains data necessary for
|
||||
// a StackNode to correctly emit valid frame data: such is the case for TCP packets which require IP
|
||||
// frame data for checksum calculation. Thus StackNodes must provide fields in their own frame
|
||||
// required by sub-stacknodes for correct encapsulation; in the case of IPv4/6 this means including fields
|
||||
// used in pseudo-header checksum like local IP (see [ipv4.CRCWriteUDPPseudo]).
|
||||
//
|
||||
// offsetToIP is the offset to the IP frame, if present, else its value should be -1.
|
||||
// The relation offsetToIP<=offsetToFrame should always hold.
|
||||
//
|
||||
// When [net.ErrClosed] is returned the StackNode should be discarded and any written data passed up normally.
|
||||
// Errors returned by Encapsulate are "extraordinary" and should not be returned unless the StackNode is receiving invalid carrierData/frameOffset.
|
||||
Encapsulate(carrierData []byte, frameOffset int) (int, error)
|
||||
Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int) (int, error)
|
||||
// Demux reads from the argument buffer where frameOffset is the offset of this StackNode's frame first byte.
|
||||
// The stack node then dispatches(demuxes) the encapsulated frames to its corresponding sub-stack-node(s).
|
||||
Demux(carrierData []byte, frameOffset int) error
|
||||
@@ -38,10 +41,12 @@ type node struct {
|
||||
currConnID uint64
|
||||
connID *uint64
|
||||
demux func([]byte, int) error
|
||||
encapsulate func([]byte, int) (int, error)
|
||||
encapsulate func([]byte, int, int) (int, error)
|
||||
proto uint16
|
||||
port uint16
|
||||
remoteAddr []byte
|
||||
// remoteAddr will be set on active(outbound) port connections
|
||||
// that require an ARP to set the remoteAddr beforehand.
|
||||
remoteAddr []byte
|
||||
}
|
||||
|
||||
type handlers struct {
|
||||
@@ -166,13 +171,13 @@ func (h *handlers) demuxByPort(buf []byte, offset int, port uint16) (*node, erro
|
||||
|
||||
// encapsulateAny finds a node suitable to write and encapsulates the package.
|
||||
// If no data is sent it returns the last error encountered.
|
||||
func (h *handlers) encapsulateAny(buf []byte, offset int) (_ *node, n int, err error) {
|
||||
func (h *handlers) encapsulateAny(buf []byte, offsetIP, offsetThisFrame int) (_ *node, n int, err error) {
|
||||
for i := range h.nodes {
|
||||
node := &h.nodes[i]
|
||||
if node.IsInvalid() {
|
||||
continue
|
||||
}
|
||||
n, err = node.encapsulate(buf, offset)
|
||||
n, err = node.encapsulate(buf, offsetIP, offsetThisFrame)
|
||||
if h.tryHandleError(node, err) {
|
||||
err = nil // CLOSE error handled gracefully by deleting node.
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func (listener *NodeTCPListener) TryAccept() (*tcp.Conn, error) {
|
||||
}
|
||||
|
||||
// Encapsulate implements [StackNode].
|
||||
func (listener *NodeTCPListener) Encapsulate(carrierData []byte, tcpFrameOffset int) (int, error) {
|
||||
func (listener *NodeTCPListener) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int) (int, error) {
|
||||
if listener.isClosed() {
|
||||
return 0, net.ErrClosed
|
||||
}
|
||||
@@ -102,7 +102,7 @@ func (listener *NodeTCPListener) Encapsulate(carrierData []byte, tcpFrameOffset
|
||||
if conn == nil {
|
||||
continue
|
||||
}
|
||||
n, err := conn.Encapsulate(carrierData, tcpFrameOffset)
|
||||
n, err := conn.Encapsulate(carrierData, offsetToIP, offsetToFrame)
|
||||
if err != nil {
|
||||
err = listener.maintainConn(listener.accepted, i, err)
|
||||
}
|
||||
|
||||
@@ -92,9 +92,9 @@ DROP:
|
||||
return lneto.ErrPacketDrop
|
||||
}
|
||||
|
||||
func (ls *StackEthernet) Encapsulate(carrierData []byte, frameOffset int) (n int, err error) {
|
||||
func (ls *StackEthernet) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int) (n int, err error) {
|
||||
mtu := ls.mtu
|
||||
dst := carrierData[frameOffset:]
|
||||
dst := carrierData[offsetToFrame:]
|
||||
if len(dst) < int(mtu) {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
@@ -104,7 +104,12 @@ func (ls *StackEthernet) Encapsulate(carrierData []byte, frameOffset int) (n int
|
||||
}
|
||||
*efrm.DestinationHardwareAddr() = ls.gwmac
|
||||
var h *node
|
||||
h, n, err = ls.handlers.encapsulateAny(dst[:mtu], 14)
|
||||
// Children (IP/ARP) start at offset 14 (after ethernet header).
|
||||
// For IP: offsetToIP=14, offsetToFrame=14
|
||||
// For ARP: offsetToIP=-1, offsetToFrame=14 (but ARP ignores offsetToIP)
|
||||
// Clip carrierData to MTU to prevent writes beyond MTU limit.
|
||||
mtuLimit := offsetToFrame + int(mtu)
|
||||
h, n, err = ls.handlers.encapsulateAny(carrierData[:mtuLimit], offsetToFrame+14, offsetToFrame+14)
|
||||
if n == 0 {
|
||||
return n, err
|
||||
}
|
||||
|
||||
@@ -140,8 +140,8 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (sb *StackIP) Encapsulate(carrierData []byte, frameOffset int) (int, error) {
|
||||
frame := carrierData[frameOffset:]
|
||||
func (sb *StackIP) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int) (int, error) {
|
||||
frame := carrierData[offsetToFrame:]
|
||||
if len(frame) < 256 {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
@@ -158,7 +158,9 @@ func (sb *StackIP) Encapsulate(carrierData []byte, frameOffset int) (int, error)
|
||||
ifrm.SetTTL(64)
|
||||
*ifrm.SourceAddr() = sb.ip
|
||||
sb.ipID = id
|
||||
node, n, err := sb.handlers.encapsulateAny(frame, headerlen)
|
||||
// Children (TCP/UDP) start at offset headerlen (20 bytes after IP header start).
|
||||
// offsetToIP is 0 relative to this slice (frame), children's frame starts at headerlen.
|
||||
node, n, err := sb.handlers.encapsulateAny(carrierData, offsetToFrame, offsetToFrame+headerlen)
|
||||
if n == 0 {
|
||||
return n, err
|
||||
}
|
||||
|
||||
@@ -46,11 +46,11 @@ func (ps *StackPorts) Protocol() uint64 { return uint64(ps.protocol) }
|
||||
|
||||
func (ps *StackPorts) ConnectionID() *uint64 { return &ps.connID }
|
||||
|
||||
func (ps *StackPorts) Encapsulate(b []byte, offset int) (n int, err error) {
|
||||
if int(ps.dstPortOff)+offset+2 > len(b) {
|
||||
func (ps *StackPorts) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int) (n int, err error) {
|
||||
if int(ps.dstPortOff)+offsetToFrame+2 > len(carrierData) {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
_, n, err = ps.handlers.encapsulateAny(b, offset)
|
||||
_, n, err = ps.handlers.encapsulateAny(carrierData, offsetToIP, offsetToFrame)
|
||||
return n, err
|
||||
}
|
||||
|
||||
|
||||
@@ -61,24 +61,25 @@ func (sudp *StackUDPPort) Demux(carrierData []byte, frameOffset int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (sudp *StackUDPPort) Encapsulate(carrierData []byte, frameOffset int) (int, error) {
|
||||
func (sudp *StackUDPPort) Encapsulate(carrierData []byte, offsetToIP, offsetToFrame int) (int, error) {
|
||||
if sudp.h.IsInvalid() {
|
||||
sudp.h.destroy()
|
||||
return 0, net.ErrClosed
|
||||
}
|
||||
ufrm, err := udp.NewFrame(carrierData[frameOffset:])
|
||||
ufrm, err := udp.NewFrame(carrierData[offsetToFrame:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ufrm.SetSourcePort(sudp.h.port)
|
||||
ufrm.SetDestinationPort(sudp.rmport)
|
||||
if len(sudp.raddr) > 0 && frameOffset >= 20 {
|
||||
err = internal.SetIPAddrs(carrierData, 0, nil, sudp.raddr)
|
||||
if len(sudp.raddr) > 0 && offsetToIP >= 0 {
|
||||
err = internal.SetIPAddrs(carrierData[offsetToIP:], 0, nil, sudp.raddr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
n, err := sudp.h.encapsulate(carrierData, frameOffset+8)
|
||||
// Child payload starts 8 bytes after UDP header start.
|
||||
n, err := sudp.h.encapsulate(carrierData, offsetToIP, offsetToFrame+8)
|
||||
if n == 0 {
|
||||
if err != nil {
|
||||
slog.Error("stackudp:encapsulate", slog.String("err", err.Error()))
|
||||
|
||||
@@ -44,7 +44,7 @@ func TestBasicStack2(t *testing.T) {
|
||||
|
||||
func expectExchange(t *testing.T, from, to *StackIP, buf []byte) {
|
||||
t.Helper()
|
||||
n, err := from.Encapsulate(buf, 0)
|
||||
n, err := from.Encapsulate(buf, -1, 0)
|
||||
if err != nil {
|
||||
t.Error("expectExchange:encapsulate:", err)
|
||||
} else if n == 0 {
|
||||
|
||||
Reference in New Issue
Block a user