-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsdnswitch.cpp
More file actions
215 lines (183 loc) · 6.04 KB
/
Copy pathsdnswitch.cpp
File metadata and controls
215 lines (183 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// sdnswitch.cpp
// Phohanh Tran, CSS 432, Assignment 3
// Date of Last Modification: 02/28/2026
// Purpose: SDN switch, implements logic to parse packet header values,
// if certain values match, this triggers specific actions
#include <iostream>
#include <sstream>
#include <cstring>
#include "sdnswitch.h"
using namespace std;
// macToUint64: Converts 6-byte MAC address to uint64_t
// Preconditions: MAC must contain 6 valid bytes
// Postconditions: Returns 64-bit integer representation
static uint64_t macToUint64(uint8_t mac[6])
{
uint64_t value = 0;
for (int i = 0; i < 6; i++)
value = (value << 8) | mac[i];
return value;
}
// SDNSwitch: Constructor initializes rule table and forwarding tables
// Preconditions: None
// Postconditions: Match+Action rules and forwarding tables are initialized
SDNSwitch::SDNSwitch()
{
initializeTables();
// Drop TCP packets to port 22 AND destination IP last byte = 5
MatchActionRule firewallRule;
firewallRule.nextHeader = 6; // TCP
firewallRule.dstPort = 22;
firewallRule.dstIPLastByte = 5;
firewallRule.action = ActionType::DROP;
rules.push_back(firewallRule);
// NAT for TCP
MatchActionRule natTCP;
natTCP.dstMac = 0xFFFFFFFFFFFF; // Ethernet
natTCP.srcIPLastByte = 10; // IPv6
natTCP.nextHeader = 6; // TCP transport layer
natTCP.action = ActionType::NAT;
natTCP.newSrcPort = 50000;
rules.push_back(natTCP);
// NAT for UDP
MatchActionRule natUDP;
natUDP.dstMac = 0xFFFFFFFFFFFF; // Ethernet
natUDP.srcIPLastByte = 10; // IPv6
natUDP.nextHeader = 17; // UDP transport layer
natUDP.action = ActionType::NAT;
natUDP.newSrcPort = 50000;
rules.push_back(natUDP);
// Route packets if destination IP last byte = 2
// ROUTE for TCP
MatchActionRule routeTCP;
routeTCP.dstMac = 0xFFFFFFFFFFFF; // Ethernet
routeTCP.dstIPLastByte = 2; // IPv6
routeTCP.nextHeader = 6; // TCP transport layer
routeTCP.action = ActionType::ROUTE;
routeTCP.outputPort = 2;
rules.push_back(routeTCP);
// ROUTE for UDP
MatchActionRule routeUDP;
routeUDP.dstMac = 0xFFFFFFFFFFFF; // Ethernet
routeUDP.dstIPLastByte = 2; // IPv6
routeUDP.nextHeader = 17; // UDP transport layer
routeUDP.action = ActionType::ROUTE;
routeUDP.outputPort = 2;
rules.push_back(routeUDP);
}
// initializeTables: Initializes default MAC table
// Preconditions: None
// Postconditions: macTable populated
void SDNSwitch::initializeTables()
{
// Broadcast MAC → Port 1
macTable[0xFFFFFFFFFFFF] = 1;
}
// matchRule: Checks if packet header fields match rule criteria
// Preconditions: Valid packet and rule
// Postconditions: Returns true if all rule conditions match
bool SDNSwitch::matchRule(Packet &pkt, MatchActionRule &rule)
{
uint64_t dstMac = macToUint64(pkt.eth.destMAC);
uint64_t srcMac = macToUint64(pkt.eth.srcMAC);
if (rule.dstMac != 0 && rule.dstMac != dstMac)
return false;
if (rule.srcMac != 0 && rule.srcMac != srcMac)
return false;
if (rule.nextHeader != 0 && rule.nextHeader != pkt.ip.nextHeader)
return false;
// IP last-byte matching
if (rule.srcIPLastByte != 0 &&
pkt.ip.srcIP[15] != rule.srcIPLastByte)
return false;
if (rule.dstIPLastByte != 0 &&
pkt.ip.destIP[15] != rule.dstIPLastByte)
return false;
// Port matching
if (pkt.isTCP)
{
if (rule.dstPort != 0 && rule.dstPort != pkt.tcp.destPort)
return false;
if (rule.srcPort != 0 && rule.srcPort != pkt.tcp.srcPort)
return false;
}
else
{
if (rule.dstPort != 0 && rule.dstPort != pkt.udp.destPort)
return false;
if (rule.srcPort != 0 && rule.srcPort != pkt.udp.srcPort)
return false;
}
return true;
}
// executeAction: Executes matched rule action
// Preconditions: Packet matches rule
// Postconditions: Packet dropped, routed, rewritten, or forwarded
void SDNSwitch::executeAction(Packet &pkt, MatchActionRule &rule)
{
switch (rule.action)
{
case ActionType::DROP:
cout << "ACTION: Packet Dropped (Firewall Rule Matched)\n";
return;
case ActionType::ROUTE:
pkt.ip.decrementHopLimit();
cout << "ACTION: Packet with Destination " << rule.dstMac << " Routed to Port "
<< rule.outputPort << endl;
return;
case ActionType::NAT:
cout << "ACTION: NAT Applied\n";
// Rewrite source IP last byte to 99
pkt.ip.srcIP[15] = 99;
if (pkt.isTCP)
{
pkt.tcp.srcPort = rule.newSrcPort;
cout << " New TCP Src Port: "
<< pkt.tcp.srcPort << endl;
}
else
{
pkt.udp.srcPort = rule.newSrcPort;
cout << " New UDP Src Port: "
<< pkt.udp.srcPort << endl;
}
return;
case ActionType::FORWARD:
cout << "ACTION: Packet with Destination " << rule.dstMac << " Forwarded to Port "
<< rule.outputPort << endl;
return;
}
}
// processPacket: Checks packet header values for match+action rules
// Preconditions: Valid packet
// Postconditions: Packet is dropped, routed, rewritten,
// switched, or forwarded to default port
void SDNSwitch::processPacket(Packet &pkt)
{
cout << "\n--- SDN Switch Processing ---\n";
// Hop limit safety check
if (pkt.ip.hopLimit == 0)
{
cout << "ACTION: Packet Dropped (Hop Limit Expired)\n";
return;
}
// Match+Action table (FIRST MATCH WINS)
for (auto &rule : rules)
{
if (matchRule(pkt, rule))
{
executeAction(pkt, rule);
return;
}
}
// L2 Switch behavior (MAC table lookup)
uint64_t dstMac = macToUint64(pkt.eth.destMAC);
if (macTable.find(dstMac) != macTable.end())
{
cout << "ACTION: Switched to Port "
<< macTable[dstMac] << endl;
return;
}
// Default behavior
cout << "ACTION: Forwarded to Default Port 0\n";
}