From 0e3ee19efea923ca6293af12e6610460c0cfb8b8 Mon Sep 17 00:00:00 2001 From: Andreas Karis Date: Sat, 23 Jul 2022 13:37:04 +0200 Subject: [PATCH] IPsec: Add option to force NAT-T encapsulation Provide options to enforce NAT-T UDP encapsulation. Options are encapsulation=true for libreswan and forceencaps=true for strongswan. This may be required in environments where firewalls drop ESP traffic but where NAT-T detection fails because packets are not subject to NAT. Signed-off-by: Andreas Karis Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2041681 Signed-off-by: Numan Siddique (cherry picked from commit d6dd8e49551141159f040406202f8550c18a1846) --- Documentation/tutorials/ovn-ipsec.rst | 24 ++++++++++++++++++++++++ NEWS | 4 ++++ controller/encaps.c | 15 +++++++++++++++ tests/ovn-ipsec.at | 3 +++ 4 files changed, 46 insertions(+) diff --git a/Documentation/tutorials/ovn-ipsec.rst b/Documentation/tutorials/ovn-ipsec.rst index 305dd566dc..aea7aa3097 100644 --- a/Documentation/tutorials/ovn-ipsec.rst +++ b/Documentation/tutorials/ovn-ipsec.rst @@ -93,6 +93,29 @@ database to false:: # systemctl enable firewalld # firewall-cmd --permanent --add-service ipsec +Enforcing IPsec NAT-T UDP encapsulation +--------------------------------------- + +In specific situations, it may be required to enforce NAT-T (RFC3948) UDP +encapsulation unconditionally and to bypass the normal NAT detection mechanism. +For example, this may be required in environments where firewalls drop ESP +traffic, but where NAT-T detection (RFC3947) fails because packets otherwise +are not subject to NAT. +In such scenarios, UDP encapsulation can be enforced with the following. + +For libreswan backends:: + + $ ovn-nbctl set nb_global . options:ipsec_encapsulation=true + +For strongswan backends:: + + $ ovn-nbctl set nb_global . options:ipsec_forceencaps=true + +.. note:: + + Support for this feature is only availably when OVN is used together with + OVS releases that accept IPsec custom tunnel options. + Troubleshooting --------------- @@ -119,6 +142,7 @@ For example:: Remote name: host_2 CA cert: /path/to/cacert.pem PSK: None + Custom Options: {'encapsulation': 'yes'} <---- Whether NAT-T is enforced Ofport: 2 <--- Whether ovs-vswitchd has assigned Ofport number to this Tunnel Port CFM state: Disabled <--- Whether CFM declared this tunnel healthy diff --git a/NEWS b/NEWS index 32e342a18b..f92be139ae 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,9 @@ OVN v22.06.1 - xx xxx xxxx -------------------------- + - Added nb_global IPsec options ipsec_encapsulation=true (libreswan) + and ipsec_forceencaps=true (strongswan) to unconditionally enforce + NAT-T UDP encapsulation. Requires OVS support for IPsec custom tunnel + options (which will be available in OVS 3.0). OVN v22.06.0 - 03 Jun 2022 -------------------------- diff --git a/controller/encaps.c b/controller/encaps.c index ed01b1368c..476da05af2 100644 --- a/controller/encaps.c +++ b/controller/encaps.c @@ -199,6 +199,21 @@ tunnel_add(struct tunnel_ctx *tc, const struct sbrec_sb_global *sbg, if (sbg->ipsec) { set_local_ip = true; smap_add(&options, "remote_name", new_chassis_id); + + /* Force NAT-T traversal via configuration */ + /* Two ipsec backends are supported: libreswan and strongswan */ + /* libreswan param: encapsulation; strongswan param: forceencaps */ + bool encapsulation; + bool forceencaps; + encapsulation = smap_get_bool(&sbg->options, "ipsec_encapsulation", + false); + forceencaps = smap_get_bool(&sbg->options, "ipsec_forceencaps", false); + if (encapsulation) { + smap_add(&options, "ipsec_encapsulation", "yes"); + } + if (forceencaps) { + smap_add(&options, "ipsec_forceencaps", "yes"); + } } if (set_local_ip) { diff --git a/tests/ovn-ipsec.at b/tests/ovn-ipsec.at index 4c600a9f27..10ef978780 100644 --- a/tests/ovn-ipsec.at +++ b/tests/ovn-ipsec.at @@ -44,15 +44,18 @@ ovs-vsctl \ # Enable IPsec ovn-nbctl set nb_global . ipsec=true +ovn-nbctl set nb_global . options:ipsec_encapsulation=true check ovn-nbctl --wait=hv sync AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:remote_ip | tr -d '"\n'], [0], [192.168.0.1]) AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:local_ip | tr -d '"\n'], [0], [192.168.0.2]) AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:remote_name | tr -d '\n'], [0], [hv1]) +AT_CHECK([as hv2 ovs-vsctl get Interface ovn-hv1-0 options:ipsec_encapsulation | tr -d '\n'], [0], [yes]) AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:remote_ip | tr -d '"\n'], [0], [192.168.0.2]) AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:local_ip | tr -d '"\n'], [0], [192.168.0.1]) AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:remote_name | tr -d '\n'], [0], [hv2]) +AT_CHECK([as hv1 ovs-vsctl get Interface ovn-hv2-0 options:ipsec_encapsulation | tr -d '\n'], [0], [yes]) AT_CLEANUP