summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-01-19 08:06:20 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-01-19 08:06:20 +0000
commit231b290b6a9bc7a8aa14aa1d3c5cb33ac8e25242 (patch)
treeade7edd26505767dbc5ea08fcf5156077ef1e890
parent37fd97989ee9d7d687649549e29bd8acd5793577 (diff)
parentb8c1bb3c6dcb03eab62dfa5719c73cbada7d60a8 (diff)
downloadandroid-clat-android-mainline-12.0.0_r83.tar.gz
Snap for 8093028 from b8c1bb3c6dcb03eab62dfa5719c73cbada7d60a8 to mainline-wifi-releaseandroid-mainline-12.0.0_r83
Change-Id: Iff284fa38bf8b97b50ea8c58340e3c33022f8101
-rw-r--r--Android.bp36
-rw-r--r--clatd.c258
-rw-r--r--clatd.h13
-rw-r--r--clatd_test.cpp100
-rw-r--r--config.h3
-rw-r--r--dump.c11
-rw-r--r--getaddr.c139
-rw-r--r--getaddr.h2
-rw-r--r--ipv4.c3
-rw-r--r--ipv6.c6
-rw-r--r--main.c83
-rw-r--r--netlink_callbacks.c67
-rw-r--r--netlink_callbacks.h24
-rw-r--r--netlink_msg.c182
-rw-r--r--netlink_msg.h30
-rw-r--r--ring.c128
-rw-r--r--ring.h55
-rw-r--r--setif.c184
-rw-r--r--setif.h28
-rw-r--r--translate.c6
-rw-r--r--vendor-464xlat.rc15
21 files changed, 202 insertions, 1171 deletions
diff --git a/Android.bp b/Android.bp
index bdddd7a..47d22a1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -32,11 +32,6 @@ cc_defaults {
// Bug: http://b/33566695
"-Wno-address-of-packed-member",
],
-
- // For MARK_UNSET.
- header_libs: [
- "libnetd_client_headers"
- ],
}
// Code used both by the daemon and by unit tests.
@@ -50,10 +45,6 @@ filegroup {
"ipv4.c",
"ipv6.c",
"logging.c",
- "netlink_callbacks.c",
- "netlink_msg.c",
- "ring.c",
- "setif.c",
"translate.c",
],
}
@@ -62,16 +53,25 @@ filegroup {
cc_binary {
name: "clatd",
defaults: ["clatd_defaults"],
+ // TODO: remove once drop_root_and_caps() is removed.
+ header_libs: [
+ "libcutils_headers", // for AID_CLAT
+ ],
srcs: [
":clatd_common",
"main.c"
],
- static_libs: ["libnl"],
+ static_libs: [
+ "libip_checksum",
+ ],
shared_libs: [
- "libcutils",
"liblog",
- "libnetutils",
],
+ relative_install_path: "for-system",
+
+ // Static libc++ for smaller apex size while shipping clatd in the mainline module.
+ // See b/213123047
+ stl: "libc++_static",
// Only enable clang-tidy for the daemon, not the tests, because enabling it for the
// tests substantially increases build/compile cycle times and doesn't really provide a
@@ -86,13 +86,15 @@ cc_binary {
tidy_flags: [
"-warnings-as-errors=clang-analyzer-security*,cert-*,android-*",
],
- // Actually not required for clatd itself. See comments in the rc file.
- init_rc: [
- "vendor-464xlat.rc",
- ],
sanitize: {
memtag_heap: true,
},
+
+ apex_available: [
+ "com.android.tethering",
+ "//apex_available:platform",
+ ],
+ min_sdk_version: "30",
}
// Unit tests.
@@ -105,8 +107,8 @@ cc_test {
],
static_libs: [
"libbase",
+ "libip_checksum",
"libnetd_test_tun_interface",
- "libnl",
],
shared_libs: [
"libcutils",
diff --git a/clatd.c b/clatd.c
index 3ffe934..f760fef 100644
--- a/clatd.c
+++ b/clatd.c
@@ -39,7 +39,6 @@
#include <sys/capability.h>
#include <sys/uio.h>
-#include <netid_client.h> // For MARK_UNSET.
#include <private/android_filesystem_config.h> // For AID_CLAT.
#include "clatd.h"
@@ -47,8 +46,6 @@
#include "dump.h"
#include "getaddr.h"
#include "logging.h"
-#include "ring.h"
-#include "setif.h"
#include "translate.h"
struct clat_config Global_Clatd_Config;
@@ -58,84 +55,6 @@ struct clat_config Global_Clatd_Config;
volatile sig_atomic_t running = 1;
-/* function: configure_packet_socket
- * Binds the packet socket and attaches the receive filter to it.
- * sock - the socket to configure
- */
-int configure_packet_socket(int sock) {
- uint32_t *ipv6 = Global_Clatd_Config.ipv6_local_subnet.s6_addr32;
-
- // clang-format off
- struct sock_filter filter_code[] = {
- // Load the first four bytes of the IPv6 destination address (starts 24 bytes in).
- // Compare it against the first four bytes of our IPv6 address, in host byte order (BPF loads
- // are always in host byte order). If it matches, continue with next instruction (JMP 0). If it
- // doesn't match, jump ahead to statement that returns 0 (ignore packet). Repeat for the other
- // three words of the IPv6 address, and if they all match, return PACKETLEN (accept packet).
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 24),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[0]), 0, 7),
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 28),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[1]), 0, 5),
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 32),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[2]), 0, 3),
- BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 36),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[3]), 0, 1),
- BPF_STMT(BPF_RET | BPF_K, PACKETLEN),
- BPF_STMT(BPF_RET | BPF_K, 0),
- };
- // clang-format on
- struct sock_fprog filter = { sizeof(filter_code) / sizeof(filter_code[0]), filter_code };
-
- if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) {
- logmsg(ANDROID_LOG_FATAL, "attach packet filter failed: %s", strerror(errno));
- return 0;
- }
-
- struct sockaddr_ll sll = {
- .sll_family = AF_PACKET,
- .sll_protocol = htons(ETH_P_IPV6),
- .sll_ifindex = if_nametoindex(Global_Clatd_Config.native_ipv6_interface),
- .sll_pkttype = PACKET_OTHERHOST, // The 464xlat IPv6 address is not assigned to the kernel.
- };
- if (bind(sock, (struct sockaddr *)&sll, sizeof(sll))) {
- logmsg(ANDROID_LOG_FATAL, "binding packet socket: %s", strerror(errno));
- return 0;
- }
-
- return 1;
-}
-
-/* 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, int mtu) {
- if (!v4_addr || !inet_pton(AF_INET, v4_addr, &Global_Clatd_Config.ipv4_local_subnet.s_addr)) {
- logmsg(ANDROID_LOG_FATAL, "Invalid IPv4 address %s", v4_addr);
- exit(1);
- }
-
- 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);
-
- // 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, mtu);
- if (status < 0) {
- logmsg(ANDROID_LOG_FATAL, "configure_tun_ip/if_up(4) failed: %s", strerror(-status));
- exit(1);
- }
-}
-
/* function: set_capability
* set the permitted, effective and inheritable capabilities of the current
* thread
@@ -156,18 +75,16 @@ void set_capability(uint64_t target_cap) {
}
}
-/* function: drop_root_but_keep_caps
- * drops root privs but keeps the needed capabilities
+/* function: drop_root_and_caps
+ * drops root privs and all capabilities
*/
-void drop_root_but_keep_caps() {
- gid_t groups[] = { AID_INET, AID_VPN };
- if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) < 0) {
+void drop_root_and_caps() {
+ // see man setgroups: this drops all supplementary groups
+ if (setgroups(0, NULL) < 0) {
logmsg(ANDROID_LOG_FATAL, "setgroups failed: %s", strerror(errno));
exit(1);
}
- prctl(PR_SET_KEEPCAPS, 1);
-
if (setresgid(AID_CLAT, AID_CLAT, AID_CLAT) < 0) {
logmsg(ANDROID_LOG_FATAL, "setresgid failed: %s", strerror(errno));
exit(1);
@@ -177,35 +94,7 @@ void drop_root_but_keep_caps() {
exit(1);
}
- // keep CAP_NET_RAW capability to open raw socket, and CAP_IPC_LOCK for mmap
- // to lock memory.
- set_capability((1 << CAP_NET_ADMIN) |
- (1 << CAP_NET_RAW) |
- (1 << CAP_IPC_LOCK));
-}
-
-/* function: open_sockets
- * opens a packet socket to receive IPv6 packets and a raw socket to send them
- * tunnel - tun device data
- * mark - the socket mark to use for the sending raw socket
- */
-void open_sockets(struct tun_data *tunnel, uint32_t mark) {
- int rawsock = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_RAW);
- if (rawsock < 0) {
- logmsg(ANDROID_LOG_FATAL, "raw socket failed: %s", strerror(errno));
- exit(1);
- }
-
- if (mark != MARK_UNSET && setsockopt(rawsock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) {
- logmsg(ANDROID_LOG_ERROR, "could not set mark on raw socket: %s", strerror(errno));
- }
-
- tunnel->write_fd6 = rawsock;
-
- tunnel->read_fd6 = ring_create(tunnel);
- if (tunnel->read_fd6 < 0) {
- exit(1);
- }
+ set_capability(0);
}
int ipv6_address_changed(const char *interface) {
@@ -231,111 +120,6 @@ 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
- * 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) {
- if (!v6_addr || !inet_pton(AF_INET6, v6_addr, &Global_Clatd_Config.ipv6_local_subnet)) {
- logmsg(ANDROID_LOG_FATAL, "Invalid source address %s", v6_addr);
- 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.
- add_anycast_address(tunnel->write_fd6, &Global_Clatd_Config.ipv6_local_subnet, interface);
-
- // Update our packet socket filter to reflect the new 464xlat IP address.
- 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.
- return 0;
- }
-
- 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
- * v4_addr - the v4 address to use on the tunnel interface
- * v6_addr - the v6 address to use on the native interface
- * tunnel - tun device data
- * 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, uint32_t mark) {
- Global_Clatd_Config.native_ipv6_interface = uplink_interface;
- if (!plat_prefix || inet_pton(AF_INET6, plat_prefix, &Global_Clatd_Config.plat_subnet) <= 0) {
- logmsg(ANDROID_LOG_FATAL, "invalid IPv6 address specified for plat prefix: %s", plat_prefix);
- exit(1);
- }
-
- 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, mtu);
-
- if (!configure_clat_ipv6_address(tunnel, uplink_interface, v6_addr)) {
- exit(1);
- }
-}
-
/* function: read_packet
* reads a packet from the tunnel fd and translates it
* read_fd - file descriptor to read original packet from
@@ -343,10 +127,8 @@ void configure_interface(const char *uplink_interface, const char *plat_prefix,
* to_ipv6 - whether the packet is to be translated to ipv6 or ipv4
*/
void read_packet(int read_fd, int write_fd, int to_ipv6) {
- ssize_t readlen;
- uint8_t buf[PACKETLEN], *packet;
-
- readlen = read(read_fd, buf, PACKETLEN);
+ uint8_t buf[PACKETLEN];
+ ssize_t readlen = read(read_fd, buf, PACKETLEN);
if (readlen < 0) {
if (errno != EAGAIN) {
@@ -359,6 +141,11 @@ void read_packet(int read_fd, int write_fd, int to_ipv6) {
return;
}
+ if (!to_ipv6) {
+ translate_packet(write_fd, 0 /* to_ipv6 */, buf, readlen);
+ return;
+ }
+
struct tun_pi *tun_header = (struct tun_pi *)buf;
if (readlen < (ssize_t)sizeof(*tun_header)) {
logmsg(ANDROID_LOG_WARN, "read_packet/short read: got %ld bytes", readlen);
@@ -375,9 +162,9 @@ void read_packet(int read_fd, int write_fd, int to_ipv6) {
logmsg(ANDROID_LOG_WARN, "%s: unexpected flags = %d", __func__, tun_header->flags);
}
- packet = (uint8_t *)(tun_header + 1);
+ uint8_t *packet = (uint8_t *)(tun_header + 1);
readlen -= sizeof(*tun_header);
- translate_packet(write_fd, to_ipv6, packet, readlen);
+ translate_packet(write_fd, 1 /* to_ipv6 */, packet, readlen);
}
/* function: event_loop
@@ -400,24 +187,13 @@ void event_loop(struct tun_data *tunnel) {
logmsg(ANDROID_LOG_WARN, "event_loop/poll returned an error: %s", strerror(errno));
}
} else {
- if (wait_fd[0].revents & POLLIN) {
- ring_read(&tunnel->ring, tunnel->fd4, 0 /* to_ipv6 */);
- }
- // If any other bit is set, assume it's due to an error (i.e. POLLERR).
- if (wait_fd[0].revents & ~POLLIN) {
- // ring_read doesn't clear the error indication on the socket.
- recv(tunnel->read_fd6, NULL, 0, MSG_PEEK);
- logmsg(ANDROID_LOG_WARN, "event_loop: clearing error on read_fd6: %s", strerror(errno));
- }
-
// Call read_packet if the socket has data to be read, but also if an
// error is waiting. If we don't call read() after getting POLLERR, a
// subsequent poll() will return immediately with POLLERR again,
// causing this code to spin in a loop. Calling read() will clear the
// socket error flag instead.
- if (wait_fd[1].revents) {
- read_packet(tunnel->fd4, tunnel->write_fd6, 1 /* to_ipv6 */);
- }
+ if (wait_fd[0].revents) read_packet(tunnel->read_fd6, tunnel->fd4, 0 /* to_ipv6 */);
+ if (wait_fd[1].revents) read_packet(tunnel->fd4, tunnel->write_fd6, 1 /* to_ipv6 */);
}
time_t now = time(NULL);
diff --git a/clatd.h b/clatd.h
index 899458c..be3c9c1 100644
--- a/clatd.h
+++ b/clatd.h
@@ -24,9 +24,9 @@
struct tun_data;
-#define MAXMTU 1500
+#define MAXMTU 65536
#define PACKETLEN (MAXMTU + sizeof(struct tun_pi))
-#define CLATD_VERSION "1.4"
+#define CLATD_VERSION "1.5"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
@@ -38,16 +38,9 @@ struct tun_data;
extern volatile sig_atomic_t running;
-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);
+void drop_root_and_caps();
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, uint32_t mark);
void event_loop(struct tun_data *tunnel);
/* function: parse_int
diff --git a/clatd_test.cpp b/clatd_test.cpp
index c16a4dd..8eef738 100644
--- a/clatd_test.cpp
+++ b/clatd_test.cpp
@@ -19,6 +19,7 @@
#include <iostream>
#include <arpa/inet.h>
+#include <linux/if_packet.h>
#include <netinet/in6.h>
#include <stdio.h>
#include <sys/uio.h>
@@ -29,10 +30,10 @@
#include "tun_interface.h"
extern "C" {
+#include "checksum.h"
#include "clatd.h"
#include "config.h"
#include "getaddr.h"
-#include "netutils/checksum.h"
#include "translate.h"
}
@@ -559,21 +560,6 @@ 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 {
- .read_fd6 = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)),
- .write_fd6 = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW),
- .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 {
@@ -624,29 +610,6 @@ TEST_F(ClatdTest, TestIPv6PrefixEqual) {
EXPECT_FALSE(ipv6_prefix_equal(&subnet2, &Global_Clatd_Config.ipv6_local_subnet));
}
-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, ConfigureTunIpManual) {
- // 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 */, 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);
- ASSERT_NE(nullptr, ip);
- EXPECT_EQ(inet_addr("192.0.2.1"), ip->ip4.s_addr);
- free(ip);
-
- v4Iface.destroy();
-}
-
TEST_F(ClatdTest, DataSanitycheck) {
// Sanity checks the data.
uint8_t v4_header[] = { IPV4_UDP_HEADER };
@@ -874,7 +837,20 @@ TEST_F(ClatdTest, TranslateChecksumNeutral) {
"UDP/IPv4 -> UDP/IPv6 checksum neutral");
}
-TEST_F(ClatdTest, GetInterfaceIp) {
+TEST_F(ClatdTest, GetInterfaceIpV4) {
+ TunInterface v4Iface;
+ ASSERT_EQ(0, v4Iface.init());
+ EXPECT_EQ(0, v4Iface.addAddress("192.0.2.1", 32));
+
+ 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);
+
+ v4Iface.destroy();
+}
+
+TEST_F(ClatdTest, GetInterfaceIpV6) {
union anyip *ip = getinterface_ip(sTun.name().c_str(), AF_INET6);
ASSERT_NE(nullptr, ip);
in6_addr expected = sTun.srcAddr();
@@ -882,50 +858,8 @@ 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) {
- 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;
- socklen_t len = sizeof(sll);
- 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) {
// Configure the clat IPv6 address.
- struct tun_data tunnel = {
- .read_fd6 = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)),
- .write_fd6 = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW),
- };
const char *ifname = sTun.name().c_str();
in6_addr myaddr = sTun.srcAddr();
@@ -933,7 +867,7 @@ TEST_F(ClatdTest, Ipv6AddressChanged) {
char addrstr[INET6_ADDRSTRLEN];
ASSERT_NE(nullptr, inet_ntop(AF_INET6, &myaddr, addrstr, sizeof(addrstr)));
- ASSERT_EQ(1, configure_clat_ipv6_address(&tunnel, ifname, addrstr));
+ Global_Clatd_Config.ipv6_local_subnet = myaddr;
EXPECT_EQ(0, ipv6_address_changed(ifname));
EXPECT_EQ(0, ipv6_address_changed(ifname));
diff --git a/config.h b/config.h
index 1ba6850..9612192 100644
--- a/config.h
+++ b/config.h
@@ -21,12 +21,9 @@
#include <linux/if.h>
#include <netinet/in.h>
-#include "ring.h"
-
struct tun_data {
char device4[IFNAMSIZ];
int read_fd6, write_fd6, fd4;
- struct packet_ring ring;
};
struct clat_config {
diff --git a/dump.c b/dump.c
index 7332d6c..289f161 100644
--- a/dump.c
+++ b/dump.c
@@ -15,9 +15,7 @@
*
* dump.c - print various headers for debugging
*/
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
+#include "dump.h"
#include <arpa/inet.h>
#include <linux/icmp.h>
@@ -29,12 +27,13 @@
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
-#include "netutils/checksum.h"
-
+#include "checksum.h"
#include "clatd.h"
#include "debug.h"
-#include "dump.h"
#include "logging.h"
#if CLAT_DEBUG
diff --git a/getaddr.c b/getaddr.c
index 6f4bc86..ba8052d 100644
--- a/getaddr.c
+++ b/getaddr.c
@@ -15,21 +15,26 @@
*
* getaddr.c - get a locally configured address
*/
+#include "getaddr.h"
+
+#include <errno.h>
+#include <linux/if_addr.h>
+#include <linux/rtnetlink.h>
#include <net/if.h>
#include <netinet/in.h>
+#include <stdlib.h>
#include <string.h>
#include <strings.h>
+#include <unistd.h>
-#include <linux/if_addr.h>
-#include <linux/rtnetlink.h>
-#include <netlink/handlers.h>
-#include <netlink/msg.h>
-
-#include "getaddr.h"
#include "logging.h"
-#include "netlink_msg.h"
-// shared state between getinterface_ip and getaddr_cb
+// Kernel suggests that keep the packet under 8KiB (NLMSG_GOODSIZE) in include/linux/netlink.h.
+#define NLMSG_SIZE 8192
+
+// shared state between getinterface_ip and parse_ifaddrmsg
+// TODO: refactor the communication between getinterface_ip and parse_ifaddrmsg because there
+// is no netlink callback anymore.
struct target {
int family;
unsigned int ifindex;
@@ -37,57 +42,97 @@ struct target {
int foundip;
};
-/* function: getaddr_cb
- * callback for getinterface_ip
- * msg - netlink message
- * data - (struct target) info for which address we're looking for
+/* function: parse_ifaddrmsg
+ * parse ifaddrmsg for getinterface_ip
+ * nh - netlink message header
+ * targ_p - (struct target) info for which address we're looking for
+ * and the parsed result if any.
*/
-static int getaddr_cb(struct nl_msg *msg, void *data) {
+static void parse_ifaddrmsg(struct nlmsghdr *nh, struct target *targ_p) {
struct ifaddrmsg *ifa_p;
struct rtattr *rta_p;
int rta_len;
- struct target *targ_p = (struct target *)data;
- ifa_p = (struct ifaddrmsg *)nlmsg_data(nlmsg_hdr(msg));
+ ifa_p = (struct ifaddrmsg *)NLMSG_DATA(nh);
rta_p = (struct rtattr *)IFA_RTA(ifa_p);
- if (ifa_p->ifa_index != targ_p->ifindex) return NL_OK;
+ if (ifa_p->ifa_index != targ_p->ifindex) return;
- if (ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) return NL_OK;
+ if (ifa_p->ifa_scope != RT_SCOPE_UNIVERSE) return;
- rta_len = RTM_PAYLOAD(nlmsg_hdr(msg));
+ rta_len = IFA_PAYLOAD(nh);
for (; RTA_OK(rta_p, rta_len); rta_p = RTA_NEXT(rta_p, rta_len)) {
switch (rta_p->rta_type) {
case IFA_ADDRESS:
if ((targ_p->family == AF_INET6) && !(ifa_p->ifa_flags & IFA_F_SECONDARY)) {
memcpy(&targ_p->ip.ip6, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
targ_p->foundip = 1;
- return NL_OK;
+ return;
}
break;
case IFA_LOCAL:
if (targ_p->family == AF_INET) {
memcpy(&targ_p->ip.ip4, RTA_DATA(rta_p), rta_p->rta_len - sizeof(struct rtattr));
targ_p->foundip = 1;
- return NL_OK;
+ return;
}
break;
}
}
-
- return NL_OK;
}
-/* function: error_handler
- * error callback for getinterface_ip
- * nla - source of the error message
- * err - netlink message
- * arg - (struct target) info for which address we're looking for
- */
-static int error_handler(__attribute__((unused)) struct sockaddr_nl *nla,
- __attribute__((unused)) struct nlmsgerr *err,
- __attribute__((unused)) void *arg) {
- return NL_OK;
+void sendrecv_ifaddrmsg(struct target *targ_p) {
+ int s = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
+ if (s < 0) {
+ logmsg(ANDROID_LOG_ERROR, "open NETLINK_ROUTE socket failed %s", strerror(errno));
+ return;
+ }
+
+ // Fill in netlink structures.
+ struct {
+ struct nlmsghdr n;
+ struct ifaddrmsg r;
+ } req = {
+ // Netlink message header.
+ .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ .n.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT,
+ .n.nlmsg_type = RTM_GETADDR,
+
+ // Interface address message header.
+ .r.ifa_family = targ_p->family,
+ };
+
+ // Send interface address message.
+ if ((send(s, &req, req.n.nlmsg_len, 0)) < 0) {
+ logmsg(ANDROID_LOG_ERROR, "send netlink socket failed %s", strerror(errno));
+ close(s);
+ return;
+ }
+
+ // Read interface address message and parse the result if any.
+ ssize_t bytes_read;
+ char buf[NLMSG_SIZE];
+ while ((bytes_read = recv(s, buf, sizeof(buf), 0)) > 0) {
+ struct nlmsghdr *nh = (struct nlmsghdr *)buf;
+ for (; NLMSG_OK(nh, bytes_read); nh = NLMSG_NEXT(nh, bytes_read)) {
+ if (nh->nlmsg_type == NLMSG_DONE) {
+ close(s);
+ return;
+ }
+ if (nh->nlmsg_type == NLMSG_ERROR) {
+ logmsg(ANDROID_LOG_ERROR, "netlink message error");
+ close(s);
+ return;
+ }
+ if (nh->nlmsg_type == RTM_NEWADDR) {
+ // Walk through the all messages and update struct target variable as the deleted
+ // callback behavior of getaddr_cb() which always returns NL_OK.
+ // TODO: review if this can early return once address has been found.
+ parse_ifaddrmsg(nh, targ_p);
+ }
+ }
+ }
+ close(s);
}
/* function: getinterface_ip
@@ -97,42 +142,28 @@ static int error_handler(__attribute__((unused)) struct sockaddr_nl *nla,
* family - family
*/
union anyip *getinterface_ip(const char *interface, int family) {
- struct ifaddrmsg ifa;
- struct nl_cb *callbacks = NULL;
- struct target targ;
union anyip *retval = NULL;
+ struct target targ = {
+ .family = family,
+ .foundip = 0,
+ .ifindex = if_nametoindex(interface),
+ };
- targ.family = family;
- targ.foundip = 0;
- targ.ifindex = if_nametoindex(interface);
if (targ.ifindex == 0) {
return NULL; // interface not found
}
- memset(&ifa, 0, sizeof(ifa));
- ifa.ifa_family = targ.family;
-
- callbacks = nl_cb_alloc(NL_CB_DEFAULT);
- if (!callbacks) {
- goto cleanup;
- }
- nl_cb_set(callbacks, NL_CB_VALID, NL_CB_CUSTOM, getaddr_cb, &targ);
- nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, &targ);
-
- // sends message and waits for a response
- send_ifaddrmsg(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ROOT, &ifa, callbacks);
+ // sends message and receives the response.
+ sendrecv_ifaddrmsg(&targ);
if (targ.foundip) {
retval = malloc(sizeof(union anyip));
if (!retval) {
logmsg(ANDROID_LOG_FATAL, "getinterface_ip/out of memory");
- goto cleanup;
+ return NULL;
}
memcpy(retval, &targ.ip, sizeof(union anyip));
}
-cleanup:
- if (callbacks) nl_cb_put(callbacks);
-
return retval;
}
diff --git a/getaddr.h b/getaddr.h
index 5718e62..482ac13 100644
--- a/getaddr.h
+++ b/getaddr.h
@@ -18,6 +18,8 @@
#ifndef __GETADDR_H__
#define __GETADDR_H__
+#include <netinet/in.h>
+
union anyip {
struct in6_addr ip6;
struct in_addr ip4;
diff --git a/ipv4.c b/ipv4.c
index c052d03..2be02e3 100644
--- a/ipv4.c
+++ b/ipv4.c
@@ -17,8 +17,7 @@
*/
#include <string.h>
-#include "netutils/checksum.h"
-
+#include "checksum.h"
#include "debug.h"
#include "dump.h"
#include "logging.h"
diff --git a/ipv6.c b/ipv6.c
index ca3e4c6..05cd3ab 100644
--- a/ipv6.c
+++ b/ipv6.c
@@ -15,12 +15,10 @@
*
* ipv6.c - takes ipv6 packets, finds their headers, and then calls translation functions on them
*/
-#include <string.h>
-
#include <arpa/inet.h>
+#include <string.h>
-#include "netutils/checksum.h"
-
+#include "checksum.h"
#include "config.h"
#include "debug.h"
#include "dump.h"
diff --git a/main.c b/main.c
index 52e22ac..3d1ff95 100644
--- a/main.c
+++ b/main.c
@@ -25,13 +25,10 @@
#include <sys/capability.h>
#include <unistd.h>
-#include <netid_client.h> // For MARK_UNSET.
-
#include "clatd.h"
#include "common.h"
#include "config.h"
#include "logging.h"
-#include "setif.h"
#define DEVICEPREFIX "v4-"
@@ -49,8 +46,9 @@ void print_help() {
printf("-p [plat prefix]\n");
printf("-4 [IPv4 address]\n");
printf("-6 [IPv6 address]\n");
- printf("-m [socket mark]\n");
printf("-t [tun file descriptor number]\n");
+ printf("-r [read socket descriptor number]\n");
+ printf("-w [write socket descriptor number]\n");
}
/* function: main
@@ -59,12 +57,12 @@ void print_help() {
int main(int argc, char **argv) {
struct tun_data tunnel;
int opt;
- char *uplink_interface = NULL, *plat_prefix = NULL, *mark_str = NULL;
- char *v4_addr = NULL, *v6_addr = NULL, *tunfd_str = NULL;
- uint32_t mark = MARK_UNSET;
+ char *uplink_interface = NULL, *plat_prefix = NULL;
+ char *v4_addr = NULL, *v6_addr = NULL, *tunfd_str = NULL, *read_sock_str = NULL,
+ *write_sock_str = NULL;
unsigned len;
- while ((opt = getopt(argc, argv, "i:p:4:6:m:t:h")) != -1) {
+ while ((opt = getopt(argc, argv, "i:p:4:6:t:r:w:h")) != -1) {
switch (opt) {
case 'i':
uplink_interface = optarg;
@@ -78,12 +76,15 @@ int main(int argc, char **argv) {
case '6':
v6_addr = optarg;
break;
- case 'm':
- mark_str = optarg;
- break;
case 't':
tunfd_str = optarg;
break;
+ case 'r':
+ read_sock_str = optarg;
+ break;
+ case 'w':
+ write_sock_str = optarg;
+ break;
case 'h':
print_help();
exit(0);
@@ -98,11 +99,6 @@ int main(int argc, char **argv) {
exit(1);
}
- if (mark_str != NULL && !parse_unsigned(mark_str, &mark)) {
- logmsg(ANDROID_LOG_FATAL, "invalid mark %s", mark_str);
- exit(1);
- }
-
if (tunfd_str != NULL && !parse_int(tunfd_str, &tunnel.fd4)) {
logmsg(ANDROID_LOG_FATAL, "invalid tunfd %s", tunfd_str);
exit(1);
@@ -112,30 +108,52 @@ int main(int argc, char **argv) {
exit(1);
}
+ if (read_sock_str != NULL && !parse_int(read_sock_str, &tunnel.read_fd6)) {
+ logmsg(ANDROID_LOG_FATAL, "invalid read socket %s", read_sock_str);
+ exit(1);
+ }
+ if (!tunnel.read_fd6) {
+ logmsg(ANDROID_LOG_FATAL, "no read_fd6 specified on commandline.");
+ exit(1);
+ }
+
+ if (write_sock_str != NULL && !parse_int(write_sock_str, &tunnel.write_fd6)) {
+ logmsg(ANDROID_LOG_FATAL, "invalid write socket %s", write_sock_str);
+ exit(1);
+ }
+ if (!tunnel.write_fd6) {
+ logmsg(ANDROID_LOG_FATAL, "no write_fd6 specified on commandline.");
+ exit(1);
+ }
+
len = snprintf(tunnel.device4, sizeof(tunnel.device4), "%s%s", DEVICEPREFIX, uplink_interface);
if (len >= sizeof(tunnel.device4)) {
logmsg(ANDROID_LOG_FATAL, "interface name too long '%s'", tunnel.device4);
exit(1);
}
- logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s mark=%s plat=%s v4=%s v6=%s",
- CLATD_VERSION, uplink_interface, 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();
+ Global_Clatd_Config.native_ipv6_interface = uplink_interface;
+ if (!plat_prefix || inet_pton(AF_INET6, plat_prefix, &Global_Clatd_Config.plat_subnet) <= 0) {
+ logmsg(ANDROID_LOG_FATAL, "invalid IPv6 address specified for plat prefix: %s", plat_prefix);
+ exit(1);
+ }
- // open our raw sockets before dropping privs
- open_sockets(&tunnel, mark);
+ if (!v4_addr || !inet_pton(AF_INET, v4_addr, &Global_Clatd_Config.ipv4_local_subnet.s_addr)) {
+ logmsg(ANDROID_LOG_FATAL, "Invalid IPv4 address %s", v4_addr);
+ exit(1);
+ }
- // keeps only admin capability
- set_capability(1 << CAP_NET_ADMIN);
+ if (!v6_addr || !inet_pton(AF_INET6, v6_addr, &Global_Clatd_Config.ipv6_local_subnet)) {
+ logmsg(ANDROID_LOG_FATAL, "Invalid source address %s", v6_addr);
+ exit(1);
+ }
- configure_interface(uplink_interface, plat_prefix, v4_addr, v6_addr, &tunnel, mark);
+ logmsg(ANDROID_LOG_INFO, "Starting clat version %s on %s plat=%s v4=%s v6=%s", CLATD_VERSION,
+ uplink_interface, plat_prefix ? plat_prefix : "(none)", v4_addr ? v4_addr : "(none)",
+ v6_addr ? v6_addr : "(none)");
- // Drop all remaining capabilities.
- set_capability(0);
+ // run under a regular user with no capabilities
+ drop_root_and_caps();
// Loop until someone sends us a signal or brings down the tun interface.
if (signal(SIGTERM, stop_loop) == SIG_ERR) {
@@ -146,11 +164,6 @@ int main(int argc, char **argv) {
event_loop(&tunnel);
logmsg(ANDROID_LOG_INFO, "Shutting down clat on %s", uplink_interface);
- del_anycast_address(tunnel.write_fd6, &Global_Clatd_Config.ipv6_local_subnet);
-
- close(tunnel.write_fd6);
- close(tunnel.read_fd6);
- close(tunnel.fd4);
if (running) {
logmsg(ANDROID_LOG_INFO, "Clatd on %s waiting for SIGTERM", uplink_interface);
diff --git a/netlink_callbacks.c b/netlink_callbacks.c
deleted file mode 100644
index 804976d..0000000
--- a/netlink_callbacks.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2012 Daniel Drown <dan-android@drown.org>
- *
- * 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.
- *
- * netlink_callbacks.c - generic callbacks for netlink responses
- */
-#include <net/if.h>
-#include <netinet/in.h>
-
-#include <linux/rtnetlink.h>
-#include <netlink/handlers.h>
-#include <netlink/msg.h>
-
-/* function: ack_handler
- * generic netlink callback for ack messages
- * msg - netlink message
- * data - pointer to an int, stores the success code
- */
-static int ack_handler(__attribute__((unused)) struct nl_msg *msg, void *data) {
- int *retval = data;
- *retval = 0;
- return NL_OK;
-}
-
-/* function: error_handler
- * generic netlink callback for error messages
- * nla - error source
- * err - netlink error message
- * arg - pointer to an int, stores the error code
- */
-static int error_handler(__attribute__((unused)) struct sockaddr_nl *nla, struct nlmsgerr *err,
- void *arg) {
- int *retval = arg;
- if (err->error < 0) {
- *retval = err->error;
- } else {
- *retval = 0; // NLMSG_ERROR used as reply type on no error
- }
- return NL_OK;
-}
-
-/* function: alloc_ack_callbacks
- * allocates a set of netlink callbacks. returns NULL on failure. callbacks will modify retval
- * with <0 meaning failure retval - shared state between caller and callback functions
- */
-struct nl_cb *alloc_ack_callbacks(int *retval) {
- struct nl_cb *callbacks;
-
- callbacks = nl_cb_alloc(NL_CB_DEFAULT);
- if (!callbacks) {
- return NULL;
- }
- nl_cb_set(callbacks, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, retval);
- nl_cb_err(callbacks, NL_CB_CUSTOM, error_handler, retval);
- return callbacks;
-}
diff --git a/netlink_callbacks.h b/netlink_callbacks.h
deleted file mode 100644
index 298ad3e..0000000
--- a/netlink_callbacks.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2012 Daniel Drown <dan-android@drown.org>
- *
- * 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.
- *
- * netlink_callbacks.h - callbacks for netlink responses
- */
-
-#ifndef __NETLINK_CALLBACKS_H__
-#define __NETLINK_CALLBACKS_H__
-
-struct nl_cb *alloc_ack_callbacks(int *retval);
-
-#endif
diff --git a/netlink_msg.c b/netlink_msg.c
deleted file mode 100644
index be76ecd..0000000
--- a/netlink_msg.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2012 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.
- *
- * netlink_msg.c - send an ifaddrmsg/ifinfomsg/rtmsg via netlink
- */
-
-#include <errno.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <netinet/in.h>
-#include <string.h>
-
-#include <netlink-private/object-api.h>
-#include <netlink-private/types.h>
-#include <netlink/msg.h>
-#include <netlink/netlink.h>
-#include <netlink/socket.h>
-
-#include "netlink_callbacks.h"
-#include "netlink_msg.h"
-
-/* function: family_size
- * returns the size of the address structure for the given family, or 0 on error
- * family - AF_INET or AF_INET6
- */
-size_t inet_family_size(int family) {
- if (family == AF_INET) {
- return sizeof(struct in_addr);
- } else if (family == AF_INET6) {
- return sizeof(struct in6_addr);
- } else {
- return 0;
- }
-}
-
-/* function: nlmsg_alloc_generic
- * allocates a netlink message with the given struct inside of it. returns NULL on failure
- * type - netlink message type
- * flags - netlink message flags
- * payload_struct - pointer to a struct to add to netlink message
- * payload_len - bytelength of structure
- */
-struct nl_msg *nlmsg_alloc_generic(uint16_t type, uint16_t flags, void *payload_struct,
- size_t payload_len) {
- struct nl_msg *msg;
-
- msg = nlmsg_alloc();
- if (!msg) {
- return NULL;
- }
-
- if ((sizeof(struct nl_msg) + payload_len) > msg->nm_size) {
- nlmsg_free(msg);
- return NULL;
- }
-
- msg->nm_nlh->nlmsg_len = NLMSG_LENGTH(payload_len);
- msg->nm_nlh->nlmsg_flags = flags;
- msg->nm_nlh->nlmsg_type = type;
-
- memcpy(nlmsg_data(msg->nm_nlh), payload_struct, payload_len);
-
- return msg;
-}
-
-/* function: nlmsg_alloc_ifaddr
- * allocates a netlink message with a struct ifaddrmsg inside of it. returns NULL on failure
- * type - netlink message type
- * flags - netlink message flags
- * ifa - ifaddrmsg to copy into the new netlink message
- */
-struct nl_msg *nlmsg_alloc_ifaddr(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa) {
- return nlmsg_alloc_generic(type, flags, ifa, sizeof(*ifa));
-}
-
-/* function: nlmsg_alloc_ifinfo
- * allocates a netlink message with a struct ifinfomsg inside of it. returns NULL on failure
- * type - netlink message type
- * flags - netlink message flags
- * ifi - ifinfomsg to copy into the new netlink message
- */
-struct nl_msg *nlmsg_alloc_ifinfo(uint16_t type, uint16_t flags, struct ifinfomsg *ifi) {
- return nlmsg_alloc_generic(type, flags, ifi, sizeof(*ifi));
-}
-
-/* function: nlmsg_alloc_rtmsg
- * allocates a netlink message with a struct rtmsg inside of it. returns NULL on failure
- * type - netlink message type
- * flags - netlink message flags
- * rt - rtmsg to copy into the new netlink message
- */
-struct nl_msg *nlmsg_alloc_rtmsg(uint16_t type, uint16_t flags, struct rtmsg *rt) {
- return nlmsg_alloc_generic(type, flags, rt, sizeof(*rt));
-}
-
-/* function: netlink_set_kernel_only
- * sets a socket to receive messages only from the kernel
- * sock - socket to connect
- */
-int netlink_set_kernel_only(struct nl_sock *nl_sk) {
- struct sockaddr_nl addr = { AF_NETLINK, 0, 0, 0 };
-
- if (!nl_sk) {
- return -EFAULT;
- }
-
- int sockfd = nl_socket_get_fd(nl_sk);
- return connect(sockfd, (struct sockaddr *)&addr, sizeof(addr));
-}
-
-/* function: send_netlink_msg
- * sends a netlink message, reads a response, and hands the response(s) to the callbacks
- * msg - netlink message to send
- * callbacks - callbacks to use on responses
- */
-void send_netlink_msg(struct nl_msg *msg, struct nl_cb *callbacks) {
- struct nl_sock *nl_sk;
-
- nl_sk = nl_socket_alloc();
- if (!nl_sk) goto cleanup;
-
- if (nl_connect(nl_sk, NETLINK_ROUTE) != 0) goto cleanup;
-
- if (nl_send_auto_complete(nl_sk, msg) < 0) goto cleanup;
-
- if (netlink_set_kernel_only(nl_sk) < 0) goto cleanup;
-
- nl_recvmsgs(nl_sk, callbacks);
-
-cleanup:
- if (nl_sk) nl_socket_free(nl_sk);
-}
-
-/* function: send_ifaddrmsg
- * sends a netlink/ifaddrmsg message and hands the responses to the callbacks
- * type - netlink message type
- * flags - netlink message flags
- * ifa - ifaddrmsg to send
- * callbacks - callbacks to use with the responses
- */
-void send_ifaddrmsg(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa, struct nl_cb *callbacks) {
- struct nl_msg *msg = NULL;
-
- msg = nlmsg_alloc_ifaddr(type, flags, ifa);
- if (!msg) return;
-
- send_netlink_msg(msg, callbacks);
-
- nlmsg_free(msg);
-}
-
-/* function: netlink_sendrecv
- * send a nl_msg and return an int status - only supports OK/ERROR responses
- * msg - msg to send
- */
-int netlink_sendrecv(struct nl_msg *msg) {
- struct nl_cb *callbacks = NULL;
- int retval = -EIO;
-
- callbacks = alloc_ack_callbacks(&retval);
- if (!callbacks) {
- return -ENOMEM;
- }
-
- send_netlink_msg(msg, callbacks);
-
- nl_cb_put(callbacks);
-
- return retval;
-}
diff --git a/netlink_msg.h b/netlink_msg.h
deleted file mode 100644
index 13e1f28..0000000
--- a/netlink_msg.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2012 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.
- *
- * netlink_msg.h - send an ifaddrmsg/ifinfomsg via netlink
- */
-#ifndef __NETLINK_IFMSG_H__
-#define __NETLINK_IFMSG_H__
-
-size_t inet_family_size(int family);
-struct nl_msg *nlmsg_alloc_ifaddr(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa);
-struct nl_msg *nlmsg_alloc_ifinfo(uint16_t type, uint16_t flags, struct ifinfomsg *ifi);
-struct nl_msg *nlmsg_alloc_rtmsg(uint16_t type, uint16_t flags, struct rtmsg *rt);
-void send_netlink_msg(struct nl_msg *msg, struct nl_cb *callbacks);
-void send_ifaddrmsg(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa, struct nl_cb *callbacks);
-int netlink_sendrecv(struct nl_msg *msg);
-int netlink_set_kernel_only(struct nl_sock *nl_sk);
-
-#endif
diff --git a/ring.c b/ring.c
deleted file mode 100644
index 7626c6d..0000000
--- a/ring.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * 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.
- *
- * ring.c - packet ring buffer functions
- */
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <linux/if.h>
-#include <linux/if_packet.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/socket.h>
-
-#include "config.h"
-#include "logging.h"
-#include "ring.h"
-#include "translate.h"
-
-int ring_create(struct tun_data *tunnel) {
- // Will eventually be bound to htons(ETH_P_IPV6) protocol,
- // but only after appropriate bpf filter is attached.
- int packetsock = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- if (packetsock < 0) {
- logmsg(ANDROID_LOG_FATAL, "packet socket failed: %s", strerror(errno));
- return -1;
- }
-
- int ver = TPACKET_V2;
- if (setsockopt(packetsock, SOL_PACKET, PACKET_VERSION, (void *)&ver, sizeof(ver))) {
- logmsg(ANDROID_LOG_FATAL, "setsockopt(PACKET_VERSION, %d) failed: %s", ver, strerror(errno));
- return -1;
- }
-
- int on = 1;
- if (setsockopt(packetsock, SOL_PACKET, PACKET_LOSS, (void *)&on, sizeof(on))) {
- logmsg(ANDROID_LOG_WARN, "PACKET_LOSS failed: %s", strerror(errno));
- }
-
- struct packet_ring *ring = &tunnel->ring;
- ring->numblocks = TP_NUM_BLOCKS;
-
- int total_frames = TP_FRAMES * ring->numblocks;
-
- struct tpacket_req req = {
- .tp_frame_size = TP_FRAME_SIZE, // Frame size.
- .tp_block_size = TP_BLOCK_SIZE, // Frames per block.
- .tp_block_nr = ring->numblocks, // Number of blocks.
- .tp_frame_nr = total_frames, // Total frames.
- };
-
- if (setsockopt(packetsock, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req)) < 0) {
- logmsg(ANDROID_LOG_FATAL, "PACKET_RX_RING failed: %s", strerror(errno));
- return -1;
- }
-
- size_t buflen = TP_BLOCK_SIZE * ring->numblocks;
- ring->base = mmap(NULL, buflen, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED | MAP_POPULATE,
- packetsock, 0);
- if (ring->base == MAP_FAILED) {
- logmsg(ANDROID_LOG_FATAL, "mmap %lu failed: %s", buflen, strerror(errno));
- return -1;
- }
-
- ring->block = 0;
- ring->slot = 0;
- ring->numslots = TP_BLOCK_SIZE / TP_FRAME_SIZE;
- ring->next = (struct tpacket2_hdr *)ring->base;
-
- logmsg(ANDROID_LOG_INFO, "Using ring buffer with %d frames (%d bytes) at %p", total_frames,
- buflen, ring->base);
-
- return packetsock;
-}
-
-/* function: ring_advance
- * advances to the next position in the packet ring
- * ring - packet ring buffer
- */
-static struct tpacket2_hdr *ring_advance(struct packet_ring *ring) {
- uint8_t *next = (uint8_t *)ring->next;
-
- ring->slot++;
- next += TP_FRAME_SIZE;
-
- if (ring->slot == ring->numslots) {
- ring->slot = 0;
- ring->block++;
-
- if (ring->block < ring->numblocks) {
- next += TP_FRAME_GAP;
- } else {
- ring->block = 0;
- next = (uint8_t *)ring->base;
- }
- }
-
- ring->next = (struct tpacket2_hdr *)next;
- return ring->next;
-}
-
-/* function: ring_read
- * reads a packet from the ring buffer and translates it
- * read_fd - file descriptor to read original packet from
- * write_fd - file descriptor to write translated packet to
- * to_ipv6 - whether the packet is to be translated to ipv6 or ipv4
- */
-void ring_read(struct packet_ring *ring, int write_fd, int to_ipv6) {
- struct tpacket2_hdr *tp = ring->next;
- if (tp->tp_status & TP_STATUS_USER) {
- uint8_t *packet = ((uint8_t *)tp) + tp->tp_net;
- translate_packet(write_fd, to_ipv6, packet, tp->tp_len);
- tp->tp_status = TP_STATUS_KERNEL;
- tp = ring_advance(ring);
- }
-}
diff --git a/ring.h b/ring.h
deleted file mode 100644
index b9b8c11..0000000
--- a/ring.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2014 The Android Open Source Project
- *
- * 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.
- *
- * ring.c - packet ring buffer functions
- */
-#ifndef __RING_H__
-#define __RING_H__
-
-#include <linux/if.h>
-#include <linux/if_packet.h>
-
-#include "clatd.h"
-
-struct tun_data;
-
-// Frame size. Must be a multiple of TPACKET_ALIGNMENT (=16)
-// Why the 16? http://lxr.free-electrons.com/source/net/packet/af_packet.c?v=3.4#L1764
-#define TP_FRAME_SIZE (TPACKET_ALIGN(MAXMTU) + TPACKET_ALIGN(TPACKET2_HDRLEN) + 16)
-
-// Block size. Must be a multiple of the page size, and a power of two for efficient memory use.
-#define TP_BLOCK_SIZE 65536
-
-// In order to save memory, our frames are not an exact divider of the block size. Therefore, the
-// mmaped region will have gaps corresponding to the empty space at the end of each block.
-#define TP_FRAMES (TP_BLOCK_SIZE / TP_FRAME_SIZE)
-#define TP_FRAME_GAP (TP_BLOCK_SIZE % TP_FRAME_SIZE)
-
-// TODO: Make this configurable. This requires some refactoring because the packet socket is
-// opened before we drop privileges, but the configuration file is read after. A value of 16
-// results in 656 frames (1048576 bytes).
-#define TP_NUM_BLOCKS 16
-
-struct packet_ring {
- uint8_t *base;
- struct tpacket2_hdr *next;
- int slot, numslots;
- int block, numblocks;
-};
-
-int ring_create(struct tun_data *tunnel);
-void ring_read(struct packet_ring *ring, int write_fd, int to_ipv6);
-
-#endif
diff --git a/setif.c b/setif.c
deleted file mode 100644
index 184a46b..0000000
--- a/setif.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright 2012 Daniel Drown <dan-android@drown.org>
- *
- * 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.
- *
- * setif.c - network interface configuration
- */
-#include <errno.h>
-#include <net/if.h>
-#include <netinet/in.h>
-
-#include <linux/rtnetlink.h>
-#include <netlink/handlers.h>
-#include <netlink/msg.h>
-
-#include "logging.h"
-#include "netlink_msg.h"
-
-#define DEBUG_OPTNAME(a) \
- case (a): { \
- optname = #a; \
- break; \
- }
-
-/* function: add_address
- * adds an IP address to/from an interface, returns 0 on success and <0 on failure
- * ifname - name of interface to change
- * family - address family (AF_INET, AF_INET6)
- * address - pointer to a struct in_addr or in6_addr
- * prefixlen - bitlength of network (example: 24 for AF_INET's 255.255.255.0)
- * broadcast - broadcast address (only for AF_INET, ignored for AF_INET6)
- */
-int add_address(const char *ifname, int family, const void *address, int prefixlen,
- const void *broadcast) {
- int retval;
- size_t addr_size;
- struct ifaddrmsg ifa;
- struct nl_msg *msg = NULL;
-
- addr_size = inet_family_size(family);
- if (addr_size == 0) {
- retval = -EAFNOSUPPORT;
- goto cleanup;
- }
-
- memset(&ifa, 0, sizeof(ifa));
- if (!(ifa.ifa_index = if_nametoindex(ifname))) {
- retval = -ENODEV;
- goto cleanup;
- }
- ifa.ifa_family = family;
- ifa.ifa_prefixlen = prefixlen;
- ifa.ifa_scope = RT_SCOPE_UNIVERSE;
-
- msg =
- nlmsg_alloc_ifaddr(RTM_NEWADDR, NLM_F_ACK | NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE, &ifa);
- if (!msg) {
- retval = -ENOMEM;
- goto cleanup;
- }
-
- if (nla_put(msg, IFA_LOCAL, addr_size, address) < 0) {
- retval = -ENOMEM;
- goto cleanup;
- }
- if (family == AF_INET6) {
- // AF_INET6 gets IFA_LOCAL + IFA_ADDRESS
- if (nla_put(msg, IFA_ADDRESS, addr_size, address) < 0) {
- retval = -ENOMEM;
- goto cleanup;
- }
- } else if (family == AF_INET) {
- // AF_INET gets IFA_LOCAL + IFA_BROADCAST
- if (nla_put(msg, IFA_BROADCAST, addr_size, broadcast) < 0) {
- retval = -ENOMEM;
- goto cleanup;
- }
- } else {
- retval = -EAFNOSUPPORT;
- goto cleanup;
- }
-
- retval = netlink_sendrecv(msg);
-
-cleanup:
- if (msg) nlmsg_free(msg);
-
- return retval;
-}
-
-/* function: if_up
- * sets interface link state to up and sets mtu, returns 0 on success and <0 on failure
- * ifname - interface name to change
- * mtu - new mtu
- */
-int if_up(const char *ifname, int mtu) {
- int retval = -1;
- struct ifinfomsg ifi;
- struct nl_msg *msg = NULL;
-
- memset(&ifi, 0, sizeof(ifi));
- if (!(ifi.ifi_index = if_nametoindex(ifname))) {
- retval = -ENODEV;
- goto cleanup;
- }
- ifi.ifi_change = IFF_UP;
- ifi.ifi_flags = IFF_UP;
-
- msg = nlmsg_alloc_ifinfo(RTM_SETLINK, NLM_F_ACK | NLM_F_REQUEST | NLM_F_ROOT, &ifi);
- if (!msg) {
- retval = -ENOMEM;
- goto cleanup;
- }
-
- if (nla_put(msg, IFLA_MTU, 4, &mtu) < 0) {
- retval = -ENOMEM;
- goto cleanup;
- }
-
- retval = netlink_sendrecv(msg);
-
-cleanup:
- if (msg) nlmsg_free(msg);
-
- return retval;
-}
-
-static int do_anycast_setsockopt(int sock, int what, struct in6_addr *addr, int ifindex) {
- struct ipv6_mreq mreq = { *addr, ifindex };
- char *optname;
- int ret;
-
- switch (what) {
- DEBUG_OPTNAME(IPV6_JOIN_ANYCAST)
- DEBUG_OPTNAME(IPV6_LEAVE_ANYCAST)
- default:
- optname = "???";
- break;
- }
-
- ret = setsockopt(sock, SOL_IPV6, what, &mreq, sizeof(mreq));
- if (ret) {
- logmsg(ANDROID_LOG_ERROR, "%s: setsockopt(%s): %s", __func__, optname, strerror(errno));
- }
-
- return ret;
-}
-
-/* function: add_anycast_address
- * adds an anycast IPv6 address to an interface, returns 0 on success and <0 on failure
- * sock - the socket to add the address to
- * addr - the IP address to add
- * ifname - name of interface to add the address to
- */
-int add_anycast_address(int sock, struct in6_addr *addr, const char *ifname) {
- int ifindex;
-
- ifindex = if_nametoindex(ifname);
- if (!ifindex) {
- logmsg(ANDROID_LOG_ERROR, "%s: unknown ifindex for interface %s", __func__, ifname);
- return -ENODEV;
- }
-
- return do_anycast_setsockopt(sock, IPV6_JOIN_ANYCAST, addr, ifindex);
-}
-
-/* function: del_anycast_address
- * removes an anycast IPv6 address from the system, returns 0 on success and <0 on failure
- * sock - the socket to remove from, must have had the address added via add_anycast_address
- * addr - the IP address to remove
- */
-int del_anycast_address(int sock, struct in6_addr *addr) {
- return do_anycast_setsockopt(sock, IPV6_LEAVE_ANYCAST, addr, 0);
-}
diff --git a/setif.h b/setif.h
deleted file mode 100644
index 2d0adb1..0000000
--- a/setif.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2012 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.
- *
- * setif.h - network interface configuration
- */
-#ifndef __SETIF_H__
-#define __SETIF_H__
-
-int add_address(const char *ifname, int family, const void *address, int cidr,
- const void *broadcast);
-int if_up(const char *ifname, int mtu);
-
-int add_anycast_address(int sock, const struct in6_addr *addr, const char *interface);
-int del_anycast_address(int sock, const struct in6_addr *addr);
-
-#endif
diff --git a/translate.c b/translate.c
index 728acc3..22830d8 100644
--- a/translate.c
+++ b/translate.c
@@ -15,17 +15,17 @@
*
* translate.c - CLAT functions / partial implementation of rfc6145
*/
-#include <string.h>
+#include "translate.h"
-#include "netutils/checksum.h"
+#include <string.h>
+#include "checksum.h"
#include "clatd.h"
#include "common.h"
#include "config.h"
#include "debug.h"
#include "icmp.h"
#include "logging.h"
-#include "translate.h"
/* function: packet_checksum
* calculates the checksum over all the packet components starting from pos
diff --git a/vendor-464xlat.rc b/vendor-464xlat.rc
deleted file mode 100644
index 609531d..0000000
--- a/vendor-464xlat.rc
+++ /dev/null
@@ -1,15 +0,0 @@
-# Certain vendors disable 464xlat by setting a vendor property.
-# The connectivity code in the Tethering APEX needs to disable
-# 464xlat when the property is set, but it is only allowed to
-# access non-vendor system properties. So copy the property to
-# a property available to system APIs in android.sysprop.
-#
-# Arguably this script should live close to the code that uses
-# it, but scrips in APEXes are not allowed to use "on property".
-# So put it here close to clatd, which is at least related to
-# 464xlat.
-on property:persist.vendor.net.doxlat=true
- setprop net.464xlat.cellular.enabled true
-
-on property:persist.vendor.net.doxlat=false
- setprop net.464xlat.cellular.enabled false