diff options
author | sotech117 <michael_foiani@brown.edu> | 2023-10-22 09:22:31 -0400 |
---|---|---|
committer | sotech117 <michael_foiani@brown.edu> | 2023-10-22 09:22:31 -0400 |
commit | 36b61f5f38bd2aae78353fa112c0787f0a89a31f (patch) | |
tree | 5ff772aeacbe6f3caf54cd8685a9ee8b19c4d0cb /pkg/ipstack/ipstack.go | |
parent | a935739d332ccb82174ddb925dcf5e473dfae41f (diff) |
forwarding works as expected among multiple subnets, but checksum fails. will focus more on RIP timeouts next.
Diffstat (limited to 'pkg/ipstack/ipstack.go')
-rw-r--r-- | pkg/ipstack/ipstack.go | 407 |
1 files changed, 187 insertions, 220 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go index e47c741..334aab5 100644 --- a/pkg/ipstack/ipstack.go +++ b/pkg/ipstack/ipstack.go @@ -69,7 +69,7 @@ var myVIP Interface var myInterfaces []*Interface var myNeighbors = make(map[string][]*Neighbor) -var myRIPNeighbors = make([]netip.Addr, 0) +var myRIPNeighbors = make(map[string]bool) type HandlerFunc func(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.IPv4Header) error @@ -102,7 +102,6 @@ func Initialize(lnxFilePath string) error { } // 1) add each local if to the routing table, as dictated by its subnet - // static := false for _, iface := range lnxConfig.Interfaces { prefix := netip.PrefixFrom(iface.AssignedIP, iface.AssignedPrefix.Bits()) i := &Interface{ @@ -123,14 +122,7 @@ func Initialize(lnxFilePath string) error { go InterfaceListenerRoutine(i) myInterfaces = append(myInterfaces, i) - routingTable[prefix] = Hop{STATIC_COST, "L", i, prefix.Addr()} - - // TODO @ MICHAEL: The hop shouldn't be the interface name - //if !static { - // ifacePrefix := netip.MustParsePrefix("0.0.0.0/0") - // routingTable[ifacePrefix] = Hop{STATIC_COST, "S", nil} - // static = true - //} + routingTable[prefix.Masked()] = Hop{LOCAL_COST, "L", i, prefix.Addr()} } // 2) add neighbors to if->neighbors map @@ -143,11 +135,33 @@ func Initialize(lnxFilePath string) error { myNeighbors[neighbor.InterfaceName] = append(myNeighbors[neighbor.InterfaceName], n) } - // - //for _, route := range lnxConfig.RipNeighbors { - // // add to RIP neighbors - // myRIPNeighbors = append(myRIPNeighbors, route) - //} + + // 3) add RIP neighbors to RIP neighbor list + for _, route := range lnxConfig.RipNeighbors { + // add to RIP neighbors + for _, iface := range myInterfaces { + for _, neighbor := range myNeighbors[iface.Name] { + if neighbor.VipAddr == route { + myRIPNeighbors[neighbor.VipAddr.String()] = true + break + } + } + } + } + + // 4) add static routes to routing table + for prefix, addr := range lnxConfig.StaticRoutes { + // need loops to find the interface that matches the neighbor to send static to + // hops needs this interface + for _, iface := range myInterfaces { + for _, neighbor := range myNeighbors[iface.Name] { + if neighbor.VipAddr == addr { + routingTable[prefix] = Hop{STATIC_COST, "S", iface, addr} + break + } + } + } + } // add protocol handlers return nil @@ -155,7 +169,6 @@ func Initialize(lnxFilePath string) error { func InterfaceListenerRoutine(i *Interface) { // decompose the interface - prefix := i.IpPrefix socket := i.RecvSocket signal := i.SocketChannel @@ -179,7 +192,7 @@ func InterfaceListenerRoutine(i *Interface) { } // TODO: remove these "training wheels" time.Sleep(1 * time.Millisecond) - err := RecvIP(prefix, socket, &isUp) + err := RecvIP(i, &isUp) if err != nil { fmt.Println("Error receiving IP packet", err) return @@ -308,9 +321,9 @@ func SprintRoutingTable() { if hop.Type == "L" { fmt.Printf("%s\t%s\tLOCAL:%s\t%d\n", hop.Type, prefix.String(), hop.Interface.Name, 0) } else if hop.Type == "S" { - fmt.Printf("%s\t%s\t%s\t%s\n", hop.Type, prefix.String(), myVIP.IpPrefix.Addr().String(), "-") + fmt.Printf("%s\t%s\t%s\t%s\n", hop.Type, prefix.String(), hop.VIP.String(), "-") } else { - fmt.Printf("%s\t%s\t%s\t%d\n", hop.Type, prefix.String(), hop.VIP, hop.Cost) + fmt.Printf("%s\t%s\t%s\t%d\n", hop.Type, prefix.String(), hop.VIP.String(), hop.Cost) } } } @@ -417,7 +430,6 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de if err != nil { return errors.WithMessage(err, "Could not bind to UDP port->\t"+dest.UdpAddr.String()) } - // *conn = *tmpConn bytesWritten, err := tmpConn.Write(bytesToSend) if err != nil { @@ -429,7 +441,13 @@ func SendIP(src *netip.Addr, dest *Neighbor, protocolNum int, message []byte, de return nil } -func RecvIP(prefix netip.Prefix, conn net.UDPConn, isOpen *bool) error { +func RecvIP(iface *Interface, isOpen *bool) error { + fmt.Printf("Receiving IP packet on %s\n", iface.Name) + + // deconstruct interface + prefix := iface.IpPrefix + conn := iface.RecvSocket + buffer := make([]byte, MAX_IP_PACKET_SIZE) // TODO: fix wordking // Read on the UDP port @@ -469,7 +487,8 @@ func RecvIP(prefix netip.Prefix, conn net.UDPConn, isOpen *bool) error { } // Next, get the message, which starts after the header - message := buffer[headerSize:] + messageLen := hdr.TotalLen - hdr.Len + message := buffer[headerSize : messageLen+headerSize] // 1) check if the TTL & checksum is valid TTL := hdr.TTL @@ -481,16 +500,22 @@ func RecvIP(prefix netip.Prefix, conn net.UDPConn, isOpen *bool) error { // check if the checksum is valid if checksumState == "FAIL" { // drop the packet + fmt.Println("checksum failed, dropping packet") return nil } // at this point, the packet is valid. next steps consider the forwarding of the packet // 2) check if the message is for me, if so, sendUP (aka call the correct handler) - fmt.Println("checking if it's for me!") + if hdr.Protocol != RIP_PROTOCOL { + fmt.Println("I see a non-rip packet") + } if hdr.Dst == prefix.Addr() { // see if there is a handler for this protocol if handler, ok := protocolHandlers[hdr.Protocol]; ok { - err := handler(&myVIP, nil, message, hdr) + if hdr.Protocol != RIP_PROTOCOL { + fmt.Println("this test packet is exactly for me") + } + err := handler(iface, nil, message, hdr) if err != nil { fmt.Println(err) } @@ -511,8 +536,8 @@ func RecvIP(prefix netip.Prefix, conn net.UDPConn, isOpen *bool) error { return nil } - // local and RIP hops - if hop.Type == "L" || hop.Type == "R" { + // local hop + if hop.Type == "L" { // if it's a local route, then the name is the interface name for _, neighbor := range myNeighbors[hop.Interface.Name] { if neighbor.VipAddr == hdr.Dst { @@ -523,17 +548,96 @@ func RecvIP(prefix netip.Prefix, conn net.UDPConn, isOpen *bool) error { } } } + + // rip hop + if hop.Type == "R" { + // if it's a rip route, then the check is against the hop vip + for _, neighbor := range myNeighbors[hop.Interface.Name] { + if neighbor.VipAddr == hop.VIP { + err2 := SendIP(nil, neighbor, hdr.Protocol, message, hdr.Dst.String(), hdr) + if err2 != nil { + return err2 + } + } + } + } } // if not in table, drop packet return nil } +// ************************************** RIP Routines ******************************************************* + +func periodicUpdateRoutine() { + for { + // for each periodic update, we want to send our nodes in the table + entries := make([]RIPEntry, len(routingTable)) + for prefix, hop := range routingTable { + entries = append(entries, + RIPEntry{ + address: ConvertIPToUint32(prefix.Addr().String()), + mask: uint32(prefix.Bits()), + cost: hop.Cost, + }) + // fmt.Printf("Sending RIP update: %s\t%d\t%d\n", prefix.Addr().String(), uint32(prefix.Bits()), hop.Cost) + } + + // send to each neighbor + for _, iface := range myInterfaces { + for _, n := range myNeighbors[iface.Name] { + _, in := myRIPNeighbors[n.VipAddr.String()] + if !in { + continue + } + message := NewRIPMessage(2, entries) + err := SendRIPMessage(*iface, n, message) + if err != nil { + // fmt.Printf("Error sending RIP message to %s\n", n.VipAddr.String()) + continue + } + } + } + + // wait 5 sec + time.Sleep(5 * time.Second) + } +} + +//timeoutTable := make(map[netip.Addr]time.Time) +//func manageTimeoutsRoutine() { +// for +//} + +func startRipRoutines() { + // send a request to every neighbor + go func() { + for _, iface := range myInterfaces { + for _, neighbor := range myNeighbors[iface.Name] { + // send a request + message := NewRIPMessage(1, nil) + err := SendRIPMessage(*iface, neighbor, message) + if err != nil { + return + } + } + } + }() + + go periodicUpdateRoutine() + + // make a "timeout" table, for each response we add to the table via rip + // go manageTimeoutsRoutine() + + // start a routine that sends updates every 10 seconds +} + // ************************************** Protocol Handlers ******************************************************* func RegisterProtocolHandler(protocolNum int) bool { if protocolNum == RIP_PROTOCOL { protocolHandlers[protocolNum] = handleRIP + go startRipRoutines() return true } if protocolNum == TEST_PROTOCOL { @@ -548,7 +652,7 @@ func handleRIP(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.I switch command { case 1: // request - SendUpdates() + // SendUpdates() break case 2: numEntries := message[1] @@ -570,22 +674,27 @@ func handleRIP(src *Interface, dest *Neighbor, message []byte, hdr *ipv4header.I // 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 := binary.LittleEndian.Uint32(message[4:8]) - prefix := netip.PrefixFrom(netip.MustParseAddr(address), int(mask)) + // fmt.Printf("Received RIP update: %s\t%d\t%d\n", address, entry.mask, entry.cost) - if address == "0.0.0.0" { + if address == "0.0.0.0" { // TODO: investigate this continue } - // TODO @ MICHAEL: check if the entry is already in the routing table and update if need be - if _, ok := routingTable[prefix]; ok { + prefix := netip.PrefixFrom(netip.MustParseAddr(address), int(entry.mask)) + // fmt.Println(prefix.String()) + + // check if the entry is already in the routing table and update if need be + if node, ok := routingTable[prefix.Masked()]; ok { + if entry.cost < node.Cost { + routingTable[prefix.Masked()] = Hop{entry.cost + 1, "R", src, hdr.Src} + } continue } if entry.cost == 17 { - routingTable[prefix] = Hop{0, "R", src, prefix.Addr()} + routingTable[prefix.Masked()] = Hop{0, "R", src, hdr.Src} } else { - routingTable[prefix] = Hop{entry.cost + 1, "R", src, prefix.Addr()} + routingTable[prefix.Masked()] = Hop{entry.cost + 1, "R", src, hdr.Src} } } } @@ -599,99 +708,6 @@ func handleTestPackets(src *Interface, dest *Neighbor, message []byte, hdr *ipv4 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) -// -// // potentially unneeded -// // message = bytes.Map(func(r rune) rune { -// // if unicode.IsPrint(r) { -// // return r -// // } -// // return -1 -// // }, message) -// -// fmt.Println("checking my interfaces") -// 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 -// } -// } -// -// // if not, need to forward the packer to a neighbor or check the table -// // after decrementing TTL and updating checksum -// // DONE IN SENDIP FUNCTION -// -// // 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, message, hdr.Dst.String(), hdr) -// if err != nil { -// fmt.Println(err) -// } -// break -// } -// } -// return nil -// } -// } -// } -// // 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 route by IP", err) -// return nil -// } -// for _, interfaces := range myInterfaces { -// if interfaces.Name == neighbor.Name { -// src := interfaces.IpPrefix.Addr() -// err = SendIP(&src, neighbor, hdr.Protocol, message, hdr.Dst.String(), hdr) -// 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 { -// src := interfaces.IpPrefix.Addr() -// err = SendIP(&src, neighbor, hdr.Protocol, message, hdr.Dst.String(), hdr) -// if err != nil { -// fmt.Println(err) -// } -// break -// } -// } -// return nil -// } -// } -// -// // 5) if not, drop the packet -// return nil -//} - // ************************************** CHECKSUM FUNCTIONS ****************************************************** func ComputeChecksum(b []byte) uint16 { @@ -711,7 +727,7 @@ func ValidateChecksum(b []byte, fromHeader uint16) uint16 { // TODO @ MICHAEL: LONGEST PREFIX MATCHING func LongestPrefix(src netip.Addr) (Hop, error) { - possibleBits := [5]int{32, 24, 16, 8, 0} + possibleBits := [2]int{32, 24} for _, bits := range possibleBits { cmpPrefix := netip.PrefixFrom(src, bits) for prefix, hop := range routingTable { @@ -792,99 +808,54 @@ func SendRIPMessage(src Interface, dest *Neighbor, message *RIPMessage) error { return nil } -func RequestRip() { - // create RIP message - message := NewRIPMessage(1, []RIPEntry{}) +//func RequestRip() { +// // create RIP message +// message := NewRIPMessage(1, []RIPEntry{}) +// +// // 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 +// } +// } +//} - // 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 - } - } +func BroadcastPeriodicUpdates() { + // for each periodic update, we want to send our nodes in the table + entries := make([]RIPEntry, len(routingTable)) + for prefix, hop := range routingTable { + entries = append(entries, + RIPEntry{ + address: ConvertIPToUint32(prefix.Addr().String()), + mask: uint32(prefix.Bits()), + cost: hop.Cost, + }) + } + message := NewRIPMessage(2, entries) + + // send to each neighbor + for _, iface := range myInterfaces { + for _, n := range myNeighbors[iface.Name] { + err := SendRIPMessage(*iface, n, message) + if err != nil { + fmt.Printf("Error sending RIP message to %s\n", n.VipAddr.String()) + continue } - 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() { @@ -965,10 +936,6 @@ func ConvertIPToUint32(ip string) uint32 { return ipUint32 } -func intersect(n1, n2 netip.Prefix) bool { - return n1.Overlaps(n2) -} - // TODO @ MICHEAL: Handle links going down and link recovery // func CheckAndUpdateRoutingTable() { // for { |