diff --git a/errors.go b/errors.go index 7275af0..ca86c8f 100644 --- a/errors.go +++ b/errors.go @@ -21,6 +21,7 @@ type errGeneric uint8 const ( _ errGeneric = iota // non-initialized err ErrPacketDrop // packet dropped + ErrBadCRC // incorrect checksum ) func (err errGeneric) Error() string { diff --git a/ethernet/definitions.go b/ethernet/definitions.go index 80c50cd..63c9c57 100644 --- a/ethernet/definitions.go +++ b/ethernet/definitions.go @@ -1,9 +1,28 @@ package ethernet +import ( + "strconv" +) + const ( sizeHeaderNoVLAN = 14 ) +// AppendAddr appends the text representation of the hardware address to the destination buffer. +func AppendAddr(dst []byte, hwAddr [6]byte) []byte { + for i, b := range hwAddr { + if i != 0 { + dst = append(dst, ':') + } + if b < 16 { + dst = append(dst, '0') + } + dst = strconv.AppendUint(dst, uint64(b), 16) + } + return dst +} + +// BroadcastAddr returns the all 0xff's broadcast hardware/MAC/EUI/OUI address. func BroadcastAddr() [6]byte { return [6]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff} } diff --git a/examples/xnet/main.go b/examples/xnet/main.go index 6e68f19..d91b29d 100644 --- a/examples/xnet/main.go +++ b/examples/xnet/main.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "encoding/hex" "errors" "flag" @@ -17,6 +18,7 @@ import ( "github.com/soypat/lneto" "github.com/soypat/lneto/dns" + "github.com/soypat/lneto/ethernet" "github.com/soypat/lneto/http/httpraw" "github.com/soypat/lneto/internal" "github.com/soypat/lneto/internal/ltesto" @@ -129,6 +131,8 @@ func run() (err error) { pfbuf = fmt.Appendf(pfbuf[:0], "%-3s %3d", context, len(pkt)) pfbuf = append(pfbuf, ' ', '[') pfbuf, err = pf.FormatFrames(pfbuf, frames, pkt) + pfbuf = bytes.ReplaceAll(pfbuf, stack.Addr().AppendTo(nil), []byte("us")) + pfbuf = bytes.ReplaceAll(pfbuf, ethernet.AppendAddr(nil, stack.HardwareAddress()), []byte("us")) pfbuf = append(pfbuf, ']', '\n') if err != nil { return err diff --git a/internet/definitions.go b/internet/definitions.go index 010a896..583cfd3 100644 --- a/internet/definitions.go +++ b/internet/definitions.go @@ -6,6 +6,8 @@ import ( "math" "net" "slices" + + "github.com/soypat/lneto" ) // StackNode is an abstraction of a packet exchanging protocol controller. This is the building block for all protocols, @@ -148,19 +150,20 @@ func (h *handlers) nodeByPortProto(port uint16, protocol uint16) *node { func (h *handlers) demuxByProto(buf []byte, offset int, proto uint16) (*node, error) { node := h.nodeByProto(proto) if node == nil { - return nil, nil + return nil, lneto.ErrPacketDrop } err := node.demux(buf, offset) if h.tryHandleError(node, err) { err = nil } + return node, err } func (h *handlers) demuxByPort(buf []byte, offset int, port uint16) (*node, error) { node := h.nodeByPort(port) if node == nil { - return nil, nil + return nil, lneto.ErrPacketDrop } err := node.demux(buf, offset) if h.tryHandleError(node, err) { diff --git a/internet/pcap/format.go b/internet/pcap/format.go index e006454..e8ec509 100644 --- a/internet/pcap/format.go +++ b/internet/pcap/format.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/soypat/lneto" + "github.com/soypat/lneto/ethernet" "github.com/soypat/lneto/tcp" ) @@ -122,15 +123,7 @@ func (f *Formatter) formatField(dst []byte, pktStartOff int, field FrameField, p } else if field.BitLength == 4*8 { dst = netip.AddrFrom4([4]byte(f.buf)).AppendTo(dst) } else if field.BitLength == 6*8 { - for i := range f.buf { - if i != 0 { - dst = append(dst, ':') - } - if f.buf[i] < 16 { - dst = append(dst, '0') - } - dst = strconv.AppendUint(dst, uint64(f.buf[i]), 16) - } + dst = ethernet.AppendAddr(dst, [6]byte(f.buf)) } else if field.BitLength == 16*8 { dst = netip.AddrFrom16([16]byte(f.buf)).AppendTo(dst) } else { diff --git a/internet/stack-ip.go b/internet/stack-ip.go index a4ec5ce..5e465ab 100644 --- a/internet/stack-ip.go +++ b/internet/stack-ip.go @@ -80,19 +80,21 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error { } dst := ifrm.DestinationAddr() if sb.ip != ([4]byte{}) && *dst != sb.ip { - return errors.New("not meant for us") // Not meant for us. + sb.handlers.debug("ip:not-for-us") + return lneto.ErrPacketDrop // Not meant for us. } sb.validator.ResetErr() ifrm.ValidateExceptCRC(&sb.validator) if err = sb.validator.ErrPop(); err != nil { + sb.handlers.error("ip:Demux.validate") return err } gotCRC := ifrm.CRC() wantCRC := ifrm.CalculateHeaderCRC() if gotCRC != wantCRC { sb.handlers.error("StackIP:Demux:crc-mismatch", slog.Uint64("want", uint64(wantCRC)), slog.Uint64("got", uint64(gotCRC))) - return errors.New("IPv4 CRC mismatch") + return lneto.ErrBadCRC } off := ifrm.HeaderLength() totalLen := ifrm.TotalLength() @@ -104,8 +106,8 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error { // nodeIdx := getNodeByProto(sb.handlers, uint16(proto)) if node == nil { // Drop packet. - sb.handlers.info("iprecv:drop", slog.String("dstaddr", netip.AddrFrom4(*ifrm.DestinationAddr()).String()), slog.String("proto", ifrm.Protocol().String())) - return nil + sb.handlers.info("ip:demux.drop", slog.String("dstaddr", netip.AddrFrom4(*ifrm.DestinationAddr()).String()), slog.String("proto", ifrm.Protocol().String())) + return lneto.ErrPacketDrop } // Incoming CRC Validation of common IP Protocols. var crc lneto.CRC791 @@ -118,7 +120,8 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error { } tfrm.CRCWrite(&crc) if crc.Sum16() != tfrm.CRC() { - return errors.New("TCP CRC mismatch") + sb.handlers.error("ip:demux.tcpcrc") + return lneto.ErrBadCRC } case lneto.IPProtoUDP: ifrm.CRCWriteUDPPseudo(&crc) @@ -128,7 +131,8 @@ func (sb *StackIP) Demux(carrierData []byte, offset int) error { } ufrm.CRCWriteIPv4(&crc) if crc.Sum16() != ufrm.CRC() { - return errors.New("UDP CRC mismatch") + sb.handlers.error("ip:demux.udpcrc") + return lneto.ErrBadCRC } } sb.handlers.info("ipDemux", slog.String("ipproto", proto.String()), slog.Int("plen", int(totalLen))) diff --git a/internet/stack-udpport.go b/internet/stack-udpport.go index e64615f..ad60790 100644 --- a/internet/stack-udpport.go +++ b/internet/stack-udpport.go @@ -43,13 +43,13 @@ func (sudp *StackUDPPort) Demux(carrierData []byte, frameOffset int) error { } dst := ufrm.DestinationPort() if dst != sudp.h.port { - return nil // Not meant for us. + return lneto.ErrPacketDrop // Not meant for us. } // TODO remote ip address handling. src := ufrm.SourcePort() if sudp.rmport != 0 && src != sudp.rmport { - return nil // Not from our target remote port. + return lneto.ErrPacketDrop // Not from our target remote port. } err = sudp.h.demux(carrierData, frameOffset+8) if err != nil {