Firewall (Dev)

Skip to end of metadata
Go to start of metadata

Author: Amer Tahir amertahir@gmail.com
Edited by: KC Wang kc.wang@bigswitch.com

Introduction

The Firewall application has been implemented as a Floodlight Module that enforces ACL rules (Access Control List) on OpenFlow enabled switches in the network using flows and by monitoring packet-in behavior. ACL rules here are just sets of conditions that permit or allow or deny a traffic flow at its ingress switch.

Each packet-in triggered by the first packet(s) of a traffic flow is matched against the set of existing firewall rules. Firewall rules are sorted based on assigned priorities and are matched against the PacketIn's header fields as defined in OFMatch (as of OpenFlow Standard 1.0). The highest priority matching firewall rule determines the action (allow/deny) of the flow. Wildcards can be used as defined in OFMatch. 

Firewall Strategy

The firewall operates in a reactive manner. Firewall rules are sorted by priority at the time they are created (via its REST API). Each incoming packet-in will be compared against the list from the highest priority until either a match is found or the list is exhausted. If a match is found, the rule's action (ALLOW or DENY) is stored in a IRoutingDecision object to be passed on to the rest of the packet-in processing pipeline. This decision eventually reaches Forwarding or any other chosen packet forwarding application (e.g., LearningSwitch). Forwarding pushes a regular forwarding flow entry if the decision is ALLOW, or a drop flow entry if the decision is DENY. In either case, the flow entry sent to the switch must exactly reflect the matching firewall rule's match attributes (including wildcards).

The firewall thus implemented allows rules to have partially overlapping flow space, arbitrated by their priority.  In the simplified example below, all traffic to 192.168.1.0/24 subnet is denied except inbound HTTP (TCP port 80) traffic.

protocol destination IP destination port action priority*
TCP 192.168.1.0/24 80 ALLOW 1
TCP 192.168.1.0/24 wildcard DENY 2

* lower number indicates higher priority

Special care is taken to handle the wildcard in this case. If a flow does not match the first (higher priority) flow but matches the second (lower priority) flow, the flow entry sent by Forwarding to the switch cannot and will not wildcard the destination port; instead, the specific port of that flow is specified in the flow entry, so that future packets of port 80 will not be dropped by the switch without sending a packet-in to the controller.

REST Interface

The Firewall Module exposes REST interface implemented as RestletRoutable using Rest API Service. Following is a list of REST methods exposed:

URI Method URI Arguments Data Data Fields Description
/wm/firewall/module/<op>/json GET op: status, enable, disable, storageRules, subnet-mask None None query the status of, enable, and disable the firewall
/wm/firewall/rules/json
GET None None None List all existing rules in json format
  POST None {"<field 1>":"<value 1>", "<field 2>":"<value 2>", ...} "field":"value" pairs below in any order and combination:
"switchid":"<xx:xx:xx:xx:xx:xx:xx:xx>", "src-inport":"<short>", 
"src-mac": "<xx:xx:xx:xx:xx:xx>", "dst-mac": "<xx:xx:xx:xx:xx:xx>", 
"dl-type": "<ARP or IPv4>", "src-ip": "<A.B.C.D/M>", "dst-ip": "<A.B.C.D/M>", 
"nw-proto": "<TCP or UDP or ICMP>", "tp-src": "<short>", "tp-dst": "<short>", 
"priority": "<int>", "action": "<ALLOW or DENY>"

Note: specifying src-ip/dst-ip without specifying dl-type as ARP, or specifying any IP-based nw-proto will automatically set dl-type to match IPv4.
Create new firewall rule
  DELETE None {"<ruleid>":"<int>"} "ruleid": "<int>"
Note: ruleid is a random number generated and returned in the json response upon successful creation
Delete a rule by ruleid

Examples using curl

Assume the controller runs on localhost. Show whether the firewall is enabled or disabled.

curl http://localhost:8080/wm/firewall/module/status/json

Enable the firewall. By default firewall denies all traffic unless an explicit ALLOW rule is created.

curl http://localhost:8080/wm/firewall/module/enable/json

Adding an ALLOW rule for all flows to pass through switch 00:00:00:00:00:00:00:01.

curl -X POST -d '{"switchid": "00:00:00:00:00:00:00:01"}' http://localhost:8080/wm/firewall/rules/json

Adding an ALLOW rule for all flows between IP host 10.0.0.3 and host 10.0.0.7. Not specifying action implies ALLOW rule.

curl -X POST -d '{"src-ip": "10.0.0.3/32", "dst-ip": "10.0.0.7/32"}' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.7/32", "dst-ip": "10.0.0.3/32"}' http://localhost:8080/wm/firewall/rules/json

Adding an ALLOW rule for all flows between host mac 00:00:00:00:00:0a and host 00:00:00:00:00:0b

curl -X POST -d '{"src-mac": "00:00:00:00:00:0a", "dst-mac": "00:00:00:00:00:0b"}' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"dst-mac": "00:00:00:00:00:0b", "dst-mac": "00:00:00:00:00:0a"}' http://localhost:8080/wm/firewall/rules/json

Adding an ALLOW rule for ping to work between IP hosts 10.0.0.3 and 10.0.0.7.

curl -X POST -d '{"src-ip": "10.0.0.3/32", "dst-ip": "10.0.0.7/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.7/32", "dst-ip": "10.0.0.3/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json

curl -X POST -d '{"src-ip": "10.0.0.3/32", "dst-ip": "10.0.0.7/32", "nw-proto":"ICMP" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.7/32", "dst-ip": "10.0.0.3/32", "nw-proto":"ICMP" }' http://localhost:8080/wm/firewall/rules/json

Adding an ALLOW rule for UDP (such as iperf) to work between IP hosts 10.0.0.4 and 10.0.0.10, and then blocking port 5010.

curl -X POST -d '{"src-ip": "10.0.0.4/32", "dst-ip": "10.0.0.10/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.10/32", "dst-ip": "10.0.0.4/32", "dl-type":"ARP" }' http://localhost:8080/wm/firewall/rules/json

curl -X POST -d '{"src-ip": "10.0.0.4/32", "dst-ip": "10.0.0.10/32", "nw-proto":"UDP" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.10/32", "dst-ip": "10.0.0.4/32", "nw-proto":"UDP" }' http://localhost:8080/wm/firewall/rules/json

curl -X POST -d '{"src-ip": "10.0.0.4/32", "dst-ip": "10.0.0.10/32", "nw-proto":"UDP", "tp-src":"5010", "action":"DENY" }' http://localhost:8080/wm/firewall/rules/json
curl -X POST -d '{"src-ip": "10.0.0.10/32", "dst-ip": "10.0.0.4/32", "nw-proto":"UDP", "tp-dst":"5010", "action":"DENY" }' http://localhost:8080/wm/firewall/rules/json

Test Methodology

Testing comprises of automated unit tests created using EasyMock. The “FirewallTest” class contains the test cases that can be executed using JUnit and Eclipse. In most of the test cases, packet-in event is simulated and the resulting firewall decision is verified based on the rules defined. Following is a list of the various test cases: 

  • testNoRules
    • Description: without any rules, send a packet-in event. The firewall should DENY the traffic. This is a boundary case.
  • testRuleInsertionIntoStorage
    • Description: adds a rule into firewall and verifies it by checking storage. This is a normal positive test case.
  • testRuleDeletion
    • Description: deletes a rule from firewall and verifies it by checking storage. Again, this is a normal positive test case.
  • testFirewallDisabled
    • Description: with the firewall disabled and a rule inserted, send a packet-in event. The firewall should DENY the traffic. This is a negative test case.
  • testSimpleAllowRule
    • Description: Adds a simple rule to allow TCP traffic from one IP address to another and sends a packet-in event. After verifying the firewall’s decision, it sends another packet that is supposed to be DROPPED, and then verifies the decision to be DROP. This test case covers normal rules (non-boundary case – i.e. no malformed packets or broadcasts)
  • testOverlappingRules
    • Description: Adds overlapping rules (deny all TCP traffic except destined for port 80). This test case covers complex cases of multiple rules (multiple allow-deny overlapping rules).
  • testARP
    • Description: tests a special scenario of ARP broadcast request packet and unicast ARP reply. There is no firewall rule allowing ARP reply, so only broadcast request packet should go through.
  • testIPBroadcast
    • Description: without any rules, send an IP broadcast (L3) packet-in event. The firewall should ALLOW the traffic. This is a positive test case that covers a special scenario of IP broadcasts (L3 + L2 broadcast).
  • testMalformedIPBroadcast
    • Description: without any rules, send a malformed IP broadcast packet-in event. The firewall should DENY the traffic, as the packet is L2 broadcast but L3 unicast. This is a boundary case.
  • testLayer2Rule
    • Description: with a rule to allow traffic from one specific MAC to another and another rule (lower priority) to deny all TCP traffic, a TCP packet-event is simulated. The firewall should ALLOW the traffic. This is a negative test case that covers a subset of scenarios where the rules cover only L2.

Issues and Limitations

  1. The firewall module's DELETE REST API call doesn’t delete flow entries on the switch. The rule is only deleted from the controller storage while the flow entry on switch is expected to time out itself per standard timeout behavior. This means the effect of deleting a rule is effective after a certain time, and an existing flow can persist for as long as it has continuous traffic through the switches.
  2. In the initial proposal, TCP/UDP port ranges were proposed to be supported by the firewall rules. However, as OpenFlow flow matching mechanism doesn’t allow specifying port ranges, this feature was not implemented. 
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.