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 (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
67 struct conf_func {
68 char com[64];
69 int (* func)(char *);
70 };
71
72 struct 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 */
90 int
91 conf_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 */
117 int
118 conf_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 */
144 int
145 conf_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 */
174 int
175 checkeol(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 */
191 int
192 Fhellotime(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 */
204 int
205 Fport(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 */
217 int
218 Fkeepalive(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 */
230 int
231 Fholddown(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
240 int
241 Fminlabel(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
250 int
251 Fmaxlabel(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
260 int
261 Fldpid(char *line)
262 {
263 if (inet_pton(AF_INET, line, &conf_ldp_id) != 1)
264 return E_CONF_PARAM;
265 return 0;
266 }
267
268 int
269 Fneighbour(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 */
298 int
299 Gneighbour(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
308 int
309 Fnodefault(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
318 int
319 Floopdetection(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