diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | iface.c | 94 | ||||
-rw-r--r-- | iface.h | 8 | ||||
-rw-r--r-- | llmnr.c | 89 | ||||
-rw-r--r-- | llmnr.h | 8 | ||||
-rw-r--r-- | llmnrd.c | 93 |
6 files changed, 116 insertions, 178 deletions
@@ -7,7 +7,7 @@ VERSION = 0.2.1 # llmnrd binary D_P = llmnrd D_OBJS = llmnr.o iface.o socket.o util.o llmnrd.o -D_LIBS = -lpthread +D_LIBS = # llmnr-query binary Q_P = llmnr-query @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2015-2017 Tobias Klauser <tklauser@distanz.ch> * * This file is part of llmnrd. * @@ -19,7 +19,6 @@ #include <assert.h> #include <errno.h> #include <netdb.h> -#include <pthread.h> #include <stdint.h> #include <string.h> #include <unistd.h> @@ -40,10 +39,7 @@ #include "iface.h" -static bool iface_running = true; -static bool iface_ipv6 = false; static unsigned int iface_ifindex = 0; -static pthread_t iface_thread; static iface_event_handler_t iface_event_handler; struct iface_record { @@ -54,7 +50,6 @@ struct iface_record { }; static struct list_head iface_list_head; -static pthread_mutex_t iface_list_mutex; size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, struct sockaddr_storage *addrs, size_t addrs_size) @@ -65,8 +60,6 @@ size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, if (!addrs) return 0; - pthread_mutex_lock(&iface_list_mutex); - list_for_each_entry(rec, &iface_list_head, list) { if (rec->index == ifindex) { size_t i; @@ -81,8 +74,6 @@ size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, } } - pthread_mutex_unlock(&iface_list_mutex); - return n; } @@ -182,8 +173,6 @@ static void iface_addr_add(unsigned int index, unsigned char family, const void fill_sockaddr_storage(&sst, family, addr); - pthread_mutex_lock(&iface_list_mutex); - list_for_each_entry(rec, &iface_list_head, list) if (rec->index == index) goto add; @@ -195,7 +184,6 @@ static void iface_addr_add(unsigned int index, unsigned char family, const void list_add_tail(&rec->list, &iface_list_head); add: iface_record_addr_add(rec, &sst); - pthread_mutex_unlock(&iface_list_mutex); } static void iface_addr_del(unsigned int index, unsigned char family, const void *addr) @@ -205,16 +193,12 @@ static void iface_addr_del(unsigned int index, unsigned char family, const void fill_sockaddr_storage(&sst, family, addr); - pthread_mutex_lock(&iface_list_mutex); - list_for_each_entry(rec, &iface_list_head, list) { if (rec->index == index) { iface_record_addr_del(rec, &sst); break; } } - - pthread_mutex_unlock(&iface_list_mutex); } static void iface_nlmsg_change_link(const struct nlmsghdr *nlh __unused) @@ -342,75 +326,33 @@ static int iface_rtnl_enumerate(int sock, uint16_t type, unsigned char family) return iface_nlmsg_process((const struct nlmsghdr *)pktbuf, recvlen); } -void iface_register_event_handler(iface_event_handler_t event_handler) +void iface_init(int sock, const char *iface, bool ipv6, + iface_event_handler_t event_handler) { - iface_event_handler = event_handler; -} - -int iface_run(void) -{ - int ret = -1; - int sock; - INIT_LIST_HEAD(&iface_list_head); - if (pthread_mutex_init(&iface_list_mutex, NULL) != 0) { - log_err("Failed to initialize interface list mutex\n"); - return -1; - } - - sock = socket_open_rtnl(iface_ipv6); - if (sock < 0) - return -1; + iface_event_handler = event_handler; + if (iface) + iface_ifindex = if_nametoindex(iface); /* send RTM_GETADDR request to initially populate the interface list */ if (iface_rtnl_enumerate(sock, RTM_GETADDR, AF_INET) < 0) - goto out; - if (iface_ipv6) { + log_err("Failed to enumerate rtnl interfaces: %s\n", strerror(errno)); + if (ipv6) if (iface_rtnl_enumerate(sock, RTM_GETADDR, AF_INET6) < 0) - goto out; - } - - while (iface_running) { - ssize_t recvlen; - uint8_t pktbuf[8192]; - - if ((recvlen = recv(sock, pktbuf, sizeof(pktbuf), 0)) < 0) { - if (errno != EINTR) - log_err("Failed to receive netlink message: %s\n", strerror(errno)); - goto out; - } - - if (iface_nlmsg_process((const struct nlmsghdr *)pktbuf, recvlen) < 0) - log_warn("Error processing netlink message\n"); - } - - pthread_mutex_destroy(&iface_list_mutex); - ret = 0; -out: - close(sock); - return ret; -} - -static void* iface_run_wrapper(void *data __unused) -{ - return ERR_PTR(iface_run()); + log_err("Failed to enumerate rtnl interfaces: %s\n", strerror(errno)); } -int iface_start_thread(bool ipv6, const char *iface) +void iface_recv(int sock) { - iface_ipv6 = ipv6; - if (iface) - iface_ifindex = if_nametoindex(iface); + ssize_t recvlen; + uint8_t pktbuf[8192]; - if (pthread_create(&iface_thread, NULL, iface_run_wrapper, NULL) < 0) { - log_err("Failed to start interface monitoring thread\n"); - return -1; + if ((recvlen = recv(sock, pktbuf, sizeof(pktbuf), 0)) < 0) { + if (errno != EINTR) + log_err("Failed to receive netlink message: %s\n", strerror(errno)); + return; } - return 0; -} - -void iface_stop(void) -{ - iface_running = false; + if (iface_nlmsg_process((const struct nlmsghdr *)pktbuf, recvlen) < 0) + log_warn("Error processing netlink message\n"); } @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2015-2017 Tobias Klauser <tklauser@distanz.ch> * * This file is part of llmnrd. * @@ -30,9 +30,9 @@ enum iface_event_type { typedef void (*iface_event_handler_t)(enum iface_event_type, unsigned char af, unsigned int ifindex); -void iface_register_event_handler(iface_event_handler_t event_handler); -int iface_start_thread(bool ipv6, const char *iface); -void iface_stop(void); +void iface_init(int sock, const char *iface, bool ipv6, + iface_event_handler_t event_handler); +void iface_recv(int sock); size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, struct sockaddr_storage *addrs, size_t addrs_size); @@ -37,52 +37,17 @@ #include "llmnr-packet.h" #include "llmnr.h" -static int llmnr_sock_ipv4 = -1; -static int llmnr_sock_ipv6 = -1; -static bool llmnr_running = true; -/* - * Host name in DNS name format (length octet + name + 0 byte) - */ +static bool llmnr_ipv6 = false; +/* Host name in DNS name format (length octet + name + 0 byte) */ static char llmnr_hostname[LLMNR_LABEL_MAX_SIZE + 2]; -static void llmnr_iface_event_handle(enum iface_event_type type, unsigned char af, - unsigned int ifindex) -{ - switch (af) { - case AF_INET: - socket_mcast_group_ipv4(llmnr_sock_ipv4, ifindex, type == IFACE_ADD); - break; - case AF_INET6: - socket_mcast_group_ipv6(llmnr_sock_ipv6, ifindex, type == IFACE_ADD); - break; - default: - /* ignore */ - break; - } -} - -int llmnr_init(const char *hostname, uint16_t port, bool ipv6, const char *iface) +void llmnr_init(const char *hostname, bool ipv6) { llmnr_hostname[0] = strlen(hostname); strncpy(&llmnr_hostname[1], hostname, LLMNR_LABEL_MAX_SIZE); llmnr_hostname[LLMNR_LABEL_MAX_SIZE + 1] = '\0'; - log_info("Starting llmnrd on port %u, hostname %s\n", port, hostname); - if (iface) - log_info("Binding to interface %s\n", iface); - - llmnr_sock_ipv4 = socket_open_ipv4(port, iface); - if (llmnr_sock_ipv4 < 0) - return -1; - - if (ipv6) { - llmnr_sock_ipv6 = socket_open_ipv6(port, iface); - if (llmnr_sock_ipv6 < 0) - return -1; - } - - iface_register_event_handler(&llmnr_iface_event_handle); - return 0; + llmnr_ipv6 = ipv6; } static bool llmnr_name_matches(const uint8_t *query) @@ -134,7 +99,7 @@ static void llmnr_respond(unsigned int ifindex, const struct llmnr_hdr *hdr, return; /* No AAAA responses if IPv6 is disabled */ - if (llmnr_sock_ipv6 < 0 && qtype == LLMNR_QTYPE_AAAA) + if (llmnr_ipv6 < 0 && qtype == LLMNR_QTYPE_AAAA) return; switch (qtype) { @@ -254,7 +219,7 @@ static void llmnr_packet_process(unsigned int ifindex, const uint8_t *pktbuf, si llmnr_respond(ifindex, hdr, query, query_len, sock, sst); } -static void llmnr_recv(int sock) +void llmnr_recv(int sock) { uint8_t pktbuf[2048], aux[128]; struct msghdr msg; @@ -297,45 +262,3 @@ static void llmnr_recv(int sock) else log_warn("Could not get interface of incoming packet\n"); } - -int llmnr_run(void) -{ - int ret = -1; - - while (llmnr_running) { - fd_set rfds; - int nfds, ret; - - FD_ZERO(&rfds); - FD_SET(llmnr_sock_ipv4, &rfds); - if (llmnr_sock_ipv6 >= 0) { - FD_SET(llmnr_sock_ipv6, &rfds); - nfds = max(llmnr_sock_ipv4, llmnr_sock_ipv6) + 1; - } else - nfds = llmnr_sock_ipv4 + 1; - - ret = select(nfds, &rfds, NULL, NULL, NULL); - if (ret < 0) { - if (errno != EINTR) - log_err("Failed to select() on socket: %s\n", strerror(errno)); - goto out; - } else if (ret) { - if (FD_ISSET(llmnr_sock_ipv4, &rfds)) - llmnr_recv(llmnr_sock_ipv4); - if (llmnr_sock_ipv6 >= 0 && FD_ISSET(llmnr_sock_ipv6, &rfds)) - llmnr_recv(llmnr_sock_ipv6); - } - } - - ret = 0; -out: - close(llmnr_sock_ipv4); - if (llmnr_sock_ipv6 >= 0) - close(llmnr_sock_ipv6); - return ret; -} - -void llmnr_stop(void) -{ - llmnr_running = false; -} @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2016 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2015-2017 Tobias Klauser <tklauser@distanz.ch> * * This file is part of llmnrd. * @@ -20,10 +20,8 @@ #define LLMNR_H #include <stdbool.h> -#include <stdint.h> -int llmnr_init(const char *hostname, uint16_t port, bool ipv6, const char *iface); -int llmnr_run(void); -void llmnr_stop(void); +void llmnr_init(const char *hostname, bool ipv6); +void llmnr_recv(int sock); #endif /* LLMNR_H */ @@ -1,7 +1,7 @@ /* * llmnrd -- LLMNR (RFC 4705) responder daemon. * - * Copyright (C) 2014-2016 Tobias Klauser <tklauser@distanz.ch> + * Copyright (C) 2014-2017 Tobias Klauser <tklauser@distanz.ch> * * This file is part of llmnrd. * @@ -38,6 +38,11 @@ #include "iface.h" #include "llmnr.h" #include "llmnr-packet.h" +#include "socket.h" + +static bool llmnrd_running = true; +static int llmnrd_sock_ipv4 = -1; +static int llmnrd_sock_ipv6 = -1; static const char *short_opts = "H:i:p:6dhV"; static const struct option long_opts[] = { @@ -82,8 +87,7 @@ static void signal_handler(int sig) case SIGQUIT: case SIGTERM: log_info("Interrupt received. Stopping llmnrd.\n"); - iface_stop(); - llmnr_stop(); + llmnrd_running = false; break; case SIGHUP: default: @@ -109,14 +113,32 @@ static void register_signal(int sig, void (*handler)(int)) } } +static void iface_event_handle(enum iface_event_type type, unsigned char af, + unsigned int ifindex) +{ + switch (af) { + case AF_INET: + socket_mcast_group_ipv4(llmnrd_sock_ipv4, ifindex, type == IFACE_ADD); + break; + case AF_INET6: + socket_mcast_group_ipv6(llmnrd_sock_ipv6, ifindex, type == IFACE_ADD); + break; + default: + /* ignore */ + break; + } +} + int main(int argc, char **argv) { - int c, ret = EXIT_FAILURE; + int c, ret = -1; long num_arg; bool daemonize = false, ipv6 = false; char *hostname = NULL; char *iface = NULL; uint16_t port = LLMNR_UDP_PORT; + int llmnrd_sock_rtnl = -1; + int nfds; while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { switch (c) { @@ -166,18 +188,71 @@ int main(int argc, char **argv) if (daemonize) { if (daemon(0, 0) != 0) { log_err("Failed to daemonize process: %s\n", strerror(errno)); - return EXIT_FAILURE; + goto out; } } - if (llmnr_init(hostname, port, ipv6, iface) < 0) + log_info("Starting llmnrd on port %u, hostname %s\n", port, hostname); + if (iface) + log_info("Binding to interface %s\n", iface); + + llmnrd_sock_ipv4 = socket_open_ipv4(port, iface); + if (llmnrd_sock_ipv4 < 0) goto out; - if (iface_start_thread(ipv6, iface) < 0) + if (ipv6) { + llmnrd_sock_ipv6 = socket_open_ipv6(port, iface); + if (llmnrd_sock_ipv6 < 0) + goto out; + } + + llmnrd_sock_rtnl = socket_open_rtnl(ipv6); + if (llmnrd_sock_rtnl < 0) goto out; - ret = llmnr_run(); + llmnr_init(hostname, ipv6); + iface_init(llmnrd_sock_rtnl, iface, ipv6, &iface_event_handle); + + nfds = max(llmnrd_sock_ipv4, llmnrd_sock_rtnl); + if (llmnrd_sock_ipv6 >= 0) + nfds = max(nfds, llmnrd_sock_ipv6); + nfds += 1; + + while (llmnrd_running) { + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(llmnrd_sock_ipv4, &rfds); + FD_SET(llmnrd_sock_rtnl, &rfds); + if (llmnrd_sock_ipv6 >= 0) + FD_SET(llmnrd_sock_ipv6, &rfds); + + ret = select(nfds, &rfds, NULL, NULL, NULL); + if (ret < 0) { + if (errno != EINTR) + log_err("Failed to select() on socket: %s\n", strerror(errno)); + goto out; + } else if (ret) { + /* handle RTNL messages first so we can respond with + * up-to-date information. + */ + if (FD_ISSET(llmnrd_sock_rtnl, &rfds)) + iface_recv(llmnrd_sock_rtnl); + if (FD_ISSET(llmnrd_sock_ipv4, &rfds)) + llmnr_recv(llmnrd_sock_ipv4); + if (llmnrd_sock_ipv6 >= 0 && FD_ISSET(llmnrd_sock_ipv6, &rfds)) + llmnr_recv(llmnrd_sock_ipv6); + } + } + + ret = 0; out: + if (llmnrd_sock_rtnl >= 0) + close(llmnrd_sock_rtnl); + if (llmnrd_sock_ipv6 >= 0) + close(llmnrd_sock_ipv6); + if (llmnrd_sock_ipv4 >= 0) + close(llmnrd_sock_ipv4); free(hostname); - return ret; + return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } |