====== Firewall Rule Syntax ====== ^ :!: This description is addressed to advanced users only, with a good understanding of how firewalls in general work and who want to know specifically how the firewall in the Internet Gate works. ^ This means that the rest of the text is only relevant for the Internet Gate unless otherwise noted. The text will loosely refer to a unit of data transmitted on the network as a packet when it would be more correct to use, for example, frame in some situations. ===== Definitions ===== A **rule** is a firewall object that is used to control how traffic passing through the firewall should be handled. Rules are grouped into **rulesets** with one set for each interface , direction and "processing level". Direction is defined from the interface's point of view, i.e. incoming refer to packets received on the interface and outgoing to packets transmitted/sent by the interface. The processing level is an internal construct, representing the different points in the internal packet flow where filtering can be applied. The two levels are "supervisor" and "user". This means that there are four basic rulesets per interface (two directions and two levels). Each rule consists of a **filter expression** which tells what packets it should match and an **action** which tells what to do with the matching packets. Supervisor rules use simple actions for coarse filtering of the traffic, while user rules utilise all available actions and can therefore offer finer control. A packet is matched against the rules in the relevant set (decided by interface, direction and "level"), starting at the first (topmost) rule in the set and continuing until a match is found or there are no more rules to match against. If no rule matches the packet the default rule is applied. In addition to the basic rulesets described above there is also one extra set for each interface which is used to filter traffic sent to the firewall log, and one extra set controlling non-IP packets. This means that there are actually six sets of rules per interface. An **active flow** is another type of firewall object which is used to control how packets are handled. It's more dynamic in its nature compared to the rules. Whereas rules are only changed when the firewall is reconfigured, an active flow can be created, destroyed or modified by a user rule action, an internal proxy's decision, or by any other firewall control mechanism. Active flows are similar to rules in that they only match specific packets, though the filtering capabilites are less general than those of a rule. Since flows mostly are used to monitor and control packets with similar properties this is not really a problem. Another similarity to rules is that each interface and direction has its own set of flows. However, for bidirectional traffic (TCP, etc.) flows in the two directions are tightly connected for stateful inspection purposes. The firewall uses a **deny all** policy by default, meaning that if no rule or active flow matches a packet, the packet is discarded. The log ruleset is the exception to this rule, since it uses an **accept all** policy instead. ===== Packet processing pipeline ===== {{ :firewall:setup_rules.gif|Pipeline schematics}} Incoming packets on an interface are first checked for validity using a predefined set of checks. After that fragments are handled specifically. The first user controlled filtering stage is the supervisor rule set. Supervisor rules are often used as a coarse filter to get rid of unwanted traffic. An example of this is the so-called "spoof protection", which makes sure that an incoming package comes from a valid IP address range. If a packet is accepted by the supervisor rule set, it is checked for matches against the active flows. Active flows can be seen as a dynamic rule set with rules for currently active "connections" (see above for more information). Packets accepted by an active flow are really accepted, while those that does not match any flow are subject to filtering by the user rule set. The user rule set work the same way as the superuser rule set, but instead of coarse filtering it's used for fine control and filtering of the traffic. Rules in the user rule set have access to all action types and can therefore be used to create active flows by using the "inspect" and "modify" actions. Finally, if logging is enabled, traffic gets filtered through the log rule set. In contrast to the other rule sets, the log rule set use a default accept all instead of a deny all policy. This means that to get rid of certain types of traffic, matching deny rules have to be written. After the final step in the firewall pipeline, the packet is passed on to the IP-layer where routing, etc. takes place, but that is outside the scope of this document. A consequence of the firewall's **deny all** policy is that a packet has to be accepted by the supervisor rule set to actually be received or transmitted. The outgoing pipeline works analogously to the incoming pipeline, with one major exception: a packet accepted by a flow is sent to the supervisor rules instead of being accepted directly. ===== Rule filter expressions ===== The filter expression consists of a number of relational expressions combined into a Boolean expression by using Boolean operators. Relational expressions consist of two operands separated by a relational operator. One of the operands is a protocol data unit (PDU) field, represented by its symbolical name and the other is a value, represented by a numerical value or the symbolical name of a constant. Common operator precedence applies, meaning that AND (&&) has higher priority than OR (||), etc. To override this, parenthesis can be used, like in normal mathematical expressions. Parenthesis can also be used to group expressions together for clarity, which is sometimes seen in automatically generated rules. ===== Rule actions ===== Each rule has an associated action, represented by its symbolical name (see below), possibly followed by a number of parameters. ===== Performance considerations ===== Factors affecting the performance of the firewall are number of rules in each ruleset, the order of the rules in the rulesets, each rule's complexity (number of expressions) and the number of active flows. Since each packet is matched against the relevant rules, the number of packets per second (pps) handled by the firewall impacts heavily on the performance. This is why traffic consisting of a lot of small packets can affect performance in a more negative way than traffic consisting of fewer large sized packets. Even if the total bandwidth of the large sized packets surpass that of the small sized packets. To optimise for performance, one should try to write rule sets where a match is found as quickly as possible. For example, if the first rule of a rule set matches 90% of the packets, the rest of the rules in the set will play a rather small role in the total performance. Another thing to bear in mind when trying to optimise for performance is to filter out unwanted or unneeded traffic as soon as possible. For example, filtering out traffic in the incoming supervisor rule set is very effective since this terminates the packet processing pipeline at the earliest stage and also stops the packet from ever reaching the IP subsystem where routing, etc. takes place. ===== Examples ===== ==== Example 1 - A simple rule ==== saddr == 10.0.0.1 deny Packets with a source IP address (saddr) equal to %%(==) 10.0.0.1%% are denied. ==== Example 2 - Boolean expressions ==== saddr == 10.0.0.1 && proto == tcp && dport == 80 accept Packets with a source IP address equal to 10.0.0.1, and (&&) an IP protocol (proto) equal to 'tcp' (symbolical name for the integer constant 6), and a TCP destination port (dport) equal to 80 are accepted. Note that the Boolean operator AND (&&) means that all three relational expressions (saddr, proto and dport) have to be true for a packet to match this rule! ==== Examle 3 - Use of parenthesis ==== saddr == 10.0.0.1 && proto == tcp && (dport == 80 || dport == 8080) accept Same as in example 2, but the destination port may be either 80 or 8080 because of the OR-expression (||) at the end. Note that the two relational expressions at the end are placed within parenthesis to get the correct evaluation of the expression. ==== Example 4 - Default "Hi" configuration ==== The rules described in this example are the factory default rules for a unit with an ADSL interface (ip address 192.168.237.238/24, used as outside, configured as "WAN"), two Ethernet interfaces (ip address 192.168.0.1/24 and 192.168.0.20/24 respectively, used as inside) and an USB interface (ip address 192.168.10.1, inside). === Outside incoming supervisor ruleset === [1] saddr == 192.168.20.1/255.255.255.0 || saddr == 192.168.0.1/255.255.255.0 || saddr == 192.168.10.1/255.255.255.0 deny [2] (daddr ==192.168.237.238/255.255.255.255) accept [3] proto == udp && sport == 67 && dport == 68 accept Rule 1 is used for "spoof protection", i.e. to filter out all packets claiming to come from a host on any of the other interfaces. Rule 2 accepts all traffic directly addressed to the interface. Rule 3 accepts traffic from a dhcp server to the dhcp client. DHCP requires a special rule since the interface address isn't known during negotiation, therefore, rule 2 isn't enough to accept the traffic. All other traffic is denied by the default rule. === Outside incoming user ruleset === [1] dport == 5060 && (proto == udp || proto == tcp) accept [2] proto == udp && dport == 68 accept Rule 1 accepts traffic to the SIP server. Rule 2 accepts traffic to the dhcp client. All other traffic is denied by the default rule. === Outside outgoing supervisor ruleset === [1] (saddr ==192.168.237.238/255.255.255.255) accept [2] saddr == 0 && proto == udp && dport == 67 accept Rule 1 accepts all traffic from the interface, i.e. internally generated traffic or NAT:ed traffic. Rule 2 accepts traffic from the dhcp client which uses source address 0.0.0.0 during negotiation. All other traffic is denied by the default rule. === Outside outgoing user ruleset === [1] saddr == 0 && proto == udp && dport == 67 accept [2] saddr != 192.168.237.238/255.255.255.255 modify dynamic source 0 [3] saddr == 192.168.237.238 accept Rule 1 accepts (without setting up any flows) traffic from the dhcp client. Rule 2 is the "NAPT everything" rule, which source NAPTs all traffic not coming from the interface's address, using addresses and ports from NAT pool 0. Rule 3 accepts all internally generated traffic. All other traffic is denied using the default rule. === Inside incoming supervisor ruleset === [1] saddr == 192.168.0.1/255.255.255.0 accept saddr == 0 && proto == udp && dport == 67 accept Rule 1 is used for "spoof protection", i.e. only traffic from the directly connected subnet is allowed. All other traffic is denied using the default rule. === Inside incoming user ruleset === [1] dport == 5060 && daddr != 192.168.0.1 && (proto == tcp || proto == udp) modify static daddr 127.0.0.1 [2] (dport == 21) && daddr != 192.168.0.1 && proto == tcp modify static daddr 192.168.0.1, static dport 8021 [3] dport == 23 && proto == tcp && %%((%%daddr == 192.168.237.238) || (daddr == 192.168.20.1) || (daddr == 192.168.0.1) || (daddr ==192.168.10.1)) deny [4] proto == tcp && (dport == 22 || dport == 25 || dport == 80 || dport == 110 || dport == 119 || dport == 143 || dport == 443 || dport == 8080) accept [5] proto == udp && (dport == 53 || dport == 67 || dport == 123) accept [6] proto == icmp && icmptype == 8 && icmpcode == 0 accept [7] daddr == 192.168.20.1/255.255.255.0 || daddr == 192.168.10.1/255.255.255.0 accept daddr == 192.168.0.1 && %%((%%proto == tcp && (dport == 80 || dport == 5060 || dport == 5320 || dport == 6779)) || (proto == udp && (dport == 5060))) accept [8] (daddr == 192.168.0.1 || daddr == 192.168.0.255) && %%((%%proto == icmp && icmptype == 8 && icmpcode == 0)) accept Rule 1 is a "transparent proxy" rule which redirects all SIP traffic not addressed to the interface to the unit's local address (127.0.0.1). Rule 2 is a "transparent proxy" rule for FTP. Rule 3 is used to explicitly deny Telnet traffic addressed to any of the unit's interfaces. That rule will disappear if administration via Telnet is enabled. Rule 4 accepts all TCP traffic that has been enabled. Rule 5 is rule 4's UDP equivalent. Rule 6 accepts "ping" traffic. Rule 7 is a "catch all" rule which ensures that certain internal services always are accessible (5060 is SIP and 5320 and 6779 are used by the smartcard interface). Rule 8 ensures that the unit always is "pingable". All other traffic is denied using the default rule. === Inside outgoing supervisor ruleset === [1] proto != noproto accept All traffic not using the (non existant) IP protocol "noproto" (254) is accepted. This is a simple and efficient way to "accept everything" === Inside outgoing user ruleset === [1] proto != noproto accept All traffic not using the (non existant) IP protocol "noproto" (254) is accepted. This is a simple and efficient way to "accept everything" Inside log ruleset [1] # log inside (default: accept) [2] (sport == 80 || dport == 80) && (saddr == 192.168.0.1 || daddr == 192.168.0.1) && proto == tcp deny [3] (dport ge 137 && dport le 139) deny Rule 1 is not really a rule, but a comment since everything from the hash mark (#) to the end of the line is ignored. Rule 2 is used to filter out traffic to and from the internal webserver, since it's quite annoying to see that traffic while analysing the firewall log. Rule 3 filters out Windows NetBIOS traffic which otherwise (if Windows machines are connected to the network) would fill up the log in no time! ===== Tutorial ===== Read the [[firewall:tutorial|firewall rules tutorial]] for further explanations and examples of writing your own firewall rules. ===== Syntax reference tables ===== Note: * All numerical values may be written in hexadecimal by adding 0x before the value, e.g. 0x42. * Some values are automatically masked before comparison, this is noted as "Mask: value", where value (of course) is the applied mask. * Where ip addresses and masks are used, symbolical parameters representing an interface's address or mask can be used instead of a value. These are replaced with the current values during the pre-processing stage of the ruleset that takes place just before the rules are parsed and installed. The parameters are enclosed in $(parameter=) as shown in the table below. ^ PDU field ^ Description ^ | proto | IP protocol.Values: 0-255, "icmp" (1), "tcp" (6), "udp" (17), "ipv6" (41), "gre" (47), "esp" (50), "noproto" (254) | | saddr | IP source address. Values: dotted decimal IP-address (1.2.3.4), 0-32 (for prefix lengths) or hostname. Each address may be masked before comparison by appending a slash (/) and a mask in the same format as the address (1.2.3.4/255.0.0.0 or 1.2.3.4/8). | | daddr | IP destination address. Values: see saddr. | | tos | IP type of service (TOS). Values: integer Mask: 0xff | | totlen | IP total length. Values: integer. Mask: 0xffff | | flags | IP flags. Values: integer, "morefrag", "dontfrag", "more_dont". Mask: 0xe0 | | secflag | IP security flag, see RFC 3514. Values:integer, “evil". Mask: 0x1000 | | fragoff | IP fragment offset Values: integer Mask: 0x1fff | | sport | TCP/UDP source port. Values: integer Mask: 0xffff | | dport | TCP/UDP destination port. Values: see sport | | tcpflags | TCP flags. Values: integer, "fin" (0x1), "syn" (0x2), "rst" (0x4), "psh" (0x8), "ack" (0x10), "urg" (0x20), "syn_ack" (0x12) Mask: 0x3f | | icmptotlen | IP total length of ICMP embedded datagram. See totlen. | | icmptype | ICMP type. Values: integer Mask: 0xff | | icmpcode | ICMP code. Values: integer Mask: 0xff | | icmpproto | IP protocol of ICMP embedded datagram. | | icmpsaddr | IP source address of ICMP embedded datagram. | | icmpdaddr | IP destination address of ICMP embedded datagram | | icmptos | IP TOS of ICMP embedded datagram | | icmpflags | IP flags of ICMP embedded datagram | | icmpsecflag | IP security flag of ICMP embedded datagram, see RFC 3514. See secflag. | | icmpfragoff | IP fragment offset of ICMP embedded datagram | | ethertype | Ethernet type.\\ **NB!** Only used in log ruleset. | | ethertype802.3 | Ethernet 802.3 type. Values: integer | | source | Pseudo field for source address and source port. Values: 0\\ **NB!** Only used in modify arguments. | | destination | Pseudo field for destination address and destination port. Values: 0\\ **NB!** Only used in modify arguments. | | etherdaddrhi | Ethernet destination address (high 32 bits). Values: integer. | | etherdaddrlo | Ethernet destination address (low 32 bits). Values: integer. | | ethersaddrhi | Ethernet source address (high 32 bits). Values: integer. | | ethersaddrlo | Ethernet source address (low 32 bits). | | arpop | ARP operation. Values: integer. Mask: 0xffff | | arpethersaddrhi | Ethernet source address (high 32 bits) inside ARP message. Values: integer. | | arpethersaddrlo | Ethernet source address (low 32 bits) inside ARP message. Values: integer. | | arpsaddr | IP source address inside ARP message. See saddr. | | arpetherdaddrhi | Ethernet destination address (high 32 bits) inside ARP message. Values: integer. | | arpetherdaddrlo | Ethernet destination address (low 32 bits) inside ARP message. Values: integer. | | arpdaddr | IP destination address inside ARP message. See saddr. | ^ Actions ^ Description ^ | accept | Accept a packet. Arguments: none. | | deny | Deny a packet. Arguments: none. | | inspect | Creates an active flow in order to inspect matching packets (perform stateful inspection of the traffic). Arguments: none. Since most protocols use bidirectional traffic flows, an inspect-rule can be used instead of two accept-rules (one for each direction) in some instances in order to automatically inspect (accept) traffic in the back direction.\\ **NB!** Only used in user rules. | | modify | Creates an active flow in order to modify matching packets (IP header fields). Implies inspect action. Arguments: static, dynamic and stateless. Each rule only takes one of the argument types, but that type can occur multiple times. Each argument can in turn take one or more sub arguments (see table below).\\ **NB!** If the stateless argument is used (see below), no flow is created and accept is implied instead of inspect!\\ **NB!** Only used in user rules! | ^ Modify arguments ^ Description ^ | static | Static modification of a PDU field. Arguments: the pdu field name and the new value. Pdu field values: saddr, sport, daddr, dport, tos. New values: depend on pdu field type (see table above).\\ Example: static dport 8080 | | dynamic | Dynamic modification of a PDU field. Arguments: pdu field name and a pool id. Pdu fields values: sport, dport, source and destination. Pool id values: 0 (zero). | | stateless | Stateless modification of a PDU field. Creates no flow and therefore does not consume any flow resources, nor performs any inspection. Arguments: same as static. | ^ Operator ^ Description ^ | ==, eq | Equal | | !=, ne | Not Equal | | >, gt | Greater than | | >=, ge | Greater than or equal | | <, lt | Less than | | %%<=%%, le | Less than or equal | | &&, and | And | | %%||%%, or | Or | | / | IP subnet mask specification. Examples: 192.168.0.0/24 or 192.168.0.0/255.255.255.0 | ^ Pre-processor parameters ^ Description ^ | $(net.if.ip=[et1]) | IP address of the et1 interface | | $(net.if.ip=[et2]) | IP address of the et2 interface | | $(net.if.mask=[et1]) | Subnet Mask of the et1 interface | | $(net.if.mask=[et2]) | Subnet Mask of the et2 interface |