1135446Strhodes/* 2262706Serwin * Copyright (C) 2004-2008, 2011, 2012, 2014 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 2000-2003 Internet Software Consortium. 4135446Strhodes * 5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18234010Sdougb/* $Id$ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21135446Strhodes 22170222Sdougb/** 23170222Sdougb * Module for parsing resolv.conf files. 24170222Sdougb * 25170222Sdougb * lwres_conf_init() creates an empty lwres_conf_t structure for 26170222Sdougb * lightweight resolver context ctx. 27193149Sdougb * 28170222Sdougb * lwres_conf_clear() frees up all the internal memory used by that 29170222Sdougb * lwres_conf_t structure in resolver context ctx. 30193149Sdougb * 31170222Sdougb * lwres_conf_parse() opens the file filename and parses it to initialise 32170222Sdougb * the resolver context ctx's lwres_conf_t structure. 33193149Sdougb * 34170222Sdougb * lwres_conf_print() prints the lwres_conf_t structure for resolver 35170222Sdougb * context ctx to the FILE fp. 36193149Sdougb * 37170222Sdougb * \section lwconfig_return Return Values 38193149Sdougb * 39170222Sdougb * lwres_conf_parse() returns #LWRES_R_SUCCESS if it successfully read and 40170222Sdougb * parsed filename. It returns #LWRES_R_FAILURE if filename could not be 41170222Sdougb * opened or contained incorrect resolver statements. 42193149Sdougb * 43170222Sdougb * lwres_conf_print() returns #LWRES_R_SUCCESS unless an error occurred 44170222Sdougb * when converting the network addresses to a numeric host address 45170222Sdougb * string. If this happens, the function returns #LWRES_R_FAILURE. 46193149Sdougb * 47170222Sdougb * \section lwconfig_see See Also 48193149Sdougb * 49170222Sdougb * stdio(3), \link resolver resolver \endlink 50193149Sdougb * 51170222Sdougb * \section files Files 52193149Sdougb * 53170222Sdougb * /etc/resolv.conf 54170222Sdougb */ 55170222Sdougb 56135446Strhodes#include <config.h> 57135446Strhodes 58135446Strhodes#include <assert.h> 59135446Strhodes#include <ctype.h> 60135446Strhodes#include <errno.h> 61135446Strhodes#include <stdlib.h> 62135446Strhodes#include <stdio.h> 63135446Strhodes#include <string.h> 64135446Strhodes#include <unistd.h> 65135446Strhodes 66135446Strhodes#include <lwres/lwbuffer.h> 67135446Strhodes#include <lwres/lwres.h> 68135446Strhodes#include <lwres/net.h> 69135446Strhodes#include <lwres/result.h> 70135446Strhodes 71135446Strhodes#include "assert_p.h" 72135446Strhodes#include "context_p.h" 73135446Strhodes 74135446Strhodes 75135446Strhodes#if ! defined(NS_INADDRSZ) 76135446Strhodes#define NS_INADDRSZ 4 77135446Strhodes#endif 78135446Strhodes 79135446Strhodes#if ! defined(NS_IN6ADDRSZ) 80135446Strhodes#define NS_IN6ADDRSZ 16 81135446Strhodes#endif 82135446Strhodes 83135446Strhodesstatic lwres_result_t 84135446Strhodeslwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp); 85135446Strhodes 86135446Strhodesstatic lwres_result_t 87135446Strhodeslwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp); 88135446Strhodes 89135446Strhodesstatic lwres_result_t 90135446Strhodeslwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp); 91135446Strhodes 92135446Strhodesstatic lwres_result_t 93135446Strhodeslwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp); 94135446Strhodes 95135446Strhodesstatic lwres_result_t 96135446Strhodeslwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp); 97135446Strhodes 98135446Strhodesstatic lwres_result_t 99135446Strhodeslwres_conf_parseoption(lwres_context_t *ctx, FILE *fp); 100135446Strhodes 101135446Strhodesstatic void 102135446Strhodeslwres_resetaddr(lwres_addr_t *addr); 103135446Strhodes 104135446Strhodesstatic lwres_result_t 105135446Strhodeslwres_create_addr(const char *buff, lwres_addr_t *addr, int convert_zero); 106135446Strhodes 107135446Strhodesstatic int lwresaddr2af(int lwresaddrtype); 108135446Strhodes 109135446Strhodes 110135446Strhodesstatic int 111135446Strhodeslwresaddr2af(int lwresaddrtype) 112135446Strhodes{ 113135446Strhodes int af = 0; 114135446Strhodes 115135446Strhodes switch (lwresaddrtype) { 116135446Strhodes case LWRES_ADDRTYPE_V4: 117135446Strhodes af = AF_INET; 118135446Strhodes break; 119135446Strhodes 120135446Strhodes case LWRES_ADDRTYPE_V6: 121135446Strhodes af = AF_INET6; 122135446Strhodes break; 123135446Strhodes } 124135446Strhodes 125135446Strhodes return (af); 126135446Strhodes} 127135446Strhodes 128135446Strhodes 129170222Sdougb/*! 130135446Strhodes * Eat characters from FP until EOL or EOF. Returns EOF or '\n' 131135446Strhodes */ 132135446Strhodesstatic int 133135446Strhodeseatline(FILE *fp) { 134135446Strhodes int ch; 135135446Strhodes 136135446Strhodes ch = fgetc(fp); 137135446Strhodes while (ch != '\n' && ch != EOF) 138135446Strhodes ch = fgetc(fp); 139135446Strhodes 140135446Strhodes return (ch); 141135446Strhodes} 142135446Strhodes 143135446Strhodes 144170222Sdougb/*! 145135446Strhodes * Eats white space up to next newline or non-whitespace character (of 146135446Strhodes * EOF). Returns the last character read. Comments are considered white 147135446Strhodes * space. 148135446Strhodes */ 149135446Strhodesstatic int 150135446Strhodeseatwhite(FILE *fp) { 151135446Strhodes int ch; 152135446Strhodes 153135446Strhodes ch = fgetc(fp); 154135446Strhodes while (ch != '\n' && ch != EOF && isspace((unsigned char)ch)) 155135446Strhodes ch = fgetc(fp); 156135446Strhodes 157135446Strhodes if (ch == ';' || ch == '#') 158135446Strhodes ch = eatline(fp); 159135446Strhodes 160135446Strhodes return (ch); 161135446Strhodes} 162135446Strhodes 163135446Strhodes 164170222Sdougb/*! 165135446Strhodes * Skip over any leading whitespace and then read in the next sequence of 166135446Strhodes * non-whitespace characters. In this context newline is not considered 167135446Strhodes * whitespace. Returns EOF on end-of-file, or the character 168135446Strhodes * that caused the reading to stop. 169135446Strhodes */ 170135446Strhodesstatic int 171135446Strhodesgetword(FILE *fp, char *buffer, size_t size) { 172135446Strhodes int ch; 173135446Strhodes char *p = buffer; 174135446Strhodes 175135446Strhodes REQUIRE(buffer != NULL); 176135446Strhodes REQUIRE(size > 0U); 177135446Strhodes 178135446Strhodes *p = '\0'; 179135446Strhodes 180135446Strhodes ch = eatwhite(fp); 181135446Strhodes 182135446Strhodes if (ch == EOF) 183135446Strhodes return (EOF); 184135446Strhodes 185135446Strhodes do { 186135446Strhodes *p = '\0'; 187135446Strhodes 188135446Strhodes if (ch == EOF || isspace((unsigned char)ch)) 189135446Strhodes break; 190135446Strhodes else if ((size_t) (p - buffer) == size - 1) 191135446Strhodes return (EOF); /* Not enough space. */ 192135446Strhodes 193135446Strhodes *p++ = (char)ch; 194135446Strhodes ch = fgetc(fp); 195135446Strhodes } while (1); 196135446Strhodes 197135446Strhodes return (ch); 198135446Strhodes} 199135446Strhodes 200135446Strhodesstatic void 201135446Strhodeslwres_resetaddr(lwres_addr_t *addr) { 202135446Strhodes REQUIRE(addr != NULL); 203135446Strhodes 204135446Strhodes memset(addr->address, 0, LWRES_ADDR_MAXLEN); 205135446Strhodes addr->family = 0; 206135446Strhodes addr->length = 0; 207135446Strhodes} 208135446Strhodes 209135446Strhodesstatic char * 210135446Strhodeslwres_strdup(lwres_context_t *ctx, const char *str) { 211135446Strhodes char *p; 212135446Strhodes 213135446Strhodes REQUIRE(str != NULL); 214135446Strhodes REQUIRE(strlen(str) > 0U); 215135446Strhodes 216135446Strhodes p = CTXMALLOC(strlen(str) + 1); 217135446Strhodes if (p != NULL) 218135446Strhodes strcpy(p, str); 219135446Strhodes 220135446Strhodes return (p); 221135446Strhodes} 222135446Strhodes 223170222Sdougb/*% intializes data structure for subsequent config parsing. */ 224135446Strhodesvoid 225135446Strhodeslwres_conf_init(lwres_context_t *ctx) { 226135446Strhodes int i; 227135446Strhodes lwres_conf_t *confdata; 228135446Strhodes 229135446Strhodes REQUIRE(ctx != NULL); 230135446Strhodes confdata = &ctx->confdata; 231135446Strhodes 232135446Strhodes confdata->nsnext = 0; 233135446Strhodes confdata->lwnext = 0; 234135446Strhodes confdata->domainname = NULL; 235135446Strhodes confdata->searchnxt = 0; 236135446Strhodes confdata->sortlistnxt = 0; 237135446Strhodes confdata->resdebug = 0; 238135446Strhodes confdata->ndots = 1; 239135446Strhodes confdata->no_tld_query = 0; 240135446Strhodes 241135446Strhodes for (i = 0; i < LWRES_CONFMAXNAMESERVERS; i++) 242135446Strhodes lwres_resetaddr(&confdata->nameservers[i]); 243135446Strhodes 244135446Strhodes for (i = 0; i < LWRES_CONFMAXSEARCH; i++) 245135446Strhodes confdata->search[i] = NULL; 246135446Strhodes 247135446Strhodes for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) { 248135446Strhodes lwres_resetaddr(&confdata->sortlist[i].addr); 249135446Strhodes lwres_resetaddr(&confdata->sortlist[i].mask); 250135446Strhodes } 251135446Strhodes} 252135446Strhodes 253170222Sdougb/*% Frees up all the internal memory used by the config data structure, returning it to the lwres_context_t. */ 254135446Strhodesvoid 255135446Strhodeslwres_conf_clear(lwres_context_t *ctx) { 256135446Strhodes int i; 257135446Strhodes lwres_conf_t *confdata; 258135446Strhodes 259135446Strhodes REQUIRE(ctx != NULL); 260135446Strhodes confdata = &ctx->confdata; 261135446Strhodes 262135446Strhodes for (i = 0; i < confdata->nsnext; i++) 263135446Strhodes lwres_resetaddr(&confdata->nameservers[i]); 264135446Strhodes 265135446Strhodes if (confdata->domainname != NULL) { 266135446Strhodes CTXFREE(confdata->domainname, 267135446Strhodes strlen(confdata->domainname) + 1); 268135446Strhodes confdata->domainname = NULL; 269135446Strhodes } 270135446Strhodes 271135446Strhodes for (i = 0; i < confdata->searchnxt; i++) { 272135446Strhodes if (confdata->search[i] != NULL) { 273135446Strhodes CTXFREE(confdata->search[i], 274135446Strhodes strlen(confdata->search[i]) + 1); 275135446Strhodes confdata->search[i] = NULL; 276135446Strhodes } 277135446Strhodes } 278135446Strhodes 279135446Strhodes for (i = 0; i < LWRES_CONFMAXSORTLIST; i++) { 280135446Strhodes lwres_resetaddr(&confdata->sortlist[i].addr); 281135446Strhodes lwres_resetaddr(&confdata->sortlist[i].mask); 282135446Strhodes } 283135446Strhodes 284135446Strhodes confdata->nsnext = 0; 285135446Strhodes confdata->lwnext = 0; 286135446Strhodes confdata->domainname = NULL; 287135446Strhodes confdata->searchnxt = 0; 288135446Strhodes confdata->sortlistnxt = 0; 289135446Strhodes confdata->resdebug = 0; 290135446Strhodes confdata->ndots = 1; 291135446Strhodes confdata->no_tld_query = 0; 292135446Strhodes} 293135446Strhodes 294135446Strhodesstatic lwres_result_t 295135446Strhodeslwres_conf_parsenameserver(lwres_context_t *ctx, FILE *fp) { 296135446Strhodes char word[LWRES_CONFMAXLINELEN]; 297135446Strhodes int res; 298135446Strhodes lwres_conf_t *confdata; 299153816Sdougb lwres_addr_t address; 300135446Strhodes 301135446Strhodes confdata = &ctx->confdata; 302135446Strhodes 303135446Strhodes if (confdata->nsnext == LWRES_CONFMAXNAMESERVERS) 304135446Strhodes return (LWRES_R_SUCCESS); 305135446Strhodes 306135446Strhodes res = getword(fp, word, sizeof(word)); 307135446Strhodes if (strlen(word) == 0U) 308135446Strhodes return (LWRES_R_FAILURE); /* Nothing on line. */ 309135446Strhodes else if (res == ' ' || res == '\t') 310135446Strhodes res = eatwhite(fp); 311135446Strhodes 312135446Strhodes if (res != EOF && res != '\n') 313135446Strhodes return (LWRES_R_FAILURE); /* Extra junk on line. */ 314135446Strhodes 315153816Sdougb res = lwres_create_addr(word, &address, 1); 316193149Sdougb if (res == LWRES_R_SUCCESS && 317193149Sdougb ((address.family == LWRES_ADDRTYPE_V4 && ctx->use_ipv4 == 1) || 318193149Sdougb (address.family == LWRES_ADDRTYPE_V6 && ctx->use_ipv6 == 1))) { 319153816Sdougb confdata->nameservers[confdata->nsnext++] = address; 320193149Sdougb } 321135446Strhodes 322135446Strhodes return (LWRES_R_SUCCESS); 323135446Strhodes} 324135446Strhodes 325135446Strhodesstatic lwres_result_t 326135446Strhodeslwres_conf_parselwserver(lwres_context_t *ctx, FILE *fp) { 327135446Strhodes char word[LWRES_CONFMAXLINELEN]; 328135446Strhodes int res; 329135446Strhodes lwres_conf_t *confdata; 330135446Strhodes 331135446Strhodes confdata = &ctx->confdata; 332135446Strhodes 333135446Strhodes if (confdata->lwnext == LWRES_CONFMAXLWSERVERS) 334135446Strhodes return (LWRES_R_SUCCESS); 335135446Strhodes 336135446Strhodes res = getword(fp, word, sizeof(word)); 337135446Strhodes if (strlen(word) == 0U) 338135446Strhodes return (LWRES_R_FAILURE); /* Nothing on line. */ 339135446Strhodes else if (res == ' ' || res == '\t') 340135446Strhodes res = eatwhite(fp); 341135446Strhodes 342135446Strhodes if (res != EOF && res != '\n') 343135446Strhodes return (LWRES_R_FAILURE); /* Extra junk on line. */ 344135446Strhodes 345135446Strhodes res = lwres_create_addr(word, 346135446Strhodes &confdata->lwservers[confdata->lwnext++], 1); 347135446Strhodes if (res != LWRES_R_SUCCESS) 348135446Strhodes return (res); 349135446Strhodes 350135446Strhodes return (LWRES_R_SUCCESS); 351135446Strhodes} 352135446Strhodes 353135446Strhodesstatic lwres_result_t 354135446Strhodeslwres_conf_parsedomain(lwres_context_t *ctx, FILE *fp) { 355135446Strhodes char word[LWRES_CONFMAXLINELEN]; 356135446Strhodes int res, i; 357135446Strhodes lwres_conf_t *confdata; 358135446Strhodes 359135446Strhodes confdata = &ctx->confdata; 360135446Strhodes 361135446Strhodes res = getword(fp, word, sizeof(word)); 362135446Strhodes if (strlen(word) == 0U) 363135446Strhodes return (LWRES_R_FAILURE); /* Nothing else on line. */ 364135446Strhodes else if (res == ' ' || res == '\t') 365135446Strhodes res = eatwhite(fp); 366135446Strhodes 367135446Strhodes if (res != EOF && res != '\n') 368135446Strhodes return (LWRES_R_FAILURE); /* Extra junk on line. */ 369135446Strhodes 370135446Strhodes if (confdata->domainname != NULL) 371135446Strhodes CTXFREE(confdata->domainname, 372135446Strhodes strlen(confdata->domainname) + 1); /* */ 373135446Strhodes 374135446Strhodes /* 375135446Strhodes * Search and domain are mutually exclusive. 376135446Strhodes */ 377135446Strhodes for (i = 0; i < LWRES_CONFMAXSEARCH; i++) { 378135446Strhodes if (confdata->search[i] != NULL) { 379135446Strhodes CTXFREE(confdata->search[i], 380135446Strhodes strlen(confdata->search[i])+1); 381135446Strhodes confdata->search[i] = NULL; 382135446Strhodes } 383135446Strhodes } 384135446Strhodes confdata->searchnxt = 0; 385135446Strhodes 386135446Strhodes confdata->domainname = lwres_strdup(ctx, word); 387135446Strhodes 388135446Strhodes if (confdata->domainname == NULL) 389135446Strhodes return (LWRES_R_FAILURE); 390135446Strhodes 391135446Strhodes return (LWRES_R_SUCCESS); 392135446Strhodes} 393135446Strhodes 394135446Strhodesstatic lwres_result_t 395135446Strhodeslwres_conf_parsesearch(lwres_context_t *ctx, FILE *fp) { 396135446Strhodes int idx, delim; 397135446Strhodes char word[LWRES_CONFMAXLINELEN]; 398135446Strhodes lwres_conf_t *confdata; 399135446Strhodes 400135446Strhodes confdata = &ctx->confdata; 401135446Strhodes 402135446Strhodes if (confdata->domainname != NULL) { 403135446Strhodes /* 404135446Strhodes * Search and domain are mutually exclusive. 405135446Strhodes */ 406135446Strhodes CTXFREE(confdata->domainname, 407135446Strhodes strlen(confdata->domainname) + 1); 408135446Strhodes confdata->domainname = NULL; 409135446Strhodes } 410135446Strhodes 411135446Strhodes /* 412135446Strhodes * Remove any previous search definitions. 413135446Strhodes */ 414135446Strhodes for (idx = 0; idx < LWRES_CONFMAXSEARCH; idx++) { 415135446Strhodes if (confdata->search[idx] != NULL) { 416135446Strhodes CTXFREE(confdata->search[idx], 417135446Strhodes strlen(confdata->search[idx])+1); 418135446Strhodes confdata->search[idx] = NULL; 419135446Strhodes } 420135446Strhodes } 421135446Strhodes confdata->searchnxt = 0; 422135446Strhodes 423135446Strhodes delim = getword(fp, word, sizeof(word)); 424135446Strhodes if (strlen(word) == 0U) 425135446Strhodes return (LWRES_R_FAILURE); /* Nothing else on line. */ 426135446Strhodes 427135446Strhodes idx = 0; 428135446Strhodes while (strlen(word) > 0U) { 429135446Strhodes if (confdata->searchnxt == LWRES_CONFMAXSEARCH) 430135446Strhodes goto ignore; /* Too many domains. */ 431135446Strhodes 432135446Strhodes confdata->search[idx] = lwres_strdup(ctx, word); 433135446Strhodes if (confdata->search[idx] == NULL) 434135446Strhodes return (LWRES_R_FAILURE); 435135446Strhodes idx++; 436135446Strhodes confdata->searchnxt++; 437135446Strhodes 438135446Strhodes ignore: 439135446Strhodes if (delim == EOF || delim == '\n') 440135446Strhodes break; 441135446Strhodes else 442135446Strhodes delim = getword(fp, word, sizeof(word)); 443135446Strhodes } 444135446Strhodes 445135446Strhodes return (LWRES_R_SUCCESS); 446135446Strhodes} 447135446Strhodes 448135446Strhodesstatic lwres_result_t 449135446Strhodeslwres_create_addr(const char *buffer, lwres_addr_t *addr, int convert_zero) { 450135446Strhodes struct in_addr v4; 451135446Strhodes struct in6_addr v6; 452135446Strhodes 453135446Strhodes if (lwres_net_aton(buffer, &v4) == 1) { 454135446Strhodes if (convert_zero) { 455135446Strhodes unsigned char zeroaddress[] = {0, 0, 0, 0}; 456135446Strhodes unsigned char loopaddress[] = {127, 0, 0, 1}; 457135446Strhodes if (memcmp(&v4, zeroaddress, 4) == 0) 458262706Serwin memmove(&v4, loopaddress, 4); 459135446Strhodes } 460135446Strhodes addr->family = LWRES_ADDRTYPE_V4; 461135446Strhodes addr->length = NS_INADDRSZ; 462262706Serwin memmove((void *)addr->address, &v4, NS_INADDRSZ); 463135446Strhodes 464135446Strhodes } else if (lwres_net_pton(AF_INET6, buffer, &v6) == 1) { 465135446Strhodes addr->family = LWRES_ADDRTYPE_V6; 466135446Strhodes addr->length = NS_IN6ADDRSZ; 467262706Serwin memmove((void *)addr->address, &v6, NS_IN6ADDRSZ); 468135446Strhodes } else { 469135446Strhodes return (LWRES_R_FAILURE); /* Unrecognised format. */ 470135446Strhodes } 471135446Strhodes 472135446Strhodes return (LWRES_R_SUCCESS); 473135446Strhodes} 474135446Strhodes 475135446Strhodesstatic lwres_result_t 476135446Strhodeslwres_conf_parsesortlist(lwres_context_t *ctx, FILE *fp) { 477135446Strhodes int delim, res, idx; 478135446Strhodes char word[LWRES_CONFMAXLINELEN]; 479135446Strhodes char *p; 480135446Strhodes lwres_conf_t *confdata; 481135446Strhodes 482135446Strhodes confdata = &ctx->confdata; 483135446Strhodes 484135446Strhodes delim = getword(fp, word, sizeof(word)); 485135446Strhodes if (strlen(word) == 0U) 486135446Strhodes return (LWRES_R_FAILURE); /* Empty line after keyword. */ 487135446Strhodes 488135446Strhodes while (strlen(word) > 0U) { 489135446Strhodes if (confdata->sortlistnxt == LWRES_CONFMAXSORTLIST) 490135446Strhodes return (LWRES_R_FAILURE); /* Too many values. */ 491135446Strhodes 492135446Strhodes p = strchr(word, '/'); 493135446Strhodes if (p != NULL) 494135446Strhodes *p++ = '\0'; 495135446Strhodes 496135446Strhodes idx = confdata->sortlistnxt; 497135446Strhodes res = lwres_create_addr(word, &confdata->sortlist[idx].addr, 1); 498135446Strhodes if (res != LWRES_R_SUCCESS) 499135446Strhodes return (res); 500135446Strhodes 501135446Strhodes if (p != NULL) { 502135446Strhodes res = lwres_create_addr(p, 503135446Strhodes &confdata->sortlist[idx].mask, 504135446Strhodes 0); 505135446Strhodes if (res != LWRES_R_SUCCESS) 506135446Strhodes return (res); 507135446Strhodes } else { 508135446Strhodes /* 509135446Strhodes * Make up a mask. 510135446Strhodes */ 511135446Strhodes confdata->sortlist[idx].mask = 512135446Strhodes confdata->sortlist[idx].addr; 513135446Strhodes 514135446Strhodes memset(&confdata->sortlist[idx].mask.address, 0xff, 515135446Strhodes confdata->sortlist[idx].addr.length); 516135446Strhodes } 517135446Strhodes 518135446Strhodes confdata->sortlistnxt++; 519135446Strhodes 520135446Strhodes if (delim == EOF || delim == '\n') 521135446Strhodes break; 522135446Strhodes else 523135446Strhodes delim = getword(fp, word, sizeof(word)); 524135446Strhodes } 525135446Strhodes 526135446Strhodes return (LWRES_R_SUCCESS); 527135446Strhodes} 528135446Strhodes 529135446Strhodesstatic lwres_result_t 530135446Strhodeslwres_conf_parseoption(lwres_context_t *ctx, FILE *fp) { 531135446Strhodes int delim; 532135446Strhodes long ndots; 533135446Strhodes char *p; 534135446Strhodes char word[LWRES_CONFMAXLINELEN]; 535135446Strhodes lwres_conf_t *confdata; 536135446Strhodes 537135446Strhodes REQUIRE(ctx != NULL); 538135446Strhodes confdata = &ctx->confdata; 539135446Strhodes 540135446Strhodes delim = getword(fp, word, sizeof(word)); 541135446Strhodes if (strlen(word) == 0U) 542135446Strhodes return (LWRES_R_FAILURE); /* Empty line after keyword. */ 543135446Strhodes 544135446Strhodes while (strlen(word) > 0U) { 545135446Strhodes if (strcmp("debug", word) == 0) { 546135446Strhodes confdata->resdebug = 1; 547135446Strhodes } else if (strcmp("no_tld_query", word) == 0) { 548135446Strhodes confdata->no_tld_query = 1; 549135446Strhodes } else if (strncmp("ndots:", word, 6) == 0) { 550135446Strhodes ndots = strtol(word + 6, &p, 10); 551135446Strhodes if (*p != '\0') /* Bad string. */ 552135446Strhodes return (LWRES_R_FAILURE); 553135446Strhodes if (ndots < 0 || ndots > 0xff) /* Out of range. */ 554135446Strhodes return (LWRES_R_FAILURE); 555135446Strhodes confdata->ndots = (lwres_uint8_t)ndots; 556135446Strhodes } 557135446Strhodes 558135446Strhodes if (delim == EOF || delim == '\n') 559135446Strhodes break; 560135446Strhodes else 561135446Strhodes delim = getword(fp, word, sizeof(word)); 562135446Strhodes } 563135446Strhodes 564135446Strhodes return (LWRES_R_SUCCESS); 565135446Strhodes} 566135446Strhodes 567170222Sdougb/*% parses a file and fills in the data structure. */ 568135446Strhodeslwres_result_t 569135446Strhodeslwres_conf_parse(lwres_context_t *ctx, const char *filename) { 570135446Strhodes FILE *fp = NULL; 571135446Strhodes char word[256]; 572135446Strhodes lwres_result_t rval, ret; 573135446Strhodes lwres_conf_t *confdata; 574135446Strhodes int stopchar; 575135446Strhodes 576135446Strhodes REQUIRE(ctx != NULL); 577135446Strhodes confdata = &ctx->confdata; 578135446Strhodes 579135446Strhodes REQUIRE(filename != NULL); 580135446Strhodes REQUIRE(strlen(filename) > 0U); 581135446Strhodes REQUIRE(confdata != NULL); 582135446Strhodes 583135446Strhodes errno = 0; 584135446Strhodes if ((fp = fopen(filename, "r")) == NULL) 585165071Sdougb return (LWRES_R_NOTFOUND); 586135446Strhodes 587135446Strhodes ret = LWRES_R_SUCCESS; 588135446Strhodes do { 589135446Strhodes stopchar = getword(fp, word, sizeof(word)); 590135446Strhodes if (stopchar == EOF) { 591135446Strhodes rval = LWRES_R_SUCCESS; 592225361Sdougb POST(rval); 593135446Strhodes break; 594135446Strhodes } 595135446Strhodes 596135446Strhodes if (strlen(word) == 0U) 597135446Strhodes rval = LWRES_R_SUCCESS; 598135446Strhodes else if (strcmp(word, "nameserver") == 0) 599135446Strhodes rval = lwres_conf_parsenameserver(ctx, fp); 600135446Strhodes else if (strcmp(word, "lwserver") == 0) 601135446Strhodes rval = lwres_conf_parselwserver(ctx, fp); 602135446Strhodes else if (strcmp(word, "domain") == 0) 603135446Strhodes rval = lwres_conf_parsedomain(ctx, fp); 604135446Strhodes else if (strcmp(word, "search") == 0) 605135446Strhodes rval = lwres_conf_parsesearch(ctx, fp); 606135446Strhodes else if (strcmp(word, "sortlist") == 0) 607135446Strhodes rval = lwres_conf_parsesortlist(ctx, fp); 608135446Strhodes else if (strcmp(word, "options") == 0) 609135446Strhodes rval = lwres_conf_parseoption(ctx, fp); 610135446Strhodes else { 611135446Strhodes /* unrecognised word. Ignore entire line */ 612135446Strhodes rval = LWRES_R_SUCCESS; 613135446Strhodes stopchar = eatline(fp); 614135446Strhodes if (stopchar == EOF) { 615135446Strhodes break; 616135446Strhodes } 617135446Strhodes } 618135446Strhodes if (ret == LWRES_R_SUCCESS && rval != LWRES_R_SUCCESS) 619135446Strhodes ret = rval; 620135446Strhodes } while (1); 621135446Strhodes 622135446Strhodes fclose(fp); 623135446Strhodes 624135446Strhodes return (ret); 625135446Strhodes} 626135446Strhodes 627170222Sdougb/*% Prints the config data structure to the FILE. */ 628135446Strhodeslwres_result_t 629135446Strhodeslwres_conf_print(lwres_context_t *ctx, FILE *fp) { 630135446Strhodes int i; 631135446Strhodes int af; 632135446Strhodes char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 633135446Strhodes const char *p; 634135446Strhodes lwres_conf_t *confdata; 635135446Strhodes lwres_addr_t tmpaddr; 636135446Strhodes 637135446Strhodes REQUIRE(ctx != NULL); 638135446Strhodes confdata = &ctx->confdata; 639135446Strhodes 640135446Strhodes REQUIRE(confdata->nsnext <= LWRES_CONFMAXNAMESERVERS); 641135446Strhodes 642135446Strhodes for (i = 0; i < confdata->nsnext; i++) { 643135446Strhodes af = lwresaddr2af(confdata->nameservers[i].family); 644135446Strhodes 645135446Strhodes p = lwres_net_ntop(af, confdata->nameservers[i].address, 646135446Strhodes tmp, sizeof(tmp)); 647135446Strhodes if (p != tmp) 648135446Strhodes return (LWRES_R_FAILURE); 649135446Strhodes 650135446Strhodes fprintf(fp, "nameserver %s\n", tmp); 651135446Strhodes } 652135446Strhodes 653135446Strhodes for (i = 0; i < confdata->lwnext; i++) { 654135446Strhodes af = lwresaddr2af(confdata->lwservers[i].family); 655135446Strhodes 656135446Strhodes p = lwres_net_ntop(af, confdata->lwservers[i].address, 657135446Strhodes tmp, sizeof(tmp)); 658135446Strhodes if (p != tmp) 659135446Strhodes return (LWRES_R_FAILURE); 660135446Strhodes 661135446Strhodes fprintf(fp, "lwserver %s\n", tmp); 662135446Strhodes } 663135446Strhodes 664135446Strhodes if (confdata->domainname != NULL) { 665135446Strhodes fprintf(fp, "domain %s\n", confdata->domainname); 666135446Strhodes } else if (confdata->searchnxt > 0) { 667135446Strhodes REQUIRE(confdata->searchnxt <= LWRES_CONFMAXSEARCH); 668135446Strhodes 669135446Strhodes fprintf(fp, "search"); 670135446Strhodes for (i = 0; i < confdata->searchnxt; i++) 671135446Strhodes fprintf(fp, " %s", confdata->search[i]); 672135446Strhodes fputc('\n', fp); 673135446Strhodes } 674135446Strhodes 675135446Strhodes REQUIRE(confdata->sortlistnxt <= LWRES_CONFMAXSORTLIST); 676135446Strhodes 677135446Strhodes if (confdata->sortlistnxt > 0) { 678135446Strhodes fputs("sortlist", fp); 679135446Strhodes for (i = 0; i < confdata->sortlistnxt; i++) { 680135446Strhodes af = lwresaddr2af(confdata->sortlist[i].addr.family); 681135446Strhodes 682135446Strhodes p = lwres_net_ntop(af, 683135446Strhodes confdata->sortlist[i].addr.address, 684135446Strhodes tmp, sizeof(tmp)); 685135446Strhodes if (p != tmp) 686135446Strhodes return (LWRES_R_FAILURE); 687135446Strhodes 688135446Strhodes fprintf(fp, " %s", tmp); 689135446Strhodes 690135446Strhodes tmpaddr = confdata->sortlist[i].mask; 691135446Strhodes memset(&tmpaddr.address, 0xff, tmpaddr.length); 692135446Strhodes 693135446Strhodes if (memcmp(&tmpaddr.address, 694135446Strhodes confdata->sortlist[i].mask.address, 695135446Strhodes confdata->sortlist[i].mask.length) != 0) { 696135446Strhodes af = lwresaddr2af( 697135446Strhodes confdata->sortlist[i].mask.family); 698135446Strhodes p = lwres_net_ntop 699135446Strhodes (af, 700135446Strhodes confdata->sortlist[i].mask.address, 701135446Strhodes tmp, sizeof(tmp)); 702135446Strhodes if (p != tmp) 703135446Strhodes return (LWRES_R_FAILURE); 704135446Strhodes 705135446Strhodes fprintf(fp, "/%s", tmp); 706135446Strhodes } 707135446Strhodes } 708135446Strhodes fputc('\n', fp); 709135446Strhodes } 710135446Strhodes 711135446Strhodes if (confdata->resdebug) 712135446Strhodes fprintf(fp, "options debug\n"); 713135446Strhodes 714135446Strhodes if (confdata->ndots > 0) 715135446Strhodes fprintf(fp, "options ndots:%d\n", confdata->ndots); 716135446Strhodes 717135446Strhodes if (confdata->no_tld_query) 718135446Strhodes fprintf(fp, "options no_tld_query\n"); 719135446Strhodes 720135446Strhodes return (LWRES_R_SUCCESS); 721135446Strhodes} 722135446Strhodes 723170222Sdougb/*% Returns a pointer to the current config structure. */ 724135446Strhodeslwres_conf_t * 725135446Strhodeslwres_conf_get(lwres_context_t *ctx) { 726135446Strhodes REQUIRE(ctx != NULL); 727135446Strhodes 728135446Strhodes return (&ctx->confdata); 729135446Strhodes} 730