2 ** Copyright (C) 2006- Sami Kerola < >
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 2 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, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #else /* Not STDC_HEADERS */
31 extern char *malloc();
32 #define EXIT_FAILURE 1 /* Failing exit status. */
33 #define EXIT_SUCCESS 0 /* Successful exit status. */
34 #endif /* STDC_HEADERS */
43 #include <arpa/inet.h>
44 #include <netinet/in.h>
45 #include <sys/socket.h>
47 #include <sys/types.h>
48 #define _XOPEN_SOURCE 600
54 #include "dhcpd-pools.h"
57 /* Parse dhcpd.leases file. All performance boosts for this
58 * function are wellcome */
59 int parse_leases(void)
62 char *line, *ipstring, *macstring, *macstring2;
64 struct stat lease_file_stats;
65 unsigned long leasesmallocsize;
66 unsigned long touchesmallocsize;
67 unsigned long backupsmallocsize;
68 int sw_active_lease = 0;
70 num_touches = num_leases = num_backups = 0;
72 dhcpd_leases = fopen(config.dhcpdlease_file, "r");
73 if (dhcpd_leases == NULL) {
74 eprintf("parse_leases: %s:", config.dhcpdlease_file);
77 #ifdef POSIX_FADV_NOREUSE
78 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_NOREUSE);
80 eprintf("parse_leases: fadvise:");
83 #endif /* POSIX_FADV_NOREUSE */
84 #ifdef POSIX_FADV_SEQUENTIAL
85 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_SEQUENTIAL);
87 eprintf("parse_leases: fadvise:");
90 #endif /* POSIX_FADV_SEQUENTIAL */
91 /* I found out that there's one lease address per 300 bytes in
92 * dhcpd.leases file. Malloc is little bit pessimistic and uses
93 * 250. If someone has higher density in lease file I'm
94 * interested to hear about that. */
95 if (stat(config.dhcpdlease_file, &lease_file_stats)) {
96 eprintf("parse_leases: %s:", config.dhcpdlease_file);
99 leasesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
100 touchesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
101 backupsmallocsize = (lease_file_stats.st_size / 120) + MAXLEN - 2;
102 leases = safe_malloc(sizeof(long int) * leasesmallocsize);
104 safe_malloc((size_t) sizeof(long int) * touchesmallocsize);
106 line = safe_malloc(sizeof(long int) * MAXLEN);
107 ipstring = safe_malloc(sizeof(long int) * MAXLEN);
108 macstring = safe_malloc(sizeof(long int) * MAXLEN);
109 macstring2 = safe_malloc(sizeof(long int) * MAXLEN);
111 while (!feof(dhcpd_leases)) {
112 fgets(line, MAXLEN, dhcpd_leases);
113 /* It's a lease, save IP */
114 if (strstr(line, "lease") == line) {
115 strncpy(ipstring, line, (size_t) MAXLEN);
116 nth_field(2, ipstring, ipstring);
117 inet_aton(ipstring, &inp);
120 /* Copy IP to correct array */
121 else if (strstr(line, "binding state active")) {
122 leases[num_leases] = htonl(inp.s_addr);
125 } else if (strstr(line, " binding state free")) {
126 touches[num_touches] = htonl(inp.s_addr);
128 } else if (strstr(line, " binding state backup")) {
129 if (num_backups == 0) {
131 safe_malloc((size_t) sizeof(long int) *
134 backups[num_backups] = htonl(inp.s_addr);
138 if ((sw_active_lease == 1)
139 && (strstr(line, "hardware ethernet"))) {
140 nth_field(3, macstring, line);
141 macstring[strlen(macstring) - 1] = '\0';
143 if (config.output_format[0] == 'X') {
145 ("<active_lease>\n\t<ip>%s</ip>\n\t<macaddress>%s</macaddress>\n</active_lease>\n",
146 ipstring, macstring);
150 if ((num_leases > leasesmallocsize) ||
151 (num_touches > touchesmallocsize) ||
152 (num_backups > backupsmallocsize)) {
153 printf("WARNING: running out of memory\n");
154 printf("\tlease/touch/backup = %lu/%lu/%lu\n",
155 leasesmallocsize, touchesmallocsize,
157 printf("\tlease/touch/backup = %lu/%lu/%lu\n",
158 num_leases, num_touches, num_backups);
160 ("Code should realloc() and init new memory, but no time to write that now!\n");
168 /* Like strcpy but for field which is separated by white spaces.
169 * Number of first field is 1 and not 0 like C programs should
170 * have. Question of semantics, send mail to author if this
171 * annoys. All performance boosts for this function are well
173 int nth_field(int n, char *dest, const char *src)
175 int i, j = 0, wordn = 0, len;
179 for (i = 0; i < len; i++) {
180 if (isspace(src[i])) {
199 /* dhcpd.conf interesting words */
200 int is_interesting_config_clause(char *s)
202 if (strstr(s, "shared-network")) {
204 } else if (strstr(s, "range")) {
206 } else if (strstr(s, "include")) {
213 /* TODO: This spagetti monster function need to be rewrote at
215 char *parse_config(int is_include, char *config_file,
216 char *current_shared_name,
217 char *next_free_shared_name,
218 struct shared_network_t *shared_p)
221 int i = 0, newclause = true, argument = false, comment =
222 false, braces = 0, quote = false;
224 int braces_shared = 1000;
226 struct range_t *range_p;
228 char *last_shared_name;
229 last_shared_name = SHARED_NETWORKS_NAMES + shared_net_names;
231 word = safe_malloc(sizeof(char) * MAXLEN);
234 /* Default place holder for ranges "All networks". */
235 shared_p->name = current_shared_name;
238 /* Open configuration file */
239 dhcpd_config = fopen(config_file, "r");
240 if (dhcpd_config == NULL) {
241 eprintf("parse_config: %s:", config_file);
244 #ifdef POSIX_FADV_NOREUSE
245 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_NOREUSE);
247 eprintf("parse_config: fadvise:");
250 #endif /* POSIX_FADV_NOREUSE */
251 #ifdef POSIX_FADV_SEQUENTIAL
252 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_SEQUENTIAL);
254 eprintf("parse_config: fadvise:");
257 #endif /* POSIX_FADV_SEQUENTIAL */
258 /* Very hairy stuff begins. */
259 while (!feof(dhcpd_config)) {
260 c = fgetc(dhcpd_config);
261 /* Certain characters are magical */
263 /* Handle comments if they are not quoted */
265 if (quote == false) {
270 if (comment == false) {
272 /* Either one or zero */
277 /* New line resets comment section, but not if quoted */
278 if (quote == false) {
283 /* Quoted colon does not mean new clause */
287 if (comment == false && argument != 2
291 } else if (argument == 2) {
292 /* Range ends to ; and this hair in code make two
293 * ranges wrote to gether like...
295 * range 10.20.30.40 10.20.30.41;range 10.20.30.42 10.20.30.43;
297 * ...to be interpreted correctly. */
305 if (comment == false) {
308 /* i == 0 detects word that ends to brace like:
310 * shared-network DSL{ ... */
319 if (comment == false) {
321 /* End of shared-network */
322 if (braces_shared == braces) {
323 current_shared_name =
325 /* TODO: Using 1000 is lame, but works. */
326 braces_shared = 1000;
327 shared_p = shared_networks;
329 /* Not literally true, but works for this program */
337 /* Either inside comment or Nth word of clause. */
339 || (newclause == false && argument == 0)) {
342 /* Strip white spaces before new clause word. */
343 if ((newclause == true || argument != 0) && isspace(c)
347 /* Save to word which clause this is. */
348 if ((newclause == true || argument != 0)
349 && (!isspace(c) || quote == true)) {
352 /* Long word which is almost causing overflow. Not any of words
353 * this program is looking for are this long. */
360 /* See if clause is something that parser is looking for. */
361 else if (newclause == true) {
362 /* Insert string end & set state */
367 argument = is_interesting_config_clause(word);
369 /* words after range, shared-network or include */
370 else if (argument != 0) {
377 /* printf ("nothing interesting: %s\n", word); */
381 /* printf ("shared-network named: %s\n", word); */
382 strcpy(next_free_shared_name, word);
384 shared_networks + num_shared_networks;
385 num_shared_networks++;
387 shared_p->name = next_free_shared_name;
388 shared_p->available = 0;
390 shared_p->touched = 0;
391 shared_p->backups = 0;
392 /* Temporary abuse of argument variable */
394 strlen(next_free_shared_name) + 1;
395 if (last_shared_name >
396 next_free_shared_name + argument) {
397 next_free_shared_name += argument;
399 /* TODO: make this go away by reallocationg more space. */
401 ("parse_config: End of shared-network space, increase SHARED_NETWORKS_NAMES and recompile");
405 braces_shared = braces;
408 /* printf ("range 2nd ip: %s\n", word); */
409 range_p = ranges + num_ranges;
410 inet_aton(word, &inp);
412 range_p->last_ip = htonl(inp.s_addr) + 1;
414 range_p->touched = 0;
415 range_p->backups = 0;
416 range_p->shared_net = shared_p;
418 if (num_ranges > RANGES) {
420 ("parse_config: Range space full! Increase RANGES and recompile.");
426 /* printf ("range 1nd ip: %s\n", word); */
427 range_p = ranges + num_ranges;
428 inet_aton(word, &inp);
429 range_p->first_ip = htonl(inp.s_addr) - 1;
430 if (range_p->first_ip == UINT_MAX) {
431 /* word was not ip, try again */
437 /* printf ("include file: %s\n", word); */
439 next_free_shared_name =
440 parse_config(false, word, current_shared_name,
441 next_free_shared_name,
447 ("parse_config: This cannot happen, report a bug!");
453 return next_free_shared_name;