aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-10-18 00:14:46 -0400
committerDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-10-18 00:14:46 -0400
commit1e1f56b0dfe1b95d181ff40eeac0cc4260c937fb (patch)
tree64033021fe0943f4862a4ff751c92fcc721d3907 /pkg
parentdb0a9f0a4605d85ba4e535ba0ab590776cc4ba0a (diff)
add REPL functionality
Diffstat (limited to 'pkg')
-rw-r--r--pkg/ipstack/ipstack.go314
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