]> git.ipfire.org Git - location/libloc.git/commitdiff
Refactor parsing IP addresses
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 9 Mar 2022 11:42:47 +0000 (11:42 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 9 Mar 2022 11:42:47 +0000 (11:42 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/address.c
src/database.c
src/libloc.c
src/libloc/address.h
src/libloc/libloc.h
src/network.c
src/test-network.c

index eab389e7d0aad71f098218728ae190b3cc2f722d..ff4630e85c1136735d09369a10bcf9f97f0103a0 100644 (file)
@@ -17,6 +17,9 @@
 #include <arpa/inet.h>
 #include <netinet/in.h>
 #include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
 #include <libloc/address.h>
 
@@ -53,3 +56,94 @@ const char* loc_address_str(const struct in6_addr* address) {
        else
                return __loc_address6_str(address, buffer, LOC_ADDRESS_BUFFER_LENGTH);
 }
+
+static void loc_address_from_address4(struct in6_addr* address,
+               const struct in_addr* address4) {
+       address->s6_addr32[0] = 0;
+       address->s6_addr32[1] = 0;
+       address->s6_addr32[2] = htonl(0xffff);
+       address->s6_addr32[3] = address4->s_addr;
+}
+
+int loc_address_parse(struct in6_addr* address, unsigned int* prefix, const char* string) {
+       char buffer[INET6_ADDRSTRLEN + 4];
+       int r;
+
+       if (!address || !string) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       // Copy the string into the buffer
+       r = snprintf(buffer, sizeof(buffer) - 1, "%s", string);
+       if (r < 0)
+               return 1;
+
+       // Find /
+       char* p = strchr(buffer, '/');
+       if (p) {
+               // Terminate the IP address
+               *p++ = '\0';
+       }
+
+       int family = AF_UNSPEC;
+
+       // Try parsing as an IPv6 address
+       r = inet_pton(AF_INET6, buffer, address);
+       switch (r) {
+               // This is not a valid IPv6 address
+               case 0:
+                       break;
+
+               // This is a valid IPv6 address
+               case 1:
+                       family = AF_INET6;
+                       break;
+
+               // Unexpected error
+               default:
+                       return 1;
+       }
+
+       // Try parsing as an IPv4 address
+       if (!family) {
+               struct in_addr address4;
+
+               r = inet_pton(AF_INET, buffer, &address4);
+               switch (r) {
+                       // This was not a valid IPv4 address
+                       case 0:
+                               break;
+
+                       // This was a valid IPv4 address
+                       case 1:
+                               family = AF_INET;
+
+                               // Copy the result
+                               loc_address_from_address4(address, &address4);
+                               break;
+
+                       // Unexpected error
+                       default:
+                               return 1;
+               }
+       }
+
+       // Invalid input
+       if (family == AF_UNSPEC) {
+               errno = EINVAL;
+               return 1;
+       }
+
+       // Did the user request a prefix?
+       if (prefix) {
+               // Set the prefix to the default value
+               *prefix = loc_address_family_bit_length(family);
+
+               // Parse the actual string
+               if (p)
+                       *prefix = strtol(p, NULL, 10);
+       }
+
+       return 0;
+}
index 2fda719a8c35dbcaa72b9238ab80a68f5f25300d..8835507e7be4bdb3c9e7b654d84d8d63f70227d0 100644 (file)
@@ -876,7 +876,7 @@ LOC_EXPORT int loc_database_lookup_from_string(struct loc_database* db,
                const char* string, struct loc_network** network) {
        struct in6_addr address;
 
-       int r = loc_parse_address(db->ctx, string, &address);
+       int r = loc_address_parse(&address, NULL, string);
        if (r)
                return r;
 
index 1fee08eaf7993600b9b2e6fa8fed71d24887ee93..cf2d740a6cde39aabe486b9f347b7bee72ea983c 100644 (file)
@@ -130,34 +130,3 @@ LOC_EXPORT int loc_get_log_priority(struct loc_ctx* ctx) {
 LOC_EXPORT void loc_set_log_priority(struct loc_ctx* ctx, int priority) {
        ctx->log_priority = priority;
 }
-
-LOC_EXPORT int loc_parse_address(struct loc_ctx* ctx, const char* string, struct in6_addr* address) {
-       DEBUG(ctx, "Parsing IP address %s\n", string);
-
-       // Try parsing this as an IPv6 address
-       int r = inet_pton(AF_INET6, string, address);
-
-       // If inet_pton returns one it has been successful
-       if (r == 1) {
-               DEBUG(ctx, "%s is an IPv6 address\n", string);
-               return 0;
-       }
-
-       // Try parsing this as an IPv4 address
-       struct in_addr ipv4_address;
-       r = inet_pton(AF_INET, string, &ipv4_address);
-       if (r == 1) {
-               DEBUG(ctx, "%s is an IPv4 address\n", string);
-
-               // Convert to IPv6-mapped address
-               address->s6_addr32[0] = htonl(0x0000);
-               address->s6_addr32[1] = htonl(0x0000);
-               address->s6_addr32[2] = htonl(0xffff);
-               address->s6_addr32[3] = ipv4_address.s_addr;
-
-               return 0;
-       }
-
-       DEBUG(ctx, "%s is not an valid IP address\n", string);
-       return -EINVAL;
-}
index 0bc04b23b92a2487ec4c34a511bec4a4facc7d7d..f7fe333a9ee6133557becc43aee1ec5337a40858 100644 (file)
@@ -27,6 +27,7 @@
 */
 
 const char* loc_address_str(const struct in6_addr* address);
+int loc_address_parse(struct in6_addr* address, unsigned int* prefix, const char* string);
 
 static inline int loc_address_family(const struct in6_addr* address) {
        if (IN6_IS_ADDR_V4MAPPED(address))
index 4854a418b1e554604824f7f323a8b44cdbc0bcd6..938ed75e0f1d77e4d28fd29e4c0e75f8e0c6fa2e 100644 (file)
@@ -36,10 +36,6 @@ void loc_set_log_fn(struct loc_ctx* ctx,
 int loc_get_log_priority(struct loc_ctx* ctx);
 void loc_set_log_priority(struct loc_ctx* ctx, int priority);
 
-#ifdef LIBLOC_PRIVATE
-int loc_parse_address(struct loc_ctx* ctx, const char* string, struct in6_addr* address);
-#endif
-
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index 219cb2be6147410084353be133c31321dafbcee0..b720a0a85a415472cf6e19944e20cf397868ca3a 100644 (file)
@@ -53,7 +53,7 @@ LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network
                struct in6_addr* address, unsigned int prefix) {
        // Validate the prefix
        if (!loc_address_valid_prefix(address, prefix)) {
-               ERROR(ctx, "Invalid prefix: %u\n", prefix);
+               ERROR(ctx, "Invalid prefix in %s: %u\n", loc_address_str(address), prefix);
                errno = EINVAL;
                return 1;
        }
@@ -88,52 +88,20 @@ LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network
        return 0;
 }
 
-LOC_EXPORT int loc_network_new_from_string(struct loc_ctx* ctx, struct loc_network** network,
-               const char* address_string) {
-       struct in6_addr first_address;
-       char* prefix_string;
-       unsigned int prefix = 128;
-       int r = -EINVAL;
-
-       DEBUG(ctx, "Attempting to parse network %s\n", address_string);
-
-       // Make a copy of the string to work on it
-       char* buffer = strdup(address_string);
-       address_string = prefix_string = buffer;
-
-       // Split address and prefix
-       address_string = strsep(&prefix_string, "/");
-
-       DEBUG(ctx, "  Split into address = %s, prefix = %s\n", address_string, prefix_string);
+LOC_EXPORT int loc_network_new_from_string(struct loc_ctx* ctx,
+               struct loc_network** network, const char* string) {
+       struct in6_addr address;
+       unsigned int prefix;
 
-       // Parse the address
-       r = loc_parse_address(ctx, address_string, &first_address);
+       // Parse the input
+       int r = loc_address_parse(&address, &prefix, string);
        if (r) {
-               DEBUG(ctx, "The address could not be parsed\n");
-               goto FAIL;
-       }
-
-       // If a prefix was given, we will try to parse it
-       if (prefix_string) {
-               // Convert prefix to integer
-               prefix = strtol(prefix_string, NULL, 10);
-
-               if (!prefix) {
-                       DEBUG(ctx, "The prefix was not parsable: %s\n", prefix_string);
-                       goto FAIL;
-               }
-       }
-
-FAIL:
-       // Free temporary buffer
-       free(buffer);
-
-       // Exit if the parsing was unsuccessful
-       if (r)
+               ERROR(ctx, "Could not parse network %s: %m\n", string);
                return r;
+       }
 
        // Create a new network
-       return loc_network_new(ctx, network, &first_address, prefix);
+       return loc_network_new(ctx, network, &address, prefix);
 }
 
 LOC_EXPORT struct loc_network* loc_network_ref(struct loc_network* network) {
index f27a06ba19c6244e7973823252d305bbcdeb583e..1c49d60658395e5fd10a882f8a41bb9ef4b725f1 100644 (file)
@@ -246,7 +246,7 @@ int main(int argc, char** argv) {
        // Try adding an invalid network
        struct loc_network* network;
        err = loc_writer_add_network(writer, &network, "xxxx:xxxx::/32");
-       if (err != -EINVAL) {
+       if (!err) {
                fprintf(stderr, "It was possible to add an invalid network (err = %d)\n", err);
                exit(EXIT_FAILURE);
        }