conffile.c revision 1.12
1/* $NetBSD: conffile.c,v 1.12 2017/01/10 21:02:38 christos Exp $ */ 2 3/* 4 * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Mihai Chelaru <kefren@NetBSD.org> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include <sys/mman.h> 33#include <sys/stat.h> 34 35#include <arpa/inet.h> 36#include <netinet/in.h> 37 38#include <ctype.h> 39#include <fcntl.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43 44#include "conffile.h" 45#include "ldp_errors.h" 46 47#define NextCommand(x) strsep(&x, " ") 48#define LINEMAXSIZE 1024 49 50char *mapped, *nextline; 51size_t mapsize; 52 53extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port, 54 min_label, max_label, no_default_route, loop_detection; 55struct in_addr conf_ldp_id; 56 57static int conf_dispatch(char*); 58static char * conf_getlinelimit(void); 59static int checkeol(char*); 60static int Fhellotime(char*); 61static int Fport(char*); 62static int Fholddown(char*); 63static int Fkeepalive(char*); 64static int Fmaxlabel(char*); 65static int Fminlabel(char*); 66static int Fldpid(char*); 67static int Fneighbour(char*); 68static int Gneighbour(struct conf_neighbour *, char *); 69static int Fnodefault(char*); 70static int Floopdetection(char*); 71static int Finterface(char*); 72static int Ginterface(struct conf_interface *, char *); 73static int Ipassive(struct conf_interface *, char *); 74static int Itaddr(struct conf_interface *, char *); 75 76struct conf_func { 77 char com[64]; 78 int (* func)(char *); 79}; 80 81struct intf_func { 82 char com[64]; 83 int (* func)(struct conf_interface *, char *); 84}; 85 86struct conf_func main_commands[] = { 87 { "hello-time", Fhellotime }, 88 { "keepalive-time", Fkeepalive }, 89 { "holddown-time", Fholddown }, 90 { "command-port", Fport }, 91 { "min-label", Fminlabel }, 92 { "max-label", Fmaxlabel }, 93 { "ldp-id", Fldpid }, 94 { "neighbor", Fneighbour }, 95 { "neighbour", Fneighbour }, 96 { "no-default-route", Fnodefault }, 97 { "loop-detection", Floopdetection }, 98 { "interface", Finterface }, 99 { "", NULL }, 100}; 101 102struct intf_func intf_commands[] = { 103 { "passive", Ipassive }, 104 { "transport-address", Itaddr }, 105 { "", NULL }, 106}; 107 108static int parseline; 109 110/* 111 * Parses config file 112 */ 113int 114conf_parsefile(const char *fname) 115{ 116 char line[LINEMAXSIZE+1]; 117 struct stat fs; 118 119 SLIST_INIT(&conei_head); 120 SLIST_INIT(&coifs_head); 121 conf_ldp_id.s_addr = 0; 122 123 int confh = open(fname, O_RDONLY, 0); 124 125 if (confh == -1 || fstat(confh, &fs) == -1 || 126 (mapped = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, confh, 0)) 127 == MAP_FAILED) { 128 if (confh != -1) 129 close(confh); 130 return E_CONF_IO; 131 } 132 133 mapsize = fs.st_size; 134 nextline = mapped; 135 for (parseline = 1; ; parseline++) { 136 char *prev = nextline; 137 if ((nextline = conf_getlinelimit()) == NULL) 138 break; 139 while (isspace((int)*prev) != 0 && prev < nextline) 140 prev++; 141 if (nextline - prev < 2) 142 continue; 143 else if (nextline - prev > LINEMAXSIZE) 144 goto parerr; 145 memcpy(line, prev, nextline - prev); 146 if (line[0] == '#') 147 continue; 148 else 149 line[nextline - prev] = '\0'; 150 if (conf_dispatch(line) != 0) 151 goto parerr; 152 } 153 munmap(mapped, mapsize); 154 close(confh); 155 return 0; 156parerr: 157 munmap(mapped, mapsize); 158 close(confh); 159 return parseline; 160} 161 162char * 163conf_getlinelimit(void) 164{ 165 char *p = nextline; 166 167 if (nextline < mapped || (size_t)(nextline - mapped) >= mapsize) 168 return NULL; 169 170 for (p = nextline; *p != '\n' && (size_t)(p - mapped) < mapsize; p++); 171 return p + 1; 172} 173 174/* 175 * Looks for a matching command on a line 176 */ 177int 178conf_dispatch(char *line) 179{ 180 int i, last_match = -1, matched = 0; 181 char *command, *nline = line; 182 183 if (strlen(line) == 0 || line[0] == '#') 184 return E_CONF_OK; 185 command = NextCommand(nline); 186 for (i = 0; main_commands[i].func != NULL; i++) 187 if (strncasecmp(main_commands[i].com, command, 188 strlen(main_commands[i].com)) == 0) { 189 matched++; 190 last_match = i; 191 } 192 if (matched == 0) 193 return E_CONF_NOMATCH; 194 else if (matched > 1) 195 return E_CONF_AMBIGUOUS; 196 197 if (nline == NULL || checkeol(nline) != 0) 198 return E_CONF_PARAM; 199 return main_commands[last_match].func(nline); 200} 201 202/* 203 * Checks if a line is terminated or else if it contains 204 * a start block bracket. If it's semicolon terminated 205 * then trim it. 206 */ 207int 208checkeol(char *line) 209{ 210 size_t len = strlen(line); 211 if (len > 0 && line[len - 1] == '\n') { 212 line[len - 1] = '\0'; 213 len--; 214 } 215 if (len > 0 && line[len - 1] == ';') { 216 line[len - 1] = '\0'; 217 return 0; 218 } 219 for (size_t i = 0; i < len; i++) 220 if (line[i] == '{') 221 return 0; 222 return -1; 223} 224 225/* 226 * Sets hello time 227 */ 228int 229Fhellotime(char *line) 230{ 231 int ht = atoi(line); 232 if (ht <= 0) 233 return E_CONF_PARAM; 234 ldp_hello_time = ht; 235 return 0; 236} 237 238/* 239 * Sets command port 240 */ 241int 242Fport(char *line) 243{ 244 int cp = atoi(line); 245 if (cp <= 0 || cp > 65535) 246 return E_CONF_PARAM; 247 command_port = cp; 248 return 0; 249} 250 251/* 252 * Sets neighbour keepalive 253 */ 254int 255Fkeepalive(char *line) 256{ 257 int kt = atoi(line); 258 if (kt <= 0) 259 return E_CONF_PARAM; 260 ldp_keepalive_time = kt; 261 return 0; 262} 263 264/* 265 * Sets neighbour holddown timer 266 */ 267int 268Fholddown(char *line) 269{ 270 int hdt = atoi(line); 271 if (hdt <= 0) 272 return E_CONF_PARAM; 273 ldp_holddown_time = hdt; 274 return 0; 275} 276 277int 278Fminlabel(char *line) 279{ 280 int ml = atoi(line); 281 if (ml <= 0) 282 return E_CONF_PARAM; 283 min_label = ml; 284 return 0; 285} 286 287int 288Fmaxlabel(char *line) 289{ 290 int ml = atoi(line); 291 if (ml <= 0) 292 return E_CONF_PARAM; 293 max_label = ml; 294 return 0; 295} 296 297int 298Fldpid(char *line) 299{ 300 if (inet_pton(AF_INET, line, &conf_ldp_id) != 1) 301 return E_CONF_PARAM; 302 return 0; 303} 304 305int 306Fneighbour(char *line) 307{ 308 char *peer; 309 struct conf_neighbour *nei; 310 struct in_addr ad; 311 char buf[LINEMAXSIZE]; 312 313 peer = NextCommand(line); 314 if (inet_pton(AF_INET, peer, &ad) != 1) 315 return E_CONF_PARAM; 316 317 nei = calloc(1, sizeof(*nei)); 318 if (nei == NULL) 319 return E_CONF_MEM; 320 nei->address.s_addr = ad.s_addr; 321 SLIST_INSERT_HEAD(&conei_head, nei, neilist); 322 323 for ( ; ; ) { 324 char *prev = nextline; 325 parseline++; 326 nextline = conf_getlinelimit(); 327 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE) 328 return -1; 329 while (isspace((int)*prev) != 0 && prev < nextline) 330 prev++; 331 memcpy(buf, prev, nextline - prev); 332 if (nextline - prev < 2 || buf[0] == '#') 333 continue; 334 else if (buf[0] == '}') 335 break; 336 else 337 buf[nextline - prev] = '\0'; 338 if (Gneighbour(nei, buf) == -1) 339 return -1; 340 } 341 return -1; 342} 343 344/* 345 * neighbour { } sub-commands 346 */ 347int 348Gneighbour(struct conf_neighbour *nei, char *line) 349{ 350 if (strncasecmp("authenticate", line, 12) == 0) { 351 nei->authenticate = 1; 352 return 0; 353 } 354 return -1; 355} 356 357int 358Fnodefault(char *line) 359{ 360 int nd = atoi(line); 361 if (nd < 0) 362 return E_CONF_PARAM; 363 no_default_route = nd; 364 return 0; 365} 366 367int 368Floopdetection(char *line) 369{ 370 int loopd = atoi(line); 371 if (loopd < 0) 372 return E_CONF_PARAM; 373 loop_detection = loopd; 374 return 0; 375} 376 377/* 378 * Interface sub-commands 379 */ 380int 381Finterface(char *line) 382{ 383 char *ifname; 384 struct conf_interface *conf_if; 385 char buf[LINEMAXSIZE]; 386 387 if ((ifname = NextCommand(line)) == NULL) 388 return -1; 389 if ((conf_if = calloc(1, sizeof(*conf_if))) == NULL) 390 return -1; 391 392 strlcpy(conf_if->if_name, ifname, IF_NAMESIZE); 393 SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist); 394 395 for ( ; ; ) { 396 char *prev = nextline; 397 parseline++; 398 nextline = conf_getlinelimit(); 399 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE) 400 return -1; 401 while (isspace((int)*prev) != 0 && prev < nextline) 402 prev++; 403 memcpy(buf, prev, nextline - prev); 404 if (nextline - prev < 2 || buf[0] == '#') 405 continue; 406 else if (buf[0] == '}') 407 break; 408 else 409 buf[nextline - prev] = '\0'; 410 if (Ginterface(conf_if, buf) == -1) 411 return -1; 412 } 413 return 0; 414} 415 416int 417Ginterface(struct conf_interface *conf_if, char *buf) 418{ 419 int i; 420 421 for (i = 0; intf_commands[i].func != NULL; i++) 422 if (strncasecmp(buf, intf_commands[i].com, 423 strlen(intf_commands[i].com)) == 0) 424 return intf_commands[i].func(conf_if, buf + 425 strlen(intf_commands[i].com) + 1); 426 /* command not found */ 427 return -1; 428} 429 430/* sets transport address */ 431int 432Itaddr(struct conf_interface *conf_if, char *buf) 433{ 434 if (inet_pton(AF_INET, buf, &conf_if->tr_addr) != 1) 435 return -1; 436 return 0; 437} 438 439/* sets passive-interface on */ 440int 441Ipassive(struct conf_interface *conf_if, char *buf) 442{ 443 conf_if->passive = 1; 444 return 0; 445} 446