1 1.15 christos /* $NetBSD: conffile.c,v 1.15 2025/09/20 15:42:01 christos Exp $ */ 2 1.1 kefren 3 1.1 kefren /* 4 1.1 kefren * Copyright (c) 2010 The NetBSD Foundation, Inc. 5 1.1 kefren * All rights reserved. 6 1.1 kefren * 7 1.1 kefren * This code is derived from software contributed to The NetBSD Foundation 8 1.1 kefren * by Mihai Chelaru <kefren (at) NetBSD.org> 9 1.1 kefren * 10 1.1 kefren * Redistribution and use in source and binary forms, with or without 11 1.1 kefren * modification, are permitted provided that the following conditions 12 1.1 kefren * are met: 13 1.1 kefren * 1. Redistributions of source code must retain the above copyright 14 1.1 kefren * notice, this list of conditions and the following disclaimer. 15 1.1 kefren * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 kefren * notice, this list of conditions and the following disclaimer in the 17 1.1 kefren * documentation and/or other materials provided with the distribution. 18 1.1 kefren * 19 1.1 kefren * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 kefren * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 kefren * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 kefren * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 kefren * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 kefren * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 kefren * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 kefren * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 kefren * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 kefren * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 kefren * POSSIBILITY OF SUCH DAMAGE. 30 1.1 kefren */ 31 1.1 kefren 32 1.12 christos #include <sys/mman.h> 33 1.12 christos #include <sys/stat.h> 34 1.12 christos 35 1.1 kefren #include <arpa/inet.h> 36 1.1 kefren #include <netinet/in.h> 37 1.12 christos 38 1.1 kefren #include <ctype.h> 39 1.1 kefren #include <fcntl.h> 40 1.1 kefren #include <stdlib.h> 41 1.1 kefren #include <string.h> 42 1.1 kefren #include <unistd.h> 43 1.1 kefren 44 1.1 kefren #include "conffile.h" 45 1.1 kefren #include "ldp_errors.h" 46 1.1 kefren 47 1.1 kefren #define NextCommand(x) strsep(&x, " ") 48 1.1 kefren #define LINEMAXSIZE 1024 49 1.1 kefren 50 1.13 joerg struct coifs_head coifs_head; 51 1.13 joerg struct conei_head conei_head; 52 1.13 joerg 53 1.8 kefren char *mapped, *nextline; 54 1.8 kefren size_t mapsize; 55 1.8 kefren 56 1.1 kefren extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port, 57 1.4 kefren min_label, max_label, no_default_route, loop_detection; 58 1.1 kefren struct in_addr conf_ldp_id; 59 1.1 kefren 60 1.1 kefren static int conf_dispatch(char*); 61 1.8 kefren static char * conf_getlinelimit(void); 62 1.1 kefren static int checkeol(char*); 63 1.1 kefren static int Fhellotime(char*); 64 1.1 kefren static int Fport(char*); 65 1.1 kefren static int Fholddown(char*); 66 1.1 kefren static int Fkeepalive(char*); 67 1.1 kefren static int Fmaxlabel(char*); 68 1.1 kefren static int Fminlabel(char*); 69 1.1 kefren static int Fldpid(char*); 70 1.1 kefren static int Fneighbour(char*); 71 1.1 kefren static int Gneighbour(struct conf_neighbour *, char *); 72 1.3 kefren static int Fnodefault(char*); 73 1.4 kefren static int Floopdetection(char*); 74 1.7 kefren static int Finterface(char*); 75 1.7 kefren static int Ginterface(struct conf_interface *, char *); 76 1.7 kefren static int Ipassive(struct conf_interface *, char *); 77 1.7 kefren static int Itaddr(struct conf_interface *, char *); 78 1.1 kefren 79 1.1 kefren struct conf_func { 80 1.1 kefren char com[64]; 81 1.1 kefren int (* func)(char *); 82 1.1 kefren }; 83 1.1 kefren 84 1.7 kefren struct intf_func { 85 1.7 kefren char com[64]; 86 1.7 kefren int (* func)(struct conf_interface *, char *); 87 1.7 kefren }; 88 1.7 kefren 89 1.1 kefren struct conf_func main_commands[] = { 90 1.1 kefren { "hello-time", Fhellotime }, 91 1.1 kefren { "keepalive-time", Fkeepalive }, 92 1.1 kefren { "holddown-time", Fholddown }, 93 1.1 kefren { "command-port", Fport }, 94 1.1 kefren { "min-label", Fminlabel }, 95 1.1 kefren { "max-label", Fmaxlabel }, 96 1.7 kefren { "ldp-id", Fldpid }, 97 1.1 kefren { "neighbor", Fneighbour }, 98 1.1 kefren { "neighbour", Fneighbour }, 99 1.3 kefren { "no-default-route", Fnodefault }, 100 1.4 kefren { "loop-detection", Floopdetection }, 101 1.7 kefren { "interface", Finterface }, 102 1.1 kefren { "", NULL }, 103 1.1 kefren }; 104 1.1 kefren 105 1.7 kefren struct intf_func intf_commands[] = { 106 1.7 kefren { "passive", Ipassive }, 107 1.7 kefren { "transport-address", Itaddr }, 108 1.7 kefren { "", NULL }, 109 1.7 kefren }; 110 1.7 kefren 111 1.7 kefren static int parseline; 112 1.7 kefren 113 1.1 kefren /* 114 1.1 kefren * Parses config file 115 1.1 kefren */ 116 1.1 kefren int 117 1.6 kefren conf_parsefile(const char *fname) 118 1.1 kefren { 119 1.8 kefren char line[LINEMAXSIZE+1]; 120 1.8 kefren struct stat fs; 121 1.1 kefren 122 1.1 kefren SLIST_INIT(&conei_head); 123 1.7 kefren SLIST_INIT(&coifs_head); 124 1.1 kefren conf_ldp_id.s_addr = 0; 125 1.1 kefren 126 1.8 kefren int confh = open(fname, O_RDONLY, 0); 127 1.1 kefren 128 1.8 kefren if (confh == -1 || fstat(confh, &fs) == -1 || 129 1.8 kefren (mapped = mmap(NULL, fs.st_size, PROT_READ, MAP_SHARED, confh, 0)) 130 1.9 christos == MAP_FAILED) { 131 1.11 christos if (confh != -1) 132 1.11 christos close(confh); 133 1.1 kefren return E_CONF_IO; 134 1.9 christos } 135 1.1 kefren 136 1.8 kefren mapsize = fs.st_size; 137 1.8 kefren nextline = mapped; 138 1.8 kefren for (parseline = 1; ; parseline++) { 139 1.8 kefren char *prev = nextline; 140 1.8 kefren if ((nextline = conf_getlinelimit()) == NULL) 141 1.8 kefren break; 142 1.15 christos while (isspace((unsigned char)*prev) != 0 && prev < nextline) 143 1.8 kefren prev++; 144 1.8 kefren if (nextline - prev < 2) 145 1.8 kefren continue; 146 1.8 kefren else if (nextline - prev > LINEMAXSIZE) 147 1.8 kefren goto parerr; 148 1.8 kefren memcpy(line, prev, nextline - prev); 149 1.8 kefren if (line[0] == '#') 150 1.8 kefren continue; 151 1.8 kefren else 152 1.8 kefren line[nextline - prev] = '\0'; 153 1.8 kefren if (conf_dispatch(line) != 0) 154 1.8 kefren goto parerr; 155 1.8 kefren } 156 1.8 kefren munmap(mapped, mapsize); 157 1.1 kefren close(confh); 158 1.1 kefren return 0; 159 1.8 kefren parerr: 160 1.8 kefren munmap(mapped, mapsize); 161 1.8 kefren close(confh); 162 1.8 kefren return parseline; 163 1.1 kefren } 164 1.1 kefren 165 1.8 kefren char * 166 1.8 kefren conf_getlinelimit(void) 167 1.1 kefren { 168 1.8 kefren char *p = nextline; 169 1.1 kefren 170 1.8 kefren if (nextline < mapped || (size_t)(nextline - mapped) >= mapsize) 171 1.8 kefren return NULL; 172 1.8 kefren 173 1.8 kefren for (p = nextline; *p != '\n' && (size_t)(p - mapped) < mapsize; p++); 174 1.8 kefren return p + 1; 175 1.1 kefren } 176 1.1 kefren 177 1.1 kefren /* 178 1.1 kefren * Looks for a matching command on a line 179 1.1 kefren */ 180 1.1 kefren int 181 1.1 kefren conf_dispatch(char *line) 182 1.1 kefren { 183 1.1 kefren int i, last_match = -1, matched = 0; 184 1.1 kefren char *command, *nline = line; 185 1.1 kefren 186 1.1 kefren if (strlen(line) == 0 || line[0] == '#') 187 1.1 kefren return E_CONF_OK; 188 1.1 kefren command = NextCommand(nline); 189 1.1 kefren for (i = 0; main_commands[i].func != NULL; i++) 190 1.1 kefren if (strncasecmp(main_commands[i].com, command, 191 1.7 kefren strlen(main_commands[i].com)) == 0) { 192 1.1 kefren matched++; 193 1.1 kefren last_match = i; 194 1.1 kefren } 195 1.1 kefren if (matched == 0) 196 1.1 kefren return E_CONF_NOMATCH; 197 1.1 kefren else if (matched > 1) 198 1.1 kefren return E_CONF_AMBIGUOUS; 199 1.1 kefren 200 1.8 kefren if (nline == NULL || checkeol(nline) != 0) 201 1.1 kefren return E_CONF_PARAM; 202 1.1 kefren return main_commands[last_match].func(nline); 203 1.1 kefren } 204 1.1 kefren 205 1.1 kefren /* 206 1.1 kefren * Checks if a line is terminated or else if it contains 207 1.1 kefren * a start block bracket. If it's semicolon terminated 208 1.1 kefren * then trim it. 209 1.1 kefren */ 210 1.1 kefren int 211 1.1 kefren checkeol(char *line) 212 1.1 kefren { 213 1.2 christos size_t len = strlen(line); 214 1.8 kefren if (len > 0 && line[len - 1] == '\n') { 215 1.8 kefren line[len - 1] = '\0'; 216 1.8 kefren len--; 217 1.8 kefren } 218 1.2 christos if (len > 0 && line[len - 1] == ';') { 219 1.2 christos line[len - 1] = '\0'; 220 1.1 kefren return 0; 221 1.1 kefren } 222 1.2 christos for (size_t i = 0; i < len; i++) 223 1.1 kefren if (line[i] == '{') 224 1.1 kefren return 0; 225 1.1 kefren return -1; 226 1.1 kefren } 227 1.1 kefren 228 1.14 christos static int 229 1.14 christos fill_info(void *param, int (*func)(void *, char *)) 230 1.14 christos { 231 1.14 christos char buf[LINEMAXSIZE]; 232 1.14 christos 233 1.14 christos for ( ; ; ) { 234 1.14 christos char *prev = nextline; 235 1.14 christos parseline++; 236 1.14 christos nextline = conf_getlinelimit(); 237 1.14 christos if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE) 238 1.14 christos return -1; 239 1.15 christos while (isspace((unsigned char)*prev) != 0 && prev < nextline) 240 1.14 christos prev++; 241 1.14 christos size_t diff = (size_t)(nextline - prev); 242 1.14 christos if (diff > LINEMAXSIZE) 243 1.14 christos return -1; 244 1.14 christos memcpy(buf, prev, diff); 245 1.14 christos if (diff < 2 || buf[0] == '#') 246 1.14 christos continue; 247 1.14 christos else if (buf[0] == '}') 248 1.14 christos break; 249 1.14 christos else 250 1.14 christos buf[diff] = '\0'; 251 1.14 christos if ((*func)(param, buf) == -1) 252 1.14 christos return -1; 253 1.14 christos } 254 1.14 christos return 0; 255 1.14 christos } 256 1.14 christos 257 1.1 kefren /* 258 1.1 kefren * Sets hello time 259 1.1 kefren */ 260 1.1 kefren int 261 1.1 kefren Fhellotime(char *line) 262 1.1 kefren { 263 1.1 kefren int ht = atoi(line); 264 1.1 kefren if (ht <= 0) 265 1.1 kefren return E_CONF_PARAM; 266 1.1 kefren ldp_hello_time = ht; 267 1.1 kefren return 0; 268 1.1 kefren } 269 1.1 kefren 270 1.1 kefren /* 271 1.1 kefren * Sets command port 272 1.1 kefren */ 273 1.1 kefren int 274 1.1 kefren Fport(char *line) 275 1.1 kefren { 276 1.1 kefren int cp = atoi(line); 277 1.1 kefren if (cp <= 0 || cp > 65535) 278 1.1 kefren return E_CONF_PARAM; 279 1.1 kefren command_port = cp; 280 1.1 kefren return 0; 281 1.1 kefren } 282 1.1 kefren 283 1.1 kefren /* 284 1.1 kefren * Sets neighbour keepalive 285 1.1 kefren */ 286 1.1 kefren int 287 1.1 kefren Fkeepalive(char *line) 288 1.1 kefren { 289 1.1 kefren int kt = atoi(line); 290 1.1 kefren if (kt <= 0) 291 1.1 kefren return E_CONF_PARAM; 292 1.1 kefren ldp_keepalive_time = kt; 293 1.1 kefren return 0; 294 1.1 kefren } 295 1.1 kefren 296 1.1 kefren /* 297 1.1 kefren * Sets neighbour holddown timer 298 1.1 kefren */ 299 1.1 kefren int 300 1.1 kefren Fholddown(char *line) 301 1.1 kefren { 302 1.1 kefren int hdt = atoi(line); 303 1.1 kefren if (hdt <= 0) 304 1.1 kefren return E_CONF_PARAM; 305 1.1 kefren ldp_holddown_time = hdt; 306 1.1 kefren return 0; 307 1.1 kefren } 308 1.1 kefren 309 1.1 kefren int 310 1.1 kefren Fminlabel(char *line) 311 1.1 kefren { 312 1.1 kefren int ml = atoi(line); 313 1.1 kefren if (ml <= 0) 314 1.1 kefren return E_CONF_PARAM; 315 1.1 kefren min_label = ml; 316 1.1 kefren return 0; 317 1.1 kefren } 318 1.1 kefren 319 1.1 kefren int 320 1.1 kefren Fmaxlabel(char *line) 321 1.1 kefren { 322 1.1 kefren int ml = atoi(line); 323 1.1 kefren if (ml <= 0) 324 1.1 kefren return E_CONF_PARAM; 325 1.1 kefren max_label = ml; 326 1.1 kefren return 0; 327 1.1 kefren } 328 1.1 kefren 329 1.1 kefren int 330 1.1 kefren Fldpid(char *line) 331 1.1 kefren { 332 1.1 kefren if (inet_pton(AF_INET, line, &conf_ldp_id) != 1) 333 1.1 kefren return E_CONF_PARAM; 334 1.1 kefren return 0; 335 1.1 kefren } 336 1.1 kefren 337 1.1 kefren int 338 1.1 kefren Fneighbour(char *line) 339 1.1 kefren { 340 1.1 kefren char *peer; 341 1.1 kefren struct conf_neighbour *nei; 342 1.1 kefren struct in_addr ad; 343 1.1 kefren 344 1.1 kefren peer = NextCommand(line); 345 1.1 kefren if (inet_pton(AF_INET, peer, &ad) != 1) 346 1.1 kefren return E_CONF_PARAM; 347 1.1 kefren 348 1.1 kefren nei = calloc(1, sizeof(*nei)); 349 1.2 christos if (nei == NULL) 350 1.2 christos return E_CONF_MEM; 351 1.1 kefren nei->address.s_addr = ad.s_addr; 352 1.1 kefren SLIST_INSERT_HEAD(&conei_head, nei, neilist); 353 1.1 kefren 354 1.14 christos return fill_info(nei, (int (*)(void *, char *))Gneighbour); 355 1.1 kefren } 356 1.1 kefren 357 1.1 kefren /* 358 1.1 kefren * neighbour { } sub-commands 359 1.1 kefren */ 360 1.1 kefren int 361 1.1 kefren Gneighbour(struct conf_neighbour *nei, char *line) 362 1.1 kefren { 363 1.1 kefren if (strncasecmp("authenticate", line, 12) == 0) { 364 1.1 kefren nei->authenticate = 1; 365 1.1 kefren return 0; 366 1.1 kefren } 367 1.1 kefren return -1; 368 1.1 kefren } 369 1.3 kefren 370 1.3 kefren int 371 1.3 kefren Fnodefault(char *line) 372 1.3 kefren { 373 1.3 kefren int nd = atoi(line); 374 1.3 kefren if (nd < 0) 375 1.3 kefren return E_CONF_PARAM; 376 1.3 kefren no_default_route = nd; 377 1.3 kefren return 0; 378 1.3 kefren } 379 1.4 kefren 380 1.4 kefren int 381 1.4 kefren Floopdetection(char *line) 382 1.4 kefren { 383 1.4 kefren int loopd = atoi(line); 384 1.4 kefren if (loopd < 0) 385 1.4 kefren return E_CONF_PARAM; 386 1.4 kefren loop_detection = loopd; 387 1.4 kefren return 0; 388 1.4 kefren } 389 1.5 kefren 390 1.7 kefren /* 391 1.7 kefren * Interface sub-commands 392 1.7 kefren */ 393 1.5 kefren int 394 1.7 kefren Finterface(char *line) 395 1.5 kefren { 396 1.7 kefren char *ifname; 397 1.10 christos struct conf_interface *conf_if; 398 1.7 kefren 399 1.10 christos if ((ifname = NextCommand(line)) == NULL) 400 1.7 kefren return -1; 401 1.10 christos if ((conf_if = calloc(1, sizeof(*conf_if))) == NULL) 402 1.10 christos return -1; 403 1.10 christos 404 1.7 kefren strlcpy(conf_if->if_name, ifname, IF_NAMESIZE); 405 1.7 kefren SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist); 406 1.5 kefren 407 1.14 christos return fill_info(conf_if, (int (*)(void *, char *))Ginterface); 408 1.7 kefren } 409 1.7 kefren 410 1.7 kefren int 411 1.7 kefren Ginterface(struct conf_interface *conf_if, char *buf) 412 1.7 kefren { 413 1.7 kefren int i; 414 1.7 kefren 415 1.7 kefren for (i = 0; intf_commands[i].func != NULL; i++) 416 1.7 kefren if (strncasecmp(buf, intf_commands[i].com, 417 1.7 kefren strlen(intf_commands[i].com)) == 0) 418 1.7 kefren return intf_commands[i].func(conf_if, buf + 419 1.7 kefren strlen(intf_commands[i].com) + 1); 420 1.7 kefren /* command not found */ 421 1.7 kefren return -1; 422 1.7 kefren } 423 1.7 kefren 424 1.7 kefren /* sets transport address */ 425 1.7 kefren int 426 1.7 kefren Itaddr(struct conf_interface *conf_if, char *buf) 427 1.7 kefren { 428 1.7 kefren if (inet_pton(AF_INET, buf, &conf_if->tr_addr) != 1) 429 1.7 kefren return -1; 430 1.7 kefren return 0; 431 1.7 kefren } 432 1.7 kefren 433 1.7 kefren /* sets passive-interface on */ 434 1.7 kefren int 435 1.7 kefren Ipassive(struct conf_interface *conf_if, char *buf) 436 1.7 kefren { 437 1.7 kefren conf_if->passive = 1; 438 1.5 kefren return 0; 439 1.5 kefren } 440