core: NAT before IPsec is not functional
UPDATE
A limitation of the PF implementation on FreeBSD makes it impossible to apply NAT rules before sending packets through an IPsec tunnel. (I think OpenBSD fixed this limitation in their PF implementation a while ago. Unfortunately, the PF implementation on FreeBSD no longer follows OpenBSD’s developments, so it’s unlikely that we see this being ported over to FreeBSD.)
There are two steps required to fix this issue:
- Patch strongSwan
- Revive some old code
@ermal provided a nice explanation how these two things solve this issue. (Note that Ermal did mention “other ways of doing it”, so there’s likely a different/better solution possible.)
The drawbacks of this fix are obvious: The strongSwan patch will never be included in any upstream release, thus it may break with any new (major) release of strongSwan. And while this solution works very well, it’s just a workaround for a limitation in PF/FreeBSD.
But, to be honest, the inability to use “NAT before IPsec” is a showstopper for me. That’s why I’m currently using a custom build of strongSwan alongside a small patch to vpn.inc.
ORIGINAL REPORT
(for reference only)
If you configure IPsec NAT, the IPsec phase 2 tunnels may become unstable. In my case all phase 2 tunnels remain disconnected:
Oct 19 12:09:28 opnsense charon: 15[IKE] <con1-000|1> IKE_SA con1-000[1] established between X[X]...Y[Y]
Oct 19 12:09:28 opnsense charon: 15[IKE] IKE_SA con1-000[1] established between X[X]...Y[Y]
Oct 19 12:09:28 opnsense charon: 15[IKE] <con1-000|1> scheduling reauthentication in 28101s
Oct 19 12:09:28 opnsense charon: 15[IKE] <con1-000|1> maximum IKE_SA lifetime 28641s
Oct 19 12:09:32 opnsense charon: 13[IKE] <con1-000|1> sending retransmit 1 of request message ID 951205933, seq 4
Oct 19 12:09:39 opnsense charon: 12[IKE] <con1-000|1> sending retransmit 2 of request message ID 951205933, seq 4
Oct 19 12:09:52 opnsense charon: 06[IKE] <con1-000|1> sending retransmit 3 of request message ID 951205933, seq 4
Oct 19 12:10:16 opnsense charon: 08[IKE] <con1-000|1> sending retransmit 4 of request message ID 951205933, seq 4
The only solution in this case is to disable all IPsec NAT entries, stop ipsec and restart it. Afterwards all phase 2 tunnels will come up immediately. Once all phase 2 tunnels are established, it is possible to enable the IPsec NAT entries again (but this is dangerous because a reconnect of the tunnel is very unlikely to succeed).
We do not have this issue with IPsec NAT disabled.
While debugging #369 with @AdSchellevis we’ve been wondering why entries to ipsec.conf
are added for IPsec NAT. Is this actually required for IPsec NAT to work? It seems that this confuses the ipsec daemon.
To be more precise: I do not use the IPsec NAT for masquerading my local networks, but instead to do actual NAT (allow my other local networks to access a remote IPsec network, even if the remote side does know nothing about these local networks). It’s exactly what is described here (see “Remote End Notes”).
About this issue
- Original URL
- State: closed
- Created 9 years ago
- Comments: 52 (50 by maintainers)
Commits related to this issue
- ipsec, cleanup non-functional nat before ipsec logic and ui for 17.7. In case the feature will reemerge at some point, it would be better to move it to the firewall section anyway. for reference about... — committed to opnsense/core by AdSchellevis 7 years ago
- restructure ipsec_find_id, remove dependency of ipsec_configure_do(), work for https://github.com/opnsense/core/issues/440 — committed to opnsense/core by AdSchellevis 7 years ago
- ipsec, support manually defined spd entries, for https://github.com/opnsense/core/issues/440 — committed to opnsense/core by AdSchellevis 7 years ago
- ipsec, cleanup spd entries after removal, for https://github.com/opnsense/core/issues/440 — committed to opnsense/core by AdSchellevis 7 years ago
- add nat type selection in firewall_nat_1to1 and change some descriptions, for https://github.com/opnsense/core/issues/440 — committed to opnsense/core by AdSchellevis 7 years ago
- ipsec: portable NAT before IPsec support PR: https://github.com/opnsense/core/issues/440 Requested by: @fraenki Researched by: @mimugmail Explained by: @bu7cher (cherry picked from comm... — committed to opnsense/core by AdSchellevis 7 years ago
I’ll take this one … long overdue 😃
I can confirm that this NAT-before-IPsec implementation is indeed working for me. Great job, @AdSchellevis and @mimugmail!
There’s one limitation that should be mentioned in the help text (and documentation):
This means that it’s required to use an IP address for “My identifier”. Anything else, for example “Distinguished name”, will not work. (Well, maybe it might work to get the IP address from the selected interface for those cases… but I’m not sure.)
@fichtner Would you mind to name @bu7cher (Andrey) in the Changelog as he did most of the research (it’s ok for him)?
@mimugmail nice team effort this is! So, cleanup is in too https://github.com/opnsense/core/commit/1fe8341a19ccc4765373696d509f509df9889fcb
In case @fraenki wants to test too, you need to pull in the following changes (in this order): https://github.com/opnsense/core/commit/9351e45d59bd7cfd9e925f6bede4c2bf8156bc48 https://github.com/opnsense/core/commit/814d18ac37ac477213fcacb43bb5e9920b92f2ff https://github.com/opnsense/core/commit/1fe8341a19ccc4765373696d509f509df9889fcb https://github.com/opnsense/core/commit/76839db73ad41b05f49144d0f963b0a150fab880
Last item on my list is to extend the one-on-one nat and then we should close this issue in my opinion.
@AdSchellevis @fraenki I have a solution now.
setkey -PD | grep unique
Get the last number
setkey -PD
The only restriction is that you need to enable some kind of shaping in order to have basic ipfw ruleset enabled. @AdSchellevis any chance to get this templated? Perhaps we can also test with pf, but I’m quite unfamiliar with it.
it looks as bit like https://forum.opnsense.org/index.php?topic=5416.0 but maybe not relevant here. I will build a test kernel anyway. Thanks for bringing this up.
@fichtner thanks for the tip i always miss that button. While here i might give you insight into it. With FreeBSD 10 the best way is to use the patches i made since the other way of using nat+rdr is very tricky. With FreeBSD 11-stable you have to be smart and use if_ipsec with routing and send needed traffic to that interface, nat there as usual with any other interface. The only complication is that you have to manager routes with it.
Have fun and hope it helps.