summaryrefslogtreecommitdiff
path: root/src/common/address.c
diff options
context:
space:
mode:
authorteor (Tim Wilson-Brown) <teor2345@gmail.com>2015-09-15 17:04:18 +1000
committerteor (Tim Wilson-Brown) <teor2345@gmail.com>2015-09-15 17:04:18 +1000
commit31eb486c4624d1437d982ffdfc1f9d7d83c5ffd6 (patch)
tree63993443cc4c4eb32efc6e218e0c35a03d956158 /src/common/address.c
parenta444b11323799536b4cd7902e29f711b0806293a (diff)
downloadtor-31eb486c4624d1437d982ffdfc1f9d7d83c5ffd6.tar.gz
tor-31eb486c4624d1437d982ffdfc1f9d7d83c5ffd6.zip
Add get_interface_address[6]_list for a list of interface IP addresses
Add get_interface_address[6]_list by refactoring get_interface_address6. Add unit tests for new and existing functions. Preparation for ticket 17027. Patch by "teor". Patch on 42b8fb5a1523 (11 Nov 2007), released in 0.2.0.11-alpha.
Diffstat (limited to 'src/common/address.c')
-rw-r--r--src/common/address.c107
1 files changed, 87 insertions, 20 deletions
diff --git a/src/common/address.c b/src/common/address.c
index dd336257ef..0614256521 100644
--- a/src/common/address.c
+++ b/src/common/address.c
@@ -1503,7 +1503,7 @@ get_interface_addresses_raw(int severity)
}
/** Return true iff <b>a</b> is a multicast address. */
-static int
+STATIC int
tor_addr_is_multicast(const tor_addr_t *a)
{
sa_family_t family = tor_addr_family(a);
@@ -1593,27 +1593,26 @@ get_interface_address6_via_udp_socket_hack(int severity,
return r;
}
-/** Set *<b>addr</b> to the IP address (if any) of whatever interface
- * connects to the Internet. This address should only be used in checking
- * whether our address has changed. Return 0 on success, -1 on failure.
+/** Set *<b>addr</b> to an arbitrary IP address (if any) of an interface that
+ * connects to the Internet. Prefer public IP addresses to internal IP
+ * addresses. This address should only be used in checking whether our
+ * address has changed, as it may be an internal IP address. Return 0 on
+ * success, -1 on failure.
+ * Prefer get_interface_address6_list for a list of all addresses on all
+ * interfaces which connect to the Internet.
*/
MOCK_IMPL(int,
get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr))
{
- /* XXX really, this function should yield a smartlist of addresses. */
smartlist_t *addrs;
tor_assert(addr);
- /* Try to do this the smart way if possible. */
- if ((addrs = get_interface_addresses_raw(severity))) {
+ /* Get a list of public or internal IPs in arbitrary order */
+ if ((addrs = get_interface_address6_list(severity, family, 1))) {
int rv = -1;
+ /* Find the first non-internal address, or the last internal address
+ * Ideally, we want the default route, see #12377 for details */
SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) {
- if (family != AF_UNSPEC && family != tor_addr_family(a))
- continue;
- if (tor_addr_is_loopback(a) ||
- tor_addr_is_multicast(a))
- continue;
-
tor_addr_copy(addr, a);
rv = 0;
@@ -1623,13 +1622,78 @@ get_interface_address6,(int severity, sa_family_t family, tor_addr_t *addr))
break;
} SMARTLIST_FOREACH_END(a);
- SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a));
- smartlist_free(addrs);
+ free_interface_address6_list(addrs);
return rv;
}
+ return -1;
+}
+
+/** Free a smartlist of IP addresses returned by get_interface_address6_list.
+ */
+void free_interface_address6_list(smartlist_t *addrs) {
+ SMARTLIST_FOREACH(addrs, tor_addr_t *, a, tor_free(a));
+ smartlist_free(addrs);
+}
+
+/** Return a smartlist of the IP addresses of type family from all interfaces
+ * on the server. Excludes loopback and multicast addresses. Only includes
+ * internal addresses if include_internal is true. (Note that a relay behind
+ * NAT may use an internal address to connect to the Internet.)
+ * An empty smartlist means that there are no addresses of the selected type
+ * matching these criteria.
+ * Returns NULL on failure.
+ * Use free_interface_address6_list to free the returned list.
+ */
+MOCK_IMPL(smartlist_t *,get_interface_address6_list,(int severity,
+ sa_family_t family,
+ int include_internal))
+{
+ smartlist_t *addrs;
+ tor_addr_t addr;
+
+ /* Try to do this the smart way if possible. */
+ if ((addrs = get_interface_addresses_raw(severity))) {
+ SMARTLIST_FOREACH_BEGIN(addrs, tor_addr_t *, a) {
+ if (family != AF_UNSPEC && family != tor_addr_family(a)){
+ SMARTLIST_DEL_CURRENT(addrs, a);
+ tor_free(a);
+ continue;
+ }
+
+ if (tor_addr_is_loopback(a) ||
+ tor_addr_is_multicast(a)) {
+ SMARTLIST_DEL_CURRENT(addrs, a);
+ tor_free(a);
+ continue;
+ }
+
+ if (!include_internal && tor_addr_is_internal(a, 0)){
+ SMARTLIST_DEL_CURRENT(addrs, a);
+ tor_free(a);
+ continue;
+ }
+ } SMARTLIST_FOREACH_END(a);
+ }
+
+ if (addrs && smartlist_len(addrs) > 0) {
+ return addrs;
+ }
+
+ /* if we removed all entries as unsuitable */
+ if (addrs) {
+ smartlist_free(addrs);
+ }
+
/* Okay, the smart way is out. */
- return get_interface_address6_via_udp_socket_hack(severity,family,addr);
+ get_interface_address6_via_udp_socket_hack(severity,family,&addr);
+ if (!include_internal && tor_addr_is_internal(&addr, 0)) {
+ return smartlist_new();
+ } else {
+ addrs = smartlist_new();
+ smartlist_add(addrs, tor_dup_addr(&addr));
+ return addrs;
+ }
}
/* ======
@@ -1871,10 +1935,13 @@ tor_dup_ip(uint32_t addr)
}
/**
- * Set *<b>addr</b> to the host-order IPv4 address (if any) of whatever
- * interface connects to the Internet. This address should only be used in
- * checking whether our address has changed. Return 0 on success, -1 on
- * failure.
+ * Set *<b>addr</b> to a host-order IPv4 address (if any) of an
+ * interface that connects to the Internet. Prefer public IP addresses to
+ * internal IP addresses. This address should only be used in checking
+ * whether our address has changed, as it may be an internal IPv4 address.
+ * Return 0 on success, -1 on failure.
+ * Prefer get_interface_address_list6 for a list of all IPv4 and IPv6
+ * addresses on all interfaces which connect to the Internet.
*/
MOCK_IMPL(int,
get_interface_address,(int severity, uint32_t *addr))