diff --git a/tlv/tlv.go b/tlv/tlv.go index 2b35ead..74a4523 100644 --- a/tlv/tlv.go +++ b/tlv/tlv.go @@ -1,6 +1,11 @@ //go:generate stringer -type=Type -trimprefix Type //go:generate stringer -type=SubType -trimprefix SubType //go:generate stringer -type=AEType -trimprefix AE + +// Package tlv implements a parser for TLV encoded babel messages defined in rfc8966 +// +// https://datatracker.ietf.org/doc/html/rfc8966#section-4 +// https://datatracker.ietf.org/doc/html/draft-ietf-babel-source-specific-07#section-7 package tlv import ( @@ -11,8 +16,10 @@ import ( "inet.af/netaddr" ) +// Type encodes the type of TLV type Type uint8 +// Type TLV constants const ( TypePad1 = Type(0) TypePadN = Type(1) @@ -29,17 +36,21 @@ const ( TypeHMAC = Type(12) ) +// TLV holds a single TLV type TLV interface { T() Type L() uint8 } +// SubType encodes the type of Sub-TLV type SubType uint8 +// IsMandatory checks if a Sub-TLV is mandatory func (s SubType) IsMandatory() bool { return s >= 128 } +// SubType Sub-TLV constants const ( SubTypePad1 = SubType(0) SubTypePadN = SubType(1) @@ -48,13 +59,16 @@ const ( SubTypeSourcePrefix = SubType(128) ) +// SubTLV holds a single Sub-TLV type SubTLV interface { T() SubType L() uint8 } +// AEType encodes the AE field in TLVs type AEType uint8 +// AEType AE constants const ( AEWildcard = AEType(0) AEIPv4 = AEType(1) @@ -63,9 +77,12 @@ const ( AEIPv4oIPv6 = AEType(4) ) +// AEFromPrefix returns the address encoding of a prefix: func AEFromPrefix(p netaddr.IPPrefix) AEType { return AEFromIP(p.IP()) } + +// AEFromIP returns the address encoding of an address. func AEFromIP(p netaddr.IP) AEType { switch { case p.IsZero(): @@ -80,6 +97,7 @@ func AEFromIP(p netaddr.IP) AEType { panic("unknown AE") } +// Scanner splits bytes into TLV tokens. type Scanner struct { buf []byte err error @@ -87,17 +105,15 @@ type Scanner struct { l uint8 } -func NewTLVScanner(buf []byte) *Scanner { - return &Scanner{ - buf: buf, - } -} - +// Reset resets a scanner state and sets a new byte slice to work on. func (ts *Scanner) Reset(buf []byte) { *ts = Scanner{} ts.buf = buf } +// Scan scans for the next TLV +// +// Returns true if a TLV is found, or false on error or no more TLVs are found. func (ts *Scanner) Scan() bool { if ts.err != nil { return false @@ -140,14 +156,17 @@ func (ts *Scanner) Scan() bool { return true } +// Err returns the first error that occured during scanning. func (ts *Scanner) Err() error { return ts.err } +// Raw returns an unparsed TLV func (ts *Scanner) Raw() Raw { return Raw{ts.t, ts.l, ts.buf[:ts.l:ts.l]} } +// PacketDecoder splits a packet into TLVs and parses their content type PacketDecoder struct { tlvscanner Scanner @@ -163,6 +182,7 @@ type PacketDecoder struct { err error } +// Reset clears the parser state and sets a new byte slice to work on. func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP) { *s = PacketDecoder{} s.tlvscanner.Reset(b) @@ -173,6 +193,9 @@ func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP) { s.nexthopv4 = nexthop } } + +// Scan parses the next TLV. +// Returns true on success or false on error and when no more TLVs can be found. func (s *PacketDecoder) Scan() bool { if s.err != nil { return false @@ -189,20 +212,20 @@ func (s *PacketDecoder) Scan() bool { switch raw.T() { case TypePad1: - s.tlv, s.subtlv, s.err = Pad1FromBytes(raw.V()) + s.tlv, s.subtlv, s.err = pad1FromBytes(raw.V()) case TypePadN: - s.tlv, s.subtlv, s.err = PadNFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = padNFromBytes(raw.V()) case TypeAckReq: - s.tlv, s.subtlv, s.err = AckReqFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = ackReqFromBytes(raw.V()) case TypeAck: - s.tlv, s.subtlv, s.err = AckFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = ackFromBytes(raw.V()) case TypeHello: - s.tlv, s.subtlv, s.err = HelloFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = helloFromBytes(raw.V()) case TypeIHU: - s.tlv, s.subtlv, s.err = IHUFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = ihuFromBytes(raw.V()) case TypeRouterID: var rid RouterID - rid, s.subtlv, s.err = RouterIDFromBytes(raw.V()) + rid, s.subtlv, s.err = routerIDFromBytes(raw.V()) if s.err != nil { break } @@ -211,7 +234,7 @@ func (s *PacketDecoder) Scan() bool { s.routerID = rid case TypeNextHop: var nh NextHop - nh, s.subtlv, s.err = NextHopFromBytes(raw.V()) + nh, s.subtlv, s.err = nextHopFromBytes(raw.V()) if s.err != nil { break } @@ -225,11 +248,11 @@ func (s *PacketDecoder) Scan() bool { s.nexthopv6 = nh.Address } case TypeUpdate: - s.tlv, s.subtlv, s.err = s.UpdateFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = s.updateFromBytes(raw.V()) case TypeRouteRequest: - s.tlv, s.subtlv, s.err = RouteRequestFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = routeRequestFromBytes(raw.V()) case TypeSeqnoRequest: - s.tlv, s.subtlv, s.err = SeqnoRequestFromBytes(raw.V()) + s.tlv, s.subtlv, s.err = seqnoRequestFromBytes(raw.V()) case TypeTSPC: s.tlv = raw s.subtlv = nil @@ -242,49 +265,51 @@ func (s *PacketDecoder) Scan() bool { return s.err == nil } + +// TLV returns the last successfully parsed TLV func (s *PacketDecoder) TLV() TLV { if s.err != nil { return nil } return s.tlv } + +// SubTLV returns the last successfully parsed Sub-TLV func (s *PacketDecoder) SubTLV() []byte { if s.err != nil { return nil } return s.subtlv } + +// Err returns the first error that occured during parsing. func (s *PacketDecoder) Err() error { return s.err } +// Raw holds an unparsed TLV type Raw struct { t Type l uint8 v []byte } +// T returns the Type of a Raw TLV func (t Raw) T() Type { return t.t } +// L returns the value of the length field in a TLV func (t Raw) L() uint8 { return t.l } +// V returns the message body of a TLV func (t Raw) V() []byte { return t.v } -type ErrTypeMismatch struct { - want Type - got Type -} - -func (e ErrTypeMismatch) Error() string { - return fmt.Sprintf("Error parsing TLV: Wrong type %s, wanted %s", e.got, e.want) -} - +// ErrTLVLength is used to inform about invalid length fields in TLVs type ErrTLVLength struct { l int want int @@ -301,6 +326,7 @@ func assertLengthGreater(b []byte, t Type, l int) error { return nil } +// ErrSubTLVLength is used to inform about invalid length fields in Sub-TLVs type ErrSubTLVLength struct { l int want int @@ -317,51 +343,70 @@ func assertSubLengthGreater(b []byte, t SubType, l int) error { return nil } +// Pad1 TLV +// +// 1 byte padding that is silently ignored. // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.1 type Pad1 struct{} +// T returns TypePad1. func (Pad1) T() Type { return TypePad1 } + +// L returns 0 message body length. func (Pad1) L() uint8 { - return 8 + return 0 } -func Pad1FromBytes(b []byte) (Pad1, []byte, error) { + +func pad1FromBytes(b []byte) (Pad1, []byte, error) { if err := assertLengthGreater(b, TypePad1, 0); err != nil { return Pad1{}, b, err } return Pad1{}, b[1:], nil } +// PadN TLV +// +// Multi byte padding that is silently ignored. // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.2 type PadN uint8 +// T returns TypePadN. func (PadN) T() Type { return TypePadN } + +// L returns the length of the padding. func (p PadN) L() uint8 { - return 2 + uint8(p) // TODO: overflow? + return uint8(p) } -func PadNFromBytes(b []byte) (PadN, []byte, error) { + +func padNFromBytes(b []byte) (PadN, []byte, error) { if err := assertLengthGreater(b, TypePadN, 0); err != nil { return PadN(0), b, err } return PadN(b[1]), b[1:], nil } +// AckReq - Acknowledgment Request TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.3 type AckReq struct { Opaque [2]byte Interval uint16 } +// T returns TypePadReq. func (AckReq) T() Type { return TypeAckReq } + +// L 8. func (a AckReq) L() uint8 { return 8 } -func AckReqFromBytes(b []byte) (AckReq, []byte, error) { +func ackReqFromBytes(b []byte) (AckReq, []byte, error) { if err := assertLengthGreater(b, TypeAckReq, 6); err != nil { return AckReq{}, b, err } @@ -374,18 +419,23 @@ func AckReqFromBytes(b []byte) (AckReq, []byte, error) { return ar, b[6:], nil } +// Ack - Acknowledgment TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.4 type Ack struct { Opaque uint16 } +// T returns TypeAck. func (Ack) T() Type { return TypeAck } + +// L is 4. func (Ack) L() uint8 { return 4 } -func AckFromBytes(b []byte) (Ack, []byte, error) { +func ackFromBytes(b []byte) (Ack, []byte, error) { if err := assertLengthGreater(b, TypeAck, 2); err != nil { return Ack{}, b, err } @@ -393,6 +443,8 @@ func AckFromBytes(b []byte) (Ack, []byte, error) { return Ack{uint16(b[0])<<8 | uint16(b[1])}, b[4:], nil } +// Hello TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.5 type Hello struct { Flags uint16 @@ -400,13 +452,16 @@ type Hello struct { Interval uint16 } +// T returns TypeHello. func (Hello) T() Type { return TypeHello } + +// L is 8. func (Hello) L() uint8 { return 8 } -func HelloFromBytes(b []byte) (Hello, []byte, error) { +func helloFromBytes(b []byte) (Hello, []byte, error) { if err := assertLengthGreater(b, TypeHello, 6); err != nil { return Hello{}, b, err } @@ -419,6 +474,8 @@ func HelloFromBytes(b []byte) (Hello, []byte, error) { return h, b[6:], nil } +// IHU - I Heard You TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.6 type IHU struct { // AE uint8 @@ -428,12 +485,17 @@ type IHU struct { Address netaddr.IP } +// T returns TypeIHU. func (IHU) T() Type { return TypeIHU } + +// AE returns the address encofing func (i IHU) AE() AEType { return AEFromIP(i.Address) } + +// L depends on the address enoding, but is at least 6 bytes. func (i IHU) L() uint8 { switch i.AE() { case 0: @@ -447,7 +509,7 @@ func (i IHU) L() uint8 { } panic("invalid AE field") } -func IHUFromBytes(b []byte) (IHU, []byte, error) { +func ihuFromBytes(b []byte) (IHU, []byte, error) { if err := assertLengthGreater(b, TypeIHU, 6); err != nil { return IHU{}, b, err } @@ -463,15 +525,18 @@ func IHUFromBytes(b []byte) (IHU, []byte, error) { return ihu, b, err } +// RouterID TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.7 type RouterID [8]byte +// Errors specific to RouterID. var ( ErrRouterIDZeros = errors.New("Invalid RouterID: consists of all zeros") ErrRouterIDOnes = errors.New("Invalid RouterID: consists of all ones") ) -func RouterIDFromBytes(b []byte) (RouterID, []byte, error) { +func routerIDFromBytes(b []byte) (RouterID, []byte, error) { if err := assertLengthGreater(b, TypeRouterID, 10); err != nil { return RouterID{}, b, err } @@ -490,12 +555,18 @@ func RouterIDFromBytes(b []byte) (RouterID, []byte, error) { return rid, b, nil } + +// T returns TypeRouterID. func (RouterID) T() Type { return TypeRouterID } + +// L is 8. func (RouterID) L() uint8 { return 8 } + +// String formats a Routerid in EUI-64 func (r RouterID) String() string { var buf bytes.Buffer buf.Grow(8*3 - 1) @@ -508,6 +579,8 @@ func (r RouterID) String() string { return buf.String() } +// NextHop TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.8 type NextHop struct { // AE uint8 @@ -515,9 +588,12 @@ type NextHop struct { Address netaddr.IP } +// T returns TypeNextHop. func (NextHop) T() Type { return TypeNextHop } + +// L depends on the address encoding, at least 2. func (n NextHop) L() uint8 { switch AEFromIP(n.Address) { case 1: @@ -529,7 +605,7 @@ func (n NextHop) L() uint8 { } panic("invalid AE field") } -func NextHopFromBytes(b []byte) (NextHop, []byte, error) { +func nextHopFromBytes(b []byte) (NextHop, []byte, error) { if err := assertLengthGreater(b, TypeNextHop, 6); err != nil { return NextHop{}, b, err } @@ -541,6 +617,8 @@ func NextHopFromBytes(b []byte) (NextHop, []byte, error) { return nh, b, err } +// Update TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.9 type Update struct { // AE uint8 @@ -555,18 +633,23 @@ type Update struct { NextHop netaddr.IP } +// T returns TypeUpdate. func (Update) T() Type { return TypeUpdate } + +// L depends on the anounced prefix, at least 10. func (u Update) L() uint8 { return 10 + psizeFromPlen(u.Prefix.Bits()) } + +// FormatHeader returns a string of the most important fields except the prefix func (u Update) FormatHeader() string { return fmt.Sprintf("Flags 0x%02x Omitted %2d Interval %4d Seqno %5d Metric %5d RouterID %s", u.Flags, u.Omitted, u.Interval, u.Seqno, u.Metric, u.RouterID, ) } -func (s *PacketDecoder) UpdateFromBytes(b []byte) (Update, []byte, error) { +func (s *PacketDecoder) updateFromBytes(b []byte) (Update, []byte, error) { if err := assertLengthGreater(b, TypeUpdate, 10); err != nil { return Update{}, b, err } @@ -619,6 +702,8 @@ func (s *PacketDecoder) UpdateFromBytes(b []byte) (Update, []byte, error) { return u, b, err } +// RouteRequest TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.10 type RouteRequest struct { // AE uint8 @@ -626,16 +711,21 @@ type RouteRequest struct { Prefix netaddr.IPPrefix } +// AE returns the address encoding of the requested prefix func (r RouteRequest) AE() AEType { return AEFromPrefix(r.Prefix) } + +// T returns TypeRouteRequest. func (RouteRequest) T() Type { return TypeRouteRequest } + +// L depends on the requested prefix, at least 4. func (r RouteRequest) L() uint8 { return 4 + psizeFromPlen(r.Prefix.Bits()) } -func RouteRequestFromBytes(b []byte) (RouteRequest, []byte, error) { +func routeRequestFromBytes(b []byte) (RouteRequest, []byte, error) { if err := assertLengthGreater(b, TypeRouteRequest, 2); err != nil { return RouteRequest{}, b, err } @@ -647,6 +737,8 @@ func RouteRequestFromBytes(b []byte) (RouteRequest, []byte, error) { return rr, b, err } +// SeqnoRequest TLV +// // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.11 type SeqnoRequest struct { // AE uint8 @@ -657,13 +749,16 @@ type SeqnoRequest struct { Prefix netaddr.IPPrefix } +// T returns TypeSeqnoRequest. func (SeqnoRequest) T() Type { return TypeSeqnoRequest } + +// L depends on the requested prefix, at least 14. func (r SeqnoRequest) L() uint8 { return 14 + psizeFromPlen(r.Prefix.Bits()) } -func SeqnoRequestFromBytes(b []byte) (SeqnoRequest, []byte, error) { +func seqnoRequestFromBytes(b []byte) (SeqnoRequest, []byte, error) { if err := assertLengthGreater(b, TypeSeqnoRequest, 14); err != nil { return SeqnoRequest{}, b, err } @@ -681,17 +776,24 @@ func SeqnoRequestFromBytes(b []byte) (SeqnoRequest, []byte, error) { return sr, b, err } +// SourcePrefix Sub-TLV +// // https://datatracker.ietf.org/doc/html/draft-ietf-babel-source-specific-07#section-7.1 type SourcePrefix struct { netaddr.IPPrefix } +// T returns SubTypeSourcePrefix. func (SourcePrefix) T() SubType { return SubTypeSourcePrefix } + +// L depends on the encoded prefix func (s SourcePrefix) L() uint8 { return psizeFromPlen(s.Bits()) } + +// SourcePrefixFromBytes parses a SourcePrefix SubTLV func SourcePrefixFromBytes(b []byte) (SourcePrefix, []byte, error) { if err := assertSubLengthGreater(b, SubTypeSourcePrefix, 2); err != nil { return SourcePrefix{}, b, err