diff options
Diffstat (limited to 'pkg/ipstack')
-rw-r--r-- | pkg/ipstack/ipstack.go | 314 |
1 files changed, 269 insertions, 45 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go index be8bc1e..dca19d6 100644 --- a/pkg/ipstack/ipstack.go +++ b/pkg/ipstack/ipstack.go @@ -51,11 +51,13 @@ type RIPEntry struct { type Hop struct { Cost uint32 - VipAsStr string + VipAsStr string + Type string + // added this for printing purposes } // GLOBAL VARIABLES (data structures) ------------------------------------------ -var myVIP netip.Addr +var myVIP Interface var myInterfaces []*Interface var myNeighbors = make(map[string][]*Neighbor) @@ -68,28 +70,30 @@ var protocolHandlers = make(map[uint16]HandlerFunc) var routingTable = make(map[netip.Prefix]Hop) // 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) error { +func createUDPConn(UdpAddr netip.AddrPort, conn *net.UDPConn, isN bool) error { listenString := UdpAddr.String() listenAddr, err := net.ResolveUDPAddr("udp4", listenString) if err != nil { return errors.WithMessage(err, "Error resolving address->\t"+listenString) } - tmpConn, err := net.ListenUDP("udp4", listenAddr) - if err != nil { - return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString) + if !isN { + tmpConn, err := net.ListenUDP("udp4", listenAddr) + if err != nil { + return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString) + } + *conn = *tmpConn + } else { + tmpConn, err := net.DialUDP("udp4", nil, listenAddr) + if err != nil { + return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString) + } + *conn = *tmpConn } - *conn = *tmpConn return nil } func Initialize(lnxFilePath string) error { - //if len(os.Args) != 2 { - // fmt.Printf("Usage: %s <configFile>\n", os.Args[0]) - // os.Exit(1) - //} - //lnxFilePath := os.Args[1] - // Parse the file lnxConfig, err := lnxconfig.ParseConfig(lnxFilePath) if err != nil { @@ -97,7 +101,8 @@ func Initialize(lnxFilePath string) error { } // 1) initialize the interfaces on this node here and into the routing table - static := false + // static := false + interfaceToReturn := Interface{} for _, iface := range lnxConfig.Interfaces { prefix := netip.PrefixFrom(iface.AssignedIP, iface.AssignedPrefix.Bits()) i := &Interface{ @@ -106,10 +111,15 @@ func Initialize(lnxFilePath string) error { UdpAddr: iface.UDPAddr, RecvSocket: net.UDPConn{}, SocketChannel: make(chan bool), - State: false, + State: true, + } + if interfaceToReturn == (Interface{}) { + interfaceToReturn = *i + myVIP = *i } + // Added this for printing purposes for REPL FYI, if you have a better way lmk - err := createUDPConn(iface.UDPAddr, &i.RecvSocket) + err := createUDPConn(iface.UDPAddr, &i.RecvSocket, false) if err != nil { return errors.WithMessage(err, "Error creating UDP socket for interface->\t"+iface.Name) } @@ -118,11 +128,12 @@ func Initialize(lnxFilePath string) error { // 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} - static = true - } + // 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 @@ -134,7 +145,7 @@ func Initialize(lnxFilePath string) error { SocketChannel: make(chan bool), } - err := createUDPConn(neighbor.UDPAddr, &n.SendSocket) + err := createUDPConn(neighbor.UDPAddr, &n.SendSocket, true) if err != nil { return errors.WithMessage(err, "Error creating UDP socket for neighbor->\t"+neighbor.DestAddr.String()) } @@ -144,14 +155,22 @@ func Initialize(lnxFilePath string) error { // add to routing table // TODO: REVISIT AND SEE IF "24" IS CORRECT neighborPrefix := netip.PrefixFrom(neighbor.DestAddr, 24) - routingTable[neighborPrefix] = Hop{LOCAL_COST, neighbor.InterfaceName} + routingTable[neighborPrefix] = Hop{LOCAL_COST, neighbor.InterfaceName, "L"} + } + + for _, route := range lnxConfig.StaticRoutes { + // add to routing table + prefix := netip.MustParsePrefix("0.0.0.0/0") + routingTable[prefix] = Hop{LOCAL_COST, route.String(), "S"} } + // added for printing purposes for REPL FYI return nil } func InterfaceListenerRoutine(socket net.UDPConn, signal <-chan bool) { - isUp := false + isUp := true + // testing purposes set to TRUE closed := false // go routine that hangs on the recv @@ -199,11 +218,34 @@ func InterfaceUp(iface *Interface) { iface.SocketChannel <- true } +func InterfaceUpREPL(ifaceName string) { + iface, err := GetInterfaceByName(ifaceName) + if err != nil { + fmt.Println("Error getting interface by name", err) + return + } + iface.State = true + iface.SocketChannel <- true +} + +// we could do either of these but the REPL results in less work done in router and host + func InterfaceDown(iface *Interface) { iface.SocketChannel <- false iface.State = false } +func InterfaceDownREPL(ifaceName string) { + iface, err := GetInterfaceByName(ifaceName) + if err != nil { + fmt.Println("Error getting interface by name", err) + return + } + iface.SocketChannel <- false + iface.State = false +} +// same as above comment + func GetInterfaceByName(ifaceName string) (*Interface, error) { for _, iface := range myInterfaces { if iface.Name == ifaceName { @@ -214,6 +256,36 @@ func GetInterfaceByName(ifaceName string) (*Interface, error) { return nil, errors.Errorf("No interface with name %s", ifaceName) } +func GetNeighborByIP(ipAddr string) (*Neighbor, error) { + for _, neighbors := range myNeighbors { + for _, neighbor := range neighbors { + if neighbor.VipAddr.String() == ipAddr { + return neighbor, nil + } + } + } + + return nil, errors.Errorf("No interface with ip %s", ipAddr) +} + +func GetRouteByIP(ipAddr string) (*Neighbor, error) { + for prefix, hop := range routingTable { + if prefix.Contains(netip.MustParseAddr(ipAddr)) { + fmt.Println("found route", hop.VipAsStr) + neighbors, err := GetNeighborsToInterface(hop.VipAsStr) + if err != nil { + fmt.Println("Error getting neighbors to interface", err) + return nil, err + } + neighbor := neighbors[0] + + return neighbor, nil + } + } + + return nil, errors.Errorf("No interface with ip %s", ipAddr) +} + func GetNeighborsToInterface(ifaceName string) ([]*Neighbor, error) { if neighbors, ok := myNeighbors[ifaceName]; ok { return neighbors, nil @@ -222,30 +294,38 @@ func GetNeighborsToInterface(ifaceName string) ([]*Neighbor, error) { return nil, errors.Errorf("No interface with name %s", ifaceName) } -func SprintInterfaces() string { - buf := "" +func GetMyVIP() Interface { + return myVIP +} + +func SprintInterfaces() { for _, iface := range myInterfaces { - buf += fmt.Sprintf("%s\t%s\t%t\n", iface.Name, iface.IpPrefix.String(), iface.State) + if iface.State { + fmt.Printf("%s\t%s\t%s\n", iface.Name, iface.IpPrefix.String(), "UP") + } else { + fmt.Printf("%s\t%s\t%s\n", iface.Name, iface.IpPrefix.String(), "DOWN") + } } - return buf } -func SprintNeighbors() string { - buf := "" +func SprintNeighbors() { for ifaceName, neighbor := range myNeighbors { for _, n := range neighbor { - buf += fmt.Sprintf("%s\t%s\t%s\n", ifaceName, n.UdpAddr.String(), n.VipAddr.String()) + fmt.Printf("%s\t%s\t%s\n", ifaceName, n.VipAddr.String(), n.UdpAddr.String()) } } - return buf } -func SprintRoutingTable() string { - buf := "" +func SprintRoutingTable() { for prefix, hop := range routingTable { - buf += fmt.Sprintf("%s\t%s\t%d\n", prefix.String(), hop.VipAsStr, hop.Cost) + if hop.Type == "L" { + fmt.Printf("%s\t%s\tLOCAL:%s\t%d\n", hop.Type, prefix.String(), hop.VipAsStr, hop.Cost) + } else if hop.Type == "S" { + fmt.Printf("%s\t%s\t%s\t%s\n", hop.Type, prefix.String(), hop.VipAsStr, "-") + } else { + fmt.Printf("%s\t%s\t%s\t%d\n", hop.Type, prefix.String(), hop.VipAsStr, hop.Cost) + } } - return buf } func DebugNeighbors() { @@ -256,6 +336,27 @@ func DebugNeighbors() { } } +// func RemoveNeighbor(neighbor Neighbor) { +// // TODO: remove from routing table +// myRoutes := GetRoutes() +// for prefix, hop := range myRoutes { +// if hop.VipAsStr == neighbor.VipAddr.String() { +// delete(myRoutes, prefix) +// } +// } + +// // TODO: remove from myNeighbors +// myNeighbors[neighbor.VipAddr.String()] = nil + +// // TODO: close the UDP socket +// err := neighbor.SendSocket.Close() +// if err != nil { +// fmt.Println("Error closing UDP socket", err) +// } + +// } +// untested function above + func CleanUp() { fmt.Print("Cleaning up...\n") // go through the interfaces, pop thread & close the UDP FDs @@ -293,7 +394,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) 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 @@ -306,7 +407,7 @@ func SendIP(src Interface, dest Neighbor, protocolNum int, message []byte) error Protocol: protocolNum, Checksum: 0, // Should be 0 until checksum is computed Src: src.IpPrefix.Addr(), - Dst: dest.VipAddr, + Dst: netip.MustParseAddr(destIP), Options: []byte{}, } @@ -334,10 +435,25 @@ func SendIP(src Interface, dest Neighbor, protocolNum int, message []byte) error if err != nil { return err } - bytesWritten, err := dest.SendSocket.WriteToUDP(bytesToSend, listenAddr) + 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()) return nil @@ -348,7 +464,7 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error { // Read on the UDP port fmt.Println("wating to read from UDP socket") - _, sourceAddr, err := conn.ReadFromUDP(buffer) + _, _, err := conn.ReadFromUDP(buffer) if err != nil { return err } @@ -384,17 +500,94 @@ func RecvIP(conn net.UDPConn, isOpen *bool) error { // Next, get the message, which starts after the header message := buffer[headerSize:] - // Finally, print everything out - fmt.Printf("Received IP packet from %s\nHeader: %v\nChecksum: %s\nMessage: %s\n", - sourceAddr.String(), hdr, checksumState, string(message)) - // TODO: handle the message // 1) check if the TTL & checksum is valid + TTL := hdr.TTL + if TTL == 0 { + // drop the packet + return nil + } + + // check if the checksum is valid + if checksumState == "FAIL" { + // 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)...) + + // 3) check if message is for a neighbor, if so, sendIP there - // 4) check if message is for a neighbor, if so, forward to the neighbor with that VIP + 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 + } + return nil + } + } + } + fmt.Println("No neighbors, checking Routes") + // 4) check forwarding table. if so, forward to the neighbor with that VIP + + // 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 + for _, neighbor := range neighbors { + fmt.Println("for neighbor", neighbor.VipAddr.String()) + // 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 + } + } + } + // send 10.2.0.3 hello + // 5) if not, drop the packet return nil } @@ -411,3 +604,34 @@ func ValidateChecksum(b []byte, fromHeader uint16) uint16 { return checksum } + +func GetInterfaces() []*Interface { + return myInterfaces +} + +func GetNeighbors() map[string][]*Neighbor { + return myNeighbors +} + +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 |