Commit 95b6a8e4 authored by Michael Tremer's avatar Michael Tremer

Refactor parsing IP addresses

Signed-off-by: default avatarMichael Tremer <michael.tremer@ipfire.org>
parent d57cf1fc
......@@ -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;
}
......@@ -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;
......
......@@ -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;
}
......@@ -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))
......
......@@ -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
......
......@@ -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) {
......
......@@ -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);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment