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