From 4f26a83faa216e1031954c94f73a45d4077d0c3b Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 27 Sep 2019 07:42:46 -0700 Subject: [PATCH] Normalize IPv4 prefix lengths --- ext/maxminddb.c | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/ext/maxminddb.c b/ext/maxminddb.c index 6a945d2..478fe04 100644 --- a/ext/maxminddb.c +++ b/ext/maxminddb.c @@ -240,17 +240,34 @@ static void get_record(INTERNAL_FUNCTION_PARAMETERS, return; } - int gai_error = 0; - int mmdb_error = MMDB_SUCCESS; - MMDB_lookup_result_s result = - MMDB_lookup_string(mmdb, ip_address, &gai_error, &mmdb_error); - - if (MMDB_SUCCESS != gai_error) { + struct addrinfo hints = { + .ai_family = AF_UNSPEC, + .ai_flags = AI_NUMERICHOST, + // We set ai_socktype so that we only get one result back + .ai_socktype = SOCK_STREAM}; + + struct addrinfo *addresses = NULL; + int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses); + if (gai_status) { THROW_EXCEPTION("InvalidArgumentException", "The value \"%s\" is not a valid IP address.", ip_address); return; } + if (!addresses && !addresses->ai_addr) { + THROW_EXCEPTION( + "InvalidArgumentException", + "getaddrinfo was successful but failed to set the addrinfo"); + return; + } + + int sa_family = addresses->ai_addr->sa_family; + + int mmdb_error = MMDB_SUCCESS; + MMDB_lookup_result_s result = + MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error); + + freeaddrinfo(addresses); if (MMDB_SUCCESS != mmdb_error) { char *exception_name; @@ -268,13 +285,18 @@ static void get_record(INTERNAL_FUNCTION_PARAMETERS, *prefix_len = result.netmask; - MMDB_entry_data_list_s *entry_data_list = NULL; + if (sa_family == AF_INET && mmdb->metadata.ip_version == 6) { + // We return the prefix length given the IPv4 address. If there is + // no IPv4 subtree, we return a prefix length of 0. + *prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0; + } if (!result.found_entry) { ZVAL_NULL(record); return; } + MMDB_entry_data_list_s *entry_data_list = NULL; int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list); if (MMDB_SUCCESS != status) {