From 069060cad6d9a21d9ec287a7ae9a22deb87f4abc Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 18 Feb 2015 16:49:51 +0100 Subject: llmnrd: Join IP multicast group on each new interface Signed-off-by: Tobias Klauser --- iface.c | 18 ++++++++++++++---- iface.h | 12 ++++++++++-- llmnr.c | 55 ++++++++++++++++++++++++++++++++++++++----------------- llmnr.h | 3 ++- llmnrd.c | 9 ++++++--- 5 files changed, 70 insertions(+), 27 deletions(-) diff --git a/iface.c b/iface.c index 510a0c4..5d0117e 100644 --- a/iface.c +++ b/iface.c @@ -41,6 +41,7 @@ static bool iface_running = true; static pthread_t iface_thread; +static iface_event_handler_t iface_event_handler; struct iface_record { struct list_head list; @@ -198,7 +199,7 @@ static void iface_nlmsg_change_addr(const struct nlmsghdr *nlh) rta = (const struct rtattr *)((const uint8_t *)nlh + NLMSG_SPACE(sizeof(*ifa))); for ( ; RTA_OK(rta, rtalen); rta = RTA_NEXT(rta, rtalen)) { char ifname[IF_NAMESIZE]; - const char *action; + enum iface_event_type type; switch (rta->rta_type) { case IFA_ADDRESS: @@ -207,17 +208,21 @@ static void iface_nlmsg_change_addr(const struct nlmsghdr *nlh) if (nlh->nlmsg_type == RTM_NEWADDR) { iface_addr_add(index, ifa->ifa_family, RTA_DATA(rta)); - action = "Added"; + type = IFACE_ADD; } else if (nlh->nlmsg_type == RTM_DELADDR) { iface_addr_del(index, ifa->ifa_family, RTA_DATA(rta)); - action = "Deleted"; + type = IFACE_DEL; } else { /* This case shouldn't occur */ continue; } + if (iface_event_handler) + (*iface_event_handler)(type, ifa->ifa_family, ifa->ifa_index); + log_info("%s IPv%c address %s on interface %s\n", - action, ifa->ifa_family == AF_INET ? '4' : '6', addr, + type == IFACE_ADD ? "Added" : "Deleted", + ifa->ifa_family == AF_INET ? '4' : '6', addr, if_indextoname(ifa->ifa_index, ifname)); } } @@ -290,6 +295,11 @@ static int iface_rtnl_enumerate(int sock, int type, int family) return iface_nlmsg_process((const struct nlmsghdr *)pktbuf, recvlen); } +void iface_register_event_handler(iface_event_handler_t event_handler) +{ + iface_event_handler = event_handler; +} + int iface_run(void) { int ret = -1; diff --git a/iface.h b/iface.h index 952b58e..cdcf716 100644 --- a/iface.h +++ b/iface.h @@ -21,10 +21,18 @@ #include -size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, - struct sockaddr_storage *addrs, size_t addrs_size); +enum iface_event_type { + IFACE_ADD, + IFACE_DEL, +}; + +typedef void (*iface_event_handler_t)(enum iface_event_type, int af, unsigned int ifindex); +void iface_register_event_handler(iface_event_handler_t event_handler); int iface_start_thread(void); void iface_stop(void); +size_t iface_addr_lookup(unsigned int ifindex, unsigned char family, + struct sockaddr_storage *addrs, size_t addrs_size); + #endif /* IFACE_H */ diff --git a/llmnr.c b/llmnr.c index 92eb562..01f25d9 100644 --- a/llmnr.c +++ b/llmnr.c @@ -32,15 +32,49 @@ #include "pkt.h" #include "socket.h" +#include "iface.h" #include "llmnr-packet.h" #include "llmnr.h" +static int llmnr_sock = -1; +static int llmnr_sock_v6 = -1; static bool llmnr_running = true; /* * 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, int af, unsigned int ifindex) +{ + switch (af) { + case AF_INET: + socket_mcast_group_ipv4(llmnr_sock, ifindex, type == IFACE_ADD); + break; + case AF_INET6: + socket_mcast_group_ipv6(llmnr_sock_v6, ifindex, type == IFACE_ADD); + break; + default: + /* ignore */ + break; + } +} + +int llmnr_init(const char *hostname, uint16_t port) +{ + 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); + + llmnr_sock = socket_open_ipv4(port); + if (llmnr_sock < 0) + return -1; + + iface_register_event_handler(&llmnr_iface_event_handle); + + return 0; +} + static bool llmnr_name_matches(const uint8_t *query) { uint8_t i, n = llmnr_hostname[0]; @@ -201,22 +235,9 @@ static void llmnr_packet_process(unsigned int ifindex, const uint8_t *pktbuf, si llmnr_respond(ifindex, hdr, query, query_len, sock, sa); } -int llmnr_run(const char *hostname, uint16_t port) +int llmnr_run(void) { int ret = -1; - int sock; - - if (port == 0) - port = LLMNR_UDP_PORT; - - llmnr_hostname[0] = strlen(hostname); - strncpy(&llmnr_hostname[1], hostname, LLMNR_LABEL_MAX_SIZE); - llmnr_hostname[LLMNR_LABEL_MAX_SIZE + 1] = '\0'; - log_info("Listening on port %u, hostname %s\n", port, hostname); - - sock = socket_open_v4(port); - if (sock < 0) - return -1; while (llmnr_running) { uint8_t pktbuf[2048], aux[128]; @@ -238,7 +259,7 @@ int llmnr_run(const char *hostname, uint16_t port) msg.msg_control = aux; msg.msg_controllen = sizeof(aux); - if ((recvlen = recvmsg(sock, &msg, 0)) < 0) { + if ((recvlen = recvmsg(llmnr_sock, &msg, 0)) < 0) { if (errno != EINTR) log_err("Failed to receive packet: %s\n", strerror(errno)); goto out; @@ -251,12 +272,12 @@ int llmnr_run(const char *hostname, uint16_t port) } } - llmnr_packet_process(ifindex, pktbuf, recvlen, sock, (const struct sockaddr *)&saddr_r); + llmnr_packet_process(ifindex, pktbuf, recvlen, llmnr_sock, (const struct sockaddr *)&saddr_r); } ret = 0; out: - close(sock); + close(llmnr_sock); return ret; } diff --git a/llmnr.h b/llmnr.h index 35050b2..cc515f1 100644 --- a/llmnr.h +++ b/llmnr.h @@ -21,7 +21,8 @@ #include -int llmnr_run(const char *hostname, uint16_t port); +int llmnr_init(const char *hostname, uint16_t port); +int llmnr_run(void); void llmnr_stop(void); #endif /* LLMNR_H */ diff --git a/llmnrd.c b/llmnrd.c index 5b1a4ea..4da5c4e 100644 --- a/llmnrd.c +++ b/llmnrd.c @@ -108,7 +108,7 @@ int main(int argc, char **argv) int c, ret = EXIT_FAILURE; long num_arg; bool daemonize = false; - char *hostname = ""; + char *hostname = NULL; uint16_t port = LLMNR_UDP_PORT; while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { @@ -140,7 +140,7 @@ int main(int argc, char **argv) register_signal(SIGTERM, signal_handler); register_signal(SIGHUP, signal_handler); - if (hostname[0] == '\0') { + if (!hostname) { /* TODO: Consider hostname changing at runtime */ hostname = xmalloc(255); if (gethostname(hostname, 255) != 0) { @@ -156,10 +156,13 @@ int main(int argc, char **argv) } } + if (llmnr_init(hostname, port) < 0) + goto out; + if (iface_start_thread() < 0) goto out; - ret = llmnr_run(hostname, port); + ret = llmnr_run(); out: free(hostname); return ret; -- cgit v1.2.3-54-g00ecf