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 (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
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 extern int ldp_hello_time, ldp_keepalive_time, ldp_holddown_time, command_port,
48 min_label, max_label, no_default_route, loop_detection;
49 int confh;
50 struct in_addr conf_ldp_id;
51
52 static int conf_dispatch(char*);
53 static int conf_readline(char*, size_t);
54 static int checkeol(char*);
55 static int Fhellotime(char*);
56 static int Fport(char*);
57 static int Fholddown(char*);
58 static int Fkeepalive(char*);
59 static int Fmaxlabel(char*);
60 static int Fminlabel(char*);
61 static int Fldpid(char*);
62 static int Fneighbour(char*);
63 static int Gneighbour(struct conf_neighbour *, char *);
64 static int Fnodefault(char*);
65 static int Floopdetection(char*);
66 static int Fpassiveif(char*);
67
68 struct conf_func {
69 char com[64];
70 int (* func)(char *);
71 };
72
73 struct 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 */
92 int
93 conf_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 */
120 int
121 conf_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 */
147 int
148 conf_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 */
177 int
178 checkeol(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 */
194 int
195 Fhellotime(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 */
207 int
208 Fport(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 */
220 int
221 Fkeepalive(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 */
233 int
234 Fholddown(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
243 int
244 Fminlabel(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
253 int
254 Fmaxlabel(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
263 int
264 Fldpid(char *line)
265 {
266 if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
267 return E_CONF_PARAM;
268 return 0;
269 }
270
271 int
272 Fneighbour(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 */
301 int
302 Gneighbour(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
311 int
312 Fnodefault(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
321 int
322 Floopdetection(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
331 int
332 Fpassiveif(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