1 /* http://dhcpd-pools.sourceforge.net/
2 ** Copyright 2006- Sami Kerola <kerolasa@iki.fi>
4 ** This program is free software: you can redistribute it and/or modify
5 ** it under the terms of the GNU General Public License as published by
6 ** the Free Software Foundation, either version 3 of the License, or
7 ** (at your option) any later version.
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ** GNU General Public License for more details.
14 ** You should have received a copy of the GNU General Public License
15 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #else /* Not STDC_HEADERS */
25 extern char *malloc();
26 #define EXIT_FAILURE 1 /* Failing exit status. */
27 #define EXIT_SUCCESS 0 /* Successful exit status. */
28 #endif /* STDC_HEADERS */
36 #include <arpa/inet.h>
43 #include <netinet/in.h>
48 #define _XOPEN_SOURCE 600
51 #include "dhcpd-pools.h"
54 /* Parse dhcpd.leases file. All performance boosts for this function are
56 int parse_leases(void)
59 char *line, *ipstring, *macstring = NULL;
61 struct stat lease_file_stats;
62 struct macaddr_t *macaddr_p = NULL;
63 unsigned long leasesmallocsize;
64 unsigned long touchesmallocsize;
65 unsigned long backupsmallocsize;
66 int sw_active_lease = 0;
68 num_touches = num_leases = num_backups = 0;
70 dhcpd_leases = fopen(config.dhcpdlease_file, "r");
71 if (dhcpd_leases == NULL) {
72 err(EXIT_FAILURE, "parse_leases: %s",
73 config.dhcpdlease_file);
75 #ifdef POSIX_FADV_WILLNEED
76 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_WILLNEED);
78 err(EXIT_FAILURE, "parse_leases: fadvise %s",
79 config.dhcpdlease_file);
81 #endif /* POSIX_FADV_WILLNEED */
82 #ifdef POSIX_FADV_SEQUENTIAL
83 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_SEQUENTIAL);
85 err(EXIT_FAILURE, "parse_leases: fadvise %s",
86 config.dhcpdlease_file);
88 #endif /* POSIX_FADV_SEQUENTIAL */
90 /* I found out that there's one lease address per 300 bytes in
91 * dhcpd.leases file. Malloc is little bit pessimistic and uses 250.
92 * If someone has higher density in lease file I'm interested to
94 if (stat(config.dhcpdlease_file, &lease_file_stats)) {
95 err(EXIT_FAILURE, "parse_leases: %s",
96 config.dhcpdlease_file);
98 leasesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
99 touchesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
100 backupsmallocsize = (lease_file_stats.st_size / 120) + MAXLEN - 2;
101 leases = safe_malloc(sizeof(long int) * leasesmallocsize);
103 safe_malloc((size_t) sizeof(long int) * touchesmallocsize);
105 line = safe_malloc(sizeof(long int) * MAXLEN);
106 ipstring = safe_malloc(sizeof(long int) * MAXLEN);
107 if (config.output_format[0] == 'X') {
108 macstring = safe_malloc(sizeof(char) * 18);
109 macaddr = safe_malloc(sizeof(struct macaddr_t));
111 macaddr_p->next = NULL;
114 while (!feof(dhcpd_leases)) {
115 fgets(line, MAXLEN, dhcpd_leases);
116 /* It's a lease, save IP */
117 if (strstr(line, "lease") == line) {
118 strncpy(ipstring, line, (size_t) MAXLEN);
119 nth_field(2, ipstring, ipstring);
120 inet_aton(ipstring, &inp);
123 /* Copy IP to correct array */
124 else if (strstr(line, "binding state active")) {
125 leases[num_leases] = htonl(inp.s_addr);
127 assert(!(leasesmallocsize < num_leases));
129 } else if (strstr(line, " binding state free")) {
130 touches[num_touches] = htonl(inp.s_addr);
132 assert(!(touchesmallocsize < num_touches));
133 } else if (strstr(line, " binding state backup")) {
134 if (num_backups == 0) {
136 safe_malloc((size_t) sizeof(long int) *
139 backups[num_backups] = htonl(inp.s_addr);
141 assert(!(backupsmallocsize < num_backups));
144 if ((macaddr != NULL)
145 && (sw_active_lease == 1)
146 && (strstr(line, "hardware ethernet"))) {
147 nth_field(3, macstring, line);
148 macstring[17] = '\0';
149 macaddr_p->ethernet = safe_strdup(macstring);
150 macaddr_p->ip = safe_strdup(ipstring);
152 safe_malloc(sizeof(struct macaddr_t));
153 macaddr_p = macaddr_p->next;
154 macaddr_p->next = NULL;
159 if (macaddr != NULL) {
162 fclose(dhcpd_leases);
166 /* Like strcpy but for field which is separated by white spaces. Number of
167 * first field is 1 and not 0 like C programs should have. Question of
168 * semantics, send mail to author if this annoys. All performance boosts for
169 * this function are well come. */
170 int nth_field(int n, char *dest, const char *src)
172 int i, j = 0, wordn = 0, len;
176 for (i = 0; i < len; i++) {
177 if (isspace(src[i])) {
196 /* dhcpd.conf interesting words */
197 int is_interesting_config_clause(char *s)
199 if (strstr(s, "range")) {
201 } else if (strstr(s, "shared-network")) {
203 } else if (strstr(s, "include")) {
210 /* FIXME: This spagetti monster function need to be rewrote at least ones. */
211 void parse_config(int is_include, char *config_file,
212 struct shared_network_t *shared_p)
215 int i = 0, newclause = true, argument = false, comment =
216 false, braces = 0, quote = false;
218 int braces_shared = 1000;
220 struct range_t *range_p;
222 word = safe_malloc(sizeof(char) * MAXLEN);
225 /* Default place holder for ranges "All networks". */
226 shared_p->name = shared_networks->name;
229 /* Open configuration file */
230 dhcpd_config = fopen(config_file, "r");
231 if (dhcpd_config == NULL) {
232 err(EXIT_FAILURE, "parse_config: %s", config_file);
234 #ifdef POSIX_FADV_WILLNEED
235 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_WILLNEED);
237 err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
239 #endif /* POSIX_FADV_WILLNEED */
240 #ifdef POSIX_FADV_SEQUENTIAL
241 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_SEQUENTIAL);
243 err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
245 #endif /* POSIX_FADV_SEQUENTIAL */
247 /* Very hairy stuff begins. */
248 while (!feof(dhcpd_config)) {
249 c = fgetc(dhcpd_config);
250 /* Certain characters are magical */
252 /* Handle comments if they are not quoted */
254 if (quote == false) {
259 if (comment == false) {
261 /* Either one or zero */
266 /* New line resets comment section, but
268 if (quote == false) {
273 /* Quoted colon does not mean new clause */
277 if (comment == false && argument != 2
281 } else if (argument == 2) {
282 /* Range ends to ; and this hair in code
283 * make two ranges wrote to gether like...
285 * range 10.20.30.40 10.20.30.41;range 10.20.30.42 10.20.30.43;
287 * ...to be interpreted correctly. */
295 if (comment == false) {
298 /* i == 0 detects word that ends to brace like:
300 * shared-network DSL{ ... */
309 if (comment == false) {
311 /* End of shared-network */
312 if (braces_shared == braces) {
313 /* FIXME: Using 1000 is lame, but
315 braces_shared = 1000;
316 shared_p = shared_networks;
318 /* Not literally true, but works for this
327 /* Either inside comment or Nth word of clause. */
329 || (newclause == false && argument == 0)) {
332 /* Strip white spaces before new clause word. */
333 if ((newclause == true || argument != 0) && isspace(c)
337 /* Save to word which clause this is. */
338 if ((newclause == true || argument != 0)
339 && (!isspace(c) || quote == true)) {
342 /* Long word which is almost causing overflow. None
343 * of words are this long which the program is
351 /* See if clause is something that parser is looking for. */
352 else if (newclause == true) {
353 /* Insert string end & set state */
358 argument = is_interesting_config_clause(word);
360 /* words after range, shared-network or include */
361 else if (argument != 0) {
368 /* printf ("range 2nd ip: %s\n", word); */
369 range_p = ranges + num_ranges;
370 inet_aton(word, &inp);
372 range_p->last_ip = htonl(inp.s_addr) + 1;
374 range_p->touched = 0;
375 range_p->backups = 0;
376 range_p->shared_net = shared_p;
378 if (RANGES < num_ranges + 1) {
385 range_p = ranges + num_ranges;
390 /* printf ("range 1nd ip: %s\n", word); */
391 range_p = ranges + num_ranges;
392 if (!(inet_aton(word, &inp))) {
393 /* word was not ip, try
397 range_p->first_ip = htonl(inp.s_addr) - 1;
401 /* printf ("shared-network named: %s\n", word); */
402 num_shared_networks++;
404 shared_networks + num_shared_networks;
405 shared_p->name = safe_strdup(word);
406 shared_p->available = 0;
408 shared_p->touched = 0;
409 shared_p->backups = 0;
410 if (SHARED_NETWORKS <
411 num_shared_networks + 2) {
413 * away by reallocationg
416 "parse_config: increase default.h SHARED_NETWORKS and recompile");
419 braces_shared = braces;
422 /* printf ("include file: %s\n", word); */
424 parse_config(false, word, shared_p);
428 /* printf ("nothing interesting: %s\n", word); */
432 warnx("impossible occurred, report a bug");
438 fclose(dhcpd_config);