summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2016-08-17 08:41:52 +0200
committerTobias Klauser <tklauser@distanz.ch>2016-08-17 08:41:52 +0200
commitf46d59e0dc7b54a3f4a7ead2fd2d4258b3f56782 (patch)
tree076ca9422193ee640dc16c69c0923a4c9feeaec1
parentf1081b6b0f47160f83ded689d956bd577819d752 (diff)
llmnrd: Allow to bind to a specific network interface
Add a command line option -i/--interface which allows to bind the llmnrd sockets to a specific interface. If used, requests are only answered on the specified interface. Example: llmnrd -i eth0 Closes #9 Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
-rw-r--r--iface.c12
-rw-r--r--iface.h2
-rw-r--r--llmnr.c8
-rw-r--r--llmnr.h4
-rw-r--r--llmnrd.c12
-rw-r--r--socket.c27
-rw-r--r--socket.h4
7 files changed, 55 insertions, 14 deletions
diff --git a/iface.c b/iface.c
index 8cb88fc..333a142 100644
--- a/iface.c
+++ b/iface.c
@@ -42,6 +42,7 @@
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;
@@ -234,6 +235,13 @@ static void iface_nlmsg_change_addr(const struct nlmsghdr *nlh)
if ((ifa->ifa_flags & (IFA_F_TEMPORARY | IFA_F_TENTATIVE)) != 0)
return;
+ /*
+ * If bound to a specific interface, don't report addresses of any other
+ * interface.
+ */
+ if (iface_ifindex > 0 && index != iface_ifindex)
+ return;
+
if_indextoname(index, ifname);
rta = (struct rtattr *)((const uint8_t *)nlh + NLMSG_SPACE(sizeof(*ifa)));
@@ -388,9 +396,11 @@ static void* iface_run_wrapper(void *data __unused)
return ERR_PTR(iface_run());
}
-int iface_start_thread(bool ipv6)
+int iface_start_thread(bool ipv6, const char *iface)
{
iface_ipv6 = ipv6;
+ if (iface)
+ iface_ifindex = if_nametoindex(iface);
if (pthread_create(&iface_thread, NULL, iface_run_wrapper, NULL) < 0) {
log_err("Failed to start interface monitoring thread\n");
diff --git a/iface.h b/iface.h
index 5032d87..11c49e7 100644
--- a/iface.h
+++ b/iface.h
@@ -31,7 +31,7 @@ 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);
+int iface_start_thread(bool ipv6, const char *iface);
void iface_stop(void);
size_t iface_addr_lookup(unsigned int ifindex, unsigned char family,
diff --git a/llmnr.c b/llmnr.c
index a833ef1..206f165 100644
--- a/llmnr.c
+++ b/llmnr.c
@@ -61,19 +61,21 @@ static void llmnr_iface_event_handle(enum iface_event_type type, unsigned char a
}
}
-int llmnr_init(const char *hostname, uint16_t port, bool ipv6)
+int llmnr_init(const char *hostname, uint16_t port, bool ipv6, const char *iface)
{
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);
+ llmnr_sock_ipv4 = socket_open_ipv4(port, iface);
if (llmnr_sock_ipv4 < 0)
return -1;
if (ipv6) {
- llmnr_sock_ipv6 = socket_open_ipv6(port);
+ llmnr_sock_ipv6 = socket_open_ipv6(port, iface);
if (llmnr_sock_ipv6 < 0)
return -1;
}
diff --git a/llmnr.h b/llmnr.h
index da86440..620e539 100644
--- a/llmnr.h
+++ b/llmnr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2015-2016 Tobias Klauser <tklauser@distanz.ch>
*
* This file is part of llmnrd.
*
@@ -22,7 +22,7 @@
#include <stdbool.h>
#include <stdint.h>
-int llmnr_init(const char *hostname, uint16_t port, bool ipv6);
+int llmnr_init(const char *hostname, uint16_t port, bool ipv6, const char *iface);
int llmnr_run(void);
void llmnr_stop(void);
diff --git a/llmnrd.c b/llmnrd.c
index 866e919..2bc4a20 100644
--- a/llmnrd.c
+++ b/llmnrd.c
@@ -39,9 +39,10 @@
#include "llmnr.h"
#include "llmnr-packet.h"
-static const char *short_opts = "H:p:6dhV";
+static const char *short_opts = "H:i:p:6dhV";
static const struct option long_opts[] = {
{ "hostname", required_argument, NULL, 'H' },
+ { "interface", required_argument, NULL, 'i' },
{ "port", required_argument, NULL, 'p' },
{ "ipv6", no_argument, NULL, '6' },
{ "daemonize", no_argument, NULL, 'd' },
@@ -55,6 +56,7 @@ static void __noreturn usage_and_exit(int status)
fprintf(stdout, "Usage: llmnrd [OPTIONS]\n"
"Options:\n"
" -H, --hostname NAME set hostname to respond with (default: system hostname)\n"
+ " -i, --interface DEV bind socket to a specific interface, e.g. eth0\n"
" -p, --port NUM set port number to listen on (default: %d)\n"
" -6, --ipv6 enable LLMNR name resolution over IPv6\n"
" -d, --daemonize run as daemon in the background\n"
@@ -113,6 +115,7 @@ int main(int argc, char **argv)
long num_arg;
bool daemonize = false, ipv6 = false;
char *hostname = NULL;
+ char *iface = NULL;
uint16_t port = LLMNR_UDP_PORT;
while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
@@ -123,6 +126,9 @@ int main(int argc, char **argv)
case 'H':
hostname = xstrdup(optarg);
break;
+ case 'i':
+ iface = xstrdup(optarg);
+ break;
case 'p':
num_arg = strtol(optarg, NULL, 0);
if (num_arg < 0 || num_arg > UINT16_MAX) {
@@ -164,10 +170,10 @@ int main(int argc, char **argv)
}
}
- if (llmnr_init(hostname, port, ipv6) < 0)
+ if (llmnr_init(hostname, port, ipv6, iface) < 0)
goto out;
- if (iface_start_thread(ipv6) < 0)
+ if (iface_start_thread(ipv6, iface) < 0)
goto out;
ret = llmnr_run();
diff --git a/socket.c b/socket.c
index 21e715a..1103779 100644
--- a/socket.c
+++ b/socket.c
@@ -36,7 +36,24 @@
static const int YES = 1;
static const int TTL = 255;
-int socket_open_ipv4(uint16_t port)
+static int socket_bind_to_device(int sock, const char *iface) {
+#ifdef SO_BINDTODEVICE
+ /* bind socket to specific interface */
+ if (iface) {
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
+ if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
+ log_err("Failed to bind socket to device %s: %s\n", iface, strerror(errno));
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+int socket_open_ipv4(uint16_t port, const char *iface)
{
int sock;
struct sockaddr_in sa;
@@ -64,6 +81,9 @@ int socket_open_ipv4(uint16_t port)
goto err;
}
+ if (socket_bind_to_device(sock, iface) < 0)
+ goto err;
+
/* bind the socket */
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
@@ -81,7 +101,7 @@ err:
return -1;
}
-int socket_open_ipv6(uint16_t port)
+int socket_open_ipv6(uint16_t port, const char *iface)
{
int sock, opt_pktinfo;
struct sockaddr_in6 sa;
@@ -120,6 +140,9 @@ int socket_open_ipv6(uint16_t port)
goto err;
}
+ if (socket_bind_to_device(sock, iface) < 0)
+ goto err;
+
/* bind the socket */
memset(&sa, 0, sizeof(sa));
sa.sin6_family = AF_INET6;
diff --git a/socket.h b/socket.h
index 93c41a0..49d999b 100644
--- a/socket.h
+++ b/socket.h
@@ -22,8 +22,8 @@
#include <stdbool.h>
#include <stdint.h>
-int socket_open_ipv4(uint16_t port);
-int socket_open_ipv6(uint16_t port);
+int socket_open_ipv4(uint16_t port, const char *iface);
+int socket_open_ipv6(uint16_t port, const char *iface);
int socket_open_rtnl(bool ipv6);
int socket_mcast_group_ipv4(int sock, unsigned int ifindex, bool join);