mirror of
https://github.com/soypat/lneto.git
synced 2026-08-22 23:49:08 +00:00
more effort into understanding why TAP interface is so slow on my linux machine to no avail
This commit is contained in:
@@ -4,7 +4,9 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"net/netip"
|
||||
"slices"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
"github.com/soypat/lneto/internal"
|
||||
@@ -66,7 +68,12 @@ func (sb *StackBasic) Recv(frame []byte) error {
|
||||
proto := ifrm.Protocol()
|
||||
if h.proto == proto {
|
||||
sb.info("iprecv", slog.String("ipproto", proto.String()), slog.Int("plen", int(totalLen)))
|
||||
return h.recv(frame[:totalLen], off)
|
||||
err = h.recv(frame[:totalLen], off)
|
||||
if err == net.ErrClosed {
|
||||
sb.info("ipclose", slog.String("proto", proto.String()))
|
||||
sb.handlers = slices.Delete(sb.handlers, i, i+1)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+135
-5
@@ -12,9 +12,13 @@ import (
|
||||
"github.com/soypat/lneto/ethernet"
|
||||
"github.com/soypat/lneto/http/httpraw"
|
||||
"github.com/soypat/lneto/ipv4"
|
||||
"github.com/soypat/lneto/ipv6"
|
||||
"github.com/soypat/lneto/tcp"
|
||||
"github.com/soypat/lneto/udp"
|
||||
)
|
||||
|
||||
const unknownPayloadProto = "payload?"
|
||||
|
||||
type PacketBreakdown struct {
|
||||
hdr httpraw.Header
|
||||
vld lneto.Validator
|
||||
@@ -115,6 +119,29 @@ func (pc *PacketBreakdown) CaptureARP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureIPv6(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("IPv6 must be parsed at byte boundary")
|
||||
}
|
||||
ifrm6, err := ipv6.NewFrame(pkt[bitOffset/8:])
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
ifrm6.ValidateSize(pc.validator())
|
||||
if pc.validator().HasError() {
|
||||
return dst, pc.validator().Err()
|
||||
}
|
||||
finfo := Frame{
|
||||
Protocol: ethernet.TypeIPv6,
|
||||
PacketBitOffset: bitOffset,
|
||||
}
|
||||
finfo.Fields = append(finfo.Fields, baseIPv6Fields[:]...)
|
||||
dst = append(dst, finfo)
|
||||
proto := ifrm6.NextHeader()
|
||||
end := 40 * octet
|
||||
return pc.captureIPProto(proto, dst, pkt, end)
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("IPv4 must be parsed at byte boundary")
|
||||
@@ -143,11 +170,17 @@ func (pc *PacketBreakdown) CaptureIPv4(dst []Frame, pkt []byte, bitOffset int) (
|
||||
proto := ifrm4.Protocol()
|
||||
dst = append(dst, finfo)
|
||||
end := bitOffset + octet*ifrm4.HeaderLength()
|
||||
return pc.captureIPProto(proto, dst, pkt, end)
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) captureIPProto(proto lneto.IPProto, dst []Frame, pkt []byte, bitOffset int) (_ []Frame, err error) {
|
||||
switch proto {
|
||||
case lneto.IPProtoTCP:
|
||||
dst, err = pc.CaptureTCP(dst, pkt, end)
|
||||
dst, err = pc.CaptureTCP(dst, pkt, bitOffset)
|
||||
case lneto.IPProtoUDP:
|
||||
dst, err = pc.CaptureUDP(dst, pkt, bitOffset)
|
||||
default:
|
||||
dst = append(dst, remainingFrameInfo(proto, 0, end, octet*len(pkt)))
|
||||
dst = append(dst, remainingFrameInfo(proto, 0, bitOffset, octet*len(pkt)))
|
||||
}
|
||||
return dst, err
|
||||
}
|
||||
@@ -183,12 +216,35 @@ func (pc *PacketBreakdown) CaptureTCP(dst []Frame, pkt []byte, bitOffset int) ([
|
||||
if len(payload) > 0 {
|
||||
dst, err = pc.CaptureHTTP(dst, pkt, end)
|
||||
if err != nil {
|
||||
dst = append(dst, remainingFrameInfo(nil, FieldClassPayload, end, len(pkt)))
|
||||
dst = append(dst, remainingFrameInfo(unknownPayloadProto, FieldClassPayload, end, octet*len(pkt)))
|
||||
}
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureUDP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
if bitOffset%8 != 0 {
|
||||
return dst, errors.New("UDP must be parsed at byte boundary")
|
||||
}
|
||||
ufrm, err := udp.NewFrame(pkt[bitOffset/8:])
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
ufrm.ValidateSize(pc.validator())
|
||||
if pc.validator().HasError() {
|
||||
return dst, pc.validator().Err()
|
||||
}
|
||||
finfo := Frame{
|
||||
Protocol: lneto.IPProtoUDP,
|
||||
PacketBitOffset: bitOffset,
|
||||
}
|
||||
finfo.Fields = append(finfo.Fields, baseUDPFields[:]...)
|
||||
dst = append(dst, finfo)
|
||||
end := bitOffset + 8*octet
|
||||
dst = append(dst, remainingFrameInfo(unknownPayloadProto, FieldClassPayload, end, octet*len(pkt)))
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func (pc *PacketBreakdown) CaptureHTTP(dst []Frame, pkt []byte, bitOffset int) ([]Frame, error) {
|
||||
const httpProtocol = "HTTP"
|
||||
if bitOffset%8 != 0 {
|
||||
@@ -357,7 +413,6 @@ func (frm Frame) AppendField(dst []byte, fieldIdx int, pkt []byte) ([]byte, erro
|
||||
|
||||
func (frm Frame) String() string {
|
||||
iopt, err := frm.FieldByClass(FieldClassOptions)
|
||||
|
||||
hasOpts := ""
|
||||
if err == nil {
|
||||
hasOpts = fmt.Sprintf(" optlen=%d", (frm.Fields[iopt].BitLength+7)/8)
|
||||
@@ -457,6 +512,56 @@ var baseARPFields = [...]FrameField{
|
||||
},
|
||||
}
|
||||
|
||||
var baseIPv6Fields = [...]FrameField{
|
||||
{
|
||||
Class: FieldClassVersion,
|
||||
FrameBitOffset: 0,
|
||||
BitLength: 4,
|
||||
},
|
||||
{
|
||||
Name: "Type of Service",
|
||||
Class: FieldClassFlags,
|
||||
FrameBitOffset: 4,
|
||||
BitLength: 1 * octet,
|
||||
RightAligned: true,
|
||||
},
|
||||
{
|
||||
Name: "Flow Label",
|
||||
Class: FieldClassID,
|
||||
FrameBitOffset: 12,
|
||||
BitLength: 20,
|
||||
RightAligned: true,
|
||||
},
|
||||
{
|
||||
Name: "Total Length",
|
||||
Class: FieldClassSize,
|
||||
FrameBitOffset: 4 * octet,
|
||||
BitLength: 2 * octet,
|
||||
},
|
||||
{
|
||||
Name: "Next Header",
|
||||
Class: 0,
|
||||
FrameBitOffset: 6 * octet,
|
||||
BitLength: 1 * octet,
|
||||
},
|
||||
{
|
||||
Name: "Hop Limit",
|
||||
Class: 0,
|
||||
FrameBitOffset: 7 * octet,
|
||||
BitLength: 1 * octet,
|
||||
},
|
||||
{
|
||||
Class: FieldClassSrc,
|
||||
FrameBitOffset: 8 * octet,
|
||||
BitLength: 16 * octet,
|
||||
},
|
||||
{
|
||||
Class: FieldClassSrc,
|
||||
FrameBitOffset: 24 * octet,
|
||||
BitLength: 16 * octet,
|
||||
},
|
||||
}
|
||||
|
||||
var baseIPv4Fields = [...]FrameField{
|
||||
{
|
||||
Class: FieldClassVersion,
|
||||
@@ -532,7 +637,7 @@ var baseTCPFields = [...]FrameField{
|
||||
},
|
||||
{
|
||||
Name: "Destination port",
|
||||
Class: FieldClassSrc,
|
||||
Class: FieldClassDst,
|
||||
FrameBitOffset: 2 * octet,
|
||||
BitLength: 2 * octet,
|
||||
},
|
||||
@@ -579,6 +684,31 @@ var baseTCPFields = [...]FrameField{
|
||||
},
|
||||
}
|
||||
|
||||
var baseUDPFields = [...]FrameField{
|
||||
{
|
||||
Name: "Source port",
|
||||
Class: FieldClassSrc,
|
||||
FrameBitOffset: 0,
|
||||
BitLength: 2 * octet,
|
||||
},
|
||||
{
|
||||
Name: "Destination port",
|
||||
Class: FieldClassDst,
|
||||
FrameBitOffset: 2 * octet,
|
||||
BitLength: 2 * octet,
|
||||
},
|
||||
{
|
||||
Class: FieldClassSize,
|
||||
FrameBitOffset: 4 * octet,
|
||||
BitLength: 2 * octet,
|
||||
},
|
||||
{
|
||||
Class: FieldClassChecksum,
|
||||
FrameBitOffset: 6 * octet,
|
||||
BitLength: 2 * octet,
|
||||
},
|
||||
}
|
||||
|
||||
func remainingFrameInfo(proto any, class FieldClass, pktBitOffset, pktBitLen int) Frame {
|
||||
return Frame{
|
||||
Protocol: proto,
|
||||
|
||||
@@ -102,6 +102,16 @@ func TestCap(t *testing.T) {
|
||||
if gotTCPFlags != wantTCPflags {
|
||||
t.Errorf("want %s TCP flags, got %s", wantTCPflags.String(), gotTCPFlags.String())
|
||||
}
|
||||
wanDstPort := gen.DstTCP
|
||||
wantSrcPort := gen.SrcTCP
|
||||
gotSrcPort := uint16(getClass(ptfrm, FieldClassSrc))
|
||||
gotDstPort := uint16(getClass(ptfrm, FieldClassDst))
|
||||
if wantSrcPort != gotSrcPort {
|
||||
t.Errorf("want %d TCP src port, got %d", wantSrcPort, gotSrcPort)
|
||||
}
|
||||
if wanDstPort != gotDstPort {
|
||||
t.Errorf("want %d TCP dst port, got %d", wanDstPort, gotDstPort)
|
||||
}
|
||||
gotHeaderLen := getClass(ptfrm, FieldClassSize)
|
||||
if gotHeaderLen != uint64(wantHeaderLen) {
|
||||
t.Errorf("want %d TCP header length, got %d", wantHeaderLen, gotHeaderLen)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package internet
|
||||
|
||||
import "github.com/soypat/lneto"
|
||||
|
||||
type PortStack struct {
|
||||
handlers []porthandler
|
||||
proto lneto.IPProto
|
||||
}
|
||||
|
||||
type porthandler struct {
|
||||
recv func([]byte, int) error
|
||||
handle func([]byte, int) (int, error)
|
||||
port uint16
|
||||
}
|
||||
Reference in New Issue
Block a user