From f6e36cf6d78ce8c5bed2e6d698928a89a9fbcc6f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 22 Mar 2015 03:10:55 +0100 Subject: First work towards multi-interface support --- src/fastd.c | 27 +++++++----- src/fastd.h | 22 ++++++---- src/peer.c | 2 + src/peer.h | 2 + src/poll.c | 6 ++- src/receive.c | 2 +- src/shell.c | 22 ++++------ src/shell.h | 1 + src/tuntap.c | 132 ++++++++++++++++++++++++++++++++-------------------------- src/types.h | 1 + 10 files changed, 121 insertions(+), 96 deletions(-) diff --git a/src/fastd.c b/src/fastd.c index 52bbf9c..228d65e 100644 --- a/src/fastd.c +++ b/src/fastd.c @@ -211,13 +211,19 @@ static inline void on_pre_up(void) { } /** Calls the on-up command */ -static inline void on_up(void) { - fastd_shell_command_exec(&conf.on_up, NULL); +static inline void on_up(fastd_iface_t *iface) { + fastd_shell_env_t *env = fastd_shell_env_alloc(); + fastd_shell_env_set_iface(env, iface); + fastd_shell_command_exec(&conf.on_up, env); + fastd_shell_env_free(env); } /** Calls the on-down command */ -static inline void on_down(void) { - fastd_shell_command_exec(&conf.on_down, NULL); +static inline void on_down(fastd_iface_t *iface) { + fastd_shell_env_t *env = fastd_shell_env_alloc(); + fastd_shell_env_set_iface(env, iface); + fastd_shell_command_exec(&conf.on_down, env); + fastd_shell_env_free(env); } /** Calls the on-post-down command */ @@ -520,7 +526,7 @@ static inline void init(int argc, char *argv[]) { on_pre_up(); - fastd_tuntap_open(); + ctx.iface = fastd_tuntap_open(NULL); /* change groups before trying to write the PID file as they can be relevant for file access */ set_groups(); @@ -541,7 +547,7 @@ static inline void init(int argc, char *argv[]) { if (conf.drop_caps == DROP_CAPS_EARLY) drop_caps(); - on_up(); + on_up(ctx.iface); if (conf.drop_caps == DROP_CAPS_ON) drop_caps(); @@ -632,17 +638,17 @@ static void delete_peers(void) { Performs cleanup of resources used by fastd Besides running the on-down scripts and closing the TUN/TAP interface, this - also frees all memory allocatedby fastd to make debugging memory leaks with + also frees all memory allocated by fastd to make debugging memory leaks with valgrind as easy as possible. */ static inline void cleanup(void) { pr_info("terminating fastd"); - on_down(); - delete_peers(); - fastd_tuntap_close(); + on_down(ctx.iface); + fastd_tuntap_close(ctx.iface); + fastd_status_close(); close_sockets(); fastd_poll_free(); @@ -658,7 +664,6 @@ static inline void cleanup(void) { VECTOR_FREE(ctx.eth_addrs); free(ctx.protocol_state); - free(ctx.ifname); #ifdef ENABLE_OPENSSL CONF_modules_free(); diff --git a/src/fastd.h b/src/fastd.h index ba6acfb..5e81890 100644 --- a/src/fastd.h +++ b/src/fastd.h @@ -154,6 +154,13 @@ struct fastd_socket { fastd_peer_t *peer; /**< If the socket belongs to a single peer (as it was create dynamically when sending a handshake), contains that peer */ }; +/** A TUN/TAP interface */ +struct fastd_iface { + fastd_poll_fd_t fd; /**< The file descriptor of the tunnel interface */ + char *name; /**< The interface name */ + fastd_peer_t *peer; /**< The peer associated with the interface (if any) */ +}; + /** Type of a traffic stat counter */ typedef enum fastd_stat_type { @@ -261,16 +268,17 @@ struct fastd_config { bool verify_config; /**< Does basic verification of the configuration and exits */ }; + /** The dynamic state of \em fastd */ struct fastd_context { bool log_initialized; /**< true if the logging facilities have been properly initialized */ - char *ifname; /**< The actual interface name */ - int64_t started; /**< The timestamp when fastd was started */ int64_t now; /**< The current monotonous timestamp in microseconds after an arbitrary point in time */ + fastd_iface_t *iface; /**< The default tunnel interface */ + uint64_t next_peer_id; /**< An monotonously increasing ID peers are identified with in some components */ VECTOR(fastd_peer_t *) peers; /**< The currectly active peers */ @@ -305,8 +313,6 @@ struct fastd_context { pthread_attr_t detached_thread; /**< pthread_attr_t for creating detached threads */ - fastd_poll_fd_t tunfd; /**< The file descriptor of the tunnel interface */ - #ifdef __ANDROID__ int android_ctrl_sock_fd; /**< The unix domain socket for communicating with Android GUI */ #endif @@ -362,10 +368,10 @@ bool fastd_android_protect_socket(int fd); void fastd_resolve_peer(fastd_peer_t *peer, fastd_remote_t *remote); -void fastd_tuntap_open(void); -void fastd_tuntap_handle(void); -void fastd_tuntap_write(fastd_buffer_t buffer); -void fastd_tuntap_close(void); +fastd_iface_t * fastd_tuntap_open(fastd_peer_t *peer); +void fastd_tuntap_handle(fastd_iface_t *iface); +void fastd_tuntap_write(fastd_iface_t *iface, fastd_buffer_t buffer); +void fastd_tuntap_close(fastd_iface_t *iface); void fastd_cap_init(void); void fastd_cap_drop(void); diff --git a/src/peer.c b/src/peer.c index 5ac517c..417e213 100644 --- a/src/peer.c +++ b/src/peer.c @@ -44,6 +44,8 @@ void fastd_peer_set_shell_env(fastd_shell_env_t *env, const fastd_peer_t *peer, fastd_shell_env_set(env, "PEER_NAME", peer ? peer->name : NULL); + fastd_shell_env_set_iface(env, peer->iface ?: ctx.iface); + switch(local_addr ? local_addr->sa.sa_family : AF_UNSPEC) { case AF_INET: inet_ntop(AF_INET, &local_addr->in.sin_addr, buf, sizeof(buf)); diff --git a/src/peer.h b/src/peer.h index 348b256..631957e 100644 --- a/src/peer.h +++ b/src/peer.h @@ -72,6 +72,8 @@ struct fastd_peer { fastd_protocol_key_t *key; /**< The peer's public key */ fastd_protocol_peer_state_t *protocol_state; /**< Protocol-specific peer state */ + fastd_iface_t *iface; /**< The interface this peer is associated with */ + /* Starting here, more dynamic fields follow: */ /** The socket used by the peer. This can either be a common bound socket or a diff --git a/src/poll.c b/src/poll.c index 6c83f97..dbb3c18 100644 --- a/src/poll.c +++ b/src/poll.c @@ -82,8 +82,12 @@ static inline void handle_fd(fastd_poll_fd_t *fd, bool input, bool error) { #endif case POLL_TYPE_IFACE: + { + fastd_iface_t *iface = container_of(fd, fastd_iface_t, fd); + if (input) - fastd_tuntap_handle(); + fastd_tuntap_handle(iface); + } break; case POLL_TYPE_SOCKET: diff --git a/src/receive.c b/src/receive.c index 8bb926c..a19039e 100644 --- a/src/receive.c +++ b/src/receive.c @@ -306,7 +306,7 @@ void fastd_handle_receive(fastd_peer_t *peer, fastd_buffer_t buffer, bool reorde if (reordered) fastd_stats_add(peer, STAT_RX_REORDERED, buffer.len); - fastd_tuntap_write(buffer); + fastd_tuntap_write(peer->iface ?: ctx.iface, buffer); if (conf.mode == MODE_TAP && conf.forward) { fastd_send_data(buffer, peer); diff --git a/src/shell.c b/src/shell.c index 90102a2..3a617be 100644 --- a/src/shell.c +++ b/src/shell.c @@ -75,6 +75,13 @@ void fastd_shell_env_free(fastd_shell_env_t *env) { free(env); } +void fastd_shell_env_set_iface(fastd_shell_env_t *env, const fastd_iface_t *iface) { + if (iface) + fastd_shell_env_set(env, "INTERFACE", iface->name); + else + fastd_shell_env_set(env, "INTERFACE", NULL); +} + /** Applies a shell environment to the current process */ static void shell_command_setenv(pid_t pid, const fastd_shell_env_t *env) { char buf[20]; @@ -84,21 +91,6 @@ static void shell_command_setenv(pid_t pid, const fastd_shell_env_t *env) { snprintf(buf, sizeof(buf), "%u", (unsigned)pid); setenv("FASTD_PID", buf, 1); - if (ctx.ifname) { - setenv("INTERFACE", ctx.ifname, 1); - } - else if (conf.ifname) { - char ifname[IF_NAMESIZE]; - - strncpy(ifname, conf.ifname, sizeof(ifname)-1); - ifname[sizeof(ifname)-1] = 0; - - setenv("INTERFACE", ifname, 1); - } - else { - unsetenv("INTERFACE"); - } - snprintf(buf, sizeof(buf), "%u", conf.mtu); setenv("INTERFACE_MTU", buf, 1); diff --git a/src/shell.h b/src/shell.h index d39bcef..57b09e6 100644 --- a/src/shell.h +++ b/src/shell.h @@ -71,6 +71,7 @@ static inline bool fastd_shell_command_isset(const fastd_shell_command_t *comman fastd_shell_env_t * fastd_shell_env_alloc(void); void fastd_shell_env_set(fastd_shell_env_t *env, const char *key, const char *value); +void fastd_shell_env_set_iface(fastd_shell_env_t *env, const fastd_iface_t *iface); void fastd_shell_env_free(fastd_shell_env_t *env); bool fastd_shell_command_exec_sync(const fastd_shell_command_t *command, const fastd_shell_env_t *env, int *ret); diff --git a/src/tuntap.c b/src/tuntap.c index 591f8d4..a303d20 100644 --- a/src/tuntap.c +++ b/src/tuntap.c @@ -66,13 +66,13 @@ static const bool multiaf_tun = true; #ifdef __linux__ /** Opens the TUN/TAP device helper shared by Android and Linux targets */ -static void tuntap_open_linux(const char * dev_name) { +static void tuntap_open_linux(fastd_iface_t *iface, const char *dev_name) { pr_debug("initializing tun/tap device..."); struct ifreq ifr = {}; - ctx.tunfd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(dev_name, O_RDWR|O_NONBLOCK)); - if (ctx.tunfd.fd < 0) + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(dev_name, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) exit_errno("could not open tun/tap device file"); if (conf.ifname) @@ -92,10 +92,10 @@ static void tuntap_open_linux(const char * dev_name) { } ifr.ifr_flags |= IFF_NO_PI; - if (ioctl(ctx.tunfd.fd, TUNSETIFF, &ifr) < 0) + if (ioctl(iface->fd.fd, TUNSETIFF, &ifr) < 0) exit_errno("TUNSETIFF ioctl failed"); - ctx.ifname = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); + iface->name = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ctl_sock < 0) @@ -113,7 +113,7 @@ static void tuntap_open_linux(const char * dev_name) { if (close(ctl_sock)) pr_error_errno("close"); - fastd_poll_fd_register(&ctx.tunfd); + fastd_poll_fd_register(&iface->fd); pr_debug("tun/tap device initialized."); } @@ -123,7 +123,7 @@ static void tuntap_open_linux(const char * dev_name) { #if defined(__ANDROID__) /** Opens the TUN/TAP device */ -void fastd_tuntap_open(void) { +static void tuntap_open(fastd_iface_t *iface) { pr_debug("initializing tun device..."); if (conf.android_integration) { @@ -132,38 +132,38 @@ void fastd_tuntap_open(void) { } pr_debug("using android TUN fd"); - ctx.tunfd = FASTD_POLL_FD(POLL_TYPE_IFACE, fastd_android_receive_tunfd()); + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, fastd_android_receive_tunfd()); fastd_android_send_pid(); - fastd_poll_fd_register(&ctx.tunfd); + fastd_poll_fd_register(&iface->fd); pr_debug("tun device initialized."); } else { /* this requires root on Android */ - tuntap_open_linux("/dev/tun"); + tuntap_open_linux(iface, "/dev/tun"); } } #elif defined(__linux__) /** Opens the TUN/TAP device */ -void fastd_tuntap_open(void) { - tuntap_open_linux("/dev/net/tun"); +static void tuntap_open(fastd_iface_t *iface) { + tuntap_open_linux(iface, "/dev/net/tun"); } #elif defined(__FreeBSD__) || defined(__OpenBSD__) /** Sets the MTU of the TUN/TAP device */ -static void set_tun_mtu(void) { +static void set_tun_mtu(fastd_iface_t *iface) { struct tuninfo tuninfo; - if (ioctl(ctx.tunfd.fd, TUNGIFINFO, &tuninfo) < 0) + if (ioctl(iface->fd.fd, TUNGIFINFO, &tuninfo) < 0) exit_errno("TUNGIFINFO ioctl failed"); tuninfo.mtu = conf.mtu; - if (ioctl(ctx.tunfd.fd, TUNSIFINFO, &tuninfo) < 0) + if (ioctl(iface->fd.fd, TUNSIFINFO, &tuninfo) < 0) exit_errno("TUNSIFINFO ioctl failed"); } @@ -171,42 +171,42 @@ static void set_tun_mtu(void) { #ifdef __FreeBSD__ /** Sets the MTU of the TAP device */ -static void set_tap_mtu(void) { +static void set_tap_mtu(fastd_iface_t *iface) { struct tapinfo tapinfo; - if (ioctl(ctx.tunfd.fd, TAPGIFINFO, &tapinfo) < 0) + if (ioctl(iface->fd.fd, TAPGIFINFO, &tapinfo) < 0) exit_errno("TAPGIFINFO ioctl failed"); tapinfo.mtu = conf.mtu; - if (ioctl(ctx.tunfd.fd, TAPSIFINFO, &tapinfo) < 0) + if (ioctl(iface->fd.fd, TAPSIFINFO, &tapinfo) < 0) exit_errno("TAPSIFINFO ioctl failed"); } /** Sets up the TUN device */ -static void setup_tun(void) { +static void setup_tun(fastd_iface_t *iface) { int one = 1; - if (ioctl(ctx.tunfd.fd, TUNSIFHEAD, &one) < 0) + if (ioctl(iface->fd.fd, TUNSIFHEAD, &one) < 0) exit_errno("TUNSIFHEAD ioctl failed"); - set_tun_mtu(); + set_tun_mtu(iface); } /** Sets up the TAP device */ -static void setup_tap(void) { +static void setup_tap(fastd_iface_t *iface) { struct ifreq ifr = {}; - if (ioctl(ctx.tunfd.fd, TAPGIFNAME, &ifr) < 0) + if (ioctl(iface->fd.fd, TAPGIFNAME, &ifr) < 0) exit_errno("TAPGIFNAME ioctl failed"); - free(ctx.ifname); - ctx.ifname = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); + free(iface->name); + iface->name = fastd_strndup(ifr.ifr_name, IFNAMSIZ-1); - set_tap_mtu(); + set_tap_mtu(iface); } /** Opens the TUN/TAP device */ -void fastd_tuntap_open(void) { +static void tuntap_open(fastd_iface_t *iface) { pr_debug("initializing tun/tap device..."); char ifname[5+IFNAMSIZ] = "/dev/"; @@ -235,41 +235,41 @@ void fastd_tuntap_open(void) { strncat(ifname, type, IFNAMSIZ-1); } - ctx.tunfd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); - if (ctx.tunfd.fd < 0) + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) exit_errno("could not open tun/tap device file"); - if (!(ctx.ifname = fdevname_r(ctx.tunfd.fd, fastd_alloc(IFNAMSIZ), IFNAMSIZ))) + if (!(iface->name = fdevname_r(iface->fd.fd, fastd_alloc(IFNAMSIZ), IFNAMSIZ))) exit_errno("could not get tun/tap interface name"); switch (conf.mode) { case MODE_TAP: - setup_tap(); + setup_tap(iface); break; case MODE_TUN: - setup_tun(); + setup_tun(iface); break; default: exit_bug("invalid mode"); } - fastd_poll_fd_register(&ctx.tunfd); + fastd_poll_fd_register(&iface->fd); pr_debug("tun/tap device initialized."); } #else /* __OpenBSD__ */ -static void set_link0(bool set) { +static void set_link0(fastd_iface_t *iface, bool set) { struct ifreq ifr = {}; int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ctl_sock < 0) exit_errno("socket"); - strncpy(ifr.ifr_name, ctx.ifname, IFNAMSIZ-1); + strncpy(ifr.ifr_name, iface->name, IFNAMSIZ-1); if (ioctl(ctl_sock, SIOCGIFFLAGS, &ifr) < 0) exit_errno("SIOCGIFFLAGS ioctl failed"); @@ -286,19 +286,19 @@ static void set_link0(bool set) { } /** Sets up the TUN device */ -static void setup_tun(void) { - set_link0(false); - set_tun_mtu(); +static void setup_tun(fastd_iface_t *iface) { + set_link0(iface, false); + set_tun_mtu(iface); } /** Sets up the TAP device */ -static void setup_tap(void) { - set_link0(true); - set_tun_mtu(); +static void setup_tap(fastd_iface_t *iface) { + set_link0(iface, true); + set_tun_mtu(iface); } /** Opens the TUN/TAP device */ -void fastd_tuntap_open(void) { +static void tuntap_open(fastd_iface_t *iface) { char ifname[5+IFNAMSIZ] = "/dev/"; if (!conf.ifname) exit_error("config error: no interface name given."); @@ -309,26 +309,26 @@ void fastd_tuntap_open(void) { pr_debug("initializing tun device..."); - ctx.tunfd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); - if (ctx.tunfd.fd < 0) + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) exit_errno("could not open tun device file"); - ctx.ifname = fastd_strndup(conf.ifname, IFNAMSIZ-1); + iface->name = fastd_strndup(conf.ifname, IFNAMSIZ-1); switch (conf.mode) { case MODE_TAP: - setup_tap(); + setup_tap(iface); break; case MODE_TUN: - setup_tun(); + setup_tun(iface); break; default: exit_bug("invalid mode"); } - fastd_poll_fd_register(&ctx.tunfd); + fastd_poll_fd_register(&iface->fd); pr_debug("tun device initialized."); } @@ -338,7 +338,7 @@ void fastd_tuntap_open(void) { #elif __APPLE__ /** Opens the TUN/TAP device */ -void fastd_tuntap_open(void) { +static void tuntap_open(fastd_iface_t *iface) { const char *devtype; switch (conf.mode) { case MODE_TAP: @@ -363,11 +363,11 @@ void fastd_tuntap_open(void) { pr_debug("initializing tun device..."); - ctx.tunfd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); - if (ctx.tunfd.fd < 0) + iface->fd = FASTD_POLL_FD(POLL_TYPE_IFACE, open(ifname, O_RDWR|O_NONBLOCK)); + if (iface->fd.fd < 0) exit_errno("could not open tun device file"); - ctx.ifname = fastd_strndup(conf.ifname, IFNAMSIZ-1); + iface->name = fastd_strndup(conf.ifname, IFNAMSIZ-1); int ctl_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (ctl_sock < 0) @@ -382,7 +382,7 @@ void fastd_tuntap_open(void) { if (close(ctl_sock)) pr_error_errno("close"); - fastd_poll_fd_register(&ctx.tunfd); + fastd_poll_fd_register(&iface->fd); pr_debug("tun device initialized."); } @@ -395,7 +395,7 @@ void fastd_tuntap_open(void) { /** Reads a packet from the TUN/TAP device */ -void fastd_tuntap_handle(void) { +void fastd_tuntap_handle(fastd_iface_t *iface) { size_t max_len = fastd_max_payload(); fastd_buffer_t buffer; @@ -404,7 +404,7 @@ void fastd_tuntap_handle(void) { else buffer = fastd_buffer_alloc(max_len, conf.min_encrypt_head_space, conf.min_encrypt_tail_space); - ssize_t len = read(ctx.tunfd.fd, buffer.data, max_len); + ssize_t len = read(iface->fd.fd, buffer.data, max_len); if (len < 0) exit_errno("read"); @@ -413,11 +413,11 @@ void fastd_tuntap_handle(void) { if (multiaf_tun && conf.mode == MODE_TUN) fastd_buffer_push_head(&buffer, 4); - fastd_send_data(buffer, NULL); + fastd_send_data(buffer, iface->peer); } /** Writes a packet to the TUN/TAP device */ -void fastd_tuntap_write(fastd_buffer_t buffer) { +void fastd_tuntap_write(fastd_iface_t *iface, fastd_buffer_t buffer) { if (multiaf_tun && conf.mode == MODE_TUN) { uint8_t version = *((uint8_t *)buffer.data) >> 4; uint32_t af; @@ -440,12 +440,24 @@ void fastd_tuntap_write(fastd_buffer_t buffer) { memcpy(buffer.data, &af, 4); } - if (write(ctx.tunfd.fd, buffer.data, buffer.len) < 0) + if (write(iface->fd.fd, buffer.data, buffer.len) < 0) pr_debug2_errno("write"); } +fastd_iface_t * fastd_tuntap_open(fastd_peer_t *peer) { + fastd_iface_t *iface = fastd_new(fastd_iface_t); + iface->peer = peer; + + tuntap_open(iface); + + return iface; +} + /** Closes the TUN/TAP device */ -void fastd_tuntap_close(void) { - if (!fastd_poll_fd_close(&ctx.tunfd)) +void fastd_tuntap_close(fastd_iface_t *iface) { + if (!fastd_poll_fd_close(&iface->fd)) pr_warn_errno("closing tun/tap: close"); + + free(iface->name); + free(iface); } diff --git a/src/types.h b/src/types.h index 2a854c2..dbb4d3c 100644 --- a/src/types.h +++ b/src/types.h @@ -94,6 +94,7 @@ typedef struct fastd_poll_fd fastd_poll_fd_t; typedef union fastd_peer_address fastd_peer_address_t; typedef struct fastd_bind_address fastd_bind_address_t; +typedef struct fastd_iface fastd_iface_t; typedef struct fastd_socket fastd_socket_t; typedef struct fastd_peer_group fastd_peer_group_t; typedef struct fastd_eth_addr fastd_eth_addr_t; -- cgit v1.2.3