aboutsummaryrefslogtreecommitdiff
path: root/pkg/ipstack/ipstack.go
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2023-10-09 18:05:30 -0400
committersotech117 <michael_foiani@brown.edu>2023-10-09 18:05:30 -0400
commit3932d9b5135c0f1831ed2cb714083559a251ff20 (patch)
treea17eaa94950729692d68d0f843c1fe28c6fef467 /pkg/ipstack/ipstack.go
parent1253398ac33d51559573972149384d1019c3ec56 (diff)
implement recvip and sendip, with tests to know it's working
Diffstat (limited to 'pkg/ipstack/ipstack.go')
-rw-r--r--pkg/ipstack/ipstack.go270
1 files changed, 142 insertions, 128 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go
index 5546e32..2063c67 100644
--- a/pkg/ipstack/ipstack.go
+++ b/pkg/ipstack/ipstack.go
@@ -2,8 +2,11 @@ package ipstack
import (
"fmt"
+ ipv4header "github.com/brown-csci1680/iptcp-headers"
+ "github.com/google/netstack/tcpip/header"
"github.com/pkg/errors"
"iptcp/pkg/lnxconfig"
+ "log"
"net"
"net/netip"
"time"
@@ -17,9 +20,9 @@ const (
// STRUCTS ---------------------------------------------------------------------
type Interface struct {
- Name string
- IpPrefix netip.Prefix
-
+ Name string
+ IpPrefix netip.Prefix
+ UdpAddr netip.AddrPort
RecvSocket net.UDPConn
SocketChannel chan bool
State bool
@@ -51,6 +54,7 @@ type Hop struct {
}
// GLOBAL VARIABLES (data structures) ------------------------------------------
+var myVIP netip.Addr
var myInterfaces []*Interface
var myNeighbors = make(map[string][]*Neighbor)
@@ -98,6 +102,7 @@ func Initialize(lnxFilePath string) error {
i := &Interface{
Name: iface.Name,
IpPrefix: prefix,
+ UdpAddr: iface.UDPAddr,
RecvSocket: net.UDPConn{},
SocketChannel: make(chan bool),
State: false,
@@ -137,6 +142,7 @@ func Initialize(lnxFilePath string) error {
myNeighbors[neighbor.InterfaceName] = append(myNeighbors[neighbor.InterfaceName], n)
// 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}
}
@@ -171,10 +177,13 @@ func InterfaceListenerRoutine(socket net.UDPConn, signal <-chan bool) {
if !isUp { // don't call the listeners if interface is down
continue
}
-
- fmt.Println("no activity, actively listening on ", socket.LocalAddr().String())
- // TODO: remove these training wheels, call the listener function
+ // TODO: remove these "training wheels"
time.Sleep(1 * time.Millisecond)
+ err := RecvIP(socket, &isUp)
+ if err != nil {
+ fmt.Println("Error receiving IP packet", err)
+ return
+ }
}
}()
@@ -205,126 +214,6 @@ func InterfaceDown(iface *Interface) {
iface.State = false
}
-/*
-
-func ListerToInterfaces() {
- for _, iface := range myInterfaces {
- go RecvIp(iface)
- }
-}
-func ValidateChecksum(b []byte, fromHeader uint16) uint16 {
- checksum := header.Checksum(b, fromHeader)
-
- return checksum
-}
-
-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)
- }
-
- addrString := fmt.Sprintf("%s:%s", dst, port)
- remoteAddr, err := net.ResolveUDPAddr("udp4", addrString)
- if err != nil {
- log.Panicln("Error resolving address: ", err)
- }
-
- fmt.Printf("Sending to %s:%d\n",
- remoteAddr.IP.String(), remoteAddr.Port)
-
- // Bind on the local UDP port: this sets the source port
- // and creates a conn
- conn, err := net.ListenUDP("udp4", bindLocalAddr)
- if err != nil {
- log.Panicln("Dial: ", err)
- }
-
- // Start filling in the header
- message := data[20:]
- hdr := ipv4header.IPv4Header{
- Version: data[0] >> 4,
- Len: 20, // Header length is always 20 when no IP options
- TOS: data[1],
- TotalLen: ipv4header.HeaderLen + len(message),
- ID: data[4],
- Flags: data[6] >> 5,
- FragOff: data[6] & 0x1f,
- TTL: data[8],
- Protocol: data[9],
- Checksum: 0, // Should be 0 until checksum is computed
- Src: netip.MustParseAddr(iface.addr.String()),
- Dst: netip.MustParseAddr(dst.String()),
- Options: []byte{},
- }
-
- // Assemble the header into a byte array
- headerBytes, err := hdr.Marshal()
- if err != nil {
- log.Fatalln("Error marshalling header: ", err)
- }
-
- // Compute the checksum (see below)
- // Cast back to an int, which is what the Header structure expects
- 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)...)
-
- // Send the message to the "link-layer" addr:port on UDP
- bytesWritten, err := conn.WriteToUDP(bytesToSend, remoteAddr)
- if err != nil {
- log.Panicln("Error writing to socket: ", err)
- }
- fmt.Printf("Sent %d bytes\n", bytesWritten)
-}
-
-func ComputeChecksum(b []byte) uint16 {
- checksum := header.Checksum(b, 0)
- checksumInv := checksum ^ 0xffff
-
- return checksumInv
-}
-
-func ForwardIP(data []byte) error {
-}
-
-func AddRecvHandler(protocolNum uint8, callbackFunc HandlerFunc) error {
- if protocolHandlers[protocolNum] != nil {
- fmt.Printf("Warning: Handler for protocol %d already exists", protocolNum)
- }
- protocolHandlers[protocolNum] = callbackFunc
- return nil
-}
-
-func RemoveRecvHandler(protocolNum uint8) error {
- // consider error
- if protocolHandlers[protocolNum] == nil {
- return errors.Errorf("No handler for protocol %d", protocolNum)
- }
- delete(protocolHandlers, protocolNum)
- return nil
-}
-
-// func routeRip(data []byte) (error) {
-// // deconstruct packet
-// newRIPMessage := RIPMessage{}
-// newRIPMessage.command = data[0]
-// newRIPMessage.numEntries = data[1]
-// newRIPMessage.entries = make([]RIPEntry, newRIPMessage.numEntries)
-// }
-
-func GetNeighbors() []netip.Addr {
- return myNeighbors
-}
-*/
-
func GetInterfaceByName(ifaceName string) (*Interface, error) {
for _, iface := range myInterfaces {
if iface.Name == ifaceName {
@@ -335,6 +224,14 @@ func GetInterfaceByName(ifaceName string) (*Interface, error) {
return nil, errors.Errorf("No interface with name %s", ifaceName)
}
+func GetNeighborsToInterface(ifaceName string) ([]*Neighbor, error) {
+ if neighbors, ok := myNeighbors[ifaceName]; ok {
+ return neighbors, nil
+ }
+
+ return nil, errors.Errorf("No interface with name %s", ifaceName)
+}
+
func SprintInterfaces() string {
buf := ""
for _, iface := range myInterfaces {
@@ -376,7 +273,10 @@ func CleanUp() {
if iface.SocketChannel != nil {
close(iface.SocketChannel)
}
- iface.RecvSocket.Close()
+ err := iface.RecvSocket.Close()
+ if err != nil {
+ continue
+ }
}
// go through the neighbors, pop thread & close the UDP FDs
@@ -385,7 +285,10 @@ func CleanUp() {
if n.SocketChannel != nil {
close(n.SocketChannel)
}
- n.SendSocket.Close()
+ err := n.SendSocket.Close()
+ if err != nil {
+ continue
+ }
}
}
@@ -398,3 +301,114 @@ func CleanUp() {
time.Sleep(5 * time.Millisecond)
}
+
+func SendIP(src Interface, dest Neighbor, protocolNum int, message []byte) error {
+ hdr := ipv4header.IPv4Header{
+ Version: 4,
+ Len: 20, // Header length is always 20 when no IP options
+ TOS: 0,
+ TotalLen: ipv4header.HeaderLen + len(message),
+ ID: 0,
+ Flags: 0,
+ FragOff: 0,
+ TTL: 32,
+ Protocol: protocolNum,
+ Checksum: 0, // Should be 0 until checksum is computed
+ Src: src.IpPrefix.Addr(),
+ Dst: dest.VipAddr,
+ Options: []byte{},
+ }
+
+ // Assemble the header into a byte array
+ headerBytes, err := hdr.Marshal()
+ if err != nil {
+ return err
+ }
+
+ // Compute the checksum (see below)
+ // Cast back to an int, which is what the Header structure expects
+ 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)...)
+
+ // Send the message to the "link-layer" addr:port on UDP
+ listenAddr, err := net.ResolveUDPAddr("udp4", dest.UdpAddr.String())
+ if err != nil {
+ return err
+ }
+ bytesWritten, err := dest.SendSocket.WriteToUDP(bytesToSend, listenAddr)
+ if err != nil {
+ return err
+ }
+ fmt.Printf("Sent %d bytes to %s\n", bytesWritten, listenAddr.String())
+
+ return nil
+}
+
+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")
+ _, sourceAddr, err := conn.ReadFromUDP(buffer)
+ if err != nil {
+ return err
+ }
+
+ if !*isOpen {
+ return errors.New("interface is down")
+ }
+
+ // Marshal the received byte array into a UDP header
+ // NOTE: This does not validate the checksum or check any fields
+ // (You'll need to do this part yourself)
+ hdr, err := ipv4header.ParseHeader(buffer)
+ if err != nil {
+ // What should you if the message fails to parse?
+ // Your node should not crash or exit when you get a bad message.
+ // Instead, simply drop the packet and return to processing.
+ fmt.Println("Error parsing header", err)
+ return err
+ }
+
+ headerSize := hdr.Len
+ headerBytes := buffer[:headerSize]
+ checksumFromHeader := uint16(hdr.Checksum)
+ computedChecksum := ValidateChecksum(headerBytes, checksumFromHeader)
+
+ var checksumState string
+ if computedChecksum == checksumFromHeader {
+ checksumState = "OK"
+ } else {
+ checksumState = "FAIL"
+ }
+
+ // 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))
+
+ return nil
+}
+
+func ComputeChecksum(b []byte) uint16 {
+ checksum := header.Checksum(b, 0)
+ checksumInv := checksum ^ 0xffff
+
+ return checksumInv
+}
+
+func ValidateChecksum(b []byte, fromHeader uint16) uint16 {
+ checksum := header.Checksum(b, fromHeader)
+
+ return checksum
+}