Home | History | Annotate | Line # | Download | only in ldpd
      1 /* $NetBSD: conffile.c,v 1.15 2025/09/20 15:42:01 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 (at) 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((unsigned char)*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 static int
    229 fill_info(void *param, int (*func)(void *, char *))
    230 {
    231 	char buf[LINEMAXSIZE];
    232 
    233 	for ( ; ; ) {
    234 		char *prev = nextline;
    235 		parseline++;
    236 		nextline = conf_getlinelimit();
    237 		if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE)
    238 			return -1;
    239 		while (isspace((unsigned char)*prev) != 0 && prev < nextline)
    240 			prev++;
    241 		size_t diff = (size_t)(nextline - prev);
    242 		if (diff > LINEMAXSIZE)
    243 			return -1;
    244 		memcpy(buf, prev, diff);
    245 		if (diff <  2 || buf[0] == '#')
    246 			continue;
    247 		else if (buf[0] == '}')
    248 			break;
    249 		else
    250 			buf[diff] = '\0';
    251 		if ((*func)(param, buf) == -1)
    252 			return -1;
    253 	}
    254 	return 0;
    255 }
    256 
    257 /*
    258  * Sets hello time
    259  */
    260 int
    261 Fhellotime(char *line)
    262 {
    263 	int ht = atoi(line);
    264 	if (ht <= 0)
    265 		return E_CONF_PARAM;
    266 	ldp_hello_time = ht;
    267 	return 0;
    268 }
    269 
    270 /*
    271  * Sets command port
    272  */
    273 int
    274 Fport(char *line)
    275 {
    276 	int cp = atoi(line);
    277 	if (cp <= 0 || cp > 65535)
    278 		return E_CONF_PARAM;
    279 	command_port = cp;
    280 	return 0;
    281 }
    282 
    283 /*
    284  * Sets neighbour keepalive
    285  */
    286 int
    287 Fkeepalive(char *line)
    288 {
    289 	int kt = atoi(line);
    290 	if (kt <= 0)
    291 		return E_CONF_PARAM;
    292 	ldp_keepalive_time = kt;
    293 	return 0;
    294 }
    295 
    296 /*
    297  * Sets neighbour holddown timer
    298  */
    299 int
    300 Fholddown(char *line)
    301 {
    302 	int hdt = atoi(line);
    303 	if (hdt <= 0)
    304 		return E_CONF_PARAM;
    305 	ldp_holddown_time = hdt;
    306 	return 0;
    307 }
    308 
    309 int
    310 Fminlabel(char *line)
    311 {
    312 	int ml = atoi(line);
    313 	if (ml <= 0)
    314 		return E_CONF_PARAM;
    315 	min_label = ml;
    316 	return 0;
    317 }
    318 
    319 int
    320 Fmaxlabel(char *line)
    321 {
    322 	int ml = atoi(line);
    323 	if (ml <= 0)
    324 		return E_CONF_PARAM;
    325 	max_label = ml;
    326 	return 0;
    327 }
    328 
    329 int
    330 Fldpid(char *line)
    331 {
    332 	if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
    333 		return E_CONF_PARAM;
    334 	return 0;
    335 }
    336 
    337 int
    338 Fneighbour(char *line)
    339 {
    340 	char *peer;
    341 	struct conf_neighbour *nei;
    342 	struct in_addr ad;
    343 
    344 	peer = NextCommand(line);
    345 	if (inet_pton(AF_INET, peer, &ad) != 1)
    346 		return E_CONF_PARAM;
    347 
    348 	nei = calloc(1, sizeof(*nei));
    349 	if (nei == NULL)
    350 		return E_CONF_MEM;
    351 	nei->address.s_addr = ad.s_addr;
    352 	SLIST_INSERT_HEAD(&conei_head, nei, neilist);
    353 
    354 	return fill_info(nei, (int (*)(void *, char *))Gneighbour);
    355 }
    356 
    357 /*
    358  * neighbour { } sub-commands
    359  */
    360 int
    361 Gneighbour(struct conf_neighbour *nei, char *line)
    362 {
    363 	if (strncasecmp("authenticate", line, 12) == 0) {
    364 		nei->authenticate = 1;
    365 		return 0;
    366 	}
    367 	return -1;
    368 }
    369 
    370 int
    371 Fnodefault(char *line)
    372 {
    373 	int nd = atoi(line);
    374 	if (nd < 0)
    375 		return E_CONF_PARAM;
    376 	no_default_route = nd;
    377 	return 0;
    378 }
    379 
    380 int
    381 Floopdetection(char *line)
    382 {
    383 	int loopd = atoi(line);
    384 	if (loopd < 0)
    385 		return E_CONF_PARAM;
    386 	loop_detection = loopd;
    387 	return 0;
    388 }
    389 
    390 /*
    391  * Interface sub-commands
    392  */
    393 int
    394 Finterface(char *line)
    395 {
    396 	char *ifname;
    397 	struct conf_interface *conf_if;
    398 
    399 	if ((ifname = NextCommand(line)) == NULL)
    400 		return -1;
    401 	if ((conf_if = calloc(1, sizeof(*conf_if))) == NULL)
    402 		return -1;
    403 
    404 	strlcpy(conf_if->if_name, ifname, IF_NAMESIZE);
    405 	SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist);
    406 
    407 	return fill_info(conf_if, (int (*)(void *, char *))Ginterface);
    408 }
    409 
    410 int
    411 Ginterface(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 */
    425 int
    426 Itaddr(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 */
    434 int
    435 Ipassive(struct conf_interface *conf_if, char *buf)
    436 {
    437 	conf_if->passive = 1;
    438 	return 0;
    439 }
    440