]> git.ipfire.org Git - people/ms/libloc.git/commitdiff
network: Add function to exclude multiple networks at once
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 12 Nov 2020 20:01:17 +0000 (20:01 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 12 Nov 2020 20:01:17 +0000 (20:01 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libloc.sym
src/loc/network.h
src/network.c

index 5392437dd2300a066ce84a5e0cbb08d08e63a515..bcd11be97336691fe1d8819b9a9a4d66945a0d69 100644 (file)
@@ -82,6 +82,7 @@ global:
        loc_network_address_family;
        loc_network_eq;
        loc_network_exclude;
+       loc_network_exclude_list;
        loc_network_format_first_address;
        loc_network_format_last_address;
        loc_network_get_asn;
index 2154cdc9b3ebca7b99b0767571906e5ae62990c4..40712b96be5ff449506a5f83e0474d342dab19ec 100644 (file)
@@ -61,6 +61,8 @@ int loc_network_is_subnet_of(struct loc_network* self, struct loc_network* other
 struct loc_network_list* loc_network_subnets(struct loc_network* network);
 struct loc_network_list* loc_network_exclude(
                struct loc_network* self, struct loc_network* other);
+struct loc_network_list* loc_network_exclude_list(
+               struct loc_network* network, struct loc_network_list* list);
 
 // List
 struct loc_network_list;
index 5719111252e31ad2f6e417dfbddedab4c3f58241..751e8e5ba1b4235d28afa7e8d5113533143ffb10 100644 (file)
@@ -677,6 +677,91 @@ ERROR:
        return NULL;
 }
 
+LOC_EXPORT struct loc_network_list* loc_network_exclude_list(
+               struct loc_network* network, struct loc_network_list* list) {
+       struct loc_network_list* to_check;
+
+       // Create a new list with all networks to look at
+       int r = loc_network_list_new(network->ctx, &to_check);
+       if (r)
+               return NULL;
+
+       struct loc_network* subnet = NULL;
+       struct loc_network_list* subnets = NULL;
+
+       for (unsigned int i = 0; i < loc_network_list_size(list); i++) {
+               subnet = loc_network_list_get(list, i);
+
+               // Find all excluded networks
+               struct loc_network_list* excluded = loc_network_exclude(network, subnet);
+               if (excluded) {
+                       // Add them all to the "to check" list
+                       loc_network_list_merge(to_check, excluded);
+                       loc_network_list_unref(excluded);
+               }
+
+               // Cleanup
+               loc_network_unref(subnet);
+       }
+
+       r = loc_network_list_new(network->ctx, &subnets);
+       if (r) {
+               loc_network_list_unref(to_check);
+               return NULL;
+       }
+
+       while (!loc_network_list_empty(to_check)) {
+               struct loc_network* subnet_to_check = loc_network_list_pop(to_check);
+
+               // Marks whether this subnet passed all checks
+               int passed = 1;
+
+               for (unsigned int i = 0; i < loc_network_list_size(list); i++) {
+                       subnet = loc_network_list_get(list, i);
+
+                       // Drop this subnet if is is already in list
+                       if (loc_network_eq(subnet_to_check, subnet)) {
+                               passed = 0;
+                               loc_network_unref(subnet);
+                               break;
+                       }
+
+                       // Drop this subnet if is a subnet of another subnet
+                       if (loc_network_is_subnet_of(subnet, subnet_to_check)) {
+                               passed = 0;
+                               loc_network_unref(subnet);
+                               break;
+                       }
+
+                       // Break it down if it overlaps
+                       if (loc_network_overlaps(subnet_to_check, subnet)) {
+                               passed = 0;
+
+                               struct loc_network_list* excluded = loc_network_exclude(subnet_to_check, subnet);
+                               if (excluded) {
+                                       loc_network_list_merge(to_check, excluded);
+                                       loc_network_list_unref(excluded);
+                               }
+
+                               loc_network_unref(subnet);
+                               break;
+                       }
+
+                       loc_network_unref(subnet);
+               }
+
+               if (passed) {
+                       r = loc_network_list_push(subnets, subnet_to_check);
+               }
+
+               loc_network_unref(subnet_to_check);
+       }
+
+       loc_network_list_unref(to_check);
+
+       return subnets;
+}
+
 LOC_EXPORT int loc_network_to_database_v1(struct loc_network* network, struct loc_database_network_v1* dbobj) {
        // Add country code
        loc_country_code_copy(dbobj->country_code, network->country_code);