conffile.c revision 1.8
1/* $NetBSD: conffile.c,v 1.8 2013/10/18 14:14:14 kefren 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 <arpa/inet.h> 33#include <netinet/in.h> 34#include <sys/mman.h> 35#include <ctype.h> 36#include <fcntl.h> 37#include <stdlib.h> 38#include <string.h> 39#include <unistd.h> 40 41#include "conffile.h" 42#include "ldp_errors.h" 43 44#define NextCommand(x) strsep(&x, " ") 45#define LINEMAXSIZE 1024 46 47char *mapped, *nextline; 48size_t mapsize; 49 50extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port, 51 min_label, max_label, no_default_route, loop_detection; 52struct in_addr conf_ldp_id; 53 54static int conf_dispatch(char*); 55static char * conf_getlinelimit(void); 56static int checkeol(char*); 57static int Fhellotime(char*); 58static int Fport(char*); 59static int Fholddown(char*); 60static int Fkeepalive(char*); 61static int Fmaxlabel(char*); 62static int Fminlabel(char*); 63static int Fldpid(char*); 64static int Fneighbour(char*); 65static int Gneighbour(struct conf_neighbour *, char *); 66static int Fnodefault(char*); 67static int Floopdetection(char*); 68static int Finterface(char*); 69static int Ginterface(struct conf_interface *, char *); 70static int Ipassive(struct conf_interface *, char *); 71static int Itaddr(struct conf_interface *, char *); 72 73struct conf_func { 74 char com[64]; 75 int (* func)(char *); 76}; 77 78struct intf_func { 79 char com[64]; 80 int (* func)(struct conf_interface *, char *); 81}; 82 83struct conf_func main_commands[] = { 84 { "hello-time", Fhellotime }, 85 { "keepalive-time", Fkeepalive }, 86 { "holddown-time", Fholddown }, 87 { "command-port", Fport }, 88 { "min-label", Fminlabel }, 89 { "max-label", Fmaxlabel }, 90 { "ldp-id", Fldpid }, 91 { "neighbor", Fneighbour }, 92 { "neighbour", Fneighbour }, 93 { "no-default-route", Fnodefault }, 94 { "loop-detection", Floopdetection }, 95 { "interface", Finterface }, 96 { "", NULL }, 97}; 98 99struct intf_func intf_commands[] = { 100 { "passive", Ipassive }, 101 { "transport-address", Itaddr }, 102 { "", NULL }, 103}; 104 105static int parseline; 106 107/* 108 * Parses config file 109 */ 110int 111conf_parsefile(const char *fname) 112{ 113 char line[LINEMAXSIZE+1]; 114 struct stat fs; 115 116 SLIST_INIT(&conei_head); 117 SLIST_INIT(&coifs_head); 118 conf_ldp_id.s_addr = 0; 119 120 int confh = open(fname, O_RDONLY, 0); 121 122 if (confh == -1 || fstat(confh, &fs) == -1 || 123 (mapped = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, confh, 0)) 124 == MAP_FAILED) 125 return E_CONF_IO; 126 127 mapsize = fs.st_size; 128 nextline = mapped; 129 for (parseline = 1; ; parseline++) { 130 char *prev = nextline; 131 if ((nextline = conf_getlinelimit()) == NULL) 132 break; 133 while (isspace((int)*prev) != 0 && prev < nextline) 134 prev++; 135 if (nextline - prev < 2) 136 continue; 137 else if (nextline - prev > LINEMAXSIZE) 138 goto parerr; 139 memcpy(line, prev, nextline - prev); 140 if (line[0] == '#') 141 continue; 142 else 143 line[nextline - prev] = '\0'; 144 if (conf_dispatch(line) != 0) 145 goto parerr; 146 } 147 munmap(mapped, mapsize); 148 close(confh); 149 return 0; 150parerr: 151 munmap(mapped, mapsize); 152 close(confh); 153 return parseline; 154} 155 156char * 157conf_getlinelimit(void) 158{ 159 char *p = nextline; 160 161 if (nextline < mapped || (size_t)(nextline - mapped) >= mapsize) 162 return NULL; 163 164 for (p = nextline; *p != '\n' && (size_t)(p - mapped) < mapsize; p++); 165 return p + 1; 166} 167 168/* 169 * Looks for a matching command on a line 170 */ 171int 172conf_dispatch(char *line) 173{ 174 int i, last_match = -1, matched = 0; 175 char *command, *nline = line; 176 177 if (strlen(line) == 0 || line[0] == '#') 178 return E_CONF_OK; 179 command = NextCommand(nline); 180 for (i = 0; main_commands[i].func != NULL; i++) 181 if (strncasecmp(main_commands[i].com, command, 182 strlen(main_commands[i].com)) == 0) { 183 matched++; 184 last_match = i; 185 } 186 if (matched == 0) 187 return E_CONF_NOMATCH; 188 else if (matched > 1) 189 return E_CONF_AMBIGUOUS; 190 191 if (nline == NULL || checkeol(nline) != 0) 192 return E_CONF_PARAM; 193 return main_commands[last_match].func(nline); 194} 195 196/* 197 * Checks if a line is terminated or else if it contains 198 * a start block bracket. If it's semicolon terminated 199 * then trim it. 200 */ 201int 202checkeol(char *line) 203{ 204 size_t len = strlen(line); 205 if (len > 0 && line[len - 1] == '\n') { 206 line[len - 1] = '\0'; 207 len--; 208 } 209 if (len > 0 && line[len - 1] == ';') { 210 line[len - 1] = '\0'; 211 return 0; 212 } 213 for (size_t i = 0; i < len; i++) 214 if (line[i] == '{') 215 return 0; 216 return -1; 217} 218 219/* 220 * Sets hello time 221 */ 222int 223Fhellotime(char *line) 224{ 225 int ht = atoi(line); 226 if (ht <= 0) 227 return E_CONF_PARAM; 228 ldp_hello_time = ht; 229 return 0; 230} 231 232/* 233 * Sets command port 234 */ 235int 236Fport(char *line) 237{ 238 int cp = atoi(line); 239 if (cp <= 0 || cp > 65535) 240 return E_CONF_PARAM; 241 command_port = cp; 242 return 0; 243} 244 245/* 246 * Sets neighbour keepalive 247 */ 248int 249Fkeepalive(char *line) 250{ 251 int kt = atoi(line); 252 if (kt <= 0) 253 return E_CONF_PARAM; 254 ldp_keepalive_time = kt; 255 return 0; 256} 257 258/* 259 * Sets neighbour holddown timer 260 */ 261int 262Fholddown(char *line) 263{ 264 int hdt = atoi(line); 265 if (hdt <= 0) 266 return E_CONF_PARAM; 267 ldp_holddown_time = hdt; 268 return 0; 269} 270 271int 272Fminlabel(char *line) 273{ 274 int ml = atoi(line); 275 if (ml <= 0) 276 return E_CONF_PARAM; 277 min_label = ml; 278 return 0; 279} 280 281int 282Fmaxlabel(char *line) 283{ 284 int ml = atoi(line); 285 if (ml <= 0) 286 return E_CONF_PARAM; 287 max_label = ml; 288 return 0; 289} 290 291int 292Fldpid(char *line) 293{ 294 if (inet_pton(AF_INET, line, &conf_ldp_id) != 1) 295 return E_CONF_PARAM; 296 return 0; 297} 298 299int 300Fneighbour(char *line) 301{ 302 char *peer; 303 struct conf_neighbour *nei; 304 struct in_addr ad; 305 char buf[LINEMAXSIZE]; 306 307 peer = NextCommand(line); 308 if (inet_pton(AF_INET, peer, &ad) != 1) 309 return E_CONF_PARAM; 310 311 nei = calloc(1, sizeof(*nei)); 312 if (nei == NULL) 313 return E_CONF_MEM; 314 nei->address.s_addr = ad.s_addr; 315 SLIST_INSERT_HEAD(&conei_head, nei, neilist); 316 317 for ( ; ; ) { 318 char *prev = nextline; 319 parseline++; 320 nextline = conf_getlinelimit(); 321 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE) 322 return -1; 323 while (isspace((int)*prev) != 0 && prev < nextline) 324 prev++; 325 memcpy(buf, prev, nextline - prev); 326 if (nextline - prev < 2 || buf[0] == '#') 327 continue; 328 else if (buf[0] == '}') 329 break; 330 else 331 buf[nextline - prev] = '\0'; 332 if (Gneighbour(nei, buf) == -1) 333 return -1; 334 } 335 return -1; 336} 337 338/* 339 * neighbour { } sub-commands 340 */ 341int 342Gneighbour(struct conf_neighbour *nei, char *line) 343{ 344 if (strncasecmp("authenticate", line, 12) == 0) { 345 nei->authenticate = 1; 346 return 0; 347 } 348 return -1; 349} 350 351int 352Fnodefault(char *line) 353{ 354 int nd = atoi(line); 355 if (nd < 0) 356 return E_CONF_PARAM; 357 no_default_route = nd; 358 return 0; 359} 360 361int 362Floopdetection(char *line) 363{ 364 int loopd = atoi(line); 365 if (loopd < 0) 366 return E_CONF_PARAM; 367 loop_detection = loopd; 368 return 0; 369} 370 371/* 372 * Interface sub-commands 373 */ 374int 375Finterface(char *line) 376{ 377 char *ifname; 378 struct conf_interface *conf_if = calloc(1, sizeof(*conf_if)); 379 char buf[LINEMAXSIZE]; 380 381 ifname = NextCommand(line); 382 if (conf_if == NULL || ifname == NULL) 383 return -1; 384 strlcpy(conf_if->if_name, ifname, IF_NAMESIZE); 385 SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist); 386 387 for ( ; ; ) { 388 char *prev = nextline; 389 parseline++; 390 nextline = conf_getlinelimit(); 391 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE) 392 return -1; 393 while (isspace((int)*prev) != 0 && prev < nextline) 394 prev++; 395 memcpy(buf, prev, nextline - prev); 396 if (nextline - prev < 2 || buf[0] == '#') 397 continue; 398 else if (buf[0] == '}') 399 break; 400 else 401 buf[nextline - prev] = '\0'; 402 if (Ginterface(conf_if, buf) == -1) 403 return -1; 404 } 405 return 0; 406} 407 408int 409Ginterface(struct conf_interface *conf_if, char *buf) 410{ 411 int i; 412 413 for (i = 0; intf_commands[i].func != NULL; i++) 414 if (strncasecmp(buf, intf_commands[i].com, 415 strlen(intf_commands[i].com)) == 0) 416 return intf_commands[i].func(conf_if, buf + 417 strlen(intf_commands[i].com) + 1); 418 /* command not found */ 419 return -1; 420} 421 422/* sets transport address */ 423int 424Itaddr(struct conf_interface *conf_if, char *buf) 425{ 426 if (inet_pton(AF_INET, buf, &conf_if->tr_addr) != 1) 427 return -1; 428 return 0; 429} 430 431/* sets passive-interface on */ 432int 433Ipassive(struct conf_interface *conf_if, char *buf) 434{ 435 conf_if->passive = 1; 436 return 0; 437} 438