From 428a2187e4c716dec1b82edb3cef07fa1084aa9f Mon Sep 17 00:00:00 2001 From: Michael Tuexen <tuexen@fh-muenster.de> Date: Fri, 28 Jul 2017 02:46:30 +0200 Subject: [PATCH] Allow automatic tun device selection on *BSD. When using local mode on *BSD, using the tun0 device was hard coded in contrast to Linux, where the next unused tun device was used. This patch changes the behaviour on *BSD to use the next unused tun device. This also requires that the device is removed when packetdrill terminates. This was the case on Linux, but not on *BSD. On *BSD there is also a new command line option (--tun-dev) to set the device name and not select an ephemerial one. --- gtests/net/packetdrill/config.c | 14 ++++++++++ gtests/net/packetdrill/config.h | 5 ++++ gtests/net/packetdrill/netdev.c | 44 ++++++++++++++++++++++++++---- gtests/net/packetdrill/platforms.h | 13 ++++----- gtests/net/packetdrill/run.c | 15 ++++++++-- 5 files changed, 74 insertions(+), 17 deletions(-) diff --git a/gtests/net/packetdrill/config.c b/gtests/net/packetdrill/config.c index e79061c4..676b2d18 100644 --- a/gtests/net/packetdrill/config.c +++ b/gtests/net/packetdrill/config.c @@ -61,6 +61,9 @@ enum option_codes { OPT_VERBOSE = 'v', /* our only single-letter option */ OPT_DEBUG, OPT_UDP_ENCAPS, +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + OPT_TUN_DEV, +#endif }; /* Specification of command line options for getopt_long(). */ @@ -91,6 +94,9 @@ struct option options[] = { { "verbose", .has_arg = false, NULL, OPT_VERBOSE }, { "debug", .has_arg = false, NULL, OPT_DEBUG }, { "udp_encapsulation", .has_arg = true, NULL, OPT_UDP_ENCAPS }, +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + { "tun_dev", .has_arg = true, NULL, OPT_TUN_DEV }, +#endif { NULL }, }; @@ -123,6 +129,9 @@ void show_usage(void) "\t[--verbose|-v]\n" "\t[--debug] * requires compilation with DEBUG *\n" "\t[--udp_encapsulation=[sctp,tcp]]\n" +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + "\t[--tun_dev=<tun_dev_name>]\n" +#endif "\tscript_path ...\n"); } @@ -485,6 +494,11 @@ static void process_option(int opt, char *optarg, struct config *config, else die("%s: bad --udp_encapsulation: %s\n", where, optarg); break; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + case OPT_TUN_DEV: + config->tun_device = strdup(optarg); + break; +#endif default: show_usage(); exit(EXIT_FAILURE); diff --git a/gtests/net/packetdrill/config.h b/gtests/net/packetdrill/config.h index d7898261..796887dc 100644 --- a/gtests/net/packetdrill/config.h +++ b/gtests/net/packetdrill/config.h @@ -106,6 +106,11 @@ struct config { struct ip_address wire_server_ip; /* IP of on-the-wire server */ char *wire_server_ip_string; /* malloc-ed server IP string */ u16 wire_server_port; /* the port the server listens on */ + + /* For local testing using a tun interface. */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + char *tun_device; +#endif }; /* Top-level info about the invocation of a test script */ diff --git a/gtests/net/packetdrill/netdev.c b/gtests/net/packetdrill/netdev.c index a8cb5175..83f81964 100644 --- a/gtests/net/packetdrill/netdev.c +++ b/gtests/net/packetdrill/netdev.c @@ -88,9 +88,12 @@ static void cleanup_old_device(struct config *config, int result; #endif + if (config->tun_device == NULL) { + return; + } asprintf(&cleanup_command, "/sbin/ifconfig %s down delete > /dev/null 2>&1", - TUN_DEV); + config->tun_device); DEBUGP("running: '%s'\n", cleanup_command); #ifdef DEBUG result = system(cleanup_command); @@ -119,16 +122,31 @@ static void create_device(struct config *config, struct local_netdev *netdev) { /* Open the tun device, which "clones" it for our purposes. */ int tun_fd; + char *tun_path; +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + struct stat buf; +#endif - tun_fd = open(TUN_PATH, O_RDWR); +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + if (config->tun_device != NULL) { + asprintf(&tun_path, "%s/%s", TUN_DIR, config->tun_device); + } else { + asprintf(&tun_path, "%s/%s", TUN_DIR, "tun"); + } +#endif +#if defined(linux) + asprintf(&tun_path, "%s/%s", TUN_DIR, "tun"); +#endif + tun_fd = open(tun_path, O_RDWR); #if defined(__FreeBSD__) if ((tun_fd < 0) && (errno == ENOENT)) { if (system("kldload -q if_tun") < 0) { die_perror("kldload -q if_tun"); } - tun_fd = open(TUN_PATH, O_RDWR); + tun_fd = open(tun_path, O_RDWR); } #endif + free(tun_path); if (tun_fd < 0) { die_perror("open tun device"); } @@ -153,8 +171,10 @@ static void create_device(struct config *config, struct local_netdev *netdev) const int mode = IFF_BROADCAST | IFF_MULTICAST; if (ioctl(netdev->tun_fd, TUNSIFMODE, &mode, sizeof(mode)) < 0) die_perror("TUNSIFMODE"); - - netdev->name = strdup(TUN_DEV); + if (fstat(netdev->tun_fd, &buf) < 0) { + die_perror("fstat tun device"); + } + netdev->name = strdup(devname(buf.st_rdev, S_IFCHR)); #endif /* defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) */ #if defined(__FreeBSD__) || defined(__NetBSD__) @@ -328,8 +348,20 @@ static void local_netdev_free(struct netdev *a_netdev) if (netdev->psock) packet_socket_free(netdev->psock); - if (netdev->tun_fd >= 0) + if (netdev->tun_fd >= 0) { close(netdev->tun_fd); +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + if (netdev->name != NULL) { + char *cleanup_command = NULL; + + asprintf(&cleanup_command, + "/sbin/ifconfig %s destroy > /dev/null 2>&1", + netdev->name); + system(cleanup_command); + free(cleanup_command); + } +#endif + } if (netdev->ipv4_control_fd >= 0) close(netdev->ipv4_control_fd); if (netdev->ipv6_control_fd >= 0) diff --git a/gtests/net/packetdrill/platforms.h b/gtests/net/packetdrill/platforms.h index 5ad85266..cf6fc9fb 100644 --- a/gtests/net/packetdrill/platforms.h +++ b/gtests/net/packetdrill/platforms.h @@ -38,7 +38,7 @@ #include <netinet/sctp.h> #define HAVE_OPEN_MEMSTREAM 1 #define HAVE_FMEMOPEN 1 -#define TUN_PATH "/dev/net/tun" +#define TUN_DIR "/dev/net" #define HAVE_TCP_INFO 1 #endif /* linux */ @@ -54,8 +54,7 @@ #include <netinet/udplite.h> #endif #define USE_LIBPCAP 1 -#define TUN_PATH "/dev/tun0" -#define TUN_DEV "tun0" +#define TUN_DIR "/dev" #define HAVE_TCP_INFO 1 #if (__FreeBSD_version < 1000000 && __FreeBSD_version > 902000) || __FreeBSD_version > 1000028 #define HAVE_FMEMOPEN 1 @@ -63,7 +62,7 @@ #include "fmemopen.h" #endif #if (__FreeBSD_version > 902000) -#define HAVE_OPEN_MEMSTREAM 1 +#define HAVE_OPEN_MEMSTREAM 1 #else #include "open_memstream.h" #endif @@ -75,8 +74,7 @@ #if defined(__OpenBSD__) #define USE_LIBPCAP 1 -#define TUN_PATH "/dev/tun0" -#define TUN_DEV "tun0" +#define TUN_DIR "/dev" #define HAVE_TCP_INFO 0 @@ -92,8 +90,7 @@ #if defined(__NetBSD__) #define USE_LIBPCAP 1 -#define TUN_PATH "/dev/tun0" -#define TUN_DEV "tun0" +#define TUN_DIR "/dev" #define HAVE_TCP_INFO 0 diff --git a/gtests/net/packetdrill/run.c b/gtests/net/packetdrill/run.c index 54f4ebbd..f5170a97 100644 --- a/gtests/net/packetdrill/run.c +++ b/gtests/net/packetdrill/run.c @@ -513,9 +513,12 @@ static s64 schedule_start_time_usecs(void) } void signal_handler(int signal_number) { - if (state != NULL) + if (state != NULL) { close_all_sockets(state); - + if (state->netdev != NULL) { + netdev_free(state->netdev); + } + } die("Handled signal %d\n", signal_number); } @@ -524,10 +527,16 @@ void run_script(struct config *config, struct script *script) char *error = NULL; struct netdev *netdev = NULL; struct event *event = NULL; - + if (signal(SIGINT, signal_handler) == SIG_ERR) { die("could not set up signal handler for SIGINT!"); } + if (signal(SIGTERM, signal_handler) == SIG_ERR) { + die("could not set up signal handler for SIGTERM!"); + } + if (signal(SIGHUP, signal_handler) == SIG_ERR) { + die("could not set up signal handler for SIGHUP!"); + } DEBUGP("run_script: running script\n"); -- GitLab