aboutsummaryrefslogtreecommitdiff
path: root/pkg/ipstack
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/ipstack')
-rw-r--r--pkg/ipstack/ipstack.go407
-rw-r--r--pkg/ipstack/ipstack_test.go31
2 files changed, 199 insertions, 239 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 {
diff --git a/pkg/ipstack/ipstack_test.go b/pkg/ipstack/ipstack_test.go
index 5cef903..e782f67 100644
--- a/pkg/ipstack/ipstack_test.go
+++ b/pkg/ipstack/ipstack_test.go
@@ -250,31 +250,20 @@ import (
//}
func TestIntersect(t *testing.T) {
- net1 := netip.MustParsePrefix("1.1.1.1/24")
+ net1 := netip.MustParsePrefix("10.0.0.0/24")
net2 := netip.MustParsePrefix("1.1.1.2/24")
net3 := netip.MustParsePrefix("1.0.0.1/24")
net4 := netip.MustParsePrefix("0.0.0.0/0") // default route
- net5 := netip.MustParsePrefix("1.1.1.1/32")
+ net5 := netip.MustParsePrefix("10.2.0.3/32")
- res00 := intersect(net1, net5)
- if !res00 {
- t.Error("net1 and net2 should intersect")
+ res00 := intersect(net5, net1)
+ if res00 {
+ t.Error("net5 -> net1 should not intersect")
t.Fail()
}
- res01 := intersect(net5, net1)
- if res01 {
- t.Error("net1 and net2 should not intersect")
- t.Fail()
- }
-
- res1 := intersect(net1, net2)
- if !res1 {
- t.Error("net1 and net2 should intersect")
- t.Fail()
- }
- res0 := intersect(net2, net1)
- if !res0 {
- t.Error("net1 and net2 should intersect")
+ res01 := intersect(net5, net4)
+ if !res01 {
+ t.Error("net5 -> net4 should intersect")
t.Fail()
}
@@ -306,3 +295,7 @@ func TestIntersect(t *testing.T) {
fmt.Println("TestIntersect successful")
}
+
+func intersect(n1, n2 netip.Prefix) bool {
+ return n1.Overlaps(n2)
+}