diff --git a/README b/README index efa6974..ede4061 100644 --- a/README +++ b/README @@ -25,6 +25,9 @@ This is dhcpd-pools which is made for ISC dhcpd pool range analysis. small some other dhcp analyzer might be more suitable for you. +== Dependencies to other projects + + http://uthash.sourceforge.net/ == Test data wanted diff --git a/THANKS b/THANKS index 55c81f5..1a8b246 100644 --- a/THANKS +++ b/THANKS @@ -21,3 +21,4 @@ Ahmed AL Dakhil Adam Ciarcinski Rezso Gajdóczy Robert Viou +Enno Gröper diff --git a/TODO b/TODO index 447c80b..d45c3c6 100644 --- a/TODO +++ b/TODO @@ -1,32 +1,10 @@ ### Bugs -> 1. from huangyu: china,fujian province,fuzhou -> -> according to my observation, every lease,for example,ip -> 192.168.0.123 perhaps appears many times in dhcpd.leases,but -> only the last time's state is the final valid state of this ip -> 192.168.0.123. -> -> No matter it appears how many times in dhcpd.leases,and no -> matter it has how many different state in dhcpd.leases. no -> matter it had been assigned to how many different mac-address. -> As long as it's last appearance's binding state is free in -> dhcpd.leases,then ,it's free,in other word,it's not active. -> -> and i notice that if a active lease time expired,dhcpd daemon -> will set this lease's binding state from active to free -> directly,without released state in this period. -> -> in other words, when a lease's binding state "active" follow by -> "free",not follow by "released";dhcpd-pools still think it's -> active. -> -> and another bug maybe is: -> -> i found dhcpd-pools didn't consider if the active lease's ends -> time is passed so it would still think the lease is active even -> if dhcpd daemon is stopped for a long time,the leases marked by -> "active" state in lease_file has expired in fact. +Reported-by: Huangyu: I found dhcpd-pools didn't consider if the + active lease's ends time is passed so it would still think the + lease is active even if dhcpd daemon is stopped for a long time, + the leases marked by "active" state in lease_file has expired in + fact. ### Feature requests diff --git a/configure.ac b/configure.ac index 845b56c..e5cc89e 100644 --- a/configure.ac +++ b/configure.ac @@ -38,6 +38,8 @@ AC_CHECK_HEADERS([\ unistd.h \ ]) +AC_CHECK_HEADER(uthash.h, [], [AC_MSG_ERROR([Unable to find uthash.h])]) + # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_HEADER_STDBOOL diff --git a/src/Makefile.am b/src/Makefile.am index d964c95..e71c0b3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,15 @@ bin_PROGRAMS = dhcpd-pools AC_PROG_RANLIB = resolv -dhcpd_pools_SOURCES = dhcpd-pools.h defaults.h dhcpd-pools.c analyze.c getdata.c other.c sort.c output.c +dhcpd_pools_SOURCES = \ + analyze.c \ + defaults.h \ + dhcpd-pools.c \ + dhcpd-pools.h \ + getdata.c \ + hash.c \ + other.c \ + output.c \ + sort.c INCLUDES = -I. -I.. diff --git a/src/analyze.c b/src/analyze.c index 77d848c..5f8d7ab 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -42,45 +42,15 @@ #include "dhcpd-pools.h" /* Clean up data */ +int ip_sort(struct leases_t *a, struct leases_t *b) +{ + return (a->ip - b->ip); +} + int prepare_data(void) { - unsigned long int i, j, k; - /* Sort leases */ - qsort(leases, (size_t) num_leases, sizeof(uint32_t), &intcomp); - - /* Get rid of lease dublicates */ - for (k = j = i = 0; i < num_leases; i++) { - if (j != leases[i]) { - leases[k] = leases[i]; - j = leases[i]; - k++; - } - } - num_leases = k; - - /* Delete touched IPs that are in use. */ - j = 0; - for (i = 0; i < num_touches; i++) { - if (bsearch - (&touches[i], leases, (size_t) num_leases, - sizeof(uint32_t), &intcomp) == NULL) { - touches[j] = touches[i]; - j++; - } - } - num_touches = j; - qsort(touches, (size_t) num_touches, sizeof(uint32_t), &intcomp); - - /* Sort ranges */ - qsort(ranges, (size_t) num_ranges, sizeof(struct range_t), &rangecomp); - - /* Sort backups */ - if (0 < num_backups) { - qsort(backups, (size_t) num_backups, sizeof(uint32_t), - &intcomp); - } - + HASH_SORT(leases, ip_sort); return 0; } @@ -88,47 +58,43 @@ int prepare_data(void) int do_counting(void) { struct range_t *range_p; - unsigned long i, j, k, l, block_size; + struct leases_t *l; + unsigned long i, k, block_size; range_p = ranges; /* Walk through ranges */ - for (i = j = k = l = 0; i < num_ranges; i++) { + for (i = 0; i < num_ranges; i++) { /* Count IPs in use */ - for (; leases[j] < range_p->last_ip && j < num_leases; j++) { - if (leases[j] < range_p->first_ip) { + for (l = leases; l != NULL && range_p->last_ip >= l->ip; l = l->hh.next) { + if (l->ip < range_p->first_ip) { + /* should not be necessary */ continue; } - /* IP with in range */ - range_p->count++; - if (range_p->shared_net) { - range_p->shared_net->used++; - } - } - - /* Count touched IPs */ - for (; touches[k] < range_p->last_ip && k < num_touches; k++) { - if (touches[k] < range_p->first_ip) { - continue; - } - /* IP with in range */ - range_p->touched++; - if (range_p->shared_net) { - range_p->shared_net->touched++; - } - } - - /* Count backup IPs */ - if (0 < num_backups) { - for (; backups[l] < range_p->last_ip - && l < num_touches; l++) { - if (touches[l] < range_p->first_ip) { - continue; - } - /* IP with in range */ + /* IP in range */ + switch (l->type) { + case ACTIVE: + range_p->count++; + break; + case FREE: + range_p->touched++; + break; + case BACKUP: range_p->backups++; - if (range_p->shared_net) { + break; + } + + if (range_p->shared_net) { + switch (l->type) { + case ACTIVE: + range_p->shared_net->used++; + break; + case FREE: + range_p->shared_net->touched++; + break; + case BACKUP: range_p->shared_net->backups++; + break; } } } @@ -140,15 +106,6 @@ int do_counting(void) range_p->shared_net->available += block_size; } - /* Go backwards one step so that not even a one IP will be - * missed. This is possibly always unnecessary. */ - if (j) { - j--; - } - if (k) { - k--; - } - range_p++; } diff --git a/src/dhcpd-pools.h b/src/dhcpd-pools.h index e97263d..bd4d34f 100644 --- a/src/dhcpd-pools.h +++ b/src/dhcpd-pools.h @@ -40,6 +40,7 @@ #include #include #include +#include /* Feature test switches */ #define _POSIX_SOURCE 1 @@ -122,6 +123,16 @@ struct macaddr_t { char *ip; struct macaddr_t *next; }; +enum ltype { + ACTIVE, + FREE, + BACKUP +}; +struct leases_t { + uint32_t ip; /* ip as key */ + enum ltype type; + UT_hash_handle hh; +}; /* Global variables */ struct configuration_t config; @@ -133,11 +144,9 @@ struct shared_network_t *shared_networks; unsigned int num_shared_networks; struct range_t *ranges; unsigned int num_ranges; -uint32_t *leases; +struct leases_t *leases; unsigned long int num_leases; -uint32_t *touches; unsigned long int num_touches; -uint32_t *backups; unsigned long int num_backups; struct macaddr_t *macaddr; @@ -200,5 +209,10 @@ int output_xml(void); int output_csv(void); /* Memory release, file closing etc */ void clean_up(void); +/* Hash functions */ +void add_lease(int ip, enum ltype type); +struct leases_t * find_lease(int ip); +void delete_lease(struct leases_t * lease); +void delete_all_leases(); #endif /* DHCPD_POOLS_H */ diff --git a/src/getdata.c b/src/getdata.c index 74202aa..6e8657d 100644 --- a/src/getdata.c +++ b/src/getdata.c @@ -71,10 +71,8 @@ int parse_leases(void) struct in_addr inp; struct stat lease_file_stats; struct macaddr_t *macaddr_p = NULL; - size_t leasesmallocsize; - size_t touchesmallocsize; - size_t backupsmallocsize; int sw_active_lease = 0; + struct leases_t * lease; num_touches = num_leases = num_backups = 0; @@ -104,14 +102,6 @@ int parse_leases(void) if (stat(config.dhcpdlease_file, &lease_file_stats)) { err(EXIT_FAILURE, "parse_leases: %s", config.dhcpdlease_file); } - leasesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2; - touchesmallocsize = (lease_file_stats.st_size / 250) + MAXLEN - 2; - backupsmallocsize = (lease_file_stats.st_size / 120) + MAXLEN - 2; - leases = safe_malloc(sizeof(uint32_t) * leasesmallocsize); - touches = safe_malloc(sizeof(uint32_t) * touchesmallocsize); - - memset(leases, 0, sizeof(uint32_t) * leasesmallocsize); - memset(touches, 0, sizeof(uint32_t) * touchesmallocsize); line = safe_malloc(sizeof(char) * MAXLEN); ipstring = safe_malloc(sizeof(char) * MAXLEN); @@ -136,40 +126,24 @@ int parse_leases(void) } /* Copy IP to correct array */ else if (xstrstr(line, " binding state active", 22)) { - leases[num_leases] = htonl(inp.s_addr); - num_leases++; - if (leasesmallocsize < num_leases) { - leasesmallocsize = - sizeof(uint32_t) * num_leases * 2; - leases = safe_realloc(leases, leasesmallocsize); - leasesmallocsize /= sizeof(uint32_t); + /* remove old entry, if exists */ + if ((lease = find_lease(htonl(inp.s_addr))) != NULL) { + delete_lease(lease); } + add_lease(htonl(inp.s_addr),ACTIVE); sw_active_lease = 1; } else if (xstrstr(line, " binding state free", 20)) { - touches[num_touches] = htonl(inp.s_addr); - num_touches++; - if (touchesmallocsize < num_touches) { - touchesmallocsize = - sizeof(uint32_t) * num_touches * 2; - touches = - safe_realloc(touches, touchesmallocsize); - touchesmallocsize /= sizeof(uint32_t); + /* remove old entry, if exists */ + if ((lease = find_lease(htonl(inp.s_addr))) != NULL) { + delete_lease(lease); } + add_lease(htonl(inp.s_addr),FREE); } else if (xstrstr(line, " binding state backup", 22)) { - if (num_backups == 0) { - backups = - safe_malloc(sizeof(uint32_t) * - backupsmallocsize); - } - backups[num_backups] = htonl(inp.s_addr); - num_backups++; - if (backupsmallocsize < num_backups) { - backupsmallocsize = - sizeof(uint32_t) * num_backups * 2; - backups = - safe_realloc(backups, backupsmallocsize); - backupsmallocsize /= sizeof(uint32_t); + /* remove old entry, if exists */ + if ((lease = find_lease(htonl(inp.s_addr))) != NULL) { + delete_lease(lease); } + add_lease(htonl(inp.s_addr),BACKUP); } if ((macaddr != NULL) diff --git a/src/hash.c b/src/hash.c new file mode 100644 index 0000000..f69b4e3 --- /dev/null +++ b/src/hash.c @@ -0,0 +1,80 @@ +/* + * The dhcpd-pools has BSD 2-clause license which also known as "Simplified + * BSD License" or "FreeBSD License". + * + * Copyright 2012- Enno Gröper. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are + * those of the authors and should not be interpreted as representing + * official policies, either expressed or implied, of Sami Kerola. + */ + +#include "dhcpd-pools.h" + +void add_lease(int ip, enum ltype type) +{ + struct leases_t *l; + l = safe_malloc(sizeof(struct leases_t)); + l->ip = ip; + l->type = type; + HASH_ADD_INT(leases, ip, l); +} + +struct leases_t *find_lease(int ip) +{ + struct leases_t *l; + + HASH_FIND_INT(leases, &ip, l); + return l; +} + +void delete_lease(struct leases_t *lease) +{ + HASH_DEL(leases, lease); + free(lease); +} + +/* uthash >= 1.9.2 +void delete_all_leases() +{ + struct leases_t *l, *tmp; + HASH_ITER(hh, leases, l, tmp) { + HASH_DEL(leases, l); + free(l); + } +} +*/ + +void delete_all_leases() +{ + struct leases_t *l; + while (leases) { + l = leases; + HASH_DEL(leases, l); /* leases advances to next on delete */ + free(l); + } +} diff --git a/src/other.c b/src/other.c index f27af70..6caf6e7 100644 --- a/src/other.c +++ b/src/other.c @@ -148,9 +148,7 @@ void clean_up(void) free(config.dhcpdlease_file); free(config.output_file); free(ranges); - free(leases); - free(backups); - free(touches); + delete_all_leases(); free(shared_networks); }