diff options
| author | android-build-team Robot <android-build-team-robot@google.com> | 2019-01-17 17:05:44 +0000 |
|---|---|---|
| committer | android-build-team Robot <android-build-team-robot@google.com> | 2019-01-17 17:05:44 +0000 |
| commit | 5e1af4085a311f34e942439c157deca95343ac5b (patch) | |
| tree | 7c3a93d70f7c39bf05b18589ae7d9951d283e467 | |
| parent | ad86af4ebb1b52a414566ec56090eb23192611f7 (diff) | |
| parent | 56c625999a4434e7b285ea8c43bcdb648872f45d (diff) | |
| download | platform_external_android-clat-5e1af4085a311f34e942439c157deca95343ac5b.tar.gz platform_external_android-clat-5e1af4085a311f34e942439c157deca95343ac5b.tar.bz2 platform_external_android-clat-5e1af4085a311f34e942439c157deca95343ac5b.zip | |
Snap for 5240105 from 56c625999a4434e7b285ea8c43bcdb648872f45d to qt-release
Change-Id: I85f2d0d11bba25ab2a9e032595d44834eda9d3b3
| -rw-r--r-- | .clang-format | 3 | ||||
| -rw-r--r-- | clatd.c | 110 | ||||
| -rw-r--r-- | clatd.h | 8 | ||||
| -rw-r--r-- | clatd_test.cpp | 112 | ||||
| -rw-r--r-- | main.c | 19 |
5 files changed, 207 insertions, 45 deletions
diff --git a/.clang-format b/.clang-format index 6682f77..f1debbd 100644 --- a/.clang-format +++ b/.clang-format @@ -1,6 +1,3 @@ -# https://clang.llvm.org/docs/ClangFormatStyleOptions.html -# Please keep this file in sync with system/core/.clang-format-4 -# BasedOnStyle: Google AlignConsecutiveAssignments: true AlignEscapedNewlines: Right @@ -110,13 +110,11 @@ int configure_packet_socket(int sock) { return 1; } -/* function: configure_tun_ip - * configures the ipv4 and ipv6 addresses on the tunnel interface - * tunnel - tun device data +/* function: ipv4_address_generate + * picks a free IPv4 address from the local subnet or exits if there are no free addresses + * returns: the IPv4 address as an in_addr_t */ -void configure_tun_ip(const struct tun_data *tunnel) { - int status; - +static in_addr_t ipv4_address_generate() { // Pick an IPv4 address to use by finding a free address in the configured prefix. Technically, // there is a race here - if another clatd calls config_select_ipv4_address after we do, but // before we call add_address, it can end up having the same IP address as we do. But the time @@ -131,22 +129,49 @@ void configure_tun_ip(const struct tun_data *tunnel) { Global_Clatd_Config.ipv4_local_prefixlen); exit(1); } - Global_Clatd_Config.ipv4_local_subnet.s_addr = localaddr; + return localaddr; +} - // Configure the interface before bringing it up. As soon as we bring the interface up, the - // framework will be notified and will assume the interface's configuration has been finalized. - status = add_address(tunnel->device4, AF_INET, &Global_Clatd_Config.ipv4_local_subnet, 32, - &Global_Clatd_Config.ipv4_local_subnet); - if (status < 0) { - logmsg(ANDROID_LOG_FATAL, "configure_tun_ip/if_address(4) failed: %s", strerror(-status)); +/* function: ipv4_address_from_cmdline + * configures the IPv4 address specified on the command line, or exits if the address is not valid + * v4_addr - a string, the IPv4 address + * returns: the IPv4 address as an in_addr_t + */ +static in_addr_t ipv4_address_from_cmdline(const char *v4_addr) { + in_addr_t localaddr; + if (!inet_pton(AF_INET, v4_addr, &localaddr)) { + logmsg(ANDROID_LOG_FATAL, "Invalid IPv4 address %s", v4_addr); exit(1); } + return localaddr; +} + +/* function: configure_tun_ip + * configures the ipv4 and ipv6 addresses on the tunnel interface + * tunnel - tun device data + */ +void configure_tun_ip(const struct tun_data *tunnel, const char *v4_addr) { + if (v4_addr) { + Global_Clatd_Config.ipv4_local_subnet.s_addr = ipv4_address_from_cmdline(v4_addr); + } else { + Global_Clatd_Config.ipv4_local_subnet.s_addr = ipv4_address_generate(); + } char addrstr[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &Global_Clatd_Config.ipv4_local_subnet, addrstr, sizeof(addrstr)); logmsg(ANDROID_LOG_INFO, "Using IPv4 address %s on %s", addrstr, tunnel->device4); - if ((status = if_up(tunnel->device4, Global_Clatd_Config.ipv4mtu)) < 0) { + // Configure the interface before bringing it up. As soon as we bring the interface up, the + // framework will be notified and will assume the interface's configuration has been finalized. + int status = add_address(tunnel->device4, AF_INET, &Global_Clatd_Config.ipv4_local_subnet, 32, + &Global_Clatd_Config.ipv4_local_subnet); + if (status < 0) { + logmsg(ANDROID_LOG_FATAL, "configure_tun_ip/if_address(4) failed: %s", strerror(-status)); + exit(1); + } + + status = if_up(tunnel->device4, Global_Clatd_Config.ipv4mtu); + if (status < 0) { logmsg(ANDROID_LOG_FATAL, "configure_tun_ip/if_up(4) failed: %s", strerror(-status)); exit(1); } @@ -251,15 +276,13 @@ int ipv6_address_changed(const char *interface) { } } -/* function: configure_clat_ipv6_address - * picks the clat IPv6 address and configures packet translation to use it. - * tunnel - tun device data +/* function: clat_ipv6_address_from_interface + * picks the clat IPv6 address based on the interface address * interface - uplink interface name * returns: 1 on success, 0 on failure */ -int configure_clat_ipv6_address(const struct tun_data *tunnel, const char *interface) { +static int clat_ipv6_address_from_interface(const char *interface) { union anyip *interface_ip; - char addrstr[INET6_ADDRSTRLEN]; // TODO: check that the prefix length is /64. interface_ip = getinterface_ip(interface, AF_INET6); @@ -270,13 +293,48 @@ int configure_clat_ipv6_address(const struct tun_data *tunnel, const char *inter // Generate an interface ID. config_generate_local_ipv6_subnet(&interface_ip->ip6); - inet_ntop(AF_INET6, &interface_ip->ip6, addrstr, sizeof(addrstr)); + + Global_Clatd_Config.ipv6_local_subnet = interface_ip->ip6; + free(interface_ip); + return 1; +} + +/* function: clat_ipv6_address_from_cmdline + * parses the clat IPv6 address from the command line + * v4_addr - a string, the IPv6 address + * returns: 1 on success, 0 on failure + */ +static int clat_ipv6_address_from_cmdline(const char *v6_addr) { + if (!inet_pton(AF_INET6, v6_addr, &Global_Clatd_Config.ipv6_local_subnet)) { + logmsg(ANDROID_LOG_FATAL, "Invalid source address %s", v6_addr); + return 0; + } + + return 1; +} + +/* 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 configure_clat_ipv6_address(const struct tun_data *tunnel, const char *interface, + const char *v6_addr) { + int ret; + if (v6_addr) { + ret = clat_ipv6_address_from_cmdline(v6_addr); + } else { + ret = clat_ipv6_address_from_interface(interface); + } + if (!ret) return 0; + + char addrstr[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, addrstr, sizeof(addrstr)); 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; add_anycast_address(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet, interface); - free(interface_ip); // Update our packet socket filter to reflect the new 464xlat IP address. if (!configure_packet_socket(tunnel->read_fd6)) { @@ -295,8 +353,8 @@ int configure_clat_ipv6_address(const struct tun_data *tunnel, const char *inter * tunnel - tun device data * net_id - NetID to use, NETID_UNSET indicates use of default network */ -void configure_interface(const char *uplink_interface, const char *plat_prefix, - struct tun_data *tunnel, unsigned net_id) { +void configure_interface(const char *uplink_interface, const char *plat_prefix, const char *v4_addr, + const char *v6_addr, struct tun_data *tunnel, unsigned net_id) { int error; if (!read_config("/system/etc/clatd.conf", uplink_interface, plat_prefix, net_id)) { @@ -335,9 +393,9 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix, exit(1); } - configure_tun_ip(tunnel); + configure_tun_ip(tunnel, v4_addr); - if (!configure_clat_ipv6_address(tunnel, uplink_interface)) { + if (!configure_clat_ipv6_address(tunnel, uplink_interface, v6_addr)) { exit(1); } } @@ -35,13 +35,15 @@ struct tun_data; #define NO_TRAFFIC_INTERFACE_POLL_FREQUENCY 90 void stop_loop(); +void configure_tun_ip(const struct tun_data *tunnel, const char *v4_addr); void set_capability(uint64_t target_cap); void drop_root_but_keep_caps(); void open_sockets(struct tun_data *tunnel, uint32_t mark); int ipv6_address_changed(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); +int configure_clat_ipv6_address(const struct tun_data *tunnel, const char *interface, + const char *src_addr); +void configure_interface(const char *uplink_interface, const char *plat_prefix, const char *v4_addr, + const char *v6, struct tun_data *tunnel, unsigned net_id); void event_loop(struct tun_data *tunnel); int parse_unsigned(const char *str, unsigned *out); diff --git a/clatd_test.cpp b/clatd_test.cpp index 81af41d..7705a36 100644 --- a/clatd_test.cpp +++ b/clatd_test.cpp @@ -294,8 +294,8 @@ void check_packet(const uint8_t *packet, size_t len, const char *msg) { void reassemble_packet(const uint8_t **fragments, const size_t lengths[], int numpackets, uint8_t *reassembled, size_t *reassembled_len, const char *msg) { - struct iphdr *ip = NULL; - struct ip6_hdr *ip6 = NULL; + struct iphdr *ip = nullptr; + struct ip6_hdr *ip6 = nullptr; size_t total_length, pos = 0; uint8_t protocol = 0; uint8_t version = ip_version(fragments[0]); @@ -560,6 +560,21 @@ int get_transport_checksum(const uint8_t *packet) { } } +static tun_data makeTunData() { + // Create some fake but realistic-looking sockets so update_clat_ipv6_address doesn't balk. + return { + .write_fd6 = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW), + .read_fd6 = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)), + .fd4 = socket(AF_UNIX, SOCK_DGRAM, 0), + }; +} + +void freeTunData(tun_data *tunnel) { + close(tunnel->write_fd6); + close(tunnel->read_fd6); + close(tunnel->fd4); +} + struct clat_config Global_Clatd_Config; class ClatdTest : public ::testing::Test { @@ -757,6 +772,55 @@ TEST_F(ClatdTest, SelectIPv4Address) { EXPECT_EQ(inet_addr("127.0.0.2"), config_select_ipv4_address(&addr, 29)); } +TEST_F(ClatdTest, ConfigureTunIp) { + addr_free_func orig_config_is_ipv4_address_free = config_is_ipv4_address_free; + config_is_ipv4_address_free = over6_free; + + Global_Clatd_Config.ipv4_local_prefixlen = 29; + Global_Clatd_Config.ipv4mtu = 1472; + + // Create an interface for configure_tun_ip to configure and bring up. + TunInterface v4Iface; + ASSERT_EQ(0, v4Iface.init()); + struct tun_data tunnel = makeTunData(); + strlcpy(tunnel.device4, v4Iface.name().c_str(), sizeof(tunnel.device4)); + + configure_tun_ip(&tunnel, nullptr /* v4_addr */); + EXPECT_EQ(inet_addr("192.0.0.6"), Global_Clatd_Config.ipv4_local_subnet.s_addr); + + union anyip *ip = getinterface_ip(v4Iface.name().c_str(), AF_INET); + EXPECT_EQ(inet_addr("192.0.0.6"), ip->ip4.s_addr); + free(ip); + + config_is_ipv4_address_free = orig_config_is_ipv4_address_free; + v4Iface.destroy(); +} + +TEST_F(ClatdTest, ConfigureTunIpManual) { + addr_free_func orig_config_is_ipv4_address_free = config_is_ipv4_address_free; + config_is_ipv4_address_free = over6_free; + + Global_Clatd_Config.ipv4_local_prefixlen = 29; + Global_Clatd_Config.ipv4mtu = 1472; + + // Create an interface for configure_tun_ip to configure and bring up. + TunInterface v4Iface; + ASSERT_EQ(0, v4Iface.init()); + struct tun_data tunnel = makeTunData(); + strlcpy(tunnel.device4, v4Iface.name().c_str(), sizeof(tunnel.device4)); + + configure_tun_ip(&tunnel, "192.0.2.1" /* v4_addr */); + EXPECT_EQ(inet_addr("192.0.2.1"), Global_Clatd_Config.ipv4_local_subnet.s_addr); + + union anyip *ip = getinterface_ip(v4Iface.name().c_str(), AF_INET); + ASSERT_NE(nullptr, ip); + EXPECT_EQ(inet_addr("192.0.2.1"), ip->ip4.s_addr); + free(ip); + + config_is_ipv4_address_free = orig_config_is_ipv4_address_free; + v4Iface.destroy(); +} + TEST_F(ClatdTest, DataSanitycheck) { // Sanity checks the data. uint8_t v4_header[] = { IPV4_UDP_HEADER }; @@ -965,16 +1029,22 @@ TEST_F(ClatdTest, GetInterfaceIp) { expect_ipv6_addr_equal(&expected, &actual); } +void expectSocketBound(int ifindex, int sock) { + // Check that the packet socket is bound to the interface. We can't check the socket filter + // because there is no way to fetch it from the kernel. + sockaddr_ll sll; + socklen_t len = sizeof(sll); + ASSERT_EQ(0, getsockname(sock, reinterpret_cast<sockaddr *>(&sll), &len)); + EXPECT_EQ(htons(ETH_P_IPV6), sll.sll_protocol); + EXPECT_EQ(ifindex, sll.sll_ifindex); +} + 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)), - }; + struct tun_data tunnel = makeTunData(); // Run configure_clat_ipv6_address. ASSERT_TRUE(IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_local_subnet)); - ASSERT_EQ(1, configure_clat_ipv6_address(&tunnel, sTun.name().c_str())); + ASSERT_EQ(1, configure_clat_ipv6_address(&tunnel, sTun.name().c_str(), nullptr /* v6_addr */)); // 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. @@ -984,6 +1054,26 @@ TEST_F(ClatdTest, ConfigureIpv6Address) { EXPECT_NE(htonl((uint32_t)0x00000464), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); EXPECT_NE((uint32_t)0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); + expectSocketBound(sTun.ifindex(), tunnel.read_fd6); + + freeTunData(&tunnel); +} + +TEST_F(ClatdTest, ConfigureIpv6AddressCommandLine) { + struct tun_data tunnel = makeTunData(); + + ASSERT_TRUE(IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_local_subnet)); + + const char *addrStr = "2001:db8::f00"; + in6_addr addr; + ASSERT_EQ(1, inet_pton(AF_INET6, addrStr, &addr)); + ASSERT_EQ(1, configure_clat_ipv6_address(&tunnel, sTun.name().c_str(), addrStr)); + + EXPECT_EQ(htonl(0x20010db8), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[0]); + EXPECT_EQ(htonl(0x00000000), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[1]); + EXPECT_EQ(htonl(0x00000000), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[2]); + EXPECT_EQ(htonl(0x00000f00), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); + // Check that the packet socket is bound to the interface. We can't check the socket filter // because there is no way to fetch it from the kernel. sockaddr_ll sll; @@ -991,6 +1081,10 @@ TEST_F(ClatdTest, ConfigureIpv6Address) { ASSERT_EQ(0, getsockname(tunnel.read_fd6, reinterpret_cast<sockaddr *>(&sll), &len)); EXPECT_EQ(htons(ETH_P_IPV6), sll.sll_protocol); EXPECT_EQ(sll.sll_ifindex, sTun.ifindex()); + + expectSocketBound(sTun.ifindex(), tunnel.read_fd6); + + freeTunData(&tunnel); } TEST_F(ClatdTest, Ipv6AddressChanged) { @@ -1000,7 +1094,7 @@ TEST_F(ClatdTest, Ipv6AddressChanged) { .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)); + ASSERT_EQ(1, configure_clat_ipv6_address(&tunnel, ifname, nullptr)); EXPECT_EQ(0, ipv6_address_changed(ifname)); EXPECT_EQ(0, ipv6_address_changed(ifname)); @@ -42,6 +42,8 @@ void print_help() { printf("android-clat arguments:\n"); printf("-i [uplink interface]\n"); printf("-p [plat prefix]\n"); + printf("-4 [IPv4 address]\n"); + printf("-6 [IPv6 address]\n"); printf("-n [NetId]\n"); printf("-m [socket mark]\n"); } @@ -53,11 +55,12 @@ int main(int argc, char **argv) { struct tun_data tunnel; int opt; char *uplink_interface = NULL, *plat_prefix = NULL, *net_id_str = NULL, *mark_str = NULL; + char *v4_addr = NULL, *v6_addr = NULL; unsigned net_id = NETID_UNSET; uint32_t mark = MARK_UNSET; unsigned len; - while ((opt = getopt(argc, argv, "i:p:n:m:h")) != -1) { + while ((opt = getopt(argc, argv, "i:p:4:6:n:m:h")) != -1) { switch (opt) { case 'i': uplink_interface = optarg; @@ -65,6 +68,12 @@ int main(int argc, char **argv) { case 'p': plat_prefix = optarg; break; + case '4': + v4_addr = optarg; + break; + case '6': + v6_addr = optarg; + break; case 'n': net_id_str = optarg; break; @@ -101,8 +110,10 @@ int main(int argc, char **argv) { exit(1); } - logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s netid=%s mark=%s", CLATD_VERSION, - uplink_interface, net_id_str ? net_id_str : "(none)", mark_str ? mark_str : "(none)"); + logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s netid=%s mark=%s plat=%s v4=%s v6=%s", + CLATD_VERSION, uplink_interface, net_id_str ? net_id_str : "(none)", + mark_str ? mark_str : "(none)", plat_prefix ? plat_prefix : "(none)", + v4_addr ? v4_addr : "(none)", v6_addr ? v6_addr : "(none)"); // run under a regular user but keep needed capabilities drop_root_but_keep_caps(); @@ -125,7 +136,7 @@ int main(int argc, char **argv) { // following line causes XLAT failure in permissive mode. unsetenv("ANDROID_DNS_MODE"); - configure_interface(uplink_interface, plat_prefix, &tunnel, net_id); + configure_interface(uplink_interface, plat_prefix, v4_addr, v6_addr, &tunnel, net_id); // Drop all remaining capabilities. set_capability(0); |
