blob: d9b26121690df67b26cb3121f5b7bc719cb4c936 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001package net.floodlightcontroller.firewall;
2
3import org.openflow.protocol.OFMatch;
4
5import net.floodlightcontroller.packet.Ethernet;
6import net.floodlightcontroller.packet.IPacket;
7import net.floodlightcontroller.packet.IPv4;
8import net.floodlightcontroller.packet.TCP;
9import net.floodlightcontroller.packet.UDP;
10
11public class FirewallRule implements Comparable<FirewallRule> {
12 public int ruleid;
13
14 public long dpid;
15 public short in_port;
16 public long dl_src;
17 public long dl_dst;
18 public short dl_type;
19 public int nw_src_prefix;
20 public int nw_src_maskbits;
21 public int nw_dst_prefix;
22 public int nw_dst_maskbits;
23 public short nw_proto;
24 public short tp_src;
25 public short tp_dst;
26
27 public boolean wildcard_dpid;
28 public boolean wildcard_in_port;
29 public boolean wildcard_dl_src;
30 public boolean wildcard_dl_dst;
31 public boolean wildcard_dl_type;
32 public boolean wildcard_nw_src;
33 public boolean wildcard_nw_dst;
34 public boolean wildcard_nw_proto;
35 public boolean wildcard_tp_src;
36 public boolean wildcard_tp_dst;
37
38 public int priority = 0;
39
40 public FirewallAction action;
41
42 public enum FirewallAction {
43 /*
44 * DENY: Deny rule
45 * ALLOW: Allow rule
46 */
47 DENY, ALLOW
48 }
49
50 public FirewallRule() {
51 this.in_port = 0;
52 this.dl_src = 0;
53 this.nw_src_prefix = 0;
54 this.nw_src_maskbits = 0;
55 this.dl_dst = 0;
56 this.nw_proto = 0;
57 this.tp_src = 0;
58 this.tp_dst = 0;
59 this.dl_dst = 0;
60 this.nw_dst_prefix = 0;
61 this.nw_dst_maskbits = 0;
62 this.dpid = -1;
63 this.wildcard_dpid = true;
64 this.wildcard_in_port = true;
65 this.wildcard_dl_src = true;
66 this.wildcard_dl_dst = true;
67 this.wildcard_dl_type = true;
68 this.wildcard_nw_src = true;
69 this.wildcard_nw_dst = true;
70 this.wildcard_nw_proto = true;
71 this.wildcard_tp_src = true;
72 this.wildcard_tp_dst = true;
73 this.priority = 0;
74 this.action = FirewallAction.ALLOW;
75 this.ruleid = 0;
76 }
77
78 /**
79 * Generates a unique ID for the instance
80 *
81 * @return int representing the unique id
82 */
83 public int genID() {
84 int uid = this.hashCode();
85 if (uid < 0) {
86 uid = Math.abs(uid);
87 uid = uid * 15551;
88 }
89 return uid;
90 }
91
92 /**
93 * Comparison method for Collections.sort method
94 *
95 * @param rule
96 * the rule to compare with
97 * @return number representing the result of comparison 0 if equal negative
98 * if less than 'rule' greater than zero if greater priority rule
99 * than 'rule'
100 */
101 @Override
102 public int compareTo(FirewallRule rule) {
103 return this.priority - rule.priority;
104 }
105
106 /**
107 * Determines if this instance matches an existing rule instance
108 *
109 * @param r
110 * : the FirewallRule instance to compare with
111 * @return boolean: true if a match is found
112 **/
113 public boolean isSameAs(FirewallRule r) {
114 if (this.action != r.action
115 || this.wildcard_dl_type != r.wildcard_dl_type
116 || (this.wildcard_dl_type == false && this.dl_type == r.dl_type)
117 || this.wildcard_tp_src != r.wildcard_tp_src
118 || (this.wildcard_tp_src == false && this.tp_src != r.tp_src)
119 || this.wildcard_tp_dst != r.wildcard_tp_dst
120 || (this.wildcard_tp_dst == false &&this.tp_dst != r.tp_dst)
121 || this.wildcard_dpid != r.wildcard_dpid
122 || (this.wildcard_dpid == false && this.dpid != r.dpid)
123 || this.wildcard_in_port != r.wildcard_in_port
124 || (this.wildcard_in_port == false && this.in_port != r.in_port)
125 || this.wildcard_nw_src != r.wildcard_nw_src
126 || (this.wildcard_nw_src == false && (this.nw_src_prefix != r.nw_src_prefix || this.nw_src_maskbits != r.nw_src_maskbits))
127 || this.wildcard_dl_src != r.wildcard_dl_src
128 || (this.wildcard_dl_src == false && this.dl_src != r.dl_src)
129 || this.wildcard_nw_proto != r.wildcard_nw_proto
130 || (this.wildcard_nw_proto == false && this.nw_proto != r.nw_proto)
131 || this.wildcard_nw_dst != r.wildcard_nw_dst
132 || (this.wildcard_nw_dst == false && (this.nw_dst_prefix != r.nw_dst_prefix || this.nw_dst_maskbits != r.nw_dst_maskbits))
133 || this.wildcard_dl_dst != r.wildcard_dl_dst
134 || (this.wildcard_dl_dst == false && this.dl_dst != r.dl_dst)) {
135 return false;
136 }
137 return true;
138 }
139
140 /**
141 * Matches this rule to a given flow - incoming packet
142 *
143 * @param switchDpid
144 * the Id of the connected switch
145 * @param inPort
146 * the switch port where the packet originated from
147 * @param packet
148 * the Ethernet packet that arrives at the switch
149 * @param wildcards
150 * the pair of wildcards (allow and deny) given by Firewall
151 * module that is used by the Firewall module's matchWithRule
152 * method to derive wildcards for the decision to be taken
153 * @return true if the rule matches the given packet-in, false otherwise
154 */
155 public boolean matchesFlow(long switchDpid, short inPort, Ethernet packet,
156 WildcardsPair wildcards) {
157 IPacket pkt = packet.getPayload();
158
159 // dl_type type
160 IPv4 pkt_ip = null;
161
162 // nw_proto types
163 TCP pkt_tcp = null;
164 UDP pkt_udp = null;
165
166 // tp_src and tp_dst (tp port numbers)
167 short pkt_tp_src = 0;
168 short pkt_tp_dst = 0;
169
170 // switchID matches?
171 if (wildcard_dpid == false && dpid != switchDpid)
172 return false;
173
174 // in_port matches?
175 if (wildcard_in_port == false && in_port != inPort)
176 return false;
177 if (action == FirewallRule.FirewallAction.DENY) {
178 wildcards.drop &= ~OFMatch.OFPFW_IN_PORT;
179 } else {
180 wildcards.allow &= ~OFMatch.OFPFW_IN_PORT;
181 }
182
183 // mac address (src and dst) match?
184 if (wildcard_dl_src == false
185 && dl_src != packet.getSourceMAC().toLong())
186 return false;
187 if (action == FirewallRule.FirewallAction.DENY) {
188 wildcards.drop &= ~OFMatch.OFPFW_DL_SRC;
189 } else {
190 wildcards.allow &= ~OFMatch.OFPFW_DL_SRC;
191 }
192
193 if (wildcard_dl_dst == false
194 && dl_dst != packet.getDestinationMAC().toLong())
195 return false;
196 if (action == FirewallRule.FirewallAction.DENY) {
197 wildcards.drop &= ~OFMatch.OFPFW_DL_DST;
198 } else {
199 wildcards.allow &= ~OFMatch.OFPFW_DL_DST;
200 }
201
202 // dl_type check: ARP, IP
203
204 // if this is not an ARP rule but the pkt is ARP,
205 // return false match - no need to continue protocol specific check
206 if (wildcard_dl_type == false) {
207 if (dl_type == Ethernet.TYPE_ARP) {
208 if (packet.getEtherType() != Ethernet.TYPE_ARP)
209 return false;
210 else {
211 if (action == FirewallRule.FirewallAction.DENY) {
212 wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
213 } else {
214 wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
215 }
216 }
217 } else if (dl_type == Ethernet.TYPE_IPv4) {
218 if (packet.getEtherType() != Ethernet.TYPE_IPv4)
219 return false;
220 else {
221 if (action == FirewallRule.FirewallAction.DENY) {
222 wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
223 } else {
224 wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
225 }
226 // IP packets, proceed with ip address check
227 pkt_ip = (IPv4) pkt;
228
229 // IP addresses (src and dst) match?
230 if (wildcard_nw_src == false
231 && this.matchIPAddress(nw_src_prefix,
232 nw_src_maskbits, pkt_ip.getSourceAddress()) == false)
233 return false;
234 if (action == FirewallRule.FirewallAction.DENY) {
235 wildcards.drop &= ~OFMatch.OFPFW_NW_SRC_ALL;
236 wildcards.drop |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
237 } else {
238 wildcards.allow &= ~OFMatch.OFPFW_NW_SRC_ALL;
239 wildcards.allow |= (nw_src_maskbits << OFMatch.OFPFW_NW_SRC_SHIFT);
240 }
241
242 if (wildcard_nw_dst == false
243 && this.matchIPAddress(nw_dst_prefix,
244 nw_dst_maskbits,
245 pkt_ip.getDestinationAddress()) == false)
246 return false;
247 if (action == FirewallRule.FirewallAction.DENY) {
248 wildcards.drop &= ~OFMatch.OFPFW_NW_DST_ALL;
249 wildcards.drop |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
250 } else {
251 wildcards.allow &= ~OFMatch.OFPFW_NW_DST_ALL;
252 wildcards.allow |= (nw_dst_maskbits << OFMatch.OFPFW_NW_DST_SHIFT);
253 }
254
255 // nw_proto check
256 if (wildcard_nw_proto == false) {
257 if (nw_proto == IPv4.PROTOCOL_TCP) {
258 if (pkt_ip.getProtocol() != IPv4.PROTOCOL_TCP)
259 return false;
260 else {
261 pkt_tcp = (TCP) pkt_ip.getPayload();
262 pkt_tp_src = pkt_tcp.getSourcePort();
263 pkt_tp_dst = pkt_tcp.getDestinationPort();
264 }
265 } else if (nw_proto == IPv4.PROTOCOL_UDP) {
266 if (pkt_ip.getProtocol() != IPv4.PROTOCOL_UDP)
267 return false;
268 else {
269 pkt_udp = (UDP) pkt_ip.getPayload();
270 pkt_tp_src = pkt_udp.getSourcePort();
271 pkt_tp_dst = pkt_udp.getDestinationPort();
272 }
273 } else if (nw_proto == IPv4.PROTOCOL_ICMP) {
274 if (pkt_ip.getProtocol() != IPv4.PROTOCOL_ICMP)
275 return false;
276 else {
277 // nothing more needed for ICMP
278 }
279 }
280 if (action == FirewallRule.FirewallAction.DENY) {
281 wildcards.drop &= ~OFMatch.OFPFW_NW_PROTO;
282 } else {
283 wildcards.allow &= ~OFMatch.OFPFW_NW_PROTO;
284 }
285
286 // TCP/UDP source and destination ports match?
287 if (pkt_tcp != null || pkt_udp != null) {
288 // does the source port match?
289 if (tp_src != 0 && tp_src != pkt_tp_src)
290 return false;
291 if (action == FirewallRule.FirewallAction.DENY) {
292 wildcards.drop &= ~OFMatch.OFPFW_TP_SRC;
293 } else {
294 wildcards.allow &= ~OFMatch.OFPFW_TP_SRC;
295 }
296
297 // does the destination port match?
298 if (tp_dst != 0 && tp_dst != pkt_tp_dst)
299 return false;
300 if (action == FirewallRule.FirewallAction.DENY) {
301 wildcards.drop &= ~OFMatch.OFPFW_TP_DST;
302 } else {
303 wildcards.allow &= ~OFMatch.OFPFW_TP_DST;
304 }
305 }
306 }
307
308 }
309 } else {
310 // non-IP packet - not supported - report no match
311 return false;
312 }
313 }
314 if (action == FirewallRule.FirewallAction.DENY) {
315 wildcards.drop &= ~OFMatch.OFPFW_DL_TYPE;
316 } else {
317 wildcards.allow &= ~OFMatch.OFPFW_DL_TYPE;
318 }
319
320 // all applicable checks passed
321 return true;
322 }
323
324 /**
325 * Determines if rule's CIDR address matches IP address of the packet
326 *
327 * @param rulePrefix
328 * prefix part of the CIDR address
329 * @param ruleBits
330 * the size of mask of the CIDR address
331 * @param packetAddress
332 * the IP address of the incoming packet to match with
333 * @return true if CIDR address matches the packet's IP address, false
334 * otherwise
335 */
336 protected boolean matchIPAddress(int rulePrefix, int ruleBits,
337 int packetAddress) {
338 boolean matched = true;
339
340 int rule_iprng = 32 - ruleBits;
341 int rule_ipint = rulePrefix;
342 int pkt_ipint = packetAddress;
343 // if there's a subnet range (bits to be wildcarded > 0)
344 if (rule_iprng > 0) {
345 // right shift bits to remove rule_iprng of LSB that are to be
346 // wildcarded
347 rule_ipint = rule_ipint >> rule_iprng;
348 pkt_ipint = pkt_ipint >> rule_iprng;
349 // now left shift to return to normal range, except that the
350 // rule_iprng number of LSB
351 // are now zeroed
352 rule_ipint = rule_ipint << rule_iprng;
353 pkt_ipint = pkt_ipint << rule_iprng;
354 }
355 // check if we have a match
356 if (rule_ipint != pkt_ipint)
357 matched = false;
358
359 return matched;
360 }
361
362 @Override
363 public int hashCode() {
364 final int prime = 2521;
365 int result = super.hashCode();
366 result = prime * result + (int) dpid;
367 result = prime * result + in_port;
368 result = prime * result + (int) dl_src;
369 result = prime * result + (int) dl_dst;
370 result = prime * result + dl_type;
371 result = prime * result + nw_src_prefix;
372 result = prime * result + nw_src_maskbits;
373 result = prime * result + nw_dst_prefix;
374 result = prime * result + nw_dst_maskbits;
375 result = prime * result + nw_proto;
376 result = prime * result + tp_src;
377 result = prime * result + tp_dst;
378 result = prime * result + action.ordinal();
379 result = prime * result + priority;
380 result = prime * result + (new Boolean(wildcard_dpid)).hashCode();
381 result = prime * result + (new Boolean(wildcard_in_port)).hashCode();
382 result = prime * result + (new Boolean(wildcard_dl_src)).hashCode();
383 result = prime * result + (new Boolean(wildcard_dl_dst)).hashCode();
384 result = prime * result + (new Boolean(wildcard_dl_type)).hashCode();
385 result = prime * result + (new Boolean(wildcard_nw_src)).hashCode();
386 result = prime * result + (new Boolean(wildcard_nw_dst)).hashCode();
387 result = prime * result + (new Boolean(wildcard_nw_proto)).hashCode();
388 result = prime * result + (new Boolean(wildcard_tp_src)).hashCode();
389 result = prime * result + (new Boolean(wildcard_tp_dst)).hashCode();
390 return result;
391 }
392}