1 /*	$NetBSD: dns-example.c,v 1.1.1.1 2013/04/11 16:43:31 christos Exp $	*/
2 /*
3   This example code shows how to use the high-level, low-level, and
4   server-level interfaces of evdns.
5 
6   XXX It's pretty ugly and should probably be cleaned up.
7  */
8 
9 #include <event2/event-config.h>
10 
11 /* Compatibility for possible missing IPv6 declarations */
12 #include "../ipv6-internal.h"
13 
14 #include <sys/types.h>
15 
16 #ifdef WIN32
17 #include <winsock2.h>
18 #include <ws2tcpip.h>
19 #else
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <arpa/inet.h>
23 #endif
24 
25 #include <event2/event.h>
26 #include <event2/dns.h>
27 #include <event2/dns_struct.h>
28 #include <event2/util.h>
29 
30 #ifdef _EVENT_HAVE_NETINET_IN6_H
31 #include <netinet/in6.h>
32 #endif
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 
38 #define u32 ev_uint32_t
39 #define u8 ev_uint8_t
40 
41 static const char *
42 debug_ntoa(u32 address)
43 {
44 	static char buf[32];
45 	u32 a = ntohl(address);
46 	evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
47 					(int)(u8)((a>>24)&0xff),
48 					(int)(u8)((a>>16)&0xff),
49 					(int)(u8)((a>>8 )&0xff),
50 					(int)(u8)((a	)&0xff));
51 	return buf;
52 }
53 
54 static void
55 main_callback(int result, char type, int count, int ttl,
56 			  void *addrs, void *orig) {
57 	char *n = (char*)orig;
58 	int i;
59 	for (i = 0; i < count; ++i) {
60 		if (type == DNS_IPv4_A) {
61 			printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
62 		} else if (type == DNS_PTR) {
63 			printf("%s: %s\n", n, ((char**)addrs)[i]);
64 		}
65 	}
66 	if (!count) {
67 		printf("%s: No answer (%d)\n", n, result);
68 	}
69 	fflush(stdout);
70 }
71 
72 static void
73 gai_callback(int err, struct evutil_addrinfo *ai, void *arg)
74 {
75 	const char *name = arg;
76 	int i;
77 	if (err) {
78 		printf("%s: %s\n", name, evutil_gai_strerror(err));
79 	}
80 	if (ai && ai->ai_canonname)
81 		printf("    %s ==> %s\n", name, ai->ai_canonname);
82 	for (i=0; ai; ai = ai->ai_next, ++i) {
83 		char buf[128];
84 		if (ai->ai_family == PF_INET) {
85 			struct sockaddr_in *sin =
86 			    (struct sockaddr_in*)ai->ai_addr;
87 			evutil_inet_ntop(AF_INET, &sin->sin_addr, buf,
88 			    sizeof(buf));
89 			printf("[%d] %s: %s\n",i,name,buf);
90 		} else {
91 			struct sockaddr_in6 *sin6 =
92 			    (struct sockaddr_in6*)ai->ai_addr;
93 			evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf,
94 			    sizeof(buf));
95 			printf("[%d] %s: %s\n",i,name,buf);
96 		}
97 	}
98 }
99 
100 static void
101 evdns_server_callback(struct evdns_server_request *req, void *data)
102 {
103 	int i, r;
104 	(void)data;
105 	/* dummy; give 192.168.11.11 as an answer for all A questions,
106 	 *	give foo.bar.example.com as an answer for all PTR questions. */
107 	for (i = 0; i < req->nquestions; ++i) {
108 		u32 ans = htonl(0xc0a80b0bUL);
109 		if (req->questions[i]->type == EVDNS_TYPE_A &&
110 		    req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
111 			printf(" -- replying for %s (A)\n", req->questions[i]->name);
112 			r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
113 										  1, &ans, 10);
114 			if (r<0)
115 				printf("eeep, didn't work.\n");
116 		} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
117 		    req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
118 			printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
119 			r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
120 											"foo.bar.example.com", 10);
121 			if (r<0)
122 				printf("ugh, no luck");
123 		} else {
124 			printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
125 				   req->questions[i]->type, req->questions[i]->dns_question_class);
126 		}
127 	}
128 
129 	r = evdns_server_request_respond(req, 0);
130 	if (r<0)
131 		printf("eeek, couldn't send reply.\n");
132 }
133 
134 static int verbose = 0;
135 
136 static void
137 logfn(int is_warn, const char *msg) {
138 	if (!is_warn && !verbose)
139 		return;
140 	fprintf(stderr, "%s: %s\n", is_warn?"WARN":"INFO", msg);
141 }
142 
143 int
144 main(int c, char **v) {
145 	int idx;
146 	int reverse = 0, servertest = 0, use_getaddrinfo = 0;
147 	struct event_base *event_base = NULL;
148 	struct evdns_base *evdns_base = NULL;
149 	const char *resolv_conf = NULL;
150 	if (c<2) {
151 		fprintf(stderr, "syntax: %s [-x] [-v] [-c resolv.conf] hostname\n", v[0]);
152 		fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
153 		return 1;
154 	}
155 	idx = 1;
156 	while (idx < c && v[idx][0] == '-') {
157 		if (!strcmp(v[idx], "-x"))
158 			reverse = 1;
159 		else if (!strcmp(v[idx], "-v"))
160 			verbose = 1;
161 		else if (!strcmp(v[idx], "-g"))
162 			use_getaddrinfo = 1;
163 		else if (!strcmp(v[idx], "-servertest"))
164 			servertest = 1;
165 		else if (!strcmp(v[idx], "-c")) {
166 			if (idx + 1 < c)
167 				resolv_conf = v[++idx];
168 			else
169 				fprintf(stderr, "-c needs an argument\n");
170 		} else
171 			fprintf(stderr, "Unknown option %s\n", v[idx]);
172 		++idx;
173 	}
174 
175 #ifdef WIN32
176 	{
177 		WSADATA WSAData;
178 		WSAStartup(0x101, &WSAData);
179 	}
180 #endif
181 
182 	event_base = event_base_new();
183 	evdns_base = evdns_base_new(event_base, 0);
184 	evdns_set_log_fn(logfn);
185 
186 	if (servertest) {
187 		evutil_socket_t sock;
188 		struct sockaddr_in my_addr;
189 		sock = socket(PF_INET, SOCK_DGRAM, 0);
190 		if (sock == -1) {
191 			perror("socket");
192 			exit(1);
193 		}
194 		evutil_make_socket_nonblocking(sock);
195 		my_addr.sin_family = AF_INET;
196 		my_addr.sin_port = htons(10053);
197 		my_addr.sin_addr.s_addr = INADDR_ANY;
198 		if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
199 			perror("bind");
200 			exit(1);
201 		}
202 		evdns_add_server_port_with_base(event_base, sock, 0, evdns_server_callback, NULL);
203 	}
204 	if (idx < c) {
205 		int res;
206 #ifdef WIN32
207 		if (resolv_conf == NULL)
208 			res = evdns_base_config_windows_nameservers(evdns_base);
209 		else
210 #endif
211 			res = evdns_base_resolv_conf_parse(evdns_base,
212 			    DNS_OPTION_NAMESERVERS,
213 			    resolv_conf ? resolv_conf : "/etc/resolv.conf");
214 
215 		if (res < 0) {
216 			fprintf(stderr, "Couldn't configure nameservers");
217 			return 1;
218 		}
219 	}
220 
221 	printf("EVUTIL_AI_CANONNAME in example = %d\n", EVUTIL_AI_CANONNAME);
222 	for (; idx < c; ++idx) {
223 		if (reverse) {
224 			struct in_addr addr;
225 			if (evutil_inet_pton(AF_INET, v[idx], &addr)!=1) {
226 				fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
227 				continue;
228 			}
229 			fprintf(stderr, "resolving %s...\n",v[idx]);
230 			evdns_base_resolve_reverse(evdns_base, &addr, 0, main_callback, v[idx]);
231 		} else if (use_getaddrinfo) {
232 			struct evutil_addrinfo hints;
233 			memset(&hints, 0, sizeof(hints));
234 			hints.ai_family = PF_UNSPEC;
235 			hints.ai_protocol = IPPROTO_TCP;
236 			hints.ai_flags = EVUTIL_AI_CANONNAME;
237 			fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
238 			evdns_getaddrinfo(evdns_base, v[idx], NULL, &hints,
239 			    gai_callback, v[idx]);
240 		} else {
241 			fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
242 			evdns_base_resolve_ipv4(evdns_base, v[idx], 0, main_callback, v[idx]);
243 		}
244 	}
245 	fflush(stdout);
246 	event_base_dispatch(event_base);
247 	return 0;
248 }
249 
250