]> git.ipfire.org Git - thirdparty/strongswan.git/blob - lib/liblwres/lwconfig.c
- import of strongswan-2.7.0
[thirdparty/strongswan.git] / lib / liblwres / lwconfig.c
1 /*
2 * Copyright (C) 2000, 2001 Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
9 * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
10 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
11 * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
13 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
15 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /* $Id: lwconfig.c,v 1.1 2004/03/15 20:35:25 as Exp $ */
19
20 /***
21 *** Module for parsing resolv.conf files.
22 ***
23 *** entry points are:
24 *** lwres_conf_init(lwres_context_t *ctx)
25 *** intializes data structure for subsequent config parsing.
26 ***
27 *** lwres_conf_parse(lwres_context_t *ctx, const char *filename)
28 *** parses a file and fills in the data structure.
29 ***
30 *** lwres_conf_print(lwres_context_t *ctx, FILE *fp)
31 *** prints the config data structure to the FILE.
32 ***
33 *** lwres_conf_clear(lwres_context_t *ctx)
34 *** frees up all the internal memory used by the config data
35 *** structure, returning it to the lwres_context_t.
36 ***
37 ***/
38
39 #include <config.h>
40
41 #include <assert.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 #include <lwres/lwbuffer.h>
50 #include <lwres/lwres.h>
51 #include <lwres/net.h>
52 #include <lwres/result.h>
53
54 #include "assert_p.h"
55 #include "context_p.h"
56
57
58 #if ! defined(NS_INADDRSZ)
59 #define NS_INADDRSZ 4
60 #endif
61
62 #if ! defined(NS_IN6ADDRSZ)
63 #define NS_IN6ADDRSZ 16
64 #endif
65
66 static lwres_result_t
67 lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp);
68
69 static lwres_result_t
70 lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp);
71
72 static lwres_result_t
73 lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp);
74
75 static lwres_result_t
76 lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp);
77
78 static lwres_result_t
79 lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp);
80
81 static lwres_result_t
82 lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp);
83
84 static void
85 lwres_resetaddr(lwres_addr_t *addr);
86
87 static lwres_result_t
88 lwres_create_addr(const char *buff, lwres_addr_t *addr, int convert_zero);
89
90 static int lwresaddr2af(int lwresaddrtype);
91
92
93 static int
94 lwresaddr2af(int lwresaddrtype)
95 {
96 int af = 0;
97
98 switch (lwresaddrtype) {
99 case LWRES_ADDRTYPE_V4:
100 af = AF_INET;
101 break;
102
103 case LWRES_ADDRTYPE_V6:
104 af = AF_INET6;
105 break;
106 }
107
108 return (af);
109 }
110
111
112 /*
113 * Eat characters from FP until EOL or EOF. Returns EOF or '\n'
114 */
115 static int
116 eatline(FILE *fp) {
117 int ch;
118
119 ch = fgetc(fp);
120 while (ch != '\n' && ch != EOF)
121 ch = fgetc(fp);
122
123 return (ch);
124 }
125
126
127 /*
128 * Eats white space up to next newline or non-whitespace character (of
129 * EOF). Returns the last character read. Comments are considered white
130 * space.
131 */
132 static int
133 eatwhite(FILE *fp) {
134 int ch;
135
136 ch = fgetc(fp);
137 while (ch != '\n' && ch != EOF && isspace((unsigned char)ch))
138 ch = fgetc(fp);
139
140 if (ch == ';' || ch == '#')
141 ch = eatline(fp);
142
143 return (ch);
144 }
145
146
147 /*
148 * Skip over any leading whitespace and then read in the next sequence of
149 * non-whitespace characters. In this context newline is not considered
150 * whitespace. Returns EOF on end-of-file, or the character
151 * that caused the reading to stop.
152 */
153 static int
154 getword(FILE *fp, char *buffer, size_t size) {
155 int ch;
156 char *p = buffer;
157
158 REQUIRE(buffer != NULL);
159 REQUIRE(size > 0);
160
161 *p = '\0';
162
163 ch = eatwhite(fp);
164
165 if (ch == EOF)
166 return (EOF);
167
168 do {
169 *p = '\0';
170
171 if (ch == EOF || isspace((unsigned char)ch))
172 break;
173 else if ((size_t) (p - buffer) == size - 1)
174 return (EOF); /* Not enough space. */
175
176 *p++ = (char)ch;
177 ch = fgetc(fp);
178 } while (1);
179
180 return (ch);
181 }
182
183 static void
184 lwres_resetaddr(lwres_addr_t *addr) {
185 REQUIRE(addr != NULL);
186
187 memset(addr->address, 0, LWRES_ADDR_MAXLEN);
188 addr->family = 0;
189 addr->length = 0;
190 }
191
192 static char *
193 lwres_strdup(lwres_context_t *ctx, const char *str) {
194 char *p;
195
196 REQUIRE(str != NULL);
197 REQUIRE(strlen(str) > 0);
198
199 p = CTXMALLOC(strlen(str) + 1);
200 if (p != NULL)
201 strcpy(p, str);
202
203 return (p);
204 }
205
206 void
207 lwres_conf_init(lwres_context_t *ctx) {
208 int i;
209 lwres_conf_t *confdata;
210
211 REQUIRE(ctx != NULL);
212 confdata = &ctx->confdata;
213
214 confdata->nsnext = 0;
215 confdata->lwnext = 0;
216 confdata->domainname = NULL;
217 confdata->searchnxt = 0;
218 confdata->sortlistnxt = 0;
219 confdata->resdebug = 0;
220 confdata->ndots = 1;
221 confdata->no_tld_query = 0;
222
223 for (i = 0 ; i < LWRES_CONFMAXNAMESERVERS ; i++)
224 lwres_resetaddr(&confdata->nameservers[i]);
225
226 for (i = 0 ; i < LWRES_CONFMAXSEARCH ; i++)
227 confdata->search[i] = NULL;
228
229 for (i = 0 ; i < LWRES_CONFMAXSORTLIST ; i++) {
230 lwres_resetaddr(&confdata->sortlist[i].addr);
231 lwres_resetaddr(&confdata->sortlist[i].mask);
232 }
233 }
234
235 void
236 lwres_conf_clear(lwres_context_t *ctx) {
237 int i;
238 lwres_conf_t *confdata;
239
240 REQUIRE(ctx != NULL);
241 confdata = &ctx->confdata;
242
243 for (i = 0 ; i < confdata->nsnext ; i++)
244 lwres_resetaddr(&confdata->nameservers[i]);
245
246 if (confdata->domainname != NULL) {
247 CTXFREE(confdata->domainname,
248 strlen(confdata->domainname) + 1);
249 confdata->domainname = NULL;
250 }
251
252 for (i = 0 ; i < confdata->searchnxt ; i++) {
253 if (confdata->search[i] != NULL) {
254 CTXFREE(confdata->search[i],
255 strlen(confdata->search[i]) + 1);
256 confdata->search[i] = NULL;
257 }
258 }
259
260 for (i = 0 ; i < LWRES_CONFMAXSORTLIST ; i++) {
261 lwres_resetaddr(&confdata->sortlist[i].addr);
262 lwres_resetaddr(&confdata->sortlist[i].mask);
263 }
264
265 confdata->nsnext = 0;
266 confdata->lwnext = 0;
267 confdata->domainname = NULL;
268 confdata->searchnxt = 0;
269 confdata->sortlistnxt = 0;
270 confdata->resdebug = 0;
271 confdata->ndots = 1;
272 confdata->no_tld_query = 0;
273 }
274
275 static lwres_result_t
276 lwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp) {
277 char word[LWRES_CONFMAXLINELEN];
278 int res;
279 lwres_conf_t *confdata;
280
281 confdata = &ctx->confdata;
282
283 if (confdata->nsnext == LWRES_CONFMAXNAMESERVERS)
284 return (LWRES_R_SUCCESS);
285
286 res = getword(fp, word, sizeof(word));
287 if (strlen(word) == 0)
288 return (LWRES_R_FAILURE); /* Nothing on line. */
289 else if (res == ' ' || res == '\t')
290 res = eatwhite(fp);
291
292 if (res != EOF && res != '\n')
293 return (LWRES_R_FAILURE); /* Extra junk on line. */
294
295 res = lwres_create_addr(word,
296 &confdata->nameservers[confdata->nsnext++], 1);
297 if (res != LWRES_R_SUCCESS)
298 return (res);
299
300 return (LWRES_R_SUCCESS);
301 }
302
303 static lwres_result_t
304 lwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp) {
305 char word[LWRES_CONFMAXLINELEN];
306 int res;
307 lwres_conf_t *confdata;
308
309 confdata = &ctx->confdata;
310
311 if (confdata->lwnext == LWRES_CONFMAXLWSERVERS)
312 return (LWRES_R_SUCCESS);
313
314 res = getword(fp, word, sizeof(word));
315 if (strlen(word) == 0)
316 return (LWRES_R_FAILURE); /* Nothing on line. */
317 else if (res == ' ' || res == '\t')
318 res = eatwhite(fp);
319
320 if (res != EOF && res != '\n')
321 return (LWRES_R_FAILURE); /* Extra junk on line. */
322
323 res = lwres_create_addr(word,
324 &confdata->lwservers[confdata->lwnext++], 1);
325 if (res != LWRES_R_SUCCESS)
326 return (res);
327
328 return (LWRES_R_SUCCESS);
329 }
330
331 static lwres_result_t
332 lwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp) {
333 char word[LWRES_CONFMAXLINELEN];
334 int res, i;
335 lwres_conf_t *confdata;
336
337 confdata = &ctx->confdata;
338
339 res = getword(fp, word, sizeof(word));
340 if (strlen(word) == 0)
341 return (LWRES_R_FAILURE); /* Nothing else on line. */
342 else if (res == ' ' || res == '\t')
343 res = eatwhite(fp);
344
345 if (res != EOF && res != '\n')
346 return (LWRES_R_FAILURE); /* Extra junk on line. */
347
348 if (confdata->domainname != NULL)
349 CTXFREE(confdata->domainname,
350 strlen(confdata->domainname) + 1); /* */
351
352 /*
353 * Search and domain are mutually exclusive.
354 */
355 for (i = 0 ; i < LWRES_CONFMAXSEARCH ; i++) {
356 if (confdata->search[i] != NULL) {
357 CTXFREE(confdata->search[i],
358 strlen(confdata->search[i])+1);
359 confdata->search[i] = NULL;
360 }
361 }
362 confdata->searchnxt = 0;
363
364 confdata->domainname = lwres_strdup(ctx, word);
365
366 if (confdata->domainname == NULL)
367 return (LWRES_R_FAILURE);
368
369 return (LWRES_R_SUCCESS);
370 }
371
372 static lwres_result_t
373 lwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp) {
374 int idx, delim;
375 char word[LWRES_CONFMAXLINELEN];
376 lwres_conf_t *confdata;
377
378 confdata = &ctx->confdata;
379
380 if (confdata->domainname != NULL) {
381 /*
382 * Search and domain are mutually exclusive.
383 */
384 CTXFREE(confdata->domainname,
385 strlen(confdata->domainname) + 1);
386 confdata->domainname = NULL;
387 }
388
389 /*
390 * Remove any previous search definitions.
391 */
392 for (idx = 0 ; idx < LWRES_CONFMAXSEARCH ; idx++) {
393 if (confdata->search[idx] != NULL) {
394 CTXFREE(confdata->search[idx],
395 strlen(confdata->search[idx])+1);
396 confdata->search[idx] = NULL;
397 }
398 }
399 confdata->searchnxt = 0;
400
401 delim = getword(fp, word, sizeof(word));
402 if (strlen(word) == 0)
403 return (LWRES_R_FAILURE); /* Nothing else on line. */
404
405 idx = 0;
406 while (strlen(word) > 0) {
407 if (confdata->searchnxt == LWRES_CONFMAXSEARCH)
408 goto ignore; /* Too many domains. */
409
410 confdata->search[idx] = lwres_strdup(ctx, word);
411 if (confdata->search[idx] == NULL)
412 return (LWRES_R_FAILURE);
413 idx++;
414 confdata->searchnxt++;
415
416 ignore:
417 if (delim == EOF || delim == '\n')
418 break;
419 else
420 delim = getword(fp, word, sizeof(word));
421 }
422
423 return (LWRES_R_SUCCESS);
424 }
425
426 static lwres_result_t
427 lwres_create_addr(const char *buffer, lwres_addr_t *addr, int convert_zero) {
428 struct in_addr v4;
429 struct in6_addr v6;
430
431 if (lwres_net_aton(buffer, &v4) == 1) {
432 if (convert_zero) {
433 unsigned char zeroaddress[] = {0, 0, 0, 0};
434 unsigned char loopaddress[] = {127, 0, 0, 1};
435 if (memcmp(&v4, zeroaddress, 4) == 0)
436 memcpy(&v4, loopaddress, 4);
437 }
438 addr->family = LWRES_ADDRTYPE_V4;
439 addr->length = NS_INADDRSZ;
440 memcpy((void *)addr->address, &v4, NS_INADDRSZ);
441
442 } else if (lwres_net_pton(AF_INET6, buffer, &v6) == 1) {
443 addr->family = LWRES_ADDRTYPE_V6;
444 addr->length = NS_IN6ADDRSZ;
445 memcpy((void *)addr->address, &v6, NS_IN6ADDRSZ);
446 } else {
447 return (LWRES_R_FAILURE); /* Unrecognised format. */
448 }
449
450 return (LWRES_R_SUCCESS);
451 }
452
453 static lwres_result_t
454 lwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp) {
455 int delim, res, idx;
456 char word[LWRES_CONFMAXLINELEN];
457 char *p;
458 lwres_conf_t *confdata;
459
460 confdata = &ctx->confdata;
461
462 delim = getword(fp, word, sizeof(word));
463 if (strlen(word) == 0)
464 return (LWRES_R_FAILURE); /* Empty line after keyword. */
465
466 while (strlen(word) > 0) {
467 if (confdata->sortlistnxt == LWRES_CONFMAXSORTLIST)
468 return (LWRES_R_FAILURE); /* Too many values. */
469
470 p = strchr(word, '/');
471 if (p != NULL)
472 *p++ = '\0';
473
474 idx = confdata->sortlistnxt;
475 res = lwres_create_addr(word, &confdata->sortlist[idx].addr, 1);
476 if (res != LWRES_R_SUCCESS)
477 return (res);
478
479 if (p != NULL) {
480 res = lwres_create_addr(p,
481 &confdata->sortlist[idx].mask,
482 0);
483 if (res != LWRES_R_SUCCESS)
484 return (res);
485 } else {
486 /*
487 * Make up a mask.
488 */
489 confdata->sortlist[idx].mask =
490 confdata->sortlist[idx].addr;
491
492 memset(&confdata->sortlist[idx].mask.address, 0xff,
493 confdata->sortlist[idx].addr.length);
494 }
495
496 confdata->sortlistnxt++;
497
498 if (delim == EOF || delim == '\n')
499 break;
500 else
501 delim = getword(fp, word, sizeof(word));
502 }
503
504 return (LWRES_R_SUCCESS);
505 }
506
507 static lwres_result_t
508 lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp) {
509 int delim;
510 long ndots;
511 char *p;
512 char word[LWRES_CONFMAXLINELEN];
513 lwres_conf_t *confdata;
514
515 REQUIRE(ctx != NULL);
516 confdata = &ctx->confdata;
517
518 delim = getword(fp, word, sizeof(word));
519 if (strlen(word) == 0)
520 return (LWRES_R_FAILURE); /* Empty line after keyword. */
521
522 while (strlen(word) > 0) {
523 if (strcmp("debug", word) == 0) {
524 confdata->resdebug = 1;
525 } else if (strcmp("no_tld_query", word) == 0) {
526 confdata->no_tld_query = 1;
527 } else if (strncmp("ndots:", word, 6) == 0) {
528 ndots = strtol(word + 6, &p, 10);
529 if (*p != '\0') /* Bad string. */
530 return (LWRES_R_FAILURE);
531 if (ndots < 0 || ndots > 0xff) /* Out of range. */
532 return (LWRES_R_FAILURE);
533 confdata->ndots = (lwres_uint8_t)ndots;
534 }
535
536 if (delim == EOF || delim == '\n')
537 break;
538 else
539 delim = getword(fp, word, sizeof(word));
540 }
541
542 return (LWRES_R_SUCCESS);
543 }
544
545 lwres_result_t
546 lwres_conf_parse(lwres_context_t *ctx, const char *filename) {
547 FILE *fp = NULL;
548 char word[256];
549 lwres_result_t rval, ret;
550 lwres_conf_t *confdata;
551 int stopchar;
552
553 REQUIRE(ctx != NULL);
554 confdata = &ctx->confdata;
555
556 REQUIRE(filename != NULL);
557 REQUIRE(strlen(filename) > 0);
558 REQUIRE(confdata != NULL);
559
560 errno = 0;
561 if ((fp = fopen(filename, "r")) == NULL)
562 return (LWRES_R_FAILURE);
563
564 ret = LWRES_R_SUCCESS;
565 do {
566 stopchar = getword(fp, word, sizeof(word));
567 if (stopchar == EOF) {
568 rval = LWRES_R_SUCCESS;
569 break;
570 }
571
572 if (strlen(word) == 0)
573 rval = LWRES_R_SUCCESS;
574 else if (strcmp(word, "nameserver") == 0)
575 rval = lwres_conf_parsenameserver(ctx, fp);
576 else if (strcmp(word, "lwserver") == 0)
577 rval = lwres_conf_parselwserver(ctx, fp);
578 else if (strcmp(word, "domain") == 0)
579 rval = lwres_conf_parsedomain(ctx, fp);
580 else if (strcmp(word, "search") == 0)
581 rval = lwres_conf_parsesearch(ctx, fp);
582 else if (strcmp(word, "sortlist") == 0)
583 rval = lwres_conf_parsesortlist(ctx, fp);
584 else if (strcmp(word, "option") == 0)
585 rval = lwres_conf_parseoption(ctx, fp);
586 else {
587 /* unrecognised word. Ignore entire line */
588 rval = LWRES_R_SUCCESS;
589 stopchar = eatline(fp);
590 if (stopchar == EOF) {
591 break;
592 }
593 }
594 if (ret == LWRES_R_SUCCESS && rval != LWRES_R_SUCCESS)
595 ret = rval;
596 } while (1);
597
598 fclose(fp);
599
600 return (ret);
601 }
602
603 lwres_result_t
604 lwres_conf_print(lwres_context_t *ctx, FILE *fp) {
605 int i;
606 int af;
607 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
608 const char *p;
609 lwres_conf_t *confdata;
610 lwres_addr_t tmpaddr;
611
612 REQUIRE(ctx != NULL);
613 confdata = &ctx->confdata;
614
615 REQUIRE(confdata->nsnext <= LWRES_CONFMAXNAMESERVERS);
616
617 for (i = 0 ; i < confdata->nsnext ; i++) {
618 af = lwresaddr2af(confdata->nameservers[i].family);
619
620 p = lwres_net_ntop(af, confdata->nameservers[i].address,
621 tmp, sizeof(tmp));
622 if (p != tmp)
623 return (LWRES_R_FAILURE);
624
625 fprintf(fp, "nameserver %s\n", tmp);
626 }
627
628 for (i = 0 ; i < confdata->lwnext ; i++) {
629 af = lwresaddr2af(confdata->lwservers[i].family);
630
631 p = lwres_net_ntop(af, confdata->lwservers[i].address,
632 tmp, sizeof(tmp));
633 if (p != tmp)
634 return (LWRES_R_FAILURE);
635
636 fprintf(fp, "lwserver %s\n", tmp);
637 }
638
639 if (confdata->domainname != NULL) {
640 fprintf(fp, "domain %s\n", confdata->domainname);
641 } else if (confdata->searchnxt > 0) {
642 REQUIRE(confdata->searchnxt <= LWRES_CONFMAXSEARCH);
643
644 fprintf(fp, "search");
645 for (i = 0 ; i < confdata->searchnxt ; i++)
646 fprintf(fp, " %s", confdata->search[i]);
647 fputc('\n', fp);
648 }
649
650 REQUIRE(confdata->sortlistnxt <= LWRES_CONFMAXSORTLIST);
651
652 if (confdata->sortlistnxt > 0) {
653 fputs("sortlist", fp);
654 for (i = 0 ; i < confdata->sortlistnxt ; i++) {
655 af = lwresaddr2af(confdata->sortlist[i].addr.family);
656
657 p = lwres_net_ntop(af,
658 confdata->sortlist[i].addr.address,
659 tmp, sizeof(tmp));
660 if (p != tmp)
661 return (LWRES_R_FAILURE);
662
663 fprintf(fp, " %s", tmp);
664
665 tmpaddr = confdata->sortlist[i].mask;
666 memset(&tmpaddr.address, 0xff, tmpaddr.length);
667
668 if (memcmp(&tmpaddr.address,
669 confdata->sortlist[i].mask.address,
670 confdata->sortlist[i].mask.length) != 0) {
671 af = lwresaddr2af(
672 confdata->sortlist[i].mask.family);
673 p = lwres_net_ntop
674 (af,
675 confdata->sortlist[i].mask.address,
676 tmp, sizeof(tmp));
677 if (p != tmp)
678 return (LWRES_R_FAILURE);
679
680 fprintf(fp, "/%s", tmp);
681 }
682 }
683 fputc('\n', fp);
684 }
685
686 if (confdata->resdebug)
687 fprintf(fp, "options debug\n");
688
689 if (confdata->ndots > 0)
690 fprintf(fp, "options ndots:%d\n", confdata->ndots);
691
692 if (confdata->no_tld_query)
693 fprintf(fp, "options no_tld_query\n");
694
695 return (LWRES_R_SUCCESS);
696 }
697
698 lwres_conf_t *
699 lwres_conf_get(lwres_context_t *ctx) {
700 REQUIRE(ctx != NULL);
701
702 return (&ctx->confdata);
703 }