commit
1d913cb5a7
7 changed files with 339 additions and 0 deletions
@ -0,0 +1,28 @@ |
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/go |
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=go |
||||
|
||||
### Go ### |
||||
# Binaries for programs and plugins |
||||
*.exe |
||||
*.exe~ |
||||
*.dll |
||||
*.so |
||||
*.dylib |
||||
|
||||
# Test binary, built with `go test -c` |
||||
*.test |
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE |
||||
*.out |
||||
|
||||
# Dependency directories (remove the comment below to include it) |
||||
# vendor/ |
||||
|
||||
### Go Patch ### |
||||
/vendor/ |
||||
/Godeps/ |
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/go |
||||
|
||||
abbel |
@ -0,0 +1,5 @@ |
||||
module git.freifunk-franken.de/jkimmel/abbel |
||||
|
||||
go 1.15 |
||||
|
||||
require golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 |
@ -0,0 +1,7 @@ |
||||
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/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= |
||||
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= |
@ -0,0 +1,126 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"log" |
||||
"net" |
||||
|
||||
"git.freifunk-franken.de/jkimmel/abbel/tlv" |
||||
"golang.org/x/net/ipv6" |
||||
) |
||||
|
||||
type options struct { |
||||
Group net.IP |
||||
Port uint16 |
||||
Ifs []net.Interface |
||||
} |
||||
|
||||
func parseOpts() (options, error) { |
||||
var opt options |
||||
var err error |
||||
|
||||
opt.Group = net.ParseIP("ff02::1:6") |
||||
opt.Port = 6696 |
||||
ifi, err := net.InterfaceByName("babel") |
||||
if err != nil { |
||||
return opt, err |
||||
} |
||||
opt.Ifs = []net.Interface{*ifi} |
||||
|
||||
return opt, err |
||||
} |
||||
|
||||
func run(opt options) error { |
||||
var err error |
||||
uc, err := net.ListenUDP("udp6", &net.UDPAddr{Port: int(opt.Port)}) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer uc.Close() |
||||
up := ipv6.NewPacketConn(uc) |
||||
|
||||
if err := up.SetControlMessage(ipv6.FlagDst, true); err != nil { |
||||
return err |
||||
} |
||||
|
||||
for ifi := range opt.Ifs { |
||||
if err := up.JoinGroup(&opt.Ifs[ifi], &net.UDPAddr{IP: opt.Group}); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
b := make([]byte, 1500) |
||||
for { |
||||
n, rcm, src, err := up.ReadFrom(b) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
_ = rcm |
||||
|
||||
magic := b[0] |
||||
version := b[1] |
||||
length := uint16(b[2])<<8 + uint16(b[3]) |
||||
|
||||
if magic != 42 { |
||||
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 { |
||||
case tlv.Update: |
||||
u, err = s.UpdateFromBytes(v) |
||||
if err != nil { |
||||
fmt.Println(u.PacketUpdateHeader, &u.Prefix, err) |
||||
} else { |
||||
if u.PacketUpdateHeader.Metric == 0xFFFF { |
||||
fmt.Print("\x1B[1m") |
||||
} |
||||
fmt.Printf("%43s: %+v\x1B[0m\n", &u.Prefix, u.PacketUpdateHeader) |
||||
} |
||||
default: |
||||
fmt.Printf(" T: %12s (%2d), L: %3d\n", t, t, len(v)) |
||||
} |
||||
|
||||
} |
||||
if ts.Err() != nil { |
||||
fmt.Println(err) |
||||
} |
||||
|
||||
//{
|
||||
// var bbuf bytes.Buffer
|
||||
// lzww := lzw.NewWriter(&bbuf, lzw.LSB, 8)
|
||||
// lzww.Write(b[:n])
|
||||
// lzww.Close()
|
||||
// fmt.Println(n, len(bbuf.Bytes()))
|
||||
//}
|
||||
//{
|
||||
// var bbuf bytes.Buffer
|
||||
// gzw, _ := gzip.NewWriterLevel(&bbuf, 9)
|
||||
// gzw.Write(b[:n])
|
||||
// gzw.Close()
|
||||
// fmt.Println(n, len(bbuf.Bytes()))
|
||||
//}
|
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func main() { |
||||
opt, err := parseOpts() |
||||
if err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
if err := run(opt); err != nil { |
||||
log.Fatal(err) |
||||
} |
||||
} |
@ -0,0 +1,74 @@ |
||||
//go:generate stringer -type=TLV
|
||||
package tlv |
||||
|
||||
import "fmt" |
||||
|
||||
type TLV uint8 |
||||
|
||||
const ( |
||||
Pad1 TLV = iota |
||||
PadN |
||||
AckReq |
||||
Ack |
||||
Hello |
||||
IHU |
||||
RouterID |
||||
NextHop |
||||
Update |
||||
RouteRequest |
||||
RouteUpdate |
||||
TSPC |
||||
HMAC |
||||
) |
||||
|
||||
type Scanner struct { |
||||
buf []byte |
||||
err error |
||||
t TLV |
||||
l uint8 |
||||
} |
||||
|
||||
func NewTLVScanner(buf []byte) *Scanner { |
||||
return &Scanner{ |
||||
buf: buf, |
||||
} |
||||
} |
||||
|
||||
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 = TLV(ts.buf[0]), 0 |
||||
|
||||
switch ts.t { |
||||
case Pad1: |
||||
ts.buf = ts.buf[1:] |
||||
default: |
||||
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:] |
||||
} |
||||
return true |
||||
} |
||||
|
||||
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] |
||||
} |
@ -0,0 +1,35 @@ |
||||
// 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]] |
||||
} |
@ -0,0 +1,64 @@ |
||||
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 |
||||
} |
Loading…
Reference in new issue