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