aboutsummaryrefslogtreecommitdiff
path: root/networking/nslookup.c
blob: 5a08844f051b5c93933443b7ae11257ba30b940c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/* 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 tarball for details.
 */

#include <resolv.h>
#include "busybox.h"

/*
 *  I'm only implementing non-interactive mode;
 *  I totally forgot nslookup even had an interactive mode.
 */

/* 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 sockaddr_to_dotted(struct sockaddr *saddr, char *buf, int buflen)
{
	if (buflen <= 0) return -1;
	buf[0] = '\0';
	if (saddr->sa_family == AF_INET) {
		inet_ntop(AF_INET, &((struct sockaddr_in*)saddr)->sin_addr, buf, buflen);
		return 0;
	}
	if (saddr->sa_family == AF_INET6) {
		inet_ntop(AF_INET6, &((struct sockaddr_in6*)saddr)->sin6_addr, buf, buflen);
		return 0;
	}
	return -1;
}

static int print_host(const char *hostname, const char *header)
{
	char str[128];	/* IPv6 address will fit, hostnames hopefully too */
	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) {
		struct addrinfo *cur = result;
		// printf("%s\n", cur->ai_canonname); ?
		while (cur) {
			sockaddr_to_dotted(cur->ai_addr, str, sizeof(str));
			printf("%s  %s\nAddress: %s", header, hostname, str);
			str[0] = ' ';
			if (getnameinfo(cur->ai_addr, cur->ai_addrlen, str+1, sizeof(str)-1, NULL, 0, NI_NAMEREQD))
				str[0] = '\0';
			puts(str);
			cur = cur->ai_next;
		}
	} else {
		bb_error_msg("getaddrinfo('%s') failed: %s", hostname, gai_strerror(rc));
	}
	freeaddrinfo(result);
	return (rc != 0);
}


/* alter the global _res nameserver structure to use
   an explicit dns server instead of what is in /etc/resolv.h */
static void set_default_dns(char *server)
{
	struct in_addr server_in_addr;

	if (inet_pton(AF_INET, server, &server_in_addr) > 0) {
		_res.nscount = 1;
		_res.nsaddr_list[0].sin_addr = server_in_addr;
	}
}


/* lookup the default nameserver and display it */
static void server_print(void)
{
	char str[INET6_ADDRSTRLEN];

	sockaddr_to_dotted((struct sockaddr*)&_res.nsaddr_list[0], str, sizeof(str));
	print_host(str, "Server:");
	puts("");
}


int nslookup_main(int argc, char **argv)
{
	/*
	* initialize DNS structure _res used in printing the default
	* name server and in the explicit name server option feature.
	*/

	res_init();

	/*
	* 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 (argc < 2 || *argv[1] == '-' || argc > 3)
		bb_show_usage();
	else if(argc == 3)
		set_default_dns(argv[2]);

	server_print();
	return print_host(argv[1], "Name:  ");
}