2 * The dhcpd-pools has BSD 2-clause license which also known as "Simplified
3 * BSD License" or "FreeBSD License".
5 * Copyright 2006- Sami Kerola. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the
19 * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS
20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE
23 * 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
29 * THE POSSIBILITY OF SUCH DAMAGE.
31 * The views and conclusions contained in the software and documentation are
32 * those of the authors and should not be interpreted as representing
33 * official policies, either expressed or implied, of Sami Kerola.
42 #else /* Not STDC_HEADERS */
43 extern char *malloc();
44 #define EXIT_FAILURE 1 /* Failing exit status. */
45 #define EXIT_SUCCESS 0 /* Successful exit status. */
46 #endif /* STDC_HEADERS */
54 #include <arpa/inet.h>
61 #include <netinet/in.h>
66 #define _XOPEN_SOURCE 600
69 #include "dhcpd-pools.h"
72 /* Parse dhcpd.leases file. All performance boosts for this function are
74 int parse_leases(void)
77 char *line, *ipstring, *macstring = NULL;
79 struct stat lease_file_stats;
80 struct macaddr_t *macaddr_p = NULL;
81 unsigned long leasesmallocsize;
82 unsigned long touchesmallocsize;
83 unsigned long backupsmallocsize;
84 int sw_active_lease = 0;
86 num_touches = num_leases = num_backups = 0;
88 dhcpd_leases = fopen(config.dhcpdlease_file, "r");
89 if (dhcpd_leases == NULL) {
90 err(EXIT_FAILURE, "parse_leases: %s",
91 config.dhcpdlease_file);
93 #ifdef POSIX_FADV_WILLNEED
94 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_WILLNEED);
96 err(EXIT_FAILURE, "parse_leases: fadvise %s",
97 config.dhcpdlease_file);
99 #endif /* POSIX_FADV_WILLNEED */
100 #ifdef POSIX_FADV_SEQUENTIAL
101 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_SEQUENTIAL);
103 err(EXIT_FAILURE, "parse_leases: fadvise %s",
104 config.dhcpdlease_file);
106 #endif /* POSIX_FADV_SEQUENTIAL */
108 /* I found out that there's one lease address per 300 bytes in
109 * dhcpd.leases file. Malloc is little bit pessimistic and uses 250.
110 * If someone has higher density in lease file I'm interested to
111 * hear about that. */
112 if (stat(config.dhcpdlease_file, &lease_file_stats)) {
113 err(EXIT_FAILURE, "parse_leases: %s",
114 config.dhcpdlease_file);
116 leasesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
117 touchesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
118 backupsmallocsize = (lease_file_stats.st_size / 120) + MAXLEN - 2;
119 leases = safe_malloc(sizeof(long int) * leasesmallocsize);
121 safe_malloc((size_t) sizeof(long int) * touchesmallocsize);
123 line = safe_malloc(sizeof(long int) * MAXLEN);
124 ipstring = safe_malloc(sizeof(long int) * MAXLEN);
125 if (config.output_format[0] == 'X') {
126 macstring = safe_malloc(sizeof(char) * 18);
127 macaddr = safe_malloc(sizeof(struct macaddr_t));
129 macaddr_p->next = NULL;
132 while (!feof(dhcpd_leases)) {
133 if (!fgets(line, MAXLEN, dhcpd_leases) && ferror(dhcpd_leases)) {
134 err(EXIT_FAILURE, "parse_leases: %s", config.dhcpdlease_file);
136 /* It's a lease, save IP */
137 if (strstr(line, "lease") == line) {
138 strncpy(ipstring, line, (size_t) MAXLEN);
139 nth_field(2, ipstring, ipstring);
140 inet_aton(ipstring, &inp);
143 /* Copy IP to correct array */
144 else if (strstr(line, "binding state active")) {
145 leases[num_leases] = htonl(inp.s_addr);
147 assert(!(leasesmallocsize < num_leases));
149 } else if (strstr(line, " binding state free")) {
150 touches[num_touches] = htonl(inp.s_addr);
152 assert(!(touchesmallocsize < num_touches));
153 } else if (strstr(line, " binding state backup")) {
154 if (num_backups == 0) {
156 safe_malloc((size_t) sizeof(long int) *
159 backups[num_backups] = htonl(inp.s_addr);
161 assert(!(backupsmallocsize < num_backups));
164 if ((macaddr != NULL)
165 && (sw_active_lease == 1)
166 && (strstr(line, "hardware ethernet"))) {
167 nth_field(3, macstring, line);
168 macstring[17] = '\0';
169 macaddr_p->ethernet = safe_strdup(macstring);
170 macaddr_p->ip = safe_strdup(ipstring);
172 safe_malloc(sizeof(struct macaddr_t));
173 macaddr_p = macaddr_p->next;
174 macaddr_p->next = NULL;
179 if (macaddr != NULL) {
182 fclose(dhcpd_leases);
186 /* Like strcpy but for field which is separated by white spaces. Number of
187 * first field is 1 and not 0 like C programs should have. Question of
188 * semantics, send mail to author if this annoys. All performance boosts for
189 * this function are well come. */
190 int nth_field(int n, char *dest, const char *src)
192 int i, j = 0, wordn = 0, len;
196 for (i = 0; i < len; i++) {
197 if (isspace(src[i])) {
216 /* dhcpd.conf interesting words */
217 int is_interesting_config_clause(char *s)
219 if (strstr(s, "range")) {
221 } else if (strstr(s, "shared-network")) {
223 } else if (strstr(s, "include")) {
230 /* FIXME: This spagetti monster function need to be rewrote at least ones. */
231 void parse_config(int is_include, char *config_file,
232 struct shared_network_t *shared_p)
235 int i = 0, newclause = true, argument = false, comment =
236 false, braces = 0, quote = false;
238 int braces_shared = 1000;
240 struct range_t *range_p;
242 word = safe_malloc(sizeof(char) * MAXLEN);
245 /* Default place holder for ranges "All networks". */
246 shared_p->name = shared_networks->name;
249 /* Open configuration file */
250 dhcpd_config = fopen(config_file, "r");
251 if (dhcpd_config == NULL) {
252 err(EXIT_FAILURE, "parse_config: %s", config_file);
254 #ifdef POSIX_FADV_WILLNEED
255 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_WILLNEED);
257 err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
259 #endif /* POSIX_FADV_WILLNEED */
260 #ifdef POSIX_FADV_SEQUENTIAL
261 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_SEQUENTIAL);
263 err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
265 #endif /* POSIX_FADV_SEQUENTIAL */
267 /* Very hairy stuff begins. */
268 while (!feof(dhcpd_config)) {
269 c = fgetc(dhcpd_config);
270 /* Certain characters are magical */
272 /* Handle comments if they are not quoted */
274 if (quote == false) {
279 if (comment == false) {
281 /* Either one or zero */
286 /* New line resets comment section, but
288 if (quote == false) {
293 /* Quoted colon does not mean new clause */
297 if (comment == false && argument != 2
301 } else if (argument == 2) {
302 /* Range ends to ; and this hair in code
303 * make two ranges wrote to gether like...
305 * range 10.20.30.40 10.20.30.41;range 10.20.30.42 10.20.30.43;
307 * ...to be interpreted correctly. */
315 if (comment == false) {
318 /* i == 0 detects word that ends to brace like:
320 * shared-network DSL{ ... */
329 if (comment == false) {
331 /* End of shared-network */
332 if (braces_shared == braces) {
333 /* FIXME: Using 1000 is lame, but
335 braces_shared = 1000;
336 shared_p = shared_networks;
338 /* Not literally true, but works for this
347 /* Either inside comment or Nth word of clause. */
349 || (newclause == false && argument == 0)) {
352 /* Strip white spaces before new clause word. */
353 if ((newclause == true || argument != 0) && isspace(c)
357 /* Save to word which clause this is. */
358 if ((newclause == true || argument != 0)
359 && (!isspace(c) || quote == true)) {
362 /* Long word which is almost causing overflow. None
363 * of words are this long which the program is
371 /* See if clause is something that parser is looking for. */
372 else if (newclause == true) {
373 /* Insert string end & set state */
378 argument = is_interesting_config_clause(word);
380 /* words after range, shared-network or include */
381 else if (argument != 0) {
388 /* printf ("range 2nd ip: %s\n", word); */
389 range_p = ranges + num_ranges;
390 inet_aton(word, &inp);
392 range_p->last_ip = htonl(inp.s_addr) + 1;
394 range_p->touched = 0;
395 range_p->backups = 0;
396 range_p->shared_net = shared_p;
398 if (RANGES < num_ranges + 1) {
405 range_p = ranges + num_ranges;
410 /* printf ("range 1nd ip: %s\n", word); */
411 range_p = ranges + num_ranges;
412 if (!(inet_aton(word, &inp))) {
413 /* word was not ip, try
417 range_p->first_ip = htonl(inp.s_addr) - 1;
421 /* printf ("shared-network named: %s\n", word); */
422 num_shared_networks++;
424 shared_networks + num_shared_networks;
425 shared_p->name = safe_strdup(word);
426 shared_p->available = 0;
428 shared_p->touched = 0;
429 shared_p->backups = 0;
430 if (SHARED_NETWORKS <
431 num_shared_networks + 2) {
433 * away by reallocationg
436 "parse_config: increase default.h SHARED_NETWORKS and recompile");
439 braces_shared = braces;
442 /* printf ("include file: %s\n", word); */
444 parse_config(false, word, shared_p);
448 /* printf ("nothing interesting: %s\n", word); */
452 warnx("impossible occurred, report a bug");
458 fclose(dhcpd_config);