complete tlv parser

This commit is contained in:
Johannes Kimmel 2021-12-13 06:55:52 +01:00
parent 9fe17ce7ed
commit ff695a5956
9 changed files with 923 additions and 159 deletions

7
go.mod
View File

@ -1,5 +1,8 @@
module git.freifunk-franken.de/jkimmel/abbel
go 1.15
go 1.0
require golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
require (
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6
)

29
go.sum
View File

@ -1,7 +1,34 @@
github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE=
go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37 h1:Tx9kY6yUkLge/pFG7IEMwDZy6CS2ajFc9TvQdPCW0uA=
go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 h1:acCzuUSQ79tGsM/O50VRFySfMm19IoMKL+sZztZkCxw=
inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6/go.mod h1:y3MGhcFMlh0KZPMuXXow8mpjxxAk3yoDNsp4cQz54i8=

108
main.go
View File

@ -7,6 +7,7 @@ import (
"git.freifunk-franken.de/jkimmel/abbel/tlv"
"golang.org/x/net/ipv6"
"inet.af/netaddr"
)
type options struct {
@ -30,6 +31,35 @@ func parseOpts() (options, error) {
return opt, err
}
func readBabelPacket(up *ipv6.PacketConn, b []byte) ([]byte, netaddr.IP, error) {
n, rcm, src, err := up.ReadFrom(b)
if err != nil {
return nil, netaddr.IP{}, err
}
_ = rcm
b = b[:n]
if len(b) < 4 {
fmt.Println("packet too short:", len(b))
}
magic := b[0]
version := b[1]
length := uint16(b[2])<<8 + uint16(b[3])
b = b[4:]
if magic != 42 {
return nil, netaddr.IP{}, fmt.Errorf("Invalid magic number %d", magic)
}
if int(length) > len(b) {
fmt.Println("invalid length:", length)
}
fmt.Println(src, rcm, magic, version, length, n)
srcipport, err := netaddr.ParseIPPort(src.String())
return b, srcipport.IP(), err
}
func run(opt options) error {
var err error
uc, err := net.ListenUDP("udp6", &net.UDPAddr{Port: int(opt.Port)})
@ -49,50 +79,66 @@ func run(opt options) error {
}
}
b := make([]byte, 1500)
buf := [4096]byte{}
for {
n, rcm, src, err := up.ReadFrom(b)
b, src, err := readBabelPacket(up, buf[:])
if err != nil {
return err
}
_ = rcm
magic := b[0]
version := b[1]
length := uint16(b[2])<<8 + uint16(b[3])
if magic != 42 {
fmt.Println("Skipping packet:", err)
continue
}
if int(length)+4 > n {
fmt.Println("invalid length")
}
fmt.Println(src, rcm, magic, version, length, n)
var u tlv.PacketUpdate
var s tlv.PacketDecoder
ts := tlv.NewTLVScanner(b[4 : 4+length])
for ts.Scan() {
t, v := ts.TLV()
switch t {
s.Reset(b, src)
for s.Scan() {
var subtlv []byte
switch t := s.TLV().(type) {
case tlv.NextHop:
fmt.Printf("%12s %s\n", t.T(), t.Address)
case tlv.Hello:
fmt.Printf("% 12s %+v\n", t.T(), t)
case tlv.Update:
u, err = s.UpdateFromBytes(v)
if err != nil {
fmt.Println(u.PacketUpdateHeader, &u.Prefix, err)
fmt.Println(t, t.Prefix, err)
} else {
if u.PacketUpdateHeader.Metric == 0xFFFF {
fmt.Print("\x1B[1m")
if t.Metric == 0xFFFF {
fmt.Print("\x1B[31m")
} else {
fmt.Print("\x1B[36m")
}
fmt.Printf("%43s: %+v\x1B[0m\n", &u.Prefix, u.PacketUpdateHeader)
fmt.Printf("% 12s %-43s%s\x1B[0m\n", t.T(), t.Prefix, t.FormatHeader())
}
case tlv.RouterID:
fmt.Printf("%12s %s\n", t.T(), t)
case tlv.RouteRequest:
fmt.Printf("%12s %s\n", t.T(), t.Prefix)
case tlv.Raw:
fmt.Printf(" T: %12s (%2d), L: %3d\n", t.T(), t.T(), len(t.V()))
case tlv.IHU:
fmt.Printf("%12s %-43sRxcost %5d Interval %4d \n", t.T(), t.Address, t.Rxcost, t.Interval)
default:
fmt.Printf(" T: %12s (%2d), L: %3d\n", t, t, len(v))
if t != nil {
fmt.Println("Unknown TLV", t.T(), t)
} else {
fmt.Println("got nil TLV")
}
}
for len(subtlv) > 0 {
switch tlv.SubType(subtlv[0]) {
case tlv.SubTypeSourcePrefix:
var pfx tlv.SourcePrefix
pfx, subtlv, err = tlv.SourcePrefixFromBytes(subtlv[2:])
fmt.Print("\x1B[7;36m")
fmt.Printf("%12s %s\x1B[0m\n", pfx.T(), pfx)
case tlv.SubTypeDiversity, tlv.SubTypePad1, tlv.SubTypePadN, tlv.SubTypeTimestamp:
fmt.Print("\x1B[7m")
fmt.Printf("%12s: %v\x1B[0m\n", "Subtlv", subtlv)
subtlv = nil
default:
panic("unknown subtlv type")
}
}
}
if ts.Err() != nil {
if s.Err() != nil {
fmt.Println(err)
}
@ -111,8 +157,6 @@ func run(opt options) error {
// fmt.Println(n, len(bbuf.Bytes()))
//}
}
return nil
}
func main() {

36
tlv/subtype_string.go Normal file
View File

@ -0,0 +1,36 @@
// Code generated by "stringer -type=SubType -trimprefix SubType"; DO NOT EDIT.
package tlv
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[SubTypePad1-0]
_ = x[SubTypePadN-1]
_ = x[SubTypeDiversity-2]
_ = x[SubTypeTimestamp-3]
_ = x[SubTypeSourcePrefix-128]
}
const (
_SubType_name_0 = "Pad1PadNDiversityTimestamp"
_SubType_name_1 = "SourcePrefix"
)
var (
_SubType_index_0 = [...]uint8{0, 4, 8, 17, 26}
)
func (i SubType) String() string {
switch {
case i <= 3:
return _SubType_name_0[_SubType_index_0[i]:_SubType_index_0[i+1]]
case i == 128:
return _SubType_name_1
default:
return "SubType(" + strconv.FormatInt(int64(i), 10) + ")"
}
}

View File

@ -1,30 +1,57 @@
//go:generate stringer -type=TLV
//go:generate stringer -type=Type -trimprefix Type
//go:generate stringer -type=SubType -trimprefix SubType
package tlv
import "fmt"
import (
"bytes"
"errors"
"fmt"
type TLV uint8
"inet.af/netaddr"
)
type Type uint8
const (
Pad1 TLV = iota
PadN
AckReq
Ack
Hello
IHU
RouterID
NextHop
Update
RouteRequest
RouteUpdate
TSPC
HMAC
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)
)
type TLV interface {
T() Type
L() uint8
}
type SubType uint8
const (
SubTypePad1 = SubType(0)
SubTypePadN = SubType(1)
SubTypeDiversity = SubType(2)
SubTypeTimestamp = SubType(3)
SubTypeSourcePrefix = SubType(128)
)
type SubTLV interface {
T() SubType
L() uint8
}
type Scanner struct {
buf []byte
err error
t TLV
t Type
l uint8
}
@ -34,6 +61,11 @@ func NewTLVScanner(buf []byte) *Scanner {
}
}
func (ts *Scanner) Reset(buf []byte) {
*ts = Scanner{}
ts.buf = buf
}
func (ts *Scanner) Scan() bool {
if ts.err != nil {
return false
@ -45,12 +77,23 @@ func (ts *Scanner) Scan() bool {
// move beginning of the buffer to the next TLV
ts.buf = ts.buf[ts.l:]
ts.t, ts.l = TLV(ts.buf[0]), 0
ts.t, ts.l = Type(ts.buf[0]), 0
switch ts.t {
case Pad1:
case TypePad1:
ts.buf = ts.buf[1:]
default:
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))
@ -58,7 +101,10 @@ func (ts *Scanner) Scan() bool {
}
// move beginning of the buffer behind the header
ts.buf = ts.buf[2:]
default:
panic("unknown type")
}
return true
}
@ -66,9 +112,640 @@ func (ts *Scanner) Err() error {
return ts.err
}
func (ts *Scanner) TLV() (TLV, []byte) {
if ts.err != nil {
return 0, nil
}
return ts.t, ts.buf[:ts.l]
func (ts *Scanner) Raw() Raw {
return Raw{ts.t, ts.l, ts.buf[:ts.l:ts.l]}
}
type PacketDecoder struct {
tlvscanner Scanner
// parser state
routerID RouterID
nexthopv6 netaddr.IP
nexthopv4 netaddr.IP
v6 [16]byte
v4 [4]byte
tlv TLV
subtlv []byte
err error
}
func (s *PacketDecoder) Reset(b []byte, nexthop netaddr.IP) {
*s = PacketDecoder{}
s.tlvscanner.Reset(b)
switch {
case nexthop.Is6():
s.nexthopv6 = nexthop
case nexthop.Is4():
s.nexthopv4 = nexthop
}
}
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
}
func (s *PacketDecoder) TLV() TLV {
if s.err != nil {
return nil
}
return s.tlv
}
func (s *PacketDecoder) Err() error {
return s.err
}
type Raw struct {
t Type
l uint8
v []byte
}
func (t Raw) T() Type {
return t.t
}
func (t Raw) L() uint8 {
return t.l
}
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)
}
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
}
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
}
type Pad1 struct{}
func (Pad1) T() Type {
return TypePad1
}
func (Pad1) L() uint8 {
return 8
}
func Pad1FromBytes(b []byte) (Pad1, []byte, error) {
if err := assertLengthGreater(b, TypePad1, 0); err != nil {
return Pad1{}, b, err
}
return Pad1{}, b[1:], nil
}
type PadN uint8
func (PadN) T() Type {
return TypePadN
}
func (p PadN) L() uint8 {
return 2 + uint8(p) // TODO: overflow?
}
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
}
type AckReq struct {
Opaque [2]byte
Interval uint16
}
func (AckReq) T() Type {
return TypeAckReq
}
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
}
type Ack struct {
Opaque uint16
}
func (Ack) T() Type {
return TypeAck
}
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
}
type Hello struct {
Flags uint16
Seqno uint16
Interval uint16
}
func (Hello) T() Type {
return TypeHello
}
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
}
type IHU struct {
// AE uint8
// reserved uint8
Rxcost uint16
Interval uint16
Address netaddr.IP
}
func (IHU) T() Type {
return TypeIHU
}
func (i IHU) AE() uint8 {
return AEFromIP(i.Address)
}
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 := 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
}
type RouterID [8]byte
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
var rid RouterID
copy(rid[:], b[2:])
b = b[10:]
if rid == (RouterID{}) {
return RouterID{}, b, ErrRouterIDZeros
}
if rid == (RouterID{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}) {
return RouterID{}, b, ErrRouterIDOnes
}
return rid, b, nil
}
func (RouterID) T() Type {
return TypeRouterID
}
func (RouterID) L() uint8 {
return 8
}
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()
}
type NextHop struct {
// AE uint8
// reserved uint8
Address netaddr.IP
}
func (NextHop) T() Type {
return TypeNextHop
}
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 := b[0]
nh.Address, b, err = ipFromBytes(ae, b[2:])
return nh, b, err
}
type Update struct {
// AE uint8
Flags uint8
// Plen uint8
Omitted uint8
Interval uint16
Seqno uint16
Metric uint16
Prefix netaddr.IPPrefix
NextHop netaddr.IP
}
func (Update) T() Type {
return TypeUpdate
}
func (u Update) L() uint8 {
return 10 + psizeFromPlen(u.Prefix.Bits())
}
func (u Update) FormatHeader() string {
return fmt.Sprintf("Flags 0x%02x Omitted %2d Interval %4d Seqno %5d Metric %5d NextHop %s",
u.Flags, u.Omitted, u.Interval, u.Seqno, u.Metric, u.NextHop,
)
}
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 := 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 0:
case 1:
u.Prefix, b, err = prefixV4Default(s.v4, plen, u.Omitted, b)
if u.Flags&0x80 > 0 {
s.v4 = u.Prefix.IP().As4()
}
u.NextHop = s.nexthopv4
case 2:
u.Prefix, b, err = prefixV6Default(s.v6, plen, u.Omitted, b)
if u.Flags&0x80 > 0 {
s.v6 = u.Prefix.IP().As16()
}
u.NextHop = s.nexthopv6
case 3:
u.Prefix, b, err = prefixV6LL(b)
u.NextHop = s.nexthopv6
}
return u, b, err
}
func AEFromPrefix(p netaddr.IPPrefix) uint8 {
return AEFromIP(p.IP())
}
func AEFromIP(p netaddr.IP) uint8 {
if p.IsZero() {
return 0
}
if p.Is4() {
return 1
}
if p.IsLinkLocalUnicast() {
return 3
}
if p.Is6() {
return 2
}
panic("unknown AE")
}
type RouteRequest struct {
// AE uint8
// plen uint8
Prefix netaddr.IPPrefix
}
func (r RouteRequest) AE() uint8 {
return AEFromPrefix(r.Prefix)
}
func (RouteRequest) T() Type {
return TypeRouteRequest
}
func (r RouteRequest) L() uint8 {
return 4 + psizeFromPlen(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
}
type SeqnoRequest struct {
// AE uint8
// Plen uint8
Seqno uint16
HopCount uint8
RouterID RouterID
Prefix netaddr.IPPrefix
}
func (SeqnoRequest) T() Type {
return TypeSeqnoRequest
}
func (r SeqnoRequest) L() uint8 {
return 14 + psizeFromPlen(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]
copy(sr.RouterID[:], b[6:])
sr.Prefix, b, err = prefixUncompressed(ae, plen, b[14:])
return sr, b, err
}
type SourcePrefix struct {
netaddr.IPPrefix
}
func (SourcePrefix) T() SubType {
return SubTypeSourcePrefix
}
func (s SourcePrefix) L() uint8 {
return psizeFromPlen(s.Bits())
}
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 uint8((uint16(plen) + 7) / 8)
}
func prefixUncompressed(ae uint8, plen uint8, b []byte) (netaddr.IPPrefix, []byte, error) {
if len(b) < int(psizeFromPlen(plen)) {
return netaddr.IPPrefix{}, 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 netaddr.IPPrefix{}, b, fmt.Errorf("Invalid AE %d", ae)
}
}
func prefixWildcard() (netaddr.IPPrefix, []byte, error) {
return netaddr.IPPrefix{}, nil, nil
}
func prefixV4(plen uint8, b []byte) (netaddr.IPPrefix, []byte, error) {
return prefixV4Default([4]byte{}, plen, 0, b)
}
func prefixV4Default(ip4default [4]byte, plen uint8, omit uint8, b []byte) (netaddr.IPPrefix, []byte, error) {
var ip4 [4]byte
psize := psizeFromPlen(plen) - omit
copy(ip4[:], ip4default[:omit])
copy(ip4[omit:], b[:psize])
return netaddr.IPPrefixFrom(netaddr.IPFrom4(ip4), plen), b[psize:], nil
}
func prefixV6(plen uint8, b []byte) (netaddr.IPPrefix, []byte, error) {
return prefixV6Default([16]byte{}, plen, 0, b)
}
func prefixV6Default(ip6default [16]byte, plen uint8, omit uint8, b []byte) (netaddr.IPPrefix, []byte, error) {
var ip6 [16]byte
psize := psizeFromPlen(plen) - omit
copy(ip6[:], ip6default[:omit])
copy(ip6[omit:], b[:psize])
return netaddr.IPPrefixFrom(netaddr.IPv6Raw(ip6), plen), b[psize:], nil
}
func prefixV6LL(b []byte) (netaddr.IPPrefix, []byte, error) {
var ip6ll [16]byte
ip6ll[0] = 0xfe
ip6ll[1] = 0x80
copy(ip6ll[8:], b[:8])
return netaddr.IPPrefixFrom(netaddr.IPv6Raw(ip6ll), 8), b[8:], nil
}
func ipFromBytes(ae uint8, b []byte) (netaddr.IP, []byte, error) {
switch ae {
case 0:
return netaddr.IP{}, b, nil
case 1:
if len(b) < 4 {
return netaddr.IP{}, b, fmt.Errorf("Not enough bytes for v4 address: %d", len(b))
}
var ip4 [4]byte
copy(ip4[:], b[:4])
return netaddr.IPFrom4(ip4), b[4:], nil
case 2:
if len(b) < 16 {
return netaddr.IP{}, b, fmt.Errorf("Not enough bytes for v6 address: %d", len(b))
}
var ip6 [16]byte
copy(ip6[:], b[:16])
return netaddr.IPv6Raw(ip6), b[16:], nil
case 3:
if len(b) < 8 {
return netaddr.IP{}, b, fmt.Errorf("Not enough bytes for v6ll address: %d", len(b))
}
var ip6ll [16]byte
ip6ll[0] = 0xfe
ip6ll[1] = 0x80
copy(ip6ll[8:], b[:8])
return netaddr.IPv6Raw(ip6ll), b[8:], nil
default:
return netaddr.IP{}, b, fmt.Errorf("Invalid AE %d", ae)
}
}

View File

@ -1,35 +0,0 @@
// Code generated by "stringer -type=TLV"; DO NOT EDIT.
package tlv
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Pad1-0]
_ = x[PadN-1]
_ = x[AckReq-2]
_ = x[Ack-3]
_ = x[Hello-4]
_ = x[IHU-5]
_ = x[RouterID-6]
_ = x[NextHop-7]
_ = x[Update-8]
_ = x[RouteRequest-9]
_ = x[RouteUpdate-10]
_ = x[TSPC-11]
_ = x[HMAC-12]
}
const _TLV_name = "Pad1PadNAckReqAckHelloIHURouterIDNextHopUpdateRouteRequestRouteUpdateTSPCHMAC"
var _TLV_index = [...]uint8{0, 4, 8, 14, 17, 22, 25, 33, 40, 46, 58, 69, 73, 77}
func (i TLV) String() string {
if i >= TLV(len(_TLV_index)-1) {
return "TLV(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _TLV_name[_TLV_index[i]:_TLV_index[i+1]]
}

41
tlv/tlv_test.go Normal file
View File

@ -0,0 +1,41 @@
package tlv
import (
"testing"
)
func TestRouterIDFailZeros(t *testing.T) {
zeros := [10]byte{}
if _, _, err := RouterIDFromBytes(zeros[:]); err != ErrRouterIDZeros {
t.Error("RouterIDFromBytes should fail with ErrRouterIDZeros")
}
}
func TestRouterIDFailOnes(t *testing.T) {
ones := [10]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
if _, _, err := RouterIDFromBytes(ones[:]); err != ErrRouterIDOnes {
t.Error("RouterIDFromBytes should fail with ErrRouterIDOnes")
}
}
func TestRouterIDFailLength(t *testing.T) {
testbytes := [300]byte{}
for i := 0; i <= len(testbytes); i++ {
_, _, err := RouterIDFromBytes(testbytes[:i])
l, isErrRouterIDLength := err.(ErrTLVLength)
switch {
case i >= 10:
if isErrRouterIDLength {
t.Error("RouterIDFromBytes returns ErrRouterIDLength for correct length data")
}
default:
if l.l != i {
t.Errorf("RouterIDFromBytes returns wrong length %d, expected %d", l, i)
}
if !isErrRouterIDLength {
t.Errorf("RouterIDFromBytes returns wrong error for packet of wrong length %d", i)
}
}
}
}

35
tlv/type_string.go Normal file
View File

@ -0,0 +1,35 @@
// Code generated by "stringer -type=Type -trimprefix Type"; DO NOT EDIT.
package tlv
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[TypePad1-0]
_ = x[TypePadN-1]
_ = x[TypeAckReq-2]
_ = x[TypeAck-3]
_ = x[TypeHello-4]
_ = x[TypeIHU-5]
_ = x[TypeRouterID-6]
_ = x[TypeNextHop-7]
_ = x[TypeUpdate-8]
_ = x[TypeRouteRequest-9]
_ = x[TypeSeqnoRequest-10]
_ = x[TypeTSPC-11]
_ = x[TypeHMAC-12]
}
const _Type_name = "Pad1PadNAckReqAckHelloIHURouterIDNextHopUpdateRouteRequestSeqnoRequestTSPCHMAC"
var _Type_index = [...]uint8{0, 4, 8, 14, 17, 22, 25, 33, 40, 46, 58, 70, 74, 78}
func (i Type) String() string {
if i >= Type(len(_Type_index)-1) {
return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Type_name[_Type_index[i]:_Type_index[i+1]]
}

View File

@ -1,64 +0,0 @@
package tlv
import (
"bytes"
"encoding/binary"
"net"
)
type PacketUpdateHeader struct {
AE uint8
Flags uint8
Plen uint8
Omitted uint8
Interval uint16
Seqno uint16
Metric uint16
}
type PacketUpdate struct {
PacketUpdateHeader
Prefix net.IPNet
}
type PacketDecoder struct {
routerID [8]byte
v4 [4]byte
v6 [16]byte
}
func (s *PacketDecoder) UpdateFromBytes(b []byte) (PacketUpdate, error) {
var u PacketUpdate
r := bytes.NewReader(b[:10])
err := binary.Read(r, binary.BigEndian, &u.PacketUpdateHeader)
b = b[10:]
psize := (u.Plen+7)/8 - u.Omitted
switch u.AE {
case 0:
case 1:
u.Prefix.Mask = net.CIDRMask(int(u.Plen), 4*8)
u.Prefix.IP = append([]byte{}, s.v4[:]...)
copy(u.Prefix.IP[u.Omitted:], b[:psize])
if u.Flags&0x80 > 0 {
copy(s.v4[:], u.Prefix.IP)
}
case 2:
u.Prefix.Mask = net.CIDRMask(int(u.Plen), 16*8)
u.Prefix.IP = append([]byte{}, s.v6[:]...)
copy(u.Prefix.IP[u.Omitted:], b[:psize])
if u.Flags&0x80 > 0 {
copy(s.v6[:], u.Prefix.IP)
}
case 3:
u.Prefix.Mask = net.CIDRMask(8, 16*8)
u.Prefix.IP = make([]byte, 16)
u.Prefix.IP[0] = 0xfe
u.Prefix.IP[1] = 0x80
copy(u.Prefix.IP[8:], b[:8])
}
return u, err
}