OpenBSD Journal

IPsec VPN and NAT

Contributed by mitja on from the a-practical-solution-to-an-unnecessary-problem dept.

At work we run a number of IPsec VPN tunnels to peers all over the world and we have always been concerned about possible RFC1918 address space collisions between our network and one of the other companies - it is surprising how often administrators keep the default 192.168.0.0/24 network! To the best of our knowledge on OpenBSD there was no good technical solution to the problem, and migrating the whole partner network to a unique address space is often politically unacceptable or too expensive.

We had known that some commercial IPsec implementations are capable of doing outgoing NAT over VPN, so it was only a matter of time when a new peer would request we do NAT. And indeed, our luck had run out in last November - a peer demanded that we hide our entire network (central hub and remote offices) behind a single IP address before we route our traffic through VPN to them.

NATting over the enc0 interface is the first thing that usually comes to mind, but this obvious solution does not work out of the box. The reason for it lies in how the IPsec code is grafted onto the network stack. A successfully established IPsec VPN tunnel creates a pair of security associations (SAs) that act as a tunnel selector - if the network traffic arriving into the gateway matches the SA in originating and destinating IP, it is marked for that specific VPN tunnel and only then passed to pf for processing on the enc0 interface. enc0 is not a typical network interface, it's a single pseudointerface that combines the unencrypted traffic of all flows, just before it gets encrypted and leaves the gateway; the packets on enc0 interface are already marked for various VPN tunnels. The problem with doing address translation on this kind of traffic is obvious: depending on what SA we negotiate with the peer (the virtual IP or the actual source IP), our traffic will either never be marked for VPN and thus never arrive on the enc0 interface (if the SA is negotiated for the desired, virtual address); or alternatively match the SA, reach enc0, get translated by a rule in pf and then get dropped by the peer (if the SA was negotiated for the actual local IP address) as it will not have the expected negotiated source IP address.

Or, in much simpler words: the order of packet processing is such that IPsec matching happens first, pf processing later - if we rewrite the source address after the packet was selected to go through a certain tunnel, it will not match what the peer was expecting and he'll drop that packet. A search of the mailing list archives has turned out some workarounds with tricky routing over the loopback interface, but I just couldn't get it to work - and judging from the archives, I was not the only one!

Short of digging deep in the kernel code and rearranging the network stack internals there is only one practical solution to the problem: tell the peer to expect the traffic from one (post-nat) address, and set up our SA for another, pre-nat address space. With this kind of setup, the interaction with pf and its "nat on enc0" rule would finally work as expected.

Luckily OpenCON 2008 was only days ahead and it was with this idea on my mind that I have run into Hans-Joerg Hoexer (hshoexer@), one of OpenBSD's IPsec/IKE maintainers. During our animated debate (it was already quite late in the evening) Marco Pfatschbacher (mpf@) joined in, listened for a while and than blurted "yeah, that's how I did it". It turned out that he had had the same idea and even actually written the code, but he has never tried to get it committed as it was lacking the mandatory documentation. We soon reached a deal - he would clean up his diff and have it reviewed while I'd write the man page bits. Testing and some minor modifications followed, until a few weeks later mpf committed his diff to -current.

So, what great new things does this change bring? I can think of two scenarios that can be solved now, "outgoing NAT" case and "connect two networks with overlapping address space" case.

Outgoing NAT example:

Let's assume that our network is 192.168.1.0/24, and the peer wants all out traffic to come from a single address, 10.10.10.1. The ipsec.conf part for this scenario is:

ike esp from 10.10.10.1 (192.168.1.0/24) to 192.168.2.0/24 peer 10.10.20.1
and we can see the new feature in action - the negotiated address will be 10.10.10.1 and as far as the peer is concerned, that's the only address on our end that he'll see the traffic from. The new additional argument, (192.168.1.0/24), tells our gateway to install our SA with the actual address range of our network, so that our traffic can enter this tunnel and reach pf. A simple pf.conf rule,
nat on enc0 from 192.168.1.0/24 to 192.168.2.0/24 -> 10.10.10.1

will then do the actual network address translation between our actual source addresses and the wished-for virtual source address that the peer will receive from the tunnel. As this scenario is entirely agnostic to the other peer, it can be any IPsec implementation on the other end. As a side note, 10.10.10.1 does not have to be configured on any of the network interfaces - just using it in the nat rule is enough.

Deconflicting networks example:

You are a network administrator at "A Corp" and one fine morning the management surprises everyone by announcing that a merger with "B Corp" has happened overnight. Your task is to connect the two networks, A and B, into one big happy network. "Piece of cake," you think to yourself, until, horrified, you realize that both networks use an identical network range, 10.10.0.0/16.

10.10.0.0/16 - [GatewayA]=====IPsec VPN=====[GatewayB] - 10.10.0.0/16

What now? Renumbering one of the networks to a deconflicting address range is out of question, it could take weeks, and the boss wants that hookup up-and-running an hour ago. Puffy to the rescue!

The setup is more trickier in this case, but binat can save your day. In a nutshell, we will binat both networks to two different, deconflicting ranges and create a tunnel between those two new ranges. It is also required that both gateways run OpenBSD, to the best of my knowledge no other IPsec implementation has a compatible capability.

The ipsec.conf part for both gateways is this:

[GatewayA]
ike esp from 10.11.0.0/16 (10.10.0.0/16) to 10.12.0.0/16 peer ip.of.gw.B
[GatewayB]
ike esp from 10.12.0.0/16 (10.10.0.0/16) to 10.11.0.0/16 peer ip.of.gw.A

As you can see, we pick up two virtual networks, 10.11.0.0/16 and 10.12.0.0/16, as replacement for our conflicting range 10.10.0.0/16.

We also need the binat rule in both pf.conf files:

[GatewayA]
binat on enc0 inet from 10.10.0.0/16 to 10.12.0.0/16 -> 10.11.0.0/16
[GatewayB]
binat on enc0 inet from 10.10.0.0/16 to 10.11.0.0/16 -> 10.12.0.0/16

For the netizens in network A, their LAN is 10.10.0.0/16 and 10.12.0.0/16 are the recently arrived coworkers. Similar for the users of network B, their LAN is still 10.10.0.0/16 and the other network is accessible through 10.11.0.0/16 address range. Simple, isn't it? :)

A split-horizon DNS configuration can make this distinction entirely transparent. Just configure your DNS server to point to 10.12.0.5 when users in network A ask it for serverB.mycorp.com, and 10.10.0.5 when users in network B ask for it. Vice versa for the serverA.mycorp.com, 10.11.0.5 for users in network B and 10.10.0.5 for users in network A. This way both groups can access both servers without any thought about our network wizardry.

What if our company suddenly acquires "C Corp" too? No problem, the basic principle scales. We need to assign a virtual, nonconflicting address range to the C network too by binating it on their gateway, and establish the required VPN tunnels between the virtual addresses of all the networks involved.

These are two examples of what mpf's changes bring to IPsec VPNs on OpenBSD. If you wish to try them, follow -current or wait for the next snapshot. We have been using this code in production for over a month now with no problems whatsoever, but testing is always welcome!

And as a final thought: the next time there is a chance of helping the developers get together, just think of the good things that come out of such encounters!

(Comments are closed)


Comments
  1. By Dmitri Alenichev (mitya) mitya@rootshell.be on http://rootshell.be/~mitya/

    great article and very useful solution, thanks!

  2. By Dick Svensson (2001:16d8:ff06:4:216:cbff:fe06:658c) on

    Will try it as soon as possible.

    txs, and great work, as always!

  3. By Anonymous Coward (70.81.15.127) on

    OMFG, OpenBSD rocks! I still don't get why more Linux people don't switch over or at least try it... My company is filled with Linux people, I just wish they could realize and see the potential OpenBSD has and gives to everyone, for free!

    Great work too all those involved in this article and this great capability!

    Comments
    1. By Anonymous Coward (208.152.231.254) on

      > OMFG, OpenBSD rocks! I still don't get why more Linux people don't switch over or at least try it... My company is filled with Linux people, I just wish they could realize and see the potential OpenBSD has and gives to everyone, for free!
      >
      > Great work too all those involved in this article and this great capability!

      Is this something that can't be done under GNU/Linux? It looks like an interesting use of NAT, rather than something that makes use of a specific feature of OpenBSD's PF that doesn't exist elsewhere.

      Comments
      1. By Anonymous Coward (84.206.8.140) on

        > > OMFG, OpenBSD rocks! I still don't get why more Linux people don't switch over or at least try it... My company is filled with Linux people, I just wish they could realize and see the potential OpenBSD has and gives to everyone, for free!
        > >
        > > Great work too all those involved in this article and this great capability!
        >
        > Is this something that can't be done under GNU/Linux? It looks like an interesting use of NAT, rather than something that makes use of a specific feature of OpenBSD's PF that doesn't exist elsewhere.
        >

        It works on Linux too, see the iptables policy match.


        -A POSTROUTING -m policy --dir out --pol ipsec -s 10.200.100.1 -j SNAT --to-source 10.100.100.10

        Comments
        1. By Anonymous Coward (59.167.252.29) on


          > It works on Linux too, see the iptables policy match.
          >
          >
          > -A POSTROUTING -m policy --dir out --pol ipsec -s 10.200.100.1 -j SNAT --to-source 10.100.100.10

          I can't imagine myself opening up a new firewall.conf file, lines of *that* flowing out of my fingertips and me enjoying it.

          Then of course, coming back to it to make amendments after 6 months... yuck.

          Comments
          1. By Matthew Closson (72.236.159.211) matthew.closson@gmail.com on

            This is something which I had been working around for quite a while by sitting one OpenBSD box in front of another. This is a great step forward for the commercial usability of the IPSEC solution OpenBSD offers. I have run into collision of address space issues with VPN's in enterprise environments quite frequently, mostly in the 10.0.0.0/8 range. In almost all of those cases the political arguments coming from both sides prevented either side from renumbering their network. Thank you for this extremely useful feature.

      2. By Brad (2001:470:b01e:3:216:41ff:fe17:6933) brad at comstyle dot com on

        > Is this something that can't be done under GNU/Linux? It looks like an interesting use of NAT, rather than something that makes use of a specific feature of OpenBSD's PF that doesn't exist elsewhere.

        It is possible, but whether you want to actually use Linux or iptables is another question.

        Comments
        1. By Anonymous Coward (85.177.85.165) on

          > > Is this something that can't be done under GNU/Linux? It looks like an interesting use of NAT, rather than something that makes use of a specific feature of OpenBSD's PF that doesn't exist elsewhere.
          >
          > It is possible, but whether you want to actually use Linux or iptables is another question.

          You're forced to because as far as I understand the code existed but was NEVER commited because it lacked documentation.

          So not commiting was prefered except of maybe announcing this status on a developer mailinglist (so maybe other developers would have done it like it happened now).

          So how else is there wich is not commited? Maybe a sane SMP implementation or other dark secrets? ;-) *sacasm*

          But you are forced to use Linux or other systems then even solutions already exist somehow.

          Comments
          1. By Arach (87.103.146.206) on

            > But you are forced to use Linux or other systems then even solutions already exist somehow.

            Nobody forced, unless a littel bit of encapsulation overconsidered harmful. You can simply do binat for packets inside etherip or ipip tunnel and do IPsec for the tunnel's channel packets.

      3. By Anonymous Coward (70.81.15.127) on

        > > OMFG, OpenBSD rocks! I still don't get why more Linux people don't switch over or at least try it... My company is filled with Linux people, I just wish they could realize and see the potential OpenBSD has and gives to everyone, for free!
        > >
        > > Great work too all those involved in this article and this great capability!
        >
        > Is this something that can't be done under GNU/Linux? It looks like an interesting use of NAT, rather than something that makes use of a specific feature of OpenBSD's PF that doesn't exist elsewhere.
        >

        Yes, it can be.

        I wasn't putting Linux down if that's the way it sounded. I'm just saying that, what OpenBSD does for everyone as a 'whole' rocks. I don't understand why more people don't switch or support OpenBSD. They always come up with something great or just brilliant and extremely well done!

        Again, nice article!

    2. By jason (64.140.240.190) on

      > OMFG, OpenBSD rocks! I still don't get why more Linux people don't switch over or at least try it... My company is filled with Linux people, I just wish they could realize and see the potential OpenBSD has and gives to everyone, for free!
      >
      > Great work too all those involved in this article and this great capability!

      If you really appreciate it, you would make donations.. wouldn't you?

      Comments
      1. By Anonymous Coward (70.81.15.127) on

        > > OMFG, OpenBSD rocks! I still don't get why more Linux people don't switch over or at least try it... My company is filled with Linux people, I just wish they could realize and see the potential OpenBSD has and gives to everyone, for free!
        > >
        > > Great work too all those involved in this article and this great capability!
        >
        > If you really appreciate it, you would make donations.. wouldn't you?

        That's why I did and I still do.

  4. By ScOut3R (213.16.104.1) gabri.mate@modernbiztonsag.org on

    That's why i love OpenBSD!

    Simple, fast solutions to real life problems!

    A great THANKS for the devs!

  5. By Anonymous Coward (213.221.123.174) on

    Thanks for these fine bits of code! :-)

    But one question remains: How many cool code isn't commited yet because of familiar situations? :-p

    "For the world, you are somebody, but for somebody you are the world."
    So thank you OpenBSD Devs! :)

    Comments
    1. By sthen (85.158.44.149) on

      > Thanks for these fine bits of code! :-)
      >
      > But one question remains: How many cool code isn't commited yet because of familiar situations? :-p

      you can help get more cool code committed by testing and reporting back on diffs that get sent out (mainly to tech@).

  6. By Anonymous Coward (122.200.148.134) on

    how about dynamic ip address or behind nat , i have try setup but still proble if dynamic ip address or nat .

  7. By Lennie (2001:470:1f15:5a9:217:31ff:fe75:76a5) on

    NAT for IPsec-tunnel ? Are you serious, get yourself some IPv6 instead ! ;-) They'll have to start using it eventually anyway.

    Comments
    1. By Noname (212.77.163.104) on

      > NAT for IPsec-tunnel ? Are you serious, get yourself some IPv6 instead ! ;-) They'll have to start using it eventually anyway.

      Not all ISPs are offering IPv6 !

    2. By tedu (64.115.195.66) on

      > NAT for IPsec-tunnel ? Are you serious, get yourself some IPv6 instead ! ;-) They'll have to start using it eventually anyway.

      Only thing more annoying than IP6 is the people who won't shut up about IP6.

    3. By Anonymous Coward (87.144.94.206) on

      > NAT for IPsec-tunnel ? Are you serious, get yourself some IPv6 instead ! ;-) They'll have to start using it eventually anyway.

      "... and migrating the whole partner network to a unique address space is often politically unacceptable or too expensive."

    4. By George Koehler (kernigh) on http://kernigh.pbwiki.com/OpenBSD

      > NAT for IPsec-tunnel ? Are you serious, get yourself some IPv6
      > instead ! ;-) They'll have to start using it eventually anyway.

      However, IPv6 does not solve the problem.

      If two IPv4 private networks use the default 192.168.0.0/24, and you want to bring them in VPN, then you need to use NAT. Suppose that instead of IPv4 192.168.0.0./24, both private networks use IPv6 fec0::/64. Then if you want to bring them in VPN, then you need to use (IPv6) NAT.

      IPv6 is good because it provides more public unicast addresses than IPv4. Many networks have IPv4 internet access through a NAT (from a private network to a single public address) because of the address shortage. These networks can be IPv6 public networks.

      If you get yourself some IPv6, and change your private networks to public networks, then you can bring them in VPN without address conflict, because public addresses do not conflict. Beware, this is no option if you want your VPN to use private IP addresses.

      Comments
      1. By Brad (2001:470:b01e:3:216:41ff:fe17:6933) brad at comstyle dot com on

        > If two IPv4 private networks use the default 192.168.0.0/24, and you want to bring them in VPN, then you need to use NAT. Suppose that instead of IPv4 192.168.0.0./24, both private networks use IPv6 fec0::/64. Then if you want to bring them in VPN, then you need to use (IPv6) NAT.

        Site locals are not supposed to be used with IPv6 and have been deprecated. OpenBSD by default will reject sending traffic to site locals.

        Comments
        1. By George Koehler (kernigh) on http://kernigh.pbwiki.com/OpenBSD

          > Site locals are not supposed to be used with IPv6 and have been
          > deprecated. OpenBSD by default will reject sending traffic to site
          > locals.

          Oops! My fec0::/64 is a bad example. You are correct, I looked at netstat -rn and saw that fec0::/10 is rejected.

  8. By tvl (81.83.46.237) on

    This is exactly what I was trying to do a few years ago. Great that it is supported now, I will try to set this up again. Thanks!!!

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]