]> granicus.if.org Git - libevent/commitdiff
Merge branch 'evutil_found_ifaddr-dev'
authorAzat Khuzhin <a3at.mail@gmail.com>
Wed, 24 Oct 2018 21:50:50 +0000 (00:50 +0300)
committerAzat Khuzhin <azat@libevent.org>
Sat, 2 Feb 2019 12:18:00 +0000 (15:18 +0300)
* evutil_found_ifaddr-dev:
  Cover evutil_v4addr_is_local_()/evutil_v6addr_is_local_()
  Split evutil_found_ifaddr() into helpers (evutil_v{4,6}addr_is_local())
  Use INADDR_ANY over 0 in evutil_found_ifaddr()
  Replace EVUTIL_V4ADDR_IS_*() macroses with static inline functions
  Filter link-local IPv4 addresses in evutil_found_ifaddr()

(cherry picked from commit b2667b76969c2ea382373f885062b45e82d0ac59)

evutil.c
test/regress_util.c
util-internal.h

index 49c9014f7b7021ece394c0e2c6371215bddd319e..d93eff5fe3c0744f6b3247df3b2f27f1191c99f4 100644 (file)
--- a/evutil.c
+++ b/evutil.c
@@ -595,44 +595,56 @@ evutil_socket_finished_connecting_(evutil_socket_t fd)
    set by evutil_check_interfaces. */
 static int have_checked_interfaces, had_ipv4_address, had_ipv6_address;
 
-/* Macro: True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8
- */
-#define EVUTIL_V4ADDR_IS_LOCALHOST(addr) (((addr)>>24) == 127)
+/* True iff the IPv4 address 'addr', in host order, is in 127.0.0.0/8 */
+static inline int evutil_v4addr_is_localhost(ev_uint32_t addr)
+{ return addr>>24 == 127; }
 
-/* Macro: True iff the IPv4 address 'addr', in host order, is a class D
- * (multiclass) address.
- */
-#define EVUTIL_V4ADDR_IS_CLASSD(addr) ((((addr)>>24) & 0xf0) == 0xe0)
+/* True iff the IPv4 address 'addr', in host order, is link-local
+ * 169.254.0.0/16 (RFC3927) */
+static inline int evutil_v4addr_is_linklocal(ev_uint32_t addr)
+{ return ((addr & 0xffff0000U) == 0xa9fe0000U); }
+
+/* True iff the IPv4 address 'addr', in host order, is a class D
+ * (multiclass) address.  */
+static inline int evutil_v4addr_is_classd(ev_uint32_t addr)
+{ return ((addr>>24) & 0xf0) == 0xe0; }
+
+int
+evutil_v4addr_is_local_(const struct in_addr *in)
+{
+       const ev_uint32_t addr = ntohl(in->s_addr);
+       return addr == INADDR_ANY ||
+               evutil_v4addr_is_localhost(addr) ||
+               evutil_v4addr_is_linklocal(addr) ||
+               evutil_v4addr_is_classd(addr);
+}
+int
+evutil_v6addr_is_local_(const struct in6_addr *in)
+{
+       static const char ZEROES[] =
+               "\x00\x00\x00\x00\x00\x00\x00\x00"
+               "\x00\x00\x00\x00\x00\x00\x00\x00";
+
+       const unsigned char *addr = (const unsigned char *)in->s6_addr;
+       return !memcmp(addr, ZEROES, 8) ||
+               ((addr[0] & 0xfe) == 0xfc) ||
+               (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
+               (addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
+               (addr[0] == 0xff);
+}
 
 static void
 evutil_found_ifaddr(const struct sockaddr *sa)
 {
-       const char ZEROES[] = "\x00\x00\x00\x00\x00\x00\x00\x00"
-           "\x00\x00\x00\x00\x00\x00\x00\x00";
-
        if (sa->sa_family == AF_INET) {
                const struct sockaddr_in *sin = (struct sockaddr_in *)sa;
-               ev_uint32_t addr = ntohl(sin->sin_addr.s_addr);
-               if (addr == 0 ||
-                   EVUTIL_V4ADDR_IS_LOCALHOST(addr) ||
-                   EVUTIL_V4ADDR_IS_CLASSD(addr)) {
-                       /* Not actually a usable external address. */
-               } else {
+               if (!evutil_v4addr_is_local_(&sin->sin_addr)) {
                        event_debug(("Detected an IPv4 interface"));
                        had_ipv4_address = 1;
                }
        } else if (sa->sa_family == AF_INET6) {
                const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
-               const unsigned char *addr =
-                   (unsigned char*)sin6->sin6_addr.s6_addr;
-               if (!memcmp(addr, ZEROES, 8) ||
-                   ((addr[0] & 0xfe) == 0xfc) ||
-                   (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) ||
-                   (addr[0] == 0xfe && (addr[1] & 0xc0) == 0xc0) ||
-                   (addr[0] == 0xff)) {
-                       /* This is a reserved, ipv4compat, ipv4map, loopback,
-                        * link-local, multicast, or unspecified address. */
-               } else {
+               if (!evutil_v6addr_is_local_(&sin6->sin6_addr)) {
                        event_debug(("Detected an IPv6 interface"));
                        had_ipv6_address = 1;
                }
index 68281e6153f5315b1d4517cb38c2cc4d71e479d2..320047fa8c18f19ea5f7c7d34008921cb02ea7f5 100644 (file)
@@ -1455,6 +1455,83 @@ end:
        ;
 }
 
+static void
+test_evutil_v4addr_is_local(void *arg)
+{
+       struct sockaddr_in sin;
+       sin.sin_family = AF_INET;
+
+       /* we use evutil_inet_pton() here to fill in network-byte order */
+#define LOCAL(str, yes) do {                                              \
+       tt_int_op(evutil_inet_pton(AF_INET, str, &sin.sin_addr), ==, 1);  \
+       tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, yes);       \
+} while (0)
+
+       /** any */
+       sin.sin_addr.s_addr = INADDR_ANY;
+       tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, 1);
+
+       /** loopback */
+       sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       tt_int_op(evutil_v4addr_is_local_(&sin.sin_addr), ==, 1);
+       LOCAL("127.0.0.1", 1);
+       LOCAL("127.255.255.255", 1);
+       LOCAL("121.0.0.1", 0);
+
+       /** link-local */
+       LOCAL("169.254.0.1", 1);
+       LOCAL("169.254.255.255", 1);
+       LOCAL("170.0.0.0", 0);
+
+       /** Multicast */
+       LOCAL("224.0.0.0", 1);
+       LOCAL("239.255.255.255", 1);
+       LOCAL("240.0.0.0", 0);
+end:
+       ;
+}
+
+static void
+test_evutil_v6addr_is_local(void *arg)
+{
+       struct sockaddr_in6 sin6;
+       struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
+       struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT;
+
+       sin6.sin6_family = AF_INET6;
+#define LOCAL6(str, yes) do {                                              \
+       tt_int_op(evutil_inet_pton(AF_INET6, str, &sin6.sin6_addr), ==, 1);\
+       tt_int_op(evutil_v6addr_is_local_(&sin6.sin6_addr), ==, yes);      \
+} while (0)
+
+       /** any */
+       tt_int_op(evutil_v6addr_is_local_(&anyaddr), ==, 1);
+       LOCAL6("::0", 1);
+
+       /** loopback */
+       tt_int_op(evutil_v6addr_is_local_(&loopback), ==, 1);
+       LOCAL6("::1", 1);
+
+       /** IPV4 mapped */
+       LOCAL6("::ffff:0:0", 1);
+       /** IPv4 translated */
+       LOCAL6("::ffff:0:0:0", 1);
+       /** IPv4/IPv6 translation */
+       LOCAL6("64:ff9b::", 0);
+       /** Link-local */
+       LOCAL6("fe80::", 1);
+       /** Multicast */
+       LOCAL6("ff00::", 1);
+       /** Unspecified */
+       LOCAL6("::", 1);
+
+       /** Global Internet */
+       LOCAL6("2001::", 0);
+       LOCAL6("2001:4860:4802:32::1b", 0);
+end:
+       ;
+}
+
 struct testcase_t util_testcases[] = {
        { "ipv4_parse", regress_ipv4_parse, 0, NULL, NULL },
        { "ipv6_parse", regress_ipv6_parse, 0, NULL, NULL },
@@ -1486,6 +1563,8 @@ struct testcase_t util_testcases[] = {
        { "monotonic_prc_precise", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"precise" },
        { "monotonic_prc_fallback", test_evutil_monotonic_prc, 0, &basic_setup, (void*)"fallback" },
        { "date_rfc1123", test_evutil_date_rfc1123, 0, NULL, NULL },
+       { "evutil_v4addr_is_local", test_evutil_v4addr_is_local, 0, NULL, NULL },
+       { "evutil_v6addr_is_local", test_evutil_v6addr_is_local, 0, NULL, NULL },
        END_OF_TESTCASES,
 };
 
index fe416409f06e897e958bd3e0e7a39d61f1511cde..b727bf1fd7e9701b0be348dc69c8c1391e2ae195 100644 (file)
@@ -527,6 +527,17 @@ evutil_socket_t evutil_eventfd_(unsigned initval, int flags);
 
 void evutil_memclear_(void *mem, size_t len);
 
+struct in_addr;
+struct in6_addr;
+
+/* This is a any, loopback, link-local, multicast */
+EVENT2_EXPORT_SYMBOL
+int evutil_v4addr_is_local_(const struct in_addr *in);
+/* This is a reserved, ipv4compat, ipv4map, loopback,
+ * link-local, multicast, or unspecified address. */
+EVENT2_EXPORT_SYMBOL
+int evutil_v6addr_is_local_(const struct in6_addr *in);
+
 #ifdef __cplusplus
 }
 #endif