package main import ( "flag" "fmt" "log" "net/netip" "strings" "git.freifunk-franken.de/jkimmel/abbel/packet" "git.freifunk-franken.de/jkimmel/abbel/tlv" ) type options struct { Group string Port uint16 Ifs []string } func parseOpts() (options, error) { var opt options var err error var unusedMulticast bool flag.StringVar(&opt.Group, "group", "ff02:0:0:0:0:0:1:6", "Multicast group to join") port := flag.Uint("port", 6696, "Port to listen on") flag.BoolVar(&unusedMulticast, "m", false, "Use multicast mode (default, unused)") ifs := flag.String("i", "any", "Comma-seperated list of interfaces to listen on or \"any\" for all interfaces in capture mode") flag.Parse() if *port == 0 || *port >= 0xffff { return options{}, fmt.Errorf("Invalid port %q", *port) } opt.Port = uint16(*port) for _, iface := range strings.Split(*ifs, ",") { opt.Ifs = append(opt.Ifs, iface) } return opt, err } type updatesKey struct { prefix netip.Prefix routerID tlv.RouterID nexthop netip.Addr } var ( updates = map[updatesKey]tlv.Update{} ) type BabelPacketConn interface { ReadFrom(b []byte) (body []byte, src netip.Addr, ifindex int, err error) Close() error } func run(opt options) error { var err error var conn BabelPacketConn conn, err = packet.Listen(opt.Group, opt.Port, opt.Ifs...) if err != nil { return err } defer conn.Close() buf := [4096]byte{} var s tlv.PacketDecoder for { b, src, ifindex, err := conn.ReadFrom(buf[:]) if err != nil { fmt.Println("Skipping packet:", err) continue } fmt.Print("\x1B[1m") fmt.Printf("Packet size %4d from %s", len(b), src) fmt.Println("\x1B[0m") s.Reset(b, src, ifindex) for s.Scan() { 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: key := updatesKey{t.Prefix, t.RouterID, t.NextHop} tmetric := t.Metric diff := int(tmetric) - int(updates[key].Metric) updates[key] = t if diff == 0 && tmetric != 0xFFFF { break } if t.Metric == 0xFFFF { fmt.Print("\x1B[31m") } else { fmt.Print("\x1B[36m") } fmt.Printf("% 12s %-43s%+6d %s\x1B[0m\n", t.T(), t.Prefix, diff, 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) case tlv.SeqnoRequest: fmt.Printf("%12s %-43sSeqno %5d HopCount %3d RouterID %s\n", t.T(), t.Prefix, t.Seqno, t.HopCount, t.RouterID) default: if t != nil { fmt.Println("Unknown TLV", t.T(), t) } else { fmt.Println("got nil TLV") } } subtlv := s.SubTLV() 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) } } } func main() { opt, err := parseOpts() if err != nil { log.Fatal(err) } if err := run(opt); err != nil { log.Fatal(err) } }