FreeS/WAN, or other IPSEC implementations, frequently run on gateway machines, the same machines running firewall or packet filtering code. This document discusses the relation between the two.
IPSEC uses three main types of packet:
IPSEC processing of incoming packets authenticates them then removes the ESP or AH header and decrypts if necessary. Successful processing exposes an inner packet which is then delivered back to the firewall machinery, marked as having arrived on an ipsec[0-3] interface. Firewall rules can use that interface label to distinguish these packets from unencrypted packets which are labelled with the physical interface they arrived on (or perhaps with a non-IPSEC virtual interface such as ppp0).
Some protocols, such as TCP and UDP, have the notion of ports. Others protocols, including ESP and AH, do not. Quite a few IPSEC newcomers have become confused on this point. There are no ports in the ESP or AH protocols, and no ports used for them. For these protocols, the idea of ports is completely irrelevant.
The protocol numbers for ESP or AH are used in the 'next header' field of the IP header. On most non-IPSEC packets, that field would have one of:
Each header in the sequence tells what the next header will be. IPSEC adds headers for ESP or AH near the beginning of the sequence. The original headers are kept and the 'next header' fields adjusted so that all headers can be correctly interpreted.
For example, using [ ] to indicate data protected by ESP and unintelligible to an eavesdropper between the gateways:
Part of the ESP header itself is encrypted, which is why the [ indicating protected data appears in the middle of some lines above. The next header field of the ESP header is protected. This makes traffic analysis more difficult. The next header field would tell an eavesdropper whether your packet was UDP to the gateway, TCP to the gateway, or encapsulated IP. It is better not to give this information away. A clever attacker may deduce some of it from the pattern of packet sizes and timings, but we need not make it easy.
IPSEC allows various combinations of these to match local policies, including combinations that use both AH and ESP headers or that nest multiple copies of these headers.
For example, suppose my employer has an IPSEC VPN running between two offices so all packets travelling between the gateways for those offices are encrypted. If gateway policies allow it (The admins could block UDP 500 and protocols 50 and 51 to disallow it), I can build an IPSEC tunnel from my desktop to a machine in some remote office. Those packets will have one ESP header throughout their life, for my end-to-end tunnel. For part of the route, however, they will also have another ESP layer for the corporate VPN's encapsulation. The whole header scheme for a packet on the Internet might be:
The first ESP (outermost) header is for the corporate VPN. The inner ESP header is for the secure machine-to-machine link.
As a consequence of the above, an IPSEC gateway should have packet filters that allow the following protocols when talking to other IPSEC gateways:
The preceeding paragraph deals with packets addressed to or sent from your gateway. It is a separate policy decision whether to permit such packets to pass through the gateway so that client machines can build end-to-end IPSEC tunnels of their own. This may not be practical if you are using NAT (IP masquerade) on your gateway, and may conflict with some corporate security policies. Other than that, it is likely a good idea.
It is possible to use firewall rules to restrict UDP 500, ESP and AH packets so that these packets are accepted only from known gateways. This is not strictly necessary since FreeS/WAN will discard packets from unknown gateways. You might, however, want to do it for any of a number of reasons. For example:
It is not possible to use only static firewall rules for this filtering if you do not know the other gateways' IP addresses in advance, for example if you have "road warriors" who may connect from a different address each time or if want to do opportunistic encryption to arbitrary gateways. In these cases, you can accept UDP 500 IKE packets from anywhere, then use the updown script feature of pluto(8) to dynamically adjust firewalling for each negotiated tunnel.
Firewall packet filtering does not much reduce the risk of a denial of service attack on FreeS/WAN. The firewall can drop packets from unknown gateways, but KLIPS does that quite efficiently anyway, so you gain little. The firewall cannot drop otherwise legitmate packets that fail KLIPS authentication, so it cannot protect against an attack designed to exhaust resources by making FreeS/WAN perform many expensive authentication operations.
In summary, firewall filtering of IPSEC packets from unknown gateways is possible but not strictly necessary.
When the IPSEC gateway is also acting as your firewall, other packet filtering rules will be in play. In general, those are outside the scope of this document. See our Linux firewall links for information. There are a few types of packet, however, which can affect the operation of FreeS/WAN or of diagnostic tools commonly used with it. These are discussed below.
ICMP is the Internet Control Message Protocol. It is used for messages between IP implementations themselves, whereas IP used is used between the clients of those implementations.
ICMP handling is tricky for firewalls. You definitely want some ICMP messages to get through; things won't work without them. On the other hand, you do equally definitely do not want untrusted folk sending arbitrary control messages to your machines.
ICMP does not use ports. Messages are distinguished by a "message type" field and, for some types, by an additiona; "code" field. The definitive list of types and codes is on the IANA site.
One expert uses this definition for ICMP message types to be dropped at the firewall.
# ICMP types which lack socially redeeming value. # 5 Redirect # 9 Router Advertisement # 10 Router Selection # 15 Information Request # 16 Information Reply # 17 Address Mask Request # 18 Address Mask Reply badicmp='5 9 10 15 16 17 18'
A more conservative approach would be to make a list of allowed types and drop everything else.
Whichever way you do it, your ICMP filtering rules on a FreeS/WAN gateway should allow at least the following ICMP packet types:
It is fairly common for firewalls to drop ICMP echo packets addressed to machines behind the firewall. If that is your policy, please create an exception for such packets arriving via an IPSEC tunnel, at least during intial testing of those tunnels.
The traceroute(1) utility uses UDP port numbers from 33434 to approximately 33633. Generally, these should be allowed through for troubleshooting.
Some firewalls drop these packets to prevent outsiders exploring the protected network with traceroute(1). If that is your policy, consider creating an exception for such packets arriving via an IPSEC tunnel, at least during intial testing of those tunnels.
Network Address Translation is a method of allocating IP addresses dynamically, typically in circumstances where the total number of machines which need to access the Internet exceeds the supply of IP addresses.
Any attempt to perform NAT operations on IPSEC packets between the IPSEC gateways creates a basic conflict:
This problem can be avoided by having the IPSEC gateway on the Internet side of the machine which handles NAT. This can be done physically with two machines, or logically with one machine performing both functions.
In pictures, using SG to indicate FreeS/WAN or other IPSEC Security Gateways, these configurations work fine and are commonly used:
clients --- NAT ----- SG ---------- SG two machines clients --- NAT/SG -----------------SG one machine
We recommend not trying to build IPSEC connections which pass through a NAT machine. This does not work:
clients --- SG --- NAT ---------- SG
It is possible to make this work sometimes, but it cannot be done entirely reliably. If you must try it, some patches which may help are listed in our web references.
There is an Internet Draft on IPSEC and NAT which may eventually evolve into a standard solution for this problem.
The ipsec.conf configuration file has three pairs of parameters used to specify an interface between FreeS/WAN and firewalling code.
One pair are set in the config setup section of the file and affect all connections:
The others are set in connection descriptions, often in the conn %default section so they apply to all connections.
Your script should take the same arguments and use the same environment variables as _updown. These are described in the pluto(8) man page. We provide an example script for use with ipchains(8) below.
Here are some mailing list comments from pluto(8) developer Hugh Redelmeier on an earlier draft of this document:
There are many important things left out - firewalling is important but must reflect (implement) policy. Since policy isn't the same for all our customers, and we're not experts, we should concentrate on FW and MASQ interactions with FreeS/WAN. - we need a diagram to show packet flow WITHIN ONE MACHINE, assuming IKE, IPsec, FW, and MASQ are all done on that machine. The flow is obvious if the components are run on different machines (trace the cables). IKE input: + packet appears on public IF, as UDP port 500 + input firewalling rules are applied (may discard) + Pluto sees the packet. IKE output: + Pluto generates the packet & writes to public IF, UDP port 500 + output firewalling rules are applied (may discard) + packet sent out public IF IPsec input, with encapsulated packet, outer destination of this host: + packet appears on public IF, protocol 50 or 51. If this packet is the result of decapsulation, it will appear instead on the paired ipsec IF. + input firewalling rules are applied (but packet is opaque) + KLIPS decapsulates it, writes result to paired ipsec IF + input firewalling rules are applied to resulting packet as input on ipsec IF + if the destination of the packet is this machine, the packet is passed on to the appropriate protocol handler. If the original packet was encapsulated more than once and the new outer destination is this machine, that handler will be KLIPS. + otherwise: * routing is done for the resulting packet. This may well direct it into KLIPS for encoding or encrypting. What happens then is described elsewhere. * forwarding firewalling rules are applied * output firewalling rules are applied * the packet is sent where routing specified IPsec input, with encapsulated packet, outer destination of another host: + packet appears on some IF, protocol 50 or 51 + input firewalling rules are applied (but packet is opaque) + routing selects where to send the packet + forwarding firewalling rules are applied (but packet is opaque) + packet forwarded, still encapsulated IPsec output, from this host or from a client: + if from a client, input firewalling rules are applied as the packet arrives on the private IF + routing directs the packet to an ipsec IF (this is how the system decides KLIPS processing is required) + if from a client, forwarding firewalling rules are applied + KLIPS eroute mechanism matches the source and destination to registered eroutes, yielding a SPI group. This dictates processing, and where the resulting packet is to be sent (the destinations SG and the nexthop). + output firewalling is not applied to the resulting encapsulated packet - Until quite recently, KLIPS would double encapsulate packets that didn't strictly need to be. Firewalling should be prepared for those packets showing up as ESP and AH protocol input packets on an ipsec IF. - MASQ processing seems to be done as if it were part of the forwarding firewall processing (this should be verified). - If a firewall is being used, it is likely the case that it needs to be adjusted whenever IPsec SAs are added or removed. Pluto invokes a script to do this (and to adjust routing) at suitable times. The default script is only suitable for ipfwadm-managed firewalls. Under LINUX 2.2.x kernels, ipchains can be managed by ipfwadm (emulation), but ipchains more powerful if manipulated using the ipchains command. In this case, a custom updown script must be used. We think that the flexibility of ipchains precludes us supplying an updown script that would be widely appropriate.We do provide a sample script in the next section. It is essentially a transliteration of the version we supply for ipfwadm. Because it doesn't process the command line argument, it cannot be directly subsituted -- it won't support the semantics of *firewall=no. It can be used in [left|right]updown=.
Here is an example updown script for use with ipchains. It is intended to be called via an updown= statement in ipsec.conf.
#! /bin/sh # sample updown script for ipchains # Copyright (C) 2000 D. Hugh Redelmeier, Henry Spencer # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation; either version 2 of the License, or (at your # option) any later version. See . # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License # for more details. # # RCSID $Id: firewall.html,v 1.3 2000/10/13 03:26:23 sandy Exp $ # check interface version case "$PLUTO_VERSION" in 1.0) ;; *) echo "$0: unknown interface version \`$PLUTO_VERSION'" >&2 exit 2 ;; esac # check parameter(s) case "$*" in '') ;; *) echo "$0: parameters unexpected" >&2 exit 2 ;; esac # utility functions for route manipulation # Meddling with this stuff should never be necessary and is most unwise. uproute() { route add -net $PLUTO_PEER_CLIENT_NET netmask $PLUTO_PEER_CLIENT_MASK \ dev $PLUTO_INTERFACE gw $PLUTO_NEXT_HOP } downroute() { route del -net $PLUTO_PEER_CLIENT_NET netmask $PLUTO_PEER_CLIENT_MASK \ dev $PLUTO_INTERFACE gw $PLUTO_NEXT_HOP } # the big choice case "$PLUTO_VERB" in prepare-host|prepare-client) # delete possibly-existing route (preliminary to adding a route) oops="`route del -net $PLUTO_PEER_CLIENT_NET \ netmask $PLUTO_PEER_CLIENT_MASK 2>&1`" status="$?" if test " $oops" = " " -a " $status" != " 0" then oops="silent error in route command, exit status $status" fi case "$oops" in 'SIOCDELRT: No such process') # This is what route (currently -- not documented!) gives # for "could not find such a route". status=0 ;; esac exit $status ;; route-host|route-client) # connection to this host or client being routed uproute ;; unroute-host|unroute-client) # connection to this host or client being unrouted downroute ;; up-host) # connection to this host coming up ;; down-host) # connection to this host going down ;; up-client) # connection to client subnet, through forwarding firewall, coming up ipchains -I forward -j ACCEPT -b \ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK \ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK ;; down-client) # connection to client subnet, through forwarding firewall, going down ipchains -D forward -j ACCEPT -b \ -s $PLUTO_MY_CLIENT_NET/$PLUTO_MY_CLIENT_MASK \ -d $PLUTO_PEER_CLIENT_NET/$PLUTO_PEER_CLIENT_MASK ;; *) echo "$0: unknown verb \`$PLUTO_VERB' or parameter \`$1'" >&2 exit 1 ;; esac
It is also possible to set up both firewalling and IPSEC with appropriate scripts at boot and then not use [left|right]updown=, or use it only for simple up and down operations.
One user, Rob Hutton, posted his boot time scripts to the mailing list, and we included them in previous versions of this documentation. They are still available from our web site.
Those scripts were based on David Ranch's scripts for his "Trinity OS" for setting up a secure Linux. Check his home page for the latest version and for information on his book on securing Linux.
Also, note Ranch's comments in this mailing list message:
Hello Hugh & SWAN peoples.. >| I was going over the rc.firewall script posted as an example on the >| FreeS/WAN web site (1.3 documentation) and would like to point out that >| when using the interface parameter with the forward rule chain, it >| indicates the DESTINATION interface. The script seems to be assuming -i >| specifies the SOURCE interface (at least based on the comments >| provided). The current rule set accepts anything headed TO the internal >| interface, while the comments say anything FROM the internal interface. >| This doesn't seem like what was intended... > >That code is from David Ranch, by way of Rob Hutton. I don't use it, >but it has some advantages over my personal hand-crafted ipchains >rules. Wow! I never knew that the TrinityOS firewall ruleset was in the Swan docs. Good news! Anyway, the TrinityOS firewall ruleset has undergone significant changes since the publishing of the "Securing Linux: Step by Step" book and is now currently at v3.58. I recommend *ALL* users to upgrade to the newer versions of the firewall to catch some significant issues. The new URL is: http://www.ecst.csuchico.edu/~dranch/LINUX/index-linux.html Unfortunately, several aspects of Rob's translation of the ruleset haven't been integrated into TrinityOS yet (specifically, his IPSEC and split configuration changes). So, though I appreciate Rob's work, the problems you pointed out aren't by me. Now that TrinityOS has finally been ported to SGML, I can finally make some upgrades to the ruleset.
If you are going to base your firewalling on Ranch's scripts, we recommend using his latest version, and sending him your IPSEC modifications for incorporation into later versions.