| 42 | - 3.1 Building a Firewall with OpenFlow [[BR]] |
| 43 | A firewall observes the packets that pass through it, and uses a set of rules to determine whether any given packet should be allowed to pass. A stateless firewall does this using only the rules and the current packet. A stateful firewall keeps track of the packets it has seen in the past, and uses information about them, along with the rules, to make its determinations. [[BR]] |
| 44 | In this exercise, you will build a stateful firewall controller for TCP connections in OpenFlow. The first packet of each connection will be handled by the controller, but all other connection packets will be handled by the OpenFlow-enabled router or switch without contacting your controller. This design will allow you to write powerful firewall rule sets without unduly impacting packet forwarding speeds. Your controller will parse a simple configuration file to load its rules. Complete stateful firewalls often handle multiple TCP/IP protocols (generally at least both TCP and UDP), track transport protocol operational states, and often understand some application protocols, particularly those utilizing multiple transport streams (such as FTP, SIP, and DHCP). The firewall you will implement for this exercise, however, needs handle only TCP, and will not directly process packet headers or data. [[BR]] |
| 45 | '''Network Setup''' [[BR]] |
| 46 | [[Image(OpenFlowAssignment1.png, 30%, nolink)]] |
| 47 | Follow instructions in the [http://groups.geni.net/geni/wiki/GENIEducation/SampleAssignments/OpenFlowAssignment/ExerciseLayout/DesignSetup DesignSetup] step to build a firewall experiment topology. The specific host names allocated for your experiment will be different, but the topology will be isomorphic. The host labeled ''left'' in the figure is “behind” the firewall, implemented by the Open vSwitch host labeled ''switch''. The host labeled ''router'' handles IP routing for the firewalled network, and every host on the other side of this router (the host labeled ''right'' being the only example on this topology; you may wish to add others for your testing and experimentation) are “outside” of the firewall. [[BR]] |
| 48 | The provided RSpec and the files it installs on the hosts it allocates will configure a complete, working network with an Open vSwitch running on the host labeled ''switch''. The Open vSwitch switch is configured to connect to a controller on localhost (that is, the switch host), but no controller is started; until a controller is started on localhost, the Open vSwitch will act like a normal learning switch, forwarding all packets to the appropriate interface based on MAC address. ''Trema'' is installed in ''/opt/trema-trema-8e97343.'' Once you have implemented your switch, you can simply use this ''Trema'' install to run it and the Open vSwitch will obey its configuration. [[BR]] |
| 49 | You can test that the network configured correctly by waiting a few moments after Flack or Omni (or whatever GENI tool you are using) suggests that the sliver is ready, and running ping right from the host allocated for left or vice-versa. Since the fallback switch configuration will act like a normal learning switch, the ping packets should go through. [[BR]] |
| 50 | '''Firewall Configuration''' |
| 51 | The firewall configuration language is very simple. All flows not specified in the configuration are assumed to be forbidden, and the default packet processing policy on the OpenFlow device you are managing should be to drop packets. The configuration language will specify, one flow to a line, the TCP flows that should be permitted to pass the firewall. The syntax is: |
| 52 | {{{ |
| 53 | <ip>[/<netmask>] <port> <ip>[/<netmask>] <port> |
| 54 | }}} |
| 55 | Items in angle brackets (<>) represent variable values, items in square brackets ([]) represent optional syntax, and unquoted characters (e.g., the slash characters) represent themselves. The first subnet (IP address plus mask length) and port number are the subnet and port number of the host initiating the connection (that is, sending the first bare SYN), and the second subnet and port number are those of the host accepting the connection. IP addresses are specified as dotted quads (e.g., 192.168.1.0) and netmasks as bit lengths (e.g., 24). If a netmask is missing (the IP address for a given subnet is not followed by a slash and an integer), it is equivalent to /32. Port numbers are integers. Either or both of the IP address or port numbers may be replaced by the word any, equivalent to 0.0.0.0/0 in the case of IP address, or to any port number, in the case of port numbers. [[BR]] |
| 56 | A sample configuration that implements a firewall permitting inbound connections to a web server at IP address 192.168.1.1 on port 80, and any outbound connections initiated by hosts inside the firewall (protecting 192.168.1.0/24) is as follows: |
| 57 | {{{ |
| 58 | any any 192.168.1.1 80 |
| 59 | 192.168.1.0/24 any any any |
| 60 | }}} |
| 61 | All whitespace will be a single ASCII space character, all newlines will be a single ASCII newline character (0x0a) Empty lines (two newlines back-to-back) are permitted. [[BR]] |
| 62 | A connection is allowable if it matches any rule. A connection matches a rule if all four elements of the four-tuple match. Subnet matching uses standard rules, expressed in this pseudocode: |
| 63 | {{{ |
| 64 | boolean subnet_match(IP subnet, int bits, IP addr) { |
| 65 | int32 bitmask = ̃((1 << 32 - bits) - 1); |
| 66 | IP addrnet = addr & bitmask; |
| 67 | return addrnet ˆ subnet == 0; |
| 68 | } |
| 69 | }}} |
| 70 | Note that rules are not bidirectional; the presence of the first rule in this set does not imply the second: |
| 71 | {{{ |
| 72 | 192.168.1.0/24 any any any |
| 73 | any any 192.168.1.0/24 any |
| 74 | }}} |
| 75 | This means that the first packet the controller sees that matches a flow causes the flow to be allowed. Packets that would trigger a reply that would be allowed are not necessarily allowed. |
| 76 | The name of a firewall configuration file will be provided on the controller command line. To provide an argument to your controller application, it must be included with the controller file name. For example, to configure your firewall found in ''firewall.rb'' to load ''fw.conf'', you would invoke: |
| 77 | {{{ |
| 78 | trema run ’firewall.rb fw.conf’ |
| 79 | }}} |
| 80 | You will then find [’firewall.rb’, ’fw.conf’] in ARGV when your controller’s start method is invoked. [[BR]] |