aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-10-19 15:59:49 -0400
committerDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-10-19 15:59:49 -0400
commit1e66c42543ddbd610968a73b30f8646f289da07a (patch)
tree7cc595addd16a9e8c007752bfc017a5aac68c0c5
parent1e1f56b0dfe1b95d181ff40eeac0cc4260c937fb (diff)
RIP
-rw-r--r--cmd/vhost/main.go15
-rw-r--r--cmd/vrouter/main.go59
-rw-r--r--pkg/ipstack/ipstack.go322
-rwxr-xr-xvhostbin3080475 -> 3080999 bytes
-rwxr-xr-xvrouterbin3080644 -> 3087867 bytes
5 files changed, 281 insertions, 115 deletions
diff --git a/cmd/vhost/main.go b/cmd/vhost/main.go
index 27e073f..2ecbfa7 100644
--- a/cmd/vhost/main.go
+++ b/cmd/vhost/main.go
@@ -65,11 +65,20 @@ func main() {
fmt.Println(err)
continue
}
- ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ err = ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ continue
+ }
+ continue
+ }
+ err = ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ continue
}
- ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
}
- }
+ }
if len(line) > 2 {
if line[:2] == "up" {
// get interface name
diff --git a/cmd/vrouter/main.go b/cmd/vrouter/main.go
index abd0fc0..89f6e5d 100644
--- a/cmd/vrouter/main.go
+++ b/cmd/vrouter/main.go
@@ -10,25 +10,25 @@ import (
)
-func SendUpdates() {
- myInterfaces := ipstack.GetInterfaces()
- myNeighbors := ipstack.GetNeighbors()
- for _, iface := range myInterfaces {
- // send RIP updates to all neighbors
- for _, _ = range myNeighbors {
- // iface.udp.Write(neighbor, data)
- // iface.RecvSocket.Write(neighbor, data)
- // wait for response for 12 seconds
- response := make([]byte, 512)
- iface.RecvSocket.Read(response)
- time.Sleep(12 * time.Second)
- if len(response) == 0 {
- // ipstack.RemoveNeighbor(neighbor)
- }
- }
- }
- time.Sleep(5 * time.Second)
-}
+// func SendUpdates() {
+// myInterfaces := ipstack.GetInterfaces()
+// myNeighbors := ipstack.GetNeighbors()
+// for _, iface := range myInterfaces {
+// // send RIP updates to all neighbors
+// for _, _ = range myNeighbors {
+// // iface.udp.Write(neighbor, data)
+// // iface.RecvSocket.Write(neighbor, data)
+// // wait for response for 12 seconds
+// response := make([]byte, 512)
+// iface.RecvSocket.Read(response)
+// time.Sleep(12 * time.Second)
+// if len(response) == 0 {
+// // ipstack.RemoveNeighbor(neighbor)
+// }
+// }
+// }
+// time.Sleep(5 * time.Second)
+// }
func main() {
if len(os.Args) != 2 {
@@ -44,8 +44,14 @@ func main() {
// myNeighbors := ipstack.GetNeighbors()
// myRoutes := ipstack.GetRoutes()
- go SendUpdates()
+ go func() {
+ for {
+ ipstack.SendUpdates()
+ time.Sleep(5 * time.Second)
+ }
+ }()
+ go ipstack.CheckAndUpdateRoutingTable()
scanner := bufio.NewScanner(os.Stdin)
@@ -90,9 +96,18 @@ func main() {
fmt.Println(err)
continue
}
- ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ err = ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ continue
+ }
+ continue
+ }
+ err = ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
+ if err != nil {
+ fmt.Println(err)
+ continue
}
- ipstack.SendIP(ipstack.GetMyVIP(), iface, 0, messageToSendBytes, ipAddr)
}
}
if len(line) > 2 {
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
diff --git a/vhost b/vhost
index 95cf628..4638046 100755
--- a/vhost
+++ b/vhost
Binary files differ
diff --git a/vrouter b/vrouter
index 0b2be65..8a24bec 100755
--- a/vrouter
+++ b/vrouter
Binary files differ