2 ** Copyright (C) 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 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 */
30 extern char *malloc();
31 #define EXIT_FAILURE 1 /* Failing exit status. */
32 #define EXIT_SUCCESS 0 /* Successful exit status. */
33 #endif /* STDC_HEADERS */
42 #include <arpa/inet.h>
43 #include <netinet/in.h>
44 #include <sys/socket.h>
46 #include <sys/types.h>
48 #define _XOPEN_SOURCE 600
56 #include "dhcpd-pools.h"
59 /* Parse dhcpd.leases file. All performance boosts for this function are
61 int parse_leases(void)
64 char *line, *ipstring, *macstring, *macstring2;
66 struct stat lease_file_stats;
67 unsigned long leasesmallocsize;
68 unsigned long touchesmallocsize;
69 unsigned long backupsmallocsize;
70 int sw_active_lease = 0;
72 num_touches = num_leases = num_backups = 0;
74 dhcpd_leases = fopen(config.dhcpdlease_file, "r");
75 if (dhcpd_leases == NULL) {
76 err(EXIT_FAILURE, "parse_leases: %s",
77 config.dhcpdlease_file);
79 #ifdef POSIX_FADV_WILLNEED
80 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_WILLNEED);
82 err(EXIT_FAILURE, "parse_leases: fadvise %s", config.dhcpdlease_file);
84 #endif /* POSIX_FADV_WILLNEED */
85 #ifdef POSIX_FADV_SEQUENTIAL
86 posix_fadvise((long) dhcpd_leases, 0, 0, POSIX_FADV_SEQUENTIAL);
88 err(EXIT_FAILURE, "parse_leases: fadvise %s", config.dhcpdlease_file);
90 #endif /* POSIX_FADV_SEQUENTIAL */
92 /* I found out that there's one lease address per 300 bytes in
93 * dhcpd.leases file. Malloc is little bit pessimistic and uses 250.
94 * If someone has higher density in lease file I'm interested to
96 if (stat(config.dhcpdlease_file, &lease_file_stats)) {
97 err(EXIT_FAILURE, "parse_leases: %s",
98 config.dhcpdlease_file);
100 leasesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
101 touchesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2;
102 backupsmallocsize = (lease_file_stats.st_size / 120) + MAXLEN - 2;
103 leases = safe_malloc(sizeof(long int) * leasesmallocsize);
105 safe_malloc((size_t) sizeof(long int) * touchesmallocsize);
107 line = safe_malloc(sizeof(long int) * MAXLEN);
108 ipstring = safe_malloc(sizeof(long int) * MAXLEN);
109 macstring = safe_malloc(sizeof(long int) * MAXLEN);
110 macstring2 = safe_malloc(sizeof(long int) * MAXLEN);
112 while (!feof(dhcpd_leases)) {
113 fgets(line, MAXLEN, dhcpd_leases);
114 /* It's a lease, save IP */
115 if (strstr(line, "lease") == line) {
116 strncpy(ipstring, line, (size_t) MAXLEN);
117 nth_field(2, ipstring, ipstring);
118 inet_aton(ipstring, &inp);
121 /* Copy IP to correct array */
122 else if (strstr(line, "binding state active")) {
123 leases[num_leases] = htonl(inp.s_addr);
125 assert(!(leasesmallocsize < num_leases));
127 } else if (strstr(line, " binding state free")) {
128 touches[num_touches] = htonl(inp.s_addr);
130 assert(!(touchesmallocsize < num_touches));
131 } else if (strstr(line, " binding state backup")) {
132 if (num_backups == 0) {
134 safe_malloc((size_t) sizeof(long int) *
137 backups[num_backups] = htonl(inp.s_addr);
139 assert(!(backupsmallocsize < num_backups));
142 /* FIXME: move to output.c and use the FILE
144 if ((config.output_format[0] == 'X')
145 && (sw_active_lease == 1)
146 && (strstr(line, "hardware ethernet"))) {
147 nth_field(3, macstring, line);
148 macstring[strlen(macstring) - 1] = '\0';
151 ("<active_lease>\n\t<ip>%s</ip>\n\t<macaddress>%s</macaddress>\n</active_lease>\n",
152 ipstring, macstring);
158 /* Like strcpy but for field which is separated by white spaces. Number of
159 * first field is 1 and not 0 like C programs should have. Question of
160 * semantics, send mail to author if this annoys. All performance boosts for
161 * this function are well come. */
162 int nth_field(int n, char *dest, const char *src)
164 int i, j = 0, wordn = 0, len;
168 for (i = 0; i < len; i++) {
169 if (isspace(src[i])) {
188 /* dhcpd.conf interesting words */
189 int is_interesting_config_clause(char *s)
191 if (strstr(s, "range")) {
193 } else if (strstr(s, "shared-network")) {
195 } else if (strstr(s, "include")) {
202 /* FIXME: This spagetti monster function need to be rewrote at least ones. */
203 char *parse_config(int is_include, char *config_file,
204 char *current_shared_name,
205 char *next_free_shared_name,
206 struct shared_network_t *shared_p)
209 int i = 0, newclause = true, argument = false, comment =
210 false, braces = 0, quote = false;
212 int braces_shared = 1000;
214 struct range_t *range_p;
216 char *last_shared_name;
217 last_shared_name = SHARED_NETWORKS_NAMES + shared_net_names;
219 word = safe_malloc(sizeof(char) * MAXLEN);
222 /* Default place holder for ranges "All networks". */
223 shared_p->name = current_shared_name;
226 /* Open configuration file */
227 dhcpd_config = fopen(config_file, "r");
228 if (dhcpd_config == NULL) {
229 err(EXIT_FAILURE, "parse_config: %s", config_file);
231 #ifdef POSIX_FADV_WILLNEED
232 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_WILLNEED);
234 err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
236 #endif /* POSIX_FADV_WILLNEED */
237 #ifdef POSIX_FADV_SEQUENTIAL
238 posix_fadvise((long) dhcpd_config, 0, 0, POSIX_FADV_SEQUENTIAL);
240 err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
242 #endif /* POSIX_FADV_SEQUENTIAL */
244 /* Very hairy stuff begins. */
245 while (!feof(dhcpd_config)) {
246 c = fgetc(dhcpd_config);
247 /* Certain characters are magical */
249 /* Handle comments if they are not quoted */
251 if (quote == false) {
256 if (comment == false) {
258 /* Either one or zero */
263 /* New line resets comment section, but
265 if (quote == false) {
270 /* Quoted colon does not mean new clause */
274 if (comment == false && argument != 2
278 } else if (argument == 2) {
279 /* Range ends to ; and this hair in code
280 * make two ranges wrote to gether like...
282 * range 10.20.30.40 10.20.30.41;range 10.20.30.42 10.20.30.43;
284 * ...to be interpreted correctly. */
292 if (comment == false) {
295 /* i == 0 detects word that ends to brace like:
297 * shared-network DSL{ ... */
306 if (comment == false) {
308 /* End of shared-network */
309 if (braces_shared == braces) {
310 current_shared_name =
312 /* FIXME: Using 1000 is lame, but
314 braces_shared = 1000;
315 shared_p = shared_networks;
317 /* Not literally true, but works for this
326 /* Either inside comment or Nth word of clause. */
328 || (newclause == false && argument == 0)) {
331 /* Strip white spaces before new clause word. */
332 if ((newclause == true || argument != 0) && isspace(c)
336 /* Save to word which clause this is. */
337 if ((newclause == true || argument != 0)
338 && (!isspace(c) || quote == true)) {
341 /* Long word which is almost causing overflow. None
342 * of words are this long which the program is
350 /* See if clause is something that parser is looking for. */
351 else if (newclause == true) {
352 /* Insert string end & set state */
357 argument = is_interesting_config_clause(word);
359 /* words after range, shared-network or include */
360 else if (argument != 0) {
367 /* printf ("range 2nd ip: %s\n", word); */
368 range_p = ranges + num_ranges;
369 inet_aton(word, &inp);
371 range_p->last_ip = htonl(inp.s_addr) + 1;
373 range_p->touched = 0;
374 range_p->backups = 0;
375 range_p->shared_net = shared_p;
377 if (RANGES < num_ranges) {
379 "parse_config: Range space full! Increase RANGES and recompile.");
384 /* printf ("range 1nd ip: %s\n", word); */
385 range_p = ranges + num_ranges;
386 if (!(inet_aton(word, &inp))) {
387 /* word was not ip, try
391 range_p->first_ip = htonl(inp.s_addr) - 1;
395 /* printf ("shared-network named: %s\n", word); */
396 strcpy(next_free_shared_name, word);
398 shared_networks + num_shared_networks;
399 num_shared_networks++;
401 shared_p->name = next_free_shared_name;
402 shared_p->available = 0;
404 shared_p->touched = 0;
405 shared_p->backups = 0;
406 /* Temporary abuse of argument
409 strlen(next_free_shared_name) + 1;
410 if (next_free_shared_name + argument <
412 next_free_shared_name += argument;
414 /* FIXME: make this go
415 * away by reallocationg
418 "parse_config: End of shared-network space, increase SHARED_NETWORKS_NAMES and recompile");
421 braces_shared = braces;
424 /* printf ("include file: %s\n", word); */
426 next_free_shared_name =
427 parse_config(false, word,
429 next_free_shared_name,
434 /* printf ("nothing interesting: %s\n", word); */
438 warnx("impossible occurred, report a bug");
444 return next_free_shared_name;