Home | History | Annotate | Line # | Download | only in sample
dns-example.c revision 1.1.1.1.4.2
      1 /*	$NetBSD: dns-example.c,v 1.1.1.1.4.2 2013/06/23 06:28:18 tls 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