package main import ( "fmt" "log" "net" "git.freifunk-franken.de/jkimmel/abbel/tlv" "golang.org/x/net/ipv6" "inet.af/netaddr" ) 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 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)}) 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 } } buf := [4096]byte{} for { b, src, err := readBabelPacket(up, buf[:]) if err != nil { fmt.Println("Skipping packet:", err) continue } var s tlv.PacketDecoder 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: if err != nil { fmt.Println(t, t.Prefix, err) } else { if t.Metric == 0xFFFF { fmt.Print("\x1B[31m") } else { fmt.Print("\x1B[36m") } 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: 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 s.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())) //} } } func main() { opt, err := parseOpts() if err != nil { log.Fatal(err) } if err := run(opt); err != nil { log.Fatal(err) } }