On 3/30/21 6:15 PM, Mark Gray wrote: > On 30/03/2021 15:28, Aaron Conole wrote: >> Mark Gray <mark.d.g...@redhat.com> writes: >> >>> When configuring IPsec, "ovs-monitor-ipsec" honours >>> the 'local_ip' option in the 'Interface' table by configuring >>> the 'left' side of the Libreswan connection with 'local_ip'. >>> If 'local_ip' is not specified, "ovs-monitor-ipsec" sets >>> 'left' to '%defaultroute' which is interpreted as the IP >>> address of the default gateway interface. >>> >>> However, when 'remote_ip' is an IPv6 address, Libreswan >>> still interprets '%defaultroute' as the IPv4 address on the >>> default gateway interface (see: >>> https://github.com/libreswan/libreswan/issues/416) giving >>> an "address family inconsistency" error. >>> >>> This patch resolves this issue by specifying the >>> connection as IPv6 when the 'remote_ip' is IPv6 and >>> 'local_ip' has not been set. >>> >>> Signed-off-by: Mark Gray <mark.d.g...@redhat.com> >>> --- >>> ipsec/ovs-monitor-ipsec.in | 54 +++++++++++++++++++++++++++++++++++++- >>> 1 file changed, 53 insertions(+), 1 deletion(-) >>> >>> diff --git a/ipsec/ovs-monitor-ipsec.in b/ipsec/ovs-monitor-ipsec.in >>> index 9f412aaaf25a..b8cfb0a8ae79 100755 >>> --- a/ipsec/ovs-monitor-ipsec.in >>> +++ b/ipsec/ovs-monitor-ipsec.in >>> @@ -14,10 +14,11 @@ >>> # limitations under the License. >>> >>> import argparse >>> +import copy >> >> I think it's okay to get things in alphabetical order, but it's not >> related. > > I'll change back > >> >>> +import ipaddress >>> import re >>> import subprocess >>> import sys >>> -import copy >>> import os >>> from string import Template >>> >>> @@ -413,6 +414,11 @@ conn prevent_unencrypted_vxlan >>> leftprotoport=udp/4789 >>> mark={0} >>> >>> +""" >>> + >>> + IPV6_CONN = """\ >>> + hostaddrfamily=ipv6 >>> + clientaddrfamily=ipv6 >>> """ >>> >>> auth_tmpl = {"psk": Template("""\ >>> @@ -528,6 +534,9 @@ conn prevent_unencrypted_vxlan >>> else: >>> auth_section = self.auth_tmpl["pki_ca"].substitute(tunnel.conf) >>> >>> + if tunnel.conf["address_family"] == "IPv6": >>> + auth_section = self.IPV6_CONN + auth_section >>> + >>> vals = tunnel.conf.copy() >>> vals["auth_section"] = auth_section >>> vals["version"] = tunnel.version >>> @@ -795,6 +804,7 @@ class IPsecTunnel(object): >>> Tunnel Type: $tunnel_type >>> Local IP: $local_ip >>> Remote IP: $remote_ip >>> + Address Family: $address_family >>> SKB mark: $skb_mark >>> Local cert: $certificate >>> Local name: $local_name >>> @@ -836,6 +846,9 @@ class IPsecTunnel(object): >>> "tunnel_type": row.type, >>> "local_ip": options.get("local_ip", "%defaultroute"), >>> "remote_ip": options.get("remote_ip"), >>> + "address_family": self._get_conn_address_family( >>> + >>> options.get("remote_ip"), >>> + >>> options.get("local_ip")), >>> "skb_mark": monitor.conf["skb_mark"], >>> "certificate": monitor.conf["pki"]["certificate"], >>> "private_key": monitor.conf["pki"]["private_key"], >>> @@ -904,6 +917,24 @@ class IPsecTunnel(object): >>> >>> return header + conf + status + spds + sas + cons + "\n" >>> >>> + def _get_conn_address_family(self, remote_ip, local_ip): >>> + remote = address_family(remote_ip) >>> + local = address_family(local_ip) >>> + >>> + if local == "IPv4" and remote == "IPv4": >>> + return "IPv4" >>> + elif local == "IPv6" and remote == "IPv6": >>> + return "IPv6" >>> + elif remote == "IPv4" and local_ip is None: >>> + return "IPv4" >>> + elif remote == "IPv6" and local_ip is None: >>> + return "IPv6" >>> + elif remote != local: >>> + # remote family and local family are mismatched >>> + return None >>> + else: >>> + return None >>> + >> >> I think we can shrink this whole section to: >> >> >> def _get_conn_address_family(self, remote_ip, local_ip): >> remote = address_family(remote_ip) >> local = address_family(local_ip) >> >> if local is None: >> return remote >> elif local != remote: >> return None >> >> return remote > > Yes, you are right. Simpler. >> >> >>> def _is_valid_tunnel_conf(self): >>> """This function verifies if IPsec tunnel has valid configuration >>> set in 'conf'. If it is valid, then it returns True. Otherwise, >>> @@ -1160,6 +1191,27 @@ class IPsecMonitor(object): >>> >>> return m.group(1) >>> >>> +def is_ipv4(address): >>> + try: >>> + ipaddress.IPv4Address(address) >>> + except ipaddress.AddressValueError: >>> + return False >>> + return True >>> + >>> +def is_ipv6(address): >>> + try: >>> + ipaddress.IPv6Address(address) >>> + except ipaddress.AddressValueError: >>> + return False >>> + return True >>> + >>> +def address_family(address): >>> + if is_ipv4(address): >>> + return "IPv4" >>> + elif is_ipv6(address): >>> + return "IPv6" >>> + else: >>> + return None >> >> Maybe the above 3 functions can look like: >> >> >> def address_family(address): >> try: >> ip = ipaddress.ip_address(address) >> ipstr = str(type(ip)) >> except ValueError: >> return None >> >> if ipstr.find('v6') != -1: >> return "IPv6" >> return "IPv4" >> > Yes, better. >> >> Note that I use ValueError above, because when I tried to test locally, >> I got the following from ipaddress: >> >> ValueError: 'asdffdsa' does not appear to be an IPv4 or IPv6 address > > IIRC I did try an invalid IP address. Maybe the behavior depends on the > version of Python. I tested this on my machine and got the same behavior > as you so I will accept that change >> >> And the block: >> >> >>> try: >> ... ip6=ipaddress.ip_address('asdffdsa') >> ... except ipaddress.AddressValueError: >> ... print("nope") >> ... >> Traceback (most recent call last): >> File "<stdin>", line 2, in <module> >> File "/usr/lib64/python3.7/ipaddress.py", line 54, in ip_address >> address) >> ValueError: 'asdffdsa' does not appear to be an IPv4 or IPv6 address >> >>> try: >> ... ip6=ipaddress.ip_address('asdffdsa') >> ... except ValueError: >> ... print("nope") >> ... >> nope >> >> So, I guess even though it implies that it will always throw >> AddressValueException in the documentation, it doesn't :-/
Shouldn't we catch both types of exception, the documented one and the real one? I mean, since it's documented, library might actually throw them or start throwing in the future. This also worth a comment in the code. >> >>> >>> def unixctl_xfrm_policies(conn, unused_argv, unused_aux): >>> global xfrm >> > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev