From: Michael Tremer Date: Wed, 9 Mar 2022 11:42:47 +0000 (+0000) Subject: Refactor parsing IP addresses X-Git-Tag: 0.9.12~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=95b6a8e402bdb88e7196d5d8c65ddfd908873d75;p=location%2Flibloc.git Refactor parsing IP addresses Signed-off-by: Michael Tremer --- diff --git a/src/address.c b/src/address.c index eab389e..ff4630e 100644 --- a/src/address.c +++ b/src/address.c @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include #include @@ -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; +} diff --git a/src/database.c b/src/database.c index 2fda719..8835507 100644 --- a/src/database.c +++ b/src/database.c @@ -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; diff --git a/src/libloc.c b/src/libloc.c index 1fee08e..cf2d740 100644 --- a/src/libloc.c +++ b/src/libloc.c @@ -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; -} diff --git a/src/libloc/address.h b/src/libloc/address.h index 0bc04b2..f7fe333 100644 --- a/src/libloc/address.h +++ b/src/libloc/address.h @@ -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)) diff --git a/src/libloc/libloc.h b/src/libloc/libloc.h index 4854a41..938ed75 100644 --- a/src/libloc/libloc.h +++ b/src/libloc/libloc.h @@ -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 diff --git a/src/network.c b/src/network.c index 219cb2b..b720a0a 100644 --- a/src/network.c +++ b/src/network.c @@ -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) { diff --git a/src/test-network.c b/src/test-network.c index f27a06b..1c49d60 100644 --- a/src/test-network.c +++ b/src/test-network.c @@ -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); }