conffile.c revision 1.8 1 /* $NetBSD: conffile.c,v 1.8 2013/10/18 14:14:14 kefren 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 return E_CONF_IO;
126
127 mapsize = fs.st_size;
128 nextline = mapped;
129 for (parseline = 1; ; parseline++) {
130 char *prev = nextline;
131 if ((nextline = conf_getlinelimit()) == NULL)
132 break;
133 while (isspace((int)*prev) != 0 && prev < nextline)
134 prev++;
135 if (nextline - prev < 2)
136 continue;
137 else if (nextline - prev > LINEMAXSIZE)
138 goto parerr;
139 memcpy(line, prev, nextline - prev);
140 if (line[0] == '#')
141 continue;
142 else
143 line[nextline - prev] = '\0';
144 if (conf_dispatch(line) != 0)
145 goto parerr;
146 }
147 munmap(mapped, mapsize);
148 close(confh);
149 return 0;
150 parerr:
151 munmap(mapped, mapsize);
152 close(confh);
153 return parseline;
154 }
155
156 char *
157 conf_getlinelimit(void)
158 {
159 char *p = nextline;
160
161 if (nextline < mapped || (size_t)(nextline - mapped) >= mapsize)
162 return NULL;
163
164 for (p = nextline; *p != '\n' && (size_t)(p - mapped) < mapsize; p++);
165 return p + 1;
166 }
167
168 /*
169 * Looks for a matching command on a line
170 */
171 int
172 conf_dispatch(char *line)
173 {
174 int i, last_match = -1, matched = 0;
175 char *command, *nline = line;
176
177 if (strlen(line) == 0 || line[0] == '#')
178 return E_CONF_OK;
179 command = NextCommand(nline);
180 for (i = 0; main_commands[i].func != NULL; i++)
181 if (strncasecmp(main_commands[i].com, command,
182 strlen(main_commands[i].com)) == 0) {
183 matched++;
184 last_match = i;
185 }
186 if (matched == 0)
187 return E_CONF_NOMATCH;
188 else if (matched > 1)
189 return E_CONF_AMBIGUOUS;
190
191 if (nline == NULL || checkeol(nline) != 0)
192 return E_CONF_PARAM;
193 return main_commands[last_match].func(nline);
194 }
195
196 /*
197 * Checks if a line is terminated or else if it contains
198 * a start block bracket. If it's semicolon terminated
199 * then trim it.
200 */
201 int
202 checkeol(char *line)
203 {
204 size_t len = strlen(line);
205 if (len > 0 && line[len - 1] == '\n') {
206 line[len - 1] = '\0';
207 len--;
208 }
209 if (len > 0 && line[len - 1] == ';') {
210 line[len - 1] = '\0';
211 return 0;
212 }
213 for (size_t i = 0; i < len; i++)
214 if (line[i] == '{')
215 return 0;
216 return -1;
217 }
218
219 /*
220 * Sets hello time
221 */
222 int
223 Fhellotime(char *line)
224 {
225 int ht = atoi(line);
226 if (ht <= 0)
227 return E_CONF_PARAM;
228 ldp_hello_time = ht;
229 return 0;
230 }
231
232 /*
233 * Sets command port
234 */
235 int
236 Fport(char *line)
237 {
238 int cp = atoi(line);
239 if (cp <= 0 || cp > 65535)
240 return E_CONF_PARAM;
241 command_port = cp;
242 return 0;
243 }
244
245 /*
246 * Sets neighbour keepalive
247 */
248 int
249 Fkeepalive(char *line)
250 {
251 int kt = atoi(line);
252 if (kt <= 0)
253 return E_CONF_PARAM;
254 ldp_keepalive_time = kt;
255 return 0;
256 }
257
258 /*
259 * Sets neighbour holddown timer
260 */
261 int
262 Fholddown(char *line)
263 {
264 int hdt = atoi(line);
265 if (hdt <= 0)
266 return E_CONF_PARAM;
267 ldp_holddown_time = hdt;
268 return 0;
269 }
270
271 int
272 Fminlabel(char *line)
273 {
274 int ml = atoi(line);
275 if (ml <= 0)
276 return E_CONF_PARAM;
277 min_label = ml;
278 return 0;
279 }
280
281 int
282 Fmaxlabel(char *line)
283 {
284 int ml = atoi(line);
285 if (ml <= 0)
286 return E_CONF_PARAM;
287 max_label = ml;
288 return 0;
289 }
290
291 int
292 Fldpid(char *line)
293 {
294 if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
295 return E_CONF_PARAM;
296 return 0;
297 }
298
299 int
300 Fneighbour(char *line)
301 {
302 char *peer;
303 struct conf_neighbour *nei;
304 struct in_addr ad;
305 char buf[LINEMAXSIZE];
306
307 peer = NextCommand(line);
308 if (inet_pton(AF_INET, peer, &ad) != 1)
309 return E_CONF_PARAM;
310
311 nei = calloc(1, sizeof(*nei));
312 if (nei == NULL)
313 return E_CONF_MEM;
314 nei->address.s_addr = ad.s_addr;
315 SLIST_INSERT_HEAD(&conei_head, nei, neilist);
316
317 for ( ; ; ) {
318 char *prev = nextline;
319 parseline++;
320 nextline = conf_getlinelimit();
321 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE)
322 return -1;
323 while (isspace((int)*prev) != 0 && prev < nextline)
324 prev++;
325 memcpy(buf, prev, nextline - prev);
326 if (nextline - prev < 2 || buf[0] == '#')
327 continue;
328 else if (buf[0] == '}')
329 break;
330 else
331 buf[nextline - prev] = '\0';
332 if (Gneighbour(nei, buf) == -1)
333 return -1;
334 }
335 return -1;
336 }
337
338 /*
339 * neighbour { } sub-commands
340 */
341 int
342 Gneighbour(struct conf_neighbour *nei, char *line)
343 {
344 if (strncasecmp("authenticate", line, 12) == 0) {
345 nei->authenticate = 1;
346 return 0;
347 }
348 return -1;
349 }
350
351 int
352 Fnodefault(char *line)
353 {
354 int nd = atoi(line);
355 if (nd < 0)
356 return E_CONF_PARAM;
357 no_default_route = nd;
358 return 0;
359 }
360
361 int
362 Floopdetection(char *line)
363 {
364 int loopd = atoi(line);
365 if (loopd < 0)
366 return E_CONF_PARAM;
367 loop_detection = loopd;
368 return 0;
369 }
370
371 /*
372 * Interface sub-commands
373 */
374 int
375 Finterface(char *line)
376 {
377 char *ifname;
378 struct conf_interface *conf_if = calloc(1, sizeof(*conf_if));
379 char buf[LINEMAXSIZE];
380
381 ifname = NextCommand(line);
382 if (conf_if == NULL || ifname == NULL)
383 return -1;
384 strlcpy(conf_if->if_name, ifname, IF_NAMESIZE);
385 SLIST_INSERT_HEAD(&coifs_head, conf_if, iflist);
386
387 for ( ; ; ) {
388 char *prev = nextline;
389 parseline++;
390 nextline = conf_getlinelimit();
391 if (nextline == NULL || (size_t)(nextline - prev) > LINEMAXSIZE)
392 return -1;
393 while (isspace((int)*prev) != 0 && prev < nextline)
394 prev++;
395 memcpy(buf, prev, nextline - prev);
396 if (nextline - prev < 2 || buf[0] == '#')
397 continue;
398 else if (buf[0] == '}')
399 break;
400 else
401 buf[nextline - prev] = '\0';
402 if (Ginterface(conf_if, buf) == -1)
403 return -1;
404 }
405 return 0;
406 }
407
408 int
409 Ginterface(struct conf_interface *conf_if, char *buf)
410 {
411 int i;
412
413 for (i = 0; intf_commands[i].func != NULL; i++)
414 if (strncasecmp(buf, intf_commands[i].com,
415 strlen(intf_commands[i].com)) == 0)
416 return intf_commands[i].func(conf_if, buf +
417 strlen(intf_commands[i].com) + 1);
418 /* command not found */
419 return -1;
420 }
421
422 /* sets transport address */
423 int
424 Itaddr(struct conf_interface *conf_if, char *buf)
425 {
426 if (inet_pton(AF_INET, buf, &conf_if->tr_addr) != 1)
427 return -1;
428 return 0;
429 }
430
431 /* sets passive-interface on */
432 int
433 Ipassive(struct conf_interface *conf_if, char *buf)
434 {
435 conf_if->passive = 1;
436 return 0;
437 }
438