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