]> git.ipfire.org Git - people/ms/libloc.git/blobdiff - src/network.c
networks: Improve parsing IP addresses
[people/ms/libloc.git] / src / network.c
index a4c7646e90fccd4d4ca3622209f2d9ae202299d7..c112a41d3428b5235737f49f2bab32fd003bd129 100644 (file)
@@ -35,6 +35,7 @@ struct loc_network {
        struct loc_ctx* ctx;
        int refcount;
 
+       int family;
        struct in6_addr first_address;
        struct in6_addr last_address;
        unsigned int prefix;
@@ -145,6 +146,12 @@ LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network
        n->first_address = make_first_address(address, &bitmask);
        n->last_address = make_last_address(&n->first_address, &bitmask);
 
+       // Set family
+       if (IN6_IS_ADDR_V4MAPPED(&n->first_address))
+               n->family = AF_INET;
+       else
+               n->family = AF_INET6;
+
        DEBUG(n->ctx, "Network allocated at %p\n", n);
        *network = n;
        return 0;
@@ -153,9 +160,10 @@ LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network
 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;
-       unsigned int prefix = 0;
        char* prefix_string;
-       int r = 1;
+       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);
@@ -164,29 +172,46 @@ LOC_EXPORT int loc_network_new_from_string(struct loc_ctx* ctx, struct loc_netwo
        // Split address and prefix
        address_string = strsep(&prefix_string, "/");
 
-       // Did we find a prefix?
-       if (prefix_string) {
-               // Convert prefix to integer
-               prefix = strtol(prefix_string, NULL, 10);
+       DEBUG(ctx, "  Split into address = %s, prefix = %s\n", address_string, prefix_string);
 
-               if (prefix) {
-                       // Parse the address
-                       r = loc_parse_address(ctx, address_string, &first_address);
+       // We need to have a prefix
+       if (!prefix_string) {
+               DEBUG(ctx, "No prefix set\n");
+               goto FAIL;
+       }
 
-                       // Map the prefix to IPv6 if needed
-                       if (IN6_IS_ADDR_V4MAPPED(&first_address))
-                               prefix += 96;
-               }
+       // Convert prefix to integer
+       unsigned int prefix = strtol(prefix_string, NULL, 10);
+
+       // End if the prefix was invalid
+       if (!prefix) {
+               DEBUG(ctx, "The prefix is zero or not a number\n");
+               goto FAIL;
        }
 
+       // Parse the address
+       r = loc_parse_address(ctx, address_string, &first_address);
+       if (r) {
+               DEBUG(ctx, "The address could not be parsed\n");
+               goto FAIL;
+       }
+
+       // Map the prefix to IPv6 if needed
+       if (IN6_IS_ADDR_V4MAPPED(&first_address))
+               prefix += 96;
+
+FAIL:
        // Free temporary buffer
        free(buffer);
 
-       if (r == 0) {
-               r = loc_network_new(ctx, network, &first_address, prefix);
-       }
+       // Exit if the parsing was unsuccessful
+       if (r)
+               return r;
+
+       DEBUG(ctx, "GOT HERE\n");
 
-       return r;
+       // Create a new network
+       return loc_network_new(ctx, network, &first_address, prefix);
 }
 
 LOC_EXPORT struct loc_network* loc_network_ref(struct loc_network* network) {
@@ -242,8 +267,7 @@ LOC_EXPORT char* loc_network_str(struct loc_network* network) {
 
        unsigned int prefix = network->prefix;
 
-       int family = loc_network_address_family(network);
-       switch (family) {
+       switch (network->family) {
                case AF_INET6:
                        r = format_ipv6_address(&network->first_address, string, length);
                        break;
@@ -272,10 +296,48 @@ LOC_EXPORT char* loc_network_str(struct loc_network* network) {
 }
 
 LOC_EXPORT int loc_network_address_family(struct loc_network* network) {
-       if (IN6_IS_ADDR_V4MAPPED(&network->first_address))
-               return AF_INET;
+       return network->family;
+}
+
+static char* loc_network_format_address(struct loc_network* network, const struct in6_addr* address) {
+       const size_t length = INET6_ADDRSTRLEN;
+
+       char* string = malloc(length);
+       if (!string)
+               return NULL;
+
+       int r = 0;
+
+       switch (network->family) {
+               case AF_INET6:
+                       r = format_ipv6_address(address, string, length);
+                       break;
+
+               case AF_INET:
+                       r = format_ipv4_address(address, string, length);
+                       break;
+
+               default:
+                       r = -1;
+                       break;
+       }
+
+       if (r) {
+               ERROR(network->ctx, "Could not format IP address to string: %s\n", strerror(errno));
+               free(string);
+
+               return NULL;
+       }
+
+       return string;
+}
+
+LOC_EXPORT char* loc_network_format_first_address(struct loc_network* network) {
+       return loc_network_format_address(network, &network->first_address);
+}
 
-       return AF_INET6;
+LOC_EXPORT char* loc_network_format_last_address(struct loc_network* network) {
+       return loc_network_format_address(network, &network->last_address);
 }
 
 LOC_EXPORT int loc_network_match_address(struct loc_network* network, const struct in6_addr* address) {