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