package ripv2 import ( "encoding/binary" "errors" "fmt" "log" "net" "os" "os/signal" "syscall" "github.com/crip/config" ) func New() Message { return Message{ RIP: make([]RIP, 25), } } /* Parse the raw data packet * Store the serialised data in the Message slice */ func (m *Message) MParse(b *[]byte, n int) error { if n == 0 { return errors.New("can't parse empty data") } if (n-4)/20 > 25 { return errors.New("rip table exceeds limit") } m.Command = Command((*b)[0]) m.Version = Version((*b)[1]) if m.Version > RIPv2 { return errors.New("unknown version") } var indexA, indexB = 4, 25 ripentry := (*b)[indexA:indexB] switch m.Command { case REQUEST: return nil case RESPONSE: for i := 0; i < (n-4)/20; i++ { m.RIP[i].AFI = binary.BigEndian.Uint16(ripentry[0:2]) m.RIP[i].RouteTag = binary.BigEndian.Uint16(ripentry[2:4]) m.RIP[i].Addr = binary.BigEndian.Uint32(ripentry[4:8]) m.RIP[i].Subnet = binary.BigEndian.Uint32(ripentry[8:12]) m.RIP[i].NextHop = binary.BigEndian.Uint32(ripentry[12:16]) m.RIP[i].Metric = binary.BigEndian.Uint32(ripentry[16:20]) indexA += 20 indexB += 20 ripentry = (*b)[indexA:indexB] } default: return errors.New("unknown command type") } return nil } /* Listen for network packets */ func (m *Message) Run(c *config.Config, callback func(*Routes)) error { iface := net.Interface{ Name: c.MulticastInterface, Flags: net.FlagMulticast, } addr := net.UDPAddr{ IP: net.ParseIP(c.IP), Port: c.Port, } conn, err := net.ListenMulticastUDP("udp4", &iface, &addr) if err != nil { return err } defer func() { if err := conn.Close(); err != nil { log.Println(err) } }() sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) buffer := make([]byte, 484) routes := Init() for { go func() { log.Println("Running") <-sigs log.Println("exit") os.Exit(0) }() n, UDPAddr, err := conn.ReadFromUDP(buffer) if err != nil { if err = conn.Close(); err != nil { log.Println(err) } log.Fatal("unable to read from socket") } if n < 24 { log.Println("packet length") } if err := m.MParse(&buffer, n); err != nil { log.Fatalln(err) } routes.ParseRoutes(*UDPAddr, &m.RIP) for _, v := range routes.Routes { fmt.Printf("Route:%s\tSubnet:%s\tNexthop:%s\tMetric:%d\tTime: %v\n", v.Addr.String(), v.Subnet.String(), v.NextHop.String(), v.Metric, v.TTL.Unix()) } callback(routes) } }