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