summaryrefslogtreecommitdiff
path: root/llmnr-query.c
diff options
context:
space:
mode:
authorTobias Klauser <tklauser@distanz.ch>2015-02-18 16:35:48 +0100
committerTobias Klauser <tklauser@distanz.ch>2015-02-18 16:40:44 +0100
commit8868bebeee5aad1247bd93a031a7fa30138da13d (patch)
tree185721438e0a62e51cc256b891f71120c80dd6e1 /llmnr-query.c
parentb37970f16650b7bef12bee4c2595cb85d1838af5 (diff)
llmnr-query: Add option to send query over different interface
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
Diffstat (limited to 'llmnr-query.c')
-rw-r--r--llmnr-query.c55
1 files changed, 44 insertions, 11 deletions
diff --git a/llmnr-query.c b/llmnr-query.c
index a1fac67..cf738e4 100644
--- a/llmnr-query.c
+++ b/llmnr-query.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <arpa/inet.h>
+#include <net/if.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/time.h>
@@ -35,10 +36,11 @@
#include "log.h"
#include "pkt.h"
-static const char *short_ops = "c:i:p:T:6hV";
+static const char *short_ops = "c:i:I:T:6hV";
static const struct option long_opts[] = {
{ "count", required_argument, NULL, 'c' },
{ "interval", required_argument, NULL, 'i' },
+ { "interface", required_argument, NULL, 'I' },
{ "type", required_argument, NULL, 'T' },
{ "ipv6", no_argument, NULL, '6' },
{ "help", no_argument, NULL, 'h' },
@@ -48,14 +50,15 @@ static const struct option long_opts[] = {
static void __noreturn usage_and_exit(int status)
{
- fprintf(stdout, "Usage: llmnr-query [OPTIONS...] <query-name>\n"
+ fprintf(stdout, "Usage: llmnr-query [OPTIONS...] NAME\n"
"Options:\n"
- " -c, --count <number> number of queries to send (default: 1)\n"
- " -i, --interval <number> interval between queries in ms (default: 500)\n"
- " -T, --type <type> set query type; must be one of A, AAAA, ANY (default: A)\n"
- " -6, --ipv6 use IPv6\n"
- " -h, --help show this help and exit\n"
- " -V, --version show version information and exit\n");
+ " -c, --count NUM number of queries to send (default: 1)\n"
+ " -i, --interval NUM interval between queries in ms (default: 500)\n"
+ " -I, --interface NAME send multicast over specified interface\n"
+ " -T, --type TYPE set query type; must be one of A, AAAA, ANY (default: A)\n"
+ " -6, --ipv6 send queries over IPv6\n"
+ " -h, --help show this help and exit\n"
+ " -V, --version show version information and exit\n");
exit(status);
}
@@ -85,7 +88,7 @@ static const char *query_type(uint16_t qtype)
int main(int argc, char **argv)
{
int c, sock;
- const char *query_name;
+ const char *query_name, *iface = NULL;
size_t query_name_len;
unsigned long i, count = 1, interval = 500;
uint16_t qtype = LLMNR_QTYPE_A;
@@ -100,6 +103,9 @@ int main(int argc, char **argv)
case 'i':
interval = strtoul(optarg, NULL, 0);
break;
+ case 'I':
+ iface = xstrdup(optarg);
+ break;
case 'T':
if (xstreq("A", optarg))
qtype = LLMNR_QTYPE_A;
@@ -140,6 +146,34 @@ int main(int argc, char **argv)
return -1;
}
+ if (iface != NULL) {
+ unsigned int ifindex = if_nametoindex(iface);
+
+ if (ifindex == 0 && errno != 0) {
+ log_err("Could not get interface %s: %s\n", iface, strerror(errno));
+ goto err;
+ }
+
+ if (ipv6) {
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex, sizeof(ifindex)) < 0) {
+ log_err("Failed to set interface '%s' for IPv6 multicast socket: %s\n",
+ iface, strerror(errno));
+ goto err;
+ }
+ } else {
+ struct ip_mreqn mreq;
+
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.imr_ifindex = ifindex;
+
+ if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0) {
+ log_err("Failed to set interface '%s' for IPv4 multicast socket: %s\n",
+ iface, strerror(errno));
+ goto err;
+ }
+ }
+ }
+
p = pkt_alloc(128);
log_info("LLMNR query: %s IN %s\n", query_name, query_type(qtype));
@@ -265,8 +299,7 @@ int main(int argc, char **argv)
}
pkt_free(p);
-
+err:
close(sock);
-
return 0;
}