mirror of
https://github.com/soypat/lneto.git
synced 2026-08-15 04:13:44 +00:00
add ipv4 frame tests; fix protocol setting
This commit is contained in:
@@ -61,7 +61,8 @@ func (sb *StackBasic) Recv(frame []byte) error {
|
||||
totalLen := ifrm.TotalLength()
|
||||
for i := range sb.handlers {
|
||||
h := &sb.handlers[i]
|
||||
if h.proto == ifrm.Protocol() {
|
||||
proto := ifrm.Protocol()
|
||||
if h.proto == proto {
|
||||
return h.recv(frame[:totalLen], off)
|
||||
}
|
||||
}
|
||||
@@ -92,6 +93,7 @@ func (sb *StackBasic) Handle(frame []byte) (int, error) {
|
||||
ifrm.SetTotalLength(uint16(totalLen))
|
||||
ifrm.SetFlags(dontFrag)
|
||||
ifrm.SetTTL(64)
|
||||
ifrm.SetProtocol(h.proto)
|
||||
ifrm.SetCRC(ifrm.CalculateHeaderCRC())
|
||||
if ifrm.Protocol() == lneto.IPProtoTCP {
|
||||
tfrm, _ := tcp.NewFrame(ifrm.Payload())
|
||||
|
||||
@@ -14,9 +14,11 @@ func TestBasicStack(t *testing.T) {
|
||||
var connCl, connSv TCPConn
|
||||
setupClientServer(t, rng, &sbCl, &sbSv, &connCl, &connSv)
|
||||
var buf [2048]byte
|
||||
nextToSend := &sbCl
|
||||
nextToRecv := &sbSv
|
||||
exchangeAndExpectStates := func(clState, svState tcp.State) {
|
||||
t.Helper()
|
||||
expectExchange(t, &sbCl, &sbSv, buf[:])
|
||||
expectExchange(t, nextToSend, nextToRecv, buf[:])
|
||||
gotCl := connCl.State()
|
||||
gotSv := connSv.State()
|
||||
if gotCl != clState {
|
||||
@@ -25,20 +27,25 @@ func TestBasicStack(t *testing.T) {
|
||||
if gotSv != svState {
|
||||
t.Errorf("want server state %s, got %s", svState, gotSv)
|
||||
}
|
||||
nextToSend, nextToRecv = nextToRecv, nextToSend
|
||||
}
|
||||
exchangeAndExpectStates(tcp.StateSynSent, tcp.StateListen)
|
||||
exchangeAndExpectStates(tcp.StateSynSent, tcp.StateSynRcvd) // Client sends over first SYN and server receives it.
|
||||
exchangeAndExpectStates(tcp.StateEstablished, tcp.StateSynRcvd) // server sends back SYNACK, establishing connection on client side.
|
||||
exchangeAndExpectStates(tcp.StateEstablished, tcp.StateEstablished) // Client sends ACK, establishing connection in full.
|
||||
}
|
||||
|
||||
func expectExchange(t *testing.T, from, to *StackBasic, buf []byte) {
|
||||
t.Helper()
|
||||
n, err := from.Handle(buf)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Error("expectExchange:Handle:", err)
|
||||
} else if n == 0 {
|
||||
t.Error("expected data exchange")
|
||||
return
|
||||
}
|
||||
err = to.Recv(buf[:n])
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Error("expectExchange:Recv:", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ const (
|
||||
sizeHeader = 20
|
||||
)
|
||||
|
||||
// ToS represents the Traffic Class (a.k.a Type of Service).
|
||||
// ToS represents the Traffic Class (a.k.a Type of Service). It is 8 bits long. 6 MSB are Differentiated Services; 2 LSB are Explicit Congenstion Notification.
|
||||
type ToS uint8
|
||||
|
||||
// DS returns the top 6 bits of the IPv4 ToS holding the Differentiated Services field
|
||||
@@ -14,7 +14,7 @@ func (tos ToS) DS() uint8 { return uint8(tos) >> 2 }
|
||||
// ECN is the Explicit Congestion Notification which provides congestion control and non-congestion control traffic.
|
||||
func (tos ToS) ECN() uint8 { return uint8(tos & 0b11) }
|
||||
|
||||
// Flags holds fragmentation field data of an IPv4 header.
|
||||
// Flags holds fragmentation field data of an IPv4 header. It is 16 bits long.
|
||||
type Flags uint16
|
||||
|
||||
// IsEvil returns true if evil bit set as per [RFC3514].
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
package ipv4
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/soypat/lneto"
|
||||
)
|
||||
|
||||
func TestFrame(t *testing.T) {
|
||||
var buf [1024]byte
|
||||
|
||||
ifrm, err := NewFrame(buf[:])
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rng := rand.New(rand.NewSource(1))
|
||||
const wantVersion = 4
|
||||
v := new(lneto.Validator)
|
||||
for i := 0; i < 100; i++ {
|
||||
// SET VALUES:
|
||||
wantIHL := uint8(5 + rng.Intn(10))
|
||||
wantToS := ToS(rng.Intn(4))
|
||||
ifrm.SetVersionAndIHL(wantVersion, wantIHL)
|
||||
wantPayloadLen := rng.Intn(6)
|
||||
ifrm.SetToS(wantToS)
|
||||
wantTotalLength := 4*uint16(wantIHL) + uint16(wantPayloadLen)
|
||||
ifrm.SetTotalLength(wantTotalLength)
|
||||
wantID := uint16(rng.Intn(math.MaxUint16))
|
||||
ifrm.SetID(wantID)
|
||||
wantFlags := Flags(rng.Intn(16))
|
||||
ifrm.SetFlags(wantFlags)
|
||||
wantTTL := uint8(rng.Intn(256))
|
||||
ifrm.SetTTL(wantTTL)
|
||||
wantProtocol := lneto.IPProto(rng.Intn(256))
|
||||
ifrm.SetProtocol(wantProtocol)
|
||||
wantCRC := uint16(rng.Intn(math.MaxUint16))
|
||||
ifrm.SetCRC(wantCRC)
|
||||
src := ifrm.SourceAddr()
|
||||
rng.Read(src[:])
|
||||
wantSrc := *src
|
||||
dst := ifrm.DestinationAddr()
|
||||
rng.Read(dst[:])
|
||||
wantDst := *dst
|
||||
ifrm.ValidateExceptCRC(v)
|
||||
ifrm.ValidateSize(v)
|
||||
if v.Err() != nil {
|
||||
t.Error(v.Err())
|
||||
}
|
||||
|
||||
// OPTION+PAYLOAD VALIDATION:
|
||||
opts := ifrm.Options()
|
||||
payload := ifrm.Payload()
|
||||
payloadOff := int(wantIHL) * 4
|
||||
wantOptions := buf[sizeHeader:payloadOff]
|
||||
wantPayload := buf[payloadOff : payloadOff+wantPayloadLen]
|
||||
if len(payload) != wantPayloadLen {
|
||||
t.Errorf("want payload length %d, got %d", wantPayloadLen, len(payload))
|
||||
}
|
||||
if len(opts) != len(wantOptions) {
|
||||
t.Errorf("want length of options %d, got %d", len(wantOptions), len(opts))
|
||||
}
|
||||
if len(opts) > 0 && &wantOptions[0] != &opts[0] {
|
||||
t.Error("first byte of options unexpected pointer")
|
||||
}
|
||||
if len(payload) > 0 && &wantPayload[0] != &payload[0] {
|
||||
t.Error("first byte of payload unexpected pointer")
|
||||
}
|
||||
if len(payload) > 0 {
|
||||
payload[0] = byte(rng.Int()) // write over start of payload to catch field aliasing.
|
||||
}
|
||||
if len(opts) > 0 {
|
||||
opts[0] = byte(rng.Int()) // Catch field aliasing.
|
||||
}
|
||||
|
||||
// FIELD VALIDATION:
|
||||
if ver, ihl := ifrm.VersionAndIHL(); ver != wantVersion || ihl != wantIHL {
|
||||
t.Errorf("wanted IHL %d, got version,IHL %d,%d ", wantIHL, ver, ihl)
|
||||
}
|
||||
if tos := ifrm.ToS(); tos != wantToS {
|
||||
t.Errorf("wanted ToS %d, got %d", wantToS, tos)
|
||||
}
|
||||
if tl := ifrm.TotalLength(); tl != wantTotalLength {
|
||||
t.Errorf("wanted total length %d, got %d", wantTotalLength, tl)
|
||||
}
|
||||
if id := ifrm.ID(); id != wantID {
|
||||
t.Errorf("want ID %d, got %d", wantID, id)
|
||||
}
|
||||
if flags := ifrm.Flags(); flags != wantFlags {
|
||||
t.Errorf("want flags %d, got %d", wantFlags, flags)
|
||||
}
|
||||
if ttl := ifrm.TTL(); ttl != wantTTL {
|
||||
t.Errorf("want TTL %d, got %d", wantTTL, ttl)
|
||||
}
|
||||
if proto := ifrm.Protocol(); proto != wantProtocol {
|
||||
t.Errorf("want protocol %d, got %d", wantProtocol, proto)
|
||||
}
|
||||
if crc := ifrm.CRC(); crc != wantCRC {
|
||||
t.Errorf("want crc %d, got %d", wantCRC, crc)
|
||||
}
|
||||
if wantDst != *dst {
|
||||
t.Errorf("want dst addr %d, got %d", wantDst, dst)
|
||||
}
|
||||
if wantSrc != *src {
|
||||
t.Errorf("want src addr %d, got %d", wantSrc, src)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user