121 lines
2.4 KiB
Go
121 lines
2.4 KiB
Go
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)
|
|
}
|
|
}
|