/[resiprocate]/main/contrib/ares/ares_init.c
ViewVC logotype

Contents of /main/contrib/ares/ares_init.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2081 - (show annotations) (download)
Wed Oct 29 16:47:31 2003 UTC (16 years, 1 month ago) by alan
Original Path: main/sip/contrib/ares/ares_init.c
File MIME type: text/plain
File size: 16315 byte(s)
Fixed OS/X portability.

1 /* Copyright 1998 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose. It is provided "as is"
13 * without express or implied warranty.
14 */
15
16 static const char rcsid[] = "$Id: ares_init.c,v 1.7 2003/10/29 16:47:31 alan Exp $";
17
18 #include <sys/types.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <time.h>
24 #include <assert.h>
25
26 #ifndef WIN32
27 #include <sys/time.h>
28 #include <sys/param.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #ifndef __CYGWIN__
32 # include <arpa/nameser.h>
33 #endif
34 #include <unistd.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #else
38 #include <Winsock2.h>
39 #include <io.h>
40 #include <Windns.h>
41 #endif
42
43 #include "ares.h"
44 #include "ares_private.h"
45
46 static int init_by_options(ares_channel channel, struct ares_options *options,
47 int optmask);
48 static int init_by_environment(ares_channel channel);
49 static int init_by_resolv_conf(ares_channel channel);
50 static int init_by_defaults(ares_channel channel);
51 static int config_domain(ares_channel channel, char *str);
52 static int config_lookup(ares_channel channel, const char *str);
53 static int config_nameserver(struct server_state **servers, int *nservers,
54 const char *str);
55 static int config_sortlist(struct apattern **sortlist, int *nsort,
56 const char *str);
57 static int set_search(ares_channel channel, const char *str);
58 static int set_options(ares_channel channel, const char *str);
59 static char *try_config(char *s, char *opt);
60 static const char *try_option(const char *p, const char *q, const char *opt);
61 static int ip_addr(const char *s, int len, struct in_addr *addr);
62 static void natural_mask(struct apattern *pat);
63
64 int ares_init(ares_channel *channelptr)
65 {
66 return ares_init_options(channelptr, NULL, 0);
67 }
68
69 int ares_init_options(ares_channel *channelptr, struct ares_options *options,
70 int optmask)
71 {
72 ares_channel channel;
73 int i, status;
74 struct server_state *server;
75 // struct timeval tv;
76
77 channel = malloc(sizeof(struct ares_channeldata));
78 if (!channel)
79 return ARES_ENOMEM;
80
81 /* Set everything to distinguished values so we know they haven't
82 * been set yet.
83 */
84 channel->flags = -1;
85 channel->timeout = -1;
86 channel->tries = -1;
87 channel->ndots = -1;
88 channel->udp_port = -1;
89 channel->tcp_port = -1;
90 channel->nservers = -1;
91 channel->ndomains = -1;
92 channel->nsort = -1;
93 channel->lookups = NULL;
94
95 /* Initialize configuration by each of the four sources, from highest
96 * precedence to lowest.
97 */
98 status = init_by_options(channel, options, optmask);
99 if (status == ARES_SUCCESS)
100 status = init_by_environment(channel);
101 if (status == ARES_SUCCESS)
102 status = init_by_resolv_conf(channel);
103 if (status == ARES_SUCCESS)
104 status = init_by_defaults(channel);
105 if (status != ARES_SUCCESS)
106 {
107 /* Something failed; clean up memory we may have allocated. */
108 if (channel->nservers != -1)
109 free(channel->servers);
110 if (channel->ndomains != -1)
111 {
112 for (i = 0; i < channel->ndomains; i++)
113 free(channel->domains[i]);
114 free(channel->domains);
115 }
116 if (channel->nsort != -1)
117 free(channel->sortlist);
118 free(channel->lookups);
119 free(channel);
120 return status;
121 }
122
123 /* Trim to one server if ARES_FLAG_PRIMARY is set. */
124 if ((channel->flags & ARES_FLAG_PRIMARY) && channel->nservers > 1)
125 channel->nservers = 1;
126
127 /* Initialize server states. */
128 for (i = 0; i < channel->nservers; i++)
129 {
130 server = &channel->servers[i];
131 server->udp_socket = -1;
132 server->tcp_socket = -1;
133 server->tcp_lenbuf_pos = 0;
134 server->tcp_buffer = NULL;
135 server->qhead = NULL;
136 server->qtail = NULL;
137 }
138
139 /* Choose a somewhat random query ID. The main point is to avoid
140 * collisions with stale queries. An attacker trying to spoof a DNS
141 * answer also has to guess the query ID, but it's only a 16-bit
142 * field, so there's not much to be done about that.
143 */
144 // gettimeofday(&tv, NULL);
145 // channel->next_id = (tv.tv_sec ^ tv.tv_usec ^ getpid()) & 0xffff;
146 {
147 static int cjNextID=1;
148 channel->next_id = cjNextID++;
149 }
150
151 channel->queries = NULL;
152
153 *channelptr = channel;
154 return ARES_SUCCESS;
155 }
156
157 static int init_by_options(ares_channel channel, struct ares_options *options,
158 int optmask)
159 {
160 int i;
161
162 /* Easy stuff. */
163 if ((optmask & ARES_OPT_FLAGS) && channel->flags == -1)
164 channel->flags = options->flags;
165 if ((optmask & ARES_OPT_TIMEOUT) && channel->timeout == -1)
166 channel->timeout = options->timeout;
167 if ((optmask & ARES_OPT_TRIES) && channel->tries == -1)
168 channel->tries = options->tries;
169 if ((optmask & ARES_OPT_NDOTS) && channel->ndots == -1)
170 channel->ndots = options->ndots;
171 if ((optmask & ARES_OPT_UDP_PORT) && channel->udp_port == -1)
172 channel->udp_port = options->udp_port;
173 if ((optmask & ARES_OPT_TCP_PORT) && channel->tcp_port == -1)
174 channel->tcp_port = options->tcp_port;
175
176 /* Copy the servers, if given. */
177 if ((optmask & ARES_OPT_SERVERS) && channel->nservers == -1)
178 {
179 channel->servers =
180 malloc(options->nservers * sizeof(struct server_state));
181 if (!channel->servers && options->nservers != 0)
182 return ARES_ENOMEM;
183 for (i = 0; i < options->nservers; i++)
184 channel->servers[i].addr = options->servers[i];
185 channel->nservers = options->nservers;
186 }
187
188 /* Copy the domains, if given. Keep channel->ndomains consistent so
189 * we can clean up in case of error.
190 */
191 if ((optmask & ARES_OPT_DOMAINS) && channel->ndomains == -1)
192 {
193 channel->domains = malloc(options->ndomains * sizeof(char *));
194 if (!channel->domains && options->ndomains != 0)
195 return ARES_ENOMEM;
196 for (i = 0; i < options->ndomains; i++)
197 {
198 channel->ndomains = i;
199 channel->domains[i] = strdup(options->domains[i]);
200 if (!channel->domains[i])
201 return ARES_ENOMEM;
202 }
203 channel->ndomains = options->ndomains;
204 }
205
206 /* Set lookups, if given. */
207 if ((optmask & ARES_OPT_LOOKUPS) && !channel->lookups)
208 {
209 channel->lookups = strdup(options->lookups);
210 if (!channel->lookups)
211 return ARES_ENOMEM;
212 }
213
214 return ARES_SUCCESS;
215 }
216
217 static int init_by_environment(ares_channel channel)
218 {
219 const char *localdomain, *res_options;
220 int status;
221
222 localdomain = getenv("LOCALDOMAIN");
223 if (localdomain && channel->ndomains == -1)
224 {
225 status = set_search(channel, localdomain);
226 if (status != ARES_SUCCESS)
227 return status;
228 }
229
230 res_options = getenv("RES_OPTIONS");
231 if (res_options)
232 {
233 status = set_options(channel, res_options);
234 if (status != ARES_SUCCESS)
235 return status;
236 }
237
238 return ARES_SUCCESS;
239 }
240
241 static int init_by_resolv_conf(ares_channel channel)
242 {
243 FILE *fp;
244 char *line = NULL, *p;
245 int linesize, status, nservers = 0, nsort = 0;
246 struct server_state *servers = NULL;
247 struct apattern *sortlist = NULL;
248
249 fp = fopen(PATH_RESOLV_CONF, "r");
250 if (!fp)
251 return (errno == ENOENT) ? ARES_SUCCESS : ARES_EFILE;
252 while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
253 {
254 if ((p = try_config(line, "domain")) && channel->ndomains == -1)
255 status = config_domain(channel, p);
256 else if ((p = try_config(line, "lookup")) && !channel->lookups)
257 status = config_lookup(channel, p);
258 else if ((p = try_config(line, "search")) && channel->ndomains == -1)
259 status = set_search(channel, p);
260 else if ((p = try_config(line, "nameserver")) && channel->nservers == -1)
261 status = config_nameserver(&servers, &nservers, p);
262 else if ((p = try_config(line, "sortlist")) && channel->nsort == -1)
263 status = config_sortlist(&sortlist, &nsort, p);
264 else if ((p = try_config(line, "options")))
265 status = set_options(channel, p);
266 else
267 status = ARES_SUCCESS;
268 if (status != ARES_SUCCESS)
269 break;
270 }
271 free(line);
272 fclose(fp);
273
274 /* Handle errors. */
275 if (status != ARES_EOF)
276 {
277 free(servers);
278 free(sortlist);
279 return status;
280 }
281
282 /* If we got any name server entries, fill them in. */
283 if (servers)
284 {
285 channel->servers = servers;
286 channel->nservers = nservers;
287 }
288
289 /* If we got any sortlist entries, fill them in. */
290 if (sortlist)
291 {
292 channel->sortlist = sortlist;
293 channel->nsort = nsort;
294 }
295
296 return ARES_SUCCESS;
297 }
298
299 static int init_by_defaults(ares_channel channel)
300 {
301 char hostname[MAXHOSTNAMELEN + 1];
302
303 if (channel->flags == -1)
304 channel->flags = 0;
305 if (channel->timeout == -1)
306 channel->timeout = DEFAULT_TIMEOUT;
307 if (channel->tries == -1)
308 channel->tries = DEFAULT_TRIES;
309 if (channel->ndots == -1)
310 channel->ndots = 1;
311 if (channel->udp_port == -1)
312 channel->udp_port = htons(NS_DEFAULTPORT);
313 if (channel->tcp_port == -1)
314 channel->tcp_port = htons(NS_DEFAULTPORT);
315
316 if (channel->nservers == -1)
317 {
318 #ifdef WIN32
319 int buf[1024];
320 DWORD size;
321 PWSTR adapter;
322 int i;
323 int num;
324
325 size = sizeof(buf);
326 adapter = 0;
327
328 DnsQueryConfig(DnsConfigDnsServerList,FALSE,adapter,NULL,buf,&size);
329
330 // assume only IPv4 address
331 assert( size%4 == 0 );
332 num = size/4;
333 assert( num > 0 );
334
335 channel->servers = malloc( num * sizeof(struct server_state));
336 if (!channel->servers)
337 {
338 return ARES_ENOMEM;
339 }
340
341 channel->nservers = 0;
342 for ( i=0; i< num ; i++ )
343 {
344 if ( buf[i] != 1 /* loopback */ )
345 {
346 channel->servers[ channel->nservers++ ].addr.s_addr = ( buf[i] );
347 }
348 }
349
350 // channel->servers[0].addr.s_addr = inet_addr("10.0.1.1");
351 #else
352
353 /* If nobody specified servers, try a local named. */
354 channel->servers = malloc(sizeof(struct server_state));
355 if (!channel->servers)
356 return ARES_ENOMEM;
357 channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
358 channel->nservers = 1;
359 #endif
360
361 }
362
363 if (channel->ndomains == -1)
364 {
365 /* Derive a default domain search list from the kernel hostname,
366 * or set it to empty if the hostname isn't helpful.
367 */
368 if (gethostname(hostname, sizeof(hostname)) == -1
369 || !strchr(hostname, '.'))
370 {
371 channel->domains = 0; // malloc(0);
372 channel->ndomains = 0;
373 }
374 else
375 {
376 channel->domains = malloc(sizeof(char *));
377 if (!channel->domains)
378 return ARES_ENOMEM;
379 channel->ndomains = 0;
380 channel->domains[0] = strdup(strchr(hostname, '.') + 1);
381 if (!channel->domains[0])
382 return ARES_ENOMEM;
383 channel->ndomains = 1;
384 }
385 }
386
387 if (channel->nsort == -1)
388 {
389 channel->sortlist = NULL;
390 channel->nsort = 0;
391 }
392
393 if (!channel->lookups)
394 {
395 channel->lookups = strdup("bf");
396 if (!channel->lookups)
397 return ARES_ENOMEM;
398 }
399
400 return ARES_SUCCESS;
401 }
402
403 static int config_domain(ares_channel channel, char *str)
404 {
405 char *q;
406
407 /* Set a single search domain. */
408 q = str;
409 while (*q && !isspace((unsigned char)*q))
410 q++;
411 *q = 0;
412 return set_search(channel, str);
413 }
414
415 static int config_lookup(ares_channel channel, const char *str)
416 {
417 char lookups[3], *l;
418 const char *p;
419
420 /* Set the lookup order. Only the first letter of each work
421 * is relevant, and it has to be "b" for DNS or "f" for the
422 * host file. Ignore everything else.
423 */
424 l = lookups;
425 p = str;
426 while (*p)
427 {
428 if ((*p == 'b' || *p == 'f') && l < lookups + 2)
429 *l++ = *p;
430 while (*p && !isspace((unsigned char)*p))
431 p++;
432 while (isspace((unsigned char)*p))
433 p++;
434 }
435 *l = 0;
436 channel->lookups = strdup(lookups);
437 return (channel->lookups) ? ARES_SUCCESS : ARES_ENOMEM;
438 }
439
440 static int config_nameserver(struct server_state **servers, int *nservers,
441 const char *str)
442 {
443 struct in_addr addr;
444 struct server_state *newserv;
445
446 /* Add a nameserver entry, if this is a valid address. */
447 addr.s_addr = inet_addr(str);
448 if (addr.s_addr == INADDR_NONE)
449 return ARES_SUCCESS;
450 newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
451 if (!newserv)
452 return ARES_ENOMEM;
453 newserv[*nservers].addr = addr;
454 *servers = newserv;
455 (*nservers)++;
456 return ARES_SUCCESS;
457 }
458
459 static int config_sortlist(struct apattern **sortlist, int *nsort,
460 const char *str)
461 {
462 struct apattern pat, *newsort;
463 const char *q;
464
465 /* Add sortlist entries. */
466 while (*str && *str != ';')
467 {
468 q = str;
469 while (*q && *q != '/' && *q != ';' && !isspace((unsigned char)*q))
470 q++;
471 if (ip_addr(str, q - str, &pat.addr) == 0)
472 {
473 /* We have a pattern address; now determine the mask. */
474 if (*q == '/')
475 {
476 str = q + 1;
477 while (*q && *q != ';' && !isspace((unsigned char)*q))
478 q++;
479 if (ip_addr(str, q - str, &pat.mask) != 0)
480 natural_mask(&pat);
481 }
482 else
483 natural_mask(&pat);
484
485 /* Add this pattern to our list. */
486 newsort = realloc(*sortlist, (*nsort + 1) * sizeof(struct apattern));
487 if (!newsort)
488 return ARES_ENOMEM;
489 newsort[*nsort] = pat;
490 *sortlist = newsort;
491 (*nsort)++;
492 }
493 else
494 {
495 while (*q && *q != ';' && !isspace((unsigned char)*q))
496 q++;
497 }
498 str = q;
499 while (isspace((unsigned char)*str))
500 str++;
501 }
502
503 return ARES_SUCCESS;
504 }
505
506 static int set_search(ares_channel channel, const char *str)
507 {
508 int n;
509 const char *p, *q;
510
511 /* Count the domains given. */
512 n = 0;
513 p = str;
514 while (*p)
515 {
516 while (*p && !isspace((unsigned char)*p))
517 p++;
518 while (isspace((unsigned char)*p))
519 p++;
520 n++;
521 }
522
523 channel->domains = malloc(n * sizeof(char *));
524 if (!channel->domains && n)
525 return ARES_ENOMEM;
526
527 /* Now copy the domains. */
528 n = 0;
529 p = str;
530 while (*p)
531 {
532 channel->ndomains = n;
533 q = p;
534 while (*q && !isspace((unsigned char)*q))
535 q++;
536 channel->domains[n] = malloc(q - p + 1);
537 if (!channel->domains[n])
538 return ARES_ENOMEM;
539 memcpy(channel->domains[n], p, q - p);
540 channel->domains[n][q - p] = 0;
541 p = q;
542 while (isspace((unsigned char)*p))
543 p++;
544 n++;
545 }
546 channel->ndomains = n;
547
548 return ARES_SUCCESS;
549 }
550
551 static int set_options(ares_channel channel, const char *str)
552 {
553 const char *p, *q, *val;
554
555 p = str;
556 while (*p)
557 {
558 q = p;
559 while (*q && !isspace((unsigned char)*q))
560 q++;
561 val = try_option(p, q, "ndots:");
562 if (val && channel->ndots == -1)
563 channel->ndots = atoi(val);
564 val = try_option(p, q, "retrans:");
565 if (val && channel->timeout == -1)
566 channel->timeout = atoi(val);
567 val = try_option(p, q, "retry:");
568 if (val && channel->tries == -1)
569 channel->tries = atoi(val);
570 p = q;
571 while (isspace((unsigned char)*p))
572 p++;
573 }
574
575 return ARES_SUCCESS;
576 }
577
578 static char *try_config(char *s, char *opt)
579 {
580 int len;
581
582 len = strlen(opt);
583 if (strncmp(s, opt, len) != 0 || !isspace((unsigned char)s[len]))
584 return NULL;
585 s += len;
586 while (isspace((unsigned char)*s))
587 s++;
588 return s;
589 }
590
591 static const char *try_option(const char *p, const char *q, const char *opt)
592 {
593 int len;
594
595 len = strlen(opt);
596 return (q - p > len && strncmp(p, opt, len) == 0) ? p + len : NULL;
597 }
598
599 static int ip_addr(const char *s, int len, struct in_addr *addr)
600 {
601 char ipbuf[16];
602
603 /* Four octets and three periods yields at most 15 characters. */
604 if (len > 15)
605 return -1;
606 memcpy(ipbuf, s, len);
607 ipbuf[len] = 0;
608
609 addr->s_addr = inet_addr(ipbuf);
610 if (addr->s_addr == INADDR_NONE && strcmp(ipbuf, "255.255.255.255") != 0)
611 return -1;
612 return 0;
613 }
614
615 static void natural_mask(struct apattern *pat)
616 {
617 struct in_addr addr;
618
619 /* Store a host-byte-order copy of pat in a struct in_addr. Icky,
620 * but portable.
621 */
622 addr.s_addr = ntohl(pat->addr.s_addr);
623
624 /* This is out of date in the CIDR world, but some people might
625 * still rely on it.
626 */
627 if (IN_CLASSA(addr.s_addr))
628 pat->mask.s_addr = htonl(IN_CLASSA_NET);
629 else if (IN_CLASSB(addr.s_addr))
630 pat->mask.s_addr = htonl(IN_CLASSB_NET);
631 else
632 pat->mask.s_addr = htonl(IN_CLASSC_NET);
633 }

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27