From a7f9da2bb4ce6649ca38ab808a7b263aff9afbd7 Mon Sep 17 00:00:00 2001 From: David Doan Date: Thu, 19 Oct 2023 22:52:11 -0400 Subject: refactored and commented --- pkg/ipstack/ipstack.go | 597 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 400 insertions(+), 197 deletions(-) (limited to 'pkg/ipstack/ipstack.go') diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go index da2d504..51ea07c 100644 --- a/pkg/ipstack/ipstack.go +++ b/pkg/ipstack/ipstack.go @@ -11,6 +11,8 @@ import ( "net/netip" "time" "encoding/binary" + "bytes" + "unicode" ) const ( @@ -19,6 +21,10 @@ const ( STATIC_COST uint32 = 4294967295 // 2^32 - 1 MaxEntries = 64 INFINITY = 15 + SIZE_OF_RIP_ENTRY = 12 + SIZE_OF_RIP_MESSAGE = 6 + RIP_PROTOCOL = 12 + TEST_PROTOCOL = 0 ) // STRUCTS --------------------------------------------------------------------- @@ -33,6 +39,7 @@ type Interface struct { } type Neighbor struct { + Name string VipAddr netip.Addr UdpAddr netip.AddrPort @@ -56,7 +63,6 @@ type Hop struct { Cost uint32 VipAsStr string Type string - // added this for printing purposes } // GLOBAL VARIABLES (data structures) ------------------------------------------ @@ -64,14 +70,15 @@ var myVIP Interface var myInterfaces []*Interface var myNeighbors = make(map[string][]*Neighbor) -// var myRIPNeighbors = make(map[string]Neighbor) -type HandlerFunc func(int, string, *[]byte) error +var myRIPNeighbors = make([]netip.Addr, 0) + +type HandlerFunc func(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.IPv4Header) error -var protocolHandlers = make(map[uint16]HandlerFunc) +var protocolHandlers = make(map[int]HandlerFunc) -// var routingTable = routingtable.New() var routingTable = make(map[netip.Prefix]Hop) +// ************************************** INIT FUNCTIONS ********************************************************** // reference: https://github.com/brown-csci1680/lecture-examples/blob/main/ip-demo/cmd/udp-ip-recv/main.go func createUDPConn(UdpAddr netip.AddrPort, conn *net.UDPConn, isN bool) error { listenString := UdpAddr.String() @@ -128,20 +135,12 @@ func Initialize(lnxFilePath string) error { } go InterfaceListenerRoutine(i.RecvSocket, i.SocketChannel) myInterfaces = append(myInterfaces, i) - - // TODO: (FOR HOSTS ONLY) - // add STATIC to routing table - // if !static { - // ifacePrefix := netip.MustParsePrefix("0.0.0.0/0") - // routingTable[ifacePrefix] = Hop{STATIC_COST, iface.Name, "S"} - // static = true - // } - // Took this out for printing purposes for REPL FYI } // 2) initialize the neighbors connected to the node and into the routing table for _, neighbor := range lnxConfig.Neighbors { n := &Neighbor{ + Name: neighbor.InterfaceName, VipAddr: neighbor.DestAddr, UdpAddr: neighbor.UDPAddr, SendSocket: net.UDPConn{}, @@ -161,13 +160,21 @@ func Initialize(lnxFilePath string) error { routingTable[neighborPrefix] = Hop{LOCAL_COST, neighbor.InterfaceName, "L"} } - for _, route := range lnxConfig.StaticRoutes { + for _, route := range lnxConfig.RipNeighbors { + // add to RIP neighbors + myRIPNeighbors = append(myRIPNeighbors, route) + } + + // StaticRoutes: make(map[netip.Prefix]netip.Addr, 0), + for prefix, addr := range lnxConfig.StaticRoutes { // add to routing table - prefix := netip.MustParsePrefix("0.0.0.0/0") - routingTable[prefix] = Hop{LOCAL_COST, route.String(), "S"} + routingTable[prefix] = Hop{STATIC_COST, addr.String(), "S"} } - // added for printing purposes for REPL FYI + SendUpdates() + // add protocol handlers + protocolHandlers[RIP_PROTOCOL] = handleRIP + protocolHandlers[TEST_PROTOCOL] = handleTestPackets return nil } @@ -216,6 +223,8 @@ func InterfaceListenerRoutine(socket net.UDPConn, signal <-chan bool) { } } +// ************************************** DOWN/UP FUNCTIONS ****************************************************** + func InterfaceUp(iface *Interface) { iface.State = true iface.SocketChannel <- true @@ -227,8 +236,7 @@ func InterfaceUpREPL(ifaceName string) { fmt.Println("Error getting interface by name", err) return } - iface.State = true - iface.SocketChannel <- true + InterfaceUp(iface) } // we could do either of these but the REPL results in less work done in router and host @@ -244,22 +252,22 @@ func InterfaceDownREPL(ifaceName string) { fmt.Println("Error getting interface by name", err) return } - iface.SocketChannel <- false - iface.State = false + InterfaceDown(iface) } -// same as above comment +// ************************************** GETTER FUNCTIONS ********************************************************** func GetInterfaceByName(ifaceName string) (*Interface, error) { + // iterate through the interfaces and return the one with the same name for _, iface := range myInterfaces { if iface.Name == ifaceName { return iface, nil } } - return nil, errors.Errorf("No interface with name %s", ifaceName) } func GetNeighborByIP(ipAddr string) (*Neighbor, error) { + // iterate through the neighbors and return the one with the same ipAddr for _, neighbors := range myNeighbors { for _, neighbor := range neighbors { if neighbor.VipAddr.String() == ipAddr { @@ -272,7 +280,16 @@ func GetNeighborByIP(ipAddr string) (*Neighbor, error) { } func GetRouteByIP(ipAddr string) (*Neighbor, error) { + // iterate through the routing table and return the one with the same ipAddr + var defaultRoute *Neighbor for prefix, hop := range routingTable { + // gets the default route + if hop.Type == "S" { + defaultRoute, _ = GetNeighborByIP(hop.VipAsStr) + continue + } + + // TODO @ MICHAEL: get the longest prefix match netIP := net.ParseIP(prefix.Addr().String()) if netIP.String() == ipAddr { fmt.Println("found route", hop.VipAsStr) @@ -285,7 +302,8 @@ func GetRouteByIP(ipAddr string) (*Neighbor, error) { } } - return nil, errors.Errorf("No interface with ip %s", ipAddr) + fmt.Println("returning default route", defaultRoute.VipAddr.String()) + return defaultRoute, nil } func GetNeighborsToInterface(ifaceName string) ([]*Neighbor, error) { @@ -300,6 +318,20 @@ func GetMyVIP() Interface { return myVIP } +func GetInterfaces() []*Interface { + return myInterfaces +} + +func GetNeighbors() map[string][]*Neighbor { + return myNeighbors +} + +func GetRoutes() map[netip.Prefix]Hop { + return routingTable +} + +// ************************************** PRINT FUNCTIONS ********************************************************** + func SprintInterfaces() { for _, iface := range myInterfaces { if iface.State { @@ -338,6 +370,7 @@ func DebugNeighbors() { } } +// TODO @ MICHAEL: // func RemoveNeighbor(neighbor Neighbor) { // // TODO: remove from routing table // myRoutes := GetRoutes() @@ -359,6 +392,8 @@ func DebugNeighbors() { // } // untested function above +// ************************************** BASIC FUNCTIONS ********************************************************** + func CleanUp() { fmt.Print("Cleaning up...\n") // go through the interfaces, pop thread & close the UDP FDs @@ -396,7 +431,7 @@ func CleanUp() { } // TODO: have it take TTL so we can decrement it when forwarding -func SendIP(src Interface, dest *Neighbor, protocolNum int, message []byte, destIP string) error { +func SendIP(src *Interface, dest *Neighbor, protocolNum int, message []byte, destIP string) error { hdr := ipv4header.IPv4Header{ Version: 4, Len: 20, // Header length is always 20 when no IP options @@ -428,36 +463,18 @@ func SendIP(src Interface, dest *Neighbor, protocolNum int, message []byte, dest log.Fatalln("Error marshalling header: ", err) } + // Combine the header and the message into a single byte array bytesToSend := make([]byte, 0, len(headerBytes)+len(message)) bytesToSend = append(bytesToSend, headerBytes...) bytesToSend = append(bytesToSend, []byte(message)...) - // Send the message to the "link-layer" addr:port on UDP - listenAddr, err := net.ResolveUDPAddr("udp4", dest.UdpAddr.String()) - if err != nil { - return err - } - // idk that this is ^^ bytesWritten, err := dest.SendSocket.Write(bytesToSend) if err != nil { return err } - - // send to the dest.UdpAddr without the SendSocket - // conn, err := net.DialUDP("udp4", nil, listenAddr) - // if err != nil { - // fmt.Println(err, "here5") - // return err - // } - - // bytesWritten, err := conn.Write(bytesToSend) - // if err != nil { - // fmt.Println(err, "here6") - // return err - // } - // what we had previously just in case - fmt.Printf("Sent %d bytes to %s\n", bytesWritten, listenAddr.String()) + // TODO @ MICHAEL UPDATE with appropriate src + fmt.Printf("Sent %d bytes to %s\n", bytesWritten, dest.UdpAddr.String()) return nil } @@ -466,6 +483,7 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error { buffer := make([]byte, MAX_IP_PACKET_SIZE) // TODO: fix wordking // Read on the UDP port + // Too much printing so I commented it out // fmt.Println("wating to read from UDP socket") _, _, err := conn.ReadFromUDP(buffer) if err != nil { @@ -516,120 +534,183 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error { // drop the packet return nil } - if hdr.Protocol == 12 { - // RIP - // 1) check if the message is for me, if so, sendUP (aka call the correct handler) - command := message[0] - if command == 1 { - // request - // SendUpdates() - } else if command == 2 { - numEntries := message[1] - - entries := make([]RIPEntry, 0, numEntries) - for i := 0; i < int(numEntries); i++ { - offset := 4 + 2 + i*12 - address := binary.BigEndian.Uint32(message[offset : offset+4]) - mask := binary.BigEndian.Uint32(message[offset+4 : offset+8]) - cost := binary.BigEndian.Uint32(message[offset+8 : offset+12]) - entries = append(entries, RIPEntry{address: address, mask: mask, cost: cost}) - } + switch hdr.Protocol { + case 0: + // call the test packet handler + err = protocolHandlers[int(hdr.Protocol)](nil, nil, message, hdr) + if err != nil { + fmt.Println("Error handling test packet", err) + return err + } + case 12: + // call the RIP handler + err = protocolHandlers[int(hdr.Protocol)](nil, nil, message, hdr) + if err != nil { + fmt.Println("Error handling RIP", err) + return err + } + default: + return nil + + } - // add to routing table - for _, entry := range entries { - address := fmt.Sprintf("%d.%d.%d.%d", byte(entry.address>>24), byte(entry.address>>16), byte(entry.address>>8), byte(entry.address)) - mask := fmt.Sprintf("%d.%d.%d.%d", byte(entry.mask>>24), byte((entry.mask>>16)&0xff), byte((entry.mask>>8)&0xff), byte(entry.mask&0xff)) - - // check if the entry is already in the routing table - if _, ok := routingTable[netip.MustParsePrefix(address+"/24")]; ok { - // if so, check if the cost is the same - // if routingTable[netip.MustParsePrefix(address+"/24")].Cost == entry.cost { - // // if so, do nothing - // continue - // } else { - // // if not, update the cost - // routingTable[netip.MustParsePrefix(address+"/24")] = Hop{entry.cost, mask, "R"} - // } - continue - } - // fmt.Println(entry.cost) - routingTable[netip.MustParsePrefix(address+"/24")] = Hop{entry.cost + 1, mask, "R"} - } + return nil +} + +// ************************************** Protocol Handlers ******************************************************* + +func handleRIP(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.IPv4Header) error { + command := message[0] + switch command { + case 1: + // request + SendUpdates() + case 2: + numEntries := message[1] + + // parse the entries + entries := make([]RIPEntry, 0, numEntries) + for i := 0; i < int(numEntries); i++ { + offset := SIZE_OF_RIP_MESSAGE + i*SIZE_OF_RIP_ENTRY + + // each field is 4 bytes + address := binary.BigEndian.Uint32(message[offset : offset+4]) + mask := binary.BigEndian.Uint32(message[offset+4 : offset+8]) + cost := binary.BigEndian.Uint32(message[offset+8 : offset+12]) + + // add to entries + entries = append(entries, RIPEntry{address: address, mask: mask, cost: cost}) } - } else { - // 2) check if the message is for me, if so, sendUP (aka call the correct handler) - if hdr.Dst.String() == myVIP.IpPrefix.Addr().String() { - fmt.Println("for me") - if hdr.Protocol == 0 { - fmt.Printf("Received test packet: Src: %s, Dst: %s, TTL: %d, Data: %s\n", - hdr.Src.String(), hdr.Dst.String(), hdr.TTL, string(message)) - return nil + // add to routing table + for _, entry := range entries { + address := fmt.Sprintf("%d.%d.%d.%d", byte(entry.address>>24), byte(entry.address>>16), byte(entry.address>>8), byte(entry.address)) + mask := fmt.Sprintf("%d.%d.%d.%d", byte(entry.mask>>24), byte((entry.mask>>16)), byte((entry.mask>>8)), byte(entry.mask)) + + if address == "0.0.0.0" { + continue + } + + // TODO @ MICHAEL: check if the entry is already in the routing table and update if need be + if _, ok := routingTable[netip.MustParsePrefix(address+"/24")]; ok { + continue } - + + routingTable[netip.MustParsePrefix(address+"/24")] = Hop{entry.cost + 1, mask, "R"} } - // if not, need to forward the packer to a neighbor or check the table - // after decrementing TTL and updating checksum - hdr.TTL-- - // update checksum - headerBytes, err = hdr.Marshal() - if err != nil { - log.Fatalln("Error marshalling header: ", err) + } + + return nil +} + +func handleTestPackets(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.IPv4Header) error { + // 2) check if the message is for me, if so, sendUP (aka call the correct handler) + // filter the message, still not the same + // TODO @ MICHAEL + message = bytes.Map(func(r rune) rune { + if unicode.IsPrint(r) { + return r } - hdr.Checksum = int(ComputeChecksum(headerBytes)) - headerBytes, err = hdr.Marshal() - if err != nil { - log.Fatalln("Error marshalling header: ", err) + return -1 + }, message) + + for _, interfaces := range myInterfaces { + if hdr.Dst.String() == interfaces.IpPrefix.Addr().String() { + fmt.Printf("Received test packet: Src: %s, Dst: %s, TTL: %d, Data: %s\n", + hdr.Src.String(), hdr.Dst.String(), hdr.TTL, string(message)) + return nil } - bytesToSend := make([]byte, 0, len(headerBytes)+len(message)) - bytesToSend = append(bytesToSend, headerBytes...) - bytesToSend = append(bytesToSend, []byte(message)...) - - - // 3) check if message is for a neighbor, if so, sendIP there - for _, neighbors := range myNeighbors { - // fmt.Println(neighbors) - for _, neighbor := range neighbors { - if hdr.Dst.String() == neighbor.VipAddr.String() { - fmt.Println("for neighbor") - // send the packet to the neighbor - err := SendIP(myVIP, neighbor, hdr.Protocol, bytesToSend, hdr.Dst.String()) - if err != nil { - fmt.Println("Error sending IP packet", err) - return err + } + + // TODO @ MICHAEL: check if this is correct... + // if not, need to forward the packer to a neighbor or check the table + // after decrementing TTL and updating checksum + hdr.TTL-- + // update checksum + headerBytes, err := hdr.Marshal() + if err != nil { + log.Fatalln("Error marshalling header: ", err) + } + + hdr.Checksum = int(ComputeChecksum(headerBytes)) + headerBytes, err = hdr.Marshal() + if err != nil { + log.Fatalln("Error marshalling header: ", err) + } + bytesToSend := make([]byte, 0, len(headerBytes)+len(message)) + bytesToSend = append(bytesToSend, headerBytes...) + bytesToSend = append(bytesToSend, message...) + + + // 3) check if message is for a neighbor, if so, sendIP there + // fmt.Println("checking neighbors") + for _, neighbors := range myNeighbors { + for _, neighbor := range neighbors { + // check for matching neighbor + if hdr.Dst.String() == neighbor.VipAddr.String() { + // get the source interface and set dst to it + for _, interfaces := range myInterfaces { + if interfaces.Name == neighbor.Name { + err = SendIP(interfaces, neighbor, hdr.Protocol, bytesToSend, hdr.Dst.String()) + if err != nil { + fmt.Println(err) + } + break } - return nil } + return nil } } - // fmt.Println("No neighbors, checking Routes") - // 4) check forwarding table. if so, forward to the neighbor with that VIP - - for prefix, hop := range routingTable { - netIP := net.ParseIP(prefix.Addr().String()) - if netIP.String() == hdr.Dst.String() { - // send the packet to next hop - neighbors, err := GetNeighborByIP(hop.VipAsStr) + } + // 4) check forwarding table. if so, forward to the neighbor with that VIP + // fmt.Println("checking routing table") + for prefix, hop := range routingTable { + netIP := net.ParseIP(prefix.Addr().String()) + // check if the destination is in the routing table + if netIP.String() == hdr.Dst.String() { + // send the packet to next hop + // get the corresponding neighbor + neighbor, err := GetNeighborByIP(hop.VipAsStr) + if err != nil { + fmt.Println("Error getting neighbor by IP", err) + // check if there is a route to hop.VipAsStr + // this should be done recursively yeah? + neighbor, err = GetRouteByIP(hop.VipAsStr) if err != nil { - fmt.Println("Error getting neighbor by IP", err) - return err + fmt.Println("Error getting route by IP", err) + return nil } - err = SendIP(myVIP, neighbors, hdr.Protocol, bytesToSend, hdr.Dst.String()) - if err != nil { - fmt.Println("Error sending IP packet", err) - return err + for _, interfaces := range myInterfaces { + if interfaces.Name == neighbor.Name { + err = SendIP(interfaces, neighbor, hdr.Protocol, bytesToSend, hdr.Dst.String()) + if err != nil { + fmt.Println(err) + } + break + } } return nil } + // get the source interface and set dst to it + for _, interfaces := range myInterfaces { + if interfaces.Name == neighbor.Name { + err = SendIP(interfaces, neighbor, hdr.Protocol, bytesToSend, hdr.Dst.String()) + if err != nil { + fmt.Println(err) + } + break + } + } + return nil } - // send 10.2.0.3 hello - // 5) if not, drop the packet - return nil } + // 5) if not, drop the packet return nil } +// ************************************** CHECKSUM FUNCTIONS ****************************************************** + func ComputeChecksum(b []byte) uint16 { checksum := header.Checksum(b, 0) checksumInv := checksum ^ 0xffff @@ -643,17 +724,9 @@ func ValidateChecksum(b []byte, fromHeader uint16) uint16 { return checksum } -func GetInterfaces() []*Interface { - return myInterfaces -} - -func GetNeighbors() map[string][]*Neighbor { - return myNeighbors -} +// ************************************** RIP FUNCTIONS ********************************************************** -func GetRoutes() map[netip.Prefix]Hop { - return routingTable -} +// TODO @ MICHAEL: LONGEST PREFIX MATCHING func NewRIPMessage(command uint8, entries []RIPEntry) *RIPMessage { return &RIPMessage{ @@ -695,13 +768,14 @@ func SendRIPMessage(src Interface, dest *Neighbor, message *RIPMessage) error { bytesToSend := make([]byte, 0, len(headerBytes)+4+1+1+len(message.entries)*12) bytesToSend = append(bytesToSend, headerBytes...) - - buf := make([]byte, 4+1+1+len(message.entries)*12) + // make the RIP message + buf := make([]byte, SIZE_OF_RIP_MESSAGE + len(message.entries)*SIZE_OF_RIP_ENTRY) buf[0] = message.command buf[1] = message.numEntries for i, entry := range message.entries { - offset := 4 + 2 + i*12 + offset := SIZE_OF_RIP_MESSAGE + i*SIZE_OF_RIP_ENTRY + // each field is 4 bytes binary.BigEndian.PutUint32(buf[offset:offset+4], entry.address) binary.BigEndian.PutUint32(buf[offset+4:offset+8], entry.mask) binary.BigEndian.PutUint32(buf[offset+8:offset+12], entry.cost) @@ -709,71 +783,200 @@ func SendRIPMessage(src Interface, dest *Neighbor, message *RIPMessage) error { bytesToSend = append(bytesToSend, buf...) + // send RIP message _, err = dest.SendSocket.Write(bytesToSend) if err != nil { return err } - - // what we had previously just in case - // lots of printing - // fmt.Printf("Sent %d bytes to %s\n", bytesWritten, dest.UdpAddr.String()) return nil } -func SendUpdates() { - entries := make([]RIPEntry, len(routingTable)) - for prefix, hop := range routingTable { - netIP := net.ParseIP(prefix.Addr().String()) - ipBytes := netIP.To4() - ipUint32 := uint32(ipBytes[0]) << 24 | uint32(ipBytes[1]) << 16 | uint32(ipBytes[2]) << 8 | uint32(ipBytes[3]) +func RequestRip() { + // create RIP message + message := NewRIPMessage(1, []RIPEntry{}) - if netIP.String() == "0.0.0.0" { + // send RIP message to RIP neighbors + for _, neighbors := range myNeighbors { + for _, neighbor := range neighbors { + // check if neighbor is RIP neighbor + // if not, continue + for _, ripNeighbor := range myRIPNeighbors { + if neighbor.VipAddr.String() == ripNeighbor.String() { + // send RIP message + err := SendRIPMessage(myVIP, neighbor, message) + if err != nil { + continue + } + } + } continue } + } +} - if hop.Type == "S" { - continue +// func SendUpdates() { +// entries := make([]RIPEntry, len(routingTable)) +// // create RIP entries from its interfaces to one another +// for _, iface := range myInterfaces { +// for _, iface2 := range myInterfaces { +// if iface.Name == iface2.Name { +// continue +// } +// entry := &RIPEntry{ +// address: ConvertIPToUint32(iface2.IpPrefix.Addr().String()), +// cost: 1, +// mask: ConvertIPToUint32(iface.IpPrefix.Addr().String()), +// } +// entries = append(entries, *entry) +// } +// } + +// // create RIP entries from its neighbors +// for prefix, hop := range routingTable { + +// // convert prefix to uint32 +// ipUint32 := ConvertIPToUint32(prefix.Addr().String()) + +// // dont send RIP entries for static routes +// if hop.Type == "S" { +// continue +// } + +// // get +// for _, neighbors := range myNeighbors { +// for _, neighbor := range neighbors { + +// // check if neighbor is RIP neighbor +// // if not, continue +// for _, ripNeighbor := range myRIPNeighbors { +// if neighbor.VipAddr.String() == ripNeighbor.String() { +// // TODO @ MICHAEL: using myVIP +// // BUG: this is not correct +// neighborUint32 := ConvertIPToUint32(myVIP.IpPrefix.Addr().String()) + +// // Split Horizon with Poisoned Reverse +// cost := hop.Cost +// if hop.Type == "R" { +// cost = INFINITY +// } + +// // create RIP entry +// entry := &RIPEntry{ +// address: ipUint32, +// cost: cost, +// mask: neighborUint32, +// } + +// // add to entries and create RIP message +// entries = append(entries, *entry) +// message := NewRIPMessage(2, entries) + +// // send RIP message +// err := SendRIPMessage(myVIP, neighbor, message) +// if err != nil { +// continue +// } +// } +// } +// continue +// } +// } + +// } +// } + +// THIS MIGHT BE WRONG... +func SendUpdates() { + entries := make([]RIPEntry, len(routingTable)) + // create RIP entries from its interfaces to one another + for _, iface := range myInterfaces { + for _, iface2 := range myInterfaces { + if iface.Name == iface2.Name { + continue + } + // cost should be 0 but it is one + entry := &RIPEntry{ + address: ConvertIPToUint32(iface2.IpPrefix.Addr().String()), + cost: LOCAL_COST, + mask: ConvertIPToUint32(iface.IpPrefix.Addr().String()), + } + entries = append(entries, *entry) + + entry = &RIPEntry{ + address: ConvertIPToUint32(iface.IpPrefix.Addr().String()), + cost: LOCAL_COST, + mask: ConvertIPToUint32(iface2.IpPrefix.Addr().String()), + } + entries = append(entries, *entry) } + } - for _, neighbors := range myNeighbors { - for _, neighbor := range neighbors { - neighborBits := net.ParseIP(myVIP.IpPrefix.Addr().String()) - neighborBits = neighborBits.To4() - neighborUint32 := uint32(neighborBits[0]) << 24 | uint32(neighborBits[1]) << 16 | uint32(neighborBits[2]) << 8 | uint32(neighborBits[3]) - cost := hop.Cost - if hop.Type == "R" { - cost = INFINITY - } - entry := &RIPEntry{ - address: ipUint32, - cost: cost, - mask: neighborUint32, + // create RIP entries from its neighbors + for _, neighbors := range myNeighbors { + for _, neighbor := range neighbors { + ipUint32 := ConvertIPToUint32(neighbor.VipAddr.String()) + var neighborUint32 uint32 + for _, interfaces := range myInterfaces { + if ifaceContainsIP(*interfaces, neighbor.VipAddr) { + neighborUint32 = ConvertIPToUint32(interfaces.IpPrefix.Addr().String()) + break } - entries = append(entries, *entry) - message := NewRIPMessage(2, entries) + } + + // create RIP entry + entry := &RIPEntry{ + address: ipUint32, + cost: LOCAL_COST, + mask: neighborUint32, + } - err := SendRIPMessage(myVIP, neighbor, message) - if err != nil { - // fmt.Println("Error sending RIP packet") - continue + // add to entries and create RIP message + entries = append(entries, *entry) + message := NewRIPMessage(2, entries) + + // send RIP message + for _, Interfaces := range myInterfaces { + if Interfaces.Name == neighbor.Name { + err := SendRIPMessage(myVIP, neighbor, message) + if err != nil { + continue + } } } + } + } +} +func ifaceContainsIP(iface Interface, ip netip.Addr) bool { + // check if the ip is in the interface's prefix + if iface.IpPrefix.Contains(netip.MustParseAddr(ip.String())) { + return true } + return false } -func CheckAndUpdateRoutingTable() { - for { - time.Sleep(12 * time.Second) - for prefix, hop := range routingTable { - // delete route if not refreshed in 12 seconds - // not sure if there is a better way to do this - if hop.Type == "R" { - delete(routingTable, prefix) - SendUpdates() - } - } - } -} \ No newline at end of file +func ConvertIPToUint32(ip string) uint32 { + netIP := net.ParseIP(ip) + ipBytes := netIP.To4() + ipUint32 := uint32(ipBytes[0]) << 24 | uint32(ipBytes[1]) << 16 | uint32(ipBytes[2]) << 8 | uint32(ipBytes[3]) + return ipUint32 +} + +// TODO @ MICHEAL: Handle links going down and link recovery +// func CheckAndUpdateRoutingTable() { +// for { +// time.Sleep(12 * time.Second) +// for prefix, hop := range routingTable { +// // delete route if not refreshed in 12 seconds +// // not sure if there is a better way to do this +// if hop.Type == "R" { +// delete(routingTable, prefix) +// SendUpdates() +// } +// } +// } +// } + +// TODO @ MICHAEL: Triggereed Updates \ No newline at end of file -- cgit v1.2.3-70-g09d2