conffile.c revision 1.9
1/* $NetBSD: conffile.c,v 1.9 2013/11/13 21:20:21 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 <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 close(confh); 126 return E_CONF_IO; 127 } 128 129 mapsize = fs.st_size; 130 nextline = mapped; 131 for (parseline = 1; ; parseline++) { 132 char *prev = nextline; 133 if ((nextline = conf_getlinelimit()) == NULL) 134 break; 135 while (isspace((int)*prev) != 0 && prev < nextline) 136 prev++; 137 if (nextline - prev < 2) 138 continue; 139 else if (nextline - prev > LINEMAXSIZE) 140 goto parerr; 141 memcpy(line, prev, nextline - prev); 142 if (line[0] == '#') 143 continue; 144 else 145 line[nextline - prev] = '\0'; 146 if (conf_dispatch(line) != 0) 147 goto parerr; 148 } 149 munmap(mapped, mapsize); 150 close(confh); 151 return 0; 152parerr: 153 munmap(mapped, mapsize); 154 close(confh); 155 return parseline; 156} 157 158char * 159conf_getlinelimit(void) 160{ 161 char *p = nextline; 162 163 if (nextline < mapped || (size_t)(nextline - mapped) >= mapsize) 164 return NULL; 165 166 for (p = nextline; *p != '\n' && (size_t)(p - mapped) < mapsize; p++); 167 return p + 1; 168} 169 170/* 171 * Looks for a matching command on a line 172 */ 173int 174conf_dispatch(char *line) 175{ 176 int i, last_match = -1, matched = 0; 177 char *command, *nline = line; 178 179 if (strlen(line) == 0 || line[0] == '#') 180 return E_CONF_OK; 181 command = NextCommand(nline); 182 for (i = 0; main_commands[i].func != NULL; i++) 183 if (strncasecmp(main_commands[i].com, command, 184 strlen(main_commands[i].com)) == 0) { 185 matched++; 186 last_match = i; 187 } 188 if (matched == 0) 189 return E_CONF_NOMATCH; 190 else if (matched > 1) 191 return E_CONF_AMBIGUOUS; 192 193 if (nline == NULL || checkeol(nline) != 0) 194 return E_CONF_PARAM; 195 return main_commands[last_match].func(nline); 196} 197 198/* 199 * Checks if a line is terminated or else if it contains 200 * a start block bracket. If it's semicolon terminated 201 * then trim it. 202 */ 203int 204checkeol(char *line) 205{ 206 size_t len = strlen(line); 207 if (len > 0 && line[len - 1] == '\n') { 208 line[len - 1] = '\0'; 209 len--; 210 } 211 if (len > 0 && line[len - 1] == ';') { 212 line[len - 1] = '\0'; 213 return 0; 214 } 215 for (size_t i = 0; i < len; i++) 216 if (line[i] == '{') 217 return 0; 218 return -1; 219} 220 221/* 222 * Sets hello time 223 */ 224int 225Fhellotime(char *line) 226{ 227 int ht = atoi(line); 228 if (ht <= 0) 229 return E_CONF_PARAM; 230 ldp_hello_time = ht; 231 return 0; 232} 233 234/* 235 * Sets command port 236 */ 237int 238Fport(char *line) 239{ 240 int cp = atoi(line); 241 if (cp <= 0 || cp > 65535) 242 return E_CONF_PARAM; 243 command_port = cp; 244 return 0; 245} 246 247/* 248 * Sets neighbour keepalive 249 */ 250int 251Fkeepalive(char *line) 252{ 253 int kt = atoi(line); 254 if (kt <= 0) 255 return E_CONF_PARAM; 256 ldp_keepalive_time = kt; 257 return 0; 258} 259 260/* 261 * Sets neighbour holddown timer 262 */ 263int 264Fholddown(char *line) 265{ 266 int hdt = atoi(line); 267 if (hdt <= 0) 268 return E_CONF_PARAM; 269 ldp_holddown_time = hdt; 270 return 0; 271} 272 273int 274Fminlabel(char *line) 275{ 276 int ml = atoi(line); 277 if (ml <= 0) 278 return E_CONF_PARAM; 279 min_label = ml; 280 return 0; 281} 282 283int 284Fmaxlabel(char *line) 285{ 286 int ml = atoi(line); 287 if (ml <= 0) 288 return E_CONF_PARAM; 289 max_label = ml; 290 return 0; 291} 292 293int 294Fldpid(char *line) 295{ 296 if (inet_pton(AF_INET, line, &conf_ldp_id) != 1) 297 return E_CONF_PARAM; 298 return 0; 299} 300 301int 302Fneighbour(char *line) 303{ 304 char *peer; 305 struct conf_neighbour *nei; 306 struct in_addr ad; 307 char buf[LINEMAXSIZE]; 308 309 peer = NextCommand(line); 310 if (inet_pton(AF_INET, peer, &ad) != 1) 311 return E_CONF_PARAM; 312 313 nei = calloc(1, sizeof(*nei)); 314 if (nei == NULL) 315 return E_CONF_MEM; 316 nei->address.s_addr = ad.s_addr; 317 SLIST_INSERT_HEAD(&conei_head, nei, neilist); 318 319 for ( ; ; ) { 320 char *prev = nextline; 321 parseline++; 322 nextline = conf_getlinelimit(); 323 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE) 324 return -1; 325 while (isspace((int)*prev) != 0 && prev < nextline) 326 prev++; 327 memcpy(buf, prev, nextline - prev); 328 if (nextline - prev < 2 || buf[0] == '#') 329 continue; 330 else if (buf[0] == '}') 331 break; 332 else 333 buf[nextline - prev] = '\0'; 334 if (Gneighbour(nei, buf) == -1) 335 return -1; 336 } 337 return -1; 338} 339 340/* 341 * neighbour { } sub-commands 342 */ 343int 344Gneighbour(struct conf_neighbour *nei, char *line) 345{ 346 if (strncasecmp("authenticate", line, 12) == 0) { 347 nei->authenticate = 1; 348 return 0; 349 } 350 return -1; 351} 352 353int 354Fnodefault(char *line) 355{ 356 int nd = atoi(line); 357 if (nd < 0) 358 return E_CONF_PARAM; 359 no_default_route = nd; 360 return 0; 361} 362 363int 364Floopdetection(char *line) 365{ 366 int loopd = atoi(line); 367 if (loopd < 0) 368 return E_CONF_PARAM; 369 loop_detection = loopd; 370 return 0; 371} 372 373/* 374 * Interface sub-commands 375 */ 376int 377Finterface(char *line) 378{ 379 char *ifname; 380 struct conf_interface *conf_if = calloc(1, sizeof(*conf_if)); 381 char buf[LINEMAXSIZE]; 382 383 ifname = NextCommand(line); 384 if (conf_if == NULL || ifname == NULL) 385 return -1; 386 strlcpy(conf_if->if_name, ifname, IF_NAMESIZE); 387 SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist); 388 389 for ( ; ; ) { 390 char *prev = nextline; 391 parseline++; 392 nextline = conf_getlinelimit(); 393 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE) 394 return -1; 395 while (isspace((int)*prev) != 0 && prev < nextline) 396 prev++; 397 memcpy(buf, prev, nextline - prev); 398 if (nextline - prev < 2 || buf[0] == '#') 399 continue; 400 else if (buf[0] == '}') 401 break; 402 else 403 buf[nextline - prev] = '\0'; 404 if (Ginterface(conf_if, buf) == -1) 405 return -1; 406 } 407 return 0; 408} 409 410int 411Ginterface(struct conf_interface *conf_if, char *buf) 412{ 413 int i; 414 415 for (i = 0; intf_commands[i].func != NULL; i++) 416 if (strncasecmp(buf, intf_commands[i].com, 417 strlen(intf_commands[i].com)) == 0) 418 return intf_commands[i].func(conf_if, buf + 419 strlen(intf_commands[i].com) + 1); 420 /* command not found */ 421 return -1; 422} 423 424/* sets transport address */ 425int 426Itaddr(struct conf_interface *conf_if, char *buf) 427{ 428 if (inet_pton(AF_INET, buf, &conf_if->tr_addr) != 1) 429 return -1; 430 return 0; 431} 432 433/* sets passive-interface on */ 434int 435Ipassive(struct conf_interface *conf_if, char *buf) 436{ 437 conf_if->passive = 1; 438 return 0; 439} 440