Compare commits

..

No commits in common. "master" and "v2.24" have entirely different histories.

132 changed files with 3499 additions and 10229 deletions

3
.gitignore vendored
View file

@ -1,8 +1,5 @@
# Wildcard + in any subdir.
*.o
*.gcno
*.gcda
*.[ch].gcov
# Exact filename in any subdir.
.deps

View file

@ -1,2 +0,0 @@
Sami Kerola <kerolasa@iki.fi>
Sami Kerola <kerolasa@iki.fi> <sami.kerola@tomtom.com>

View file

@ -1,6 +1,7 @@
## Makefile.am -- Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = gnu
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = \
.version \
@ -15,40 +16,12 @@ $(top_srcdir)/.version:
dist-hook:
echo $(VERSION) > $(distdir)/.tarball-version
PATHFILES =
CLEANFILES = $(PATHFILES)
EXTRA_DIST += $(PATHFILES:=.in)
CLEANFILES =
CLEAN_LOCALS =
edit_cmd = sed \
-e 's|@ALARM_CRIT[@]|$(ALARM_CRIT)|g' \
-e 's|@ALARM_WARN[@]|$(ALARM_WARN)|g' \
-e 's|@DHCPDCONF_FILE[@]|$(DHCPDCONF_FILE)|g' \
-e 's|@DHCPDLEASE_FILE[@]|$(DHCPDLEASE_FILE)|g' \
-e 's|@OUTPUT_FORMAT[@]|$(OUTPUT_FORMAT)|g' \
-e 's|@OUTPUT_LIMIT[@]|$(OUTPUT_LIMIT)|g' \
-e 's|@PACKAGE_BUGREPORT[@]|$(PACKAGE_BUGREPORT)|g' \
-e 's|@PACKAGE_MAINTAINER[@]|$(PACKAGE_MAINTAINER)|g' \
-e 's|@PACKAGE_NAME[@]|$(PACKAGE_NAME)|g' \
-e 's|@PACKAGE_URL[@]|$(PACKAGE_URL)|g' \
-e 's|@SHELL[@]|$(SHELL)|g' \
-e 's|@VERSION[@]|$(VERSION)|g' \
-e 's|@bindir[@]|$(bindir)|g' \
-e 's|@docdir[@]|$(docdir)|g' \
-e 's|@top_srcdir[@]|$(top_srcdir)|g'
$(PATHFILES): Makefile
@ rm -f $@ $@.tmp
$(AM_V_at) mkdir -p $$(dirname $@)
$(AM_V_GEN) srcdir=''; \
test -f ./$@.in || srcdir=$(srcdir)/; \
$(edit_cmd) $${srcdir}$@.in >$@.tmp
@ mv $@.tmp $@
include contrib/Makemodule.am
include doc/Makemodule.am
include man/Makemodule.am
include samples/Makemodule.am
include src/Makemodule.am
include tests/Makemodule.am

271
NEWS
View file

@ -5,277 +5,6 @@ See the end for copying conditions.
Please send dhcpd-pools bug reports to kerolasa@iki.fi.
gpg: Signature is crated using RSA key ID 8ED396E37E38D471A00530D3A9553245FDE9B739.
Version 3.3
Belkacem Daheb (2):
add start, end and hostname printing support for xml and json
getdata output: add start, end and hostname printing support for xml and json
M. van Brummelen (1):
docs: fix manual page groff warning
Sami Kerola (9):
update project web page
website: use https
chore: update web links
getdata: only emit warning when config include file cannot be read
gnulib: update bootstrap and gitignore files
build-sys: quote subshell execution in the autotools file
build-sys: update bootstrap from gnulib
output: update html javascripts
release: 3.3
luisδμ (1):
fix: avoid generation of unvalid JSON in summary
Version 3.2
Jean Benoit (1):
contrib: snmptest.pl SNMPwalk can't access to all variables/wrong sort
Sami Kerola (5):
contrib: point out where one can find zabbix template
build-sys: update .gitignore files
config: remove unnecessary padding
build-sys: autotools and gnulib related updates
build-sys: routine update
release: 3.2
Version 3.1
Mark Sangster (1):
output: fix warn and crit counts on shared networks
Sami Kerola (31):
webpage: add instructions how to get output you need
build-sys: add coverage files to .gitignore
tests: improve coverage
docs: fix peoples name in THANKS file to have correct characters
add .mailmap
output: fix implicit conversion
main: simplify option parsing
fix typo
main: move print_mac_addreses to state structure
main: move output_format to state, and rename color_format
webpages: use html sample output
fix switch missing default case warnings
sort: ensure NaN will not trip over comp_double()
drop images, java scripts, and such from web sitemap file
getdata: remote dead code
other: use strftime() to generate date-time string
lib: update .gitignore
fix typos
various: fix few warnings
warnings: ensure optimal packing in structures
other: use IP string lengths from netinet/in.h
mustach: sync with most recent mustach upstream changes
various: tidy up variable scopes, and one name mismatch
build-sys: update .gitignore files
output: add warning and critical threshold counts to mustach
samples: make prometheus template less klunky
misc: fix spelling issues
output: add ethernet address priting support to --mustach
build-sys: update bootstrap from gnulib
output: update javascripts
release: 3.1
Version 3.0
Sami Kerola (56):
release: update web page meta data
update sitemap
output: make output_analysis() to be regular function
getdata: fix typo
output: add output helper functions
output: add color support to text output
output: include earlier missing data to json output
output: add --skip-ok option
other: add --skip-ok to usage() output
output: json nan values need quoting
other: do not use 'else' after 'return'
getdata: do not use 'else' after 'continue'
include: use project specific header guard
output: use range_output_helper() value in output_xml()
output: add mustach templating support
output: add separate first_ip and last_ip to json and mustach outputs
docs: add mustach sample files
tests: add mustach check
output: make mustach processing more robust
output: avoid mixing ntop_ipaddr() output buffers
output: do not skip over first range in mustach output
output: save and reuse output helper results
output: add must_put_err() utility function
output: include stdlib.h to avoid compilation error
gnulib: use nstrftime instead of strftime
build-sys: omit mustach compilation when it cannot work
usage: add error message informing mustach support is not available
output: deduplicate file closing code
clean up: remove unused variable
all files: replace global variables with runtime config state structure
all files: re-indent
analyze: bug fix shared networks counts
other: add Jose Bollo to version output credits
output: improve mustach template parsing error
analysis: shared networks to be linked list
output: make --skip-ok to effect --perfdata
output: move shared net andn range status check to output_helper
output: make warning and critical colors work in html output
output: display more entries in html table by default
output: shared net can be in suppressed state
output: improve html table
hash: include stdlib.h to avoid implicit declarations
clean up: fix couple compiler warnings
thanks: add Troy D. Hanson to credits about uthash
samples: add prometheus text file collector mustach template
output: make --skip to take arguments what will be skipped
misc: move command line option parsing to separate function
misc: move couple enums from global scope to file scope
docs: improve doxygen documentation
output: remove unused variable attribute
output: add more items to mustach tags
output: unify time stamp creations
orther: fix xstrstr_init() memcmp() return value usage
output: add some trivia data to json output
usage: --skip=ignored is actually 'suppressed'
release: 3.0
Version 2.29
Boris Lytochkin (1):
introduce -A arg: treat single subnets as shared-network with CIDR as their name
Manuel Hachtkemper (1):
alarming: add additional performance data
Sami Kerola (47):
tell in README when ./bootstrap is needed
add dhcpd-pools website content to a subdirectory
add sitemap url to robots.txt file
use long options in .indent.pro file
webpages: make index page mobile device friendly
webpages: compress sitemap.txt file
getdata: flip ranges if they are in greater smaller order
tests: add range definition flip test
contrib: add archlinux package build file
contrib: remove unnecessary cgi script
contrib: remove awk file duplicate
getdata: get rid of remaining stdbool usage
argument parsing: fix compiler warning
add dhcpd-pools Description Of A Project file
fix doap file git repository and license section
output: check alarming mode can output successfully
build-sys: update bootstrap from gnulib
build-sys: update gnulib .gitignore file
analyze: use while() when for() is less fit to purpose
build-sys: default to ./configure --enable-silent-rules
build-sys: always use restrict found by autoconf
docs: fix couple typos and improve a sentence in README
output: remove unnecessary increment
portability: add gnulib modules earlier missing
remove const and pure function attributes
man: improve synopsis and output limit
man: remove old html table only option argument from manual
getdata: report position in config file when parsing fails
output: fix timestamp localization on html page
output: add include avoid referringt to undefined definition
getdata: remove POSIX_FADV_NOREUSE
style: use same argument names in header and source file
contrib: Klaus Slott told about opensuse package
getdata: fpos_t is not easy to print correctly
lib: update .gitignore
fix typo
variable: add const to print_mac_addreses_tmp
lib: update .gitignore
add --ip-version option to force either IPv4 or IPv6 analysis
lib: update .gitignore
getdata: add cidr range support
build-sys: update bootstrap from gnulib
docs: update doxygen configuration file
docs: tell what needs to be done when releasing new version
docs: add build instruction link to the project web page
docs: update maintainer gpg key
release: 2.29
Version 2.28
Sami Kerola (26):
portability: Solaris 10 does not have err.h
fix couple compiler warnings
make binary exec path dynamic in scripts referring to it
update doxygen.conf file
add --snet-alarms option to suppress excess range alarms
add --warn-count and --crit-count options to suppress alarm noise
improve README file instructions
make html output to use Bootstrap and DataTables
fix typo in README
correct return value FIXME items
use more descriptive names in limit bits enum definition
remove upper limit of sort order definitions
fix protocol specifier in html output
use bitmap for booleans and other config that has known size
simplify output format selection, and passing
fix doxygen build
fix improve variable names
print include system error message when output fails
drop a core when bug condition happens
make usage() easier to read
unify quotation in error messages
add --warn-count and --crit-count test, and fix related bug
test all sorting options
change NAN markup to make tests work on mac
fix out of tree build tests
release: 2.28
Version 2.27
Sami Kerola (9):
docs: remove very basic git usage info
docs: remove todo items that will never happen
output: remove empty element from xml
add touched addresses counts to xml and json reports
add xml format check
improve html output
add hint about configure options to README
man: fix character class change
gitignore: update gnulib file list
release: 2.27
Version 2.26
$ git shortlog v2.25..v2.26
Sami Kerola (15):
news: add the note about .sig pgp key id
reindent all files
declare global variables only once
add appropriate sorting function for struct leases_t
update kernel.org url in README
getdata: fix buffer-overflows reported by address sanitizer
update bootstrap from gnulib
getdata: fix buffer overflow [AddressSanitizer]
other: reduce variable scope
output: prefer thread safe function localtime_r()
tests: add regression test to avoid shared-net off by one alarming
issue
output: avoid division by zero
other: disallow unsigned counter ever to have minus value
maint: remove unnecessary braces, spaces, update gnulib .gitignore
release: 2.26
Wolfgang Steudel (1):
alarming: include last shared network in alarming [off by one]
Version 2.25
$ git shortlog v2.24..v2.25
Sami Kerola (14):
build-sys: use more strict method to check __builtin_expect
getdata: add missing HAVE_POSIX_FADVISE protection
getdata: fix consecutive range definition regression
man: add tip analysis of include files can be useful
thanks: add Fredrik Lysén & Conor McCarthy
generic: use pure and const function attributes when possible
tests: fix testing error
output: make nagios output have performance data
build-sys: update gitinore file
output: use symbolic exit values for nagios commands
build-sys: update bootstrap script
build-sys: require automake 1.12 to get working test-driver
contrib: add release siging key to contrib/
release: 2.25
Version 2.24
$ git shortlog v2.23..v2.24

220
README
View file

@ -1,62 +1,196 @@
This is dhcpd-pools - ISC dhcpd lease status utility.
This is dhcpd-pools which is made for ISC dhcpd pool range analysis.
Quick start.
== Quick start
Get the uthash, assuming you do not have it already.
cd /tmp
wget https://github.com/troydhanson/uthash/archive/master.zip
unzip master.zip
Build the dhcpd-pools project.
cd /tmp/dhcpd-pools
./bootstrap # only when building git clone
./configure --with-uthash=/tmp/uthash-master/include
./bootstrap
./configure --prefix=/usr/local
make
make check
make install
Notice that there are configuration options for default dhcpd.conf,
dhcpd.leases paths, among other things.
./configure --help
== General information
Remember to read the friendly manual page.
With this command you can check usage of pool addresses
when address space is great. Command is designed so that
it will not get slow even there is thousands of IPs in
lease file. This kind of huge dhcpd installation can be
near by DSL DSLAMs or some other public access connection
points.
man ./man/dhcpd-pools.1
This command will not print nice to know information like
DHCPStatus does. Output is limited only to list only
usage for ranges, shared network and total address space.
Limiting what is printed is the right thing to do when
there is thousands of addresses. If your address space is
small some other dhcp analyzer might be more suitable for
you.
Dependencies to other projects.
== Dependencies to other projects
https://www.gnu.org/software/gnulib/
http://www.gnu.org/software/gnulib/
You can avoid repeated gnulib downloads by setting
GNULIB_SRCDIR environment variable. For example:
If you have gnulib checked out somewhere at file
system you can avoid download by setting
GNULIB_SRCDIR environment variable.
git clone git://git.savannah.gnu.org/gnulib.git ~/src/gnulib
export GNULIB_SRCDIR="$HOME/src/gnulib"
http://uthash.sourceforge.net/
Assumign detached gnulib please remember to git pull the
latest updates before building dhcpd-pools.
https://troydhanson.github.io/uthash/
See quick start.
https://getbootstrap.com/
https://datatables.net/
Bootstrap and DataTables java scripts are used in html
output.
Test data wanted.
== Test data wanted
Maintainer is interested to get copy of your dhcpd.conf
and dhcpd.leases files, and include files if you use them.
and dhcpd.leases file, with includes if you use them.
Intention is to collect large set of data to build
realistic regression test environment.
realistic regression test environment. By giving your
data to maintainer you can be sure that updates will work
for you.
If you are interested to help this way put all files into
tar.gz, and send them to:
tar.gz, and send them to kerolasa@iki.fi. It would be nice
that email subject line would have 'dhcpd-pools test data'.
Sami Kerola <kerolasa@iki.fi>
== Instructions for developers
AUTOTOOLS:
* "./bootstrap" generates all files needed to compile and
install the code (run it after checkout from git)
* "make distclean" removes all unnecessary files, but the
code can still be recompiled with "./configure; make"
PATCHES:
* First get familiar with git. In case you are completely
lost watch Greg Kroah-Hartman explaining the very
basics.
http://archive.fosdem.org/2010/schedule/events/linuxkernelpatch
* Get up to date version of the code base.
$ git clone git://dhcpd-pools.git.sourceforge.net/gitroot/dhcpd-pools/dhcpd-pools
* Don't include generated (autotools) stuff to your
patches (hint: use git-clean [-X])
* Add a Signed-off-by line, use "git commit -s"
* Patches are delivered via email only. The following
commands will do the correct thing.
$ git format-patch -C origin/master..yourbranch -o ~/patches
When you send only one patch use the following.
$ git send-email --to kerolasa@iki.fi 0001*
The command above expects you have configured email
sending properly. See git.wiki for help.
https://git.wiki.kernel.org/index.php/GitTips#Mail
* One patch per email, with the changelog in the body of
the email.
* When you send series of pathes include introductory
message.
$ git send-email --compose --to kerolasa@iki.fi ~/00*
Good introductory message will have at least
-- snip
Your Name (3):
firstfile.c: short description
secondfile.c: another description
firstfile.c | 2 +-
secondfile.c | 2 +-
secondfile.c | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
-- snip
Above introductory can be generated with git.
$ git shortlog master..yourbranch
$ git diff --stat master..yourbranch
* Subject: [PATCH] subsystem: description. Following
~/.gitconfig will help you a little.
-- snip
[user]
name = Your Name
email = your.name@example.com
[format]
subjectprefix = PATCH
numbered = auto
signoff = yes
[sendemail]
chainreplyto = false
cc = your.name@example.com
-- snip
* If someone else wrote the patch, they should be
credited (and blamed) for it. To communicate this, add
a line:
From: John Doe <jdoe@wherever.com>
The sign-off is a simple line at the end of the
explanation for the patch, which certifies that you
wrote it or otherwise have the right to pass it on as a
open-source patch. The rules are pretty simple: if you
can certify the below:
By making a contribution to this project, I certify
that:
(a) The contribution was created in whole or in
part by me and I have the right to submit it
under the open source license indicated in the
file; or
(b) The contribution is based upon previous work
that, to the best of my knowledge, is covered
under an appropriate open source license and I
have the right under that license to submit
that work with modifications, whether created
in whole or in part by me, under the same open
source license (unless I am permitted to submit
under a different license), as indicated in the
file; or
(c) The contribution was provided directly to me by
some other person who certified (a), (b) or (c)
and I have not modified it.
(d) I understand and agree that this project and
the contribution are public and that a record
of the contribution (including all personal
information I submit with it, including my
sign-off) is maintained indefinitely and may be
redistributed consistent with this project or
the open source license(s) involved.
then you just add a line saying
Signed-off-by: Random J Developer <random@developer.example.org>
using your real name (sorry, no pseudonyms or anonymous
contributions.)
* If the the business with git is too difficult just send
source code files as is as email attachment to
maintainer.
CODING STYLE:
* The preferred coding style is based on the linux kernel
Documentation/CodingStyle. For more details see:
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob_plain;f=Documentation/CodingStyle
* Source code is pretty printed by using two, and only
the two, indent command switches -kr -i8

35
THANKS
View file

@ -5,24 +5,23 @@ Project is maintained by Sami Kerola <kerolasa@iki.fi>
People who reported problems, give improvement suggestions or even
contributed code.
Otto J. Mäkelä
Otto J. Mäkelä
Mika Paananen
Frank Bulk
Roar Pettersen
Jeff Wieland
Rusty
Fredrik Vöcks
Fredrik Vöcks
Dan Thorson
Stian Øvrevåge
Stian Øvrevåge
Dominic Germain
Anders Låstad
Anders Låstad
Thor Eivind Brantzeg
Ahmed AL Dakhil
Adam Ciarcinski
Rezső Gajdóczy
Rezso Gajdóczy
Robert Viou
Enno Gröper
Troy D. Hanson
Enno Gröper
Ryan Malek
Cheer Xiao
Gilles Bouthenot
@ -30,25 +29,3 @@ Helmut Grohne
Joey D.
Ryan Steinmetz
Dan Pritts
Fredrik Lysén
Conor McCarthy
Wolfgang Steudel
Aaron Paetznick
Tim Cantin
Martijn van Brummelen
Anton Tkachev
Derrick Lin
Ivanov Ivan
Manuel Hachtkemper
Klaus Slott
Boris Lytochkin
Jeff Bailey
José Bollo
Sebastián Cramatte
Mark Sangster
Brent Swingle
Mathieu Morier
Jean Benoit
Belkacem Daheb
Björn Lässig
Luisδμ

36
TODO
View file

@ -15,19 +15,25 @@ o When time stamps are part of lease situation evaluation (see
expiry happens.
o Add lease time histogram support.
### When releasing
### Next major version
o Update gnulib
o Update bootstrap
o Update DataTables, and bootstrap versions; see https://datatables.net/download/index
o Update NEWS, webpages/index.html dateModified & version
o Make annotated git tag
o ./configure --enable-doxygen && make distcheck
o BROWSER=cat man -H ./man/dhcpd-pools.1 | tee ./webpages/man.html
o gpg --armor --detach-sign dhcpd-pools*tar*
* Update sitemap
o Upload files to sourceforge
o mv doc/html webpages/doxygen
o sftp index.html man.html doxygen/* -> sourceforge web
remove old doxygen before uploading new
o Send email to dhcpd-pools-announce@lists.sourceforge.net subject: Version 3.n is released
1 Well structured code, with extendible sane architecture.
2 Server, which has analysis in cache for N seconds and will
answer via socket.
3 Configuration file for server.
4 State file, where different ranges, shared networks etc have
unique identifiers (needed for graphs).
5 Support for snmp and munin protocols.
6 SNMP traps when limits get exceeded.
7 Some clever check_dhcpd_pools binary for Nagios & other
monitoring software.
8 Super server support, which will collect analysis from other
dhcpd-pool servers.
9 Nice http view interface on super server, much can be copied
from http://piwik.org/
10 And some other things perhaps...
When items 1-7 are done v3 can be released. To support rewrite
there should be a design document with nice blue print, which is
a web page.

1774
bootstrap

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,10 @@
# Bootstrap configuration. -*- sh -*-
# Bootstrap configuration.
# Copyright (C) 2006-2025 Free Software Foundation, Inc.
# Copyright (C) 2006-2012 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
@ -13,14 +13,13 @@
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# gnulib modules used by this package.
gnulib_modules="
close-stream
closeout
error
fclose
fcntl-h
fdopen
@ -28,11 +27,9 @@ gnulib_modules="
fopen
getopt-gnu
inet_pton
isnan
langinfo
netinet_in
nstrftime
progname
quote
realloc-gnu
stat
stddef
@ -40,9 +37,8 @@ gnulib_modules="
stdlib
stpncpy
strdup-posix
strftime
strstr
strtod
time_r
xalloc
"
@ -64,7 +60,7 @@ XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
gettext_external=0
grep '^[ ]*AM_GNU_GETTEXT(external\>' configure.ac > /dev/null &&
gettext_external=1
grep '^[ ]*AM_GNU_GETTEXT(\[external]' configure.ac > /dev/null &&
grep '^[ ]*AM_GNU_GETTEXT(\[external\]' configure.ac > /dev/null &&
gettext_external=1
if test $gettext_external = 1; then

View file

@ -1,7 +1,5 @@
/ar-lib
/compile
/config.guess
/config.rpath
/config.sub
/depcomp
/install-sh

View file

@ -1,12 +1,12 @@
#!/bin/sh
# Print a version string.
scriptversion=2022-01-27.18; # UTC
scriptversion=2012-12-31.23; # UTC
# Copyright (C) 2007-2022 Free Software Foundation, Inc.
# Copyright (C) 2007-2013 Free Software Foundation, Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
@ -15,9 +15,9 @@ scriptversion=2022-01-27.18; # UTC
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# This script is derived from GIT-VERSION-GEN from GIT: https://git-scm.com/.
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
# It may be run two ways:
# - from a git repository in which the "git describe" command below
# produces useful output (thus requiring at least one signed tag)
@ -65,21 +65,19 @@ scriptversion=2022-01-27.18; # UTC
# EXTRA_DIST = $(top_srcdir)/.version
# BUILT_SOURCES = $(top_srcdir)/.version
# $(top_srcdir)/.version:
# echo '$(VERSION)' > $@-t
# mv $@-t $@
# echo $(VERSION) > $@-t && mv $@-t $@
# dist-hook:
# echo '$(VERSION)' > $(distdir)/.tarball-version
# echo $(VERSION) > $(distdir)/.tarball-version
me=$0
year=`expr "$scriptversion" : '\([^-]*\)'`
version="git-version-gen $scriptversion
Copyright (C) ${year} Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law."
Copyright 2011 Free Software Foundation, Inc.
There is NO warranty. You may redistribute this software
under the terms of the GNU General Public License.
For more information about these matters, see the files named COPYING."
usage="\
Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT]
@ -87,9 +85,8 @@ Print a version string.
Options:
--prefix PREFIX prefix of git tags (default 'v')
--fallback VERSION
fallback version to use if \"git --version\" fails
--prefix prefix of git tags (default 'v')
--fallback fallback version to use if \"git --version\" fails
--help display this help and exit
--version output version information and exit
@ -103,8 +100,8 @@ while test $# -gt 0; do
case $1 in
--help) echo "$usage"; exit 0;;
--version) echo "$version"; exit 0;;
--prefix) shift; prefix=${1?};;
--fallback) shift; fallback=${1?};;
--prefix) shift; prefix="$1";;
--fallback) shift; fallback="$1";;
-*)
echo "$0: Unknown option '$1'." >&2
echo "$0: Try '--help' for more information." >&2
@ -143,9 +140,11 @@ then
v=`cat $tarball_version_file` || v=
case $v in
*$nl*) v= ;; # reject multi-line output
[0-9]*) ;;
*) v= ;;
esac
test "x$v" = x \
&& echo "$0: WARNING: $tarball_version_file is damaged" 1>&2
&& echo "$0: WARNING: $tarball_version_file is missing or damaged" 1>&2
fi
if test "x$v" != x
@ -167,10 +166,9 @@ then
# tag or the previous older version that did not?
# Newer: v6.10-77-g0f8faeb
# Older: v6.10-g0f8faeb
vprefix=`expr "X$v" : 'X\(.*\)-g[^-]*$'` || vprefix=$v
case $vprefix in
*-*) : git describe is probably okay three part flavor ;;
*)
case $v in
*-*-*) : git describe is okay three part flavor ;;
*-*)
: git describe is older two part flavor
# Recreate the number of commits and rewrite such that the
# result is the same as if we were using the newer version
@ -185,9 +183,9 @@ then
;;
esac
# Change the penultimate "-" to ".", for version-comparing tools.
# Remove the "g" to save a byte.
v=`echo "$v" | sed 's/-\([^-]*\)-g\([^-]*\)$/.\1-\2/'`;
# Change the first '-' to a '.', so version-comparing tools work properly.
# Remove the "g" in git describe's output string, to save a byte.
v=`echo "$v" | sed 's/-/./;s/\(.*\)-g/\1-/'`;
v_from_git=1
elif test "x$fallback" = x || git --version >/dev/null 2>&1; then
v=UNKNOWN
@ -201,7 +199,7 @@ v=`echo "$v" |sed "s/^$prefix//"`
# string we're using came from git. I.e., skip the test if it's "UNKNOWN"
# or if it came from .tarball-version.
if test "x$v_from_git" != x; then
# Don't declare a version "dirty" merely because a timestamp has changed.
# Don't declare a version "dirty" merely because a time stamp has changed.
git update-index --refresh > /dev/null 2>&1
dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty=
@ -216,12 +214,12 @@ if test "x$v_from_git" != x; then
fi
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
printf %s "$v"
echo "$v" | tr -d "$nl"
# Local variables:
# eval: (add-hook 'before-save-hook 'time-stamp)
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC0"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

View file

@ -2,18 +2,18 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_CONFIG_MACRO_DIRS([m4])
AC_CONFIG_MACRO_DIR([m4])
AC_INIT([dhcpd-pools],
[m4_esyscmd([build-aux/git-version-gen .tarball-version])],
[kerolasa@iki.fi],[],
[https://dhcpd-pools.sourceforge.net/])
[http://dhcpd-pools.sourceforge.net/])
PACKAGE_MAINTAINER="Sami Kerola"
AC_SUBST([PACKAGE_MAINTAINER])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([
-Wall
-Wextra-portability
1.12
1.10
foreign
dist-xz
no-dist-gzip
@ -24,9 +24,6 @@ AM_INIT_AUTOMAKE([
AC_CONFIG_SRCDIR([src/dhcpd-pools.h])
AC_CONFIG_HEADERS([config.h])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])],
[AC_SUBST([AM_DEFAULT_VERBOSITY], [1])])
# Checks for programs
AC_USE_SYSTEM_EXTENSIONS
AC_C_RESTRICT
@ -69,27 +66,11 @@ AC_TYPE_UINT32_T
AC_FUNC_ERROR_AT_LINE
AC_CHECK_FUNCS([\
__fpending \
open_memstream \
posix_fadvise \
])
AC_CHECK_DECL([strndupa])
AC_CHECK_FUNCS([fpclassify], [],
[AC_CHECK_LIB([m], [fpclassify], [MATH_LIBS="-lm"])]
[AC_CHECK_LIB([m], [__fpclassify], [MATH_LIBS="-lm"])]
)
AC_SUBST([MATH_LIBS])
AS_IF([test "x$ac_cv_func_open_memstream" = "xyes" && test "x$ac_cv_have_decl_strndupa" == "xyes"], [
build_mustach=yes
AC_DEFINE([BUILD_MUSTACH], [1], [build mustach support])
], [
build_mustach=no
])
AM_CONDITIONAL([ENABLE_MUSTACH], [test "x$build_mustach" = xyes])
AC_MSG_CHECKING([if the compiler supports __builtin_expect])
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
return __builtin_expect(1, 1) ? 1 : 0
]])],[
have_builtin_expect=yes
@ -153,7 +134,8 @@ AM_CONDITIONAL([ENABLE_DOXYGEN], [test "x$enable_doxygen" = "xyes"])
AS_IF([test x$enable_doxygen = xyes], [
AC_CHECK_PROGS([DOXYGEN], [doxygen])
AS_IF([test "x$DOXYGEN" = "x"],
AC_MSG_ERROR([doxygen not in path])
AC_MSG_ERROR([doxygen not in path]),
AC_CONFIG_FILES([doc/doxy.conf])
)
AC_CHECK_PROGS([DOXYGEN_DOT], [dot])
@ -167,6 +149,7 @@ AM_CONDITIONAL([HAVE_DOXYGEN_DOT], [test "x$DOXYGEN_DOT" != "x"])
AC_CONFIG_FILES([
Makefile
lib/Makefile
man/dhcpd-pools.1
])
AC_OUTPUT

1
contrib/.gitignore vendored
View file

@ -1 +0,0 @@
/nagios.conf

View file

@ -1,5 +1,3 @@
contribdir = $(datadir)/dhcpd-pools/
PATHFILES += contrib/nagios.conf
dist_contrib_SCRIPTS = contrib/snmptest.pl
dist_contrib_DATA = contrib/nagios.conf
EXTRA_DIST += contrib/munin_plugins
dist_contrib_SCRIPTS = contrib/dhcpd-pools.cgi contrib/snmptest.pl
EXTRA_DIST += contrib/nagios.conf contrib/munin_plugins

View file

@ -1,36 +0,0 @@
# Archlinux package file. Just download this file, and
# makepkg PKGBUILD
# pacman -U ./dhcpd-pools*.pkg.tar.xz
pkgname=dhcpd-pools
pkgver=0
pkgrel=1
pkgdesc="ISC dhcpd lease status utility"
arch=('i686' 'x86_64')
url=https://dhcpd-pools.sourceforge.net/
license=('BSD')
depends=('pacman')
makedepends=('uthash' 'git')
source=("$pkgname"::'git://git.code.sf.net/p/dhcpd-pools/code')
md5sums=('SKIP')
pkgver() {
cd "$srcdir/$pkgname"
# Use the tag of the last commit
git describe --long | sed -E 's/([^-]*-g)/r\1/;s/-/./g'
}
build() {
cd "$srcdir/$pkgname"
./bootstrap
./configure \
--prefix=/usr \
--bindir=/usr/bin
make
}
package() {
cd "$srcdir/$pkgname"
make PREFIX=/ DESTDIR="$pkgdir" install
install -D -m644 COPYING "${pkgdir}/usr/share/licenses/${pkgname}/COPYING"
}

View file

@ -4,11 +4,12 @@
# analysis algorithm is sane. This script is no longer
# maintained, and can be considered as historic reference.
#
# Licensed under the Open Software License version 1.0
# https://opensource.org/license/osl-1-0/
# Licensed under the Open Software License version 1.1
# http://opensource.org/licenses/osl.php
#
# Sami Kerola <sami.kerola@teliasonera.com>
#
# Latest version is available from http://www.iki.fi/kerolasa/dhcp/
# This is version 1.4
BEGIN {

34
contrib/dhcpd-pools.cgi Executable file
View file

@ -0,0 +1,34 @@
#!/bin/sh
#
# Simple CGI for dhcpd-pools.
echo Content-type: text/html
echo
# To make lease table more fancy use CSS definition something
# like this in your style.css file.
#
# TABLE.dhcpd-pools {
# border-style : groove;
# margin-left : 2px;
# foo : bar;
# }
#
# http://www.w3.org/TR/REC-CSS2/tables.html
#
# And uncomment this line.
#
#echo <link type="text/css" rel="stylesheet" href="/style.css" />
echo "<html>"
echo "<body>"
echo "<p>This was situation at "
date
echo "</p>"
/usr/local/bin/dhcpd-pools --format html
echo "</body>"
echo "</html>"
# EOF

View file

@ -1,111 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFLH/jcBEADNgkgZAr7b/qvHzNkme8eSplDA8UHhcCFQmBnQ8HYFEYBi1Y5a
GhICcuisRSuZIPLtqRF8ntoOXsOHOUxnn5hVR62HxMLgOC1PQMw8TzREobbkAxMp
Vg66c6JXD2+jEGuAbhRk1XyWJHaCN2ewT06ToqGi7jhlw6nz1AHyohhyxeRlyMff
a4daTIRREnh2qouImSOE0E8ETAb0eOnFOsweHhmbpC/RDzuY7Ns8YcNH3FbWT1Kl
4W9vOstB1JcgSz38/tnzoMG2Mf2jI8LgR+6xiHTb7i6bgyWiBOxcJWouTVam6SC0
Bc5cAe8EqHT6NMEjtNjDEzmb3ZFpFUnNKgKK5Wzghf17HAvYwpjYxNNoQl9jNIkf
XroquAyDDXW0IkNdGDARjJGW17r38oRH/R3q79DZNlqV/DPk4YLb0EAKzRAdBYGm
v8Bj+uLXc4JT9kTB5E8DT2ZR+61E4eT/zk4rpZ5j6tTktLNaSG58VYc+oQlPkPsB
ntraDsORpa5cK9uPUbHIHN1qd4gi35O4UDSqS023XnStQqsUD4vlzICedPDypn28
h9q2nlNQHSDjIRnZFD+z9IHfVoBNTfm5/UH7NKBAvSS6rP5zsgi2fittt5AFdbmQ
VBOtpYp5vbcdSt8gNdJRy8FRaiQ/2n74xF1Zso/PGni1xRmseS+qBGI95QARAQAB
tB1TYW1pIEtlcm9sYSA8a2Vyb2xhc2FAaWtpLmZpPokCcwQTAQgAXQIbAwULCQgH
AgYVCAkKCwIEFgIDAQIeAQIXgAIZARsYaHR0cDovL2h0dHAta2V5cy5nbnVwZy5u
ZXQWIQSO05bjfjjUcaAFMNOpVTJF/em3OQUCWb42mgUJGcI7YwAKCRCpVTJF/em3
OWNBD/4/N0OO6cA3bmEAum5qmHdcJVcUor9ClY3oY2QWdTyDCmSJLcTZUNsTrYYA
hY5vQsDxG6ZaKiITvhwp9y4PdJmnqqzRfnqnXusSVEsqG3vGHIVlpQj8Vgurr68d
1x2buHGRvRrjBMWR/Ro1TUeNOmM4HStcvjXRTWlHk9VXi9nk+uMQY9n1lXYNChda
0usj7q5QXXFXbOukKrvEZzt4I1tGbSEv7bBIghr5fMAJg8ZqAMDwfqsUKSM38HF4
leCUgMZS7XuXuEb35ImjR1VYYCb+L2Q/PFqDOEGQpUwyLOzXcU9TaIDjMhNQY19y
DTUjW1YdQtf+3XmQFa4X1Od0jP1PiVJhw1LNCQLOENs+SRqT9s0W8+nP3qjso/LR
T3vR3FcGSw6KrESMFvmwY7EEYGvOpEgaIv8sIJl7un4BoWHYq/2D6jDHK/YmbpgG
J2FIvZZ4vVYixqgrqCh54USpwTaKd4KQpdm4zZMJ2yIznR6+gXxTi2TyUwKFV67y
RY6o5n3jusWuRejB1BI2eXRbFSeZn6IxAG8QLlLHu1R/XBB1dYDkbtYZ5XuAJRTH
qjCL+s/4rjJIUj02dmmtiyObN3bs/48DTQsDqgCYbA2wmbBjT9lPmRWfncBSlqbx
XSRwyXnDql+UIi6wphBdESn5TNVJjWxYQ16ZRYoZlz4tV2bPl4kCHAQQAQoABgUC
WCOB1QAKCRCB/dUuZfDuelcKD/4iggO8sgYYmTf63y2LJhG7e2d3K/cbQ04Pn/iF
b6zBa5kCsLAWHJmWBPlPkQB3HjZ+j1OSs4sHvwuotuVde2cbtzEvuphQRamFSU83
lakXwXrk00IU7oVEz1Yo9c7IB6pOY0uDgQMIp/Vitm9pomZXAV3S1bYciYuvXdJC
6SaUbyrHzkVgxEV7TSK2XUgMFGnBCIUhqxNA+chkGg6KS715XH8MJyb1Izinsjux
Q07+tquoiYqRhSntTc+bJ83OpSB8bPlqP1FZdc+ypZjq8OEpFIZK8QtK+849vzYw
vORq19mwFAY9y6XZip7YZzSGzn7Q4v3XfVJlIwGrkHSnUkqOmQXGdoSHAiwX3WhU
nPtpYFZQoFFQjm0SsgdPWbqJmmLj2MjHUFbKzl9PVa0INnwp6RxfzNZjU6OxphoI
ocw+2hmXv/lHzb+cwFf8Nae0WOJkCoGwxk9mYA0omhuKJ/WWVvauu+uaswBkeX6O
1Yf1jSrWgK5u+jbDcmZj0kFL0zdB/pBxshngxCA3efPd1e2dJGcPlaoqkwZAtEmG
hwWDj9Gk5IhSX1/Wpv+ke2wprUPzwv7Z5loXroLub2R29FWyHzymwlnts5hSg7kR
1PzxD3iOHFgmnWcBCchf8UWmAjrutZQJZWLTDkzlC6Vj8rkJcgdb0v14zvYVJTWs
Q/hMDYkCHAQSAQoABgUCWCN/ZwAKCRCRAl9JYWN/KLmND/9k8ydscqaMW86NswOC
drJDXuOTDvJJlnLYhgO1+jKQizbHQqnszIVk7KvXY2/K++TdTNdG/+/LosvtIRKb
2DEvV2hPZhc3UxZ2Gnx9ocqjSCfmd9er9EY34WGLtr57eQnu93CJGe10F3qg4rr3
8zsgQcLXomvKnB2J5oRWBla01DXZhum1uIbehrqDmBUz9YxAIz9adY0AjDyLNvAB
IghkjobLHWhouQaTV1IT6Koixdrj6eKekjRojWVZ7Po5dcUe525NlA1yBJhI9VDF
TLy6DHEwmJJuAQqDpyRILzSDsyQ0B+wBgpGks5reCDZlwAjogLy0O6nV2qYKfVXK
ziHeXPvzLPEfSmkA0ZutLXnJBLNfod4zELLJrPJA27dDdQO4yImoAjjTklyBpHXy
Fp3r5RlDq5yA9VpNkC58KJQZoiplkUNBaQTjYgcYX4LDaU4bEq++CUUEnisIyqPO
KqJPJAvmlm1d2vOMxhzcjxt3xBAvDZ8ibRIXlV296Y56SEBe5UZhyUqpAQBa0zsp
oQm9MdkqoC+IDBTRVnbGSxsw0GiQRpAJyNOlkTzP6z6ySmRIQ1hH1TqXx7TChPqP
tcLHLOnRTY9/v5Kt8APa+qgn/0UVgGcetkarqXNdtq+zD1x9C0DFNURBl0uH/E1E
Dtyx4xI6xCY3jzv0Cb1y9Afrc7Q7U2FtaSBLZXJvbGEgKGh0dHA6Ly93d3cuaWtp
LmZpL2tlcm9sYXNhLykgPGtlcm9sYXNhQGlraS5maT6JAlYEEwECAEACGwMHCwkI
BwMCAQYVCAIJCgsEFgIDAQIeAQIXgBYhBI7TluN+ONRxoAUw06lVMkX96bc5BQJZ
vjaaBQkZwjtjAAoJEKlVMkX96bc58KYP/jvpHWmoKKFzqClLdDkN8tBo30GgHGoh
WKHbgW859mi/ZcYzTxlx6Dm88QwV5DRulgqAHvLTippncR3LTpL3Ys86ZDoIskF9
BnWOm/bC+Czl9mDL6BNfFEWWnfeGFsCaMq/Jx8nj8i2o0ezhbTjCeGeng4quWK1D
T6G8Kvnk7Dc+i0n20LUQf2WRCLrtJEl/PMElc+11X/jLm9ypjE/jr24xiNsZck45
4rdMsdkZqgbSHWNIHyxS66mWmD1vbHp3kq0ic09ISCx/Xc7OQpv7V0hN+lxE+AvA
3Mjp2i7A3ntwUbPwmZkdiWUrBqU4CYee0S4fbgroUjNQ/JhGZmCku5YbcyAg4KrP
quXEftY0HP3qQMMElcwna5ljDQdC9NGuSWkH0OKZsuXlgtIz583wjNTKupzii+jo
AJcNnbdRR4i/U7cI+/ySluTp+Az/odmTNzssGnlsXOSGYWk4o6ruKvU4HzUauMEO
XPrTvI7IlH/GIHvwrOcXAyAU90M0qppC4YjXK8oCawzTnbQVQsbedwoNaEPaD4Bz
N4ka9PtvgKnBzODvOeDsTz1O6vTomttW2C6nficc/PXQvxDkZ3NeJw3eGiiAQxeA
w2Ps3+oIasyQZZVLlvu8dfE2BsPArggPLNgd6bLk3yk/gQGR0D+/TyHuCgPM1nZt
mBG3utrXfMz3iQIcBBABCgAGBQJYI4HVAAoJEIH91S5l8O56YhYQAIfxcRP31w+6
htYZO5dGS1zF1CReY8VO/AyBa59YJHAlFSbOhqHQY1SAYD+H1IZhv/JCvQScZhyT
giI3KPP1RAPUa1xGZrf4hwl7Yu8ZpFn1Y0Gxd4bj2i9HWJcd1A+ci4kc+dU4rPEB
ac2U06vcIyuyCSjuK2RdYCyd7pQRkoUtZxWen6sxi1khsw3Qucfbr5QZyh/roA4i
hTb3VlFFIiCRcZOAqSYml9a+kbDxpgswbdCE3EMHVYBWtFwWImZOhnsun148H7EA
+b+hAcbkoNpXJOfC8q/EM0qm6C1GhryXe1voLxfeMdKKjXM78dc0z3L/Vz0E+stD
qrT7CG1jLSk/rIjSvRhbnEX/ZTKa+19ytht0B2zxkokjevvzw6cXSM5JjG8Q9k7R
PcPOTS0t7MSwRqCEFvhvswH3JYy0SH0U2nKbPmkY1Awh6BZNyGpf3dxHV648RVZv
lrXUbXv1azD8U+llaMkVx0PTbej0RcRHQM6B5zJ0qu1MC64V/v2uUK3MNl38JdFa
wkB494uf024FRIfJlQ8+WYrsGlHbUBZZsWzsyrPaeaqL0Xcy+hOc7wu7cZPxkqL8
71O3jbq2dFkBWA4ANsiRdJTh14qoen4YVdc9gjq6HsuFyu0gauDktLaLUHVCX27e
kWThHNxeNoGkcKKHoQdHrN8sII8C1q6fiQIcBBIBCgAGBQJYI39nAAoJEJECX0lh
Y38oIbEP/165gMnaD+g7cfGsHCHQk9/ZrE+4iXfZSwxlhaJ4kK88Ad/tPvoiOxmS
NaUIfH/koGBQNeE/OjjIkPiGlsldg9//4mGmSglM4jLeQBG0QuTLo30aNCl9xU6q
rv9PV/ROfjRUF5NxCAiDdA24uBZ8CftdK5sglD6fazeINQyNk5Wm8e7Jk9PRzIuK
jnZRyaGJl3egx5smWnCZZ8QfjsYXDzbp1uDavmF7Qczp+xbzBhdh6VdSZ0VwvnPr
kN3CzGiR3AuG982R41UGZQ3a+3d38QnmX8cdT1yCqJLrSh4+AJbuGrndOqxBhTN0
VQBIGHteZ6ezxDHs4kVBwfSc3XOzNimJKFVxWCJDXZQojKawu7PaDPYGxU9OWAjs
OWtJFTGqeEiBDQbnLwncT5l/I1O1zv9MIFhQ4MgJeRbvG/QjuLrP6RoIMGZLkX6K
o35dZ6gO/XAdhJmOhfon6Q5/RPdB11e/UkM58xZMbQLGJ3Gm9vjz039vwMabMjXf
28UE3xKzdzDg8Fb3ykNtIQSFNr/cf5YBZ7KMtfJ6ugExmJQQdWxZLQpHoNNCmknt
OHOajlB628N3J0PKlwPjjt5KveBO2ur/yAly6SSv2Oi/astGscgrJtIyPFKMmKar
gPzEnPv4DfLbHnskHkyzVBrQE16Pmcfx4fAe2LeDIO8KJMqSxKOouQINBFLH/jcB
EADGsDuJyhEGExcInkb4Zy8HlSNaT0nFxpQK+tI5RlqyC11TnxdUDCQwPPRh/hdN
s7RDQ6lHhmXydD04+Sjjn0nkQCxd8TlBTwOU6BV4vPF7BonskTMHb6mXxOo+6f7+
J5q4beQ7XzRSoFqLZ0kiump7B4m6L4WSqZmcfi8f6EOQZHK1HsTB2jE+cwaPm7vN
eNaKXYM6hHojZ7XnDavv4vMxfLRGGx5e6wNcZexD4t4pkMwmA+A576t5CnIm8JVB
2HLj2YZN6DfIfYQ9EcMYSYVLg/EuivPaMZIoIa9ki5TbeQDANluJqAG+i+CSoIfJ
X1V1p0WoeSEKJnGBhVFmajU+nek1lCqeM/VXQF4dWbFCQm8/eKl1M9PY77dwT90x
RZDeigM6o6CoB+6rfePAnwsmtA21LyQ9WMTCH9qii9SvlWkfCvLK3HnC/2d1ctws
F8yoc6KF+Qwj7RV23/iHYqjxB8OcOAyHuv+k0sD9o0MLlzAExOftLPkwyWS8ePs7
rJVLSA42N3diUYx5TO3NzmU8ifn4hGxbF9J/sIYQUfCxH9V+DBe2vhVSZ/bQKpVU
ZTE8KxINL32JvTR3HbEwHKIe0xIFnDOMGrWP7icPEsaSKj/0vEq/Is/R2nJWfD0V
zs7vil9zYU16vHQtZrv/5SzavzDRFGxLm7/jDfrzMuNRdQARAQABiQIlBBgBAgAP
BQJSx/43AhsMBQkJZgGAAAoJEKlVMkX96bc5cYEQAI8xVRdoza/MY9KFJCRiobii
4GjxAJqIXXvbY8mM7rvmiLnzfr5msLzSop7Epse6tkI8QvYXbY+EjXke27J8rM/z
qXyqdKJfcqKVzq6fIQyVVsz9o0hwvuSjkcSgCV2b8XHKbNygSnNh2VJ5YY/zL2x5
tsySa3tLukh46ydKWRQqOSMIxMT0TnCOiTMr5INwGnX68rB0kEuCSUdkzDuyulW2
T0oN7Yx4ASgrJixwSu/UNMO/fXvkG0NYIWeXQcnn0C8zQv/PAfzJ9O+24Md4m6tz
VuDpblSRB6E8xQhusysRc4BEHB/G3Ege3JR/tumT6solJD7pfFDYkC9rAKhTKK9h
1b2VpEGxN9o8qwwjtNljLakEYXuWNpCmZxKAR4Agg3UY8CGmgsTKyjsfB9iO2+LX
CS9uQMAtIHbnr++mPASBEKD6rP8QIyf12fbI9JRNGWcXQVZBGXWmu4UaKOrXBTVz
ooj2yG7kZmKO0FoIaCqqTUs2/KhnFj2EFvym2j1OMrYxOM/pT6w3cv3CwGb1ILOX
0qrTQiEpOExSMa21Mi4678jXt6F6NPWG/lwlgE1WM9i9jIcua+NU5ZJiqQ/rjuSR
MB/WFrQy66/jb9wWNp/G6DXrANgdgoC9Dq5oviB+dqSXlU5b0atG4ru506mXCHKm
OC+wu0oRlGQ/X6iuuDfS
=fVwo
-----END PGP PUBLIC KEY BLOCK-----

1
contrib/nagios.conf Normal file
View file

@ -0,0 +1 @@
command[check_dhcpd_pools]=/usr/bin/dhcpd-pools --warning $ARG1$ --critical $ARG2$

View file

@ -1 +0,0 @@
command[check_dhcpd_pools]=@bindir@/dhcpd-pools --warning $ARG1$ --critical $ARG2$

View file

@ -1,4 +0,0 @@
Klaus Slott made a package that works for opensuse, and is
a good starting point for whom ever happens to need an rpm.
https://build.opensuse.org/package/show/home:Mr_Manor/dhcpd-pools

View file

@ -23,10 +23,9 @@
# you set $dbg to 1 then output will be generated in /tmp.
use strict;
use NetSNMP::OID;
# Version info:
my $SNMPver = "snmp1.1";
my $SNMPver = "snmp1.0";
my $DHCPver = "dhcp1.0";
my $VERSION = "$SNMPver/$DHCPver";
#
@ -194,7 +193,7 @@ sub ParseDataFile () {
}
close IN;
if ($dbg) {
foreach (sort Oidcmp @validoidlist) { print DBG "ValidOID: $_\n"; }
foreach (sort @validoidlist) { print DBG "ValidOID: $_\n"; }
}
if ($dbg) {
@ -371,7 +370,7 @@ sub GetData ($) {
@userquery = split (/\./, $userqueryoid);
my $found = 0;
foreach (sort Oidcmp @validoidlist) {
foreach (sort @validoidlist) {
$next = $_;
print DBG "Comparing $userqueryoid vs. $_\n" if $dbg;
@validoid = split (/\./, $_);
@ -433,12 +432,6 @@ sub Pong {
$line = 0;
}
sub Oidcmp {
my $oida = new NetSNMP::OID($a);
my $oidb = new NetSNMP::OID($b);
snmp_oid_compare($oida, $oidb);
}
################################## START ##################################
#
# Main

View file

@ -1,4 +0,0 @@
Zabbix 5 template, and instructions how to use it, can be found from
Mathieu's repository.
https://github.com/mmorier86/dhcpd-pools-zabbix-template

3
doc/.gitignore vendored
View file

@ -1,3 +0,0 @@
/doxy.conf
/doxyfile.stamp
/html

View file

@ -1,14 +1,10 @@
PATHFILES += \
doc/doxy.conf
nodist_noinst_DATA = \
doc/doxy.conf
EXTRA_DIST += \
doc/doxy.conf.in \
doc/introduction.dox
if ENABLE_DOXYGEN
doc/doxyfile.stamp:
doxyfile.stamp:
$(DOXYGEN) doc/doxy.conf
date > doc/doxyfile.stamp

File diff suppressed because it is too large Load diff

216
lib/.gitignore vendored
View file

@ -1,52 +1,45 @@
/alloca.h
/alloca.in.h
/arg-nonnull.h
/*.o
/*.lo
/.deps/
/.gitignore~
/.libs/
/arpa/
/arpa_inet.c
/Makefile
/Makefile.am
/Makefile.in
/_Exit.c
/arg-nonnull.h
/arpa_inet.in.h
/assert.in.h
/attribute.h
/basename-lgpl.c
/basename-lgpl.h
/c32is-impl.h
/c32isprint.c
/calloc.c
/atexit.c
/c++defs.h
/c-ctype.c
/c-ctype.h
/c++defs.h
/cdefs.h
/cloexec.c
/cloexec.h
/c-strcase.h
/c-strcasecmp.c
/c-strcaseeq.h
/c-strncasecmp.c
/calloc.c
/charset.alias
/close-stream.c
/close-stream.h
/close.c
/closeout.c
/closeout.h
/close-stream.c
/close-stream.h
/c-strcasecmp.c
/c-strcaseeq.h
/c-strcase.h
/c-strncasecmp.c
/dup2.c
/config.charset
/configmake.h
/dosname.h
/errno.in.h
/error.c
/error.h
/error.in.h
/exitfail.c
/exitfail.h
/fclose.c
/fcntl.c
/fcntl.h
/fcntl.in.h
/fd-hook.c
/fd-hook.h
/fdopen.c
/fflush.c
/filename.h
/flexmember.h
/float.c
/float+.h
/float.h
/float.in.h
/fopen.c
/fpending.c
/fpending.h
@ -59,204 +52,91 @@
/fstat.c
/ftell.c
/ftello.c
/getdtablesize.c
/getlocalename_l-unsafe.c
/getlocalename_l-unsafe.h
/getopt1.c
/getopt.c
/getopt-cdefs.in.h
/getopt-core.h
/getopt-ext.h
/getopt.in.h
/getopt1.c
/getopt_int.h
/getopt-pfx-core.h
/getopt-pfx-ext.h
/getprogname.c
/getprogname.h
/gettext.h
/hard-locale.c
/hard-locale.h
/ialloc.c
/ialloc.h
/idx.h
/inet_pton.c
/intprops.h
/intprops-internal.h
/inttypes.h
/inttypes.in.h
/isnan.c
/isnand.c
/isnanf.c
/isnanl.c
/itold.c
/lc-charset-dispatch.c
/lc-charset-dispatch.h
/libc-config.h
/langinfo.h
/langinfo.in.h
/libdhcpd_pools.la
/libdhcpd_pools_la-arpa_inet.lo
/libdhcpd_pools_la-basename-lgpl.lo
/libdhcpd_pools_la-c32isprint.lo
/libdhcpd_pools_la-c-ctype.lo
/libdhcpd_pools_la-cloexec.lo
/libdhcpd_pools_la-closeout.lo
/libdhcpd_pools_la-close-stream.lo
/libdhcpd_pools_la-c-strcasecmp.lo
/libdhcpd_pools_la-exitfail.lo
/libdhcpd_pools_la-fclose.lo
/libdhcpd_pools_la-fcntl.lo
/libdhcpd_pools_la-fd-hook.lo
/libdhcpd_pools_la-fflush.lo
/libdhcpd_pools_la-float.lo
/libdhcpd_pools_la-fopen.lo
/libdhcpd_pools_la-fpurge.lo
/libdhcpd_pools_la-freading.lo
/libdhcpd_pools_la-fseek.lo
/libdhcpd_pools_la-fseeko.lo
/libdhcpd_pools_la-getprogname.lo
/libdhcpd_pools_la-hard-locale.lo
/libdhcpd_pools_la-ialloc.lo
/libdhcpd_pools_la-localcharset.lo
/libdhcpd_pools_la-malloca.lo
/libdhcpd_pools_la-math.lo
/libdhcpd_pools_la-mbrtoc32.lo
/libdhcpd_pools_la-mbrtowc.lo
/libdhcpd_pools_la-mbszero.lo
/libdhcpd_pools_la-mktime.lo
/libdhcpd_pools_la-nstrftime.lo
/libdhcpd_pools_la-progname.lo
/libdhcpd_pools_la-quotearg.lo
/libdhcpd_pools_la-reallocarray.lo
/libdhcpd_pools_la-realloc.lo
/libdhcpd_pools_la-setlocale_null.lo
/libdhcpd_pools_la-setlocale_null-unlocked.lo
/libdhcpd_pools_la-stat-time.lo
/libdhcpd_pools_la-stdlib.lo
/libdhcpd_pools_la-sys_socket.lo
/libdhcpd_pools_la-timegm.lo
/libdhcpd_pools_la-time_rz.lo
/libdhcpd_pools_la-unistd.lo
/libdhcpd_pools_la-wctype-h.lo
/libdhcpd_pools_la-xalloc-die.lo
/libdhcpd_pools_la-xmalloc.lo
/.libs/
/limits.h
/limits.in.h
/localcharset.c
/localcharset.h
/locale.h
/locale.in.h
/localename.h
/localename-unsafe.c
/lseek.c
/Makefile.am
/malloca.c
/malloca.h
/malloc.c
/math.c
/math.h
/math.in.h
/mbrtoc32.c
/mbrtowc.c
/mbrtowc-impl.h
/mbrtowc-impl-utf8.h
/mbsinit.c
/mbszero.c
/mbtowc-lock.c
/mbtowc-lock.h
/memchr.c
/memchr.valgrind
/minmax.h
/mktime.c
/mktime-internal.h
/memcpy.c
/msvc-inval.c
/msvc-inval.h
/msvc-nothrow.c
/msvc-nothrow.h
/netinet_in.in.h
/_Noreturn.h
/nstrftime.c
/open.c
/pathmax.h
/progname.c
/progname.h
/quote.h
/quotearg.c
/quotearg.h
/quote.h
/reallocarray.c
/realloc.c
/setenv.c
/setlocale-lock.c
/setlocale_null.c
/setlocale_null.h
/setlocale_null-unlocked.c
/ref-add.sed
/ref-add.sin
/ref-del.sed
/ref-del.sin
/stat.c
/stat-time.c
/stat-time.h
/stat-w32.c
/stat-w32.h
/stdckdint.h
/stdckdint.in.h
/stddef.h
/stdalign.h
/stdalign.in.h
/stdarg.in.h
/stdbool.in.h
/stddef.in.h
/stdint.in.h
/stdio.h
/stdio-impl.h
/stdio.c
/stdio.h
/stdio.in.h
/stdio-read.c
/stdio-write.c
/stdlib.c
/stdlib.h
/stdlib.in.h
/stpncpy.c
/str-two-way.h
/strdup.c
/streq.h
/strerror.c
/strerror-override.c
/strerror-override.h
/strerror.c
/strftime.c
/strftime.h
/string.h
/string.in.h
/strstr.c
/strtod.c
/str-two-way.h
/sys/
/sys_socket.c
/sys_socket.in.h
/sys_stat.in.h
/sys_types.in.h
/sys_uio.in.h
/timegm.c
/time.h
/time.in.h
/time-internal.h
/time_r.c
/time_rz.c
/tzset.c
/uchar.h
/uchar.in.h
/unictype/
/unictype/bitmap.h
/unictype/ctype_print.c
/unictype/ctype_print.h
/unictype/.gitignore
/unictype.h
/unictype.in.h
/unistd.c
/unistd.h
/unistd.in.h
/unitypes.h
/unitypes.in.h
/unsetenv.c
/unused-parameter.h
/verify.h
/warn-on-use.h
/wchar.h
/wchar.in.h
/wctype.h
/wctype-h.c
/wctype.h
/wctype.in.h
/windows-initguard.h
/xalloc-die.c
/xalloc.h
/xalloc-oversized.h
/xalloc.h
/xmalloc.c
/xprintf.c
/xprintf.h
/xstrtod.c
/xstrtod.h
/stpncpy.c

View file

@ -1,2 +1,3 @@
man_MANS = man/dhcpd-pools.1
PATHFILES += man/dhcpd-pools.1
EXTRA_DIST += man/dhcpd-pools.1.in
CLEANFILES += man/dhcpd-pools.1

View file

@ -1,28 +1,9 @@
'\" t
.TH DHCPD-POOLS "1" "2024-08-09" "@VERSION@" "User Commands"
.TH DHCPD-POOLS "1" "2012-11-25" "@PACKAGE_STRING@" "User Commands"
.SH NAME
dhcpd-pools \- ISC dhcpd pools usage analysis
.SH SYNOPSIS
.SY dhcpd-pools
.OP \-\-config file
.OP \-\-leases file
.OP \-\-sort nimcptTe
.OP \-\-reverse
.OP \-\-format tHcxXjJ
.OP \-\-mustach template
.OP \-\-output file
.OP \-\-limit nr
.OP \-\-color when
.OP \-\-warning percent
.OP \-\-critical percent
.OP \-\-warn\-count number
.OP \-\-crit\-count number
.OP \-\-snet\-alarms
.OP \-\-minsize size
.OP \-\-perfdata
.OP \-\-version
.OP \-\-help
.YS
.B dhcpd-pools
[options]
.SH DESCRIPTION
The program analyses ISC dhcpd shared network and pool usage and outputs the
results in a format selected by user.
@ -68,29 +49,29 @@ only if there is failover configuration.
.SH OPTIONS
.TP
\fB\-c\fR, \fB\-\-config\fR=\fIFILE\fR
Path to the dhcpd.conf file. If the dhcpd.conf has include files they
can be analysed separately, that can be useful when trying to understand
or monitor subset of data.
Path to the dhcpd.conf file.
.TP
\fB\-l\fR, \fB\-\-leases\fR=\fIFILE\fR
Path to the dhcpd.leases file.
.TP
\fB\-s\fR, \fB\-\-sort\fR=\fI[nimcptTe]\fR
Sort ranges by chosen fields as a sorting keys. Keys weight from left to
right, i.e., if more weighting keys are equal next one is used. The IP
field is default sort key.
Sort ranges by chosen fields as a sorting keys. Maximum of five sort keys
can be defined. Keys weight from left to right, i.e., if more weighting keys
are equal next one is used. The IP field is default sort key.
.TP
\fB\-r\fR, \fB\-\-reverse\fR
Sort results in reverse order.
.TP
\fB\-f\fR, \fB\-\-format\fR=\fI[tHcxXjJ]\fR
\fB\-f\fR, \fB\-\-format\fR=\fI[thHcxXjJ]\fR
Output format.
Text
.RI ( t ).
Full-html
Standard html
.RI ( h )
outputs only the HTML tables, and is useful for embedding more complex web
pages. Full-html
.RI ( H )
page output. In html page critical and warning thresholds can be visualized
with \-\-color=always option. The
provides complete HTML headers, etc., including in-line CSS. The
.RI ( c )
stands for comma-separated values. Output format xml
.RI ( x )
@ -105,18 +86,6 @@ to include ethernet address.
The default format is
.IR @OUTPUT_FORMAT@ .
.TP
\fB\-\-mustach\fR=\fITEMPLATE\fR
Output using mustach
.I template
file. This is useful when the native output formats controlled with
.B \-\-format
option do not provide what you need. See below example mustach template
that is using all available {{tags}} to demonstrate what can be displayed
and how.
.IP
@bindir@/dhcpd-pools --config @docdir@/dhcpd.conf --leases
@docdir@/dhcpd.leases --mustach @docdir@/mustach.template
.TP
\fB\-o\fR, \fB\-\-output\fR=\fIFILE\fR
.I File
where output is written. Default is stdout.
@ -135,17 +104,29 @@ determines which numeric analysis tables to include in the output. The
following values are "OR'd" together to create the desired output. The
default is
.IR @OUTPUT_LIMIT@ .
.IP
.TS
tab(:);
ll.
0\fI1\fR:Print ranges
0\fI2\fR:Print shared networks
0\fI4\fR:Print total summary
\fI1\fR0:Print range header
\fI2\fR0:Print shared network header
\fI4\fR0:Print total summary header
.TE
.PP
.RS
.PD 0
.TP
.B 01
Print ranges
.TP
.B 02
Print shared networks
.TP
.B 04
Print total summary
.TP
.B 10
Print range header
.TP
.B 20
Print shared network header
.TP
.B 40
Print total summary header
.PD
.RE
.IP
The output limit for total summary has special meaning in
.B \-\-warning
@ -155,37 +136,6 @@ alarming context. When the alarming is in use, and total is not wanted
to be seen then in the case of alarming returning success nothing is
printed.
.TP
\fB\-\-color\fR=\fIwhen\fR
Use yellow for warning, red for critical, green for suppressed by \-\-minsize
and blue when \-\-snet\-alarms is the cause of suppression or shared network
does not have any ranges. The
.I when
string can be
.BR always ,
.BR never ,
or
.BR auto .
Default is auto, that uses colors when command is running in interactive
terminal. With use of
.B \-\-warning
or
.B \-\-critical
coloring thresholds can be changed, but one must also use
.B \-\-format=text
to avoid turning on alarting mode.
.TP
\fB\-\-skip\fR=\fIwhen\fR
The
.I when
can be one of the following:
.IR ok ,
.IR warning ,
.IR critical ,
.IR minsize ,
or
.IR suppressed .
The skipping criteria is exact match with colors in \-\-color option.
.TP
\fB\-\-warning\fR=\fIpercent\fR
Turn on alarm output format, and specify percentage number which will
cause an alarm. If either a range or shared network will exceed
@ -209,55 +159,12 @@ is
If critical percentage is not specified it defaults to
.BR @ALARM_CRIT@ .
.TP
\fB\-\-warn\-count\fR=\fInumber\fR
A
.I number
of free leases before alarm is raised. When specified both \-\-warning
.I percent
and count
.I number
are required to be exceeded in order to alarm criteria being fulfilled.
.IP
This option is intended to be used in setup where very large and small
shared-networks and ranges co-exists. In such environments percent based
alarming can lead to either flood of alarms about small ranges, or way too
great overhead of free addresses in large shared-networks. Suggested usage
is to set percentage to a level that makes small ranges to ring, and set the
count to match level when an enormous shared-network is too few free leases.
.IP
Defaults to 2^32, that is size of entire IPv4 address space.
.TP
\fB\-\-crit\-count\fR=\fInumber\fR
Same as \-\-warn\-count, but for critical alarms.
.TP
\fB\-\-snet\-alarms
Suppress range alarms that are part of shared networks. Use of this option
will keep alarm criteria applied to ranges that are not part of shared-net
along with shared-net alarms. This option may help reducing alarm noise for
configurations that has lots of small ranges in big shared-networks.
.TP
\fB\-\-minsize\fR=\fIsize\fR
\fB\-\-minsize\fR=\fIsize\f
Ignore ranges and shared networks that are smaller or equal to the
defined size. This option is meaningful only in context of alarming, and
will intended to suppress for example single host ranges. By default this
will intented to supress for example single host ranges. By default this
option is not in use.
.TP
\fB\-p\fR, \fB\-\-perfdata\fR
Print additional performance data, like lease count, touched leases and
backup leases. This option is meaningful only in context of alarming and
will print lots of data, if there are many networks. By default this option
is not in use.
.TP
\fB\-A\fR, \fB\-\-all\-as\-shared\fR
Treat all stand-alone subnets as shared-network with named formed from it's
CIDR. By default this option is not in use for backwards compatibility.
.TP
\fB\-\-ip\-version\fR=\fI4|6\fR
Force command to read configuration and leases files in IPv4 or IPv6 mode.
Notice that when inputs do not match with what is forced analysis output is
garbage. This option should not be necessary to use, and exists only to
allow debugging.
.TP
\fB\-v\fR, \fB\-\-version\fR
Print version information to standard output and exit successfully.
.TP
@ -286,7 +193,7 @@ $ dhcpd-pools \-c dhcpd.conf \-l dhcpd.leases \-L 22 \-\-critical 70 \-\-warning
.br
[no-output]
.br
Suppress printing OK, and make alarm only to go off if shared networks
Supress printing OK, and make alarm only to go off if shared networks
exceed critial or warning levels.
.SH FILES
.TP
@ -295,23 +202,14 @@ ISC dhcpd configuration file.
.TP
@DHCPDLEASE_FILE@
ISC dhcpd lease file.
.TP
@docdir@/prometheus.template
Prometheus text file collector mustach template.
.SH AUTHORS
Original design by Sami Kerola.
.br
uthash by Troy D. Hanson.
.br
XML support by Dominic Germain, Sogetel inc.
.br
IPv6 support by Cheer Xiao.
.br
Mustache templating support by José Bollo.
.SH LICENSE
The dhcpd-pools uses FreeBSD License, uthash uses BSD license, the mustache
uses Apache License, and the gnulib modules are mostly, but not entirely,
GPL.
.PP
The software has FreeBSD License.
.SH "REPORTING BUGS"
Report bugs to
.MT @PACKAGE_BUGREPORT@
@ -324,6 +222,4 @@ Home page
.SH "SEE ALSO"
.BR dhcpd.leases (5),
.BR dhcpd.conf (5),
.BR chmod (1),
.UR https://mustache.github.io/
.UE
.BR chmod (1)

View file

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<rdf:RDF xml:lang="en" xmlns="http://usefulinc.com/ns/doap#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
xmlns:foaf="http://xmlns.com/foaf/0.1/">
<Project rdf:about="https://dhcpd-pools.sourceforge.net/">
<name>dhcpd-pools</name>
<homepage rdf:resource="https://dhcpd-pools.sourceforge.net/" />
<shortdesc>This is dhcpd-pools ISC dhcp shared network and pool
range usage analysis tool.</shortdesc>
<description>Purpose of command is to count usage ratio of each
IP range and shared network pool which ISC dhcpd is in control
of. Program is written C. Design goal is to get analysis done
quickly where there is lots of data. On cheap laptop the speed
of analysis is more than 100k leases per second. Number of
ranges, or shared networks, does not make any significant
difference in getting analysis done.</description>
<mailing-list rdf:resource="https://lists.sourceforge.net/lists/listinfo/dhcpd-pools-announce" />
<download-page rdf:resource="https://sourceforge.net/projects/dhcpd-pools/files/" />
<programming-language>C</programming-language>
<repository>
<GitRepository>
<location rdf:resource="git://git.code.sf.net/p/dhcpd-pools/code" />
<browse rdf:resource="https://sourceforge.net/p/dhcpd-pools/code/ci/master/tree/" />
</GitRepository>
</repository>
<License>
<rdfs:label>BSD 2-Clause license</rdfs:label>
<rdfs:seeAlso rdf:resource="https://sourceforge.net/p/dhcpd-pools/code/ci/master/tree/COPYING?format=raw" />
</License>
<maintainer>
<foaf:Person>
<foaf:name>Sami Kerola</foaf:name>
<foaf:mbox rdf:resource="mailto:kerolasa@iki.fi" />
</foaf:Person>
</maintainer>
</Project>
</rdf:RDF>

View file

@ -1,5 +0,0 @@
dist_doc_DATA = \
samples/dhcpd.conf \
samples/dhcpd.leases \
samples/mustach.template \
samples/prometheus.template

View file

@ -1,31 +0,0 @@
shared-network example1 {
subnet 10.0.0.0 netmask 255.255.255.0 {
pool {
range 10.0.0.1 10.0.0.20;
}
}
subnet 10.1.0.0 netmask 255.255.255.0 {
pool {
range 10.1.0.1 10.1.0.20;
}
}
}
shared-network example2 {
subnet 10.2.0.0 netmask 255.255.255.0 {
pool {
range 10.2.0.1 10.2.0.20;
}
}
subnet 10.3.0.0 netmask 255.255.255.0 {
pool {
range 10.3.0.1 10.3.0.20;
}
}
}
subnet 10.4.0.0 netmask 255.255.255.0 {
pool {
range 10.4.0.1 10.4.0.20;
}
}

View file

@ -1,210 +0,0 @@
lease 10.0.0.0 {
binding state active;
hardware ethernet 00:00:00:00:00:00;
}
lease 10.0.0.1 {
binding state active;
hardware ethernet 00:00:00:00:00:01;
}
lease 10.0.0.2 {
binding state active;
hardware ethernet 00:00:00:00:00:02;
}
lease 10.0.0.3 {
binding state active;
hardware ethernet 00:00:00:00:00:03;
}
lease 10.0.0.4 {
binding state active;
hardware ethernet 00:00:00:00:00:04;
}
lease 10.0.0.5 {
binding state active;
hardware ethernet 00:00:00:00:00:05;
}
lease 10.0.0.6 {
binding state active;
hardware ethernet 00:00:00:00:00:06;
}
lease 10.0.0.7 {
binding state active;
hardware ethernet 00:00:00:00:00:07;
}
lease 10.0.0.8 {
binding state active;
hardware ethernet 00:00:00:00:00:08;
}
lease 10.0.0.9 {
binding state active;
hardware ethernet 00:00:00:00:00:09;
}
lease 10.0.0.10 {
binding state active;
hardware ethernet 00:00:00:00:00:10;
}
lease 10.0.0.11 {
binding state active;
hardware ethernet 00:00:00:00:00:11;
}
lease 10.0.0.12 {
binding state backup;
hardware ethernet 00:00:00:00:00:12;
}
lease 10.1.0.0 {
binding state active;
hardware ethernet 00:00:00:00:01:00;
}
lease 10.1.0.1 {
binding state active;
hardware ethernet 00:00:00:00:01:01;
}
lease 10.1.0.2 {
binding state active;
hardware ethernet 00:00:00:00:01:02;
}
lease 10.1.0.3 {
binding state active;
hardware ethernet 00:00:00:00:01:03;
}
lease 10.1.0.4 {
binding state active;
hardware ethernet 00:00:00:00:01:04;
}
lease 10.1.0.5 {
binding state active;
hardware ethernet 00:00:00:00:01:05;
}
lease 10.1.0.6 {
binding state active;
hardware ethernet 00:00:00:00:01:06;
}
lease 10.1.0.7 {
binding state active;
hardware ethernet 00:00:00:00:01:07;
}
lease 10.1.0.8 {
binding state active;
hardware ethernet 00:00:00:00:01:08;
}
lease 10.1.0.9 {
binding state active;
hardware ethernet 00:00:00:00:01:09;
}
lease 10.1.0.10 {
binding state active;
hardware ethernet 00:00:00:00:01:10;
}
lease 10.2.0.0 {
binding state active;
hardware ethernet 00:00:00:00:02:00;
}
lease 10.2.0.1 {
binding state active;
hardware ethernet 00:00:00:00:02:01;
}
lease 10.2.0.2 {
binding state active;
hardware ethernet 00:00:00:00:02:02;
}
lease 10.2.0.3 {
binding state active;
hardware ethernet 00:00:00:00:02:03;
}
lease 10.2.0.4 {
binding state active;
hardware ethernet 00:00:00:00:02:04;
}
lease 10.2.0.5 {
binding state active;
hardware ethernet 00:00:00:00:02:05;
}
lease 10.2.0.6 {
binding state active;
hardware ethernet 00:00:00:00:02:06;
}
lease 10.2.0.7 {
binding state active;
hardware ethernet 00:00:00:00:02:07;
}
lease 10.2.0.8 {
binding state active;
hardware ethernet 00:00:00:00:02:08;
}
lease 10.3.0.0 {
binding state active;
hardware ethernet 00:00:00:00:03:00;
}
lease 10.3.0.1 {
binding state active;
hardware ethernet 00:00:00:00:03:01;
}
lease 10.3.0.2 {
binding state active;
hardware ethernet 00:00:00:00:03:02;
}
lease 10.3.0.3 {
binding state active;
hardware ethernet 00:00:00:00:03:03;
}
lease 10.3.0.4 {
binding state active;
hardware ethernet 00:00:00:00:03:04;
}
lease 10.3.0.5 {
binding state active;
hardware ethernet 00:00:00:00:03:05;
}
lease 10.3.0.6 {
binding state active;
hardware ethernet 00:00:00:00:03:06;
}
lease 10.3.0.7 {
binding state active;
hardware ethernet 00:00:00:00:03:07;
}
lease 10.3.0.8 {
binding state active;
hardware ethernet 00:00:00:00:03:08;
}
lease 10.3.0.9 {
binding state active;
hardware ethernet 00:00:00:00:03:09;
}
lease 10.3.0.9 {
binding state active;
hardware ethernet 00:00:00:00:03:09;
}
lease 10.4.0.0 {
binding state active;
hardware ethernet 00:00:00:00:04:00;
}
lease 10.4.0.1 {
binding state active;
hardware ethernet 00:00:00:00:04:01;
}
lease 10.4.0.2 {
binding state active;
hardware ethernet 00:00:00:00:04:02;
}
lease 10.4.0.3 {
binding state active;
hardware ethernet 00:00:00:00:04:03;
}
lease 10.4.0.4 {
binding state active;
hardware ethernet 00:00:00:00:04:04;
}
lease 10.4.0.5 {
binding state active;
hardware ethernet 00:00:00:00:04:05;
}
lease 10.4.0.6 {
binding state backup;
hardware ethernet 00:00:00:00:04:06;
}

View file

@ -1,76 +0,0 @@
Ethernets:{{#active_lease}}
macaddress: {{macaddress}} ip: {{ip}}{{/active_lease}}
Subnets:{{#subnets}}
location: {{location}}
range: {{range}}
first_ip: {{first_ip}}
last_ip: {{last_ip}}
used: {{used}}
touched: {{touched}}
defined: {{defined}}
free: {{free}}
percent: {{percent}}
touch_count: {{touch_count}}
touch_percent: {{touch_percent}}
backup_count: {{backup_count}}
backup_percent: {{backup_percent}}
status: {{status}}
gettimeofday: {{gettimeofday}}
lease_file_epoch_mtime: {{lease_file_epoch_mtime}}
{{/subnets}}
Shared-networks:{{#shared-networks}}
location: {{location}}
defined: {{defined}}
used: {{used}}
touched: {{touched}}
free: {{free}}
percent: {{percent}}
touch_count: {{touch_count}}
touch_percent: {{touch_percent}}
backup_count: {{backup_count}}
backup_percent: {{backup_percent}}
status: {{status}}
gettimeofday: {{gettimeofday}}
lease_file_epoch_mtime: {{lease_file_epoch_mtime}}
{{/shared-networks}}
Summary:{{#summary}}
location: {{location}}
defined: {{defined}}
used: {{used}}
touched: {{touched}}
free: {{free}}
percent: {{percent}}
touch_count: {{touch_count}}
touch_percent: {{touch_percent}}
backup_count: {{backup_count}}
backup_percent: {{backup_percent}}
status: {{status}}
gettimeofday: {{gettimeofday}}
lease_file_epoch_mtime: {{lease_file_epoch_mtime}}
{{/summary}}
localtime: {{localtime}}
number_of_ranges: {{number_of_ranges}}
number_of_shared_networks: {{number_of_shared_networks}}
version: {{version}}
conf_file_path: {{conf_file_path}}
conf_file_local_mtime: {{conf_file_local_mtime}}
conf_file_epoch_mtime: {{conf_file_epoch_mtime}}
lease_file_path: {{lease_file_path}}
lease_file_local_mtime: {{lease_file_local_mtime}}
lease_file_epoch_mtime: {{lease_file_epoch_mtime}}
template_file_path: {{template_file_path}}
template_file_local_mtime: {{template_file_local_mtime}}
template_file_epoch_mtime: {{template_file_epoch_mtime}}
number_of_ranges_warning: {{number_of_ranges_warning}}
number_of_ranges_critical: {{number_of_ranges_critical}}
number_of_shared_networks: {{number_of_shared_networks}}
number_of_shared_networks_warning: {{number_of_shared_networks_warning}}
number_of_shared_networks_critical: {{number_of_shared_networks_critical}}

View file

@ -1,11 +0,0 @@
# This mustach template can be used as Prometheus text file.
# https://prometheus.io/
# HELP dhcpd_pools ISC dhcpd statistics
# TYPE dhcpd_pools gauge
{{#subnets}}dhcpd_pools{location="{{location}}",range="{{first_ip}}",used="1"} {{used}} {{gettimeofday}}000
dhcpd_pools{location="{{location}}",range="{{first_ip}}",touched="1"} {{touched}} {{gettimeofday}}000
dhcpd_pools{location="{{location}}",range="{{first_ip}}",defined="1"} {{defined}} {{gettimeofday}}000
dhcpd_pools{location="{{location}}",range="{{first_ip}}",free="1"} {{free}} {{gettimeofday}}000
dhcpd_pools{location="{{location}}",range="{{first_ip}}",touch_count="1"} {{touch_count}} {{gettimeofday}}000
dhcpd_pools{location="{{location}}",range="{{first_ip}}",status="1"} {{status}} {{gettimeofday}}000
{{/subnets}}

18
src/.indent.pro vendored
View file

@ -1,16 +1,2 @@
-linux
-TFILE
-Tconf_t
-Tipaddr_t
-Tleases_t
-Toff_t
-Trange_t
-Tsize_t
-Ttime_t
-Tuintmax_t
--blank-lines-after-declarations
--format-all-comments
--line-length100
--preprocessor-indentation1
--start-left-side-of-comments
--swallow-optional-blank-lines
-linux -Tuintmax_t -TFILE -Tsize_t -Toff_t -Ttime_t -ppi1

View file

@ -4,10 +4,11 @@ bin_PROGRAMS = dhcpd-pools
AC_PROG_RANLIB = resolv
AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib -I$(top_builddir)/lib
dhcpd_pools_LDADD = $(top_builddir)/lib/libdhcpd_pools.la $(MATH_LIBS)
dhcpd_pools_LDADD = $(top_builddir)/lib/libdhcpd_pools.la
dhcpd_pools_SOURCES = \
src/analyze.c \
src/defaults.h \
src/dhcpd-pools.c \
src/dhcpd-pools.h \
src/getdata.c \
@ -15,10 +16,3 @@ dhcpd_pools_SOURCES = \
src/other.c \
src/output.c \
src/sort.c
if ENABLE_MUSTACH
dhcpd_pools_SOURCES += \
src/mustach-dhcpd-pools.c \
src/mustach.c \
src/mustach.h
endif

View file

@ -46,33 +46,40 @@
#include "dhcpd-pools.h"
/*! \brief Prepare data for analysis. The function will sort leases and
* ranges. */
void prepare_data(struct conf_t *state)
* ranges.
* FIXME: This function should return void. */
int prepare_data(void)
{
/* Sort leases */
HASH_SORT(state->leases, leasecomp);
HASH_SORT(leases, ipcomp);
/* Sort ranges */
qsort(state->ranges, state->num_ranges, sizeof(struct range_t), &rangecomp);
qsort(ranges, (size_t)num_ranges, sizeof(struct range_t), &rangecomp);
return 0;
}
/*!\brief Perform counting. Join leases with ranges, and update range and
* shared network counters. */
void do_counting(struct conf_t *state)
/*! \brief Perform counting. Join leases with ranges, and update counters.
* FIXME: This function should return void. */
int do_counting(void)
{
struct range_t *restrict range_p = state->ranges;
const struct leases_t *restrict l = state->leases;
unsigned long i;
double block_size;
struct range_t *restrict range_p;
const struct leases_t *restrict l = leases;
unsigned long i, k, block_size;
range_p = ranges;
/* Walk through ranges */
for (i = 0; i < state->num_ranges; i++, range_p++) {
while (l != NULL && ipcomp(&range_p->first_ip, &l->ip) < 0)
l = l->hh.prev; /* rewind */
for (i = 0; i < num_ranges; i++) {
for (; l != NULL && ipcomp(&range_p->first_ip, &l->ip) < 0;
l = l->hh.prev)
/* rewind */ ;
if (l == NULL)
l = state->leases;
for (; l != NULL && ipcomp(&l->ip, &range_p->last_ip) <= 0; l = l->hh.next) {
if (unlikely(ipcomp(&l->ip, &range_p->first_ip) < 0))
continue; /* cannot happen? */
l = leases;
for (; l != NULL && ipcomp(&l->ip, &range_p->last_ip) <= 0;
l = l->hh.next) {
if (ipcomp(&l->ip, &range_p->first_ip) < 0) {
/* should not be necessary */
continue;
}
/* IP in range */
switch (l->type) {
case FREE:
@ -84,23 +91,46 @@ void do_counting(struct conf_t *state)
case BACKUP:
range_p->backups++;
break;
default:
abort();
}
if (range_p->shared_net) {
switch (l->type) {
case FREE:
range_p->shared_net->touched++;
break;
case ACTIVE:
range_p->shared_net->used++;
break;
case BACKUP:
range_p->shared_net->backups++;
break;
}
}
}
/* Size of range size. */
/* Size of range, shared net & all networks */
block_size = get_range_size(range_p);
/* Count together ranges within shared network block. */
range_p->shared_net->available += block_size;
range_p->shared_net->used += range_p->count;
range_p->shared_net->touched += range_p->touched;
range_p->shared_net->backups += range_p->backups;
/* When shared network is not 'all networks' add it as well. */
if (range_p->shared_net != state->shared_net_root) {
state->shared_net_root->available += block_size;
state->shared_net_root->used += range_p->count;
state->shared_net_root->touched += range_p->touched;
state->shared_net_root->backups += range_p->backups;
if (range_p->shared_net) {
range_p->shared_net->available += block_size;
}
range_p++;
}
/* FIXME: During count of other shared networks default network
* and all networks got mixed together semantically. The below
* fixes the problem, but is not elegant. */
shared_networks->available = 0;
shared_networks->used = 0;
shared_networks->touched = 0;
range_p = ranges;
for (k = 0; k < num_ranges; k++) {
shared_networks->available += get_range_size(range_p);
shared_networks->used += range_p->count;
shared_networks->touched += range_p->touched;
shared_networks->backups += range_p->backups;
range_p++;
}
return 0;
}

55
src/defaults.h Normal file
View file

@ -0,0 +1,55 @@
/*
* The dhcpd-pools has BSD 2-clause license which also known as "Simplified
* BSD License" or "FreeBSD License".
*
* Copyright 2006- Sami Kerola. 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.
*/
/*! \file defaults.h
* \brief Default settings which cannot be changed without recompiling
* the software.
*/
#ifndef DEFAULTS_H
# define DEFAULTS_H 1
#include "dhcpd-pools.h"
/*! \var MAXLEN
* \brief Maximum expected line length in dhcpd.conf and dhcpd.leases
* files. */
static const size_t MAXLEN = 1024;
/*! \var SHARED_NETWORKS
* \brief Maximum number of different shared networks in dhcpd.conf file. */
static const unsigned int SHARED_NETWORKS = 8192;
#endif /* DEFAULTS_H */

View file

@ -38,253 +38,166 @@
*/
#include <config.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
#include <limits.h>
#include "close-stream.h"
#include "closeout.h"
#include "error.h"
#include "defaults.h"
#include "dhcpd-pools.h"
#include "progname.h"
#include "quote.h"
#include "xalloc.h"
#include "dhcpd-pools.h"
/* Function pointers */
int (*parse_ipaddr) (struct conf_t *state, const char *restrict src, union ipaddr_t *restrict dst);
void (*copy_ipaddr) (union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
const char *(*ntop_ipaddr) (const union ipaddr_t *ip);
double (*get_range_size) (const struct range_t *r);
int (*xstrstr) (struct conf_t *state, const char *restrict str);
int (*ipcomp) (const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
int (*leasecomp) (const struct leases_t *restrict a, const struct leases_t *restrict b);
void (*add_lease) (struct conf_t *state, union ipaddr_t *ip, enum ltype type);
struct leases_t *(*find_lease) (struct conf_t *state, union ipaddr_t *ip);
/*! \brief An option argument parser to populate state header_limit and
* number_limit values.
*/
static int return_limit(const char c)
{
if ('0' <= c && c < '8')
return c - '0';
error(EXIT_FAILURE, 0, "return_limit: output mask %s is illegal", quote(optarg));
return 0;
}
/*! \brief Run time initialization. Global allocations, counter
* initializations, etc are here. */
static void prepare_memory(struct conf_t *state)
{
state->ranges = xmalloc(sizeof(struct range_t) * state->ranges_size);
/* First shared network entry is all networks */
state->shared_net_root = xcalloc(sizeof(struct shared_network_t), 1);
state->shared_net_root->name = xstrdup("All networks");
state->shared_net_head = state->shared_net_root;
}
/*! \brief The --skip option argument parser. */
static void skip_arg_parse(struct conf_t *state, char *arg)
/*! \brief Start of execution. Parse options, and call other other
* functions one after another. At the moment adding threading support
* would be difficult, but there does not seem to be valid reason to
* consider that. Overall the analysis already quick enough even without
* making it parallel.
*
* \return Return value indicates success or fail or analysis, unless
* either --warning or --critical options are in use, which makes the
* return value in some cases to match with Nagios expectations about
* alarming. */
int main(int argc, char **argv)
{
int i, sorts = 0;
int option_index = 0;
char const *tmp;
struct range_t *tmp_ranges;
enum {
OPT_ARG_OK = 0,
OPT_ARG_WARNING,
OPT_ARG_CRITICAL,
OPT_ARG_MINSIZE,
OPT_ARG_SUPPRESSED
};
char *const tokens[] = {
[OPT_ARG_OK] = "ok",
[OPT_ARG_WARNING] = "warning",
[OPT_ARG_CRITICAL] = "critical",
[OPT_ARG_MINSIZE] = "minsize",
[OPT_ARG_SUPPRESSED] = "suppressed",
NULL
};
char *value;
while (*arg != '\0') {
switch (getsubopt(&arg, tokens, &value)) {
case OPT_ARG_OK:
state->skip_ok = 1;
break;
case OPT_ARG_WARNING:
state->skip_warning = 1;
break;
case OPT_ARG_CRITICAL:
state->skip_critical = 1;
break;
case OPT_ARG_MINSIZE:
state->skip_minsize = 1;
break;
case OPT_ARG_SUPPRESSED:
state->skip_suppressed = 1;
break;
default:
error(EXIT_FAILURE, 0, "unknown --skip specifier: %s", value);
}
}
}
/*! \brief Command line options parser. */
static void parse_command_line_opts(struct conf_t *state, int argc, char **argv)
{
enum {
OPT_SNET_ALARMS = CHAR_MAX + 1,
OPT_WARN,
OPT_WARN = CHAR_MAX + 1,
OPT_CRIT,
OPT_MINSIZE,
OPT_WARN_COUNT,
OPT_CRIT_COUNT,
OPT_COLOR,
OPT_SKIP,
OPT_SET_IPV,
OPT_MUSTACH
OPT_MINSIZE
};
int ret_val;
/* Options for getopt_long */
static struct option const long_options[] = {
{"config", required_argument, NULL, 'c'},
{"leases", required_argument, NULL, 'l'},
{"color", required_argument, NULL, OPT_COLOR},
{"skip", required_argument, NULL, OPT_SKIP},
{"format", required_argument, NULL, 'f'},
{"sort", required_argument, NULL, 's'},
{"reverse", no_argument, NULL, 'r'},
{"output", required_argument, NULL, 'o'},
{"limit", required_argument, NULL, 'L'},
{"mustach", required_argument, NULL, OPT_MUSTACH},
{"version", no_argument, NULL, 'v'},
{"help", no_argument, NULL, 'h'},
{"snet-alarms", no_argument, NULL, OPT_SNET_ALARMS},
{"warning", required_argument, NULL, OPT_WARN},
{"critical", required_argument, NULL, OPT_CRIT},
{"warn-count", required_argument, NULL, OPT_WARN_COUNT},
{"crit-count", required_argument, NULL, OPT_CRIT_COUNT},
{"minsize", required_argument, NULL, OPT_MINSIZE},
{"perfdata", no_argument, NULL, 'p'},
{"all-as-shared", no_argument, NULL, 'A'},
{"ip-version", required_argument, NULL, OPT_SET_IPV},
{NULL, 0, NULL, 0}
};
int alarming = 0;
atexit(close_stdout);
set_program_name(argv[0]);
/* FIXME: These allocations should be fully dynamic, e.g., grow
* if needed. */
config.dhcpdconf_file = xmalloc(sizeof(char) * MAXLEN);
config.dhcpdlease_file = xmalloc(sizeof(char) * MAXLEN);
config.output_file = xmalloc(sizeof(char) * MAXLEN);
/* Make sure string has zero length if there is no
* command line option */
config.output_file[0] = '\0';
/* Alarming defaults. */
config.warning = ALARM_WARN;
config.critical = ALARM_CRIT;
/* File location defaults */
strncpy(config.dhcpdconf_file, DHCPDCONF_FILE, MAXLEN - 1);
strncpy(config.dhcpdlease_file, DHCPDLEASE_FILE, MAXLEN - 1);
tmp = OUTPUT_LIMIT;
config.output_limit[0] = (*tmp - '0');
tmp++;
config.output_limit[1] = (*tmp - '0');
config.fullhtml = false;
/* Make sure some output format is selected by default */
strncpy(config.output_format, OUTPUT_FORMAT, (size_t)1);
/* Default sort order is by IPs small to big */
config.reverse_order = false;
config.backups_found = false;
/* Parse command line options */
while (1) {
int c;
c = getopt_long(argc, argv, "c:l:f:o:s:rL:vh",
long_options, &option_index);
c = getopt_long(argc, argv, "c:l:f:o:s:rL:pAvh", long_options, NULL);
if (c == EOF)
break;
switch (c) {
case 'c':
/* config file */
state->dhcpdconf_file = optarg;
strncpy(config.dhcpdconf_file, optarg, MAXLEN - 1);
break;
case 'l':
/* lease file */
state->dhcpdlease_file = optarg;
strncpy(config.dhcpdlease_file, optarg, MAXLEN - 1);
break;
case 'f':
/* Output format */
state->output_format = optarg[0];
strncpy(config.output_format, optarg, (size_t)1);
break;
case 's':
{
/* Output sorting option */
struct output_sort *p = state->sorts;
char *ptr = optarg;
while (p && p->next)
p = p->next;
while (*ptr) {
if (state->sorts == NULL) {
state->sorts =
xcalloc(1, sizeof(struct output_sort));
p = state->sorts;
} else {
p->next = xcalloc(1, sizeof(struct output_sort));
p = p->next;
}
p->func = field_selector(*ptr++);
}
/* Output sorting option */
sorts = strlen(optarg);
if (5 < sorts) {
warnx
("main: only first 5 sort orders will be used");
strncpy(config.sort, optarg, (size_t)5);
sorts = 5;
} else {
strncpy(config.sort, optarg, (size_t)sorts);
}
for (i = 0; i < sorts; i++) {
field_selector(config.sort[i]);
}
break;
case 'r':
/* What ever sort in reverse order */
state->reverse_order = 1;
config.reverse_order = true;
break;
case 'o':
/* Output file */
state->output_file = optarg;
strncpy(config.output_file, optarg, MAXLEN - 1);
break;
case 'L':
/* Specification what will be printed */
state->header_limit = return_limit(optarg[0]);
state->number_limit = return_limit(optarg[1]);
break;
case OPT_MUSTACH:
#ifdef BUILD_MUSTACH
state->mustach_template = optarg;
state->output_format = 'm';
state->print_mac_addreses = 1;
#else
error(EXIT_FAILURE, 0, "compiled without mustach support");
#endif
break;
case OPT_COLOR:
state->color_mode = parse_color_mode(optarg);
if (state->color_mode == color_unknown)
error(EXIT_FAILURE, errno, "unknown color mode: %s", quote(optarg));
break;
case OPT_SKIP:
skip_arg_parse(state, optarg);
break;
case OPT_SNET_ALARMS:
state->snet_alarms = 1;
break;
case OPT_WARN:
alarming = 1;
state->warning = strtod_or_err(optarg, "illegal argument");
break;
case OPT_CRIT:
alarming = 1;
state->critical = strtod_or_err(optarg, "illegal argument");
break;
case OPT_WARN_COUNT:
alarming = 1;
state->warn_count = strtod_or_err(optarg, "illegal argument");
break;
case OPT_CRIT_COUNT:
alarming = 1;
state->crit_count = strtod_or_err(optarg, "illegal argument");
break;
case OPT_MINSIZE:
state->minsize = strtod_or_err(optarg, "illegal argument");
break;
case OPT_SET_IPV:
switch (optarg[0]) {
case '4':
set_ipv_functions(state, IPv4);
break;
case '6':
set_ipv_functions(state, IPv6);
break;
default:
error(EXIT_FAILURE, 0, "unknown --ip-version argument: %s", optarg);
for (i = 0; i < 2; i++) {
if (optarg[i] >= '0' && optarg[i] < '8') {
config.output_limit[i] =
optarg[i] - '0';
} else {
clean_up();
errx(EXIT_FAILURE,
"main: output mask `%s' is illegal",
optarg);
}
}
break;
case 'p':
/* Print additional performance data in alarming mode */
state->perfdata = 1;
case OPT_WARN:
strcpy(config.output_format, "a");
config.warning =
strtod_or_err(optarg, "illegal argument");
break;
case 'A':
/* Treat single networks as shared with network CIDR as name */
state->all_as_shared = 1;
case OPT_CRIT:
strcpy(config.output_format, "a");
config.critical =
strtod_or_err(optarg, "illegal argument");
break;
case OPT_MINSIZE:
config.minsize =
strtod_or_err(optarg, "illegal argument");
break;
case 'v':
/* Print version */
@ -293,76 +206,88 @@ static void parse_command_line_opts(struct conf_t *state, int argc, char **argv)
/* Print help */
usage(EXIT_SUCCESS);
default:
error(EXIT_FAILURE, 0, "Try %s --help for more information.", program_name);
errx(EXIT_FAILURE,
"Try `%s --help' for more information.",
program_name);
}
}
/* Use default dhcpd.conf when user did not define anything. */
if (state->dhcpdconf_file == NULL)
state->dhcpdconf_file = DHCPDCONF_FILE;
/* Use default dhcpd.leases when user did not define anything. */
if (state->dhcpdlease_file == NULL)
state->dhcpdlease_file = DHCPDLEASE_FILE;
/* Use default limits when user did not define anything. */
if (state->header_limit == 8) {
char const *default_limit = OUTPUT_LIMIT;
state->header_limit = return_limit(default_limit[0]);
state->number_limit = return_limit(default_limit[1]);
/* Output function selection */
switch (config.output_format[0]) {
case 't':
output_analysis = output_txt;
break;
case 'a':
output_analysis = output_alarming;
break;
case 'h':
output_analysis = output_html;
break;
case 'H':
output_analysis = output_html;
config.fullhtml = true;
break;
case 'x':
output_analysis = output_xml;
break;
case 'X':
output_analysis = output_xml;
break;
case 'j':
output_analysis = output_json;
break;
case 'J':
output_analysis = output_json;
break;
case 'c':
output_analysis = output_csv;
break;
default:
clean_up();
errx(EXIT_FAILURE, "main: unknown output format `%c'",
config.output_format[0]);
}
/* Output format is not defined, if alarm thresholds are then it's alarming, else use the
* default. */
if (state->output_format == '\0') {
if (alarming == 1)
state->output_format = 'a';
else {
const char *const default_format = OUTPUT_FORMAT;
state->output_format = default_format[0];
}
}
if (state->output_format == 'X' || state->output_format == 'J') {
state->print_mac_addreses = 1;
}
}
/*!\brief Start of execution. This will mostly call other functions one
* after another.
*
* \return Return value indicates success or fail or analysis, unless
* either --warning or --critical options are in use, which makes the
* return value in some cases to match with Nagios expectations about
* alarming. */
int main(int argc, char **argv)
{
struct conf_t state = {
.warning = ALARM_WARN,
.critical = ALARM_CRIT,
.warn_count = 0x100000000, /* == 2^32 that is the entire IPv4 space */
.crit_count = 0x100000000, /* basically turns off the count criteria */
.header_limit = 8,
.ranges_size = 64,
.ip_version = IPvUNKNOWN,
.color_mode = color_auto
};
int ret_val;
atexit(close_stdout);
set_program_name(argv[0]);
prepare_memory(&state);
set_ipv_functions(&state, IPvUNKNOWN);
parse_command_line_opts(&state, argc, argv);
/* Do the job */
parse_config(&state, 1, state.dhcpdconf_file, state.shared_net_root);
parse_leases(&state);
prepare_data(&state);
do_counting(&state);
if (state.sorts != NULL)
mergesort_ranges(&state, state.ranges, state.num_ranges, NULL, 1);
if (state.reverse_order == 1)
flip_ranges(&state);
ret_val = output_analysis(&state);
clean_up(&state);
prepare_memory();
set_ipv_functions(VERSION_UNKNOWN);
parse_config(true, config.dhcpdconf_file, shared_networks);
parse_leases();
prepare_data();
do_counting();
tmp_ranges = xmalloc(sizeof(struct range_t) * num_ranges);
if (sorts != 0) {
mergesort_ranges(ranges, num_ranges, tmp_ranges);
}
if (config.reverse_order == true) {
flip_ranges(ranges, tmp_ranges);
}
free(tmp_ranges);
ret_val = output_analysis();
clean_up();
return (ret_val);
}
/*! \brief Run time initialization. Global allocations, counter
* initializations, etc are here.
* FIXME: This function should return void. */
int prepare_memory(void)
{
config.dhcp_version = VERSION_UNKNOWN;
RANGES = 64;
num_ranges = num_shared_networks = 0;
shared_networks =
xmalloc(sizeof(struct shared_network_t) * SHARED_NETWORKS);
ranges = xmalloc(sizeof(struct range_t) * RANGES);
/* First shared network entry is all networks */
shared_networks->name = xstrdup("All networks");
shared_networks->used = 0;
shared_networks->touched = 0;
shared_networks->backups = 0;
return 0;
}

View file

@ -35,6 +35,8 @@
/*! \file dhcpd-pools.h
* \brief Global definitions of structures, enums, and function prototypes.
* FIXME: The file has too many global variables. Most of them should be
* removed, if not all.
*/
#ifndef DHCPD_POOLS_H
@ -42,6 +44,7 @@
# include <config.h>
# include <arpa/inet.h>
# include <stdbool.h>
# include <stddef.h>
# include <stdio.h>
# include <string.h>
@ -61,37 +64,23 @@
# define unlikely(x) (x)
# endif
/*! \def _DP_ATTRIBUTE_HOT
* \brief The function attribute __hot__ was added in gcc 4.3. See gnu
* documentation for further information.
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-hot-function-attribute
*/
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
# define _DP_ATTRIBUTE_HOT __attribute__ ((__hot__))
# else
# define _DP_ATTRIBUTE_HOT /* empty */
# endif
/*! \union ipaddr_t
* \brief Memory space for a binary IP address saving. */
union ipaddr_t {
uint32_t v4;
unsigned char v6[16];
};
/*! \enum dhcp_version
* \brief The IP version, IPv4 or IPv6, served by the dhcpd.
* \brief Indicator which IP version is in use.
*/
enum dhcp_version {
IPvUNKNOWN,
IPv4,
IPv6
VERSION_4,
VERSION_6,
VERSION_UNKNOWN
};
/*! \enum prefix_t
* \brief Enumeration of interesting data in dhcpd.leases file, that has to
* be further examined, and saved. Functions xstrstr_v4() and xstrstr_v6()
* return one of these values to parse_leases().
* \brief Enumeration of interesting data in dhcpd.leases file, that has
* to be further examined, and saved.
*/
enum prefix_t {
PREFIX_LEASE,
@ -102,25 +91,29 @@ enum prefix_t {
PREFIX_BINDING_STATE_ACTIVE,
PREFIX_BINDING_STATE_BACKUP,
PREFIX_HARDWARE_ETHERNET,
PREFIX_STARTS,
PREFIX_ENDS,
PREFIX_HOSTNAME,
NUM_OF_PREFIX
};
/*! \enum color_mode
* \brief Enumeration whether to use or not color output.
/*! \struct configuration_t
* \brief Runtime configuration.
*/
enum color_mode {
color_unknown,
color_off,
color_on,
color_auto /*!< Default, use colors when output terminal is interactive. */
struct configuration_t {
char dhcpv6;
enum dhcp_version dhcp_version;
char *dhcpdconf_file;
char *dhcpdlease_file;
char output_format[2];
bool fullhtml;
char sort[6];
bool reverse_order;
char *output_file;
int output_limit[2];
bool backups_found;
double warning;
double critical;
double minsize;
};
/*! \struct shared_network_t
* \brief Counters for an individual shared network. This data entry is
* also used for 'all networks' counting.
* \brief Counters for an individual shared network.
*/
struct shared_network_t {
char *name;
@ -128,10 +121,7 @@ struct shared_network_t {
double used;
double touched;
double backups;
struct shared_network_t *next;
int netmask;
};
/*! \struct range_t
* \brief Counters for an individual range.
*/
@ -143,230 +133,162 @@ struct range_t {
double touched;
double backups;
};
/*! \struct output_helper_t
* \brief Various per range and shared net temporary calculation results.
/*! \enum isc_conf_parser
* \brief Configuration file parsing state flags.
*/
struct output_helper_t {
double range_size;
double percent;
double tc;
double tcp;
double bup;
int status;
enum isc_conf_parser {
ITS_NOTHING_INTERESTING,
ITS_A_RANGE_FIRST_IP,
ITS_A_RANGE_SECOND_IP,
ITS_A_SHAREDNET,
ITS_AN_INCLUCE
};
/*! \struct status_counts_t
* \brief Range and shared network alarming status counts.
*/
struct status_counts_t {
unsigned int warning;
unsigned int critical;
unsigned int ok;
unsigned int ignored;
};
/*! \enum ltype
* \brief Lease state types. These are the possible values in struct leases_t.
* \brief Lease state types.
*/
enum ltype {
ACTIVE,
FREE,
BACKUP
};
/*! \struct leases_t
* \brief An individual lease. These leaases are hashed.
* \brief An individual lease. The leaases are hashed.
*/
struct leases_t {
union ipaddr_t ip; /* ip as key */
enum ltype type;
char *ethernet;
UT_hash_handle hh;
enum ltype type;
char *ends;
char *starts;
char *hostname;
};
/*! \enum limbits
* \brief Output limit bits.
* \brief Output limit bits
*/
enum limbits {
R_BIT = (1 << 0), /*!< Range limit. */
S_BIT = (1 << 1), /*!< Shared networks limit. */
A_BIT = (1 << 2) /*!< All networks summary limit. */
BIT1 = 0x1,
BIT2 = 0x2,
BIT3 = 0x4
};
/*! \def STATE_OK
* \brief Nagios alarm exit value.
*/
# define STATE_OK 0
# define STATE_WARNING 1
# define STATE_CRITICAL 2
/*! \var comparer_t
* \brief Function pointer holding sort algorithm.
*/
typedef int (*comparer_t) (struct range_t *r1, struct range_t *r2);
/*! \struct output_sort
* \brief Linked list of sort functions.
*/
struct output_sort {
comparer_t func;
struct output_sort *next;
};
/*! \struct conf_t
* \brief Runtime configuration state.
*/
struct conf_t {
struct shared_network_t *shared_net_root; /*!< First entry in shared network linked list, that is the 'all networks', */
struct shared_network_t *shared_net_head; /*!< Last entry in shared network linked list. */
struct range_t *ranges; /*!< Array of ranges. */
unsigned int num_ranges; /*!< Number of ranges in the ranges array. */
enum dhcp_version ip_version; /*!< Designator if the dhcpd is running in IPv4 or IPv6 mode. */
size_t ranges_size; /*!< Size of the ranges array. */
struct leases_t *leases; /*!< An array of individual leases from dhcpd.leases file. */
const char *dhcpdconf_file; /*!< Path to dhcpd.conf file. */
const char *dhcpdlease_file; /*!< Path to dhcpd.leases file. */
struct output_sort *sorts; /*!< Linked list how to sort ranges. */
const char *output_file; /*!< Output file path. */
const char *mustach_template; /*!< Mustach template file path. */
double warning; /*!< Warning percent threshold. */
double critical; /*!< Critical percent threshold. */
double warn_count; /*!< Maximum number of free IP's before warning. */
double crit_count; /*!< Maximum number of free IP's before critical. */
double minsize; /*!< Minimum size of range or shared network to be considered exceeding threshold. */
int color_format; /*!< Column to use in color_tags array. */
char output_format; /*!< Output format, such as text, json, xml, .... */
uint32_t
print_mac_addreses:1, /*!< Print mac address in xml or json. */
reverse_order:1, /*!< Reverse sort order. */
backups_found:1, /*!< Indicator if dhcpd.leases file has leases in backup state. */
snet_alarms:1, /*!< Suppress alarming thresholds for ranges that are part of a shared network. */
perfdata:1, /*!< Include performance statistics when using Nagios alarm output format. */
all_as_shared:1, /*!< Treat stand-alone subnets as a shared network. */
header_limit:4, /*!< Bits to suppress header output. */
number_limit:3, /*!< Bits to suppress value output. */
skip_ok:1, /*!< Skip none-alarming values from output. */
skip_warning:1, /*!< Skip warning values from output. */
skip_critical:1, /*!< Skip critical values from output. */
skip_minsize:1, /*!< Skip alarming values that are below minsize from output. */
skip_suppressed:1, /*!< Skip alarming values that are suppressed with --snet-alarms option, or they are shared networks without IP availability. */
color_mode:2; /*!< Indicator if colors should be used in output. */
};
/* Global variables */
/* \var prefix_length Length of each prefix. */
int prefix_length[2][NUM_OF_PREFIX];
/* \var config Runtime configuration. */
struct configuration_t config;
/* \var shared_networks Pointer holding shared network count results. */
struct shared_network_t *shared_networks;
/* \var num_shared_networks Number of shared networks found. */
unsigned int num_shared_networks;
/* \var ranges Pointer holding range count results. */
struct range_t *ranges;
/* \var num_ranges Number of ranges found. */
unsigned int num_ranges;
/* \var leases Pointer holding all leases. */
struct leases_t *leases;
/*! \var RANGES Maximum number of ranges. */
unsigned int RANGES;
/* Function prototypes */
/* analyze.c */
extern void prepare_data(struct conf_t *state);
extern void do_counting(struct conf_t *state);
/* getdata.c */
extern int parse_leases(struct conf_t *state);
extern void parse_config(struct conf_t *state, const int is_include,
const char *restrict config_file,
struct shared_network_t *restrict shared_p);
/* hash.c */
extern void (*add_lease) (struct conf_t *state, union ipaddr_t *addr, enum ltype type);
extern void add_lease_init(struct conf_t *state, union ipaddr_t *addr, enum ltype type);
extern void add_lease_v4(struct conf_t *state, union ipaddr_t *addr, enum ltype type);
extern void add_lease_v6(struct conf_t *state, union ipaddr_t *addr, enum ltype type);
extern struct leases_t *(*find_lease) (struct conf_t *state, union ipaddr_t *addr);
extern struct leases_t *find_lease_init(struct conf_t *state, union ipaddr_t *addr);
extern struct leases_t *find_lease_v4(struct conf_t *state, union ipaddr_t *addr);
extern struct leases_t *find_lease_v6(struct conf_t *state, union ipaddr_t *addr);
extern void delete_lease(struct conf_t *state, struct leases_t *lease);
extern void delete_all_leases(struct conf_t *state);
/* mustach-dhcpd-pools.c */
extern int mustach_dhcpd_pools(struct conf_t *state);
/* other.c */
extern void set_ipv_functions(struct conf_t *state, int version);
extern void flip_ranges(struct conf_t *state);
extern void clean_up(struct conf_t *state);
extern void parse_cidr(struct conf_t *state, struct range_t *range_p, const char *word);
extern int parse_color_mode(const char *restrict arg);
extern double strtod_or_err(const char *restrict str, const char *restrict errmesg);
extern void __attribute__ ((noreturn)) print_version(void);
extern void __attribute__ ((noreturn)) usage(int status);
extern void dp_time_tool(FILE *file, const char *path, int epoch);
extern int (*parse_ipaddr) (struct conf_t *state, const char *restrict src,
union ipaddr_t *restrict dst);
extern int parse_ipaddr_init(struct conf_t *state, const char *restrict src,
union ipaddr_t *restrict dst);
extern int parse_ipaddr_v4(struct conf_t *state, const char *restrict src,
union ipaddr_t *restrict dst);
extern int parse_ipaddr_v6(struct conf_t *state, const char *restrict src,
union ipaddr_t *restrict dst);
extern int (*xstrstr) (struct conf_t *state, const char *restrict str);
extern int xstrstr_init(struct conf_t *state, const char *restrict str);
extern int xstrstr_v4(struct conf_t *state, const char *restrict str);
extern int xstrstr_v6(struct conf_t *state, const char *restrict str);
extern void (*copy_ipaddr) (union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
extern void copy_ipaddr_init(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
extern void copy_ipaddr_v4(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
extern void copy_ipaddr_v6(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
extern const char *(*ntop_ipaddr) (const union ipaddr_t *ip);
extern const char *ntop_ipaddr_init(const union ipaddr_t *ip);
extern const char *ntop_ipaddr_v4(const union ipaddr_t *ip);
extern const char *ntop_ipaddr_v6(const union ipaddr_t *ip);
extern double (*get_range_size) (const struct range_t *r);
extern double get_range_size_init(const struct range_t *r);
extern double get_range_size_v4(const struct range_t *r);
extern double get_range_size_v6(const struct range_t *r);
/* output.c */
extern int range_output_helper(struct conf_t *state, struct output_helper_t *oh,
struct range_t *range_p);
extern int shnet_output_helper(struct conf_t *state, struct output_helper_t *oh,
struct shared_network_t *shared_p);
extern int output_analysis(struct conf_t *state);
extern void range_alarms(struct conf_t *state, struct status_counts_t *rangstat);
extern void shared_net_alarms(struct conf_t *state, struct status_counts_t *sharstat);
/* sort.c */
extern void mergesort_ranges(struct conf_t *state,
struct range_t *restrict orig, unsigned int size,
struct range_t *restrict temp, const int root_call);
extern int (*leasecomp) (const struct leases_t *restrict a, const struct leases_t *restrict b);
extern int leasecomp_init(const struct leases_t *restrict a
__attribute__ ((unused)),
const struct leases_t *restrict b __attribute__ ((unused)));
extern int leasecomp_v4(const struct leases_t *restrict a, const struct leases_t *restrict b);
extern int leasecomp_v6(const struct leases_t *restrict a, const struct leases_t *restrict b);
extern int (*ipcomp) (const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
extern int ipcomp_init(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
extern int ipcomp_v4(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
extern int ipcomp_v6(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
extern int rangecomp(const void *restrict r1, const void *restrict r2)
int prepare_memory(void);
void set_ipv_functions(int version);
int parse_leases(void);
void parse_config(int, const char *__restrict,
struct shared_network_t *__restrict)
__attribute__ ((nonnull(2, 3)));
int prepare_data(void);
int do_counting(void);
void flip_ranges(struct range_t *__restrict ranges,
struct range_t *__restrict tmp_ranges)
__attribute__ ((nonnull(1, 2)));
/* support functions */
int (*parse_ipaddr)(const char *restrict src, union ipaddr_t *restrict dst);
int parse_ipaddr_init(const char *restrict src, union ipaddr_t *restrict dst);
int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst);
int parse_ipaddr_v6(const char *restrict src, union ipaddr_t *restrict dst);
extern int comp_cur(struct range_t *r1, struct range_t *r2);
extern int comp_double(double f1, double f2);
extern int comp_ip(struct range_t *r1, struct range_t *r2);
extern int comp_max(struct range_t *r1, struct range_t *r2);
extern int comp_percent(struct range_t *r1, struct range_t *r2);
extern int comp_tc(struct range_t *r1, struct range_t *r2);
extern int comp_tcperc(struct range_t *r1, struct range_t *r2);
extern int comp_touched(struct range_t *r1, struct range_t *r2);
void (*copy_ipaddr)(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
void copy_ipaddr_init(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
void copy_ipaddr_v4(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
void copy_ipaddr_v6(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src);
extern comparer_t field_selector(char c);
extern double ret_percent(struct range_t r);
extern double ret_tc(struct range_t r);
extern double ret_tcperc(struct range_t r);
const char *(*ntop_ipaddr)(const union ipaddr_t *ip);
const char *ntop_ipaddr_init(const union ipaddr_t *ip);
const char *ntop_ipaddr_v4(const union ipaddr_t *ip);
const char *ntop_ipaddr_v6(const union ipaddr_t *ip);
#endif /* DHCPD_POOLS_H */
double (*get_range_size)(const struct range_t *r);
double get_range_size_init(const struct range_t *r);
double get_range_size_v4(const struct range_t *r);
double get_range_size_v6(const struct range_t *r);
int (*xstrstr)(const char *__restrict str);
int xstrstr_init(const char *__restrict str)
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((__hot__))
# endif
;
int xstrstr_v4(const char *__restrict str)
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((__hot__))
# endif
;
int xstrstr_v6(const char *__restrict str)
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((__hot__))
# endif
;
double strtod_or_err(const char *__restrict str,
const char *__restrict errmesg);
void print_version(void) __attribute__ ((noreturn));
void usage(int status) __attribute__ ((noreturn));
/* qsort required functions... */
/* ...for ranges and... */
int (*ipcomp)(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
int ipcomp_init(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
int ipcomp_v4(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
int ipcomp_v6(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b);
int comp_cur(struct range_t *r1, struct range_t *r2);
int comp_double(double f1, double f2);
int comp_ip(struct range_t *r1, struct range_t *r2);
int comp_max(struct range_t *r1, struct range_t *r2);
int comp_percent(struct range_t *r1, struct range_t *r2);
int comp_tc(struct range_t *r1, struct range_t *r2);
int comp_tcperc(struct range_t *r1, struct range_t *r2);
int comp_touched(struct range_t *r1, struct range_t *r2);
int rangecomp(const void *__restrict r1, const void *__restrict r2)
__attribute__ ((nonnull(1, 2)));
/* sort function pointer and functions */
typedef int (*comparer_t) (struct range_t *r1, struct range_t *r2);
comparer_t field_selector(char c);
double ret_percent(struct range_t r);
double ret_tc(struct range_t r);
double ret_tcperc(struct range_t r);
void mergesort_ranges(struct range_t *__restrict orig, int size,
struct range_t *__restrict temp)
__attribute__ ((nonnull(1, 3)));
/* output function pointer and functions */
int (*output_analysis) (void);
int output_txt(void);
int output_html(void);
int output_xml(void);
int output_json(void);
int output_csv(void);
int output_alarming(void);
/* Memory release, file closing etc */
void clean_up(void);
/* Hash functions */
void (*add_lease)(union ipaddr_t *ip, enum ltype type);
void add_lease_init(union ipaddr_t *ip, enum ltype type);
void add_lease_v4(union ipaddr_t *ip, enum ltype type);
void add_lease_v6(union ipaddr_t *ip, enum ltype type);
struct leases_t *(*find_lease)(union ipaddr_t *ip);
struct leases_t *find_lease_init(union ipaddr_t *ip);
struct leases_t *find_lease_v4(union ipaddr_t *ip);
struct leases_t *find_lease_v6(union ipaddr_t *ip);
void delete_lease(struct leases_t *lease);
void delete_all_leases(void);
#endif /* DHCPD_POOLS_H */

View file

@ -40,143 +40,117 @@
#include <config.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include "error.h"
#include "xalloc.h"
#include "defaults.h"
#include "dhcpd-pools.h"
/*! \enum dhcpd_magic_numbers
* \brief MAXLEN is maximum expected line length in dhcpd.conf and
* dhcpd.leases.
*/
enum dhcpd_magic_numbers {
MAXLEN = 1024
};
/*! \enum isc_conf_parser
* \brief Configuration file parsing state flags. The
* is_interesting_config_clause() will return one of these to parse_config().
*/
enum isc_conf_parser {
ITS_NOTHING_INTERESTING,
ITS_A_RANGE_FIRST_IP,
ITS_A_RANGE_SECOND_IP,
ITS_A_SHAREDNET,
ITS_AN_INCLUDE,
ITS_A_SUBNET,
ITS_A_NETMASK
};
#include "xalloc.h"
/*! \brief Lease file parser. The parser can only read ISC DHCPD
* dhcpd.leases file format. */
int parse_leases(struct conf_t *state)
int parse_leases(void)
{
FILE *dhcpd_leases;
char *line, *ipstring, macstring[20], *stop, endsstr[30], startsstr[30], hostnamestr[MAXLEN];
char *line, *ipstring, macstring[20], *stop;
union ipaddr_t addr;
struct stat lease_file_stats;
bool ethernets = false;
struct leases_t *lease;
dhcpd_leases = fopen(state->dhcpdlease_file, "r");
if (dhcpd_leases == NULL)
error(EXIT_FAILURE, errno, "parse_leases: %s", state->dhcpdlease_file);
dhcpd_leases = fopen(config.dhcpdlease_file, "r");
if (dhcpd_leases == NULL) {
err(EXIT_FAILURE, "parse_leases: %s", config.dhcpdlease_file);
}
#ifdef HAVE_POSIX_FADVISE
# ifdef POSIX_FADV_NOREUSE
if (posix_fadvise(fileno(dhcpd_leases), 0, 0, POSIX_FADV_NOREUSE) != 0) {
err(EXIT_FAILURE, "parse_leases: fadvise %s",
config.dhcpdlease_file);
}
# endif /* POSIX_FADV_NOREUSE */
# ifdef POSIX_FADV_SEQUENTIAL
if (posix_fadvise(fileno(dhcpd_leases), 0, 0, POSIX_FADV_SEQUENTIAL) != 0)
error(EXIT_FAILURE, errno, "parse_leases: fadvise %s", state->dhcpdlease_file);
if (posix_fadvise(fileno(dhcpd_leases), 0, 0, POSIX_FADV_SEQUENTIAL) != 0) {
err(EXIT_FAILURE, "parse_leases: fadvise %s",
config.dhcpdlease_file);
}
# endif /* POSIX_FADV_SEQUENTIAL */
#endif /* HAVE_POSIX_FADVISE */
/* I found out that there's one lease address per 300 bytes in
* dhcpd.leases file. Malloc is little bit pessimistic and uses 250.
* If someone has higher density in lease file I'm interested to
* hear about that. */
if (stat(config.dhcpdlease_file, &lease_file_stats)) {
err(EXIT_FAILURE, "parse_leases: %s", config.dhcpdlease_file);
}
line = xmalloc(sizeof(char) * MAXLEN);
line[0] = '\0';
ipstring = xmalloc(sizeof(char) * MAXLEN);
ipstring[0] = '\0';
endsstr[0] = '\0';
startsstr[0] = '\0';
hostnamestr[0] = '\0';
if (config.output_format[0] == 'X' || config.output_format[0] == 'J') {
ethernets = true;
}
while (!feof(dhcpd_leases)) {
if (!fgets(line, MAXLEN, dhcpd_leases) && ferror(dhcpd_leases))
error(EXIT_FAILURE, errno, "parse_leases: %s", state->dhcpdlease_file);
switch (xstrstr(state, line)) {
/* It's a lease, save IP */
if (!fgets(line, MAXLEN, dhcpd_leases) && ferror(dhcpd_leases)) {
err(EXIT_FAILURE, "parse_leases: %s",
config.dhcpdlease_file);
}
switch(xstrstr(line)) {
/* It's a lease, save IP */
case PREFIX_LEASE:
stop =
memccpy(ipstring,
line + (state->ip_version ==
IPv4 ? 6 : 9), ' ', strlen(line));
stop = memccpy(ipstring, line + (config.dhcp_version == VERSION_4 ? 6 : 9), ' ', strlen(line));
if (stop != NULL) {
--stop;
*stop = '\0';
}
parse_ipaddr(state, ipstring, &addr);
parse_ipaddr(ipstring, &addr);
break;
case PREFIX_BINDING_STATE_FREE:
case PREFIX_BINDING_STATE_ABANDONED:
case PREFIX_BINDING_STATE_EXPIRED:
case PREFIX_BINDING_STATE_RELEASED:
if ((lease = find_lease(state, &addr)) != NULL)
delete_lease(state, lease);
add_lease(state, &addr, FREE);
if ((lease = find_lease(&addr)) != NULL) {
delete_lease(lease);
}
add_lease(&addr, FREE);
break;
case PREFIX_BINDING_STATE_ACTIVE:
/* remove old entry, if exists */
if ((lease = find_lease(state, &addr)) != NULL)
delete_lease(state, lease);
add_lease(state, &addr, ACTIVE);
if ((lease = find_lease(&addr)) != NULL) {
delete_lease(lease);
}
add_lease(&addr, ACTIVE);
break;
case PREFIX_BINDING_STATE_BACKUP:
/* remove old entry, if exists */
if ((lease = find_lease(state, &addr)) != NULL)
delete_lease(state, lease);
add_lease(state, &addr, BACKUP);
state->backups_found = 1;
if ((lease = find_lease(&addr)) != NULL) {
delete_lease(lease);
}
add_lease(&addr, BACKUP);
config.backups_found = true;
break;
case PREFIX_HARDWARE_ETHERNET:
if (state->print_mac_addreses == 0)
if (ethernets == false)
break;
memcpy(macstring, line + 20, 17);
macstring[17] = '\0';
if ((lease = find_lease(state, &addr)) != NULL) {
if ((lease = find_lease(&addr)) != NULL) {
lease->ethernet = xstrdup(macstring);
lease->starts = xstrdup(startsstr);
startsstr[0] = '\0';
lease->ends = xstrdup(endsstr);
endsstr[0] = '\0';
}
break;
case PREFIX_ENDS:
if (state->print_mac_addreses == 0)
break;
strncpy(endsstr, line + 7, sizeof(endsstr)-1);
endsstr[strlen(endsstr)-2] = '\0';
break;
case PREFIX_STARTS:
if (state->print_mac_addreses == 0)
break;
strncpy(startsstr, line + 9, sizeof(startsstr)-1);
startsstr[strlen(startsstr)-2] = '\0';
break;
case PREFIX_HOSTNAME:
if (state->print_mac_addreses == 0)
break;
strncpy(hostnamestr, line + 19, sizeof(hostnamestr)-1);
hostnamestr[strlen(hostnamestr)-3] = '\0';
if ((lease = find_lease(state, &addr)) != NULL) {
lease->hostname = xstrdup(hostnamestr);
}
hostnamestr[0] = '\0';
break;
default:
/* do nothing */ ;
/* do nothing */;
}
}
#undef HAS_PREFIX
@ -189,88 +163,70 @@ int parse_leases(struct conf_t *state)
/*! \brief Keyword search in dhcpd.conf file.
* \param s A line from the dhcpd.conf file.
* \return Indicator what configuration was found. */
static int is_interesting_config_clause(struct conf_t *state, char const *restrict s)
static int is_interesting_config_clause(char const *restrict s)
{
if (strstr(s, "range"))
return ITS_A_RANGE_FIRST_IP;
if (strstr(s, "shared-network"))
return ITS_A_SHAREDNET;
if (state->all_as_shared) {
if (strstr(s, "subnet"))
return ITS_A_SUBNET;
if (strstr(s, "netmask"))
return ITS_A_NETMASK;
}
if (strstr(s, "include"))
return ITS_AN_INCLUDE;
return ITS_AN_INCLUCE;
return ITS_NOTHING_INTERESTING;
}
/*! \brief Flip first and last IP in range if they are in unusual order.
*/
static void reorder_last_first(struct range_t *range_p)
{
if (ipcomp(&range_p->first_ip, &range_p->last_ip) > 0) {
union ipaddr_t tmp;
tmp = range_p->first_ip;
range_p->first_ip = range_p->last_ip;
range_p->last_ip = tmp;
}
}
/*! \brief The dhcpd.conf file parser.
* FIXME: This spaghetti monster function needs to be rewrote at least
* ones more.
* FIXME: This spaghetti monster function need to be rewrote at least
* ones.
*/
void parse_config(struct conf_t *state, const int is_include, const char *restrict config_file,
void parse_config(int is_include, const char *restrict config_file,
struct shared_network_t *restrict shared_p)
{
FILE *dhcpd_config;
int newclause = 1, comment = 0, one_ip_range = 0; /* booleans */
bool newclause = true, comment = false, one_ip_range = false;
int quote = 0, braces = 0, argument = ITS_NOTHING_INTERESTING;
size_t i = 0;
char *word;
int braces_shared = 1000;
union ipaddr_t addr;
struct range_t *range_p = NULL;
struct range_t *range_p;
word = xmalloc(sizeof(char) * MAXLEN);
if (is_include)
if (is_include) {
/* Default place holder for ranges "All networks". */
shared_p->name = state->shared_net_root->name;
shared_p->name = shared_networks->name;
}
/* Open configuration file */
dhcpd_config = fopen(config_file, "r");
if (dhcpd_config == NULL) {
if (is_include) {
error(0, errno, "cannot open inlude: %s", config_file);
return;
}
/* config if from command line, just exit with error */
error(EXIT_FAILURE, errno, "parse_config: %s", config_file);
err(EXIT_FAILURE, "parse_config: %s", config_file);
}
#ifdef HAVE_POSIX_FADVISE
# ifdef POSIX_FADV_SEQUENTIAL
if (posix_fadvise(fileno(dhcpd_config), 0, 0, POSIX_FADV_SEQUENTIAL) != 0)
error(EXIT_FAILURE, errno, "parse_config: fadvise %s", config_file);
# endif /* POSIX_FADV_SEQUENTIAL */
#endif /* HAVE_POSIX_FADVISE */
#ifdef POSIX_FADV_NOREUSE
if (posix_fadvise(fileno(dhcpd_config), 0, 0, POSIX_FADV_NOREUSE) != 0) {
err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
}
#endif /* POSIX_FADV_NOREUSE */
#ifdef POSIX_FADV_SEQUENTIAL
if (posix_fadvise(fileno(dhcpd_config), 0, 0, POSIX_FADV_SEQUENTIAL) != 0) {
err(EXIT_FAILURE, "parse_config: fadvise %s", config_file);
}
#endif /* POSIX_FADV_SEQUENTIAL */
/* Very hairy stuff begins. */
while (unlikely(!feof(dhcpd_config))) {
int c;
char c;
c = fgetc(dhcpd_config);
if (CHAR_MAX < c)
continue;
/* Certain characters are magical */
switch (c) {
/* Handle comments if they are not quoted */
case '#':
if (quote == 0)
comment = 1;
if (quote == 0) {
comment = true;
}
continue;
case '"':
if (comment == 0) {
if (comment == false) {
quote++;
/* Either one or zero */
quote = quote % 2;
@ -279,19 +235,22 @@ void parse_config(struct conf_t *state, const int is_include, const char *restri
case '\n':
/* New line resets comment section, but
* not if quoted */
if (quote == 0)
comment = 0;
if (quote == 0) {
comment = false;
}
break;
case ';':
/* Quoted colon does not mean new clause */
if (0 < quote)
if (0 < quote) {
break;
if (comment == 0
}
if (comment == false
&& argument != ITS_A_RANGE_FIRST_IP
&& argument != ITS_A_RANGE_SECOND_IP && argument != ITS_AN_INCLUDE) {
newclause = 1;
&& argument != ITS_A_RANGE_SECOND_IP
&& argument != ITS_AN_INCLUCE) {
newclause = true;
i = 0;
} else if (argument == ITS_A_RANGE_FIRST_IP && one_ip_range == 1) {
} else if (argument == ITS_A_RANGE_FIRST_IP && one_ip_range == true) {
argument = ITS_A_RANGE_SECOND_IP;
c = ' ';
} else if (argument == ITS_A_RANGE_SECOND_IP && 0 < i) {
@ -302,178 +261,165 @@ void parse_config(struct conf_t *state, const int is_include, const char *restri
*
* ...to be interpreted correctly. */
c = ' ';
break;
} else if (argument == ITS_A_RANGE_SECOND_IP && i == 0) {
if (!range_p) {
long int pos;
pos = ftell(dhcpd_config);
error(EXIT_FAILURE, 0, "parse_config: parsing failed at position: %ld", pos);
}
range_p->last_ip = range_p->first_ip;
goto newrange;
}
continue;
case '{':
if (0 < quote)
if (0 < quote) {
break;
if (comment == 0)
}
if (comment == 0) {
braces++;
}
/* i == 0 detects word that ends to brace like:
*
* shared-network DSL{ ... */
if (i == 0) {
newclause = 1;
newclause = true;
continue;
}
break;
case '}':
if (0 < quote)
} else {
break;
if (comment == 0) {
}
case '}':
if (0 < quote) {
break;
}
if (comment == false) {
braces--;
/* End of shared-network */
if (braces_shared == braces) {
/* FIXME: Using 1000 is lame, but
* works. */
braces_shared = 1000;
shared_p = state->shared_net_root;
shared_p = shared_networks;
}
/* Not literally 1, but works for this
/* Not literally true, but works for this
* program */
newclause = 1;
newclause = true;
}
continue;
default:
break;
}
/* Either inside comment or Nth word of clause. */
if (comment == 1 || (newclause == 0 && argument == ITS_NOTHING_INTERESTING))
if (comment == true
|| (newclause == false
&& argument == ITS_NOTHING_INTERESTING)) {
continue;
}
/* Strip white spaces before new clause word. */
if ((newclause == 1 || argument != ITS_NOTHING_INTERESTING)
&& isspace(c) && i == 0 && one_ip_range == 0)
if ((newclause == true || argument != ITS_NOTHING_INTERESTING)
&& isspace(c) && i == 0 && one_ip_range == false) {
continue;
}
/* Save to word which clause this is. */
if ((newclause == 1 || argument != ITS_NOTHING_INTERESTING)
if ((newclause == true || argument != ITS_NOTHING_INTERESTING)
&& (!isspace(c) || 0 < quote)) {
word[i] = (char) c;
word[i] = c;
i++;
/* Long word which is almost causing overflow. None
* of words are this long which the program is
* searching. */
if (MAXLEN == i) {
newclause = 0;
if (MAXLEN < i) {
newclause = false;
i = 0;
continue;
}
}
/* See if clause is something that parser is looking for. */
else if (newclause == 1) {
else if (newclause == true) {
/* Insert string end & set state */
word[i] = '\0';
if (word[i - 1] != '{')
newclause = 0;
if (word[i - 1] != '{') {
newclause = false;
}
i = 0;
argument = is_interesting_config_clause(state, word);
if (argument == ITS_A_RANGE_FIRST_IP)
one_ip_range = 1;
argument = is_interesting_config_clause(word);
if (argument == ITS_A_RANGE_FIRST_IP) {
one_ip_range = true;
}
}
/* words after range, shared-network or include */
else if (argument != ITS_NOTHING_INTERESTING) {
word[i] = '\0';
newclause = 0;
newclause = false;
i = 0;
switch (argument) {
case ITS_A_RANGE_SECOND_IP:
/* printf ("range 2nd ip: %s\n", word); */
range_p = state->ranges + state->num_ranges;
range_p = ranges + num_ranges;
argument = ITS_NOTHING_INTERESTING;
if (strchr(word, '/')) {
parse_cidr(state, range_p, word);
one_ip_range = 0;
} else {
/* not cidr */
parse_ipaddr(state, word, &addr);
if (one_ip_range == 1) {
one_ip_range = 0;
copy_ipaddr(&range_p->first_ip, &addr);
}
copy_ipaddr(&range_p->last_ip, &addr);
reorder_last_first(range_p);
parse_ipaddr(word, &addr);
if (one_ip_range == true) {
one_ip_range = false;
copy_ipaddr(&range_p->first_ip, &addr);
}
copy_ipaddr(&range_p->last_ip, &addr);
newrange:
range_p->count = 0;
range_p->touched = 0;
range_p->backups = 0;
range_p->shared_net = shared_p;
state->num_ranges++;
if (state->ranges_size <= state->num_ranges) {
state->ranges_size *= 2;
state->ranges = xrealloc(state->ranges, sizeof(struct range_t) * state->ranges_size);
range_p = state->ranges + state->num_ranges;
num_ranges++;
if (RANGES < num_ranges + 1) {
RANGES *= 2;
ranges =
xrealloc(ranges,
sizeof(struct
range_t) * RANGES);
range_p = ranges + num_ranges;
}
newclause = 1;
newclause = true;
break;
case ITS_A_RANGE_FIRST_IP:
/* printf ("range 1st ip: %s\n", word); */
range_p = state->ranges + state->num_ranges;
if (!(parse_ipaddr(state, word, &addr)))
/* word was not ip, try again */
/* printf ("range 1nd ip: %s\n", word); */
range_p = ranges + num_ranges;
if (!(parse_ipaddr(word, &addr))) {
/* word was not ip, try
* again */
break;
}
copy_ipaddr(&range_p->first_ip, &addr);
one_ip_range = 0;
one_ip_range = false;
argument = ITS_A_RANGE_SECOND_IP;
break;
case ITS_A_SHAREDNET:
case ITS_A_SUBNET:
/* ignore subnets inside a shared-network */
if (argument == ITS_A_SUBNET && shared_p != state->shared_net_root) {
argument = ITS_NOTHING_INTERESTING;
break;
}
state->shared_net_head->next = xcalloc(sizeof(struct shared_network_t), 1);
state->shared_net_head = state->shared_net_head->next;
shared_p = state->shared_net_head;
/* printf ("shared-network named: %s\n", word); */
num_shared_networks++;
shared_p =
shared_networks + num_shared_networks;
shared_p->name = xstrdup(word);
shared_p->netmask = (argument == ITS_A_SUBNET ? -1 : 0); /* do not fill in netmask */
/* record network's mask too */
if (argument == ITS_A_SUBNET)
newclause = 1;
argument = ITS_NOTHING_INTERESTING;
braces_shared = braces;
break;
case ITS_A_NETMASK:
/* fill in only when requested to do so */
if (shared_p->netmask) {
if (!(parse_ipaddr(state, word, &addr)))
break;
shared_p->netmask = 32;
while ((addr.v4 & 0x01) == 0) {
addr.v4 >>= 1;
shared_p->netmask--;
}
snprintf(word, MAXLEN-1, "%s/%d", shared_p->name, shared_p->netmask);
if (shared_p->name)
free(shared_p->name);
shared_p->name = xstrdup(word);
shared_p->available = 0;
shared_p->used = 0;
shared_p->touched = 0;
shared_p->backups = 0;
if (SHARED_NETWORKS < num_shared_networks + 2) {
/* FIXME: make this
* away by reallocating
* more space. */
errx(EXIT_FAILURE,
"parse_config: increase default.h SHARED_NETWORKS and recompile");
}
argument = ITS_NOTHING_INTERESTING;
braces_shared = braces;
break;
case ITS_AN_INCLUDE:
case ITS_AN_INCLUCE:
/* printf ("include file: %s\n", word); */
argument = ITS_NOTHING_INTERESTING;
parse_config(state, 0, word, shared_p);
newclause = 1;
parse_config(false, word, shared_p);
newclause = true;
break;
case ITS_NOTHING_INTERESTING:
/* printf ("nothing interesting: %s\n", word); */
argument = ITS_NOTHING_INTERESTING;
break;
default:
puts("impossible occurred, report a bug");
abort();
warnx("impossible occurred, report a bug");
assert(0);
}
}
}

View file

@ -38,13 +38,8 @@
* analysis happen as quick as possible..
*/
#include <config.h>
#include <stdlib.h>
#include "xalloc.h"
#include "dhcpd-pools.h"
#include "xalloc.h"
#define HASH_FIND_V6(head, findv6, out) HASH_FIND(hh, head, findv6, 16, out)
#define HASH_ADD_V6(head, v6field, add) HASH_ADD(hh, head, v6field, 16, add)
@ -52,104 +47,81 @@
/*! \brief Add a lease to hash array.
* \param addr Binary IP to be added in leases hash.
* \param type Lease state of the IP. */
void add_lease_init(struct conf_t *state __attribute__ ((unused)), union ipaddr_t *addr
__attribute__ ((unused)), enum ltype type __attribute__ ((unused)))
void add_lease_init(union ipaddr_t *addr __attribute__((unused)), enum ltype type __attribute__((unused)))
{
}
void add_lease_v4(struct conf_t *state, union ipaddr_t *addr, enum ltype type)
void add_lease_v4(union ipaddr_t *addr, enum ltype type)
{
struct leases_t *l;
l = xmalloc(sizeof(struct leases_t));
copy_ipaddr(&l->ip, addr);
l->type = type;
HASH_ADD_INT(state->leases, ip.v4, l);
HASH_ADD_INT(leases, ip.v4, l);
l->ethernet = NULL;
l->ends = NULL;
l->starts = NULL;
l->hostname = NULL;
}
void add_lease_v6(struct conf_t *state, union ipaddr_t *addr, enum ltype type)
void add_lease_v6(union ipaddr_t *addr, enum ltype type)
{
struct leases_t *l;
l = xmalloc(sizeof(struct leases_t));
copy_ipaddr(&l->ip, addr);
l->type = type;
HASH_ADD_V6(state->leases, ip.v6, l);
HASH_ADD_V6(leases, ip.v6, l);
l->ethernet = NULL;
l->ends = NULL;
l->starts = NULL;
l->hostname = NULL;
}
/*! \brief Find pointer to lease from hash array.
* \param addr Binary IP searched from leases hash.
* \return A lease structure about requested IP, or NULL.
*/
struct leases_t *find_lease_init(struct conf_t *state __attribute__ ((unused)), union ipaddr_t *addr
__attribute__ ((unused)))
struct leases_t *find_lease_init(union ipaddr_t *addr __attribute__((unused)))
{
return NULL;
}
struct leases_t *find_lease_v4(struct conf_t *state, union ipaddr_t *addr)
struct leases_t *find_lease_v4(union ipaddr_t *addr)
{
struct leases_t *l;
HASH_FIND_INT(state->leases, &addr->v4, l);
HASH_FIND_INT(leases, &addr->v4, l);
return l;
}
struct leases_t *find_lease_v6(struct conf_t *state, union ipaddr_t *addr)
struct leases_t *find_lease_v6(union ipaddr_t *addr)
{
struct leases_t *l;
HASH_FIND_V6(state->leases, &addr->v4, l);
HASH_FIND_V6(leases, &addr->v4, l);
return l;
}
/*! \brief Delete a lease from hash array.
* \param lease Pointer to lease hash. */
void delete_lease(struct conf_t *state, struct leases_t *lease)
void delete_lease(struct leases_t *lease)
{
free(lease->ethernet);
free(lease->ends);
free(lease->starts);
free(lease->hostname);
HASH_DEL(state->leases, lease);
HASH_DEL(leases, lease);
free(lease);
}
/*! \brief Delete all leases from hash array. */
#ifdef HASH_ITER
void delete_all_leases(struct conf_t *state)
void delete_all_leases(void)
{
struct leases_t *l, *tmp;
HASH_ITER(hh, state->leases, l, tmp) {
HASH_ITER(hh, leases, l, tmp) {
free(l->ethernet);
free(l->ends);
free(l->starts);
free(l->hostname);
HASH_DEL(state->leases, l);
HASH_DEL(leases, l);
free(l);
}
}
#else
void delete_all_leases(struct conf_t *state)
void delete_all_leases(void)
{
while (state->leases) {
while (leases) {
struct leases_t *l;
l = state->leases;
l = leases;
free(l->ethernet);
free(l->ends);
free(l->starts);
free(l->hostname);
HASH_DEL(state->leases, l); /* leases advances to next on delete */
HASH_DEL(leases, l); /* leases advances to next on delete */
free(l);
}
}

View file

@ -1,519 +0,0 @@
/*
* The dhcpd-pools has BSD 2-clause license which also known as "Simplified
* BSD License" or "FreeBSD License".
*
* Copyright 2006- Sami Kerola. 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.
*/
/*! \file mustach-dhcpd-pools.c
* \brief Mustache templating specific functions.
*/
#include <config.h>
#include <fcntl.h>
#include <errno.h>
#include <error.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include "close-stream.h"
#include "dhcpd-pools.h"
#include "error.h"
#include "mustach.h"
#include "xalloc.h"
/*! \struct expl
* \brief A structure that travels through mustach via closure void pointer.
*/
struct expl {
struct conf_t *state;
struct leases_t *lease_p;
struct range_t *range_p;
struct shared_network_t *shnet_p;
struct output_helper_t oh;
int current;
uint32_t pad;
};
static int must_enter(void *closure, const char *name);
static int must_leave(void *closure);
/*! \brief Template base level tag parser and printer. */
static int must_put_base(void *closure, const char *name, int escape
__attribute__ ((unused)), FILE *file)
{
struct expl *e = closure;
if (!strcmp(name, "localtime")) {
dp_time_tool(file, NULL, 0);
return 0;
}
if (!strcmp(name, "number_of_ranges")) {
fprintf(file, "%u", e->state->num_ranges);
return 0;
}
if (!strcmp(name, "number_of_ranges_warning")) {
struct status_counts_t stat = { 0 };
range_alarms(e->state, &stat);
fprintf(file, "%u", stat.warning);
return 0;
}
if (!strcmp(name, "number_of_ranges_critical")) {
struct status_counts_t stat = { 0 };
range_alarms(e->state, &stat);
fprintf(file, "%u", stat.critical);
return 0;
}
if (!strcmp(name, "number_of_shared_networks")) {
uint32_t num = 0;
struct shared_network_t *shared_p;
for (shared_p = e->state->shared_net_root->next; shared_p;
shared_p = shared_p->next) {
num++;
}
fprintf(file, "%u", num);
return 0;
}
if (!strcmp(name, "number_of_shared_networks_warning")) {
struct status_counts_t stat = { 0 };
shared_net_alarms(e->state, &stat);
fprintf(file, "%u", stat.warning);
return 0;
}
if (!strcmp(name, "number_of_shared_networks_critical")) {
struct status_counts_t stat = { 0 };
shared_net_alarms(e->state, &stat);
fprintf(file, "%u", stat.critical);
return 0;
}
if (!strcmp(name, "version")) {
fprintf(file, "%s", PACKAGE_VERSION);
return 0;
}
/* lease file */
if (!strcmp(name, "lease_file_path")) {
fprintf(file, "%s", e->state->dhcpdlease_file);
return 0;
}
if (!strcmp(name, "lease_file_local_mtime")) {
dp_time_tool(file, e->state->dhcpdlease_file, 0);
return 0;
}
if (!strcmp(name, "lease_file_epoch_mtime")) {
dp_time_tool(file, e->state->dhcpdlease_file, 1);
return 0;
}
/* conf file */
if (!strcmp(name, "conf_file_path")) {
fprintf(file, "%s", e->state->dhcpdconf_file);
return 0;
}
if (!strcmp(name, "conf_file_local_mtime")) {
dp_time_tool(file, e->state->dhcpdconf_file, 0);
return 0;
}
if (!strcmp(name, "conf_file_epoch_mtime")) {
dp_time_tool(file, e->state->dhcpdconf_file, 1);
return 0;
}
/* template file */
if (!strcmp(name, "template_file_path")) {
fprintf(file, "%s", e->state->mustach_template);
return 0;
}
if (!strcmp(name, "template_file_local_mtime")) {
dp_time_tool(file, e->state->mustach_template, 0);
return 0;
}
if (!strcmp(name, "template_file_epoch_mtime")) {
dp_time_tool(file, e->state->mustach_template, 1);
return 0;
}
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unexpected tag: %s", name);
return 1;
}
/*! \struct mustach_itf
* \brief Mustach function pointers. */
static struct mustach_itf itf = {
.start = NULL,
.enter = must_enter,
.put = must_put_base,
.next = NULL,
.leave = must_leave
};
/*! \brief Mustach active lease aka {{#active_lease}} tag parser and printer. */
static int must_put_active_lease(void *closure, const char *name, int escape
__attribute__((unused)), FILE *file)
{
struct expl *e = closure;
if (!strcmp(name, "ip")) {
fprintf(file, "%s", ntop_ipaddr(&e->lease_p->ip));
return 0;
}
if (!strcmp(name, "macaddress")) {
fprintf(file, "%s", e->lease_p->ethernet);
return 0;
}
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unexpected tag: %s", name);
return 1;
}
/*! \brief A function to move to next lease when {{/active_lease}} is encountered. */
static int must_next_active_lease(void *closure)
{
struct expl *e = closure;
e->lease_p = e->lease_p->hh.next;
if (e->lease_p == NULL)
return 0;
return 1;
}
/*! \brief Mustach range aka {{#subnets}} tag parser and printer. */
static int must_put_range(void *closure, const char *name, int escape
__attribute__ ((unused)), FILE *file)
{
struct expl *e = closure;
if (!strcmp(name, "location")) {
fprintf(file, "%s", e->range_p->shared_net->name);
return 0;
}
if (!strcmp(name, "range")) {
fprintf(file, "%s - ", ntop_ipaddr(&e->range_p->first_ip));
fprintf(file, "%s", ntop_ipaddr(&e->range_p->last_ip));
return 0;
}
if (!strcmp(name, "first_ip")) {
fprintf(file, "%s", ntop_ipaddr(&e->range_p->first_ip));
return 0;
}
if (!strcmp(name, "last_ip")) {
fprintf(file, "%s", ntop_ipaddr(&e->range_p->last_ip));
return 0;
}
if (!strcmp(name, "used")) {
fprintf(file, "%g", e->range_p->count);
return 0;
}
if (!strcmp(name, "touched")) {
fprintf(file, "%g", e->range_p->touched);
return 0;
}
if (!strcmp(name, "defined")) {
fprintf(file, "%g", e->oh.range_size);
return 0;
}
if (!strcmp(name, "free")) {
fprintf(file, "%g", e->oh.range_size - e->range_p->count);
return 0;
}
if (!strcmp(name, "percent")) {
fprintf(file, "%g", e->oh.percent);
return 0;
}
if (!strcmp(name, "touch_count")) {
fprintf(file, "%g", e->oh.tc);
return 0;
}
if (!strcmp(name, "touch_percent")) {
fprintf(file, "%g", e->oh.tcp);
return 0;
}
if (e->state->backups_found == 1) {
if (!strcmp(name, "backup_count")) {
fprintf(file, "%g", e->range_p->backups);
return 0;
}
if (!strcmp(name, "backup_percent")) {
fprintf(file, "%g", e->oh.bup);
return 0;
}
}
if (!strcmp(name, "status")) {
fprintf(file, "%d", e->oh.status);
return 0;
}
if (!strcmp(name, "gettimeofday")) {
dp_time_tool(file, NULL, 1);
return 0;
}
if (!strcmp(name, "lease_file_epoch_mtime")) {
dp_time_tool(file, e->state->dhcpdlease_file, 1);
return 0;
}
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unexpected tag: %s", name);
return 1;
}
/*! \brief Mustach shared networks aka {{#shared-networks}} tag parser and printer. */
static int must_put_shnet(void *closure, const char *name, int escape
__attribute__ ((unused)), FILE *file)
{
struct expl *e = closure;
if (!strcmp(name, "location")) {
fprintf(file, "%s", e->shnet_p->name);
return 0;
}
if (!strcmp(name, "defined")) {
fprintf(file, "%g", e->shnet_p->available);
return 0;
}
if (!strcmp(name, "used")) {
fprintf(file, "%g", e->shnet_p->used);
return 0;
}
if (!strcmp(name, "touched")) {
fprintf(file, "%g", e->shnet_p->touched);
return 0;
}
if (!strcmp(name, "free")) {
fprintf(file, "%g", e->shnet_p->available - e->shnet_p->used);
return 0;
}
if (!strcmp(name, "percent")) {
fprintf(file, "%g", e->oh.percent);
return 0;
}
if (!strcmp(name, "touch_count")) {
fprintf(file, "%g", e->oh.tc);
return 0;
}
if (!strcmp(name, "touch_percent")) {
fprintf(file, "%g", e->oh.tcp);
return 0;
}
if (e->state->backups_found == 1) {
if (!strcmp(name, "backup_count")) {
fprintf(file, "%g", e->shnet_p->backups);
return 0;
}
if (!strcmp(name, "backup_percent")) {
fprintf(file, "%g", e->oh.bup);
return 0;
}
}
if (!strcmp(name, "status")) {
fprintf(file, "%d", e->oh.status);
return 0;
}
if (!strcmp(name, "gettimeofday")) {
dp_time_tool(file, NULL, 1);
return 0;
}
if (!strcmp(name, "lease_file_epoch_mtime")) {
dp_time_tool(file, e->state->dhcpdlease_file, 1);
return 0;
}
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unexpected tag: %s", name);
return 1;
}
/*! \brief A function to move to next range when {{/subnets}} is encountered. */
static int must_next_range(void *closure)
{
struct expl *e = closure;
do {
e->range_p++;
e->current--;
if (e->current <= 0)
return 0;
} while (range_output_helper(e->state, &e->oh, e->range_p));
return 1;
}
/*! \brief A function to move to next shared network when {{/shared-networks}}
* is encountered. */
static int must_next_shnet(void *closure)
{
struct expl *e = closure;
if (e->current == 1 || e->shnet_p == NULL)
return 0;
while (1) {
e->shnet_p = e->shnet_p->next;
if (e->shnet_p == NULL)
break;
if (shnet_output_helper(e->state, &e->oh, e->shnet_p))
continue;
else
return 1;
}
return 0;
}
/*! \brief Function that is called when mustach is searching output loops from
* template file. */
static int must_enter(void *closure, const char *name)
{
struct expl *e = closure;
if (!strcmp(name, "active_lease")) {
itf.put = must_put_active_lease;
itf.next = must_next_active_lease;
e->current = 0;
e->lease_p = e->state->leases;
return must_next_active_lease(closure);
}
if (!strcmp(name, "subnets")) {
itf.put = must_put_range;
itf.next = must_next_range;
e->current = e->state->num_ranges + 1;
e->range_p = e->state->ranges;
/* must_next_range() will skip_ok when needed */
e->range_p--;
return must_next_range(closure);
}
if (!strcmp(name, "shared-networks")) {
itf.put = must_put_shnet;
itf.next = must_next_shnet;
e->shnet_p = e->state->shared_net_root;
e->current = 0;
return must_next_shnet(closure);
}
if (!strcmp(name, "summary")) {
itf.put = must_put_shnet;
itf.next = must_next_shnet;
e->shnet_p = e->state->shared_net_root;
e->current = 1;
shnet_output_helper(e->state, &e->oh, e->shnet_p);
return 1;
}
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unexpected tag: %s", name);
return 1;
}
/*! \brief Function that is called when all elements within a print loop are outputted. */
static int must_leave(void *closure)
{
struct expl *e = closure;
e->shnet_p = e->state->shared_net_root;
e->range_p = e->state->ranges;
itf.put = must_put_base;
return 0;
}
/*! \brief Read mustach template to memory. */
static char *must_read_template(const char *filename)
{
int f;
struct stat s;
char *result;
if (filename == NULL)
error(EXIT_FAILURE, 0, "must_read_template: --mustach argument missing");
if ((f = open(filename, O_RDONLY)) < 0) {
error(EXIT_FAILURE, errno, "must_read_template: open: %s", filename);
}
fstat(f, &s);
result = xmalloc(s.st_size + 1);
if (read(f, result, s.st_size) != s.st_size) {
error(EXIT_FAILURE, errno, "must_read_template: read: %s", filename);
}
close(f);
result[s.st_size] = 0;
return result;
}
/*! \brief Start mustach processing. */
int mustach_dhcpd_pools(struct conf_t *state)
{
struct expl e = { .state = state };
char *template;
FILE *outfile;
int ret;
template = must_read_template(state->mustach_template);
if (state->output_file) {
outfile = fopen(state->output_file, "w+");
if (outfile == NULL) {
error(EXIT_FAILURE, errno, "mustach_dhcpd_pools: fopen: %s",
state->output_file);
}
} else {
outfile = stdout;
}
ret = fmustach(template, &itf, &e, outfile);
free(template);
if (outfile == stdout) {
if (fflush(stdout))
error(EXIT_FAILURE, errno, "mustach_dhcpd_pools: fflush");
} else {
if (close_stream(outfile))
error(EXIT_FAILURE, errno, "mustach_dhcpd_pools: fclose");
}
switch (ret) {
case MUSTACH_OK:
return 0;
case MUSTACH_ERROR_SYSTEM:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: system error");
break;
case MUSTACH_ERROR_UNEXPECTED_END:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unexpected end");
break;
case MUSTACH_ERROR_EMPTY_TAG:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: empty tag");
break;
case MUSTACH_ERROR_TAG_TOO_LONG:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: too long tag");
break;
case MUSTACH_ERROR_BAD_SEPARATORS:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: bad separator");
break;
case MUSTACH_ERROR_TOO_DEEP:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: too deep");
break;
case MUSTACH_ERROR_CLOSING:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: closing");
break;
case MUSTACH_ERROR_BAD_UNESCAPE_TAG:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: bad escape tag");
break;
default:
error(EXIT_FAILURE, 0, "mustach_dhcpd_pools: fmustach: unknown error");
}
return 1;
}

View file

@ -1,325 +0,0 @@
/*
Author: José Bollo <jobol@nonadev.net>
Author: José Bollo <jose.bollo@iot.bzh>
https://gitlab.com/jobol/mustach
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#define _GNU_SOURCE
#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include "mustach.h"
#define NAME_LENGTH_MAX 1024
#define DEPTH_MAX 256
#if !defined(NO_OPEN_MEMSTREAM)
static FILE *memfile_open(char **buffer, size_t *size)
{
return open_memstream(buffer, size);
}
static void memfile_abort(FILE *file, char **buffer, size_t *size)
{
fclose(file);
free(*buffer);
*buffer = NULL;
*size = 0;
}
static int memfile_close(FILE *file, char **buffer, size_t *size)
{
int rc;
/* adds terminating null */
rc = fputc(0, file) ? MUSTACH_ERROR_SYSTEM : 0;
fclose(file);
if (rc == 0)
/* removes terminating null of the length */
(*size)--;
else {
free(*buffer);
*buffer = NULL;
*size = 0;
}
return rc;
}
#else
static FILE *memfile_open(char **buffer, size_t *size)
{
return tmpfile();
}
static void memfile_abort(FILE *file, char **buffer, size_t *size)
{
fclose(file);
*buffer = NULL;
*size = 0;
}
static int memfile_close(FILE *file, char **buffer, size_t *size)
{
int rc;
size_t s;
char *b;
s = (size_t)ftell(file);
b = malloc(s + 1);
if (b == NULL) {
rc = MUSTACH_ERROR_SYSTEM;
errno = ENOMEM;
s = 0;
} else {
rewind(file);
if (1 == fread(b, s, 1, file)) {
rc = 0;
b[s] = 0;
} else {
rc = MUSTACH_ERROR_SYSTEM;
free(b);
b = NULL;
s = 0;
}
}
*buffer = b;
*size = s;
return rc;
}
#endif
static int getpartial(struct mustach_itf *itf, void *closure, const char *name, char **result)
{
int rc;
FILE *file;
size_t size;
*result = NULL;
file = memfile_open(result, &size);
if (file == NULL)
rc = MUSTACH_ERROR_SYSTEM;
else {
rc = itf->put(closure, name, 0, file);
if (rc < 0)
memfile_abort(file, result, &size);
else
rc = memfile_close(file, result, &size);
}
return rc;
}
static int process(const char *template, struct mustach_itf *itf, void *closure, FILE *file, const char *opstr, const char *clstr)
{
char name[NAME_LENGTH_MAX + 1], *partial, c, *tmp;
const char *beg, *term;
struct { const char *name, *again; size_t length; int emit, entered; } stack[DEPTH_MAX];
size_t oplen, cllen, len, l;
int depth, rc, emit;
emit = 1;
oplen = strlen(opstr);
cllen = strlen(clstr);
depth = 0;
for(;;) {
beg = strstr(template, opstr);
if (beg == NULL) {
/* no more mustach */
if (emit)
fwrite(template, strlen(template), 1, file);
return depth ? MUSTACH_ERROR_UNEXPECTED_END : 0;
}
if (emit)
fwrite(template, (size_t)(beg - template), 1, file);
beg += oplen;
term = strstr(beg, clstr);
if (term == NULL)
return MUSTACH_ERROR_UNEXPECTED_END;
template = term + cllen;
len = (size_t)(term - beg);
c = *beg;
switch(c) {
case '!':
case '=':
break;
case '{':
for (l = 0 ; clstr[l] == '}' ; l++);
if (clstr[l]) {
if (!len || beg[len-1] != '}')
return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
len--;
} else {
if (term[l] != '}')
return MUSTACH_ERROR_BAD_UNESCAPE_TAG;
template++;
}
c = '&';
/*@fallthrough@*/
case '^':
case '#':
case '/':
case '&':
case '>':
#if !defined(NO_EXTENSION_FOR_MUSTACH) && !defined(NO_COLON_EXTENSION_FOR_MUSTACH)
case ':':
#endif
beg++; len--;
default:
while (len && isspace(beg[0])) { beg++; len--; }
while (len && isspace(beg[len-1])) len--;
#if defined(NO_EXTENSION_FOR_MUSTACH) || defined(NO_ALLOW_EMPTY_TAG)
if (len == 0)
return MUSTACH_ERROR_EMPTY_TAG;
#endif
if (len > NAME_LENGTH_MAX)
return MUSTACH_ERROR_TAG_TOO_LONG;
memcpy(name, beg, len);
name[len] = 0;
break;
}
switch(c) {
case '!':
/* comment */
/* nothing to do */
break;
case '=':
/* defines separators */
if (len < 5 || beg[len - 1] != '=')
return MUSTACH_ERROR_BAD_SEPARATORS;
beg++;
len -= 2;
for (l = 0; l < len && !isspace(beg[l]) ; l++);
if (l == len)
return MUSTACH_ERROR_BAD_SEPARATORS;
oplen = l;
tmp = alloca(oplen + 1);
memcpy(tmp, beg, oplen);
tmp[oplen] = 0;
opstr = tmp;
while (l < len && isspace(beg[l])) l++;
if (l == len)
return MUSTACH_ERROR_BAD_SEPARATORS;
cllen = len - l;
tmp = alloca(cllen + 1);
memcpy(tmp, beg + l, cllen);
tmp[cllen] = 0;
clstr = tmp;
break;
case '^':
case '#':
/* begin section */
if (depth == DEPTH_MAX)
return MUSTACH_ERROR_TOO_DEEP;
rc = emit;
if (rc) {
rc = itf->enter(closure, name);
if (rc < 0)
return rc;
}
stack[depth].name = beg;
stack[depth].again = template;
stack[depth].length = len;
stack[depth].emit = emit;
stack[depth].entered = rc;
if ((c == '#') == (rc == 0))
emit = 0;
depth++;
break;
case '/':
/* end section */
if (depth-- == 0 || len != stack[depth].length || memcmp(stack[depth].name, name, len))
return MUSTACH_ERROR_CLOSING;
rc = emit && stack[depth].entered ? itf->next(closure) : 0;
if (rc < 0)
return rc;
if (rc) {
template = stack[depth++].again;
} else {
emit = stack[depth].emit;
if (emit && stack[depth].entered)
itf->leave(closure);
}
break;
case '>':
/* partials */
if (emit) {
rc = getpartial(itf, closure, name, &partial);
if (rc == 0) {
rc = process(partial, itf, closure, file, opstr, clstr);
free(partial);
}
if (rc < 0)
return rc;
}
break;
default:
/* replacement */
if (emit) {
rc = itf->put(closure, name, c != '&', file);
if (rc < 0)
return rc;
}
break;
}
}
}
int fmustach(const char *template, struct mustach_itf *itf, void *closure, FILE *file)
{
int rc = itf->start ? itf->start(closure) : 0;
if (rc == 0)
rc = process(template, itf, closure, file, "{{", "}}");
return rc;
}
int fdmustach(const char *template, struct mustach_itf *itf, void *closure, int fd)
{
int rc;
FILE *file;
file = fdopen(fd, "w");
if (file == NULL) {
rc = MUSTACH_ERROR_SYSTEM;
errno = ENOMEM;
} else {
rc = fmustach(template, itf, closure, file);
fclose(file);
}
return rc;
}
int mustach(const char *template, struct mustach_itf *itf, void *closure, char **result, size_t *size)
{
int rc;
FILE *file;
size_t s;
*result = NULL;
if (size == NULL)
size = &s;
file = memfile_open(result, size);
if (file == NULL)
rc = MUSTACH_ERROR_SYSTEM;
else {
rc = fmustach(template, itf, closure, file);
if (rc < 0)
memfile_abort(file, result, size);
else
rc = memfile_close(file, result, size);
}
return rc;
}

View file

@ -1,120 +0,0 @@
/*
Author: José Bollo <jobol@nonadev.net>
Author: José Bollo <jose.bollo@iot.bzh>
https://gitlab.com/jobol/mustach
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _mustach_h_included_
#define _mustach_h_included_
/**
* mustach_itf - interface for callbacks
*
* All of this function should return a negative value to stop
* the mustache processing. The returned negative value will be
* then returned to the caller of mustach as is.
*
* The functions enter and next should return 0 or 1.
*
* All other functions should normally return 0. If it returns
* a negative value, it means an error that stop the process
* and that is reported to the caller.
*
* @start: Starts the mustach processing of the closure
* 'start' is optional (can be NULL)
*
* @put: Writes the value of 'name' to 'file' with 'escape' or not
* As an extension (see NO_ALLOW_EMPTY_TAG), the 'name' can be
* the empty string. In that later case an implemntation can
* return MUSTACH_ERROR_EMPTY_TAG to refuse empty names.
*
* @enter: Enters the section of 'name' if possible.
* Musts return 1 if entered or 0 if not entered.
* When 1 is returned, the function 'leave' will always be called.
* Conversely 'leave' is never called when enter returns 0 or
* a negative value.
* When 1 is returned, the function must activate the first
* item of the section.
*
* @next: Activates the next item of the section if it exists.
* Musts return 1 when the next item is activated.
* Musts return 0 when there is no item to activate.
*
* @leave: Leaves the last entered section
*/
struct mustach_itf {
int (*start)(void *closure);
int (*put)(void *closure, const char *name, int escape, FILE *file);
int (*enter)(void *closure, const char *name);
int (*next)(void *closure);
int (*leave)(void *closure);
};
#define MUSTACH_OK 0
#define MUSTACH_ERROR_SYSTEM -1
#define MUSTACH_ERROR_UNEXPECTED_END -2
#define MUSTACH_ERROR_EMPTY_TAG -3
#define MUSTACH_ERROR_TAG_TOO_LONG -4
#define MUSTACH_ERROR_BAD_SEPARATORS -5
#define MUSTACH_ERROR_TOO_DEEP -6
#define MUSTACH_ERROR_CLOSING -7
#define MUSTACH_ERROR_BAD_UNESCAPE_TAG -8
/* compatibility with older bad name */
#define MUSTACH_ERROR_TOO_DEPTH MUSTACH_ERROR_TOO_DEEP
/**
* fmustach - Renders the mustache 'template' in 'file' for 'itf' and 'closure'.
*
* @template: the template string to instanciate
* @itf: the interface to the functions that mustach calls
* @closure: the closure to pass to functions called
* @file: the file where to write the result
*
* Returns 0 in case of success, -1 with errno set in case of system error
* a other negative value in case of error.
*/
extern int fmustach(const char *template, struct mustach_itf *itf, void *closure, FILE *file);
/**
* fmustach - Renders the mustache 'template' in 'fd' for 'itf' and 'closure'.
*
* @template: the template string to instanciate
* @itf: the interface to the functions that mustach calls
* @closure: the closure to pass to functions called
* @fd: the file descriptor number where to write the result
*
* Returns 0 in case of success, -1 with errno set in case of system error
* a other negative value in case of error.
*/
extern int fdmustach(const char *template, struct mustach_itf *itf, void *closure, int fd);
/**
* fmustach - Renders the mustache 'template' in 'result' for 'itf' and 'closure'.
*
* @template: the template string to instanciate
* @itf: the interface to the functions that mustach calls
* @closure: the closure to pass to functions called
* @result: the pointer receiving the result when 0 is returned
* @size: the size of the returned result
*
* Returns 0 in case of success, -1 with errno set in case of system error
* a other negative value in case of error.
*/
extern int mustach(const char *template, struct mustach_itf *itf, void *closure, char **result, size_t *size);
#endif

View file

@ -39,75 +39,62 @@
#include <config.h>
#include "dhcpd-pools.h"
#include "defaults.h"
#include "progname.h"
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "error.h"
#include "progname.h"
#include "quote.h"
#include "xalloc.h"
#include "dhcpd-pools.h"
static char *(*cidr_last) (union ipaddr_t *restrict addr, const int mask);
static char *cidr_last_v4(union ipaddr_t *restrict addr, const int mask);
static char *cidr_last_v6(union ipaddr_t *restrict addr, const int mask);
#include <limits.h>
/*! \brief Set function pointers depending on IP version.
* \param ip IP version.
*/
void set_ipv_functions(struct conf_t *state, int version)
void set_ipv_functions(int version)
{
switch (version) {
case IPv4:
state->ip_version = version;
case VERSION_4:
config.dhcp_version = version;
add_lease = add_lease_v4;
copy_ipaddr = copy_ipaddr_v4;
find_lease = find_lease_v4;
get_range_size = get_range_size_v4;
ipcomp = ipcomp_v4;
leasecomp = leasecomp_v4;
ntop_ipaddr = ntop_ipaddr_v4;
parse_ipaddr = parse_ipaddr_v4;
cidr_last = cidr_last_v4;
xstrstr = xstrstr_v4;
break;
case IPv6:
state->ip_version = version;
case VERSION_6:
config.dhcp_version = version;
add_lease = add_lease_v6;
copy_ipaddr = copy_ipaddr_v6;
find_lease = find_lease_v6;
get_range_size = get_range_size_v6;
ipcomp = ipcomp_v6;
leasecomp = leasecomp_v6;
ntop_ipaddr = ntop_ipaddr_v6;
parse_ipaddr = parse_ipaddr_v6;
cidr_last = cidr_last_v6;
xstrstr = xstrstr_v6;
break;
case IPvUNKNOWN:
state->ip_version = version;
case VERSION_UNKNOWN:
config.dhcp_version = version;
add_lease = add_lease_init;
copy_ipaddr = copy_ipaddr_init;
find_lease = find_lease_init;
get_range_size = get_range_size_init;
ipcomp = ipcomp_init;
leasecomp = leasecomp_init;
ntop_ipaddr = ntop_ipaddr_init;
parse_ipaddr = parse_ipaddr_init;
cidr_last = NULL;
xstrstr = xstrstr_init;
break;
@ -123,160 +110,55 @@ void set_ipv_functions(struct conf_t *state, int version)
* \param dst An union which will hold conversion result.
* \return Was parsing successful.
*/
int parse_ipaddr_init(struct conf_t *state, const char *restrict src, union ipaddr_t *restrict dst)
int parse_ipaddr_init(const char *restrict src, union ipaddr_t *restrict dst)
{
struct in_addr addr;
struct in6_addr addr6;
if (inet_aton(src, &addr) == 1)
set_ipv_functions(state, IPv4);
else if (inet_pton(AF_INET6, src, &addr6) == 1)
set_ipv_functions(state, IPv6);
else
if (inet_aton(src, &addr) == 1) {
set_ipv_functions(VERSION_4);
} else if (inet_pton(AF_INET6, src, &addr6) == 1) {
set_ipv_functions(VERSION_6);
} else {
return 0;
return parse_ipaddr(state, src, dst);
}
return parse_ipaddr(src, dst);
}
int parse_ipaddr_v4(struct conf_t *state
__attribute__ ((unused)), const char *restrict src,
union ipaddr_t *restrict dst)
int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst)
{
int rv;
struct in_addr addr;
rv = inet_aton(src, &addr);
dst->v4 = ntohl(addr.s_addr);
return rv == 1;
}
int parse_ipaddr_v6(struct conf_t *state
__attribute__ ((unused)), const char *restrict src,
union ipaddr_t *restrict dst)
int parse_ipaddr_v6(const char *restrict src, union ipaddr_t *restrict dst)
{
int rv;
struct in6_addr addr;
rv = inet_pton(AF_INET6, src, &addr);
memcpy(&dst->v6, addr.s6_addr, sizeof(addr.s6_addr));
return rv == 1;
}
/*! \brief Convert string to a desimal format network marks.
* \param src Digit that should be a network mask.
* \return Network mask, or -1 when failing.
*/
static int strtol_mask(const char *str)
{
long num;
char *end = NULL;
errno = 0;
if (str == NULL || *str == '\0')
goto err;
num = strtol(str, &end, 10);
if (errno || str == end || (end && *end))
goto err;
if (num < 0 || 128 < num)
goto err;
return (int)num;
err:
return -1;
}
/*! \brief Find last address in IPv4 range by using cidr format.
* \param addr Pointer to memory where address needs to be stored.
* \return Allocated string format of the address.
*/
static char *cidr_last_v4(union ipaddr_t *restrict addr, const int mask)
{
union ipaddr_t last_ip;
uint32_t netmask;
const char *ip;
if (mask)
netmask = (1U << (32 - mask)) - 1;
else
netmask = 0;
last_ip.v4 = addr->v4 | netmask;
ip = ntop_ipaddr(&last_ip);
return xstrdup(ip);
}
/*! \brief Find last address in IPv6 range by using cidr format.
* \param addr Pointer to memory where address needs to be stored.
* \return Allocated string format of the address.
*/
static char *cidr_last_v6(union ipaddr_t *restrict addr, const int mask)
{
union ipaddr_t bitmask;
int i, j;
char ip[128];
memset(&bitmask, 0x0, sizeof(bitmask));
for (i = mask, j = 0; i > 0; i -= 8, j++) {
if (i >= 8)
bitmask.v6[j] = 0xff;
else
bitmask.v6[j] = (unsigned char)(0xffU << (8 - i));
}
for (i = 0; i < (int)sizeof(bitmask); i++)
addr->v6[i] |= ~bitmask.v6[i];
inet_ntop(AF_INET6, addr, ip, sizeof(ip));
return xstrdup(ip);
}
/*! \brief Convert a cidr notated address to a range.
* \param range_p Pointer to memory where addresses need to be stored.
* \param word A range as a cidr string.
*/
void parse_cidr(struct conf_t *state, struct range_t *range_p, const char *word)
{
char *divider;
int mask;
union ipaddr_t addr;
char *last;
/* determine cidr */
divider = strchr(word, '/');
*divider++ = '\0';
mask = strtol_mask(divider);
if (mask < 0)
error(EXIT_FAILURE, 0, "cidr %s invalid mask %s", word, divider);
if (state->ip_version == IPvUNKNOWN) {
if (!strchr(word, ':'))
set_ipv_functions(state, IPv4);
else
set_ipv_functions(state, IPv6);
}
/* start of the range is easy */
parse_ipaddr(state, word, &addr);
copy_ipaddr(&range_p->first_ip, &addr);
/* end of the range depends cidr size */
last = cidr_last(&addr, mask);
parse_ipaddr(state, last, &addr);
copy_ipaddr(&range_p->last_ip, &addr);
free(last);
}
/*! \brief Copy IP address to union.
*
* \param dst Destination for a binary IP address.
* \param src Sourse of an IP address. */
void copy_ipaddr_init(union ipaddr_t *restrict dst __attribute__ ((unused)),
const union ipaddr_t *restrict src __attribute__ ((unused)))
void copy_ipaddr_init(union ipaddr_t *restrict dst __attribute__((unused)),
const union ipaddr_t *restrict src __attribute__((unused)))
{
}
void copy_ipaddr_v4(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src)
void copy_ipaddr_v4(union ipaddr_t *restrict dst,
const union ipaddr_t *restrict src)
{
dst->v4 = src->v4;
}
void copy_ipaddr_v6(union ipaddr_t *restrict dst, const union ipaddr_t *restrict src)
void copy_ipaddr_v6(union ipaddr_t *restrict dst,
const union ipaddr_t *restrict src)
{
memcpy(&dst->v6, &src->v6, sizeof(src->v6));
}
@ -289,27 +171,25 @@ void copy_ipaddr_v6(union ipaddr_t *restrict dst, const union ipaddr_t *restrict
* \param ip Binary IP address.
* \return Printable address.
*/
const char *ntop_ipaddr_init(const union ipaddr_t *ip __attribute__ ((unused)))
const char *ntop_ipaddr_init(const union ipaddr_t *ip __attribute__((unused)))
{
static char buffer = '\0';
return &buffer;
}
const char *ntop_ipaddr_v4(const union ipaddr_t *ip)
{
static char buffer[INET_ADDRSTRLEN];
static char buffer[sizeof("255.255.255.255")];
struct in_addr addr;
addr.s_addr = htonl(ip->v4);
return inet_ntop(AF_INET, &addr, buffer, sizeof(buffer));
}
const char *ntop_ipaddr_v6(const union ipaddr_t *ip)
{
static char buffer[INET6_ADDRSTRLEN];
static char
buffer[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
struct in6_addr addr;
memcpy(addr.s6_addr, ip->v6, sizeof(addr.s6_addr));
return inet_ntop(AF_INET6, &addr, buffer, sizeof(buffer));
}
@ -320,7 +200,7 @@ const char *ntop_ipaddr_v6(const union ipaddr_t *ip)
* and last IP in the range.
* \return Size of a range.
*/
double get_range_size_init(const struct range_t *r __attribute__ ((unused)))
double get_range_size_init(const struct range_t *r __attribute__((unused)))
{
return 0;
}
@ -334,7 +214,6 @@ double get_range_size_v6(const struct range_t *r)
{
double size = 0;
int i;
/* When calculating the size of an IPv6 range overflow may occur.
* In that case only the last LONG_BIT bits are preserved, thus
* we just skip the first (16 - LONG_BIT) bits... */
@ -352,14 +231,17 @@ double get_range_size_v6(const struct range_t *r)
* \param str A line from dhcpd.conf
* \return prefix_t enum value
*/
int xstrstr_init(struct conf_t *state, const char *restrict str)
int
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((hot))
#endif
xstrstr_init(const char *restrict str)
{
if (!memcmp("lease ", str, 6)) {
set_ipv_functions(state, IPv4);
if (memcmp("lease ", str, 6)) {
set_ipv_functions(VERSION_4);
return PREFIX_LEASE;
}
if (!memcmp(" iaaddr ", str, 9)) {
set_ipv_functions(state, IPv6);
} else if (memcmp(" iaaddr ", str, 9)) {
set_ipv_functions(VERSION_6);
return PREFIX_LEASE;
}
return NUM_OF_PREFIX;
@ -375,14 +257,14 @@ int
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((hot))
#endif
xstrstr_v4(struct conf_t *state __attribute__ ((unused)), const char *restrict str)
xstrstr_v4(const char *restrict str)
{
size_t len;
if (str[2] == 'b' || str[2] == 'h')
if (str[2] == 'b' || str[2] == 'h') {
len = strlen(str);
else
} else {
len = 0;
}
if (15 < len) {
switch (str[16]) {
case 'f':
@ -411,18 +293,11 @@ int
if (!memcmp(" hardware ethernet", str, 19))
return PREFIX_HARDWARE_ETHERNET;
break;
default:
break;
}
}
if (!memcmp("lease ", str, 6))
if (!memcmp("lease ", str, 6)) {
return PREFIX_LEASE;
else if (!memcmp(" starts ", str, 9))
return PREFIX_STARTS;
else if (!memcmp(" ends ", str, 7))
return PREFIX_ENDS;
else if (!memcmp(" client-hostname ", str, 18))
return PREFIX_HOSTNAME;
}
return NUM_OF_PREFIX;
}
@ -436,14 +311,14 @@ int
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((hot))
#endif
xstrstr_v6(struct conf_t *state __attribute__ ((unused)), const char *restrict str)
xstrstr_v6(const char *restrict str)
{
size_t len;
if (str[4] == 'b' || str[2] == 'h')
if (str[4] == 'b' || str[2] == 'h') {
len = strlen(str);
else
} else {
len = 0;
}
if (17 < len) {
switch (str[18]) {
case 'f':
@ -472,37 +347,14 @@ int
if (!memcmp(" hardware ethernet", str, 19))
return PREFIX_HARDWARE_ETHERNET;
break;
default:
break;
}
}
if (!memcmp(" iaaddr ", str, 9))
if (!memcmp(" iaaddr ", str, 9)) {
return PREFIX_LEASE;
else if (!memcmp(" starts ", str, 9))
return PREFIX_STARTS;
else if (!memcmp(" ends ", str, 7))
return PREFIX_ENDS;
else if (!memcmp(" client-hostname ", str, 18))
return PREFIX_HOSTNAME;
}
return NUM_OF_PREFIX;
}
/*! \brief Parse option argument color mode.
*
* \param Color mode string.
* \return color mode enum.
*/
int parse_color_mode(const char *restrict arg)
{
if (!strcmp(arg, "always"))
return color_on;
if (!strcmp(arg, "auto"))
return color_auto;
if (!strcmp(arg, "never"))
return color_off;
return color_unknown;
}
/*! \brief Return a double floating point value.
*
* \param str String to be converted to a double.
@ -518,142 +370,118 @@ double strtod_or_err(const char *restrict str, const char *restrict errmesg)
goto err;
errno = 0;
num = strtod(str, &end);
if (errno || str == end || (end && *end))
goto err;
return num;
err:
error(EXIT_FAILURE, errno, "%s: %s", errmesg, quote(str));
return 0;
if (errno)
err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
}
/*! \brief Reverse range.
* Used before output, if a caller has requested reverse sorting. */
void flip_ranges(struct conf_t *state)
* Used before output, if a caller has requested reverse sorting.
* FIXME: The temporary memory area handling should be internal to this
* function, not a parameter.
*
* \param flip_me The range that needs to be inverted.
* \param tmp_ranges Temporary memory area for the flip. */
void flip_ranges(struct range_t *restrict flip_me,
struct range_t *restrict tmp_ranges)
{
unsigned int i = state->num_ranges - 1, j;
struct range_t *tmp_ranges;
unsigned int i = num_ranges - 1, j;
tmp_ranges = xmalloc(sizeof(struct range_t) * state->num_ranges);
for (j = 0; j < state->num_ranges; j++, i--)
*(tmp_ranges + j) = *(state->ranges + i);
memcpy(state->ranges, tmp_ranges, state->num_ranges * sizeof(struct range_t));
free(tmp_ranges);
for (j = 0; j < num_ranges; j++) {
*(tmp_ranges + j) = *(flip_me + i);
i--;
}
memcpy(flip_me, tmp_ranges, num_ranges * sizeof(struct range_t));
}
/*! \brief Free memory, flush buffers etc. */
void clean_up(struct conf_t *state)
void clean_up(void)
{
struct output_sort *cur, *next;
struct shared_network_t *c, *n;
unsigned int i;
/* Just in case there something in buffers */
if (fflush(NULL))
error(EXIT_FAILURE, errno, "clean_up: fflush");
free(state->ranges);
delete_all_leases(state);
for (cur = state->sorts; cur; cur = next) {
next = cur->next;
free(cur);
if (fflush(NULL)) {
warn("clean_up: fflush");
}
for (c = state->shared_net_root; c; c = n) {
n = c->next;
free(c->name);
free(c);
}
}
/*! \brief Print a time stamp of a path or now to output file. */
void dp_time_tool(FILE *file, const char *path, const int epoch)
{
struct stat st;
if (path)
stat(path, &st);
else
clock_gettime(CLOCK_REALTIME, &st.st_mtim);
if (epoch)
fprintf(file, "%ld", st.st_mtim.tv_sec);
else {
char time_stamp[64];
const time_t mtime = st.st_mtim.tv_sec;
struct tm tm;
localtime_r(&mtime, &tm);
strftime(time_stamp, sizeof(time_stamp), "%FT%T%z", &tm);
fprintf(file, "%s", time_stamp);
free(config.dhcpdconf_file);
free(config.dhcpdlease_file);
free(config.output_file);
free(ranges);
delete_all_leases();
if (shared_networks) {
num_shared_networks++;
for (i = 0; i < num_shared_networks; i++) {
free((shared_networks + i)->name);
}
free(shared_networks);
}
}
/*! \brief A version printing. */
void __attribute__ ((__noreturn__)) print_version(void)
{
#define stringify(s) #s
#define stringify_value(s) stringify(s)
fprintf(stdout, "%s\n"
"Original design and maintainer Sami Kerola.\n"
"uthash %s by Troy D. Hanson.\n"
"Original design by Sami Kerola.\n"
"XML support by Dominic Germain, Sogetel inc.\n"
"IPv6 support by Cheer Xiao.\n"
"Mustach templating support by Jose Bollo.\n"
" The dhcpd-pools is FreeBSD Licensed,\n"
" uthash uses BSD license,\n"
" gnulib parts are mostly GPL,\n"
" and mustache uses Apache License.\n", PACKAGE_STRING,
stringify_value(UTHASH_VERSION));
"IPv6 support by Cheer Xiao.\n\n"
"The software has FreeBSD License.\n", PACKAGE_STRING);
exit(EXIT_SUCCESS);
}
/*! \brief Command line help screen. */
void __attribute__ ((__noreturn__)) usage(int status)
{
FILE *out = status == EXIT_SUCCESS ? stdout : stderr;
FILE *out;
out = status != 0 ? stderr : stdout;
fprintf(out, "Usage: %s [OPTIONS]\n", program_name);
fputs( "\n", out);
fputs( "This is ISC dhcpd pools usage analyzer.\n", out);
fputs( "\n", out);
fputs( " -c, --config=FILE path to the dhcpd.conf file\n", out);
fputs( " -l, --leases=FILE path to the dhcpd.leases file\n", out);
fputs( " -f, --format=[thHcxXjJ] output format\n", out);
fputs( " t for text\n", out);
fputs( " H for full html page\n", out);
fputs( " x for xml\n", out);
fputs( " X for xml with active lease details\n", out);
fputs( " j for json\n", out);
fputs( " J for json with active lease details\n", out);
fputs( " c for comma separated values\n", out);
#ifdef BUILD_MUSTACH
fputs( " --mustach=FILE output using mustach template file\n", out);
#endif
fputs( " -s, --sort=[nimcptTe] sort ranges by\n", out);
fputs( " n name\n", out);
fputs( " i IP\n", out);
fputs( " m maximum\n", out);
fputs( " c current\n", out);
fputs( " p percent\n", out);
fputs( " t touched\n", out);
fputs( " T t+c\n", out);
fputs( " e t+c perc\n", out);
fputs( " -r, --reverse reverse order sort\n", out);
fputs( " -o, --output=FILE output into a file\n", out);
fputs( " -L, --limit=NR output limit mask 77 - 00\n", out);
fputs( " --color=WHEN use colors 'always', 'never', or 'auto'\n", out);
fputs( " --warning=PERC set warning alarming threshold\n", out);
fputs( " --critical=PERC set critical alarming threshold\n", out);
fputs( " --skip=WHAT do not print threshold 'ok', 'warning', 'critical',\n", out);
fputs( " 'minsize', or 'suppressed'\n", out);
fputs( " --warn-count=NR a number of free leases before warning raised\n", out);
fputs( " --crit-count=NR a number of free leases before critical raised\n", out);
fputs( " --minsize=size disable alarms for small ranges and shared-nets\n", out);
fputs( " --snet-alarms suppress range alarms that are part of a shared-net\n", out);
fputs( " -p, --perfdata print additional perfdata in alarming mode\n", out);
fputs( " -A, --all-as-shared treat single subnets as shared-network with CIDR as their name\n", out);
fputs( " --ip-version=4|6 force analysis to use either IPv4 or IPv6 functions\n", out);
fputs( " -v, --version output version information and exit\n", out);
fputs( " -h, --help display this help and exit\n", out);
fputs( "\n", out);
fprintf(out, "Report bugs to <%s>\n", PACKAGE_BUGREPORT);
fprintf(out, "Homepage: %s\n", PACKAGE_URL);
fprintf(out, "\
Usage: %s [OPTIONS]\n\n\
This is ISC dhcpd pools usage analyzer.\n\
\n", program_name);
fprintf(out, "\
-c, --config=FILE path to the dhcpd.conf file\n\
-l, --leases=FILE path to the dhcpd.leases file\n");
fprintf(out, "\
-f, --format=[thHcxXjJ] output format\n\
t for text\n\
h for html table\n\
H for full html page\n\
x for xml\n\
X for xml with active lease details\n\
j for json\n\
J for json with active lease details\n\
c for comma separated values\n");
fprintf(out, "\
-s, --sort=[nimcptTe] sort ranges by\n\
n name\n\
i IP\n\
m maximum\n\
c current\n\
p percent\n\
t touched\n\
T t+c\n\
e t+c perc\n\
-r, --reverse reverse order sort\n\
-o, --output=FILE output into a file\n\
-L, --limit=NR output limit mask 77 - 00\n");
fprintf(out, "\
--warning=PERC set warning alarming limit\n\
--critical=PERC set critical alarming limit\n\
--minsize=size disable alarms for small ranges and shared-nets\n");
fprintf(out, "\
-v, --version version information\n\
-h, --help this screen\n\
\n\
Report bugs to <%s>\n\
Homepage: %s\n", PACKAGE_BUGREPORT, PACKAGE_URL);
exit(status);
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}

File diff suppressed because it is too large Load diff

View file

@ -40,30 +40,28 @@
#include <config.h>
#include <math.h>
#include <err.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "error.h"
#include "progname.h"
#include "quote.h"
#include "xalloc.h"
#include "dhcpd-pools.h"
#include "progname.h"
/*! \brief Compare IP address, with IPv4/v6 determination.
* \param a Binary IP address.
* \param b Binary IP address.
* \return If a < b return -1, if a < b return 1, when they are equal return 0.
*/
int ipcomp_init(const union ipaddr_t *restrict a __attribute__ ((unused)),
const union ipaddr_t *restrict b __attribute__ ((unused)))
int ipcomp_init(const union ipaddr_t *restrict a __attribute__((unused)),
const union ipaddr_t *restrict b __attribute__((unused)))
{
return 0;
}
int ipcomp_v4(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b)
int ipcomp_v4(const union ipaddr_t *restrict a,
const union ipaddr_t *restrict b)
{
if (a->v4 < b->v4)
return -1;
@ -72,36 +70,12 @@ int ipcomp_v4(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b
return 0;
}
int ipcomp_v6(const union ipaddr_t *restrict a, const union ipaddr_t *restrict b)
int ipcomp_v6(const union ipaddr_t *restrict a,
const union ipaddr_t *restrict b)
{
return memcmp(&a->v6, &b->v6, sizeof(a->v6));
}
/*! \brief Compare IP address in leases_t structure, with IPv4/v6 determination.
* \param a Binary IP address.
* \param b Binary IP address.
* \return If a < b return -1, if a < b return 1, when they are equal return 0.
*/
int leasecomp_init(const struct leases_t *restrict a __attribute__ ((unused)),
const struct leases_t *restrict b __attribute__ ((unused)))
{
return 0;
}
int leasecomp_v4(const struct leases_t *restrict a, const struct leases_t *restrict b)
{
if (a->ip.v4 < b->ip.v4)
return -1;
if (a->ip.v4 > b->ip.v4)
return 1;
return 0;
}
int leasecomp_v6(const struct leases_t *restrict a, const struct leases_t *restrict b)
{
return memcmp(&a->ip.v6, &b->ip.v6, sizeof(a->ip.v6));
}
/*! \brief Compare IP address in leases. Suitable for sorting range table.
* \param r1 A range structure.
* \param r2 A range structure.
@ -119,14 +93,9 @@ int rangecomp(const void *restrict r1, const void *restrict r2)
*/
int comp_double(double f1, double f2)
{
if (isless(f1, f2))
return -1;
else if (isless(f2, f1))
return 1;
return 0;
return f1 < f2 ? -1 : f1 > f2 ? 1 : 0;
}
/*! \brief Compare two range_t by their first_ip.
* \param r1,r2 Pointers to data to compare.
* \return Like strcmp.
@ -228,7 +197,7 @@ comparer_t field_selector(char c)
{
switch (c) {
case 'n':
return NULL;
break;
case 'i':
return comp_ip;
case 'm':
@ -244,11 +213,10 @@ comparer_t field_selector(char c)
case 'e':
return comp_tcperc;
default:
{
char str[2] = { c, '\0' };
error(EXIT_FAILURE, 0, "field_selector: unknown sort order: %s",
quote(str));
}
clean_up();
warnx("field_selector: unknown sort order `%c'", c);
errx(EXIT_FAILURE, "Try `%s --help' for more information.",
program_name);
}
return NULL;
}
@ -258,69 +226,85 @@ comparer_t field_selector(char c)
* \param right The right side of the merge sort.
* \return Relevant for merge sort decision.
*/
static int merge(struct conf_t *state, struct range_t *restrict left, struct range_t *restrict right)
static int merge(struct range_t *restrict left, struct range_t *restrict right)
{
struct output_sort *p;
int ret;
int i, len, ret;
comparer_t comparer;
int cmp;
for (p = state->sorts; p; p = p->next) {
if (p->func == NULL) {
/* String sorting is special. */
ret = strcmp(left->shared_net->name, right->shared_net->name);
} else {
/* Range sorts are common. */
ret = p->func(left, right);
len = strlen(config.sort);
for (i = 0; i < len; i++) {
/* Handling strings is case of it's own */
if (config.sort[i] == 'n') {
ret =
strcmp(left->shared_net->name,
right->shared_net->name);
if (0 < ret)
return (0);
if (ret < 0)
return (1);
continue;
}
if (0 < ret)
return (0);
if (ret < 0)
/* Select which function is pointed by comparer */
comparer = field_selector(config.sort[i]);
cmp = comparer(left, right);
/* If fields are equal use next sort method */
if (cmp == 0) {
continue;
}
if (cmp < 0) {
return (1);
}
return (0);
}
/* this is reached if nothing was sorted */
/* If all comparers where equal */
return (0);
}
/*! \brief Mergesort for range table.
* \param orig Pointer to range that is requested to be sorted.
* \param size Number of ranges to be sorted.
* \param temp Temporary memory space, needed when a values has to be
* flipped.
*/
void mergesort_ranges(struct conf_t *state, struct range_t *restrict orig, unsigned int size,
struct range_t *restrict temp, const int root_call)
void mergesort_ranges(struct range_t *restrict orig, int size,
struct range_t *restrict temp)
{
unsigned int left, i, u_right;
int left, right, i;
struct range_t hold;
/* Merge sort split size */
static const unsigned int MIN_MERGE_SIZE = 8;
if (temp == NULL)
temp = xmalloc(sizeof(struct range_t) * size);
static const int MIN_MERGE_SIZE = 8;
if (size < MIN_MERGE_SIZE) {
for (left = 0; left < size; left++) {
int s_right;
hold = *(orig + left);
for (s_right = left - 1; 0 <= s_right; s_right--) {
if (merge(state, (orig + s_right), &hold))
for (right = left - 1; 0 <= right; right--) {
if (merge((orig + right), &hold)) {
break;
*(orig + s_right + 1) = *(orig + s_right);
}
*(orig + right + 1) = *(orig + right);
}
*(orig + s_right + 1) = hold;
*(orig + right + 1) = hold;
}
if (root_call)
free(temp);
return;
}
mergesort_ranges(state, orig, size / 2, temp, 0);
mergesort_ranges(state, orig + size / 2, size - size / 2, temp, 0);
mergesort_ranges(orig, size / 2, temp);
mergesort_ranges(orig + size / 2, size - size / 2, temp);
left = 0;
u_right = size / 2;
right = size / 2;
i = 0;
while (left < size / 2 && u_right < size) {
if (merge(state, (orig + left), (orig + u_right))) {
while (left < size / 2 && right < size) {
if (merge((orig + left), (orig + right))) {
*(temp + i) = *(orig + left);
left++;
} else {
*(temp + i) = *(orig + u_right);
u_right++;
*(temp + i) = *(orig + right);
right++;
}
i++;
}
@ -329,13 +313,11 @@ void mergesort_ranges(struct conf_t *state, struct range_t *restrict orig, unsig
left++;
i++;
}
while (u_right < size) {
*(temp + i) = *(orig + u_right);
u_right++;
while (right < size) {
*(temp + i) = *(orig + right);
right++;
i++;
}
memcpy(orig, temp, size * sizeof(struct range_t));
if (root_call)
free(temp);
memcpy(orig, temp, size * sizeof(struct range_t));
}

View file

@ -1,5 +1,4 @@
TESTS = \
tests/alarm-count-option \
tests/alarm-critical \
tests/alarm-critical-ranges \
tests/alarm-critical-snets \
@ -9,38 +8,15 @@ TESTS = \
tests/alarm-warning \
tests/alarm-warning-ranges \
tests/alarm-warning-snets \
tests/shnet-alarm \
tests/big-small \
tests/binding-states \
tests/bootp \
tests/cidr-v4 \
tests/cidr-v6 \
tests/complete \
tests/complete-perfdata \
tests/empty \
tests/errors \
tests/full-json \
tests/full-xml \
tests/formats \
tests/leading0 \
tests/one-ip \
tests/one-line \
tests/parser \
tests/range4 \
tests/range6 \
tests/same-twice \
tests/shufled \
tests/simple \
tests/skip \
tests/sorts \
tests/statuses \
tests/v6 \
tests/v6-perfdata
if ENABLE_MUSTACH
TESTS += \
tests/mustach
endif
tests/v6
EXTRA_DIST += \
tests/confs \

View file

@ -1,44 +0,0 @@
#!/bin/sh
#
# Alarm warning both ranges and shared networks.
IAM=$(basename $0)
if [ ! -d tests/outputs ]; then
mkdir tests/outputs
fi
echo '== warn count ==' > tests/outputs/$IAM
dhcpd-pools --config $top_srcdir/tests/confs/complete --leases $top_srcdir/tests/leases/complete \
--color=never --warning=40 --warn-count=20 --output=tests/outputs/$IAM-too
echo $? >> tests/outputs/$IAM-too
cat tests/outputs/$IAM-too >> tests/outputs/$IAM
echo '== crit count ==' >> tests/outputs/$IAM
dhcpd-pools --config $top_srcdir/tests/confs/complete --leases $top_srcdir/tests/leases/complete \
--color=never --critical=40 --crit-count=20 --output=tests/outputs/$IAM-too
echo $? >> tests/outputs/$IAM-too
cat tests/outputs/$IAM-too >> tests/outputs/$IAM
echo '== minsize ==' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--color=never --warning=40 --warn-count=20 --minsize=40 -o tests/outputs/$IAM-too
echo $? >> tests/outputs/$IAM-too
cat tests/outputs/$IAM-too >> tests/outputs/$IAM
echo '== snet alarms ==' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--color=never --warning=40 --snet-alarms -o tests/outputs/$IAM-too
echo $? >> tests/outputs/$IAM-too
cat tests/outputs/$IAM-too >> tests/outputs/$IAM
echo '== shared net count alarms ==' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--color=always --format t --crit-count=20 --critical=0 --warning=0 --warn-count=24 \
--output=tests/outputs/$IAM-too
echo $? >> tests/outputs/$IAM-too
cat tests/outputs/$IAM-too >> tests/outputs/$IAM
rm -f tests/outputs/$IAM-too
diff -u $top_srcdir/tests/expected/$IAM tests/outputs/$IAM
exit $?

View file

@ -1 +0,0 @@
test.sh

View file

@ -1,14 +0,0 @@
#!/bin/sh
#
# Minimal regression test suite.
IAM=$(basename $0)
if [ ! -d tests/outputs ]; then
mkdir tests/outputs
fi
dhcpd-pools -c $top_srcdir/tests/confs/$IAM --color=never \
-l $top_srcdir/tests/leases/$IAM -o tests/outputs/$IAM
diff -u $top_srcdir/tests/expected/$IAM tests/outputs/$IAM
exit $?

View file

@ -1 +0,0 @@
test.sh

View file

@ -1 +0,0 @@
test.sh

View file

@ -1,16 +0,0 @@
#!/bin/sh
#
# Minimal regression test suite.
IAM=$(basename $0)
TESTDATA=${IAM%-*}
if [ ! -d tests/outputs ]; then
mkdir tests/outputs
fi
dhcpd-pools -c $top_srcdir/tests/confs/$TESTDATA \
-l $top_srcdir/tests/leases/$TESTDATA -o tests/outputs/$IAM \
--warning 80 --perfdata
diff -u $top_srcdir/tests/expected/$IAM tests/outputs/$IAM
exit $?

View file

@ -1,5 +0,0 @@
subnet 10.0.0.0 netmask 255.255.255.0 {
pool {
range 10.0.0.10 10.0.0.1;
}
}

View file

@ -1 +0,0 @@
complete

View file

@ -1,31 +0,0 @@
shared-network example1 {
subnet 10.0.0.0 netmask 255.255.255.0 {
pool {
range 10.0.0.1/27;
}
}
subnet 10.1.0.0 netmask 255.255.255.0 {
pool {
range 10.1.0.1/27;
}
}
}
shared-network example2 {
subnet 10.2.0.0 netmask 255.255.255.0 {
pool {
range 10.2.0.1/27;
}
}
subnet 10.3.0.0 netmask 255.255.255.0 {
pool {
range 10.3.0.1/27;
}
}
}
subnet 10.4.0.0 netmask 255.255.255.0 {
pool {
range 10.4.0.1/28;
}
}

View file

@ -1,10 +0,0 @@
subnet6 dead:abba:1000::/56 {
range6 dead:abba:1000::2/120;
prefix6 dead:abba:1000:0100:: dead:abba:1000:ff00::/56;
}
subnet6 dead:abba:40ff::/56 {
range6 dead:abba:4000::2/120;
prefix6 dead:abba:4000:0100:: dead:abba:4000:ff00::/56;
}

View file

@ -1 +0,0 @@
complete

View file

@ -1 +0,0 @@
pool {range 10.0.0.1 10.0.0.5;range 10.0.0.6 10.0.0.10;}

View file

@ -1,31 +0,0 @@
shared-network example1 {
subnet 10.0.0.0 netmask 255.255.255.0 {
pool {
range 10.0.0.0/27;
}
}
subnet 10.1.0.0 netmask 255.255.255.0 {
pool {
range 10.1.0.1/27;
}
}
}
shared-network example2 {
subnet 10.2.0.0 netmask 255.255.255.0 {
pool {
range 10.2.0.1/28;
}
}
subnet 10.3.0.0 netmask 255.255.255.0 {
pool {
range 10.3.0.1/29;
}
}
}
subnet 10.4.0.0 netmask 255.255.255.0 {
pool {
range 10.4.0.1/32;
}
}

View file

@ -1,4 +0,0 @@
subnet6 dead:abba:1000::/56 {
range6 dead:abba:1000::/56;
prefix6 dead:abba:1000:0100:: dead:abba:1000:ff00::/56;
}

View file

@ -1 +0,0 @@
complete

View file

@ -1 +0,0 @@
complete

View file

@ -1 +0,0 @@
complete

View file

@ -1,48 +0,0 @@
#!/bin/sh
#
# Test error inputs.
IAM=$(basename $0)
if [ ! -d tests/outputs ]; then
mkdir tests/outputs
fi
echo '=== output mask' >| tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
-L 88 >> tests/outputs/$IAM 2>&1
echo '=== unknown specifier' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--skip=okish >> tests/outputs/$IAM 2>&1
echo '=== color mode' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--color=sometimes >> tests/outputs/$IAM 2>&1
echo '=== IPv5' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--ip-version=5 >> tests/outputs/$IAM 2>&1
echo '=== missing conf' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete_NXFILE -l $top_srcdir/tests/leases/complete 2>&1 | \
sed 's/: ..\/..\/tests/: .\/tests/'>> tests/outputs/$IAM
echo '=== missing leases' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete_NXFILE 2>&1 | \
sed 's/: ..\/..\/tests/: .\/tests/' >> tests/outputs/$IAM
echo '=== html table' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--format=html >> tests/outputs/$IAM 2>&1
echo '=== none existing format' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
-fz >> tests/outputs/$IAM 2>&1
echo '=== broken percent input' >> tests/outputs/$IAM
dhcpd-pools -c $top_srcdir/tests/confs/complete -l $top_srcdir/tests/leases/complete \
--warning=eighty >> tests/outputs/$IAM 2>&1
diff -u $top_srcdir/tests/expected/$IAM tests/outputs/$IAM
exit $?

View file

@ -1,34 +0,0 @@
== warn count ==
WARNING: dhcpd-pools: Ranges - crit: 0 warn: 3 ok: 2; | range_crit=0 range_warn=3 range_ok=2
Shared nets - crit: 0 warn: 1 ok: 1; | snet_crit=0 snet_warn=1 snet_ok=1
1
== crit count ==
CRITICAL: dhcpd-pools: Ranges - crit: 3 warn: 0 ok: 2; | range_crit=3 range_warn=0 range_ok=2
Shared nets - crit: 1 warn: 0 ok: 1; | snet_crit=1 snet_warn=0 snet_ok=1
2
== minsize ==
OK: Ranges - crit: 0 warn: 0 ok: 2 ignored: 3; | range_crit=0 range_warn=0 range_ok=2 range_ignored=3
Shared nets - crit: 0 warn: 0 ok: 0 ignored: 2; | snet_crit=0 snet_warn=0 snet_ok=0 snet_ignored=2
0
== snet alarms ==
WARNING: dhcpd-pools: Ranges - crit: 0 warn: 0 ok: 2; | range_crit=0 range_warn=0 range_ok=2
Shared nets - crit: 0 warn: 2 ok: 0; | snet_crit=0 snet_warn=2 snet_ok=0
1
== shared net count alarms ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0

View file

@ -1,3 +1,2 @@
CRITICAL: dhcpd-pools: Ranges - crit: 1 warn: 0 ok: 4; | range_crit=1 range_warn=0 range_ok=4
Shared nets - crit: 1 warn: 0 ok: 1; | snet_crit=1 snet_warn=0 snet_ok=1
CRITICAL: dhcpd-pools: Ranges; crit: 1 warn: 0 ok: 4 Shared nets; crit: 1 warn: 0 ok: 1
2

View file

@ -1,3 +1,2 @@
CRITICAL: dhcpd-pools: Ranges - crit: 1 warn: 0 ok: 4; | range_crit=1 range_warn=0 range_ok=4
CRITICAL: dhcpd-pools: Ranges; crit: 1 warn: 0 ok: 4
2

View file

@ -1,2 +1,2 @@
CRITICAL: dhcpd-pools: Shared nets - crit: 1 warn: 0 ok: 1; | snet_crit=1 snet_warn=0 snet_ok=1
CRITICAL: dhcpd-pools: Shared nets; crit: 1 warn: 0 ok: 1
2

View file

@ -1,2 +1 @@
OK: Ranges - crit: 0 warn: 0 ok: 0 ignored: 1; | range_crit=0 range_warn=0 range_ok=0 range_ignored=1
Shared nets - crit: 0 warn: 0 ok: 0; | snet_crit=0 snet_warn=0 snet_ok=0
OK: Ranges; crit: 0 warn: 0 ok: 0 ignored: 1 Shared nets; crit: 0 warn: 0 ok: 0

View file

@ -1,3 +1,2 @@
OK: Ranges - crit: 0 warn: 0 ok: 5; | range_crit=0 range_warn=0 range_ok=5
Shared nets - crit: 0 warn: 0 ok: 2; | snet_crit=0 snet_warn=0 snet_ok=2
OK: Ranges; crit: 0 warn: 0 ok: 5 Shared nets; crit: 0 warn: 0 ok: 2
0

View file

@ -1,2 +1,2 @@
OK: Shared nets - crit: 0 warn: 0 ok: 2; | snet_crit=0 snet_warn=0 snet_ok=2
OK: Shared nets; crit: 0 warn: 0 ok: 2
0

View file

@ -1,3 +1,2 @@
WARNING: dhcpd-pools: Ranges - crit: 0 warn: 1 ok: 4; | range_crit=0 range_warn=1 range_ok=4
Shared nets - crit: 0 warn: 1 ok: 1; | snet_crit=0 snet_warn=1 snet_ok=1
WARNING: dhcpd-pools: Ranges; crit: 0 warn: 1 ok: 4 Shared nets; crit: 0 warn: 1 ok: 1
1

View file

@ -1,3 +1,2 @@
WARNING: dhcpd-pools: Ranges - crit: 0 warn: 1 ok: 4; | range_crit=0 range_warn=1 range_ok=4
WARNING: dhcpd-pools: Ranges; crit: 0 warn: 1 ok: 4
1

View file

@ -1,2 +1,2 @@
WARNING: dhcpd-pools: Shared nets - crit: 0 warn: 1 ok: 1; | snet_crit=0 snet_warn=1 snet_ok=1
WARNING: dhcpd-pools: Shared nets; crit: 0 warn: 1 ok: 1
1

View file

@ -1 +0,0 @@
simple

View file

@ -1,16 +0,0 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc bu bu perc
example1 10.0.0.1 - 10.0.0.20 20 4 20.000 3 7 35.000 2 10.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000 0 0.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000 0 0.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000 0 0.000
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000 0 0.000
Shared networks:
name max cur percent touch t+c t+c perc bu bu perc
example1 40 14 35.000 3 17 42.500 2 5.000
example2 40 17 42.500 0 17 42.500 0 0.000
Sum of all ranges:
name max cur percent touch t+c t+c perc bu bu perc
All networks 100 36 36.000 3 39 39.000 2 2.000

View file

@ -1 +0,0 @@
simple

10
tests/expected/bootp Normal file
View file

@ -0,0 +1,10 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.0.0.1 - 10.0.0.10 10 10 100.000 0 10 100.000
Shared networks:
name max cur percent touch t+c t+c perc
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 10 10 100.000 0 10 100.000

View file

@ -1,16 +0,0 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
example1 10.0.0.1 - 10.0.0.31 31 11 35.484 0 11 35.484
example1 10.1.0.1 - 10.1.0.31 31 10 32.258 0 10 32.258
example2 10.2.0.1 - 10.2.0.31 31 8 25.806 0 8 25.806
example2 10.3.0.1 - 10.3.0.31 31 9 29.032 0 9 29.032
All networks 10.4.0.1 - 10.4.0.15 15 5 33.333 0 5 33.333
Shared networks:
name max cur percent touch t+c t+c perc
example1 62 21 33.871 0 21 33.871
example2 62 17 27.419 0 17 27.419
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 139 43 30.935 0 43 30.935

View file

@ -1,11 +0,0 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks dead:abba:1000::2 - dead:abba:1000::ff 254 0 0.000 0 0 0.000
All networks dead:abba:4000::2 - dead:abba:4000::ff 254 1 0.394 0 1 0.394
Shared networks:
name max cur percent touch t+c t+c perc
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 508 1 0.197 0 1 0.197

View file

@ -1,3 +0,0 @@
OK: Ranges - crit: 0 warn: 0 ok: 5; | range_crit=0 range_warn=0 range_ok=5 10.4.0.1_r=5;16;18;0;20 10.4.0.1_rt=0 10.3.0.1_r=9;16;18;0;20 10.3.0.1_rt=0 10.2.0.1_r=8;16;18;0;20 10.2.0.1_rt=0 10.1.0.1_r=10;16;18;0;20 10.1.0.1_rt=0 10.0.0.1_r=11;16;18;0;20 10.0.0.1_rt=0
Shared nets - crit: 0 warn: 0 ok: 2; | snet_crit=0 snet_warn=0 snet_ok=2 'example1_s'=21;32;36;0;40 'example1_st'=0 'example2_s'=17;32;36;0;40 'example2_st'=0

View file

@ -6,4 +6,4 @@ name max cur percent touch t+c t+c perc
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 0 0 nan 0 0 nan
All networks 0 0 -nan 0 0 -nan

View file

@ -1,27 +0,0 @@
=== output mask
dhcpd-pools: return_limit: output mask '88' is illegal
=== unknown specifier
dhcpd-pools: unknown --skip specifier: okish
=== color mode
dhcpd-pools: unknown color mode: 'sometimes'
=== IPv5
dhcpd-pools: unknown --ip-version argument: 5
=== missing conf
dhcpd-pools: cannot open inlude: ./tests/confs/complete_NXFILE: No such file or directory
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
Shared networks:
name max cur percent touch t+c t+c perc
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 0 0 nan 0 0 nan
=== missing leases
dhcpd-pools: parse_leases: ./tests/leases/complete_NXFILE: No such file or directory
=== html table
dhcpd-pools: html table only output format is deprecated
=== none existing format
dhcpd-pools: unknown output format: 'z'
=== broken percent input
dhcpd-pools: illegal argument: 'eighty'

View file

@ -1,284 +0,0 @@
=== color text
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
=== html
<!DOCTYPE html>
<html>
<head>
<title>ISC dhcpd dhcpd-pools output</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/dt-2.2.2/datatables.min.css">
<style type="text/css">
table.dhcpd-pools th { text-transform: capitalize }
</style>
</head>
<body>
<div class="container">
<h2>ISC DHCPD status</h2>
<h3>Sum of all</h3>
<table id="a" class="dhcpd-pools order-column table table-hover" summary="all">
<thead>
<tr>
<th>name</th>
<th>max</th>
<th>cur</th>
<th>free</th>
<th>percent</th>
<th>touch</th>
<th>t+c</th>
<th>t+c perc</th>
</tr>
</thead>
<tbody>
<tr>
<td>All networks</td>
<td>100</td>
<td>43</td>
<td>57</td>
<td>43.000</td>
<td>0</td>
<td>43</td>
<td>43.000</td>
</tr>
</tbody>
</table>
<h3>Shared networks</h3>
<table id="s" class="dhcpd-pools order-column table table-hover" summary="snet">
<thead>
<tr>
<th>name</th>
<th>max</th>
<th>cur</th>
<th>free</th>
<th>percent</th>
<th>touch</th>
<th>t+c</th>
<th>t+c perc</th>
</tr>
</thead>
<tbody>
<tr>
<td>example1</td>
<td>40</td>
<td>21</td>
<td>19</td>
<td>52.5</td>
<td>0</td>
<td>21</td>
<td>52.500</td>
</tr>
<tr>
<td>example2</td>
<td>40</td>
<td>17</td>
<td>23</td>
<td>42.5</td>
<td>0</td>
<td>17</td>
<td>42.500</td>
</tr>
</tbody>
</table>
<h3>Ranges</h3>
<table id="r" class="dhcpd-pools order-column table table-hover" summary="ranges">
<thead>
<tr>
<th>shared net name</th>
<th>first ip</th>
<th>last ip</th>
<th>max</th>
<th>cur</th>
<th>free</th>
<th>percent</th>
<th>touch</th>
<th>t+c</th>
<th>t+c perc</th>
</tr>
</thead>
<tbody>
<tr>
<td>example1</td>
<td>10.0.0.1</td>
<td>10.0.0.20</td>
<td>20</td>
<td>11</td>
<td>9</td>
<td>55</td>
<td>0</td>
<td>11</td>
<td>55.000</td>
</tr>
<tr>
<td>example1</td>
<td>10.1.0.1</td>
<td>10.1.0.20</td>
<td>20</td>
<td>10</td>
<td>10</td>
<td>50</td>
<td>0</td>
<td>10</td>
<td>50.000</td>
</tr>
<tr>
<td>example2</td>
<td>10.2.0.1</td>
<td>10.2.0.20</td>
<td>20</td>
<td>8</td>
<td>12</td>
<td>40</td>
<td>0</td>
<td>8</td>
<td>40.000</td>
</tr>
<tr>
<td>example2</td>
<td>10.3.0.1</td>
<td>10.3.0.20</td>
<td>20</td>
<td>9</td>
<td>11</td>
<td>45</td>
<td>0</td>
<td>9</td>
<td>45.000</td>
</tr>
<tr>
<td>All networks</td>
<td>10.4.0.1</td>
<td>10.4.0.20</td>
<td>20</td>
<td>5</td>
<td>15</td>
<td>25</td>
<td>0</td>
<td>5</td>
<td>25.000</td>
</tr>
</tbody>
</table>
<br /><div class="well well-lg">
More info at <a href="https://dhcpd-pools.sourceforge.net/">https://dhcpd-pools.sourceforge.net/</a>
</small></div></div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/dt/dt-2.2.2/datatables.min.js"></script>
<script type="text/javascript" class="init">$(document).ready(function() { $('#s').DataTable({ "iDisplayLength": 50, "lengthMenu": [ [25, 50, 100, -1], [25, 50, 100, "All"] ], "order": [[ 4, "desc" ]] } ); } );</script>
<script type="text/javascript" class="init">$(document).ready(function() { $('#r').DataTable({ "iDisplayLength": 100, "lengthMenu": [ [25, 50, 100, -1], [25, 50, 100, "All"] ], "order": [[ 6, "desc" ]] } ); } );</script>
</body></html>
=== xml
<dhcpstatus>
<subnet>
<location>example1</location>
<range>10.0.0.1 - 10.0.0.20</range>
<defined>20</defined>
<used>11</used>
<touched>0</touched>
<free>9</free>
</subnet>
<subnet>
<location>example1</location>
<range>10.1.0.1 - 10.1.0.20</range>
<defined>20</defined>
<used>10</used>
<touched>0</touched>
<free>10</free>
</subnet>
<subnet>
<location>example2</location>
<range>10.2.0.1 - 10.2.0.20</range>
<defined>20</defined>
<used>8</used>
<touched>0</touched>
<free>12</free>
</subnet>
<subnet>
<location>example2</location>
<range>10.3.0.1 - 10.3.0.20</range>
<defined>20</defined>
<used>9</used>
<touched>0</touched>
<free>11</free>
</subnet>
<subnet>
<location>All networks</location>
<range>10.4.0.1 - 10.4.0.20</range>
<defined>20</defined>
<used>5</used>
<touched>0</touched>
<free>15</free>
</subnet>
<shared-network>
<location>example1</location>
<defined>40</defined>
<used>21</used>
<touched>0</touched>
<free>19</free>
</shared-network>
<shared-network>
<location>example2</location>
<defined>40</defined>
<used>17</used>
<touched>0</touched>
<free>23</free>
</shared-network>
<summary>
<location>All networks</location>
<defined>100</defined>
<used>43</used>
<touched>0</touched>
<free>57</free>
</summary>
</dhcpstatus>
=== csv
"Ranges:"
"shared net name","first ip","last ip","max","cur","percent","touch","t+c","t+c perc"
"example1","10.0.0.1","10.0.0.20","20","11","55.000","0","11","55.000"
"example1","10.1.0.1","10.1.0.20","20","10","50.000","0","10","50.000"
"example2","10.2.0.1","10.2.0.20","20","8","40.000","0","8","40.000"
"example2","10.3.0.1","10.3.0.20","20","9","45.000","0","9","45.000"
"All networks","10.4.0.1","10.4.0.20","20","5","25.000","0","5","25.000"
"Shared networks:"
"name","max","cur","percent","touch","t+c","t+c perc"
"example1","40","21","52.500","0","21","52.500"
"example2","40","17","42.500","0","17","42.500"
"Sum of all ranges:"
"name","max","cur","percent","touch","t+c","t+c perc"
"All networks","100","43","43.000","0","43","43.000"
=== json
{
"subnets": [
{ "location":"example1", "range":"10.0.0.1 - 10.0.0.20", "first_ip":"10.0.0.1", "last_ip":"10.0.0.20", "defined":20, "used":11, "touched":0, "free":9, "percent":55, "touch_count":11, "touch_percent":55, "status":0 },
{ "location":"example1", "range":"10.1.0.1 - 10.1.0.20", "first_ip":"10.1.0.1", "last_ip":"10.1.0.20", "defined":20, "used":10, "touched":0, "free":10, "percent":50, "touch_count":10, "touch_percent":50, "status":0 },
{ "location":"example2", "range":"10.2.0.1 - 10.2.0.20", "first_ip":"10.2.0.1", "last_ip":"10.2.0.20", "defined":20, "used":8, "touched":0, "free":12, "percent":40, "touch_count":8, "touch_percent":40, "status":0 },
{ "location":"example2", "range":"10.3.0.1 - 10.3.0.20", "first_ip":"10.3.0.1", "last_ip":"10.3.0.20", "defined":20, "used":9, "touched":0, "free":11, "percent":45, "touch_count":9, "touch_percent":45, "status":0 },
{ "location":"All networks", "range":"10.4.0.1 - 10.4.0.20", "first_ip":"10.4.0.1", "last_ip":"10.4.0.20", "defined":20, "used":5, "touched":0, "free":15, "percent":25, "touch_count":5, "touch_percent":25, "status":0 }
],
"shared-networks": [
{ "location":"example1", "defined":40, "used":21, "touched":0, "free":19, "percent":52.5, "touch_count":21, "touch_percent":52.5, "status":0 },
{ "location":"example2", "defined":40, "used":17, "touched":0, "free":23, "percent":42.5, "touch_count":17, "touch_percent":42.5, "status":0 }
]
}
=== perfdata
CRITICAL: dhcpd-pools: Ranges - crit: 3 warn: 2 ok: 0; | range_crit=3 range_warn=2 range_ok=0 10.4.0.1_r=5;4;8;0;20 10.4.0.1_rt=0 10.3.0.1_r=9;4;8;0;20 10.3.0.1_rt=0 10.2.0.1_r=8;4;8;0;20 10.2.0.1_rt=0 10.1.0.1_r=10;4;8;0;20 10.1.0.1_rt=0 10.0.0.1_r=11;4;8;0;20 10.0.0.1_rt=0
Shared nets - crit: 2 warn: 0 ok: 0; | snet_crit=2 snet_warn=0 snet_ok=0 'example1_s'=21;8;16;0;40 'example1_st'=0 'example2_s'=17;8;16;0;40 'example2_st'=0

View file

@ -1,317 +0,0 @@
Ethernets:
macaddress: 00:00:00:00:00:01 ip: 10.0.0.1
macaddress: 00:00:00:00:00:02 ip: 10.0.0.2
macaddress: 00:00:00:00:00:03 ip: 10.0.0.3
macaddress: 00:00:00:00:00:04 ip: 10.0.0.4
macaddress: 00:00:00:00:00:05 ip: 10.0.0.5
macaddress: 00:00:00:00:00:06 ip: 10.0.0.6
macaddress: 00:00:00:00:00:07 ip: 10.0.0.7
macaddress: 00:00:00:00:00:08 ip: 10.0.0.8
macaddress: 00:00:00:00:00:09 ip: 10.0.0.9
macaddress: 00:00:00:00:00:10 ip: 10.0.0.10
macaddress: 00:00:00:00:00:11 ip: 10.0.0.11
macaddress: 00:00:00:00:00:12 ip: 10.0.0.12
macaddress: 00:00:00:00:01:00 ip: 10.1.0.0
macaddress: 00:00:00:00:01:01 ip: 10.1.0.1
macaddress: 00:00:00:00:01:02 ip: 10.1.0.2
macaddress: 00:00:00:00:01:03 ip: 10.1.0.3
macaddress: 00:00:00:00:01:04 ip: 10.1.0.4
macaddress: 00:00:00:00:01:05 ip: 10.1.0.5
macaddress: 00:00:00:00:01:06 ip: 10.1.0.6
macaddress: 00:00:00:00:01:07 ip: 10.1.0.7
macaddress: 00:00:00:00:01:08 ip: 10.1.0.8
macaddress: 00:00:00:00:01:09 ip: 10.1.0.9
macaddress: 00:00:00:00:01:10 ip: 10.1.0.10
macaddress: 00:00:00:00:02:00 ip: 10.2.0.0
macaddress: 00:00:00:00:02:01 ip: 10.2.0.1
macaddress: 00:00:00:00:02:02 ip: 10.2.0.2
macaddress: 00:00:00:00:02:03 ip: 10.2.0.3
macaddress: 00:00:00:00:02:04 ip: 10.2.0.4
macaddress: 00:00:00:00:02:05 ip: 10.2.0.5
macaddress: 00:00:00:00:02:06 ip: 10.2.0.6
macaddress: 00:00:00:00:02:07 ip: 10.2.0.7
macaddress: 00:00:00:00:02:08 ip: 10.2.0.8
macaddress: 00:00:00:00:03:00 ip: 10.3.0.0
macaddress: 00:00:00:00:03:01 ip: 10.3.0.1
macaddress: 00:00:00:00:03:02 ip: 10.3.0.2
macaddress: 00:00:00:00:03:03 ip: 10.3.0.3
macaddress: 00:00:00:00:03:04 ip: 10.3.0.4
macaddress: 00:00:00:00:03:05 ip: 10.3.0.5
macaddress: 00:00:00:00:03:06 ip: 10.3.0.6
macaddress: 00:00:00:00:03:07 ip: 10.3.0.7
macaddress: 00:00:00:00:03:08 ip: 10.3.0.8
macaddress: 00:00:00:00:03:09 ip: 10.3.0.9
macaddress: 00:00:00:00:04:00 ip: 10.4.0.0
macaddress: 00:00:00:00:04:01 ip: 10.4.0.1
macaddress: 00:00:00:00:04:02 ip: 10.4.0.2
macaddress: 00:00:00:00:04:03 ip: 10.4.0.3
macaddress: 00:00:00:00:04:04 ip: 10.4.0.4
macaddress: 00:00:00:00:04:05 ip: 10.4.0.5
macaddress: 00:00:00:00:04:06 ip: 10.4.0.6
Subnets:
location: example1
range: 10.0.0.1 - 10.0.0.20
first_ip: 10.0.0.1
last_ip: 10.0.0.20
used: 11
touched: 0
defined: 20
free: 9
percent: 55
touch_count: 11
touch_percent: 55
backup_count: 1
backup_percent: 5
status: 0
location: example1
range: 10.1.0.1 - 10.1.0.20
first_ip: 10.1.0.1
last_ip: 10.1.0.20
used: 10
touched: 0
defined: 20
free: 10
percent: 50
touch_count: 10
touch_percent: 50
backup_count: 0
backup_percent: 0
status: 0
location: example2
range: 10.2.0.1 - 10.2.0.20
first_ip: 10.2.0.1
last_ip: 10.2.0.20
used: 8
touched: 0
defined: 20
free: 12
percent: 40
touch_count: 8
touch_percent: 40
backup_count: 0
backup_percent: 0
status: 0
location: example2
range: 10.3.0.1 - 10.3.0.20
first_ip: 10.3.0.1
last_ip: 10.3.0.20
used: 9
touched: 0
defined: 20
free: 11
percent: 45
touch_count: 9
touch_percent: 45
backup_count: 0
backup_percent: 0
status: 0
location: All networks
range: 10.4.0.1 - 10.4.0.20
first_ip: 10.4.0.1
last_ip: 10.4.0.20
used: 5
touched: 0
defined: 20
free: 15
percent: 25
touch_count: 5
touch_percent: 25
backup_count: 1
backup_percent: 5
status: 0
Shared-networks:
location: example1
defined: 40
used: 21
touched: 0
free: 19
percent: 52.5
touch_count: 21
touch_percent: 52.5
backup_count: 1
backup_percent: 2.5
status: 0
location: example2
defined: 40
used: 17
touched: 0
free: 23
percent: 42.5
touch_count: 17
touch_percent: 42.5
backup_count: 0
backup_percent: 0
status: 0
Summary:
location: All networks
defined: 100
used: 43
touched: 0
free: 57
percent: 43
touch_count: 43
touch_percent: 43
backup_count: 2
backup_percent: 2
status: 0
number_of_ranges: 5
number_of_shared_networks: 2
number_of_ranges_warning: 0
number_of_ranges_critical: 0
number_of_shared_networks: 2
number_of_shared_networks_warning: 0
number_of_shared_networks_critical: 0
--- skip ok ---
Ethernets:
macaddress: 00:00:00:00:00:01 ip: 10.0.0.1
macaddress: 00:00:00:00:00:02 ip: 10.0.0.2
macaddress: 00:00:00:00:00:03 ip: 10.0.0.3
macaddress: 00:00:00:00:00:04 ip: 10.0.0.4
macaddress: 00:00:00:00:00:05 ip: 10.0.0.5
macaddress: 00:00:00:00:00:06 ip: 10.0.0.6
macaddress: 00:00:00:00:00:07 ip: 10.0.0.7
macaddress: 00:00:00:00:00:08 ip: 10.0.0.8
macaddress: 00:00:00:00:00:09 ip: 10.0.0.9
macaddress: 00:00:00:00:00:10 ip: 10.0.0.10
macaddress: 00:00:00:00:00:11 ip: 10.0.0.11
macaddress: 00:00:00:00:00:12 ip: 10.0.0.12
macaddress: 00:00:00:00:01:00 ip: 10.1.0.0
macaddress: 00:00:00:00:01:01 ip: 10.1.0.1
macaddress: 00:00:00:00:01:02 ip: 10.1.0.2
macaddress: 00:00:00:00:01:03 ip: 10.1.0.3
macaddress: 00:00:00:00:01:04 ip: 10.1.0.4
macaddress: 00:00:00:00:01:05 ip: 10.1.0.5
macaddress: 00:00:00:00:01:06 ip: 10.1.0.6
macaddress: 00:00:00:00:01:07 ip: 10.1.0.7
macaddress: 00:00:00:00:01:08 ip: 10.1.0.8
macaddress: 00:00:00:00:01:09 ip: 10.1.0.9
macaddress: 00:00:00:00:01:10 ip: 10.1.0.10
macaddress: 00:00:00:00:02:00 ip: 10.2.0.0
macaddress: 00:00:00:00:02:01 ip: 10.2.0.1
macaddress: 00:00:00:00:02:02 ip: 10.2.0.2
macaddress: 00:00:00:00:02:03 ip: 10.2.0.3
macaddress: 00:00:00:00:02:04 ip: 10.2.0.4
macaddress: 00:00:00:00:02:05 ip: 10.2.0.5
macaddress: 00:00:00:00:02:06 ip: 10.2.0.6
macaddress: 00:00:00:00:02:07 ip: 10.2.0.7
macaddress: 00:00:00:00:02:08 ip: 10.2.0.8
macaddress: 00:00:00:00:03:00 ip: 10.3.0.0
macaddress: 00:00:00:00:03:01 ip: 10.3.0.1
macaddress: 00:00:00:00:03:02 ip: 10.3.0.2
macaddress: 00:00:00:00:03:03 ip: 10.3.0.3
macaddress: 00:00:00:00:03:04 ip: 10.3.0.4
macaddress: 00:00:00:00:03:05 ip: 10.3.0.5
macaddress: 00:00:00:00:03:06 ip: 10.3.0.6
macaddress: 00:00:00:00:03:07 ip: 10.3.0.7
macaddress: 00:00:00:00:03:08 ip: 10.3.0.8
macaddress: 00:00:00:00:03:09 ip: 10.3.0.9
macaddress: 00:00:00:00:04:00 ip: 10.4.0.0
macaddress: 00:00:00:00:04:01 ip: 10.4.0.1
macaddress: 00:00:00:00:04:02 ip: 10.4.0.2
macaddress: 00:00:00:00:04:03 ip: 10.4.0.3
macaddress: 00:00:00:00:04:04 ip: 10.4.0.4
macaddress: 00:00:00:00:04:05 ip: 10.4.0.5
macaddress: 00:00:00:00:04:06 ip: 10.4.0.6
Subnets:
location: example1
range: 10.0.0.1 - 10.0.0.20
first_ip: 10.0.0.1
last_ip: 10.0.0.20
used: 11
touched: 0
defined: 20
free: 9
percent: 55
touch_count: 11
touch_percent: 55
backup_count: 1
backup_percent: 5
status: 1
location: example1
range: 10.1.0.1 - 10.1.0.20
first_ip: 10.1.0.1
last_ip: 10.1.0.20
used: 10
touched: 0
defined: 20
free: 10
percent: 50
touch_count: 10
touch_percent: 50
backup_count: 0
backup_percent: 0
status: 1
location: example2
range: 10.3.0.1 - 10.3.0.20
first_ip: 10.3.0.1
last_ip: 10.3.0.20
used: 9
touched: 0
defined: 20
free: 11
percent: 45
touch_count: 9
touch_percent: 45
backup_count: 0
backup_percent: 0
status: 1
Shared-networks:
location: example1
defined: 40
used: 21
touched: 0
free: 19
percent: 52.5
touch_count: 21
touch_percent: 52.5
backup_count: 1
backup_percent: 2.5
status: 1
Summary:
location: All networks
defined: 100
used: 43
touched: 0
free: 57
percent: 43
touch_count: 43
touch_percent: 43
backup_count: 2
backup_percent: 2
status: 0
number_of_ranges: 5
number_of_shared_networks: 2
number_of_ranges_warning: 3
number_of_ranges_critical: 0
number_of_shared_networks: 2
number_of_shared_networks_warning: 1
number_of_shared_networks_critical: 0

View file

@ -1,11 +0,0 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.0.0.1 - 10.0.0.5 5 5 100.000 0 5 100.000
All networks 10.0.0.6 - 10.0.0.10 5 5 100.000 0 5 100.000
Shared networks:
name max cur percent touch t+c t+c perc
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 10 10 100.000 0 10 100.000

View file

@ -1 +0,0 @@
complete

View file

@ -1,16 +0,0 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
example1 10.0.0.0 - 10.0.0.31 32 12 37.500 0 12 37.500
example1 10.1.0.1 - 10.1.0.31 31 10 32.258 0 10 32.258
example2 10.2.0.1 - 10.2.0.15 15 8 53.333 0 8 53.333
example2 10.3.0.1 - 10.3.0.7 7 7 100.000 0 7 100.000
All networks 10.4.0.1 - 10.4.0.1 1 1 100.000 0 1 100.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 63 22 34.921 0 22 34.921
example2 22 15 68.182 0 15 68.182
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 86 38 44.186 0 38 44.186

View file

@ -1,10 +0,0 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks dead:abba:1000:: - dead:abba:1000:ff:ffff:ffff:ffff:ffff 4.72237e+21 2 0.000 1 3 0.000
Shared networks:
name max cur percent touch t+c t+c perc
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 4.72237e+21 2 0.000 1 3 0.000

View file

@ -1,9 +1,9 @@
{
"active_leases": [
{ "ip":"10.0.0.5", "macaddress":"00:00:00:00:00:00", "starts":"", "ends":"", "hostname":"" }
{ "ip":"10.0.0.5", "macaddress":"00:00:00:00:00:00" }
],
"subnets": [
{ "location":"All networks", "range":"10.0.0.1 - 10.0.0.10", "first_ip":"10.0.0.1", "last_ip":"10.0.0.10", "defined":10, "used":1, "touched":0, "free":9, "percent":10, "touch_count":1, "touch_percent":10, "status":0 }
{ "location":"All networks", "range":"10.0.0.1 - 10.0.0.10", "defined":10, "used":1, "free":9 }
],
"shared-networks": [
],
@ -11,13 +11,6 @@
"location":"All networks",
"defined":10,
"used":1,
"touched":0,
"free":9,
"percent":10,
"touch_count":1,
"touch_percent":10,
"status":0
},
"trivia": {
"free":9
}
}

View file

@ -1,24 +0,0 @@
<dhcpstatus>
<active_lease>
<ip>10.0.0.5</ip>
<macaddress>00:00:00:00:00:00</macaddress>
<starts></starts>
<ends></ends>
<hostname></hostname>
</active_lease>
<subnet>
<location>All networks</location>
<range>10.0.0.1 - 10.0.0.10</range>
<defined>10</defined>
<used>1</used>
<touched>0</touched>
<free>9</free>
</subnet>
<summary>
<location>All networks</location>
<defined>10</defined>
<used>1</used>
<touched>0</touched>
<free>9</free>
</summary>
</dhcpstatus>

View file

@ -1,3 +0,0 @@
CRITICAL: dhcpd-pools: Ranges - crit: 2 warn: 0 ok: 3; | range_crit=2 range_warn=0 range_ok=3
Shared nets - crit: 1 warn: 0 ok: 1; | snet_crit=1 snet_warn=0 snet_ok=1
2

View file

@ -1,16 +0,0 @@
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 3 15.000 0 3 15.000
example1 10.0.0.1 - 10.0.0.20 20 9 45.000 0 9 45.000
example1 10.1.0.1 - 10.1.0.20 20 4 20.000 0 4 20.000
example2 10.2.0.1 - 10.2.0.20 20 4 20.000 0 4 20.000
example2 10.3.0.1 - 10.3.0.20 20 3 15.000 0 3 15.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 13 32.500 0 13 32.500
example2 40 7 17.500 0 7 17.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 23 23.000 0 23 23.000

View file

@ -1,80 +0,0 @@
--- skip ok ---
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc bu bu perc
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000 1 5.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000 0 0.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000 0 0.000
Shared networks:
name max cur percent touch t+c t+c perc bu bu perc
example1 40 21 52.500 0 21 52.500 1 2.500
Sum of all ranges:
name max cur percent touch t+c t+c perc bu bu perc
All networks 100 43 43.000 0 43 43.000 2 2.000
--- skip warning ---
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc bu bu perc
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000 1 5.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000 0 0.000
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000 1 5.000
Shared networks:
name max cur percent touch t+c t+c perc bu bu perc
example1 40 21 52.500 0 21 52.500 1 2.500
example2 40 17 42.500 0 17 42.500 0 0.000
Sum of all ranges:
name max cur percent touch t+c t+c perc bu bu perc
All networks 100 43 43.000 0 43 43.000 2 2.000
--- skip critical ok ---
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc bu bu perc
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000 0 0.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000 0 0.000
Shared networks:
name max cur percent touch t+c t+c perc bu bu perc
Sum of all ranges:
name max cur percent touch t+c t+c perc bu bu perc
All networks 100 43 43.000 0 43 43.000 2 2.000
--- skip suppressed ---
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc bu bu perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000 1 5.000
Shared networks:
name max cur percent touch t+c t+c perc bu bu perc
example1 40 21 52.500 0 21 52.500 1 2.500
example2 40 17 42.500 0 17 42.500 0 0.000
Sum of all ranges:
name max cur percent touch t+c t+c perc bu bu perc
All networks 100 43 43.000 0 43 43.000 2 2.000
--- skip minsize ---
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc bu bu perc
Shared networks:
name max cur percent touch t+c t+c perc bu bu perc
example1 40 21 52.500 0 21 52.500 1 2.500
example2 40 17 42.500 0 17 42.500 0 0.000
Sum of all ranges:
name max cur percent touch t+c t+c perc bu bu perc
All networks 100 43 43.000 0 43 43.000 2 2.000
--- skip count ok ---
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc bu bu perc
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000 1 5.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000 0 0.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000 0 0.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000 0 0.000
Shared networks:
name max cur percent touch t+c t+c perc bu bu perc
Sum of all ranges:
name max cur percent touch t+c t+c perc bu bu perc
All networks 100 43 43.000 0 43 43.000 2 2.000

View file

@ -1,168 +0,0 @@
== name ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
== ip ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
== maximum ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
== current ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
1
== percent ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
1
1
== touched ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
== t+c ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
== t+c perc ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
== reverse ==
Ranges:
shared net name first ip last ip max cur percent touch t+c t+c perc
All networks 10.4.0.1 - 10.4.0.20 20 5 25.000 0 5 25.000
example2 10.3.0.1 - 10.3.0.20 20 9 45.000 0 9 45.000
example2 10.2.0.1 - 10.2.0.20 20 8 40.000 0 8 40.000
example1 10.1.0.1 - 10.1.0.20 20 10 50.000 0 10 50.000
example1 10.0.0.1 - 10.0.0.20 20 11 55.000 0 11 55.000
Shared networks:
name max cur percent touch t+c t+c perc
example1 40 21 52.500 0 21 52.500
example2 40 17 42.500 0 17 42.500
Sum of all ranges:
name max cur percent touch t+c t+c perc
All networks 100 43 43.000 0 43 43.000
0
== broken ==
dhcpd-pools: field_selector: unknown sort order: 'x'
1

View file

@ -1,29 +0,0 @@
{
"subnets": [
{ "location":"example1", "range":"10.0.0.1 - 10.0.0.20", "first_ip":"10.0.0.1", "last_ip":"10.0.0.20", "defined":20, "used":11, "touched":0, "free":9, "percent":55, "touch_count":11, "touch_percent":55, "status":4 },
{ "location":"example1", "range":"10.1.0.1 - 10.1.0.20", "first_ip":"10.1.0.1", "last_ip":"10.1.0.20", "defined":20, "used":10, "touched":0, "free":10, "percent":50, "touch_count":10, "touch_percent":50, "status":4 },
{ "location":"example2", "range":"10.2.0.1 - 10.2.0.20", "first_ip":"10.2.0.1", "last_ip":"10.2.0.20", "defined":20, "used":8, "touched":0, "free":12, "percent":40, "touch_count":8, "touch_percent":40, "status":4 },
{ "location":"example2", "range":"10.3.0.1 - 10.3.0.20", "first_ip":"10.3.0.1", "last_ip":"10.3.0.20", "defined":20, "used":9, "touched":0, "free":11, "percent":45, "touch_count":9, "touch_percent":45, "status":4 },
{ "location":"10.4.0.0/24", "range":"10.4.0.1 - 10.4.0.20", "first_ip":"10.4.0.1", "last_ip":"10.4.0.20", "defined":20, "used":5, "touched":0, "free":15, "percent":25, "touch_count":5, "touch_percent":25, "status":4 }
],
"shared-networks": [
{ "location":"example1", "defined":40, "used":21, "touched":0, "free":19, "percent":52.5, "touch_count":21, "touch_percent":52.5, "status":2 },
{ "location":"example2", "defined":40, "used":17, "touched":0, "free":23, "percent":42.5, "touch_count":17, "touch_percent":42.5, "status":2 },
{ "location":"10.4.0.0/24", "defined":20, "used":5, "touched":0, "free":15, "percent":25, "touch_count":5, "touch_percent":25, "status":1 }
]
}
== minsize
{
"subnets": [
{ "location":"example1", "range":"10.0.0.1 - 10.0.0.20", "first_ip":"10.0.0.1", "last_ip":"10.0.0.20", "defined":20, "used":11, "touched":0, "free":9, "percent":55, "touch_count":11, "touch_percent":55, "status":3 },
{ "location":"example1", "range":"10.1.0.1 - 10.1.0.20", "first_ip":"10.1.0.1", "last_ip":"10.1.0.20", "defined":20, "used":10, "touched":0, "free":10, "percent":50, "touch_count":10, "touch_percent":50, "status":3 },
{ "location":"example2", "range":"10.2.0.1 - 10.2.0.20", "first_ip":"10.2.0.1", "last_ip":"10.2.0.20", "defined":20, "used":8, "touched":0, "free":12, "percent":40, "touch_count":8, "touch_percent":40, "status":3 },
{ "location":"example2", "range":"10.3.0.1 - 10.3.0.20", "first_ip":"10.3.0.1", "last_ip":"10.3.0.20", "defined":20, "used":9, "touched":0, "free":11, "percent":45, "touch_count":9, "touch_percent":45, "status":3 },
{ "location":"10.4.0.0/24", "range":"10.4.0.1 - 10.4.0.20", "first_ip":"10.4.0.1", "last_ip":"10.4.0.20", "defined":20, "used":5, "touched":0, "free":15, "percent":25, "touch_count":5, "touch_percent":25, "status":3 }
],
"shared-networks": [
{ "location":"example1", "defined":40, "used":21, "touched":0, "free":19, "percent":52.5, "touch_count":21, "touch_percent":52.5, "status":2 },
{ "location":"example2", "defined":40, "used":17, "touched":0, "free":23, "percent":42.5, "touch_count":17, "touch_percent":42.5, "status":2 },
{ "location":"10.4.0.0/24", "defined":20, "used":5, "touched":0, "free":15, "percent":25, "touch_count":5, "touch_percent":25, "status":3 }
]
}

Some files were not shown because too many files have changed in this diff Show more