conffile.c revision 1.14 1 /* $NetBSD: conffile.c,v 1.14 2025/09/20 15:36:29 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((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 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((int)*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