]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-pfroute: Maintain virtual flag when repopulating interface addrs
authorTobias Brunner <tobias@strongswan.org>
Tue, 25 Jul 2023 08:21:40 +0000 (10:21 +0200)
committerTobias Brunner <tobias@strongswan.org>
Thu, 27 Jul 2023 06:21:26 +0000 (08:21 +0200)
When adding a virtual IP on a TUN interface, the interface might get
activated (in terms of receiving the event) after we've already set the
virtual flag for the added address.  As the activation repopulates the
addresses on the interface, this cleared the flag and the address would
no longer be treated as virtual IP when installing routes for CHILD_SAs
that reference it in their local traffic selectors.

Closes strongswan/strongswan#1807

src/libcharon/plugins/kernel_pfroute/kernel_pfroute_net.c

index b933b7c92ed9013263f9d7586aca15c49ef76204..02a8b59253c8287e7327a319e261f1306292540c 100644 (file)
@@ -780,20 +780,46 @@ static void process_addr(private_kernel_pfroute_net_t *this,
        }
 }
 
+/**
+ * Check if the address is already known so we can keep it as-is with the
+ * virtual flag.  Destroys the given host_t object if it is found.
+ */
+static bool existing_addr_entry(iface_entry_t *iface, linked_list_t *addrs,
+                                                               host_t *ip)
+{
+       enumerator_t *enumerator;
+       addr_entry_t *addr;
+       bool found = FALSE;
+
+       enumerator = addrs->create_enumerator(addrs);
+       while (enumerator->enumerate(enumerator, &addr))
+       {
+               if (ip->ip_equals(ip, addr->ip))
+               {
+                       ip->destroy(ip);
+                       addrs->remove_at(addrs, enumerator);
+                       iface->addrs->insert_last(iface->addrs, addr);
+                       found = TRUE;
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+       return found;
+}
+
 /**
  * Re-initialize address list of an interface if it changes state
  */
 static void repopulate_iface(private_kernel_pfroute_net_t *this,
                                                         iface_entry_t *iface)
 {
+       linked_list_t *addrs;
        struct ifaddrs *ifap, *ifa;
        addr_entry_t *addr;
+       host_t *ip;
 
-       while (iface->addrs->remove_last(iface->addrs, (void**)&addr) == SUCCESS)
-       {
-               addr_map_entry_remove(addr, iface, this);
-               addr_entry_destroy(addr);
-       }
+       addrs = iface->addrs;
+       iface->addrs = linked_list_create();
 
        if (getifaddrs(&ifap) == 0)
        {
@@ -805,11 +831,15 @@ static void repopulate_iface(private_kernel_pfroute_net_t *this,
                                {
                                        case AF_INET:
                                        case AF_INET6:
-                                               INIT(addr,
-                                                       .ip = host_create_from_sockaddr(ifa->ifa_addr),
-                                               );
-                                               iface->addrs->insert_last(iface->addrs, addr);
-                                               addr_map_entry_add(this, addr, iface);
+                                               ip = host_create_from_sockaddr(ifa->ifa_addr);
+                                               if (!existing_addr_entry(iface, addrs, ip))
+                                               {
+                                                       INIT(addr,
+                                                               .ip = ip,
+                                                       );
+                                                       iface->addrs->insert_last(iface->addrs, addr);
+                                                       addr_map_entry_add(this, addr, iface);
+                                               }
                                                break;
                                        default:
                                                break;
@@ -818,6 +848,13 @@ static void repopulate_iface(private_kernel_pfroute_net_t *this,
                }
                freeifaddrs(ifap);
        }
+
+       while (addrs->remove_last(addrs, (void**)&addr) == SUCCESS)
+       {
+               addr_map_entry_remove(addr, iface, this);
+               addr_entry_destroy(addr);
+       }
+       addrs->destroy(addrs);
 }
 
 /**