Compare commits

...

2 Commits

Author SHA1 Message Date
Johannes Kimmel ff695a5956 complete tlv parser 2021-12-13 06:55:52 +01:00
Johannes Kimmel 9fe17ce7ed add MIT license 2021-12-13 06:00:41 +01:00
10 changed files with 944 additions and 159 deletions

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Johannes Kimmel
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

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
}