From 077d576becae10b35b84782d4070fbf2f5c0b7c8 Mon Sep 17 00:00:00 2001 From: sotech117 Date: Mon, 9 Oct 2023 06:00:08 +0000 Subject: good progress, fixing almost all of the red. in the process of ensuring the data structures are initialized correctly. --- cmd/example/main.go | 5 +- doc-example/binaries.example.json | 17 ++++ doc-example/nodes.json | 7 ++ pkg/ipstack/ipstack.go | 193 ++++++++++++++++++++++++-------------- pkg/ipstack/ipstack_test.go | 20 ++++ pkg/lnxconfig/lnxconfig.go | 11 --- pkg/routingtable/routingtable.go | 51 +++++----- 7 files changed, 199 insertions(+), 105 deletions(-) create mode 100644 doc-example/binaries.example.json create mode 100644 doc-example/nodes.json create mode 100644 pkg/ipstack/ipstack_test.go diff --git a/cmd/example/main.go b/cmd/example/main.go index 5b6ae61..383e490 100644 --- a/cmd/example/main.go +++ b/cmd/example/main.go @@ -2,7 +2,7 @@ package main import ( "fmt" - "iptcp-jailpt2/pkg/lnxconfig" + "iptcp/pkg/lnxconfig" "net/netip" "os" ) @@ -24,5 +24,8 @@ func main() { for _, iface := range lnxConfig.Interfaces { prefixForm := netip.PrefixFrom(iface.AssignedIP, iface.AssignedPrefix.Bits()) fmt.Printf("%s has IP %s\n", iface.Name, prefixForm.String()) + + fmt.Printf(iface.UDPAddr.String() + "\n") + fmt.Printf(iface.AssignedIP.String() + "\n") } } diff --git a/doc-example/binaries.example.json b/doc-example/binaries.example.json new file mode 100644 index 0000000..b6ff6d9 --- /dev/null +++ b/doc-example/binaries.example.json @@ -0,0 +1,17 @@ +{ + "h1": { + "binary_path": "./vhost" + }, + "h2": { + "binary_path": "./vhost" + }, + "h3": { + "binary_path": "./vhost" + }, + "r1": { + "binary_path": "./vrouter" + }, + "r2": { + "binary_path": "./vrouter" + } +} \ No newline at end of file diff --git a/doc-example/nodes.json b/doc-example/nodes.json new file mode 100644 index 0000000..7b91355 --- /dev/null +++ b/doc-example/nodes.json @@ -0,0 +1,7 @@ +{ + "h1": "host", + "h2": "host", + "h3": "host", + "r1": "router", + "r2": "router" +} \ No newline at end of file diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go index 770fd17..abaa09f 100644 --- a/pkg/ipstack/ipstack.go +++ b/pkg/ipstack/ipstack.go @@ -2,102 +2,147 @@ package ipstack import ( "fmt" - ipv4header "github.com/brown-csci1680/iptcp-headers" - "github.com/google/netstack/tcpip/header" "github.com/pkg/errors" - "../../pkg/lnxconfig" - "log" + "iptcp/pkg/lnxconfig" "net" "net/netip" - "os" ) const ( - MAX_IP_PACKET_SIZE = 1400 + MAX_IP_PACKET_SIZE = 1400 + LOCAL_COST uint32 = 4294967295 // 2^32 - 1 + STATIC_COST uint32 = 1 ) +// STRUCTS --------------------------------------------------------------------- type Interface struct { - Name string - AssignedIP netip.Addr - AssignedPrefix netip.Prefix + Name string + IpAddress netip.Addr + IpPrefix netip.Prefix - UDPAddr netip.AddrPort - State bool - neighbors map[netip.AddrPort]netip.AddrPort + RecvSocket net.Conn + SocketChannel chan<- bool + State bool } -// type Host struct { -// Interface Interface -// Neighbors []Neighbor -// } - -// type Router struct { -// Interfaces []Interface -// Neighbors []Neighbor -// RIPNeighbors []Neighbor -// } +type Neighbor struct { + VipAddr netip.Addr + UdpAddr netip.AddrPort - -type Neighbor struct{ - DestAddr netip.Addr - UDPAddr netip.AddrPort - - InterfaceName string + SendSocket net.Conn + SocketChannel chan<- bool } type RIPMessage struct { - command uint8_t; - numEntries uint8_t; - entries []RIPEntry; + command uint8 + numEntries uint8 + entries []RIPEntry } type RIPEntry struct { - addr netip.Addr; - cost uint16_t; - mask netip.Prefix; + addr netip.Addr + cost uint32 + mask netip.Prefix } -myInterfaces := make([]Interface); -myNeighbors := make(map[string]Neighbor) -myRIPNeighbors := make(map[string]Neighbor) -protocolHandlers := make(map[uint16]HandlerFunc) -// routingTable := make(map[Address]Routing) +type Hop struct { + Cost uint32 + VipAsStr string +} -func Initialize(config IpConfig) (error) { - if len(os.Args) != 2 { - fmt.Printf("Usage: %s \n", os.Args[0]) - os.Exit(1) +// GLOBAL VARIABLES (data structures) ------------------------------------------ +var myInterfaces []Interface +var myNeighbors = make(map[string]Neighbor) + +// var myRIPNeighbors = make(map[string]Neighbor) +type HandlerFunc func(int, string, *[]byte) error + +var protocolHandlers = make(map[uint16]HandlerFunc) + +// var routingTable = routingtable.New() +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.Conn) error { + listenString := UdpAddr.String() + listenAddr, err := net.ResolveUDPAddr("udp4", listenString) + if err != nil { + return errors.WithMessage(err, "Error resolving address->\t"+listenString) } - fileName := os.Args[1] + tmpConn, err := net.ListenUDP("udp4", listenAddr) + if err != nil { + return errors.WithMessage(err, "Could not bind to UDP port->\t"+listenString) + } + *conn = tmpConn + + return nil +} + +func Initialize(lnxFilePath string) error { + //if len(os.Args) != 2 { + // fmt.Printf("Usage: %s \n", os.Args[0]) + // os.Exit(1) + //} + //lnxFilePath := os.Args[1] // Parse the file - lnxConfig, err := lnxconfig.ParseConfig(fileName) + lnxConfig, err := lnxconfig.ParseConfig(lnxFilePath) if err != nil { - panic(err) + return errors.WithMessage(err, "Error parsing config file->\t"+lnxFilePath) } - // populate routing table??? + // 1) initialize the interfaces on this node here and into the routing table for _, iface := range lnxConfig.Interfaces { - myInterfaces = append(myInterfaces, Interface{iface.Name, iface.AssignedIP, iface.AssignedPrefix, iface.UDPAddr, 0}) + i := &Interface{ + Name: iface.Name, + IpAddress: iface.AssignedIP, + IpPrefix: iface.AssignedPrefix, + RecvSocket: nil, + SocketChannel: nil, + State: false, + } + err := createUDPConn(iface.UDPAddr, &i.RecvSocket) + if err != nil { + return errors.WithMessage(err, "Error creating UDP socket for interface->\t"+iface.Name) + } + myInterfaces = append(myInterfaces, *i) + + // add to routing table + ifacePrefix := netip.PrefixFrom(iface.AssignedIP, iface.AssignedPrefix.Bits()) + routingTable[ifacePrefix] = Hop{STATIC_COST, iface.Name} } + // 2) initialize the neighbors connected to the node for _, neighbor := range lnxConfig.Neighbors { - myNeighbors[neighbor.DestAddr.String()] = Neighbor{neighbor.DestAddr, neighbor.UDPAddr, neighbor.InterfaceName} - } + n := &Neighbor{ + VipAddr: neighbor.DestAddr, + UdpAddr: neighbor.UDPAddr, + SendSocket: nil, + } + err := createUDPConn(neighbor.UDPAddr, &n.SendSocket) + if err != nil { + return errors.WithMessage(err, "Error creating UDP socket for neighbor->\t"+neighbor.DestAddr.String()) + } + // TODO: make a hash map + myNeighbors[neighbor.InterfaceName] = *n - // add RIP neighbors - for _, neighbor := range lnxConfig.RipNeighbors { - myRIPNeighbors[neighbor.DestAddr.String()] = Neighbor{neighbor.DestAddr, neighbor.UDPAddr, neighbor.InterfaceName} + // add to routing table + neighborPrefix := netip.PrefixFrom(neighbor.DestAddr, 24) + routingTable[neighborPrefix] = Hop{LOCAL_COST, neighbor.InterfaceName} } + + return nil } +/* + func ListerToInterfaces() { for _, iface := range myInterfaces { go RecvIp(iface) } } -func RecvIp(iface Interface) (error) { +func RecvIp(iface Interface) error { for { buffer := make([]byte, MAX_IP_PACKET_SIZE) _, sourceAddr, err := iface.udp.ReadFrom(buffer) @@ -125,7 +170,7 @@ func RecvIp(iface Interface) (error) { checksumState = "FAIL" continue } - + // check ttl ttl := data[8] if ttl == 0 { @@ -133,7 +178,6 @@ func RecvIp(iface Interface) (error) { continue } - destAddr := netip.AddrFrom(data[16:20]) protocolNum := data[9] @@ -174,7 +218,7 @@ func ValidateChecksum(b []byte, fromHeader uint16) uint16 { return checksum } -func SendIp(dst netip.Addr, port uint16, protocolNum uint16, data []byte, iface Interface) (error) { +func SendIp(dst netip.Addr, port uint16, protocolNum uint16, data []byte, iface Interface) error { bindLocalAddr, err := net.ResolveUDPAddr("udp4", iface.UDPAddr.String()) if err != nil { log.Panicln("Error resolving address: ", err) @@ -248,15 +292,10 @@ func ComputeChecksum(b []byte) uint16 { return checksumInv } -func ForwardIP(data []byte) (error) { -} - -type HandlerFunc = func help(*Packet, []interface{}) (error) { - - // do smth with packet +func ForwardIP(data []byte) error { } -func AddRecvHandler(protocolNum uint8, callbackFunc HandlerFunc) (error) { +func AddRecvHandler(protocolNum uint8, callbackFunc HandlerFunc) error { if protocolHandlers[protocolNum] != nil { fmt.Printf("Warning: Handler for protocol %d already exists", protocolNum) } @@ -264,7 +303,7 @@ func AddRecvHandler(protocolNum uint8, callbackFunc HandlerFunc) (error) { return nil } -func RemoveRecvHandler(protocolNum uint8) (error) { +func RemoveRecvHandler(protocolNum uint8) error { // consider error if protocolHandlers[protocolNum] == nil { return errors.Errorf("No handler for protocol %d", protocolNum) @@ -281,18 +320,28 @@ func RemoveRecvHandler(protocolNum uint8) (error) { // newRIPMessage.entries = make([]RIPEntry, newRIPMessage.numEntries) // } -func PrintNeighbors() { - for _, iface := range myNeighbors { - fmt.Printf("%s\n", iface.addr.String()) - } +func GetNeighbors() []netip.Addr { + return myNeighbors } +*/ func PrintInterfaces() { for _, iface := range myInterfaces { - fmt.Printf("%s\n", iface.addr.String()) + fmt.Printf("%s\t%s\t%t\n", iface.Name, iface.IpPrefix.String(), iface.State) } } -func GetNeighbors() ([]netip.Addr) { - return myNeighbors + +func PrintNeighbors() { + for ifaceName, neighbor := range myNeighbors { + fmt.Printf("%s\t%s\t%s\n", ifaceName, neighbor.IpAddress.String(), neighbor.UdpAddr.String()) + } } +func SprintRoutingTable() string { + message := "" + for prefix, hop := range routingTable { + message += fmt.Sprintf("%s\t%s\t%d\n", prefix.String(), hop.VipAsStr, hop.Cost) + } + + return message +} diff --git a/pkg/ipstack/ipstack_test.go b/pkg/ipstack/ipstack_test.go new file mode 100644 index 0000000..5530b9d --- /dev/null +++ b/pkg/ipstack/ipstack_test.go @@ -0,0 +1,20 @@ +package ipstack + +import ( + "fmt" + "testing" +) + +func TestInitialize(t *testing.T) { + lnxFilePath := "../../doc-example/r2.lnx" + err := Initialize(lnxFilePath) + if err != nil { + t.Error(err) + } + fmt.Println("TestInitialize successful") + PrintInterfaces() + fmt.Println("Interfaces^^") + PrintNeighbors() + fmt.Println("Neighbors^^") + fmt.Println(SprintRoutingTable()) +} diff --git a/pkg/lnxconfig/lnxconfig.go b/pkg/lnxconfig/lnxconfig.go index d0699f9..8e43613 100644 --- a/pkg/lnxconfig/lnxconfig.go +++ b/pkg/lnxconfig/lnxconfig.go @@ -17,17 +17,6 @@ const ( RoutingTypeRIP RoutingMode = 2 ) -/* - * NOTE: These data structures only represent structure of a - * configuration file. In your implementation, you will still need to - * build your own data structures that store relevant information - * about your links, interfaces, etc. at runtime. - * - * These structs only represent the things in the config file--you - * will probably only parse these at startup in order to set up your own - * data structures. - * - */ type IPConfig struct { Interfaces []InterfaceConfig Neighbors []NeighborConfig diff --git a/pkg/routingtable/routingtable.go b/pkg/routingtable/routingtable.go index 7f7e2b2..90b64ae 100644 --- a/pkg/routingtable/routingtable.go +++ b/pkg/routingtable/routingtable.go @@ -7,17 +7,26 @@ import ( ) type Address struct { - addr netip.Addr - prefix netip.Prefix + Addr netip.Addr + Prefix netip.Prefix } -type Route struct { - dest Address - cost uint32 - mask netip.Prefix +type Hop struct { + Cost uint32 + VipAsStr string } -var table map[Address]Route +type RoutingTable map[Address]Hop + +const ( + STATIC_COST uint32 = 4294967295 // 2^32 - 1 +) + +// TODO: consider making this take in arguments, such as a config file +func New() *RoutingTable { + var table = make(RoutingTable) + return &table +} //func Initialize(config lnxconfig.IPConfig) error { // if len(os.Args) != 2 { @@ -42,39 +51,39 @@ var table map[Address]Route // //} -func AddRoute(dest Address, cost uint32, mask netip.Prefix) error { - if _, ok := table[dest]; ok { +func AddRoute(srcAddr Address, cost uint32, addrAsStr string, tableReference *RoutingTable) error { + if _, ok := (*tableReference)[srcAddr]; ok { return errors.New("Route already exists") } - table[dest] = Route{dest, cost, mask} + (*tableReference)[srcAddr] = Hop{cost, addrAsStr} return nil } -func RemoveRoute(dest Address) error { - if _, ok := table[dest]; !ok { +func RemoveRoute(dest Address, table *RoutingTable) error { + if _, ok := (*table)[dest]; !ok { return errors.New("Route doesn't exist") } - delete(table, dest) + delete(*table, dest) return nil } // TODO: implement this with most specific prefix matching -func GetRoute(dest Address) (Route, error) { +func Route(dest Address, table *RoutingTable) (Hop, error) { // get the most specific route - for key, value := range table { - if key.prefix.Contains(dest.addr) { - return value, nil + for address, route := range *table { + if address.Prefix.Contains(dest.Addr) { + return route, nil } } - return Route{}, errors.New("Route doesn't exist") + return Hop{}, errors.New("Route doesn't exist") } -func SprintRoutingTable() string { +func SprintRoutingTable(table *RoutingTable) string { message := "" - for address, route := range table { - message += fmt.Sprintf("%s/%d\t%d\n", address.addr, address.prefix, route.cost) + for address, route := range *table { + message += fmt.Sprintf("%s/%d\t%d\n", address.Addr, address.Prefix, route.Cost) } return message -- cgit v1.2.3-70-g09d2