mirror of
https://github.com/soypat/lneto.git
synced 2026-07-26 02:28:45 +00:00
a2970b923d
* add ipv6 to xnet.StackAsync * dns improvements * improve DNS workings of StackAsync * add tentative ICMPv6 * work on prefixes and fix some small bugs, plan UDP/TCP6 * fix bugs in StackAsync and ipv4.Prefix.Contains * update arpsubtable * completely remove legacy internet.StackIP for StackIPv4/v6 * ipv4/ipv6 tcp/udp * add TCP6/UDP6 dialing APIs * add xnet.Stack6 interface * more ipv6 integration into StackAsync; various tweaks to lneto and documentation+TODOs * add stack6 tests * replace netip.Prefix with ipv4.Prefix where it makes sense
175 lines
5.5 KiB
Go
175 lines
5.5 KiB
Go
package lneto_test
|
|
|
|
import (
|
|
"bytes"
|
|
"math/rand"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/soypat/lneto"
|
|
"github.com/soypat/lneto/ethernet"
|
|
"github.com/soypat/lneto/internal"
|
|
"github.com/soypat/lneto/internal/ltesto"
|
|
"github.com/soypat/lneto/ipv4"
|
|
"github.com/soypat/lneto/tcp"
|
|
)
|
|
|
|
func TestTCPMarshalUnmarshal(t *testing.T) {
|
|
rng := rand.New(rand.NewSource(1))
|
|
var gen ltesto.PacketGen
|
|
gen.RandomizeAddrs(rng)
|
|
const maxSize = 4096
|
|
src := make([]byte, maxSize)
|
|
dst := make([]byte, maxSize)
|
|
for range 512 {
|
|
src = gen.AppendRandomIPv4TCPPacket(src[:0], rng, tcp.Segment{
|
|
SEQ: tcp.Value(rng.Int()),
|
|
ACK: tcp.Value(rng.Int()),
|
|
DATALEN: tcp.Size(rng.Intn(256)),
|
|
WND: tcp.Size(rng.Intn(1024)),
|
|
Flags: tcp.FlagACK,
|
|
})
|
|
dst = dst[:len(src)]
|
|
testMoveTCPPacket(t, src, dst)
|
|
if !internal.BytesEqual(src, dst) {
|
|
t.Fatal("mismatching data")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testMoveTCPPacket(t *testing.T, src, dst []byte) {
|
|
if len(src) != len(dst) {
|
|
panic("expect src and dst same length")
|
|
}
|
|
efrm, err := ethernet.NewFrame(src)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
epl := efrm.Payload()
|
|
ifrm, err := ipv4.NewFrame(epl)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ipl := ifrm.Payload()
|
|
tfrm, err := tcp.NewFrame(ipl)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
efrm2, _ := ethernet.NewFrame(dst)
|
|
*efrm2.DestinationHardwareAddr() = *efrm.DestinationHardwareAddr()
|
|
*efrm2.SourceHardwareAddr() = *efrm.SourceHardwareAddr()
|
|
efrm2.SetEtherType(efrm.EtherTypeOrSize())
|
|
if efrm.IsVLAN() {
|
|
efrm2.SetVLAN(efrm.VLAN())
|
|
}
|
|
ifrm2, _ := ipv4.NewFrame(efrm2.Payload())
|
|
ifrm2.SetVersionAndIHL(ifrm.VersionAndIHL())
|
|
ifrm2.SetToS(ifrm.ToS())
|
|
ifrm2.SetFlags(ifrm.Flags())
|
|
ifrm2.SetTotalLength(ifrm.TotalLength())
|
|
ifrm2.SetID(ifrm.ID())
|
|
ifrm2.SetTTL(ifrm.TTL())
|
|
ifrm2.SetProtocol(ifrm.Protocol())
|
|
ifrm2.SetCRC(ifrm.CRC())
|
|
*ifrm2.SourceAddr() = *ifrm.SourceAddr()
|
|
*ifrm2.DestinationAddr() = *ifrm.DestinationAddr()
|
|
|
|
tfrm2, _ := tcp.NewFrame(ifrm2.Payload())
|
|
tfrm2.SetSourcePort(tfrm.SourcePort())
|
|
tfrm2.SetDestinationPort(tfrm.DestinationPort())
|
|
tfrm2.SetSeq(tfrm.Seq())
|
|
tfrm2.SetAck(tfrm.Ack())
|
|
tfrm2.SetOffsetAndFlags(tfrm.OffsetAndFlags())
|
|
tfrm2.SetWindowSize(tfrm.WindowSize())
|
|
tfrm2.SetCRC(tfrm.CRC())
|
|
tfrm2.SetUrgentPtr(tfrm.UrgentPtr())
|
|
|
|
copy(ifrm2.Options(), ifrm.Options())
|
|
copy(tfrm2.Options(), tfrm.Options())
|
|
copy(tfrm2.Payload(), tfrm.Payload())
|
|
|
|
elen := efrm.HeaderLength()
|
|
if !internal.BytesEqual(src[:elen], dst[:elen]) {
|
|
t.Fatalf("Ethernet header mismatch\n%x\n%x", src[:elen], dst[:elen])
|
|
}
|
|
ilen := ifrm.HeaderLength()
|
|
if !internal.BytesEqual(src[elen:elen+20], dst[elen:elen+20]) {
|
|
t.Fatalf("IPv4 header mismatch\n%x\n%x", src[elen:elen+20], dst[elen:elen+20])
|
|
}
|
|
ipoptLen := len(ifrm.Options())
|
|
if !internal.BytesEqual(ifrm.Options(), ifrm2.Options()) {
|
|
t.Fatalf("IPv4 options mismatch\n%x\n%x", ifrm.Options(), ifrm2.Options())
|
|
} else if ipoptLen > 0 && &ifrm.Options()[0] != &src[elen+20] {
|
|
t.Fatal("IPv4 options start pointer mismatch")
|
|
}
|
|
|
|
tlen := tfrm.HeaderLength()
|
|
toff := elen + ilen + ipoptLen
|
|
if !internal.BytesEqual(src[toff:toff+tlen], dst[toff:toff+tlen]) {
|
|
t.Fatalf("TCP header mismatch\n%x\n%x", src[toff:toff+tlen], dst[toff:toff+tlen])
|
|
}
|
|
payload := tfrm.Payload()
|
|
|
|
if !internal.BytesEqual(payload, tfrm2.Payload()) {
|
|
t.Fatalf("payload mismatch %d %d", len(payload), len(tfrm2.Payload()))
|
|
}
|
|
}
|
|
|
|
func TestIPv4TCPChecksum(t *testing.T) {
|
|
var tcpPackets = [][]byte{
|
|
{0xc0, 0xff, 0xee, 0x00, 0xde, 0xad, 0x4e, 0x8b, 0x3a, 0xf9, 0xfb, 0x6b, 0x08, 0x00, 0x45, 0x00,
|
|
0x00, 0x3c, 0x01, 0xbe, 0x40, 0x00, 0x40, 0x06, 0xa3, 0xaa, 0xc0, 0xa8, 0x0a, 0x01, 0xc0, 0xa8,
|
|
0x0a, 0x02, 0xe7, 0x0a, 0x00, 0x50, 0x40, 0x60, 0xd5, 0xcc, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
|
|
0xfa, 0xf0, 0x62, 0xbc, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xbb, 0xac,
|
|
0x9b, 0xca, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07},
|
|
{0xc0, 0xff, 0xee, 0x00, 0xde, 0xad, 0x4e, 0x8b, 0x3a, 0xf9, 0xfb, 0x6b, 0x08, 0x00, 0x45, 0x00,
|
|
0x00, 0x3c, 0xfa, 0xfd, 0x40, 0x00, 0x40, 0x06, 0xaa, 0x6a, 0xc0, 0xa8, 0x0a, 0x01, 0xc0, 0xa8,
|
|
0x0a, 0x02, 0xe7, 0x0e, 0x00, 0x50, 0x9c, 0xdc, 0xfe, 0x05, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02,
|
|
0xfa, 0xf0, 0xde, 0x02, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a, 0xbb, 0xac,
|
|
0x9b, 0xca, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07},
|
|
}
|
|
var vld lneto.Validator
|
|
for _, tcpPacket := range tcpPackets {
|
|
efrm, _ := ethernet.NewFrame(tcpPacket)
|
|
efrm.ValidateSize(&vld)
|
|
ifrm, _ := ipv4.NewFrame(efrm.Payload())
|
|
ifrm.ValidateSize(&vld)
|
|
tfrm, _ := tcp.NewFrame(ifrm.Payload())
|
|
tfrm.ValidateExceptCRC(&vld)
|
|
if err := vld.ErrPop(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wantCRC := ifrm.CRC()
|
|
// Zero the CRC field so its value does not add to the final result.
|
|
ifrm.SetCRC(0)
|
|
gotCRC := ifrm.CalculateHeaderCRC()
|
|
if wantCRC != gotCRC {
|
|
t.Errorf("IPv4 CRC miscalculated. want %x, got %x", wantCRC, gotCRC)
|
|
}
|
|
wantCRC = tfrm.CRC()
|
|
var crc lneto.CRC791
|
|
ifrm.CRCWriteTCPPseudo(&crc)
|
|
// Zero the CRC field so its value does not add to the final result.
|
|
tfrm.SetCRC(0)
|
|
gotCRC = crc.PayloadSum16(tfrm.RawData())
|
|
if wantCRC != gotCRC {
|
|
t.Errorf("TCP CRC miscalculated. want %x, got %x", wantCRC, gotCRC)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNoDeps(t *testing.T) {
|
|
data, err := os.ReadFile("go.mod")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
const expect = "module github.com/soypat/lneto\n\ngo 1.2"
|
|
if !bytes.HasPrefix(data, []byte(expect)) {
|
|
t.Fatalf("unexpected go.mod file:\nexpect:%sx\ngot:%s", expect, string(data))
|
|
}
|
|
if bytes.Contains(data, []byte("require")) {
|
|
t.Fatal("no dependencies allowed in lneto")
|
|
}
|
|
}
|