[tor-commits] [tor/master] We allow IPv6 connections, don't use sockaddr_in with getsockname

nickm at torproject.org nickm at torproject.org
Tue Apr 24 15:08:39 UTC 2012


commit a74905cea45acf6d7278326360b179eda3d013ec
Author: Nick Mathewson <nickm at torproject.org>
Date:   Fri Mar 30 16:43:52 2012 -0400

    We allow IPv6 connections, don't use sockaddr_in with getsockname
    
    This fixes client_check_address_changed to work better with IPv6 Tor
    clients, and prevents them from spewing errors. Fix for ticket 5537.
---
 changes/bug5537     |    5 ++++
 src/or/connection.c |   65 +++++++++++++++++++++++++++++++++------------------
 2 files changed, 47 insertions(+), 23 deletions(-)

diff --git a/changes/bug5537 b/changes/bug5537
new file mode 100644
index 0000000..bcad2a2
--- /dev/null
+++ b/changes/bug5537
@@ -0,0 +1,5 @@
+  o Minor features:
+    - Make the code that clients use to detect an address change be
+      IPv6-aware, so that it won't fill clients' logs with error
+      messages when trying to get the IPv4 address of an IPv6
+      connection. Implements ticket 5537.
diff --git a/src/or/connection.c b/src/or/connection.c
index c9093fe..d6b9adc 100644
--- a/src/or/connection.c
+++ b/src/or/connection.c
@@ -74,10 +74,14 @@ static void connection_send_socks5_connect(connection_t *conn);
 static const char *proxy_type_to_string(int proxy_type);
 static int get_proxy_type(void);
 
-/** The last IPv4 address that our network interface seemed to have been
- * binding to, in host order.  We use this to detect when our IP changes. */
-static uint32_t last_interface_ip = 0;
-/** A list of uint32_ts for addresses we've used in outgoing connections.
+/** The last addresses that our network interface seemed to have been
+ * binding to.  We use this as one way to detect when our IP changes.
+ *
+ * XXX024 We should really use the entire list of interfaces here.
+ **/
+static tor_addr_t *last_interface_ipv4 = NULL;
+static tor_addr_t *last_interface_ipv6 = NULL;
+/** A list of tor_addr_t for addresses we've used in outgoing connections.
  * Used to detect IP address changes. */
 static smartlist_t *outgoing_addrs = NULL;
 
@@ -3691,47 +3695,62 @@ alloc_http_authenticator(const char *authenticator)
 static void
 client_check_address_changed(tor_socket_t sock)
 {
-  uint32_t iface_ip, ip_out; /* host order */
-  struct sockaddr_in out_addr;
-  socklen_t out_addr_len = (socklen_t) sizeof(out_addr);
-  uint32_t *ip; /* host order */
+  struct sockaddr_storage out_sockaddr;
+  socklen_t out_addr_len = (socklen_t) sizeof(out_sockaddr);
+  tor_addr_t out_addr, iface_addr;
+  tor_addr_t **last_interface_ip_ptr;
+  sa_family_t family;
 
-  if (!last_interface_ip)
-    get_interface_address(LOG_INFO, &last_interface_ip);
   if (!outgoing_addrs)
     outgoing_addrs = smartlist_new();
 
-  if (getsockname(sock, (struct sockaddr*)&out_addr, &out_addr_len)<0) {
+  if (getsockname(sock, (struct sockaddr*)&out_sockaddr, &out_addr_len)<0) {
     int e = tor_socket_errno(sock);
     log_warn(LD_NET, "getsockname() to check for address change failed: %s",
              tor_socket_strerror(e));
     return;
   }
+  tor_addr_from_sockaddr(&out_addr, (struct sockaddr*)&out_sockaddr, NULL);
+  family = tor_addr_family(&out_addr);
+
+  if (family == AF_INET)
+    last_interface_ip_ptr = &last_interface_ipv4;
+  else if (family == AF_INET6)
+    last_interface_ip_ptr = &last_interface_ipv6;
+  else
+    return;
+
+  if (! *last_interface_ip_ptr) {
+    tor_addr_t *a = tor_malloc_zero(sizeof(tor_addr_t));
+    if (get_interface_address6(LOG_INFO, family, a)==0) {
+      *last_interface_ip_ptr = a;
+    } else {
+      tor_free(a);
+    }
+  }
 
   /* If we've used this address previously, we're okay. */
-  ip_out = ntohl(out_addr.sin_addr.s_addr);
-  SMARTLIST_FOREACH(outgoing_addrs, uint32_t*, ip_ptr,
-                    if (*ip_ptr == ip_out) return;
+  SMARTLIST_FOREACH(outgoing_addrs, const tor_addr_t *, a_ptr,
+                    if (tor_addr_eq(a_ptr, &out_addr))
+                      return;
                     );
 
   /* Uh-oh.  We haven't connected from this address before. Has the interface
    * address changed? */
-  if (get_interface_address(LOG_INFO, &iface_ip)<0)
+  if (get_interface_address6(LOG_INFO, family, &iface_addr)<0)
     return;
-  ip = tor_malloc(sizeof(uint32_t));
-  *ip = ip_out;
 
-  if (iface_ip == last_interface_ip) {
+  if (tor_addr_eq(&iface_addr, *last_interface_ip_ptr)) {
     /* Nope, it hasn't changed.  Add this address to the list. */
-    smartlist_add(outgoing_addrs, ip);
+    smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t)));
   } else {
     /* The interface changed.  We're a client, so we need to regenerate our
      * keys.  First, reset the state. */
     log(LOG_NOTICE, LD_NET, "Our IP address has changed.  Rotating keys...");
-    last_interface_ip = iface_ip;
-    SMARTLIST_FOREACH(outgoing_addrs, void*, ip_ptr, tor_free(ip_ptr));
+    tor_addr_copy(*last_interface_ip_ptr, &iface_addr);
+    SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t*, a_ptr, tor_free(a_ptr));
     smartlist_clear(outgoing_addrs);
-    smartlist_add(outgoing_addrs, ip);
+    smartlist_add(outgoing_addrs, tor_memdup(&out_addr, sizeof(tor_addr_t)));
     /* Okay, now change our keys. */
     ip_address_changed(1);
   }
@@ -4231,7 +4250,7 @@ connection_free_all(void)
   SMARTLIST_FOREACH(conns, connection_t *, conn, _connection_free(conn));
 
   if (outgoing_addrs) {
-    SMARTLIST_FOREACH(outgoing_addrs, void*, addr, tor_free(addr));
+    SMARTLIST_FOREACH(outgoing_addrs, tor_addr_t *, addr, tor_free(addr));
     smartlist_free(outgoing_addrs);
     outgoing_addrs = NULL;
   }





More information about the tor-commits mailing list