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 50struct coifs_head coifs_head; 51struct conei_head conei_head; 52 53char *mapped, *nextline; 54size_t mapsize; 55 56extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port, 57 min_label, max_label, no_default_route, loop_detection; 58struct in_addr conf_ldp_id; 59 60static int conf_dispatch(char*); 61static char * conf_getlinelimit(void); 62static int checkeol(char*); 63static int Fhellotime(char*); 64static int Fport(char*); 65static int Fholddown(char*); 66static int Fkeepalive(char*); 67static int Fmaxlabel(char*); 68static int Fminlabel(char*); 69static int Fldpid(char*); 70static int Fneighbour(char*); 71static int Gneighbour(struct conf_neighbour *, char *); 72static int Fnodefault(char*); 73static int Floopdetection(char*); 74static int Finterface(char*); 75static int Ginterface(struct conf_interface *, char *); 76static int Ipassive(struct conf_interface *, char *); 77static int Itaddr(struct conf_interface *, char *); 78 79struct conf_func { 80 char com[64]; 81 int (* func)(char *); 82}; 83 84struct intf_func { 85 char com[64]; 86 int (* func)(struct conf_interface *, char *); 87}; 88 89struct 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 105struct intf_func intf_commands[] = { 106 { "passive", Ipassive }, 107 { "transport-address", Itaddr }, 108 { "", NULL }, 109}; 110 111static int parseline; 112 113/* 114 * Parses config file 115 */ 116int 117conf_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; 159parerr: 160 munmap(mapped, mapsize); 161 close(confh); 162 return parseline; 163} 164 165char * 166conf_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 */ 180int 181conf_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 */ 210int 211checkeol(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 */ 231int 232Fhellotime(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 */ 244int 245Fport(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 */ 257int 258Fkeepalive(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 */ 270int 271Fholddown(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 280int 281Fminlabel(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 290int 291Fmaxlabel(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 300int 301Fldpid(char *line) 302{ 303 if (inet_pton(AF_INET, line, &conf_ldp_id) != 1) 304 return E_CONF_PARAM; 305 return 0; 306} 307 308int 309Fneighbour(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 */ 350int 351Gneighbour(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 360int 361Fnodefault(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 370int 371Floopdetection(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 */ 383int 384Finterface(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 419int 420Ginterface(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 */ 434int 435Itaddr(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 */ 443int 444Ipassive(struct conf_interface *conf_if, char *buf) 445{ 446 conf_if->passive = 1; 447 return 0; 448} 449