diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/ipstack/ipstack.go | 322 |
1 files changed, 232 insertions, 90 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go index dca19d6..da2d504 100644 --- a/pkg/ipstack/ipstack.go +++ b/pkg/ipstack/ipstack.go @@ -10,12 +10,15 @@ import ( "net" "net/netip" "time" + "encoding/binary" ) const ( MAX_IP_PACKET_SIZE = 1400 LOCAL_COST uint32 = 0 STATIC_COST uint32 = 4294967295 // 2^32 - 1 + MaxEntries = 64 + INFINITY = 15 ) // STRUCTS --------------------------------------------------------------------- @@ -44,9 +47,9 @@ type RIPMessage struct { } type RIPEntry struct { - addr netip.Addr + address uint32 cost uint32 - mask netip.Prefix + mask uint32 } type Hop struct { @@ -270,15 +273,14 @@ func GetNeighborByIP(ipAddr string) (*Neighbor, error) { func GetRouteByIP(ipAddr string) (*Neighbor, error) { for prefix, hop := range routingTable { - if prefix.Contains(netip.MustParseAddr(ipAddr)) { + netIP := net.ParseIP(prefix.Addr().String()) + if netIP.String() == ipAddr { fmt.Println("found route", hop.VipAsStr) - neighbors, err := GetNeighborsToInterface(hop.VipAsStr) + neighbor, err := GetNeighborByIP(hop.VipAsStr) if err != nil { fmt.Println("Error getting neighbors to interface", err) - return nil, err + continue // fix with longest prefix matching? } - neighbor := neighbors[0] - return neighbor, nil } } @@ -319,7 +321,7 @@ func SprintNeighbors() { func SprintRoutingTable() { for prefix, hop := range routingTable { if hop.Type == "L" { - fmt.Printf("%s\t%s\tLOCAL:%s\t%d\n", hop.Type, prefix.String(), hop.VipAsStr, hop.Cost) + fmt.Printf("%s\t%s\tLOCAL:%s\t%d\n", hop.Type, prefix.String(), hop.VipAsStr, 0) } else if hop.Type == "S" { fmt.Printf("%s\t%s\t%s\t%s\n", hop.Type, prefix.String(), hop.VipAsStr, "-") } else { @@ -435,6 +437,7 @@ func SendIP(src Interface, dest *Neighbor, protocolNum int, message []byte, dest if err != nil { return err } + // idk that this is ^^ bytesWritten, err := dest.SendSocket.Write(bytesToSend) if err != nil { return err @@ -463,7 +466,7 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error { buffer := make([]byte, MAX_IP_PACKET_SIZE) // TODO: fix wordking // Read on the UDP port - fmt.Println("wating to read from UDP socket") + // fmt.Println("wating to read from UDP socket") _, _, err := conn.ReadFromUDP(buffer) if err != nil { return err @@ -513,81 +516,116 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error { // drop the packet return nil } - - // 2) check if the message is for me, if so, sendUP (aka call the correct handler) - if hdr.Dst.String() == myVIP.IpPrefix.Addr().String() { - // call the correct handler in our case its just printing out the message - 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 - } - - } - // 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, []byte(message)...) - + 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}) + } - // 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 + // 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"} + } + } + } 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 } + } - } - fmt.Println("No neighbors, checking Routes") - // 4) check forwarding table. if so, forward to the neighbor with that VIP + // 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, []byte(message)...) - // needs RIP Protocol I believed - for prefix, hop := range routingTable { - fmt.Println(prefix) - if prefix.Contains(hdr.Dst) { - // send the packet to the neighbor - fmt.Println("testing", prefix, hdr.Dst.String()) - neighbors, err := GetNeighborsToInterface(hop.VipAsStr) - if err != nil { - fmt.Println("Error getting neighbor by IP", err) - return err - } - // get the longest prefix match + // 3) check if message is for a neighbor, if so, sendIP there + for _, neighbors := range myNeighbors { + // fmt.Println(neighbors) for _, neighbor := range neighbors { - fmt.Println("for neighbor", neighbor.VipAddr.String()) - // send the packet to the neighbor + 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 + } + return nil + } } - // err = SendIP(myVIP, neighbor, hdr.Protocol, bytesToSend, hdr.Dst.String()) - if err != nil { - fmt.Println("Error sending IP packet", err) - return err + } + // 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) + if err != nil { + fmt.Println("Error getting neighbor by IP", err) + return err + } + err = SendIP(myVIP, neighbors, hdr.Protocol, bytesToSend, hdr.Dst.String()) + if err != nil { + fmt.Println("Error sending IP packet", err) + return err + } + return nil } } + // send 10.2.0.3 hello + // 5) if not, drop the packet + return nil } - // send 10.2.0.3 hello - // 5) if not, drop the packet return nil } @@ -617,21 +655,125 @@ func GetRoutes() map[netip.Prefix]Hop { return routingTable } -// func LongestPrefixMatch(ipAddr string) (netip.Addr, error) { -// var longestMatch netip.Addr -// var longestMatchLength int -// ip := netip.MustParseAddr(ipAddr) -// for prefix := range routingTable { -// // Extract the prefix length using the Bits method -// prefixLen := prefix.Bits() -// if prefix.Contains(ip) && prefixLen > longestMatchLength { -// longestMatch = ip -// longestMatchLength = prefixLen -// } -// } -// if longestMatch == (netip.Addr{}) { -// return netip.Addr{}, errors.New("No match found in routing table") -// } -// return longestMatch, nil -// } -// A possible implementation of LongestPrefixMatch, need RIP Protocol to test?
\ No newline at end of file +func NewRIPMessage(command uint8, entries []RIPEntry) *RIPMessage { + return &RIPMessage{ + command: command, + numEntries: uint8(len(entries)), + entries: entries, + } +} + +func SendRIPMessage(src Interface, dest *Neighbor, message *RIPMessage) error { + hdr := ipv4header.IPv4Header{ + Version: 4, + Len: 20, // Header length is always 20 when no IP options + TOS: 0, + TotalLen: ipv4header.HeaderLen + 4 + 1 + 1 + len(message.entries)*12, + ID: 0, + Flags: 0, + FragOff: 0, + TTL: 32, + Protocol: 12, + Checksum: 0, // Should be 0 until checksum is computed + Src: src.IpPrefix.Addr(), + Dst: netip.MustParseAddr(dest.VipAddr.String()), + Options: []byte{}, + } + + headerBytes, err := hdr.Marshal() + if err != nil { + return 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)+4+1+1+len(message.entries)*12) + bytesToSend = append(bytesToSend, headerBytes...) + + + buf := make([]byte, 4+1+1+len(message.entries)*12) + buf[0] = message.command + buf[1] = message.numEntries + + for i, entry := range message.entries { + offset := 4 + 2 + i*12 + 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) + } + + bytesToSend = append(bytesToSend, buf...) + + _, 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]) + + if netIP.String() == "0.0.0.0" { + continue + } + + if hop.Type == "S" { + continue + } + + 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, + } + entries = append(entries, *entry) + message := NewRIPMessage(2, entries) + + err := SendRIPMessage(myVIP, neighbor, message) + if err != nil { + // fmt.Println("Error sending RIP packet") + continue + } + } + } + + } +} + +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 |