aboutsummaryrefslogtreecommitdiff
path: root/pkg/ipstack
diff options
context:
space:
mode:
authorDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-11-02 18:57:56 -0400
committerDavid Doan <daviddoan@Davids-MacBook-Pro-70.local>2023-11-02 18:57:56 -0400
commit5d7ffd42b638f33d32c01c46f853e26a5028b552 (patch)
treeed7220178ce76a213341f14fb27c6af63e95209a /pkg/ipstack
parenta8c9b48821c85e072ca9054621928e415540b12c (diff)
milestone 1
Diffstat (limited to 'pkg/ipstack')
-rw-r--r--pkg/ipstack/ipstack.go350
1 files changed, 346 insertions, 4 deletions
diff --git a/pkg/ipstack/ipstack.go b/pkg/ipstack/ipstack.go
index fe8d743..78a6b96 100644
--- a/pkg/ipstack/ipstack.go
+++ b/pkg/ipstack/ipstack.go
@@ -20,11 +20,15 @@ import (
"github.com/google/netstack/tcpip/header"
"github.com/pkg/errors"
"iptcp/pkg/lnxconfig"
+ "iptcp/pkg/iptcp_utils"
"log"
"net"
"net/netip"
"sync"
"time"
+ "strings"
+ "math/rand"
+ // "github.com/google/netstack/tcpip/header"
)
const (
@@ -35,6 +39,7 @@ const (
SIZE_OF_RIP_ENTRY = 12
RIP_PROTOCOL = 200
TEST_PROTOCOL = 0
+ TCP_PROTOCOL = 6
SIZE_OF_RIP_HEADER = 4
MAX_TIMEOUT = 12
)
@@ -682,16 +687,20 @@ func StartRipRoutines() {
// RegisterProtocolHandler registers a protocol handler for a given protocol number
// Returns true if the protocol number is valid, false otherwise
func RegisterProtocolHandler(protocolNum int) bool {
- if protocolNum == RIP_PROTOCOL {
+ switch protocolNum {
+ case RIP_PROTOCOL:
protocolHandlers[protocolNum] = HandleRIP
go StartRipRoutines()
return true
- }
- if protocolNum == TEST_PROTOCOL {
+ case TEST_PROTOCOL:
protocolHandlers[protocolNum] = HandleTestPackets
return true
+ case TCP_PROTOCOL:
+ protocolHandlers[protocolNum] = HandleTCP
+ return true
+ default:
+ return false
}
- return false
}
// HandleRIP handles incoming RIP packets in the following way:
@@ -853,6 +862,132 @@ func HandleTestPackets(src *Interface, message []byte, hdr *ipv4header.IPv4Heade
return nil
}
+func HandleTCP(src *Interface, message []byte, hdr *ipv4header.IPv4Header) error {
+ fmt.Println("I see a TCP packet")
+ // ipHeaderSize := hdr.Len
+ tcpHeaderAndData := message
+ tcpHdr := iptcp_utils.ParseTCPHeader(tcpHeaderAndData)
+ tcpPayload := tcpHeaderAndData[tcpHdr.DataOffset:]
+ tcpChecksumFromHeader := tcpHdr.Checksum
+ tcpHdr.Checksum = 0
+ tcpComputedChecksum := iptcp_utils.ComputeTCPChecksum(&tcpHdr, hdr.Src, hdr.Dst, tcpPayload)
+
+ var tcpChecksumState string
+ if tcpComputedChecksum == tcpChecksumFromHeader {
+ tcpChecksumState = "OK"
+ } else {
+ tcpChecksumState = "FAIL"
+ }
+
+ if tcpChecksumState == "FAIL" {
+ // drop the packet
+ fmt.Println("checksum failed, dropping packet")
+ return nil
+ }
+
+ switch tcpHdr.Flags {
+ case 0x02:
+ fmt.Println("I see a SYN flag")
+ // if the SYN flag is set, then send a SYNACK
+ available := false
+ mapMutex.Lock()
+ for _, socketEntry := range VHostSocketMaps {
+ if socketEntry.LocalPort == tcpHdr.DstPort && socketEntry.LocalIP == hdr.Dst.String() && socketEntry.State == Listening{
+ // add a new socketEntry to the map
+ newEntry := &SocketEntry{
+ LocalPort: tcpHdr.DstPort,
+ RemotePort: tcpHdr.SrcPort,
+ LocalIP: hdr.Dst.String(),
+ RemoteIP: hdr.Src.String(),
+ State: SYNRECIEVED,
+ Socket: socketsMade,
+ }
+ socketsMade += 1
+ // add the entry to the map
+ VHostSocketMaps[socketsMade] = newEntry
+ available = true
+ break
+ }
+ }
+ mapMutex.Unlock()
+ if !available {
+ fmt.Println("no socket available")
+ return nil
+ }
+ // make the header
+ tcpHdr := &header.TCPFields{
+ SrcPort: tcpHdr.DstPort,
+ DstPort: tcpHdr.SrcPort,
+ SeqNum: tcpHdr.SeqNum,
+ AckNum: tcpHdr.SeqNum + 1,
+ DataOffset: 20,
+ Flags: 0x12,
+ WindowSize: MAX_WINDOW_SIZE,
+ Checksum: 0,
+ UrgentPointer: 0,
+ }
+ // make the payload
+ synAckPayload := []byte{}
+ err := SendTCP(tcpHdr, synAckPayload, hdr.Dst, hdr.Src)
+ if err != nil {
+ fmt.Println(err)
+ }
+ break
+ case 0x12:
+ fmt.Println("I see a SYNACK flag")
+ // lookup for socket entry and update its state
+ mapMutex.Lock()
+ for _, socketEntry := range VHostSocketMaps {
+ if socketEntry.LocalPort == tcpHdr.DstPort && socketEntry.LocalIP == hdr.Dst.String() && socketEntry.State == SYNSENT {
+ socketEntry.State = Established
+ break
+ }
+ }
+ mapMutex.Unlock()
+
+ // send an ACK
+ // make the header
+ tcpHdr := &header.TCPFields{
+ SrcPort: tcpHdr.DstPort,
+ DstPort: tcpHdr.SrcPort,
+ SeqNum: tcpHdr.SeqNum,
+ AckNum: tcpHdr.SeqNum + 1,
+ DataOffset: 20,
+ Flags: 0x10,
+ WindowSize: MAX_WINDOW_SIZE,
+ Checksum: 0,
+ UrgentPointer: 0,
+ }
+ // make the payload
+ ackPayload := []byte{}
+ err := SendTCP(tcpHdr, ackPayload, hdr.Dst, hdr.Src)
+ if err != nil {
+ fmt.Println(err)
+ }
+ break
+ case 0x10:
+ fmt.Println("I see an ACK flag")
+ // lookup for socket entry and update its state
+ // set synChan to true (TODO)
+
+ mapMutex.Lock()
+ for _, socketEntry := range VHostSocketMaps {
+ if socketEntry.LocalPort == tcpHdr.DstPort && socketEntry.LocalIP == hdr.Dst.String() && socketEntry.State == SYNRECIEVED {
+ socketEntry.State = Established
+ break
+ }
+ }
+ mapMutex.Unlock()
+ break
+ default:
+ fmt.Println("I see a non TCP packet")
+ break
+ }
+
+
+ return nil
+}
+
// *********************************************** HELPERS **********************************************************
// Route returns the next HOP, based on longest prefix match for a given ip
@@ -1006,3 +1141,210 @@ func CleanUp() {
time.Sleep(5 * time.Millisecond)
}
+
+// ************************************** TCP FUNCTIONS **********************************************************
+
+type ConnectionState string
+const (
+ Established ConnectionState = "ESTABLISHED"
+ Listening ConnectionState = "LISTENING"
+ Closed ConnectionState = "CLOSED"
+ SYNSENT ConnectionState = "SYNSENT"
+ SYNRECIEVED ConnectionState = "SYNRECIEVED"
+ MAX_WINDOW_SIZE = 65535
+)
+
+// VTCPListener represents a listener socket (similar to Go’s net.TCPListener)
+type VTCPListener struct {
+ LocalAddr string
+ LocalPort uint16
+ RemoteAddr string
+ RemotePort uint16
+ Socket int
+ State ConnectionState
+}
+
+// // VTCPConn represents a “normal” socket for a TCP connection between two endpoints (similar to Go’s net.TCPConn)
+type VTCPConn struct {
+ LocalAddr string
+ LocalPort uint16
+ RemoteAddr string
+ RemotePort uint16
+ Socket int
+ State ConnectionState
+ Buffer []byte
+}
+
+type SocketEntry struct {
+ Socket int
+ LocalIP string
+ LocalPort uint16
+ RemoteIP string
+ RemotePort uint16
+ State ConnectionState
+}
+
+// create a socket map to print the local and remote ip and port as well as the state of the socket
+var VHostSocketMaps = make(map[int]*SocketEntry)
+var mapMutex = &sync.Mutex{}
+var socketsMade = 0
+var startingSeqNum = rand.Uint32()
+
+// Listen Sockets
+func VListen(port uint16) (*VTCPListener, error) {
+ myIP := GetInterfaces()[0].IpPrefix.Addr()
+ listener := &VTCPListener{
+ Socket: socketsMade,
+ State: Listening,
+ LocalPort: port,
+ LocalAddr: myIP.String(),
+ }
+
+ // add the socket to the socket map
+ mapMutex.Lock()
+ VHostSocketMaps[socketsMade] = &SocketEntry{
+ Socket: socketsMade,
+ LocalIP: myIP.String(),
+ LocalPort: port,
+ RemoteIP: "0.0.0.0",
+ RemotePort: 0,
+ State: Listening,
+ }
+ mapMutex.Unlock()
+ socketsMade += 1
+ return listener, nil
+
+}
+
+func (l *VTCPListener) VAccept() (*VTCPConn, error) {
+ // synChan = make(chan bool)
+ for {
+ // wait for a SYN request
+ mapMutex.Lock()
+ for _, socketEntry := range VHostSocketMaps {
+ if socketEntry.State == Established {
+ // create a new VTCPConn
+ conn := &VTCPConn{
+ LocalAddr: socketEntry.LocalIP,
+ LocalPort: socketEntry.LocalPort,
+ RemoteAddr: socketEntry.RemoteIP,
+ RemotePort: socketEntry.RemotePort,
+ Socket: socketEntry.Socket,
+ State: Established,
+ }
+ return conn, nil
+ }
+ }
+ mapMutex.Unlock()
+
+ }
+}
+
+func GetRandomPort() uint16 {
+ const (
+ minDynamicPort = 49152
+ maxDynamicPort = 65535
+ )
+ return uint16(rand.Intn(maxDynamicPort - minDynamicPort) + minDynamicPort)
+}
+
+func VConnect(ip string, port uint16) (*VTCPConn, error) {
+ // get my ip address
+ myIP := GetInterfaces()[0].IpPrefix.Addr()
+ // get random port
+ portRand := GetRandomPort()
+
+ tcpHdr := &header.TCPFields{
+ SrcPort: portRand,
+ DstPort: port,
+ SeqNum: startingSeqNum,
+ AckNum: startingSeqNum,
+ DataOffset: 20,
+ Flags: header.TCPFlagSyn,
+ WindowSize: MAX_WINDOW_SIZE,
+ Checksum: 0,
+ UrgentPointer: 0,
+ }
+ payload := []byte{}
+ ipParsed, err := netip.ParseAddr(ip)
+ if err != nil {
+ return nil, err
+ }
+ err = SendTCP(tcpHdr, payload, myIP, ipParsed)
+ if err != nil {
+ return nil, err
+ }
+
+ conn := &VTCPConn{
+ LocalAddr: myIP.String(),
+ LocalPort: portRand,
+ RemoteAddr: ip,
+ RemotePort: port,
+ Socket: socketsMade,
+ State: Established,
+ Buffer: []byte{},
+ }
+
+ // add the socket to the socket map
+ mapMutex.Lock()
+ VHostSocketMaps[socketsMade] = &SocketEntry{
+ Socket: socketsMade,
+ LocalIP: myIP.String(),
+ LocalPort: portRand,
+ RemoteIP: ip,
+ RemotePort: port,
+ State: SYNSENT,
+ }
+ mapMutex.Unlock()
+ socketsMade += 1
+
+ return conn, nil
+}
+
+func SendTCP(tcpHdr *header.TCPFields, payload []byte, myIP netip.Addr, ipParsed netip.Addr) error {
+ checksum := iptcp_utils.ComputeTCPChecksum(tcpHdr, myIP, ipParsed, payload)
+ tcpHdr.Checksum = checksum
+
+ tcpHeaderBytes := make(header.TCP, iptcp_utils.TcpHeaderLen)
+ tcpHeaderBytes.Encode(tcpHdr)
+
+ ipPacketPayload := make([]byte, 0, len(tcpHeaderBytes)+len(payload))
+ ipPacketPayload = append(ipPacketPayload, tcpHeaderBytes...)
+ ipPacketPayload = append(ipPacketPayload, []byte(payload)...)
+
+ // lookup neighbor
+ address := ipParsed
+ hop, err := Route(address)
+ if err != nil {
+ fmt.Println(err)
+ return err
+ }
+ myAddr := hop.Interface.IpPrefix.Addr()
+
+ for _, neighbor := range GetNeighbors()[hop.Interface.Name] {
+ if neighbor.VipAddr == address ||
+ neighbor.VipAddr == hop.VIP && hop.Type == "S" {
+ bytesWritten, err := SendIP(&myAddr, neighbor, TCP_PROTOCOL, ipPacketPayload, ipParsed.String(), nil)
+ fmt.Printf("Sent %d bytes to %s\n", bytesWritten, neighbor.VipAddr.String())
+ if err != nil {
+ fmt.Println(err)
+ }
+ }
+ }
+ return nil
+}
+
+func SprintSockets() string {
+ tmp := ""
+ for _, socket := range VHostSocketMaps {
+ // remove the spaces of the local and remote ip variables
+ socket.LocalIP = strings.ReplaceAll(socket.LocalIP, " ", "")
+ socket.RemoteIP = strings.ReplaceAll(socket.RemoteIP, " ", "")
+ if socket.RemotePort == 0 {
+ tmp += fmt.Sprintf("%d\t%s\t%d\t%s\t\t%d\t%s\n", socket.Socket, socket.LocalIP, socket.LocalPort, socket.RemoteIP, socket.RemotePort, socket.State)
+ continue
+ }
+ tmp += fmt.Sprintf("%d\t%s\t%d\t%s\t%d\t%s\n", socket.Socket, socket.LocalIP, socket.LocalPort, socket.RemoteIP, socket.RemotePort, socket.State)
+ }
+ return tmp
+} \ No newline at end of file