123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /* vi: set sw=4 ts=4: */
- /*
- * Mini nslookup implementation for busybox
- *
- * Copyright (C) 1999,2000 by Lineo, inc. and John Beppu
- * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
- *
- * Correct default name server display and explicit name server option
- * added by Ben Zeckel <bzeckel@hmc.edu> June 2001
- *
- * Licensed under GPLv2 or later, see file LICENSE in this source tree.
- */
- //usage:#define nslookup_trivial_usage
- //usage: "[HOST] [SERVER]"
- //usage:#define nslookup_full_usage "\n\n"
- //usage: "Query the nameserver for the IP address of the given HOST\n"
- //usage: "optionally using a specified DNS server"
- //usage:
- //usage:#define nslookup_example_usage
- //usage: "$ nslookup localhost\n"
- //usage: "Server: default\n"
- //usage: "Address: default\n"
- //usage: "\n"
- //usage: "Name: debian\n"
- //usage: "Address: 127.0.0.1\n"
- #include <resolv.h>
- #include "libbb.h"
- /*
- * I'm only implementing non-interactive mode;
- * I totally forgot nslookup even had an interactive mode.
- *
- * This applet is the only user of res_init(). Without it,
- * you may avoid pulling in _res global from libc.
- */
- /* Examples of 'standard' nslookup output
- * $ nslookup yahoo.com
- * Server: 128.193.0.10
- * Address: 128.193.0.10#53
- *
- * Non-authoritative answer:
- * Name: yahoo.com
- * Address: 216.109.112.135
- * Name: yahoo.com
- * Address: 66.94.234.13
- *
- * $ nslookup 204.152.191.37
- * Server: 128.193.4.20
- * Address: 128.193.4.20#53
- *
- * Non-authoritative answer:
- * 37.191.152.204.in-addr.arpa canonical name = 37.32-27.191.152.204.in-addr.arpa.
- * 37.32-27.191.152.204.in-addr.arpa name = zeus-pub2.kernel.org.
- *
- * Authoritative answers can be found from:
- * 32-27.191.152.204.in-addr.arpa nameserver = ns1.kernel.org.
- * 32-27.191.152.204.in-addr.arpa nameserver = ns2.kernel.org.
- * 32-27.191.152.204.in-addr.arpa nameserver = ns3.kernel.org.
- * ns1.kernel.org internet address = 140.211.167.34
- * ns2.kernel.org internet address = 204.152.191.4
- * ns3.kernel.org internet address = 204.152.191.36
- */
- static int print_host(const char *hostname, const char *header)
- {
- /* We can't use xhost2sockaddr() - we want to get ALL addresses,
- * not just one */
- struct addrinfo *result = NULL;
- int rc;
- struct addrinfo hint;
- memset(&hint, 0 , sizeof(hint));
- /* hint.ai_family = AF_UNSPEC; - zero anyway */
- /* Needed. Or else we will get each address thrice (or more)
- * for each possible socket type (tcp,udp,raw...): */
- hint.ai_socktype = SOCK_STREAM;
- // hint.ai_flags = AI_CANONNAME;
- rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
- if (rc == 0) {
- struct addrinfo *cur = result;
- unsigned cnt = 0;
- printf("%-10s %s\n", header, hostname);
- // puts(cur->ai_canonname); ?
- while (cur) {
- char *dotted, *revhost;
- dotted = xmalloc_sockaddr2dotted_noport(cur->ai_addr);
- revhost = xmalloc_sockaddr2hostonly_noport(cur->ai_addr);
- printf("Address %u: %s%c", ++cnt, dotted, revhost ? ' ' : '\n');
- if (revhost) {
- puts(revhost);
- if (ENABLE_FEATURE_CLEAN_UP)
- free(revhost);
- }
- if (ENABLE_FEATURE_CLEAN_UP)
- free(dotted);
- cur = cur->ai_next;
- }
- } else {
- #if ENABLE_VERBOSE_RESOLUTION_ERRORS
- bb_error_msg("can't resolve '%s': %s", hostname, gai_strerror(rc));
- #else
- bb_error_msg("can't resolve '%s'", hostname);
- #endif
- }
- if (ENABLE_FEATURE_CLEAN_UP && result)
- freeaddrinfo(result);
- return (rc != 0);
- }
- /* lookup the default nameserver and display it */
- static void server_print(void)
- {
- char *server;
- struct sockaddr *sa;
- #if ENABLE_FEATURE_IPV6
- sa = (struct sockaddr*)_res._u._ext.nsaddrs[0];
- if (!sa)
- #endif
- sa = (struct sockaddr*)&_res.nsaddr_list[0];
- server = xmalloc_sockaddr2dotted_noport(sa);
- print_host(server, "Server:");
- if (ENABLE_FEATURE_CLEAN_UP)
- free(server);
- bb_putchar('\n');
- }
- /* alter the global _res nameserver structure to use
- an explicit dns server instead of what is in /etc/resolv.conf */
- static void set_default_dns(const char *server)
- {
- len_and_sockaddr *lsa;
- if (!server)
- return;
- /* NB: this works even with, say, "[::1]:5353"! :) */
- lsa = xhost2sockaddr(server, 53);
- if (lsa->u.sa.sa_family == AF_INET) {
- _res.nscount = 1;
- /* struct copy */
- _res.nsaddr_list[0] = lsa->u.sin;
- }
- #if ENABLE_FEATURE_IPV6
- /* Hoped libc can cope with IPv4 address there too.
- * No such luck, glibc 2.4 segfaults even with IPv6,
- * maybe I misunderstand how to make glibc use IPv6 addr?
- * (uclibc 0.9.31+ should work) */
- if (lsa->u.sa.sa_family == AF_INET6) {
- // glibc neither SEGVs nor sends any dgrams with this
- // (strace shows no socket ops):
- //_res.nscount = 0;
- _res._u._ext.nscount = 1;
- /* store a pointer to part of malloc'ed lsa */
- _res._u._ext.nsaddrs[0] = &lsa->u.sin6;
- /* must not free(lsa)! */
- }
- #endif
- }
- int nslookup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
- int nslookup_main(int argc, char **argv)
- {
- /* We allow 1 or 2 arguments.
- * The first is the name to be looked up and the second is an
- * optional DNS server with which to do the lookup.
- * More than 3 arguments is an error to follow the pattern of the
- * standard nslookup */
- if (!argv[1] || argv[1][0] == '-' || argc > 3)
- bb_show_usage();
- /* initialize DNS structure _res used in printing the default
- * name server and in the explicit name server option feature. */
- res_init();
- /* rfc2133 says this enables IPv6 lookups */
- /* (but it also says "may be enabled in /etc/resolv.conf") */
- /*_res.options |= RES_USE_INET6;*/
- set_default_dns(argv[2]);
- server_print();
- /* getaddrinfo and friends are free to request a resolver
- * reinitialization. Just in case, set_default_dns() again
- * after getaddrinfo (in server_print). This reportedly helps
- * with bug 675 "nslookup does not properly use second argument"
- * at least on Debian Wheezy and Openwrt AA (eglibc based).
- */
- set_default_dns(argv[2]);
- return print_host(argv[1], "Name:");
- }
|