summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2015-02-18 16:49:51 +0100
committerTobias Klauser <tklauser@distanz.ch>2015-02-18 16:49:51 +0100
commit069060cad6d9a21d9ec287a7ae9a22deb87f4abc (patch)
tree93846e5638c08a6bd3e1f38e79bae78dcbba01df
parent8868bebeee5aad1247bd93a031a7fa30138da13d (diff)
llmnrd: Join IP multicast group on each new interface
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
-rw-r--r--iface.c18
-rw-r--r--iface.h12
-rw-r--r--llmnr.c55
-rw-r--r--llmnr.h3
-rw-r--r--llmnrd.c9
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 <sys/socket.h>
-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 <stdint.h>
-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;