conffile.c revision 1.6
1/* $NetBSD: conffile.c,v 1.6 2013/07/11 10:46:19 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@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
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
47extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
48	min_label, max_label, no_default_route, loop_detection;
49int confh;
50struct in_addr conf_ldp_id;
51
52static int conf_dispatch(char*);
53static int conf_readline(char*, size_t);
54static int checkeol(char*);
55static int Fhellotime(char*);
56static int Fport(char*);
57static int Fholddown(char*);
58static int Fkeepalive(char*);
59static int Fmaxlabel(char*);
60static int Fminlabel(char*);
61static int Fldpid(char*);
62static int Fneighbour(char*);
63static int Gneighbour(struct conf_neighbour *, char *);
64static int Fnodefault(char*);
65static int Floopdetection(char*);
66static int Fpassiveif(char*);
67
68struct conf_func {
69	char com[64];
70	int (* func)(char *);
71};
72
73struct conf_func main_commands[] = {
74	{ "hello-time", Fhellotime },
75	{ "keepalive-time", Fkeepalive },
76	{ "holddown-time", Fholddown },
77	{ "command-port", Fport },
78	{ "min-label", Fminlabel },
79	{ "max-label", Fmaxlabel },
80	{ "LDP-ID", Fldpid },
81	{ "neighbor", Fneighbour },
82	{ "neighbour", Fneighbour },
83	{ "no-default-route", Fnodefault },
84	{ "loop-detection", Floopdetection },
85	{ "passive-if", Fpassiveif },
86	{ "", NULL },
87};
88
89/*
90 * Parses config file
91 */
92int
93conf_parsefile(const char *fname)
94{
95	int i;
96	char buf[LINEMAXSIZE + 1];
97
98	SLIST_INIT(&conei_head);
99	SLIST_INIT(&passifs_head);
100	conf_ldp_id.s_addr = 0;
101
102	confh = open(fname, O_RDONLY, 0);
103
104	if (confh == -1)
105		return E_CONF_IO;
106
107	for (i = 1; conf_readline(buf, sizeof(buf)) >= 0; i++)
108		if (conf_dispatch(buf) != 0) {
109			close(confh);
110			return i;
111		}
112
113	close(confh);
114	return 0;
115}
116
117/*
118 * Reads a line from config file
119 */
120int
121conf_readline(char *buf, size_t bufsize)
122{
123	size_t i;
124
125	for (i = 0; i < bufsize; i++) {
126		if (read(confh, &buf[i], 1) != 1) {
127			if (i == 0)
128				return E_CONF_IO;
129			break;
130		}
131		if (buf[i] == '\n')
132			break;
133		if (i == 0 && isspace((unsigned char)buf[i]) != 0) {
134			i--;
135			continue;
136		}
137	}
138	if (i == bufsize)
139		return E_CONF_MEM;
140	buf[i] = '\0';
141	return i;
142}
143
144/*
145 * Looks for a matching command on a line
146 */
147int
148conf_dispatch(char *line)
149{
150	int i, last_match = -1, matched = 0;
151	char *command, *nline = line;
152
153	if (strlen(line) == 0 || line[0] == '#')
154		return E_CONF_OK;
155	command = NextCommand(nline);
156	for (i = 0; main_commands[i].func != NULL; i++)
157		if (strncasecmp(main_commands[i].com, command,
158		    strlen(command)) == 0) {
159			matched++;
160			last_match = i;
161		}
162	if (matched == 0)
163		return E_CONF_NOMATCH;
164	else if (matched > 1)
165		return E_CONF_AMBIGUOUS;
166
167	if (checkeol(nline) != 0)
168		return E_CONF_PARAM;
169	return main_commands[last_match].func(nline);
170}
171
172/*
173 * Checks if a line is terminated or else if it contains
174 * a start block bracket. If it's semicolon terminated
175 * then trim it.
176 */
177int
178checkeol(char *line)
179{
180	size_t len = strlen(line);
181	if (len > 0 && line[len - 1] == ';') {
182		line[len - 1] = '\0';
183		return 0;
184	}
185	for (size_t i = 0; i < len; i++)
186		if (line[i] == '{')
187			return 0;
188	return -1;
189}
190
191/*
192 * Sets hello time
193 */
194int
195Fhellotime(char *line)
196{
197	int ht = atoi(line);
198	if (ht <= 0)
199		return E_CONF_PARAM;
200	ldp_hello_time = ht;
201	return 0;
202}
203
204/*
205 * Sets command port
206 */
207int
208Fport(char *line)
209{
210	int cp = atoi(line);
211	if (cp <= 0 || cp > 65535)
212		return E_CONF_PARAM;
213	command_port = cp;
214	return 0;
215}
216
217/*
218 * Sets neighbour keepalive
219 */
220int
221Fkeepalive(char *line)
222{
223	int kt = atoi(line);
224	if (kt <= 0)
225		return E_CONF_PARAM;
226	ldp_keepalive_time = kt;
227	return 0;
228}
229
230/*
231 * Sets neighbour holddown timer
232 */
233int
234Fholddown(char *line)
235{
236	int hdt = atoi(line);
237	if (hdt <= 0)
238		return E_CONF_PARAM;
239	ldp_holddown_time = hdt;
240	return 0;
241}
242
243int
244Fminlabel(char *line)
245{
246	int ml = atoi(line);
247	if (ml <= 0)
248		return E_CONF_PARAM;
249	min_label = ml;
250	return 0;
251}
252
253int
254Fmaxlabel(char *line)
255{
256	int ml = atoi(line);
257	if (ml <= 0)
258		return E_CONF_PARAM;
259	max_label = ml;
260	return 0;
261}
262
263int
264Fldpid(char *line)
265{
266	if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
267		return E_CONF_PARAM;
268	return 0;
269}
270
271int
272Fneighbour(char *line)
273{
274	char *peer;
275	struct conf_neighbour *nei;
276	struct in_addr ad;
277	char buf[1024];
278
279	peer = NextCommand(line);
280	if (inet_pton(AF_INET, peer, &ad) != 1)
281		return E_CONF_PARAM;
282
283	nei = calloc(1, sizeof(*nei));
284	if (nei == NULL)
285		return E_CONF_MEM;
286	nei->address.s_addr = ad.s_addr;
287	SLIST_INSERT_HEAD(&conei_head, nei, neilist);
288
289	while (conf_readline(buf, sizeof(buf)) >= 0) {
290		if (buf[0] == '}')
291			return 0;
292		if (Gneighbour(nei, buf) == -1)
293			return -1;
294	}
295	return -1;
296}
297
298/*
299 * neighbour { } sub-commands
300 */
301int
302Gneighbour(struct conf_neighbour *nei, char *line)
303{
304	if (strncasecmp("authenticate", line, 12) == 0) {
305		nei->authenticate = 1;
306		return 0;
307	}
308	return -1;
309}
310
311int
312Fnodefault(char *line)
313{
314	int nd = atoi(line);
315	if (nd < 0)
316		return E_CONF_PARAM;
317	no_default_route = nd;
318	return 0;
319}
320
321int
322Floopdetection(char *line)
323{
324	int loopd = atoi(line);
325	if (loopd < 0)
326		return E_CONF_PARAM;
327	loop_detection = loopd;
328	return 0;
329}
330
331int
332Fpassiveif(char *line)
333{
334	struct passive_if *pif;
335
336	if (strlen(line) > IF_NAMESIZE - 1)
337		return E_CONF_PARAM;
338	pif = calloc(1, sizeof(*pif));
339	strlcpy(pif->if_name, line, IF_NAMESIZE);
340	SLIST_INSERT_HEAD(&passifs_head, pif, listentry);
341	return 0;
342}
343