Skip to content
Stephen Brennan edited this page Apr 14, 2015 · 1 revision

PyWall

It's still a stupid name. Suggestions are still welcome! Anyway, we might as well keep our architecture plans here.

NetFilterQueue

The library we're using is a Python binding to the C NetfilterQueue library. It has two classes:

  • NetfilterQueue - a queue of packets from the kernel waiting for a routing decision from us.
    • bind(queue_num, callback) - bind to queue_num. Also, sets the callback for each packet that arrives in the queue.
    • unbind() - unbind our queue
    • run() - block waiting for packets, calling the callback function for each packet.
  • Packet
    • get_payload() - Gets the packet payload.
    • get_payload_len() - Gets the payload length
    • accept() - Send the packet back to the kernel to be forwarded up the network stack.
    • drop() - Block this packet from going further.

The callback function takes a single argument, an instance of Packet.

PyWall Architecture

I'm going to stick mostly to the design that IPTables has. The way IPTables works, in a nutshell, is that it has these things called "chains". A packet enters the "INPUT" chain, and gets matched against each rule in the chain sequentially. A rule has a predicate, and an action (which is a jump to a new chain). The first rule in the chain that the packet matches, it follows. The "ACCEPT" and "DROP" chains are the final destinations for packets. Here is a simple example:

Input Chain

  • If TCP Packet, goto TCP chain
  • If UDP Packet, goto UDP chain
  • If it's an ICMP packet, do the proper response
  • Otherwise, goto DROP

TCP Chain

  • If it's with an existing connection, goto ACCEPT
  • If it's an incoming connection, goto DROP
  • If it's invalid, goto DROP

UDP Chain

  • Goto ACCEPT

OK, so here's going to be our class architecture for this (of course, suggestions are more than welcome).

  • PyWall - the main firewall class.
    • Constructor - TBD, probably will just have the NFQueue number.
    • add_chain(name) - add a chain with the given name. I don't think we need a chain class, as it's just a list of rules.
    • add_rule(chain, rule) - add a rule to the end of the chain.
    • run() - Calls run on the NetfilterQueue object.
    • callback(packet) - processes a packet: start at INPUT
  • Rule - a rule class (or function). We can use functions for simpler rules, and classes for rules that need to share state.
    • __call__(packet) - apply the rule. Return False if it doesn't match. Otherwise, return the name of the next chain for that packet.

I'm thinking we will want to write our own Packet class as well, with TCP and UDP subclasses. When we receive a packet, we can parse it into our own class, and that way the rules won't have to do packet mangling.

Rules

OK, so we'll need to implement the following rules:

  • Source address
  • Destination address
  • Source port (TCP/UDP)
  • Destination port (TCP/UDP)
  • TCP flags
  • TCP connection tracking

And probably some more, which we can come up with after we've completed the basics.

Clone this wiki locally