diff --git a/src/util.c b/src/util.c index c7f27ea..074009f 100644 --- a/src/util.c +++ b/src/util.c @@ -24,6 +24,8 @@ #include "util.h" +#include +#include gboolean @@ -225,3 +227,52 @@ get_call_icon_symbolic_name (gboolean inbound, return type_icon_name[index]; } + +/** + * get_address_family_for_ip: + * @ip: The IP address to check + * @only_configured_interfaces: Only consider address families of configured + * network interfaces + * + * Returns: #AF_INET for IPv4, #AF_INET6 for IPv6 and #AF_UNSPEC otherwise. + * If @only_configured_interfaces is #TRUE and the resulting address family of @ip + * is not configured on any network interface, it will also return #AF_UNSPEC + */ +int +get_address_family_for_ip (const char *ip, + gboolean only_configured_interfaces) +{ + struct addrinfo hints = { 0 }; + struct addrinfo *result; + int family = AF_UNSPEC; + int res_gai; + + g_return_val_if_fail (!STR_IS_NULL_OR_EMPTY (ip), AF_UNSPEC); + + hints.ai_flags = AI_V4MAPPED | AI_NUMERICHOST; + if (only_configured_interfaces) + hints.ai_flags |= AI_ADDRCONFIG; + hints.ai_family = AF_UNSPEC; + + + res_gai = getaddrinfo (ip, NULL, &hints, &result); + if (res_gai != 0) { + g_info ("Cannot get address information for host %s: %s", + ip, + gai_strerror (res_gai)); + + return AF_UNSPEC; + } + + family = result->ai_family; + + freeaddrinfo (result); + + if (family != AF_INET && family != AF_INET6) { + g_warning ("Address information for host %s indicates non internet host", ip); + + return AF_UNSPEC; + } + + return family; +} diff --git a/src/util.h b/src/util.h index 4f4f88a..9a7e284 100644 --- a/src/util.h +++ b/src/util.h @@ -129,5 +129,7 @@ const char *get_protocol_from_address_with_fallback (const char *target); gboolean dtmf_tone_key_is_valid (char key); const char *get_call_icon_symbolic_name (gboolean inbound, gboolean missed); +int get_address_family_for_ip (const char *ip, + gboolean only_configured_interfaces); G_END_DECLS diff --git a/tests/test-util.c b/tests/test-util.c index 31182b2..3ba0fb3 100644 --- a/tests/test-util.c +++ b/tests/test-util.c @@ -10,6 +10,9 @@ #include +#include + + static void test_protocol_prefix (void) { @@ -69,6 +72,27 @@ test_null_empty_strings (void) g_assert_false (STR_IS_NULL_OR_EMPTY ("lorem ipsum")); } + +static void +test_ip_address_family (void) +{ + g_assert_cmpint (get_address_family_for_ip ("10.42.0.1", FALSE), ==, AF_INET); + g_assert_cmpint (get_address_family_for_ip ("9.9.9.9", FALSE), ==, AF_INET); + g_assert_cmpint (get_address_family_for_ip ("127.0.0.1", FALSE), ==, AF_INET); + g_assert_cmpint (get_address_family_for_ip ("0.0.0.0", FALSE), ==, AF_INET); + + + g_assert_cmpint (get_address_family_for_ip ("FE80:0000:0000:0000:0202:C3DF:FE1E:8329", FALSE), ==, AF_INET6); + g_assert_cmpint (get_address_family_for_ip ("FE80::0202:C3DF:FE1E:8329", FALSE), ==, AF_INET6); + g_assert_cmpint (get_address_family_for_ip ("fe80::0202:c3df:fe1e:8329", FALSE), ==, AF_INET6); + g_assert_cmpint (get_address_family_for_ip ("::", FALSE), ==, AF_INET6); + g_assert_cmpint (get_address_family_for_ip ("::1", FALSE), ==, AF_INET6); + + g_assert_cmpint (get_address_family_for_ip ("example.org", FALSE), ==, AF_UNSPEC); + +} + + int main (int argc, char *argv[]) @@ -79,6 +103,7 @@ main (int argc, g_test_add_func ("/Calls/util/dtmf_tones", (GTestFunc) test_dtmf_tone_validity); g_test_add_func ("/Calls/util/call_icon_names", (GTestFunc) test_call_icon_names); g_test_add_func ("/Calls/util/null-or-empty-strings", (GTestFunc) test_null_empty_strings); + g_test_add_func ("/Calls/util/ip_address_family", (GTestFunc) test_ip_address_family); g_test_run (); }