diff options
| author | Maciej enczykowski <maze@google.com> | 2020-01-21 19:12:38 -0800 |
|---|---|---|
| committer | android-build-merger <android-build-merger@google.com> | 2020-01-21 19:12:38 -0800 |
| commit | e0417af9dfb3e96cad6a2eeec6df349b2425fd28 (patch) | |
| tree | 288263ef03ad0e74f3e59eca1bbde7f1b133504b | |
| parent | 4b4a836778a1a76523fd84a269e4c2e20616e32f (diff) | |
| parent | b00113f49a8128a47ae5d908c024cf122b725585 (diff) | |
| download | platform_external_android-clat-e0417af9dfb3e96cad6a2eeec6df349b2425fd28.tar.gz platform_external_android-clat-e0417af9dfb3e96cad6a2eeec6df349b2425fd28.tar.bz2 platform_external_android-clat-e0417af9dfb3e96cad6a2eeec6df349b2425fd28.zip | |
Derive mtu from ipv6 route to ipv4 /96 prefix instead of device
am: b00113f49a
Change-Id: Ib8d9b9a6a23f78cda1024e3a35408c73eea20af5
| -rw-r--r-- | Android.bp | 1 | ||||
| -rw-r--r-- | clatd.c | 81 | ||||
| -rw-r--r-- | clatd.h | 5 | ||||
| -rw-r--r-- | clatd_test.cpp | 11 | ||||
| -rw-r--r-- | config.c | 6 | ||||
| -rw-r--r-- | config.h | 1 | ||||
| -rw-r--r-- | main.c | 2 | ||||
| -rw-r--r-- | mtu.c | 49 | ||||
| -rw-r--r-- | mtu.h | 24 |
9 files changed, 68 insertions, 112 deletions
@@ -30,7 +30,6 @@ filegroup { "ipv4.c", "ipv6.c", "logging.c", - "mtu.c", "netlink_callbacks.c", "netlink_msg.c", "ring.c", @@ -46,7 +46,6 @@ #include "dump.h" #include "getaddr.h" #include "logging.h" -#include "mtu.h" #include "resolv_netid.h" #include "ring.h" #include "setif.h" @@ -149,8 +148,9 @@ static in_addr_t ipv4_address_from_cmdline(const char *v4_addr) { /* function: configure_tun_ip * configures the ipv4 and ipv6 addresses on the tunnel interface * tunnel - tun device data + * mtu - mtu of tun device */ -void configure_tun_ip(const struct tun_data *tunnel, const char *v4_addr) { +void configure_tun_ip(const struct tun_data *tunnel, const char *v4_addr, int mtu) { if (v4_addr) { Global_Clatd_Config.ipv4_local_subnet.s_addr = ipv4_address_from_cmdline(v4_addr); } else { @@ -170,7 +170,7 @@ void configure_tun_ip(const struct tun_data *tunnel, const char *v4_addr) { exit(1); } - status = if_up(tunnel->device4, Global_Clatd_Config.ipv4mtu); + status = if_up(tunnel->device4, mtu); if (status < 0) { logmsg(ANDROID_LOG_FATAL, "configure_tun_ip/if_up(4) failed: %s", strerror(-status)); exit(1); @@ -346,41 +346,74 @@ int configure_clat_ipv6_address(const struct tun_data *tunnel, const char *inter return 1; } +int detect_mtu(const struct in6_addr *plat_subnet, uint32_t plat_suffix, uint32_t mark) { + // Create an IPv6 UDP socket. + int s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0); + if (s < 0) { + logmsg(ANDROID_LOG_FATAL, "socket(AF_INET6, SOCK_DGRAM, 0) failed"); + exit(1); + } + + // Socket's mark affects routing decisions (network selection) + if ((mark != MARK_UNSET) && setsockopt(s, SOL_SOCKET, SO_MARK, &mark, sizeof(mark))) { + logmsg(ANDROID_LOG_FATAL, "setsockopt(SOL_SOCKET, SO_MARK) failed: %s", strerror(errno)); + exit(1); + } + + // Try to connect udp socket to plat_subnet(96 bits):plat_suffix(32 bits) + struct sockaddr_in6 dst = { + .sin6_family = AF_INET6, + .sin6_addr = *plat_subnet, + }; + dst.sin6_addr.s6_addr32[3] = plat_suffix; + if (connect(s, (struct sockaddr *)&dst, sizeof(dst))) { + logmsg(ANDROID_LOG_FATAL, "connect() failed: %s", strerror(errno)); + exit(1); + } + + // Fetch the socket's IPv6 mtu - this is effectively fetching mtu from routing table + int mtu; + socklen_t sz_mtu = sizeof(mtu); + if (getsockopt(s, SOL_IPV6, IPV6_MTU, &mtu, &sz_mtu)) { + logmsg(ANDROID_LOG_FATAL, "getsockopt(SOL_IPV6, IPV6_MTU) failed: %s", strerror(errno)); + exit(1); + } + if (sz_mtu != sizeof(mtu)) { + logmsg(ANDROID_LOG_FATAL, "getsockopt(SOL_IPV6, IPV6_MTU) returned unexpected size: %d", + sz_mtu); + exit(1); + } + close(s); + + return mtu; +} + /* function: configure_interface * reads the configuration and applies it to the interface * uplink_interface - network interface to use to reach the ipv6 internet * plat_prefix - PLAT prefix to use * tunnel - tun device data * net_id - NetID to use, NETID_UNSET indicates use of default network + * mark - the socket mark to use for the sending raw socket */ 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) { - + const char *v6_addr, struct tun_data *tunnel, unsigned net_id, + uint32_t mark) { if (!read_config("/system/etc/clatd.conf", uplink_interface, plat_prefix, net_id)) { logmsg(ANDROID_LOG_FATAL, "read_config failed"); exit(1); } - if (Global_Clatd_Config.mtu > MAXMTU) { - logmsg(ANDROID_LOG_WARN, "Max MTU is %d, requested %d", MAXMTU, Global_Clatd_Config.mtu); - Global_Clatd_Config.mtu = MAXMTU; - } - if (Global_Clatd_Config.mtu <= 0) { - Global_Clatd_Config.mtu = getifmtu(Global_Clatd_Config.default_pdp_interface); - logmsg(ANDROID_LOG_WARN, "ifmtu=%d", Global_Clatd_Config.mtu); - } - if (Global_Clatd_Config.mtu < 1280) { - logmsg(ANDROID_LOG_WARN, "mtu too small = %d", Global_Clatd_Config.mtu); - Global_Clatd_Config.mtu = 1280; - } - - if (Global_Clatd_Config.ipv4mtu <= 0 || - Global_Clatd_Config.ipv4mtu > Global_Clatd_Config.mtu - MTU_DELTA) { - Global_Clatd_Config.ipv4mtu = Global_Clatd_Config.mtu - MTU_DELTA; - logmsg(ANDROID_LOG_WARN, "ipv4mtu now set to = %d", Global_Clatd_Config.ipv4mtu); - } + int mtu = detect_mtu(&Global_Clatd_Config.plat_subnet, htonl(0x08080808), mark); + // clamp to minimum ipv6 mtu - this probably cannot ever trigger + if (mtu < 1280) mtu = 1280; + // clamp to buffer size + if (mtu > MAXMTU) mtu = MAXMTU; + // decrease by ipv6(40) + ipv6 fragmentation header(8) vs ipv4(20) overhead of 28 bytes + mtu -= MTU_DELTA; + logmsg(ANDROID_LOG_WARN, "ipv4 mtu is %d", mtu); - configure_tun_ip(tunnel, v4_addr); + configure_tun_ip(tunnel, v4_addr, mtu); if (!configure_clat_ipv6_address(tunnel, uplink_interface, v6_addr)) { exit(1); @@ -36,15 +36,16 @@ 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 configure_tun_ip(const struct tun_data *tunnel, const char *v4_addr, int mtu); 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, const char *src_addr); +int detect_mtu(const struct in6_addr *plat_subnet, uint32_t plat_suffix, uint32_t mark); 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); + const char *v6, struct tun_data *tunnel, unsigned net_id, uint32_t mark); void event_loop(struct tun_data *tunnel); /* function: parse_int diff --git a/clatd_test.cpp b/clatd_test.cpp index f01f49d..08b444c 100644 --- a/clatd_test.cpp +++ b/clatd_test.cpp @@ -772,12 +772,16 @@ TEST_F(ClatdTest, SelectIPv4Address) { EXPECT_EQ(inet_addr("127.0.0.2"), config_select_ipv4_address(&addr, 29)); } +TEST_F(ClatdTest, DetectMtu) { + // ::1 with bottom 32 bits set to 1 is still ::1 which routes via lo with mtu of 64KiB + ASSERT_EQ(detect_mtu(&in6addr_loopback, htonl(1), 0 /*MARK_UNSET*/), 65536); +} + 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; @@ -785,7 +789,7 @@ TEST_F(ClatdTest, ConfigureTunIp) { struct tun_data tunnel = makeTunData(); strlcpy(tunnel.device4, v4Iface.name().c_str(), sizeof(tunnel.device4)); - configure_tun_ip(&tunnel, nullptr /* v4_addr */); + configure_tun_ip(&tunnel, nullptr /* v4_addr */, 1472); 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); @@ -801,7 +805,6 @@ TEST_F(ClatdTest, ConfigureTunIpManual) { 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; @@ -809,7 +812,7 @@ TEST_F(ClatdTest, ConfigureTunIpManual) { 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 */); + configure_tun_ip(&tunnel, "192.0.2.1" /* v4_addr */, 1472); 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); @@ -318,10 +318,6 @@ int read_config(const char *file, const char *uplink_interface, const char *plat Global_Clatd_Config.default_pdp_interface = strdup(uplink_interface); if (!Global_Clatd_Config.default_pdp_interface) goto failed; - Global_Clatd_Config.mtu = -1; - - Global_Clatd_Config.ipv4mtu = -1; - if (!config_item_ip(root, "ipv4_local_subnet", DEFAULT_IPV4_LOCAL_SUBNET, &Global_Clatd_Config.ipv4_local_subnet)) goto failed; @@ -377,8 +373,6 @@ failed: void dump_config() { char charbuffer[INET6_ADDRSTRLEN]; - logmsg(ANDROID_LOG_DEBUG, "mtu = %d", Global_Clatd_Config.mtu); - logmsg(ANDROID_LOG_DEBUG, "ipv4mtu = %d", Global_Clatd_Config.ipv4mtu); logmsg( ANDROID_LOG_DEBUG, "ipv6_local_subnet = %s", inet_ntop(AF_INET6, &Global_Clatd_Config.ipv6_local_subnet, charbuffer, sizeof(charbuffer))); @@ -26,7 +26,6 @@ #define DNS64_DETECTION_HOSTNAME "ipv4only.arpa" struct clat_config { - int16_t mtu, ipv4mtu; struct in6_addr ipv6_local_subnet; struct in6_addr ipv6_host_id; struct in_addr ipv4_local_subnet; @@ -142,7 +142,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, v4_addr, v6_addr, &tunnel, net_id); + configure_interface(uplink_interface, plat_prefix, v4_addr, v6_addr, &tunnel, net_id, mark); // Drop all remaining capabilities. set_capability(0); @@ -1,49 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * mtu.c - get interface mtu - */ - -#include <net/if.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include "mtu.h" - -/* function: getifmtu - * returns the interface mtu or -1 on failure - * ifname - interface name - */ -int getifmtu(const char *ifname) { - int fd; - struct ifreq if_mtu; - - fd = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (fd < 0) { - return -1; - } - strncpy(if_mtu.ifr_name, ifname, IFNAMSIZ); - if_mtu.ifr_name[IFNAMSIZ - 1] = '\0'; - if (ioctl(fd, SIOCGIFMTU, &if_mtu) < 0) { - close(fd); - return -1; - } - close(fd); - return if_mtu.ifr_mtu; -} @@ -1,24 +0,0 @@ -/* - * Copyright 2011 Daniel Drown - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * mtu.c - get interface mtu - */ - -#ifndef __MTU_H__ -#define __MTU_H__ - -int getifmtu(const char *ifname); - -#endif |
