The FireBrick includes a session tracking firewall. Session tracking means that each session of IP traffic is recorded in the FireBrick. Each packet that arrives either matches an existing session or is considered for creating a new one. The sessions can tell the Firebrick to drop the packet, reject it, or pass it on.
If passing on the packet then changes can be made to IP addresses or ports on the way, and routing of the packet can be over-ridden to send it to a specific gateway.
Protecting the FireBrick itself
Not all variants of the FireBrick even have firewalling, so the FireBrick is designed to have built-in protections. These apply after any firewalling or mapping rules have been done.
The main controls are that each service can be locked down to being allowed only from specific IP addresses, routing table, and even locked to only local subnets.
As such you do not normally need firewalling rules for traffic to the FireBrick itself, but obviously, you may add such rules if you wish.
The web control pages have additional controls, including trusted IP addresses which are allowed even if not from a local subnet and allow some access without logins (see CQM). Trusted IPs are also used to control access to packet dumping.
The diagnostics section of the web control pages allows testing of access controls and of firewalling logic.
When a packet arrives that is not part of an existing session, then a new session will have to be created. The rules for creating a new session are very flexible. It is these rules that control what is allowed in to and out of your network so it is important to understand how they work.
There are two top level objects that affect the firewalling rules, route-override and rule-set.
The route-override object defines rules that affect where traffic is routed and overrides the normal routing rules within the FireBrick. In general, you do not need to override routing rules. This allows routing based on source IP address as well as target IP and even based on protocols and ports.
The routing override is done before working out what firewall rules apply, and also whenever one of the rules makes a change that could be affected by the routing override.
The routing override does not decide if a session is allowed or not, just where the traffic is to be routed if it is allowed.
It also has a few additional settings which are often related to routing and are set based on the route-override table if not explicitly set by the rule-set rules. There is one route-override table (per routing table). The routing override applies both ways to the traffic, defining both the forward direction and the reply direction for packets.
The rule-set tables allow specific types of traffic to be identified and allowed or rejected/dropped/ignored. It also allows a number of settings to be changed, including changing IP addresses and ports or setting flags or establishing traffic shaping.
You can have many rule-set objects and they are considered one after the other in order, checking all of them unless told to stop.
Each rule-set has a number of rule entries, one of which is picked (the first that matches within the rule-set). There is also an option to have share objects within a rule to allow a load-balanced choice of which settings to apply when the rule has been selected.
Typically people will have a rule-set covering some aspect of the system, such as external traffic, or a specific interface, etc. It is also sensible to have one rule-set for firewalling, and one rule-set for mapping.
The routing override rule objects, the rule-set objects and their rule objects all have matching criteria. These are a set of attributes which are checked against the session being considered to decide if the rule-set or rule applies. You do not have to specify all (or any) of these attributes, and any you omit are ignored.
All of the attributes you specify must match the session being considered. They mostly contain lists and ranges of values, one of which must match. The session being considered may change after each rule-set, and it is the changed version that is tested for the routing override and the next rule-set.
|profile||Profile name||The profile must be active.|
|source-ip||IP range/name list||The source IP must be in the list. The list can be IPs, IPs with netmasks, IPv4 ranges, or named IP groups.|
|target-ip||IP range/name list||The target IP must be on the list. The list can be IPs, IPs with netmasks, IPv4 ranges, or named IP groups.|
|ip||IP range/name list||Either the source or target IP must be in the list. The list can be IPs, IPs with netmasks, IPv4 ranges, or named IP groups.|
|protocol||List of IP protocol numbers||The protocol must be on the list.|
|source-port||List of port numbers or ranges||The source port must be in the list. Only makes sense if this is a protocol with ports such as TCP or UDP.|
|target-port||List of port numbers or ranges||The target port must be on the list. Only makes sense if this is a protocol with ports such as TCP or UDP.|
|source-interface||List of names of interfaces||The source interface must be on the list.|
|target-interface||List of names of interfaces||The target interface based on routing logic and route override must be in the list. This attribute does not apply to routing override rules.|
|interface||List of names of interfaces||The source interface or target interface based on routing logic and route override must be in the list. This attribute does not apply to routing override rules.|
In addition to the matching criteria, route-override and rule-set have a table attribute which defines which routing table they apply to. This has a default of 0 and must match.
Each rule-set is considered in order. If the matching criteria match, then the rule entries are considered in order. The first matching rule is applied. Either way, checking goes on to the next rule-set until all rule-set objects have been checked or you have requested the session be dropped, rejected, ignored or accepted.
Note that if the matching criteria of a rule-set do not match, the rule-set is skipped and checking continues to the next rule-set.
The rule objects in a rule-set also have a number of attributes that can make changes to the session and packets that are passed on. These attributes all start set-.
If a rule-set matches the criteria, the rule entries are checked in order and the first matching one is applied. All of these action attributes are applied from that matching rule.
|set-source-ip||IP address||Sets a new source IP address.|
|set-target-ip||IP address||Sets a new target IP address.|
|set-source-port||Port (0-65535)||Sets a new source port address (only makes sense for protocols with ports like TCP or UDP).|
|set-target-port||Port (0-65535)||Sets a new source port address (only makes sense for protocols with ports like TCP or UDP).|
|set-nat||true/false||Sets the NAT flag which will cause the source IP and port to be changed. This does not change source IP or port for further matching criteria, it just sets the NAT flag. This takes precedence over the route override settings.|
|set-gateway||IP address||Sets a new gateway for this traffic. This takes precedence over the route override settings.|
|set-graph||Graph/shaper name||Sets a graph/shaper to apply. This takes precedence over the route override settings.|
|set-reverse-graph||Graph/shaper name||Sets a graph/shaper to apply for the other side of the session. This takes precedence over the route override settings.|
|set-table||Routing table number||Changes the routing table.|
|set-initial-time-out||Interval||Sets the initial time-out for the session (i.e. until a reply packet is received).|
|set-ongoing-time-out||Interval||Sets the ongoing time-out for the session (i.e. after a reply packet has been received).|
These settings can also be used within a shared object within a rule which provides load balancing. The settings in the rule are first applied, and then any defined in the chosen share is applied.
Each session has two sides, one for forwarding traffic and one for reverse traffic. As part of setting up a session a graph name can be specified to allow data passing through the session to be graphed and shaped.
Normally you only need to set the graph once for traffic as a graph shows both Tx and Rx traffic and allows rate limits for shaping tx and Rx independently.
The Tx and Rx for the graph used with set-graph are for traffic in the direction the rule matched (Tx) or reply traffic (Rx). However, for set-reverse-graph, they are the other way around.
In some cases, you may want a graph to apply a specific way around. The most common would be shaping traffic for a specific IP where the same graph should be used for traffic for sessions originating from the IP and sessions destined for the IP, but in such cases, the graphs operate in the reverse direction one way. The set-reverse-graph setting allows a rule for traffic to the IP to use set-graph, and sessions from the IP to set-reverse-graph, thus ensuring the Tx and Rx are right for the traffic (e.g. you might pick tx as all packets to the IP and Rx is all packets from).
In such cases, we recommend using a route-override ride to set the graph. A route-override rule is checked when a session is created and checked for traffic both ways. If a route-override rule matches the reverse traffic direction then the set-graph in the route-override rule applies to the reverse side of the session. This means the Tx and Rx for a route-override rule always apply to the direction of the route-override rule matching.
Bear in mind each session can have exactly two graphs, one for each side of the session. This means if one rule uses set-graph and one in a later rule-set uses set-reverse-graph, then you have two graphs set, one each side. i.e. set-reverse-graph is not simply setting the graph backwards it is setting the other side graph.
Processing of rule-set sets continues until you set a action=”drop” or action=”reject” or or action=”ignore” or action=”accept” attribute. This can be the result of a no-match-action on a rule-set and applies if the rule-set conditions match but no rule is matched. It can also be an action on a rule and applies if the rule matches. There is no point in any set- attributes on a rule that has drop, ignore or reject actions set.
Note that on the rule set the no-match-action attribute is mandatory and you must set to continue, drop, reject, ignore or accept to specify what happens if none of the rules in the rule-set match.
Continue to next rule-set, if any. If last rule-set then allow this session through. This is the default.
|accept||Allow this session through without checking any further rule-set.|
|reject||Do not allow this session, and set up a session that generates ICMP error replies. No further checking.|
Do not allow this session, and set up a session that drops packets. No further checking.
|ignore||Drop this packet and do not make any session. This is not very efficient as subsequence packets that are the same are checked. No further checking|
The rule-set can have a log attribute, set to true or false. If the rule-set matches then the log setting is applied.
Each rule in the rule-set also has a log attribute, and if the rule matches the log setting is applied.
The log setting is applied before checking if action is set, so you can request that a dropped session is logged.
As mentioned, a rule can have a list of share objects. These can override some of the actions in the rule. If the rule is being applied, the actions on the rule are applied and then one of the share objects picked. The actions on that share are then applied. The share objects contain a weight which controls how likely they are to be picked. Also, they have a profile. Only share objects which have an active profile are considered.
The <subnet…/> allows nat=”true” to be set – the effect of this that before considering rule-sets, if the traffic is from the specified subnet, then a set-nat=”true” is done. This can be overridden by rules.
The <dongle…/> has nat=”true” by default. The effect of this is that if, after considering rule-sets, and set-nat has not been used on any rules, and the destination of the traffic is a dongle with NAT set, then set-nat=”true” is done at that stage. Explicitly using a set-nat=”false” in a rule stops this, as does nat=”false” in the dongle config.
Technical details – How session tracking works
Session tracking means correlating packets that belong to a session. For some protocols like TCP, this is relatively simple as the session has a clearly defined start and end, and a way to identify what packets are in a session (by IPs and ports). Some are harder, such as UDP, where IPs and ports identify the session but there is no defined start and end. Some, such as IPSec, cannot be tracked by anything more than just IP addresses.
All types of session tracking use time-outs. There are two values that can be specified, an initial time-out and an ongoing time-out. When the session starts it has the initial time-out but as soon as a packet goes the other way (a reply) the time-out changes to the ongoing time-out.
For TCP the time-out starts small, a few seconds, but as soon as there is a reply the time-out changes to a long time-out (e.g. an hour). This is because TCP had a defined end. Once a FIN or RST is received then the time-out drops to a few seconds.
For UDP the time-out starts longer, e.g. 10 seconds, and when there is a reply it gets shorter, e.g. a second.
The time-outs can be fine-tuned in the configuration for specific protocols and ports and IP addresses. The actual time-out used is one taken from a list of pre-defined time-out values that is at least the one specified in the config.
You can use the names of interfaces in the interface, source-interface and target-interface attributes as well as the following special cases.
- self the FireBrick itself.
- pppoe any PPPoE link.
- dongle any USB/3G dongle link.
- l2tp any L2TP tunnel.
- fb105 any FB105 tunnel.
- indirect indirect via an unresolved gateway e.g. bonded gateway traffic or using ipv6 over ipv4 tunnel.
- nowhere where there is no route (default action ignore).
- multiple where a packet could go to multiple Ethernet interfaces, ARPs have been sent but no reply to actual interface undecided (default action is ignore).
- unknown any other type of route/interface, including blackhole routes (such as <route…/> with no gateway) and multiple Ethernet interfaces where all ARPs have timed out (default action is ignore).
The routing logic allows for the same subnet to exist on multiple Ethernet interfaces.
This allows traffic to be directed based on which interface answers ARPs for the IP address in question. However, for the first packet where there are no ARP replies cached this means the target interface is not known and so normal matching in rule-set and rules cannot work properly.
To accommodate this such sessions appear to have a target interface of multiple which can be checked and traffic allowed or rejected as required. However, to avoid holes in file-walls in such cases the overall default action (which is normally allow) is set to ignore in such cases.
Typically the packet will be retried by which time there is a suitable ARP response and normal rule matching can be applied to the target interface.
When session tracking applies
Session tracking applies to all traffic within a routing table which has any session tracking rules. This means if you have no rules defined, then packets are not session tracked (saving processing time and memory).
As soon as any rules (route-override or rule-set) are defined using a routing table (as table=”…” or set-table=”…”), then all traffic using that routing table is then session tracked.
- The configuration consists of an ordered list of rule-sets each of which has an order set of rules.
- The rule-set is considered in order, and within each rule-set, the rules are considered in order.
- Each rule-set has a set of matching criteria, and if these do not match the rule-set is not considered. Checking moves on to the next rule-set. The rule-set can be based on a profile.
- Each rule has a set of matching criteria in the same way. Once a rule is found that matches its criteria then no further rules in the rule-set are considered. i.e. only the one first matching rule in each rule-set is applied.
- The matching rule has actions which are processed. If a rule-set meets the entry criteria but no rule in a rule-set matches then there are actions on the rule-set itself that are used. if a rule matches, then the actions on the rule-set are completely ignored.
- The actions change things, like IP addresses or the overall action (allow/drop/reject/ignore). These changed parameters are then used to check the criteria for the next rule-set and its rules. I.e. changes accumulate as checking continues from one rule-set to the next. Once all rule-sets have been checked the final outcome applies.
Routing traffic is normally based on the target IP of the packet and finding the best and most specific route in the routing table. However, you can define a route-override for each routing table, and include a set of rules.
The first matching rule in the rule-override is picked and the gateway specified used instead of the target IP. This gateway is then considered using the normal routing rules. The route-override logic means session tracking the traffic, and the route remains using the new gateway for the whole of the life of the session.
This allows routing based on source interface, source IP as well as target IP, protocol, and ports. The target-interface can also be tested but this the interface based solely on the target IP using normal routing tables. The route-override table is checked before rule-set, and if the rule-set changes any settings (unless the rule-set specifically sets a gateway as part of its rules). The route-override is also used to work out the gateway for the reply traffic on any session (the target-interface test is based on the IP, not the actual interface from which the packet arrived).
Load sharing is possible on models with bonding enabled. Load sharing allows a list of share actions within a rule. If a matching rule is found, the actions on that rule are applied. Then, one of the share entries is picked at random based on the weight attribute on each. Any which have a profile with is inactive are not considered. The actions on that share are then applied, possibly overwriting those set by the rule, which acts as default. Typically the share entries set a new target IP or port for load shared services.
Examples – NAT private IPs
This rule-set on its own without the encompassing rule would cause all traffic from any RFC1918 addresses to have set-nat set to true, which is generally what you want (private IPs are NATed). However, the embedded rule says that traffic that is also to an RFC1918 address will not have set-nat set. This allows two interfaces that use RFC1918 addresses to talk to each other without using NAT.
You will note the rule does not say set-nat=”false”. It does not have to, as the actions in the rule-set do not apply at all if the rule matches and the actions in the rule do not contain set-nat. This does mean that if some previous rule causes set-nat to be set to true, this would not change that even for RFC1918 to RFC1918 traffic.
<rule-set name=”private IP NAT” set-nat=”true” source-ip=”192.168.0.0/16 172.16.0.0/12 10.0.0.0/8″>
<rule target-ip=”192.168.0.0/16 172.16.0.0/12 10.0.0.0/8″ comment=”Not setting NAT”/>
Names IP and protocols
IP addresses can be entered as single IP (e.g. 188.8.131.52), an IP and bit length (e.g. 192.168.0.0/24), a range of IPv4 addresses (e.g. 192.168.0.1-100), or a name of an ip-group. An ip-group can be defined within a rule-set and at a top-level and the specified name matches those in the same rule-set first rather and only considers names at the top level if no match found.
There are a number of special cases that are built into the session tracking system.
In these examples we use A, B, etc, to be the IP and port and protocol and table, etc, for one end. E.g. a packet may be A-B, i.e. traffic from A’s IP and port to B’s IP and port. This might be mapped, e.g. A-B:C-B meaning traffic A-B is mapped C-B (changing source address or port), and the reverse traffic B-C is mapped B-A.
The default action is normally to allow all. However, the factory default config has a rule dropping sessions to the LAN. This means a firewalling FireBrick is blocking inbound traffic by default.
As described there is an exception to this. If the interface is nowhere or unknown then the default if no rules match is drop. If the target interface is multiple the default if no rules match is ignore. These exceptions do not apply if a rule matches within a rule set as that has a default of allow unless set otherwise in the rule.
Bear in mind these defaults only apply where firewalling applies at all – i.e. having no rules will mean no firewall regardless of these defaults.
For a new packet, e.g. A-B, if the rules define it should be dropped or rejected then a one-sided session is created with a one-second timeout, and no reverse mapping. This means further packets A-B are dropped or rejected immediately without re-checking the rule-sets. However, if a packet was received B-A (unlikely as this would logically be a reply to a packet that was never sent) then that is considered independently via the rules.
ICMP (and ICMPv6 for IPv6) are processed specially. If they contain a non-error packet then they are treated like any other protocol that does not have ports and so can match a rule for the protocol.
If they contain an error, then they have a payload which quotes the initial bytes of a packet to which the error relates. In this case, the content of this packet is checked against the rules instead of the ICMP itself.
However, an ICMP error can never start a session. This prevents an error packet being checked against outbound rules and creating a reverse path through the firewall. If there is no established session the ICMP packet is dropped.
It is possible to create a session, e.g. A-B:C-B, which is a case where traffic A-B is mapped to C-B, and in this case, C is usually NAT source (i.e. the FireBrick’s address and an ephemeral port). In this case reply traffic, B-C is mapped back to B-A.
However, if a packet B-A is received, i.e. matching exactly the IPs and ports as a reply to the original packet, then this is checked against firewall rules. If it is allowed it would create a non-mapped session B-A:B-A. However, doing this would make a “Y” set of sessions. Packets A-B would not know if they should match A-B:C-B and change to C-B, or map the reverse on B-A:B-A and just be allowed as a B-A packet. If this scenario happens then the new session is simply not allowed and the B-A packet is dropped.
If the FireBrick is restarted then all sessions are lost. In this case, packets that arrive, even if continuing a previously valid session, are checked against the firewall rules. If they are allowed then a new session is made. If they are not then a one-sided block/reject session is made.
Imagine if originally there was A-B:A-B session, i.e. A-B is allowed (and not changed). Replies B-A is allowed. Once sessions are lost, B-A is not allowed so makes a one-sided dropping session. But then a packet A-B is sent (maybe resending as no reply, etc). In this case, a session clash happens very much like the “Y” routing above. However, as one side of the session is one-side, the session is discarded and the new session made. The A-B traffic flows and further B-A replies are then allowed – restoring the session after a firewall restart.
This really only works where there is no dynamic mapping such as set-nat, and options may be added to disallow TCP sessions that are not the start of a session (SYN+noACK).
A TCP session can start based on any packet (as above, restoring sessions). However, if the packet would cause a set-nat session and the packet is not the first in the TCP flow (i.e. SYN and no FIN) then that makes no sense as the dynamic set-nat will be different this time. In such cases, a one-side reject session is made.
A triangular route applies where traffic takes one route A to B and a different route B to A. Such routing is allowed in IP and allowed on the FireBrick. Once established a session can continue on any interfaces (though it does have to match routing tables, which are interface specific).
However, if a triangular route has the FireBrick in one direction and not in the other, then this can cause issues. Any form of IP or port mapping cannot work in such cases as the mapping is not un-done when the reply goes via a different route. However, using set-nat always sets the new source IP to one allocated to the FireBrick itself and so reply traffic will hopefully go back via the FireBrick and avoid triangular routing.
Whilst such triangular routing it is not a problem where the mapping is not done and the FireBrick is simply firewalling. It does typically mean there is a route past the firewall, which is generally bad. It also means session time-outs and tracking do not work correctly causing sessions to drop more often and have to be restarted, or continue for longer and not be dropped. Both of these are less efficient than usual session tracking.
An implicit final rule-set applies if an IPv6/4 NAT block is configured. This is an IPv6 prefix (at least /96) defined with the nat64 attribute in system. By arranging for this to be routed to the FireBrick (e.g. static or BGP announced) then traffic to this block is mapped to an IPv4 address based on the last 32 bits. Using a DNS proxy such as trick or treat daemon to return IPv6 addresses where a host only has an IPv4 address this allows IPv6 only hosts to access IPv4 internet.
The rule only applies where port mapping and set-nat can sensibly be applied, i.e. protocols with ports like TCP and UDP as well as ICMP for pings, etc. The rule blocks any attempt to map to 0.0.0.0/8, 127.0.0.0/8 and 184.108.40.206/3