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