]> git.ipfire.org Git - people/ms/libloc.git/blobdiff - src/network.c
Prevent segmentation fault when no prefix is present
[people/ms/libloc.git] / src / network.c
index bc359f6c408163464e6678e6c5816beab7d3ed5a..dc1775a83da18424b231547a64dabf887703620d 100644 (file)
 #include <assert.h>
 #include <endian.h>
 #include <errno.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include <loc/libloc.h>
 #include <loc/network.h>
-
-#include "libloc-private.h"
-#include "as.h"
+#include <loc/private.h>
 
 struct loc_network {
        struct loc_ctx* ctx;
@@ -35,8 +34,7 @@ struct loc_network {
        unsigned int prefix;
 
        char country_code[3];
-
-       struct loc_as* as;
+       uint32_t asn;
 };
 
 LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network,
@@ -80,10 +78,50 @@ LOC_EXPORT int loc_network_new(struct loc_ctx* ctx, struct loc_network** network
        return 0;
 }
 
+static int loc_network_address_family(struct loc_network* network) {
+       if (IN6_IS_ADDR_V4MAPPED(&network->start_address))
+               return AF_INET;
+
+       return AF_INET6;
+}
+
+static int parse_address(struct loc_ctx* ctx, const char* string, struct in6_addr* address) {
+       DEBUG(ctx, "Paring 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 1;
+}
+
 LOC_EXPORT int loc_network_new_from_string(struct loc_ctx* ctx, struct loc_network** network,
                const char* address_string) {
        struct in6_addr start_address;
+       unsigned int prefix = 0;
        char* prefix_string;
+       int r = 1;
 
        // Make a copy of the string to work on it
        char* buffer = strdup(address_string);
@@ -92,16 +130,21 @@ LOC_EXPORT int loc_network_new_from_string(struct loc_ctx* ctx, struct loc_netwo
        // Split address and prefix
        address_string = strsep(&prefix_string, "/");
 
-       // Convert prefix to integer
-       unsigned int prefix = strtol(prefix_string, NULL, 10);
+       // Did we find a prefix?
+       if (prefix_string) {
+               // Convert prefix to integer
+               prefix = strtol(prefix_string, NULL, 10);
 
-       // Parse the address
-       int r = inet_pton(AF_INET6, address_string, &start_address);
+               if (prefix) {
+                       // Parse the address
+                       r = parse_address(ctx, address_string, &start_address);
+               }
+       }
 
        // Free temporary buffer
        free(buffer);
 
-       if (r == 1) {
+       if (r == 0) {
                r = loc_network_new(ctx, network, start_address, prefix);
        }
 
@@ -117,9 +160,6 @@ LOC_EXPORT struct loc_network* loc_network_ref(struct loc_network* network) {
 static void loc_network_free(struct loc_network* network) {
        DEBUG(network->ctx, "Releasing network at %p\n", network);
 
-       if (network->as)
-               loc_as_unref(network->as);
-
        loc_unref(network->ctx);
        free(network);
 }
@@ -132,18 +172,52 @@ LOC_EXPORT struct loc_network* loc_network_unref(struct loc_network* network) {
        return NULL;
 }
 
+static int format_ipv6_address(struct loc_network* network, char* string, size_t length) {
+       const char* ret = inet_ntop(AF_INET6, &network->start_address, string, length);
+       if (!ret)
+               return -1;
+
+       return 0;
+}
+
+static int format_ipv4_address(struct loc_network* network, char* string, size_t length) {
+       struct in_addr ipv4_address;
+       ipv4_address.s_addr = network->start_address.s6_addr32[3];
+
+       const char* ret = inet_ntop(AF_INET, &ipv4_address, string, length);
+       if (!ret)
+               return -1;
+
+       return 0;
+}
+
 LOC_EXPORT char* loc_network_str(struct loc_network* network) {
-       const size_t l = INET6_ADDRSTRLEN + 3;
+       int r;
+       const size_t length = INET6_ADDRSTRLEN + 4;
 
-       char* string = malloc(l);
+       char* string = malloc(length);
        if (!string)
                return NULL;
 
-       const char* ret = inet_ntop(AF_INET6, &network->start_address, string, l);
-       if (!ret) {
-               ERROR(network->ctx, "Could not convert network to string: %s\n", strerror(errno));
+       int family = loc_network_address_family(network);
+       switch (family) {
+               case AF_INET6:
+                       r = format_ipv6_address(network, string, length);
+                       break;
+
+               case AF_INET:
+                       r = format_ipv4_address(network, string, length);
+                       break;
 
+               default:
+                       r = -1;
+                       break;
+       }
+
+       if (r) {
+               ERROR(network->ctx, "Could not convert network to string: %s\n", strerror(errno));
                free(string);
+
                return NULL;
        }
 
@@ -169,6 +243,16 @@ LOC_EXPORT int loc_network_set_country_code(struct loc_network* network, const c
        return 0;
 }
 
+LOC_EXPORT uint32_t loc_network_get_asn(struct loc_network* network) {
+       return network->asn;
+}
+
+LOC_EXPORT int loc_network_set_asn(struct loc_network* network, uint32_t asn) {
+       network->asn = asn;
+
+       return 0;
+}
+
 LOC_EXPORT int loc_network_to_database_v0(struct loc_network* network, struct loc_database_network_v0* dbobj) {
        dbobj->prefix = htobe16(network->prefix);
 
@@ -178,11 +262,7 @@ LOC_EXPORT int loc_network_to_database_v0(struct loc_network* network, struct lo
        }
 
        // Add ASN
-       uint32_t asn = 0;
-       if (network->as) {
-               asn = loc_as_get_number(network->as);
-       }
-       dbobj->asn = htobe32(asn);
+       dbobj->asn = htobe32(network->asn);
 
        return 0;
 }