Move main() out of clatd.c.

This allows us to unit test methods that are in clatd.c.
Also simplify the build file, adding a defaults stanza and
grouping files in a filegroup so that both the code and the unit
test have the same source files.

Test: atest clatd_test
Test: builds, boots, 464xlat works
Change-Id: I544c3ee846abd3e38b80a2d9a4db5497fd9beb0c
This commit is contained in:
Lorenzo Colitti 2019-01-04 14:59:11 +09:00
commit eb92f48b1d
9 changed files with 247 additions and 175 deletions

View file

@ -1,26 +1,5 @@
// The clat daemon.
cc_binary {
name: "clatd",
srcs: [
"clatd.c",
"dump.c",
"checksum.c",
"translate.c",
"icmp.c",
"ipv4.c",
"ipv6.c",
"config.c",
"dns64.c",
"logging.c",
"getaddr.c",
"netlink_callbacks.c",
"netlink_msg.c",
"setif.c",
"mtu.c",
"tun.c",
"ring.c",
],
cc_defaults {
name: "clatd_defaults",
cflags: [
"-Wall",
@ -31,15 +10,51 @@ cc_binary {
"-Wno-address-of-packed-member",
],
// For NETID_UNSET and MARK_UNSET.
include_dirs: ["bionic/libc/dns/include"],
// For NETID_USE_LOCAL_NAMESERVERS.
header_libs: ["libnetd_client_headers"],
}
// Code used both by the daemon and by unit tests.
filegroup {
name: "clatd_common",
srcs: [
"checksum.c",
"config.c",
"clatd.c",
"dns64.c",
"dump.c",
"getaddr.c",
"icmp.c",
"ipv4.c",
"ipv6.c",
"logging.c",
"mtu.c",
"netlink_callbacks.c",
"netlink_msg.c",
"ring.c",
"setif.c",
"tun.c",
"translate.c",
],
}
// The clat daemon.
cc_binary {
name: "clatd",
defaults: ["clatd_defaults"],
srcs: [
":clatd_common",
"main.c"
],
static_libs: ["libnl"],
shared_libs: [
"libcutils",
"liblog",
"libnetutils",
],
}
// The configuration file.
@ -51,28 +66,18 @@ prebuilt_etc {
// Unit tests.
cc_test {
name: "clatd_test",
cflags: [
"-Wall",
"-Werror",
"-Wunused-parameter",
// Bug: http://b/33566695
"-Wno-address-of-packed-member",
],
defaults: ["clatd_defaults"],
srcs: [
"clatd_test.cpp",
"checksum.c",
"translate.c",
"icmp.c",
"ipv4.c",
"ipv6.c",
"logging.c",
"config.c",
"tun.c",
":clatd_common",
"clatd_test.cpp"
],
static_libs: [
"libbase",
"libnetd_test_tun_interface",
"libnl",
],
shared_libs: [
"libcutils",
"liblog",
"libnetutils",
],
@ -81,12 +86,7 @@ cc_test {
// Microbenchmark.
cc_test {
name: "clatd_microbenchmark",
cflags: [
"-Wall",
"-Werror",
"-Wunused-parameter",
],
defaults: ["clatd_defaults"],
srcs: [
"clatd_microbenchmark.c",
"checksum.c",

110
clatd.c
View file

@ -53,8 +53,6 @@
#include "translate.h"
#include "tun.h"
#define DEVICEPREFIX "v4-"
/* 40 bytes IPv6 header - 20 bytes IPv4 header + 8 bytes fragment header */
#define MTU_DELTA 28
@ -426,17 +424,6 @@ void event_loop(struct tun_data *tunnel) {
}
}
/* function: print_help
* in case the user is running this on the command line
*/
void print_help() {
printf("android-clat arguments:\n");
printf("-i [uplink interface]\n");
printf("-p [plat prefix]\n");
printf("-n [NetId]\n");
printf("-m [socket mark]\n");
}
/* function: parse_unsigned
* parses a string as a decimal/hex/octal unsigned integer
* str - the string to parse
@ -447,100 +434,3 @@ int parse_unsigned(const char *str, unsigned *out) {
*out = strtoul(str, &end_ptr, 0);
return *str && !*end_ptr;
}
/* function: main
* allocate and setup the tun device, then run the event loop
*/
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;
unsigned net_id = NETID_UNSET;
uint32_t mark = MARK_UNSET;
unsigned len;
while ((opt = getopt(argc, argv, "i:p:n:m:h")) != -1) {
switch (opt) {
case 'i':
uplink_interface = optarg;
break;
case 'p':
plat_prefix = optarg;
break;
case 'n':
net_id_str = optarg;
break;
case 'm':
mark_str = optarg;
break;
case 'h':
print_help();
exit(0);
default:
logmsg(ANDROID_LOG_FATAL, "Unknown option -%c. Exiting.", (char)optopt);
exit(1);
}
}
if (uplink_interface == NULL) {
logmsg(ANDROID_LOG_FATAL, "clatd called without an interface");
exit(1);
}
if (net_id_str != NULL && !parse_unsigned(net_id_str, &net_id)) {
logmsg(ANDROID_LOG_FATAL, "invalid NetID %s", net_id_str);
exit(1);
}
if (mark_str != NULL && !parse_unsigned(mark_str, &mark)) {
logmsg(ANDROID_LOG_FATAL, "invalid mark %s", mark_str);
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 netid=%s mark=%s", CLATD_VERSION,
uplink_interface, net_id_str ? net_id_str : "(none)", mark_str ? mark_str : "(none)");
// run under a regular user but keep needed capabilities
drop_root_but_keep_caps();
// open our raw sockets before dropping privs
open_sockets(&tunnel, mark);
// keeps only admin capability
set_capability(1 << CAP_NET_ADMIN);
// we can create tun devices as non-root because we're in the VPN group.
tunnel.fd4 = tun_open();
if (tunnel.fd4 < 0) {
logmsg(ANDROID_LOG_FATAL, "tun_open4 failed: %s", strerror(errno));
exit(1);
}
// When run from netd, the environment variable ANDROID_DNS_MODE is set to
// "local", but that only works for the netd process itself. Removing the
// following line causes XLAT failure in permissive mode.
unsetenv("ANDROID_DNS_MODE");
configure_interface(uplink_interface, plat_prefix, &tunnel, net_id);
update_clat_ipv6_address(&tunnel, uplink_interface);
// Loop until someone sends us a signal or brings down the tun interface.
if (signal(SIGTERM, stop_loop) == SIG_ERR) {
logmsg(ANDROID_LOG_FATAL, "sigterm handler failed: %s", strerror(errno));
exit(1);
}
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);
return 0;
}

30
clatd.h
View file

@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
* clatd.h - main system definitions
* clatd.h - main routines used by clatd
*/
#ifndef __CLATD_H__
#define __CLATD_H__
#include <sys/uio.h>
struct tun_data;
#define MAXMTU 1500
#define PACKETLEN (MAXMTU + sizeof(struct tun_pi))
#define CLATD_VERSION "1.4"
@ -32,21 +34,15 @@
// how frequently (in seconds) to poll for an address change while there is no traffic
#define NO_TRAFFIC_INTERFACE_POLL_FREQUENCY 90
// A clat_packet is an array of iovec structures representing a packet that we are translating.
// The CLAT_POS_XXX constants represent the array indices within the clat_packet that contain
// specific parts of the packet. The packet_* functions operate on all the packet segments past a
// given position.
typedef enum {
CLAT_POS_TUNHDR,
CLAT_POS_IPHDR,
CLAT_POS_FRAGHDR,
CLAT_POS_TRANSPORTHDR,
CLAT_POS_ICMPERR_IPHDR,
CLAT_POS_ICMPERR_FRAGHDR,
CLAT_POS_ICMPERR_TRANSPORTHDR,
CLAT_POS_PAYLOAD,
CLAT_POS_MAX
} clat_packet_index;
typedef struct iovec clat_packet[CLAT_POS_MAX];
void stop_loop();
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 update_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);
int parse_unsigned(const char *str, unsigned *out);
#endif /* __CLATD_H__ */

40
common.h Normal file
View file

@ -0,0 +1,40 @@
/*
* Copyright 2018 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.
*
* common.h - common definitions
*/
#ifndef __CLATD_COMMON_H__
#define __CLATD_COMMON_H__
#include <sys/uio.h>
// A clat_packet is an array of iovec structures representing a packet that we are translating.
// The CLAT_POS_XXX constants represent the array indices within the clat_packet that contain
// specific parts of the packet. The packet_* functions operate on all the packet segments past a
// given position.
typedef enum {
CLAT_POS_TUNHDR,
CLAT_POS_IPHDR,
CLAT_POS_FRAGHDR,
CLAT_POS_TRANSPORTHDR,
CLAT_POS_ICMPERR_IPHDR,
CLAT_POS_ICMPERR_FRAGHDR,
CLAT_POS_ICMPERR_TRANSPORTHDR,
CLAT_POS_PAYLOAD,
CLAT_POS_MAX
} clat_packet_index;
typedef struct iovec clat_packet[CLAT_POS_MAX];
#endif /* __CLATD_COMMON_H__ */

144
main.c Normal file
View file

@ -0,0 +1,144 @@
/*
* Copyright 2018 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.
*
* main.c - main function
*/
#include <errno.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/capability.h>
#include <unistd.h>
#include "resolv_netid.h"
#include "clatd.h"
#include "common.h"
#include "config.h"
#include "logging.h"
#include "setif.h"
#include "tun.h"
#define DEVICEPREFIX "v4-"
/* function: print_help
* in case the user is running this on the command line
*/
void print_help() {
printf("android-clat arguments:\n");
printf("-i [uplink interface]\n");
printf("-p [plat prefix]\n");
printf("-n [NetId]\n");
printf("-m [socket mark]\n");
}
/* function: main
* allocate and setup the tun device, then run the event loop
*/
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;
unsigned net_id = NETID_UNSET;
uint32_t mark = MARK_UNSET;
unsigned len;
while ((opt = getopt(argc, argv, "i:p:n:m:h")) != -1) {
switch (opt) {
case 'i':
uplink_interface = optarg;
break;
case 'p':
plat_prefix = optarg;
break;
case 'n':
net_id_str = optarg;
break;
case 'm':
mark_str = optarg;
break;
case 'h':
print_help();
exit(0);
default:
logmsg(ANDROID_LOG_FATAL, "Unknown option -%c. Exiting.", (char)optopt);
exit(1);
}
}
if (uplink_interface == NULL) {
logmsg(ANDROID_LOG_FATAL, "clatd called without an interface");
exit(1);
}
if (net_id_str != NULL && !parse_unsigned(net_id_str, &net_id)) {
logmsg(ANDROID_LOG_FATAL, "invalid NetID %s", net_id_str);
exit(1);
}
if (mark_str != NULL && !parse_unsigned(mark_str, &mark)) {
logmsg(ANDROID_LOG_FATAL, "invalid mark %s", mark_str);
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 netid=%s mark=%s", CLATD_VERSION,
uplink_interface, net_id_str ? net_id_str : "(none)", mark_str ? mark_str : "(none)");
// run under a regular user but keep needed capabilities
drop_root_but_keep_caps();
// open our raw sockets before dropping privs
open_sockets(&tunnel, mark);
// keeps only admin capability
set_capability(1 << CAP_NET_ADMIN);
// we can create tun devices as non-root because we're in the VPN group.
tunnel.fd4 = tun_open();
if (tunnel.fd4 < 0) {
logmsg(ANDROID_LOG_FATAL, "tun_open4 failed: %s", strerror(errno));
exit(1);
}
// When run from netd, the environment variable ANDROID_DNS_MODE is set to
// "local", but that only works for the netd process itself. Removing the
// following line causes XLAT failure in permissive mode.
unsetenv("ANDROID_DNS_MODE");
configure_interface(uplink_interface, plat_prefix, &tunnel, net_id);
update_clat_ipv6_address(&tunnel, uplink_interface);
// Loop until someone sends us a signal or brings down the tun interface.
if (signal(SIGTERM, stop_loop) == SIG_ERR) {
logmsg(ANDROID_LOG_FATAL, "sigterm handler failed: %s", strerror(errno));
exit(1);
}
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);
return 0;
}

View file

@ -19,6 +19,7 @@
#include "checksum.h"
#include "clatd.h"
#include "common.h"
#include "config.h"
#include "debug.h"
#include "icmp.h"

View file

@ -29,6 +29,7 @@
#include <netinet/udp.h>
#include "clatd.h"
#include "common.h"
#define MAX_TCP_HDR (15 * 4) // Data offset field is 4 bits and counts in 32-bit words.

2
tun.c
View file

@ -24,7 +24,7 @@
#include <sys/uio.h>
#include <unistd.h>
#include "clatd.h"
#include "common.h"
/* function: tun_open
* tries to open the tunnel device

2
tun.h
View file

@ -20,7 +20,7 @@
#include <linux/if.h>
#include "clatd.h"
#include "common.h"
#include "ring.h"
struct tun_data {