diff options
author | Tobias Klauser <tklauser@distanz.ch> | 2015-02-18 14:07:43 +0100 |
---|---|---|
committer | Tobias Klauser <tklauser@distanz.ch> | 2015-02-18 14:07:43 +0100 |
commit | 2bab52017fb4901e9c642fab585f7169e6d11253 (patch) | |
tree | 3bd13cd52fe28975a6891d65dcff26185c85f91e | |
parent | 09e957eec11ac38a4c6dcef9012aa4ab8de9fb5b (diff) |
llmnr-query: Support sending queries using IPv6
Partially resolves #5 (IPv6 support)
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
-rw-r--r-- | llmnr-query.c | 48 |
1 files changed, 35 insertions, 13 deletions
diff --git a/llmnr-query.c b/llmnr-query.c index e3565e6..e7dd2fa 100644 --- a/llmnr-query.c +++ b/llmnr-query.c @@ -35,11 +35,12 @@ #include "log.h" #include "pkt.h" -static const char *short_ops = "c:i:p:T:hV"; +static const char *short_ops = "c:i:p:T:6hV"; static const struct option long_opts[] = { { "count", required_argument, NULL, 'c' }, { "interval", required_argument, NULL, 'i' }, { "type", required_argument, NULL, 'T' }, + { "ipv6", no_argument, NULL, '6' }, { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 }, @@ -49,11 +50,12 @@ static void __noreturn usage_and_exit(int status) { fprintf(stdout, "Usage: llmnr-query [OPTIONS...] <query-name>\n" "Options:\n" - " -c, --count number of queries to send (default: 1)\n" - " -i, --interval interval between queries in ms (default: 500)\n" - " -T, --type LLMNR query type, must be one of A, AAAA, ANY (default: A)\n" - " -h, --help show this help and exit\n" - " -V, --version show version information and exit\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"); exit(status); } @@ -86,6 +88,7 @@ int main(int argc, char **argv) size_t query_name_len; unsigned long i, count = 1, interval = 500; uint16_t qtype = LLMNR_QTYPE_A; + bool ipv6 = false; struct pkt *p; while ((c = getopt_long(argc, argv, short_ops, long_opts, NULL)) != -1) { @@ -108,6 +111,9 @@ int main(int argc, char **argv) usage_and_exit(EXIT_FAILURE); } break; + case '6': + ipv6 = true; + break; case 'V': version_and_exit(); case 'h': @@ -127,7 +133,7 @@ int main(int argc, char **argv) return -1; } - sock = socket(AF_INET, SOCK_DGRAM, 0); + sock = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); if (sock < 0) { log_err("Failed to open UDP socket: %s\n", strerror(errno)); return -1; @@ -139,7 +145,7 @@ int main(int argc, char **argv) for (i = 0; i < count; i++) { struct llmnr_hdr *hdr; - struct sockaddr_in sin; + struct sockaddr_storage sst; size_t query_pkt_len; fd_set rfds; struct timeval tv; @@ -160,14 +166,30 @@ int main(int argc, char **argv) pkt_put_u16(p, htons(qtype)); pkt_put_u16(p, htons(LLMNR_QCLASS_IN)); - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = inet_addr(LLMNR_IPV4_MCAST_ADDR); - sin.sin_port = htons(LLMNR_UDP_PORT); + memset(&sst, 0, sizeof(sst)); + if (ipv6) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)&sst; + + sin6->sin6_family = AF_INET6; + sin6->sin6_port = htons(LLMNR_UDP_PORT); + if (inet_pton(AF_INET6, LLMNR_IPV6_MCAST_ADDR, &sin6->sin6_addr) != 1) { + log_err("Failed to convert IPv6 address: %s\n", strerror(errno)); + break; + } + } else { + struct sockaddr_in *sin = (struct sockaddr_in *)&sst; + + sin->sin_family = AF_INET; + sin->sin_port = htons(LLMNR_UDP_PORT); + if (inet_pton(AF_INET, LLMNR_IPV4_MCAST_ADDR, &sin->sin_addr) != 1) { + log_err("Failed to convert IPv4 address: %s\n", strerror(errno)); + break; + } + } query_pkt_len = pkt_len(p) - sizeof(*hdr); - if (sendto(sock, p->data, pkt_len(p), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) { + if (sendto(sock, p->data, pkt_len(p), 0, (struct sockaddr *)&sst, sizeof(sst)) < 0) { log_err("Failed to send UDP packet: %s\n", strerror(errno)); break; } |