//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 ( "bytes" "errors" "fmt" "net/netip" ) // Type encodes the type of TLV type Type uint8 // Type TLV constants const ( TypePad1 = Type(0) TypePadN = Type(1) TypeAckReq = Type(2) TypeAck = Type(3) TypeHello = Type(4) TypeIHU = Type(5) TypeRouterID = Type(6) TypeNextHop = Type(7) TypeUpdate = Type(8) TypeRouteRequest = Type(9) TypeSeqnoRequest = Type(10) TypeTSPC = Type(11) 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) SubTypeDiversity = SubType(2) SubTypeTimestamp = SubType(3) 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) AEIPv6 = AEType(2) AEIPv6LL = AEType(3) AEIPv4oIPv6 = AEType(4) ) // AEFromPrefix returns the address encoding of a prefix: func AEFromPrefix(p netip.Prefix) AEType { return AEFromIP(p.Addr()) } // AEFromIP returns the address encoding of an address. func AEFromIP(p netip.Addr) AEType { switch { case p.IsUnspecified(), p == netip.Addr{}: return AEWildcard case p.Is4(): return AEIPv4 case p.IsLinkLocalUnicast(): return AEIPv6LL case p.Is6(): return AEIPv6 } panic("unknown AE") } // Scanner splits bytes into TLV tokens. type Scanner struct { buf []byte err error t Type l uint8 } // 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 } if len(ts.buf) <= int(ts.l) { return false } // move beginning of the buffer to the next TLV ts.buf = ts.buf[ts.l:] ts.t, ts.l = Type(ts.buf[0]), 0 switch ts.t { case TypePad1: ts.buf = ts.buf[1:] case TypePadN, TypeAckReq, TypeAck, TypeHello, TypeIHU, TypeRouterID, TypeNextHop, TypeUpdate, TypeRouteRequest, TypeSeqnoRequest, TypeTSPC, TypeHMAC: ts.l = ts.buf[1] if 2+int(ts.l) > len(ts.buf) { ts.err = fmt.Errorf("Invalid length: type %d, length %d, size %d", ts.t, ts.l, len(ts.buf)) return false } // move beginning of the buffer behind the header ts.buf = ts.buf[2:] default: panic("unknown type") } 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 // parser state routerID RouterID nexthopv6 netip.Addr nexthopv4 netip.Addr v6 [16]byte v4 [4]byte tlv TLV subtlv []byte err error } // Reset clears the parser state and sets a new byte slice to work on. func (s *PacketDecoder) Reset(b []byte, nexthop netip.Addr, ifindex int) { *s = PacketDecoder{} s.tlvscanner.Reset(b) switch { case nexthop.Is6(): s.nexthopv6 = nexthop case nexthop.Is4(): 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 } if !s.tlvscanner.Scan() { if err := s.tlvscanner.Err(); err != nil { s.err = err } return false } raw := s.tlvscanner.Raw() switch raw.T() { case TypePad1: s.tlv, s.subtlv, s.err = pad1FromBytes(raw.V()) case TypePadN: s.tlv, s.subtlv, s.err = padNFromBytes(raw.V()) case TypeAckReq: s.tlv, s.subtlv, s.err = ackReqFromBytes(raw.V()) case TypeAck: s.tlv, s.subtlv, s.err = ackFromBytes(raw.V()) case TypeHello: s.tlv, s.subtlv, s.err = helloFromBytes(raw.V()) case TypeIHU: s.tlv, s.subtlv, s.err = ihuFromBytes(raw.V()) case TypeRouterID: var rid RouterID rid, s.subtlv, s.err = routerIDFromBytes(raw.V()) if s.err != nil { break } s.tlv = rid s.routerID = rid case TypeNextHop: var nh NextHop nh, s.subtlv, s.err = nextHopFromBytes(raw.V()) if s.err != nil { break } s.tlv = nh switch AEFromIP(nh.Address) { case 1: s.nexthopv4 = nh.Address case 2, 3: s.nexthopv6 = nh.Address } case TypeUpdate: s.tlv, s.subtlv, s.err = s.updateFromBytes(raw.V()) case TypeRouteRequest: s.tlv, s.subtlv, s.err = routeRequestFromBytes(raw.V()) case TypeSeqnoRequest: s.tlv, s.subtlv, s.err = seqnoRequestFromBytes(raw.V()) case TypeTSPC: s.tlv = raw s.subtlv = nil case TypeHMAC: s.tlv = raw s.subtlv = nil default: s.err = fmt.Errorf("Unknown TLV Type: %+v", raw) } 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 } // ErrTLVLength is used to inform about invalid length fields in TLVs type ErrTLVLength struct { l int want int t Type } func (e ErrTLVLength) Error() string { return fmt.Sprintf("Invalid TLV length: %d, Type %q needs at least %d", e.l, e.t, e.want) } func assertLengthGreater(b []byte, t Type, l int) error { if len(b) < l { return ErrTLVLength{len(b), l, t} } return nil } // ErrSubTLVLength is used to inform about invalid length fields in Sub-TLVs type ErrSubTLVLength struct { l int want int t SubType } func (e ErrSubTLVLength) Error() string { return fmt.Sprintf("Invalid SubTLV length: %d, Type %q needs at least %d", e.l, e.t, e.want) } func assertSubLengthGreater(b []byte, t SubType, l int) error { if len(b) < l { return ErrSubTLVLength{len(b), l, t} } 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 0 } 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 uint8(p) } 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) { if err := assertLengthGreater(b, TypeAckReq, 6); err != nil { return AckReq{}, b, err } var ar AckReq ar.Opaque[0] = b[2] ar.Opaque[1] = b[3] ar.Interval = uint16(b[4])<<8 | uint16(b[5]) 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) { if err := assertLengthGreater(b, TypeAck, 2); err != nil { return Ack{}, b, err } 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 Seqno uint16 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) { if err := assertLengthGreater(b, TypeHello, 6); err != nil { return Hello{}, b, err } var h Hello h.Flags = uint16(b[0])<<8 | uint16(b[1]) h.Seqno = uint16(b[2])<<8 | uint16(b[3]) h.Interval = uint16(b[4])<<8 | uint16(b[5]) 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 // reserved uint8 Rxcost uint16 Interval uint16 Address netip.Addr } // 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: return 6 // Header only case 1: return 6 + 4 // IPv4 - no compression case 2: return 6 + 16 // IPv6 - no compression case 3: return 6 + 8 // IPv6 Link Local } panic("invalid AE field") } func ihuFromBytes(b []byte) (IHU, []byte, error) { if err := assertLengthGreater(b, TypeIHU, 6); err != nil { return IHU{}, b, err } var ihu IHU var err error ae := AEType(b[0]) ihu.Rxcost = uint16(b[2])<<8 | uint16(b[3]) ihu.Interval = uint16(b[4])<<8 | uint16(b[5]) ihu.Address, b, err = ipFromBytes(ae, b[6:]) 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) { if err := assertLengthGreater(b, TypeRouterID, 10); err != nil { return RouterID{}, b, err } // skip 2 reserved bytes rid, b := RouterID(b[2:10]), b[10:] switch rid { case RouterID{}: return RouterID{}, b, ErrRouterIDZeros case RouterID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}: return RouterID{}, b, ErrRouterIDOnes } 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) for i, b := range r { if i > 0 { buf.WriteByte(':') } fmt.Fprintf(&buf, "%02x", b) } return buf.String() } // NextHop TLV // // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.8 type NextHop struct { // AE uint8 // reserved uint8 Address netip.Addr } // 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: return 2 + 4 // IPv4 - no compression case 2: return 2 + 16 // IPv6 - no compression case 3: return 2 + 8 // IPv6 Link Local } panic("invalid AE field") } func nextHopFromBytes(b []byte) (NextHop, []byte, error) { if err := assertLengthGreater(b, TypeNextHop, 6); err != nil { return NextHop{}, b, err } var nh NextHop var err error ae := AEType(b[0]) nh.Address, b, err = ipFromBytes(ae, b[2:]) return nh, b, err } // Update TLV // // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.9 type Update struct { // AE uint8 Flags uint8 // Plen uint8 Omitted uint8 Interval uint16 Seqno uint16 Metric uint16 RouterID RouterID Prefix netip.Prefix NextHop netip.Addr } // 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(uint8(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) { if err := assertLengthGreater(b, TypeUpdate, 10); err != nil { return Update{}, b, err } var u Update var err error ae := AEType(b[0]) u.Flags = b[1] plen := b[2] u.Omitted = b[3] u.Interval = uint16(b[4])<<8 | uint16(b[5]) u.Seqno = uint16(b[6])<<8 | uint16(b[7]) u.Metric = uint16(b[8])<<8 | uint16(b[8]) b = b[10:] switch ae { case AEWildcard: case AEIPv4: u.Prefix, b, err = prefixV4Default(s.v4, plen, u.Omitted, b) if u.Flags&0x80 > 0 { s.v4 = u.Prefix.Addr().As4() } u.NextHop = s.nexthopv4 case AEIPv6: u.Prefix, b, err = prefixV6Default(s.v6, plen, u.Omitted, b) if u.Flags&0x80 > 0 { s.v6 = u.Prefix.Addr().As16() } u.NextHop = s.nexthopv6 case AEIPv6LL: u.Prefix, b, err = prefixV6LL(b) u.NextHop = s.nexthopv6 case AEIPv4oIPv6: return Update{}, b, fmt.Errorf("Not implemented AE Type %s", ae) default: return Update{}, b, fmt.Errorf("Unknown AE Type %d", ae) } if u.Flags&0x40 > 0 { addr := u.Prefix.Addr() switch { case addr.Is6(): v6 := addr.As16() s.routerID = RouterID(v6[8:]) case addr.Is4(): s.routerID = RouterID{} v4 := addr.As4() copy(s.routerID[4:], v4[:]) } } u.RouterID = s.routerID return u, b, err } // RouteRequest TLV // // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.10 type RouteRequest struct { // AE uint8 // plen uint8 Prefix netip.Prefix } // 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(uint8(r.Prefix.Bits())) } func routeRequestFromBytes(b []byte) (RouteRequest, []byte, error) { if err := assertLengthGreater(b, TypeRouteRequest, 2); err != nil { return RouteRequest{}, b, err } var rr RouteRequest var err error rr.Prefix, b, err = prefixUncompressed(b[0], b[1], b[2:]) return rr, b, err } // SeqnoRequest TLV // // https://datatracker.ietf.org/doc/html/rfc8966#section-4.6.11 type SeqnoRequest struct { // AE uint8 // Plen uint8 Seqno uint16 HopCount uint8 RouterID RouterID Prefix netip.Prefix } // 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(uint8(r.Prefix.Bits())) } func seqnoRequestFromBytes(b []byte) (SeqnoRequest, []byte, error) { if err := assertLengthGreater(b, TypeSeqnoRequest, 14); err != nil { return SeqnoRequest{}, b, err } var err error var sr SeqnoRequest ae := b[0] plen := b[1] sr.Seqno = uint16(b[2])<<8 | uint16(b[3]) sr.HopCount = b[4] sr.RouterID = RouterID(b[6:]) sr.Prefix, b, err = prefixUncompressed(ae, plen, b[14:]) 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 { netip.Prefix } // T returns SubTypeSourcePrefix. func (SourcePrefix) T() SubType { return SubTypeSourcePrefix } // L depends on the encoded prefix func (s SourcePrefix) L() uint8 { return psizeFromPlen(uint8(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 } plen := b[0] // TODO: error on 0 b = b[1:] pfx, b, err := prefixUncompressed(2, plen, b) return SourcePrefix{pfx}, b, err } func psizeFromPlen(plen uint8) uint8 { return (plen + 7) / 8 } func prefixUncompressed(ae uint8, plen uint8, b []byte) (netip.Prefix, []byte, error) { if len(b) < int(psizeFromPlen(plen)) { return netip.Prefix{}, b, fmt.Errorf("plen too large") } switch ae { case 0: return prefixWildcard() case 1: return prefixV4(plen, b) case 2: return prefixV6(plen, b) case 3: return prefixV6LL(b) default: return netip.Prefix{}, b, fmt.Errorf("Invalid AE %d", ae) } } func prefixWildcard() (netip.Prefix, []byte, error) { return netip.Prefix{}, nil, nil } func prefixV4(plen uint8, b []byte) (netip.Prefix, []byte, error) { return prefixV4Default([4]byte{}, plen, 0, b) } func prefixV4Default(ip4default [4]byte, plen uint8, omit uint8, b []byte) (netip.Prefix, []byte, error) { var ip4 [4]byte psize := psizeFromPlen(plen) - omit copy(ip4[:], ip4default[:omit]) copy(ip4[omit:], b[:psize]) return netip.PrefixFrom(netip.AddrFrom4(ip4), int(plen)), b[psize:], nil } func prefixV6(plen uint8, b []byte) (netip.Prefix, []byte, error) { return prefixV6Default([16]byte{}, plen, 0, b) } func prefixV6Default(ip6default [16]byte, plen uint8, omit uint8, b []byte) (netip.Prefix, []byte, error) { var ip6 [16]byte psize := psizeFromPlen(plen) - omit copy(ip6[:], ip6default[:omit]) copy(ip6[omit:], b[:psize]) return netip.PrefixFrom(netip.AddrFrom16(ip6), int(plen)), b[psize:], nil } func prefixV6LL(b []byte) (netip.Prefix, []byte, error) { var ip6ll [16]byte ip6ll[0] = 0xfe ip6ll[1] = 0x80 copy(ip6ll[8:], b[:8]) return netip.PrefixFrom(netip.AddrFrom16(ip6ll), 8), b[8:], nil } type ErrorIpFromBytesLength struct { ae AEType length int } func (e ErrorIpFromBytesLength) Error() string { return fmt.Sprintf("Not enough bytes for address encoding %s: %d", e.ae, e.length) } func ipFromBytes(ae AEType, b []byte) (netip.Addr, []byte, error) { switch ae { case AEWildcard: return netip.Addr{}, b, nil case AEIPv4: if len(b) < 4 { return netip.Addr{}, b, ErrorIpFromBytesLength{ae: AEIPv4, length: len(b)} } return netip.AddrFrom4([4]byte(b)), b[4:], nil case AEIPv6: if len(b) < 16 { return netip.Addr{}, b, ErrorIpFromBytesLength{ae: AEIPv6, length: len(b)} } return netip.AddrFrom16([16]byte(b)), b[16:], nil case AEIPv6LL: if len(b) < 8 { return netip.Addr{}, b, ErrorIpFromBytesLength{ae: AEIPv6LL, length: len(b)} } var ip6ll [16]byte ip6ll[0] = 0xfe ip6ll[1] = 0x80 copy(ip6ll[8:], b[:8]) return netip.AddrFrom16(ip6ll), b[8:], nil case AEIPv4oIPv6: return netip.Addr{}, b, fmt.Errorf("Not implemented AE Type %s", ae) default: return netip.Addr{}, b, fmt.Errorf("Invalid AE %d", ae) } }