Drop support for updating IPv6 addresses in clatd.
am: 66deecd38f

Change-Id: I2c1c37d733a0147f6f5e764ba603e1bddc754f4c
diff --git a/clatd.c b/clatd.c
index 2ef10a5..bcbd9c5 100644
--- a/clatd.c
+++ b/clatd.c
@@ -228,13 +228,36 @@
   }
 }
 
-/* function: update_clat_ipv6_address
+int ipv6_address_changed(const char *interface) {
+  union anyip *interface_ip;
+
+  interface_ip = getinterface_ip(interface, AF_INET6);
+  if (!interface_ip) {
+    logmsg(ANDROID_LOG_ERROR, "Unable to find an IPv6 address on interface %s", interface);
+    return 1;
+  }
+
+  if (!ipv6_prefix_equal(&interface_ip->ip6, &Global_Clatd_Config.ipv6_local_subnet)) {
+    char oldstr[INET6_ADDRSTRLEN];
+    char newstr[INET6_ADDRSTRLEN];
+    inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, oldstr, sizeof(oldstr));
+    inet_ntop(AF_INET6, &interface_ip->ip6, newstr, sizeof(newstr));
+    logmsg(ANDROID_LOG_INFO, "IPv6 prefix on %s changed: %s -> %s", interface, oldstr, newstr);
+    free(interface_ip);
+    return 1;
+  } else {
+    free(interface_ip);
+    return 0;
+  }
+}
+
+/* function: configure_clat_ipv6_address
  * picks the clat IPv6 address and configures packet translation to use it.
  *   tunnel - tun device data
  *   interface - uplink interface name
  *   returns: 1 on success, 0 on failure
  */
-int update_clat_ipv6_address(const struct tun_data *tunnel, const char *interface) {
+int configure_clat_ipv6_address(const struct tun_data *tunnel, const char *interface) {
   union anyip *interface_ip;
   char addrstr[INET6_ADDRSTRLEN];
 
@@ -245,27 +268,10 @@
     return 0;
   }
 
-  // If our prefix hasn't changed, do nothing. (If this is the first time we configure an IPv6
-  // address, Global_Clatd_Config.ipv6_local_subnet will be ::, which won't match our new prefix.)
-  if (ipv6_prefix_equal(&interface_ip->ip6, &Global_Clatd_Config.ipv6_local_subnet)) {
-    free(interface_ip);
-    return 1;
-  }
-
   // Generate an interface ID.
   config_generate_local_ipv6_subnet(&interface_ip->ip6);
   inet_ntop(AF_INET6, &interface_ip->ip6, addrstr, sizeof(addrstr));
-
-  if (IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_local_subnet)) {
-    // Startup.
-    logmsg(ANDROID_LOG_INFO, "Using IPv6 address %s on %s", addrstr, interface);
-  } else {
-    // Prefix change.
-    char from_addr[INET6_ADDRSTRLEN];
-    inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, from_addr, sizeof(from_addr));
-    logmsg(ANDROID_LOG_INFO, "clat IPv6 address changed from %s to %s", from_addr, addrstr);
-    del_anycast_address(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet);
-  }
+  logmsg(ANDROID_LOG_INFO, "Using IPv6 address %s on %s", addrstr, interface);
 
   // Start translating packets to the new prefix.
   Global_Clatd_Config.ipv6_local_subnet = interface_ip->ip6;
@@ -276,7 +282,7 @@
   if (!configure_packet_socket(tunnel->read_fd6)) {
     // Things aren't going to work. Bail out and hope we have better luck next time.
     // We don't log an error here because configure_packet_socket has already done so.
-    exit(1);
+    return 0;
   }
 
   return 1;
@@ -330,6 +336,10 @@
   }
 
   configure_tun_ip(tunnel);
+
+  if (!configure_clat_ipv6_address(tunnel, uplink_interface)) {
+    exit(1);
+  }
 }
 
 /* function: read_packet
@@ -418,8 +428,9 @@
 
     time_t now = time(NULL);
     if (last_interface_poll < (now - INTERFACE_POLL_FREQUENCY)) {
-      update_clat_ipv6_address(tunnel, Global_Clatd_Config.default_pdp_interface);
-      last_interface_poll = now;
+      if (ipv6_address_changed(Global_Clatd_Config.default_pdp_interface)) {
+        break;
+      }
     }
   }
 }
diff --git a/clatd.h b/clatd.h
index 32f8cd5..67ba990 100644
--- a/clatd.h
+++ b/clatd.h
@@ -39,7 +39,7 @@
 void drop_root_but_keep_caps();
 void open_sockets(struct tun_data *tunnel, uint32_t mark);
 int ipv6_address_changed(const char *interface);
-int update_clat_ipv6_address(const struct tun_data *tunnel, const char *interface);
+int configure_clat_ipv6_address(const struct tun_data *tunnel, const char *interface);
 void configure_interface(const char *uplink_interface, const char *plat_prefix,
                          struct tun_data *tunnel, unsigned net_id);
 void event_loop(struct tun_data *tunnel);
diff --git a/clatd_test.cpp b/clatd_test.cpp
index 4f998ea..81af41d 100644
--- a/clatd_test.cpp
+++ b/clatd_test.cpp
@@ -24,6 +24,8 @@
 #include <sys/uio.h>
 
 #include <gtest/gtest.h>
+
+#include "netutils/ifc.h"
 #include "tun_interface.h"
 
 extern "C" {
@@ -963,16 +965,16 @@
   expect_ipv6_addr_equal(&expected, &actual);
 }
 
-TEST_F(ClatdTest, UpdateIpv6Address) {
+TEST_F(ClatdTest, ConfigureIpv6Address) {
   // Create some fake but realistic-looking sockets so update_clat_ipv6_address doesn't balk.
   struct tun_data tunnel = {
     .write_fd6 = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW),
     .read_fd6  = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)),
   };
 
-  // Run update_clat_ipv6_address with no local IID yet picked.
+  // Run configure_clat_ipv6_address.
   ASSERT_TRUE(IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_local_subnet));
-  ASSERT_EQ(1, update_clat_ipv6_address(&tunnel, sTun.name().c_str()));
+  ASSERT_EQ(1, configure_clat_ipv6_address(&tunnel, sTun.name().c_str()));
 
   // Check that it generated an IID in the same prefix as the address assigned to the interface,
   // and that the IID is not the default IID.
@@ -990,3 +992,32 @@
   EXPECT_EQ(htons(ETH_P_IPV6), sll.sll_protocol);
   EXPECT_EQ(sll.sll_ifindex, sTun.ifindex());
 }
+
+TEST_F(ClatdTest, Ipv6AddressChanged) {
+  // Configure the clat IPv6 address.
+  struct tun_data tunnel = {
+    .write_fd6 = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW),
+    .read_fd6  = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)),
+  };
+  const char *ifname = sTun.name().c_str();
+  ASSERT_EQ(1, configure_clat_ipv6_address(&tunnel, ifname));
+  EXPECT_EQ(0, ipv6_address_changed(ifname));
+  EXPECT_EQ(0, ipv6_address_changed(ifname));
+
+  // Change the IP address on the tun interface to a new prefix.
+  char srcaddr[INET6_ADDRSTRLEN];
+  char dstaddr[INET6_ADDRSTRLEN];
+  ASSERT_NE(nullptr, inet_ntop(AF_INET6, &sTun.srcAddr(), srcaddr, sizeof(srcaddr)));
+  ASSERT_NE(nullptr, inet_ntop(AF_INET6, &sTun.dstAddr(), dstaddr, sizeof(dstaddr)));
+  EXPECT_EQ(0, ifc_del_address(ifname, srcaddr, 64));
+  EXPECT_EQ(0, ifc_del_address(ifname, dstaddr, 64));
+
+  // Check that we can tell that the address has changed.
+  EXPECT_EQ(0, ifc_add_address(ifname, "2001:db8::1:2", 64));
+  EXPECT_EQ(1, ipv6_address_changed(ifname));
+  EXPECT_EQ(1, ipv6_address_changed(ifname));
+
+  // Restore the tun interface configuration.
+  sTun.destroy();
+  ASSERT_EQ(0, sTun.init());
+}
diff --git a/main.c b/main.c
index e717498..11c51a5 100644
--- a/main.c
+++ b/main.c
@@ -127,7 +127,8 @@
 
   configure_interface(uplink_interface, plat_prefix, &tunnel, net_id);
 
-  update_clat_ipv6_address(&tunnel, uplink_interface);
+  // Drop all remaining capabilities.
+  set_capability(0);
 
   // Loop until someone sends us a signal or brings down the tun interface.
   if (signal(SIGTERM, stop_loop) == SIG_ERR) {