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