The Linux kernel used by fli4l provides a packet filter which controls who is allowed to communicate with or through the Router. Furthermore, things like port forwarding (a packet addressed to the router is forwarded to another internal computer) and masquerading (packets sent from a computer behind the router are changed to look as if they came from the router itself) can be realized.
The structure of the packet filter is shown in Figure 3.1.
Packets arrive over a network interface and pass through the PREROUTING-chain. Here the packets addressed to the router are passed to another computer by changing destination address and destination port. If the packet is addressed to the router it is sent to the INPUT-chain, if not, to the FORWARD-chain. Both chains will check if the packet is permitted. If the packet is accepted, it is delivered to the local destination process or passed via the POSTROUTING-chain (in which packet masquerading is done) to the network interface by which it can reach its target. Locally generated packets are filtered in the OUTPUT-chain and finally (if successfully) also pass through the POSTROUTING-chain to the correct network interface.
With the packet filter configuration, the individual chains of the packet filter can be modified directly. An individual array exists for each chain, one for the INPUT-chain (PF_INPUT_%), one for the FORWARD-chain (PF_FORWARD_%), one for the OUTPUT-chain (PF_OUTPUT_%), one for the PREROUTING-chain (managing port forwarding) (PF_PREROUTING_%), and one for the POSTROUTING-chain, managing packet masquerading (PF_POSTROUTING_%).
An entry in one of these arrays consists mainly of an action (see below) which can be restricted by additional conditions. These conditions relate to properties of the considered packet. A packet contains information about its origin (source PC that has sent the packet), its target (to which PC and which application should the packet be delivered) and much more. Conditions can refer to the following properties of a packet:
If a packet comes in, the entries resp. the resulting rules generated are processed from top to bottom and the first action to which all conditions apply is performed. If none of the rules matches, the default action is executed, which may be specified for (almost) any table.
An entry has the following format, bearing in mind that all restrictions are optional:
restriction{0,} [[source] [destination]] action [BIDIRECTIONAL|LOG|NOLOG]
At all points where networks, IP addresses or hosts need to be specified, you can also refer to IP_NET_%, IP_NET_%_IPADDR or via @hostname to a host from HOST_%. If OPT_DNS is enabled, then outside of actions via @fqdn also hosts which are nicht mentioned in HOST_% can be referenced by their names. This is particularly useful if dealing with external hosts which also possess many (and changing) IP addresses.
The following actions appy:
Some of these actions may be modified in behaviour by using the options BIDIRECTIONAL, LOG or NOLOG. BIDIRECTIONAL generates the same rule a second time with source and destination adresse exchanged (and source and destination port exchanged and/or in- and outbound network interface exchanged if specified). LOG/NOLOG activates resp. deactivates logging for this rule.
Restrictions may be defined by constraints explained in the following sections. You may use any at any place where you don't want restrictions but want/have to specify something. Constraints can be specified in any order if they have a preceding prefix. This applies to all restrictions, except for specifying a source or destination address which must always be placed directly in front of the action, other constraints must be specified before. Restrictions can also be negated, simply prefix them by a !.
Each packet contains source and target informations in a tuple of an IP address and ports.3.2 This source resp. target can serve as a constraint and may be addressed like this:
Expression | Meaning |
ip |
a simple IP address |
network |
a network declaration in the form of <ip>/<netmask> |
port[-port] |
a port resp. a port range |
IP_NET_x_IPADDR |
the IP address of the x router's interface |
IP_NET_x |
the x router's subnet |
IP_ROUTE_x |
the subnet x specified in the route
(default routes can't be used, they would match any and are excluded precautiously) |
@name |
one of the names or aliases set via HOST_%_*; the associated IP address will be filled in here |
<ip oder netzwerk>:port[-port] |
Host- resp. network address in one of the variants above, combined with a port resp. port range |
Example: '192.168.6.2 any DROP'
If two of these lines shine up the first will be considered as source and the second as target. Hence, in this example we drop the packets originating from the computer with the IP address 192.168.6.2, regardless of where they are targeted.
If only one line exists the decision if target or source is meant will be made depending on the value, which is quite easy:
If you would like to shorten the example above you could write
'192.168.6.2 DROP'
. No port is mentioned, hence the constraint
is valid for the source (the machine the packet originated from).
If we were to allow communication with the ssh-deamon, we could
write 'any any:22 ACCEPT'
(packets from any machine to ssh-port
22 of any machine will be accepted) or even shorter '22 ACCEPT'
. Only
a port is mentioned, hence we address the target and thus all packets
targeted to port 22.
For simplification you may append BIDIRECTIONAL to the action to express that the rule is valid for both communication directions. Then rules will be generated with source and target addresses and if applicable ports and network interfaces exchanged while leaving the rest untouched.
Examples:
127.0.0.1 ACCEPT |
local communication (source 127.0.0.1) is allowed | ||
any 192.168.12.1 DROP |
packets to address 192.168.12.1 will be dropped | ||
any 192.168.12.1 DROP LOG |
packets to address 192.168.12.1 will be dropped and logged additionally | ||
any 192.168.12.1 DROP NOLOG |
packets to address 192.168.12.1 will be dropped but not logged | ||
22 ACCEPT |
packets to port 22 (ssh) will be accepted | ||
IP_NET_1_NET ACCEPT |
packets from the subnet connected to the first interface will be accepted | ||
IP_NET_1_NET IP_NET_2_NET |
communication between the subnets connected to the first and second | ||
ACCEPT BIDIRECTIONAL |
interface are allowed |
A rule can be restricted concerning the Interface on which a packet was received resp. will be transmitted. The format is as follows: if:in:out
In the INPUT-chain the interface for outbound packets is not restrictable (the packet does not leave anyway), in the POSTROUTING-chain the interface for received packets is not restrictable, because the informations about it do not exist anymore. Only in the FORWARD-chain constraints for both can be defined.
Possible values for in resp. out:
IP_NET_x_DEV
A rule can be restricted concerning the protocol a packet belongs to. The format is as follows: prot:protocol resp. prot:icmp:icmp-type. protocol can be set to one of the following values:
If such a constraint does not exists, but port numbers should be used in a rule, then the rule is generated twice, once for the tcp and once for the udp protocol.
Via mac:mac-address constraints based on the MAC address may be specified.
fli4l's packet filter gathers informations on the state of connections. This informations can be used to filter packets, i.e let only packets pass that belong to connections already existing. The state of a connection can take this values:3.3
State | Meaning |
INVALID | The packet does not belong to a know connection. |
ESTABLISHED | The packet belongs to a connection, where packets have already been transmitted in both directions. |
NEW | The packet has established a new connection or belongs to a connection that did not have packets transmitted in both directions. |
RELATED | The packet establishes a new connection, but has a relation to an already existing connection (i.e. ftp establishes a separate connection for data transfer). |
States are defined as follows: state:state(s). If you want to specify more than one state they have to be separated by commas. I.e. to let packets pass that belong directly or indirectly to established connections write state:ESTABLISHED,RELATED (this makes sense in INPUT- or FORWARD-chain).
Under certain circumstances you may wish to restrict the frequency of actions, i.e. allow only one ICMP-Echo request per second. This may be reached with limit-constraints, which look like this: limit:Frequency:Burst. The frequency is specified as n/time units (second, minute, hour, day), however, events may also occur in rapid succession (Burst). limit:3/minute:5 for example means that a maximum of three events per minute is allowed, but also five events in rapid succession will be accepted.
To simplify dealing with the packet filter you may summarize rules frequently occuring in templates. Thus, it is possible to provide a wide range of packet filtering rules and combine them in a collection with a symbolic name. Instead of directly using protocols and port numbers, you may then use entries such as tmpl:ssh if you want to use the ssh protocol in a rule. How to deal with templates is shown here using the example of ssh.
If you want to reach your fli4l from the Internet via ssh, write into an entry in the array variable PF_input_% the corresponding service name (here ssh) preceded by tmpl and the action to apply for this service. Example:
PF_INPUT_2='tmpl:ssh ACCEPT'
tmpl: means that the rule should be based on a template. Specify the name of the service after the `:', adapted to our example hence ssh. At last you have to set an action to be bound to the service. Since we want to acces the fli4l over the internet, we allow the connection with ACCEPT. Restrictions for IP-addresses or nets are not provided so the ssh-service will be accessible on all interfaces from all networks. If you want to invoke further restrictions for accessing the ssh-service you may use the packet filter notation already explained above.
For which services rules are predefined (e.g. templates exist) can be seen
in the template file at opt/etc/fwrules.tmpl/templates
. A list in a table
follows (see table 3.8).
Template | Protocol | Port(s) |
dhcp | udp | 67-68 |
dns | tcp/udp | 53 |
elster | tcp | 159.154.8.2:21 |
elster | tcp | 159.154.8.35:21 |
elster | tcp | 193.109.238.26:8000 |
elster | tcp | 193.109.238.27:8000 |
elster | tcp | 193.109.238.58:80 |
elster | tcp | 193.109.238.59:80 |
elster | tcp | 62.157.211.58:8000 |
elster | tcp | 62.157.211.59:8000 |
elster | tcp | 62.157.211.60:8000 |
elster | tcp | 80.146.179.2:80 |
elster | tcp | 80.146.179.3:80 |
ftp | tcp | 21 |
http | tcp | 80 |
https | tcp | 443 |
hylafax | tcp | 4559 |
imap | tcp | 143 |
imaps | tcp | 993 |
imond | tcp | 5000 |
ipmi | tcp | 22 |
ipmi | tcp | 2937 |
ipmi | tcp | 443 |
ipmi | tcp | 5120 |
ipmi | tcp | 5123 |
ipmi | tcp | 5900 |
ipmi | tcp | 5901 |
ipmi | tcp | 80 |
ipmi | tcp | 8889 |
ipmi | udp | 623 |
irc | tcp | 6667 |
ldap | tcp/udp | 389 |
tcp | 110 | |
tcp | 143 | |
tcp | 25 | |
tcp | 465 | |
tcp | 587 | |
tcp | 993 | |
tcp | 995 | |
mysql | tcp | 3306 |
nfs | tcp/udp | 111 |
nfs | tcp/udp | 2049 |
nntp | tcp | 119 |
ntp | udp | 123 |
oracle | tcp | 1521 |
pcanywhere | tcp | 5631-5632 |
ping | icmp:0 | |
ping | icmp:8 | |
pop3 | tcp | 110 |
pop3s | tcp | 995 |
privoxy | tcp | 8118 |
proxmox | tcp | 8006 |
proxmox | tcp | 5900 |
proxmox | tcp | 3128 |
rdp | tcp | 3389 |
rsync | tcp | 873 |
samba | tcp | 139 |
samba | tcp | 445 |
samba | udp | 137-138 |
sip | tcp/udp | 5060-5061 |
smtp | tcp | 25 |
snmp | tcp/udp | 161 |
socks | tcp | 1080 |
squid | tcp | 3128 |
ssh | tcp | 22 |
ssmtp | tcp | 465 |
submission | tcp | 587 |
svn | tcp | 3690 |
syslog | udp | 514 |
teamspeak | tcp | 14534 |
teamspeak | tcp | 51234 |
teamspeak | udp | 8767 |
telmond | tcp | 5001 |
telnet | tcp | 23 |
teredo | udp | 3544 |
tftp | udp | 69 |
time | tcp/udp | 37 |
traceroute | udp | 33404-33464 |
vdr | tcp | 6419 |
vnc | tcp | 5900 |
whois | tcp | 43 |
xbl | tcp/udp | 3074 |
xbl | udp | 88 |
xmppclient | tcp | 5222 |
xmppserver | tcp | 5269 |
The Syntax for this kind of packet filter rules is
tmpl:<Name of the service> <Constraint> <Action>
<Constraint>
allows everything mentioned at 3.10.2.
Possible values for <Action>
are listed and described
in 3.10.1.
Some more examples should clarify the process. At first let's have a look at PF_PREROUTING:
PF_PREROUTING_N='2' PF_PREROUTING_1='tmpl:xbl dynamic DNAT:@xbox' PF_PREROUTING_2='tmpl:https dynamic DNAT:192.168.193.250'
The rule PF_PREROUTING_1 supplies the Xbox with everything necessary for Xbox Live. By the use of tmpl:xbl all ports and protocols used for Xbox Live will be forwarded to the xbox. Instead of using an IP address we use an entry from the HOST_%_NAME-array. dynamic tells the fli4l to forward all ports from the internet interface.
The second rule forwards the https-protocol to a webserver in a DMZ (Demilitarized Zone).
No let's have a look at PF_INPUT:
PF_INPUT_N='3' PF_INPUT_1='if:IP_NET_1_DEV:any ACCEPT' PF_INPUT_2='if:pppoe:any prot:tcp 113 ACCEPT' PF_INPUT_3='if:br0:any tmpl:dns @xbox IP_NET_1_IPADDR ACCEPT'
The first rule allows access to the router for everyone from the net defined in IP_NET_1. The second rule opens the ident-port needed for package oident. The third rule allows the xbox to access fli4l's DNS server. Notice the use of a host alias here.
PF_FORWARD and PF_POSTROUTING do not provide tmpl-specific content.
It is also possible to create templates yourself or for other packages to
provide their own ones. To create a template you only need to create a text
file with the rules in it and name it like the template. For a private template
file use the directory etc/fwrules.tmpl
(create it if necessary) under
your config directory as shown in picture 3.2.
Package developers or users needing templates for more than one configuration
may place their template files directly in opt/etc/fwrules.tmpl.
The templates in the user's config directory override other settings, though.
The templates included in fli4l will be interpreted as the last ones. This enables you to
override fli4l's templates when providing templates by
the same name in your config-directory.
If, for example you like to create the template vpn_friends, create a file by the name vpn_friends. The template should contain the services ssh, smtp, dns and samba. Hence you write the following to vpn_friends:
prot:tcp 22 prot:tcp 25 53 prot:udp 137-138 prot:tcp 139 prot:tcp 445
Every time you use the template vpn_friends rules will be
created for all contained protocols and ports.
PF_FORWARD_x='tmpl:vpn_friends ACCEPT'
will create theses
FORWARD-rules:
prot:tcp 22 ACCEPT prot:tcp 25 ACCEPT 53 ACCEPT prot:udp 137-138 ACCEPT prot:tcp 139 ACCEPT prot:tcp 445 ACCEPT
The packet filter is mainly configured by four array-variables:
For all chains following applies the setting of the protocol level in PF_LOG_LEVEL, which may be set to one of these values: debug, info, notice, warning, err, crit, alert, emerg.
The INPUT-chain defines who is allowed to access the router. If no rule of the INPUT-chain matches, the default action handles the packet and the protocol variable decides wheter a rejection will be written to the system-protocol or not.
The following restrictions apply to the parameters:
If you want to configure the router's behaviour completely yourself you may enter `no' here but you will have to define all rules on your own then. An equivalent to the default behaviour would look like this (the explanation of user defined chains can be found here):
PF_INPUT_ACCEPT_DEF='no' # # limit ICMP echo requests - use a separate chain # PF_USR_CHAIN_N='1' PF_USR_CHAIN_1_NAME='usr-in-icmp' PF_USR_CHAIN_1_RULE_N='2' PF_USR_CHAIN_1_RULE_1='prot:icmp:echo-request length:0-150 limit:1/second:5 ACCEPT' PF_USR_CHAIN_1_RULE_2='state:RELATED ACCEPT' PF_INPUT_N='4' PF_INPUT_1='prot:icmp usr-in-icmp' PF_INPUT_2='state:ESTABLISHED,RELATED ACCEPT' PF_INPUT_3='if:lo:any ACCEPT' PF_INPUT_4='state:NEW 127.0.0.1 DROP BIDIRECTIONAL'
The first rule branches to the rate limited ``usr-in-icmp''-chain.
The second only accepts packets belonging to established connections
(packets that have either the state ESTABLISHED or
RELATED), and the third one allows local communication
(if:lo:any ACCEPT
). The fourth filters packets that pretend to
be local communication but are not accepted by the rules defined before.
If you work with OpenVPN, the rules have to be enhanced to enable packets used by the chains there.
PF_INPUT_N='5' ... PF_INPUT_5='ovpn-chain'
By using the FORWARD-chain will be configured which packets are forwarded by the router. If no rule of the FORWARD-chain matches, the default action handles the packet and the protocol variable decides wheter a rejection will be written to the system-protocol or not.
With the used parameters the restriction applies that only the actions ACCEPT, DROP and REJECT are allowed.
'state:ESTABLISHED,RELATED ACCEPT'
,
aswell as a rule to drop packets of unknown state:
'state:INVALID DROP'
.
and at last a rule to drop packets with faked IP addresses:
'state:NEW 127.0.0.1 DROP BIDIRECTIONAL'
.
In addition the other subsystems will generate some default rules - a configuration without default rules with port forwarding and OpenVPN would contain at least the following rules:
PF_FORWARD_ACCEPT_DEF='no' PF_FORWARD_N='5' PF_FORWARD_1='state:ESTABLISHED,RELATED ACCEPT' PF_FORWARD_2='state:INVALID DROP' PF_FORWARD_3='state:NEW 127.0.0.1 DROP BIDIRECTIONAL' PF_FORWARD_4='pfwaccess-chain' PF_FORWARD_5='ovpn-chain'
The OUTPUT-chain configures what the router is allowed to access. If no rule of the OUTPUT-chain matches, the default action handles the packet and the protocol variable decides wheter a rejection will be written to the system-protocol or not.
With the used parameters the following restrictions apply:
If you want to configure the router's behaviour completely yourself you may enter `no' here but you will have to define all rules on your own then. An equivalent to the default behaviour would look like this:
PF_OUTPUT_ACCEPT_DEF='no' PF_OUTPUT_N='1' PF_OUTPUT_1='state:ESTABLISHED,RELATED ACCEPT'
This single rule accepts only packets belonging to established connections (e.g. packets of the state ESTABLISHED or RELATED).
In several cases you may want to establish own chains to filter packets in detail there. These chains can be defined and filled with rules via PF_USR_CHAIN_%. The names of the chains have to start with usr- and after their definition can be used everywhere in the INPUT- or FORWARD-chain as actions. The ICMP-filter chain used before will serve as an example here:
PF_USR_CHAIN_N='1' # # create usr-in-icmp # PF_USR_CHAIN_1_NAME='usr-in-icmp' # # add rule to usr-in-icmp # PF_USR_CHAIN_1_RULE_N='2' PF_USR_CHAIN_1_RULE_1='prot:icmp:echo-request length:0-150 limit:1/second:5 ACCEPT' PF_USR_CHAIN_1_RULE_2='state:RELATED ACCEPT' # # use chain in PF_INPUT # PF_INPUT_2='prot:icmp usr-in-icmp'
Packets still can be changed after the routing decision. For example they
may get a new target address to be forwarded to another computer (port
forwarding) or a new source address may be inserted to mask the network
behind the router. Masquerading is used i.e. to provide internet access
for a private net over one public IP or a in DMZ-setup to hide the structure
of the local net from computers in the DMZ.
Configuration is done with two chains, PREROUTING- and
POSTROUTING-chain.
By the POSTROUTING-chain the
packets are defined that have to be masked by the router. If no rule of
the POSTROUTING-chain matches, the packets will be forwarded unmasked.
Two variants exist for masquerading: one for network interfaces that do get an IP address allocated on dialin (MASQUERADE) and one for network interfaces with static IP address (SNAT). SNAT in addition expects the source IP address to be inserted into the packet. It may be specified as an:
For both SNAT and MASQUERADE a port or port range may be set to which the source port may be redirected. Usually this notation is necessary because the kernel can choose the ports on its own. But there exist applications that desire the source port unchanged (and thus require 1:1-NAT) or which forbid PAT (Port Address Translation) or NAPT (Network Address and Port Translation). The port range is simply added to the end, like this: SNAT:IP_NET_1_IPADDR:4000-8000.
With the POSTROUTING-chain only ACCEPT, SNAT, NETMAP and MASQUERADE may be used as actions.
The PREROUTING-chain configures which packets should be transferred to another computer. If no rule of the PREROUTING-chain matches the packets will be processed further without changes. The action DNAT expects the IP address to be inserted as the target address. It may be specified as an:
At last a port or port range may be set to which the target port may be redirected. This is only necessary if the target port should be changed. The port (range) is simply added to the end, like this: DNAT:@server:21.
REDIRECT behaves like DNAT, except for that the Destination IP address is always set to the (primary) IP address of the interface on which the packet came in so the packet is delivered locally. This is needed i.e. for transparent proxies, see OPT_TRANSPROXY.
If you want a port forwarded to an interface with a dynamic address you do not know to which IP the packet should be sent (at the time of configuration). Thus you can use dynamic in the PREROUTING-chain as a wildcard for the IP address assigned later on, like this:
'dynamic:80 DNAT:1.2.3.4' # forward http-packets to # IP address 1.2.3.4 'prot:gre any dynamic DNAT:1.2.3.4' # forward gre-packets (part of the PPTP- # protocol) to IP address 1.2.3.4
Only ACCEPT, DNAT, NETMAP and REDIRECT may be used as actions with the PREROUTING-chain.
For further examples on port forwarding see the next paragraph.
Below see some examples of the packet filter configuration.
fli4l's default configuration for the INPUT-chain looks like this:
PF_INPUT_POLICY='REJECT' PF_INPUT_ACCEPT_DEF='yes' PF_INPUT_LOG='no' PF_INPUT_N='1' PF_INPUT_1='IP_NET_1 ACCEPT'
By this we accomplish that
PF_INPUT_1='IP_NET_1 ACCEPT'
),
PF_INPUT_ACCEPT_DEF='yes'
),
PF_INPUT_ACCEPT_DEF='yes'
),
PF_INPUT_POLICY='REJECT'
),
PF_INPUT_LOG='no'
).
The FORWARD-chain looks alike: Only packets of our local net and packets belonging to connections that were established by machines in our local net should be forwarded. In addition NetBIOS- and CIFS-packets will be dropped.
PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' PF_FORWARD_N='2' PF_FORWARD_1='tmpl:samba DROP' PF_FORWARD_2='IP_NET_1 ACCEPT'
Note the dependance on the order of rules: At first the NetBIOS-packets are dropped and afterwards the packets of the local net are accepted.
The local net may communicate with the router, its packets get forwarded, only the masking which is necessary for the internet access of a local network is still missing:
PF_POSTROUTING_N='1' PF_POSTROUTING_1='IP_NET_1 MASQUERADE'
If we do want to have several local subnets which should communicate with each other free and unmasked we have to ensure that packets between those nets don't get dropped or masked. In order to achieve this we add a rule or edit the existing one.
Let's assume we have a DSL connection over PPPoE and the two subnets are IP_NET_1 (192.168.6.0/24) and IP_NET_2 (192.168.7.0/24). In this case the configuration would be as follows:
PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' PF_FORWARD_N='4' PF_FORWARD_1='IP_NET_1 IP_NET_2 ACCEPT BIDIRECTIONAL' PF_FORWARD_2='tmpl:samba DROP' PF_FORWARD_3='IP_NET_1 ACCEPT' PF_FORWARD_4='IP_NET_2 ACCEPT' PF_POSTROUTING_N='3' PF_POSTROUTING_1='IP_NET_1 IP_NET_2 ACCEPT BIDIRECTIONAL' PF_POSTROUTING_2='IP_NET_1 MASQUERADE' PF_POSTROUTING_3='IP_NET_2 MASQUERADE'
The first rule ensures forwarding of packets between both subnets without further processing. The third and fourth rule ensure that both subnets also have Internet access. The first rule of the POSTROUTING-chain provides unmasked communication between both subnets.
In other words we could say that only packets transferred over the pppoe-interface have to be masked:
PF_POSTROUTING_N='1' PF_POSTROUTING_1='if:any:pppoe MASQUERADE'
We could as well have restricted the port filtering to the pppoe-interface and combined both subnets to one, as seen here:
PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' PF_FORWARD_N='2' PF_FORWARD_1='if:any:pppoe tmpl:samba DROP' PF_FORWARD_2='192.168.6.0/23 ACCEPT' PF_POSTROUTING_N='1' PF_POSTROUTING_1='if:any:pppoe MASQUERADE'
Packets going out over the pppoe-interface and those addressed to udp-ports 137-138 or to tcp-ports 139 and 445 will be dropped (rule 1), all other packets from subnet 192.168.6.0/23 will be forwarded (rule 2).
Let's add a net 10.0.0.0/24 (i.e. a dial-in network) which we want to communicate with unmasked, but packets to udp-ports 137-138 and to tcp-Ports 139 and 445 should be dropped:
PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' PF_FORWARD_N='4' PF_FORWARD_1='IP_NET_1 IP_NET_2 ACCEPT BIDIRECTIONAL' PF_FORWARD_2='tmpl:samba DROP' PF_FORWARD_3='192.168.6.0/23 ACCEPT' PF_FORWARD_4='10.0.0.0/24 ACCEPT' PF_POSTROUTING_N='2' PF_POSTROUTING_1='10.0.0.0/24 ACCEPT BIDIRECTIONAL' PF_POSTROUTING_2='192.168.6.0/23 MASQUERADE'
PF_FORWARD_ACCEPT_DEF='yes'
.
An alternative:
PF_POSTROUTING_N='1' PF_POSTROUTING_1='if:any:pppoe MASQUERADE'
This rule enables masking only for packets going out over the pppoe-interface.
Blacklists (a machine in this list is forbidden to do something) and Whitelists (a machine in this list is allowed to do something) are defined in a very similarl way. Rules are written that are very special at the beginning and to the end are becoming more universal. With a blacklist rules are defined that at the beginning forbid something and at the end allow something to all not previously mentioned. With a Whitelist it is exactly the other way round.
Example 1: All machines in subnet 192.168.6.0/24 except number 12 are allowed to access the Internet as long as they don't use CIFS Ports 137-138 (udp), 139 and 445 (tcp) to communicate:
PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' PF_FORWARD_N='3' PF_FORWARD_1='192.168.6.12 DROP' PF_FORWARD_2='tmpl:samba DROP' PF_FORWARD_3='192.168.6.0/23 ACCEPT' PF_POSTROUTING_N='1' PF_POSTROUTING_2='192.168.6.0/24 MASQUERADE'
Example 2: Only machine 12 has Internet access (with exception of the ports mentioned above...), all others are only allowed to communicate with another local subnet:
PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' PF_FORWARD_N='3' PF_FORWARD_1='192.168.6.0/24 192.168.7.0/24 ACCEPT BIDIRECTIONAL' PF_FORWARD_2='tmpl:samba DROP' PF_FORWARD_3='192.168.6.12 ACCEPT' PF_POSTROUTING_N='1' PF_POSTROUTING_1='if:any:pppoe MASQUERADE'
# # Access to the router # PF_INPUT_POLICY='REJECT' PF_INPUT_ACCEPT_DEF='yes' PF_INPUT_LOG='no' PF_INPUT_N='1' PF_INPUT_1='IP_NET_1 ACCEPT' # all hosts of the local net are allowed # to access the router # # Internet access # PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' PF_FORWARD_N='2' PF_FORWARD_1='tmpl:samba DROP' # Samba-packets, that want to leave the # net are dropped PF_FORWARD_2='IP_NET_1 ACCEPT' # all other packets are allowed # to leave the local net # # Maskieren des lokalen Netzes # PF_POSTROUTING_N='1' PF_POSTROUTING_1='IP_NET_1 MASQUERADE' # mask packets leaving the # subnet
# # Access to the router # PF_INPUT_POLICY='REJECT' PF_INPUT_ACCEPT_DEF='yes' PF_INPUT_LOG='no' PF_INPUT_N='2' PF_INPUT_1='IP_NET_1 ACCEPT' # all hosts of the local net are allowed # to access the router PF_INPUT_2='IP_NET_2 ACCEPT' # all hosts of the local net are allowed # to access the router # # Internet access # PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' # # Free communication between the nets # PF_FORWARD_N='4' PF_FORWARD_1='IP_NET_1 IP_NET_2 ACCEPT BIDIRECTIONAL' PF_FORWARD_2='tmpl:samba DROP' # Samba-packets, that want to leave the # net are dropped PF_FORWARD_3='IP_NET_1 ACCEPT' # all other packets are allowed # to leave the local net PF_FORWARD_4='IP_NET_2 ACCEPT' # all other packets are allowed # to leave the local net # # Masking of local nets, unmasked communication between those nets # PF_POSTROUTING_N='3' PF_POSTROUTING_1'IP_NET_1 IP_NET_2 ACCEPT BIDIRECTIONAL' PF_POSTROUTING_2='IP_NET_1 MASQUERADE' # mask packets leaving the # subnet PF_POSTROUTING_3='IP_NET_2 MASQUERADE' # mask packets leaving the # subnet
# # Access to the router # PF_INPUT_POLICY='REJECT' PF_INPUT_ACCEPT_DEF='yes' PF_INPUT_LOG='no' PF_INPUT_N='4' PF_INPUT_1='IP_NET_1 ACCEPT' # all hosts of the local net are allowed # to access the router PF_INPUT_2='IP_NET_2 ACCEPT' # all hosts of the local net are allowed # to access the router PF_INPUT_3='tmpl:ssh ACCEPT' # allow access to the SSH service # from everywhere PF_INPUT_4='tmpl:http 1.2.3.4/24 ACCEPT' # allow machines from # a defined subnet access to the # HTTP service # # Internet access # PF_FORWARD_POLICY='REJECT' PF_FORWARD_ACCEPT_DEF='yes' PF_FORWARD_LOG='no' # # No communication between the nets, both nets have # Internet access, Samba-packets are dropped # PF_FORWARD_N='2' PF_FORWARD_1='tmpl:samba if:any:pppoe DROP' # Samba-packets, that want to leave the # net are dropped PF_FORWARD_2='if:any:pppoe ACCEPT' # all other packets are allowed # to leave the local net # # Masking of local nets, unmasked communication between those nets # PF_POSTROUTING_N='1' PF_POSTROUTING_1='if:any:pppoe MASQUERADE' # mask packets leaving the # subnet
Port forwarding can be accomplished with the PREROUTING-rules like
this (TARGET
refers to the original target address (optional) and
the original target port, NEW_TARGET
refers to the new target address
and new target port (optional), PROTOCOL
refers to the protocol in use):
TARGET='<port>' NEW_TARGET='<ip>' PROTOCOL='<proto>' PF_PREROUTING_x='prot:<proto> dynamic:<port> DNAT:<ip>' TARGET='<port1>-<port2>' NEW_TARGET='<ip>' PROTOCOL='<proto>' PF_PREROUTING_x='prot:<proto> dynamic:<port1>-<port2> DNAT:<ip>' TARGET='<ip>:<port-a>' NEW_TARGET='<ip>:<port-b>' PROTOCOL='<proto>' PF_PREROUTING_x='prot:<proto> any <ip>:<port-a> DNAT:<ip>:<port-b>'
PF_FORWARD_x='IP_NET_1 ACCEPT'does not exist (FORWARD).
Example 1: Let's assume we only have one net IP_NET_1,
a squid proxy is running there on a host by the name of proxy and
the whole http-traffic should be processed by it. Squid listens
on port 3128. For simplicity we refer via @proxy to the host
entered in HOST_1_NAME='proxy'
(see
Domain Configuration).
Here are the resulting rules:
... PF_PREROUTING_x='@proxy ACCEPT' # packets from the proxy should not be redirected PF_PREROUTING_x='prot:tcp IP_NET_1 80 DNAT:@proxy:3128' # HTTP-packets from IP_NET_1 will be redirected to @proxy, Port 3128 # independet of the target PF_POSTROUTING_x='any @proxy:3128 SNAT:IP_NET_1_IPADDR' # change all packets to port 3128 in a way as if they came from # fli4l (IP_NET_1_IPADDR) PF_FORWARD_x='prot:tcp @proxy 80 ACCEPT' # let HTTP-packets from the proxy pass the FORWARD-chain (if necessary) ...
If more nets or conflicting port forwardings (which are also DNAT-rules) exist, the rules may have to be more differentiated.
Example 2: Our proxy by the name of proxy resides in IP_NET_1, listens to port 3128 and should only serve clients from IP_NET_1. IP_NET_1 is reachabel over IP_NET_1_DEV. Packets from other nets should not be considered.
... PF_PREROUTING_x='if:IP_NET_1_DEV:any !@proxy 80 DNAT:@proxy:3128' # Redirect queries to the HTTP-port that do not emerge from the proxy but # come in on an internal interface (IP_NET_1_DEV) to the proxy's port. # At this point it is important to check with if:IP_NET_1_DEV:any that the # packets are coming from inside because otherwise packets from outside # would also be redirected (security breakage) PF_POSTROUTING_x='prot:tcp IP_NET_1 @proxy:3128 SNAT:IP_NET_1_IPADDR' # Change HTTP-packets originating from IP_NET_1 and destinated to proxy-port 3128 # in a way as if they came from fli4l (IP_NET_1_IPADDR) PF_FORWARD_x='prot:tcp @proxy 80 ACCEPT' # let HTTP-packets from the proxy pass the FORWARD-chain (if necessary) ...
Example 3: To ease our live and shorten the rules we may use templates (see Using Templates With The Packet Filter). At this point tmpl:http, translated in prot:tcp any any:80 is of advantage. tmpl:http IP_NET_1 DNAT:@proxy:3128 then changes to prot:tcp IP_NET_1 80 DNAT:@proxy:3128.
Both IP_NET_1 and IP_NET_2 should be redirected transparently over the proxy. Simplified you could write:
... PF_PREROUTING_x='tmpl:http @proxy ACCEPT' # HTTP-packets from the proxy should not be redirected PF_PREROUTING_x='tmpl:http IP_NET_1 DNAT:@proxy:3128' # HTTP-packets from IP_NET_1 should be redirected PF_PREROUTING_x='tmpl:http IP_NET_2 DNAT:@proxy:3128' # HTTP-packets from IP_NET_2 should be redirected PF_POSTROUTING_x='IP_NET_1 @proxy:3128 SNAT:IP_NET_1_IPADDR' PF_POSTROUTING_x='IP_NET_2 @proxy:3128 SNAT:IP_NET_2_IPADDR' PF_FORWARD_x='tmpl:http @proxy ACCEPT' ...
You may continue here forever...
fli4l may also serve to build a DMZ. As this is only another additional ruleset for the router please refer to the wiki at https://ssl.nettworks.org/wiki for the time being.
Using IP-Masquerading has the advantage that a bunch of machines in the LAN can be routed over only one official IP-address. However, there are also disadvantages that you have to take into account.
A big problem for example is that no machine from outside can contact the machines in the LAN. This may be desired for security reasons but certain protocols will not work anymore because they require a connection from outside.
A classic example is FTP. Beside a communication channel to exchange commands and answers another channel is needed (an IP-port) to transfer the actual data. fli4l uses certain conntrack-helpers for this in order to open such ports instantaneously and redirect them to the machine in question when needed. The conntrack-helper ``listens'' to the data stream to recognize when such an additional port is needed.
Typical applications for conntrack-helpers are i.e. chat-protocols and Internet games.
Conntrack-helper are activated over rules in two special arrays. The array PF_PREROUTING_CT_% contains helper-assignments to packets coming from outside, the array PF_OUTPUT_CT_% contains helper-assignments to packets generated on the router. Some practical examples help to illustrate this.
Example 1: If active FTP from the LAN should be allowed this is, from the router's view, a connection from outside the router, thus an entry in PF_PREROUTING_CT_% has to be created:
PF_PREROUTING_CT_N='1' PF_PREROUTING_CT_1='tmpl:ftp IP_NET_1 HELPER:ftp'
The ftp-helper module will be loaded for all TCP connections from the local network (IP_NET_1) to any other addresses' port 21 (which is the ftp-Port). This module will allow the FTP server to establish a data transfer connection back to the client during this connection by opening a ``hole'' in the firewall temporarily.
Example 2: If you want to enable passive ftp for a FTP server on the LAN (the data connection is established from the outside to the inside, so that a hole in the firewall must be opened here as well), this is also seen as a connection from outside by the router. Here we see the rule as for this:
PF_PREROUTING_CT_N='1' PF_PREROUTING_CT_1='tmpl:ftp any dynamic HELPER:ftp'
By this rule it is expressed that all FTP connections to the dynamic address of the router are associated to the FTP conntrack helper. Here dynamic was used because it is assumed that the router is responsible for dialing in to the Internet and thus has an external IP address. If the router performs dial-in via DSL, the rule can also be written as:
PF_PREROUTING_CT_N='1' PF_PREROUTING_CT_1='tmpl:ftp if:pppoe:any HELPER:ftp'
By this rule it is expressed that all FTP connections coming from the DSL interface (pppoe) are associated to the conntrack helper.
If the router is not dialing, but e.g. is behind another router (Fritz! box, cable modem, a.s.o.) the following rules can be used:
PF_PREROUTING_CT_N='1' PF_PREROUTING_CT_1='tmpl:ftp if:IP_NET_2_DEV:any HELPER:ftp'
It is assumed in the Example, that the connection to the other router is performed over the interface associated with the second subnet (IP_NET_2_DEV).
Remember that of course an additional configuration of the FORWARD-chain is needed to really forward the FTP-packets. A typical rule would be
PF_PREROUTING_1='tmpl:ftp any dynamic DNAT:@ftpserver'
assuming that the host running the FTP-server has the name ftpserver.
Example 3: If you like to use active FTP directly from fli4l (perhaps with the help of the ftp program from the Tools-package) the firewall has to be prepared, this time in the OUTPUT-chain by using the array PF_output_CT_%:
PF_OUTPUT_CT_N='1' PF_OUTPUT_CT_1='tmpl:ftp HELPER:ftp'
This rule is not necessary if FTP_PF_ENABLE_ACTIVE='yes'
is used - see the documentation for the ftp-OPT in
the tools-package.
Following is an overview over the existing conntrack-helpers:
Helper | Explanation |
ftp | File Transfer Protocol |
h323 | H.323 (Voice over IP) |
irc | Internet Relay Chat |
pptp | PPTP Masquerading (By the use of this module it is possible to run more than one PPTP-Client behind the fli4l router at the same time.) |
sip | Session Initiation Protocol |
sane | SANE Network Procotol |
snmp | Simple Network Management Protocol |
tftp | Trivial File Transfer Protocol |
Here is an overview over the variables to configure: