From owner-freebsd-net@FreeBSD.ORG Fri Jun 23 06:22:29 2006 Return-Path: X-Original-To: freebsd-net@freebsd.org Delivered-To: freebsd-net@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id D8D8216A492 for ; Fri, 23 Jun 2006 06:22:29 +0000 (UTC) (envelope-from fox@verio.net) Received: from dfw-smtpout4.email.verio.net (dfw-smtpout4.email.verio.net [129.250.36.44]) by mx1.FreeBSD.org (Postfix) with ESMTP id 5F97143D45 for ; Fri, 23 Jun 2006 06:22:29 +0000 (GMT) (envelope-from fox@verio.net) Received: from [129.250.36.62] (helo=dfw-mmp2.email.verio.net) by dfw-smtpout4.email.verio.net with esmtp id 1Ftf3h-0006QW-Nn for freebsd-net@freebsd.org; Fri, 23 Jun 2006 06:22:25 +0000 Received: from [129.250.40.241] (helo=limbo.int.dllstx01.us.it.verio.net) by dfw-mmp2.email.verio.net with esmtp id 1Ftf3h-0001Ya-EA for freebsd-net@freebsd.org; Fri, 23 Jun 2006 06:22:25 +0000 Received: by limbo.int.dllstx01.us.it.verio.net (Postfix, from userid 1000) id E273D8E2CC; Fri, 23 Jun 2006 01:22:21 -0500 (CDT) Date: Fri, 23 Jun 2006 01:22:21 -0500 From: David DeSimone To: freebsd-net@freebsd.org Message-ID: <20060623062221.GA23272@verio.net> Mail-Followup-To: freebsd-net@freebsd.org References: <449228FA.50303@thebeastie.org> <20060616122855.GA29279@uk.tiscali.com> <20060616154306.GA18578@verio.net> <449B5D50.8000700@thebeastie.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii; x-action=pgp-signed Content-Disposition: inline In-Reply-To: <449B5D50.8000700@thebeastie.org> Precedence: bulk User-Agent: Mutt/1.5.9i Subject: Re: VPN with FAST_IPSEC and ipsec tools X-BeenThere: freebsd-net@freebsd.org X-Mailman-Version: 2.1.5 List-Id: Networking and TCP/IP with FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 Jun 2006 06:22:29 -0000 -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Michael Vince wrote: > > > The main reason to use IPSEC tunnel mode and avoid GIF is that such > > a config is interoperable with other IPSEC implementations, and thus > > is much more useful in the real world. > > OK that said, how do you create a network to network tunnel based VPN > without using the gif or gre devices? Ok, here's a typical setup that I've used. Suppose you have two gateways: Gateway 1 IP = 1.2.3.4 Networks behind it: 192.168.1.0/24 192.168.2.0/24 Gateway 2 IP = 5.6.7.8 Networks behind it: 192.168.11.0/24 192.168.12.0/24 Most of the examples you'll find will teach you to use IPSEC in Transport mode. But Transport mode is only used for one endpoint to talk to another endpoint. What you want here (and what other gateways like Cisco will implement) is Tunnel mode, where the traffic is encapsulated rather than merely encrypted. First you must define your SA's (security associations) in ipsec.conf. SA's are defined from the perspective of the gateway. What is "inbound" on one gateway is "outbound" on the other. You can't use the same ipsec.conf on each endpoint; you have to tailor it to match what it should expect to see. Gateway 1's ipsec.conf: # This is ipsec.conf # Load it using: setkey -f /etc/ipsec.conf spdflush; # If you ever reload you will want to start fresh # Outbound traffic spdadd 192.168.1.0/24 192.168.11.0/24 any \ -P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; spdadd 192.168.2.0/24 192.168.11.0/24 any \ -P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; spdadd 192.168.1.0/24 192.168.12.0/24 any \ -P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; spdadd 192.168.2.0/24 192.168.12.0/24 any \ -P out ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; # Inbound traffic spdadd 192.168.11.0/24 192.168.1.0/24 any \ -P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; spdadd 192.168.12.0/24 192.168.1.0/24 any \ -P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; spdadd 192.168.11.0/24 192.168.2.0/24 any \ -P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; spdadd 192.168.12.0/24 192.168.2.0/24 any \ -P in ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; Things to notice: There are 8 SA's defined, because each gateway has two subnets, and each unique subnet needs an SA defined IN EACH DIRECTION. So, 2 subnets here x 2 subnets there x 2 directions = 8 SA's total. Half of the SA's will be from the perspective of inbound traffic, (using "-P in") and the other half will be output ("-P out"). When an SA is inbound ("-P in"), the tunnel descriptor will have the remote gateway listed first, followed by the local gateway. Inbound traffic flows FROM the remote gateway (5.6.7.8) TO the local gateway (1.2.3.4), leading to a descriptor of "esp/tunnel/5.6.7.8-1.2.3.4/unique;" When an SA is outbound ("-P out"), the descriptor will be reversed, showing traffic FROM this gateway TO the remote, as in "esp/tunnel/1.2.3.4-5.6.7.8/unique;" When an SA is inbound ("-P in"), the remote gateway's network will appear first (because it is the source), followed by the local gateway's network (the destination). That is why the first inbound specification reads "spdadd 192.168.11.0/24 192.168.1.0/24 any", specifying traffic coming FROM a remote network TO a local network. An output SA specifies a local network followed by a remote network. I hope you can see the pattern. Gateway 2's ipsec.conf: # This is ipsec.conf # Load it using: setkey -f /etc/ipsec.conf spdflush; # If you ever reload you will want to start fresh # Inbound traffic spdadd 192.168.11.0/24 192.168.1.0/24 any \ -P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; spdadd 192.168.12.0/24 192.168.1.0/24 any \ -P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; spdadd 192.168.11.0/24 192.168.2.0/24 any \ -P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; spdadd 192.168.12.0/24 192.168.2.0/24 any \ -P out ipsec esp/tunnel/5.6.7.8-1.2.3.4/unique; # Outbound traffic spdadd 192.168.1.0/24 192.168.11.0/24 any \ -P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; spdadd 192.168.2.0/24 192.168.11.0/24 any \ -P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; spdadd 192.168.1.0/24 192.168.12.0/24 any \ -P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; spdadd 192.168.2.0/24 192.168.12.0/24 any \ -P in ipsec esp/tunnel/1.2.3.4-5.6.7.8/unique; Things to notice: The pattern is exactly the same, but what was defined as "-P out" on the other gateway shows up as "-P in" on this gateway, and vice-versa. This configuration is sufficient to define the necessary SA prototypes, but in order to negotiate keys and parameters, you need IKE, and for that you need the ipsec-tools port, in order to get racoon(8). Just as each gateway has its own tailored ipsec.conf, each gateway also has its own racoon.conf. There is of course more than one way to set up an IKE daemon. These are the settings that I use. Gateway 1's racoon.conf: # This is racoon.conf # Loaded by racoon when it starts, or when receiving a HUP. log notify; # notify(*), debug, debug2 path pre_shared_key "/etc/ipsec.keys"; path pidfile "/var/run/racoon.pid"; listen { isakmp 1.2.3.4; strict_address; # Needed? } remote 5.6.7.8 { exchange_mode aggressive,main,base; my_identifier address 1.2.3.4; peers_identifier address 5.6.7.8; verify_identifier off; proposal_check claim; # obey, strict, claim(*), exact(*) proposal { encryption_algorithm aes; hash_algorithm sha1; authentication_method pre_shared_key; dh_group 2; lifetime time 24 hours; } } sainfo address 192.168.1.0/24 any address 192.168.11.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.2.0/24 any address 192.168.11.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.1.0/24 any address 192.168.12.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.2.0/24 any address 192.168.12.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.11.0/24 any address 192.168.1.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.11.0/24 any address 192.168.2.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.12.0/24 any address 192.168.1.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.12.0/24 any address 192.168.2.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } Things to notice: Some people feel aggressive mode is not as secure. If you don't like it, remove it. There should be one "remote" section for each gateway that you converse with. In my config, I specify IP's as identifiers. I am not sure if this is actually necessary, which is why I turn verification off. I have not tested this portion strongly, but the config does work. The main use of proposal_check is to decide what to do when the two gateways do not agree on lifetime parameters. It is best for the gateways to never disagree, of course. :) The proposal section sets encryption and verification parameters for Phase 1 of IKE, where the gateways first establish trust. My config uses pre-shared secrets. I have not (yet) experimented with certificate-based authentication. The "sainfo" sections duplicate the information found in ipsec.conf. For every SA, there needs to be an "sainfo" section describing the exact same pair of networks. Yes, it is cumbersome. I have wished that racoon could just read the information out of the kernel, but I believe the problem is that the kernel only keeps track of networks that match SA's. The other parameters (lifetime, encryption, etc) are not stored anywhere else. They come from racoon negotiating these parameters with the remote system. If you are really lucky, and all your tunnels use exactly the same encryption parameters, you could instead use a single "anonymous" sainfo section like so: sainfo anonymous { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } This will avoid a lot of repetitive data entry. However, if you have different tunnels with different peers who want different parameters, you will have to specify them explicitly. Yes, you must specify the compression algorithm, even if you are not going to use compression. Racoon demands it. Gateway 2's racoon.conf: # This is racoon.conf # Loaded by racoon when it starts, or when receiving a HUP. log notify; # notify(*), debug, debug2 path pre_shared_key "/etc/ipsec.keys"; path pidfile "/var/run/racoon.pid"; listen { isakmp 5.6.7.8; strict_address; # Needed? } remote 1.2.3.4 { exchange_mode aggressive,main,base; my_identifier address 5.6.7.8; peers_identifier address 1.2.3.4; verify_identifier off; proposal_check claim; # obey, strict, claim(*), exact(*) proposal { encryption_algorithm aes; hash_algorithm sha1; authentication_method pre_shared_key; dh_group 2; lifetime time 24 hours; } } sainfo address 192.168.1.0/24 any address 192.168.11.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.2.0/24 any address 192.168.11.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.1.0/24 any address 192.168.12.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.2.0/24 any address 192.168.12.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.11.0/24 any address 192.168.1.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.11.0/24 any address 192.168.2.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.12.0/24 any address 192.168.1.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } sainfo address 192.168.12.0/24 any address 192.168.2.0/24 any { lifetime time 1 hour; encryption_algorithm aes; authentication_algorithm hmac_sha1; compression_algorithm deflate; } Things to notice: Yes, this file is almost exactly the same, with the IP's swapped. What is local here is remote there, and vice-versa. The "sainfo" sections must be left unchanged. If they were different, the two racoons would not agree on parameter negotiations, and would fail to negotiate a tunnel. Finally, you must specify the keys. Each gateway needs to define the keys used on the other gateways. Gateway 1's ipsec.keys: # Keys for IKE 5.6.7.8 SECRET_KEY Gateway 2's ipsec.keys: # Keys for IKE 1.2.3.4 SECRET_KEY Things to notice: Each gateway has keys defined for OTHER gateways. The OTHER gateway has to have the SAME key defined for THIS gateway. This ipsec.keys file MUST BE PROTECTED. If you do not have it set to permissions 0600, racoon will silently IGNORE the file, and your IKE negotiation will fail, and there will be no indication in the logs as to why. Check your permissions! With these parameters a pair of gateways should be able to establish IPSEC sessions with each other, even if the other gateway is some other standards-compliant IPSEC implementation, such as found on Cisco or Checkpoint devices. I have tested specifically with those implementations, and have had no problems. I suppose I should talk about PF. All my gateways use PF, so I have not tested with any other firewall methods such as ipfw. You must certainly allow your gateways to speak IKE and ESP to each other if you want them to work. I use a table called IPSEC_PEERS which I load with the IP's of my peer gateways, and then I use these rules to pass traffic: EXTIP="(fxp0)" pass in quick proto udp from to $EXTIP port 500 keep state pass in quick proto esp from to $EXTIP keep state pass out quick from self keep state I am not convinced that "keep state" is needed or even useful here, since neither UDP nor ESP are stateful protocols, and even if PF did not keep state the traffic would still be allowed anyway. An interesting side effect of IPSEC is that PF cannot track the full state of it ("enc0" patches notwithstanding). Traffic arrives on an internal interface, and then if it becomes encrypted, the traffic "mysteriously disappears" as far as PF can tell. The traffic never goes out another interface. However, reply traffic from the other side of the tunnel does magically "appear" from nowhere. A typical gateway will have an "outbound" rule like this: pass in quick on { $INT } all keep state where $INT defines the interfaces on the internal side. Since "keep state" is specified, reply traffic from the external net will have no trouble coming back in. However, VPN traffic does not come in through the external network... at least, not in any way that PF can determine. The traffic comes in as seemingly-unrelated ESP, is decrypted in the kernel, then magically appears decrypted on the internal interface for the first time. Your firewall will not understand this and will block the traffic unless you add a rule like this: # VPN traffic appears here...? pass out quick on { $INT } to $INT:network keep state So, traffic appearing suddenly on an internal interface, destined for an internal network, is permitted, on the assumption that it must have come from an external VPN. Naturally you can (and probably should) set up much more prohibitive rules, but keep in mind that the first chance you will have to sense inbound VPN traffic is when it is headed OUTBOUND on your INTERNAL interfaces. - -- David DeSimone == Network Admin == fox@verio.net "It took me fifteen years to discover that I had no talent for writing, but I couldn't give it up because by that time I was too famous. -- Robert Benchley -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (GNU/Linux) iD8DBQFEm4idFSrKRjX5eCoRAkFEAJ9QCbodDJUvwG3RG0fuQTXlKRX2dwCbBUhG Q2QZv3RX582uXHSwBeyQuUk= =LxYq -----END PGP SIGNATURE-----