Compare commits

..

224 commits

Author SHA1 Message Date
Sami Kerola
1722d54103
chore: update web pages
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2025-04-28 15:32:04 +01:00
Sami Kerola
1c413b0653
release: 3.3
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2025-04-28 14:36:52 +01:00
Sami Kerola
d020e4d09f
output: update html javascripts
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2025-04-28 14:33:35 +01:00
Sami Kerola
f917d5b223
build-sys: update bootstrap from gnulib
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2025-04-28 14:33:26 +01:00
Sami Kerola
5b7ab28314
build-sys: quote subshell execution in the autotools file
Ryan discovered a typo/issue while handling the man targets.  This change
fixes the issue.

Reported-by: Ryan Steinmetz <zi@freebsd.org>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2025-04-28 14:22:56 +01:00
Belkacem Daheb
dc649e27cd
getdata output: add start, end and hostname printing support for xml and json
Ensure strings are always null terminated.
2024-08-09 12:51:20 +01:00
luisδμ
7fc13c60e0
fix: avoid generation of unvalid JSON in summary
This can happen when there are no available shared networks.  A division by
zero throws 'nan', which is non JSON-valid unless it's surrounded by double
quotes.
2024-08-09 12:30:49 +01:00
Sami Kerola
5ed6e7688f
gnulib: update bootstrap and gitignore files
And it turns out mustach.c will not compile without config.h being
explicitly included before other headers, so let me do that.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2024-08-09 12:06:22 +01:00
M. van Brummelen
9c6336e5b6
docs: fix manual page groff warning
The only thing the change does is the way the manpage gets parsed, and fixes
follwing warning.

"W: dhcpd-pools: groff-message an.tmac:<standard input>:147: warning: tbl
preprocessor failed, or it or soelim was not run; table(s) likely not
rendered (TE macro called with TW register undefined)
[usr/share/man/man1/dhcpd-pools.1.gz:1]"

Reference: https://www.mail-archive.com/debian-devel@lists.debian.org/msg377263.html
Signed-off-by: M. van Brummelen <mvb@debian.org>
Reviewed-by: Sami Kerola <kerolasa@iki.fi>
2024-08-09 11:00:02 +01:00
Sami Kerola
d94654e100
getdata: only emit warning when config include file cannot be read
Not being able to open primary config file will cause fatal error, where as
include files will only warn.  This is useful for setups that want to
publish some of the dhcp lease data, but not all.  Such setup obviously
required dhcpd server to have differnt account than dhcpd-pools, with
carefully managed read permissions.

Requested-by: Björn Lässig <b.laessig@pengutronix.de>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2024-01-28 16:07:56 +00:00
Sami Kerola
dc1f0b9b76
chore: update web links
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2023-09-02 11:55:16 +01:00
Belkacem Daheb
3d37ac0a2d
add start, end and hostname printing support for xml and json
In short it gets these parameters and prints them in json and xml formats.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2023-08-15 22:17:38 +01:00
Sami Kerola
102d017ed5
website: use https
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2023-03-26 11:15:36 +01:00
Sami Kerola
501bc15b43
update project web page
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2022-11-26 10:00:53 +00:00
Sami Kerola
0c5b8301dd
release: 3.2
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2022-06-04 12:42:00 +01:00
Sami Kerola
1d20604519
build-sys: routine update
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2022-06-04 12:40:39 +01:00
Sami Kerola
5126e63665
build-sys: autotools and gnulib related updates
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2021-09-05 15:52:07 +01:00
Sami Kerola
c7e0058994
config: remove unnecessary padding
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2021-09-05 15:51:29 +01:00
Sami Kerola
2ecfc86a06
build-sys: update .gitignore files
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2020-09-09 20:22:37 +01:00
Jean Benoit
0f19d44c1d
contrib: snmptest.pl SNMPwalk can't access to all variables/wrong sort
Large quantity of data will be missing when snmptest.pl is used.  The reason
is a sort in lexicographic order:

    $ snmpwalk -v2c -c public localhost .1.3.6.1.4.1.2021.250.255 |head
    iso.3.6.1.4.1.2021.250.255.2.1 = STRING:  "10.4.52.1"
    iso.3.6.1.4.1.2021.250.255.2.10 = STRING: "192.168.35.64"
    iso.3.6.1.4.1.2021.250.255.2.100 = STRING: "192.168.196.1"
    iso.3.6.1.4.1.2021.250.255.2.101 = STRING: "192.168.198.1"
    iso.3.6.1.4.1.2021.250.255.2.102 = STRING: "192.168.209.225"
    iso.3.6.1.4.1.2021.250.255.2.103 = STRING: "192.168.209.241"

SNMPGetNext after "root.2.1" should give "root.2.2".  Thus, lots of
variables are missing.

The function is now dependant on a CPAN module NetSNMP::OID, (debian/ubuntu
package is called libsnmp-perl).  This is probably not the most efficient
way to do it: walking the whole tree will be much slower.

Signed-off-by: Jean Benoit <jean@unistra.fr>
2020-09-04 19:38:17 +01:00
Sami Kerola
b005ce9a25
contrib: point out where one can find zabbix template
Thanks to Mathieu Morier for adding a Zabbix support.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2020-08-29 09:46:21 +01:00
Sami Kerola
45f7fc1514
release: 3.1
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2020-03-31 20:20:10 +01:00
Sami Kerola
ec613f762d
output: update javascripts
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2020-03-31 20:17:08 +01:00
Sami Kerola
e48768b041
build-sys: update bootstrap from gnulib
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2020-03-31 20:14:34 +01:00
Sami Kerola
544e7ec0a5
output: add ethernet address priting support to --mustach
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-10-26 22:23:19 +01:00
Sami Kerola
b96c6c14d2
misc: fix spelling issues
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-09-12 22:29:44 +01:00
Sami Kerola
21194d2e4a
samples: make prometheus template less klunky
This should work nicer when displaying various statistics from prometheus
with grafana.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-07-27 22:53:42 +01:00
Sami Kerola
fb518b7a19
output: add warning and critical threshold counts to mustach
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-07-27 22:20:44 +01:00
Sami Kerola
707eafa670
build-sys: update .gitignore files
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-07-27 21:17:45 +01:00
Mark Sangster
07b4eaa480
output: fix warn and crit counts on shared networks
The crit/warn_count is tested against used rather than free.  It is only for
shared networks, the range correctly subtracts count from size to get its
free.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-04-15 19:34:28 +01:00
Sami Kerola
17d68b7e3e
various: tidy up variable scopes, and one name mismatch
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-03-26 21:26:51 +00:00
Sami Kerola
4f64902a9e
mustach: sync with most recent mustach upstream changes
Git: https://gitlab.com/jobol/mustach.git
Commit: 3a694bdc6cdd374358a30949206e315ed3428cf9
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-03-26 21:00:40 +00:00
Sami Kerola
008e9f17c1
other: use IP string lengths from netinet/in.h
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-03-23 22:19:13 +00:00
Sami Kerola
71714a0993
warnings: ensure optimal packing in structures
Add padding where needed and order structure when it makes alignment fall
naturally to better order, with a single padding at the end of structure.

Reference: http://www.catb.org/esr/structure-packing/
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-02-17 11:43:02 +00:00
Sami Kerola
6f6369f517
various: fix few warnings
-Wmissing-variable-declarations -Wunreachable-code-break and -Wshadow.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-02-09 17:43:16 +00:00
Sami Kerola
8731c6a11f
fix typos
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-01-14 22:59:13 +00:00
Sami Kerola
d29b498cae
lib: update .gitignore
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-01-04 22:44:11 +00:00
Sami Kerola
48e46e8698
other: use strftime() to generate date-time string
It is better to use library function to create date-time string than sprintf
various struct tm members.  In same go retire time() call that is obsoleted
by clock_gettime().

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2019-01-04 22:44:07 +00:00
Sami Kerola
4befdeeb47
getdata: remote dead code
These few lines has been part of code without any point in releases 2.17 to
3.0 and six and half years.  Oops.

Reference: ae7747db87
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-10-26 22:01:26 +01:00
Sami Kerola
9727bb28b9
drop images, java scripts, and such from web sitemap file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-08-26 09:32:15 +01:00
Sami Kerola
5027b50ade
sort: ensure NaN will not trip over comp_double()
In unlikely event of NaN being compared avoid exception.  If NaN appears in
input data it will be evaluated as equal with any value.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-07-23 21:41:59 +01:00
Sami Kerola
27c70a0efe
fix switch missing default case warnings
src/other.c:387:3: warning: switch missing default case [-Wswitch-default]

The one in do_counting() should be unreachable, so add abort() call to it.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-07-23 21:33:45 +01:00
Sami Kerola
7fe686b417
webpages: use html sample output
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-05-20 15:54:58 +01:00
Sami Kerola
3f85360c64
main: move output_format to state, and rename color_format
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-05-20 12:03:07 +01:00
Sami Kerola
e8e9d49ebb
main: move print_mac_addreses to state structure
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-05-20 11:47:30 +01:00
Sami Kerola
4e7ab66fd4
fix typo
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-05-15 21:31:52 +01:00
Sami Kerola
b568725e7d
main: simplify option parsing
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-05-15 21:16:38 +01:00
Sami Kerola
a192f51545
output: fix implicit conversion
src/output.c:731:38: warning: implicit conversion from ‘float’ to ‘double’
when passing argument to function [-Wdouble-promotion]

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-05-04 22:22:02 +01:00
Sami Kerola
679d63dd9f
add .mailmap
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-02-24 11:48:02 +00:00
Sami Kerola
0fe89808ee
docs: fix peoples name in THANKS file to have correct characters
Unicode fixes.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2018-01-14 18:35:15 +00:00
Sami Kerola
447241e6c3
tests: improve coverage
Add error condition checks.  Add lease file binding states.  Check all
output formats.  Check leases file that is in mad order, cse all sorting
methods when checking this.  Use json output to check status classfications.
Add cidr range checks.  Add conf include and comment parsing input checks.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-26 15:14:49 +00:00
Sami Kerola
2849dde21b
build-sys: add coverage files to .gitignore
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-26 13:59:17 +00:00
Sami Kerola
813e320b68
webpage: add instructions how to get output you need
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-15 20:09:52 +00:00
Sami Kerola
e6e90b4d62
release: 3.0
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-15 13:29:46 +00:00
Sami Kerola
a1d2bd2cf7
usage: --skip=ignored is actually 'suppressed'
When making --skip to take arguments ignored was for moment a work name for
'suppressed' state, and that was accidentally left to usage() output.

Reference: 3369278fc0
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-14 22:30:07 +00:00
Sami Kerola
46ec42182b
output: add some trivia data to json output
These are software version, dhcpd conf and leases paths and mtime epoch
timestamps.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-14 20:24:15 +00:00
Sami Kerola
444815f964
orther: fix xstrstr_init() memcmp() return value usage
This is a bug.  The xstrstr_init initialized wrong IP version functions when
this function was the first to run and set function pointers.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-14 18:58:11 +00:00
Sami Kerola
6d737a7607
output: unify time stamp creations
Use iso time stamp in both mustach and html outputs.  Effectively this is a
removal of libc langinfo D_T_FMT format, that pulled a lot of gnulib stuff
to project almost unnecessarily.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-14 11:08:46 +00:00
Sami Kerola
ff3d9523e6
output: add more items to mustach tags
Base level printing; localstime, number of ranges and shared networks,
project version, and file paths and time stamps.

Also print error and stop template processing when unknown tag is
encountered.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-14 10:48:52 +00:00
Sami Kerola
d24313d25a
output: remove unused variable attribute
The closure is used.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-14 00:17:56 +00:00
Sami Kerola
c687f38ed6
docs: improve doxygen documentation
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-14 00:11:46 +00:00
Sami Kerola
887845df2a
misc: move couple enums from global scope to file scope
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 21:55:14 +00:00
Sami Kerola
74b697321f
misc: move command line option parsing to separate function
Earlier main() had lots of temporary variables related to command line
parsing.  By moving these to separate function runtime can forget these
variables when moving on.  If nothing else this makes running gdb nicer when
debugging crashes, but as said stack memory should also be spared for better
purpose.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 21:52:03 +00:00
Sami Kerola
3369278fc0
output: make --skip to take arguments what will be skipped
Accidental typo in usage() caused realisation making skipping to fully
controllable is good idea.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 20:23:12 +00:00
Sami Kerola
e4f7259cf6
samples: add prometheus text file collector mustach template
Because prometheus needs timestamp information add that to mustach, and
update manual page what tags are available.

Reference: https://prometheus.io/docs/instrumenting/exposition_formats/
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 14:18:05 +00:00
Sami Kerola
eabaa8adc2
thanks: add Troy D. Hanson to credits about uthash
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 11:53:21 +00:00
Sami Kerola
8fba5c5e6b
clean up: fix couple compiler warnings
src/sort.c:255:5: warning: no previous prototype for 'merge'
src/sort.c:290:2: warning: ISO C90 forbids mixed declarations and code
src/mustach-dhcpd-pools.c:67:5: warning: no previous prototype for 'must_put_err'
src/output.c:109:26: warning: comparing floating point with == or != is unsafe (x5)

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 11:37:18 +00:00
Sami Kerola
88a3f1eb53
hash: include stdlib.h to avoid implicit declarations
Reported-by: Frank Bulk <fbulk@mypremieronline.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 11:37:15 +00:00
Sami Kerola
8ae5fbf489
output: improve html table
Update DataTables and Bootstrap versions.  Add free IP counts to table.
Replace yellow as warning with magenta that is easier to read from white
background.  Use italic and bold to emphasis warning and critical.  Remove
strips.  Use ascent percent sort by default.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 10:16:34 +00:00
Sami Kerola
b2c764924b
output: shared net can be in suppressed state
Avoid calling abort() when this very unlikely situation happens.

Reference: 48962004b8
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-13 09:57:22 +00:00
Sami Kerola
242c58f45e
output: display more entries in html table by default
And add 'All' to 'Show number of entries' menu.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 23:14:23 +00:00
Sami Kerola
c029c7581a
output: make warning and critical colors work in html output
Users should combine this with --color=always to web pages to work
correctly.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 22:19:09 +00:00
Sami Kerola
a64630aa49
output: move shared net andn range status check to output_helper
Having same logic in many places is error prone if and when the logic needs
maintenance.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 17:43:42 +00:00
Sami Kerola
15f08bbf02
output: make --skip-ok to effect --perfdata
Reported-by: Frank Bulk <fbulk@mypremieronline.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 17:31:01 +00:00
Sami Kerola
ef5421ed05
analysis: shared networks to be linked list
This way memory is allocated only for items that are in use, and walking
through shared network items is also more straightforward.

As an unfortunate side effect in --perfdata output shared networks are no
longer printed in reverse order.  This should be a cosmetic issue.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 16:54:00 +00:00
Sami Kerola
a237c11d5a
output: improve mustach template parsing error
Following error did not inform clearly what is wrong.

$ ./dhcpd-pools -l samples/dhcpd.leases -c samples/dhcpd.conf -fm
./dhcpd-pools: must_read_template: open: (null): Bad address

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 15:22:46 +00:00
Sami Kerola
5a8c178924
other: add Jose Bollo to version output credits
Be also a little bit more verbose about licenses in version output.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 15:12:16 +00:00
Sami Kerola
d25e7afa1c
analyze: bug fix shared networks counts
This also fixes backup state counts that were added to shared networks
twice, making the numbers to be much greater than they really where.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 15:12:16 +00:00
Sami Kerola
7cd381ed83
all files: re-indent
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 15:12:16 +00:00
Sami Kerola
1875a13733
all files: replace global variables with runtime config state structure
Earlier variables magically appeared to scope of functions that took void as
argument.  One could figure out perhaps they were globals, but programs that
do that are unnessarily hard to follow.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-12 15:12:15 +00:00
Sami Kerola
adda925c1e
clean up: remove unused variable
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 23:59:13 +00:00
Sami Kerola
3dda0a77a5
output: deduplicate file closing code
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 23:09:33 +00:00
Sami Kerola
7575294c36
usage: add error message informing mustach support is not available
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 21:15:36 +00:00
Sami Kerola
39b2811aa7
build-sys: omit mustach compilation when it cannot work
For example mac does not have open_memstream(3), and strndupa(3) can also be
missing.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 16:13:14 +00:00
Sami Kerola
b96f8cd8ad
gnulib: use nstrftime instead of strftime
The strftime module is obsolete.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 15:37:07 +00:00
Sami Kerola
54cedc1001
output: include stdlib.h to avoid compilation error
The stdlib.h has EXIT_FAILURE and free(3).

Reported-by: Sebastián Cramatte <scramatte@nixus.es>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 14:29:00 +00:00
Sami Kerola
e4baff79bd
output: add must_put_err() utility function
This function deals situation when mustach put happens before enter, that is
a sign of an invalid input template.  Good side of adding this function is
that dhcpd-pools does not need to modify code provided by Jose.

Reference: 66183bc7c7
Proposed-by: José Bollo <jobol@nonadev.net>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 09:00:33 +00:00
Sami Kerola
4fc4bcd083
output: save and reuse output helper results
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 08:39:50 +00:00
Sami Kerola
d5ae2a80c0
output: do not skip over first range in mustach output
Off by one that is caused by must_next_range() advancing pointer, and moving
over the first range.  Fix by setting indexes one step backwards, that is
not excellent but better than copying skip_ok stuff to must_enter().

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 08:20:10 +00:00
Sami Kerola
50fc4ebe9d
output: avoid mixing ntop_ipaddr() output buffers
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-11 08:19:56 +00:00
Sami Kerola
66183bc7c7
output: make mustach processing more robust
Fix issues found with afl-fuzz.  It is a pity I had to change mustach.c it
is no longer exactly the same as upstream.  Lets see if Jose will accept
these changes.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-09 19:49:37 +00:00
Sami Kerola
2ec953858b
tests: add mustach check
Use samples directory data as input to ensure they do not break.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-09 19:49:17 +00:00
Sami Kerola
39e6e65201
docs: add mustach sample files
Include samples to installation, and give a hint to user where it can be
found in manual page.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-09 19:49:17 +00:00
Sami Kerola
74fdf90980
output: add separate first_ip and last_ip to json and mustach outputs
This give greater liberty to people who are using these formats to do what
ever they need to.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-09 19:49:17 +00:00
Sami Kerola
7d9a5b5561
output: add mustach templating support
Based on José Bollo's mustache C implementation.  This adaptation uses
project specific data structures to avoid overhead with json parsing.

Reference: https://gitlab.com/jobol/mustach.git
Commit: d84608a69033d38c81b8fcff0cb272e225dd5428
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-09 19:49:13 +00:00
Sami Kerola
fe847bb9b1
output: use range_output_helper() value in output_xml()
Earlier commit started to use range_output_helper() in output_xml() so
remove the unnecessary calls to get_range_size().

Reference: c55c823753
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-08 23:04:28 +00:00
Sami Kerola
1182ec4cc9
include: use project specific header guard
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-07 13:45:17 +00:00
Sami Kerola
e9736f74e7
getdata: do not use 'else' after 'continue'
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-07 13:44:50 +00:00
Sami Kerola
e5cd46e4e9
other: do not use 'else' after 'return'
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-07 13:12:37 +00:00
Sami Kerola
eb7547c742
output: json nan values need quoting
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-07 10:41:53 +00:00
Sami Kerola
8fe7dc2c03
other: add --skip-ok to usage() output
Forgot in previous commit.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-06 22:34:06 +00:00
Sami Kerola
c55c823753
output: add --skip-ok option
Omit ranges and shared networks that do not exceed warning or critical
thresholds.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-06 22:11:47 +00:00
Sami Kerola
e079cc16e0
output: include earlier missing data to json output
This commit adds all the data that is in text output to json output.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-06 21:39:15 +00:00
Sami Kerola
344ed2900d
output: add color support to text output
When --warning or --critical thresholds are defined with text output lines
that exceed threshold will be either yellow (warning) or red (critical).

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-06 21:31:57 +00:00
Sami Kerola
48962004b8
output: add output helper functions
There is too much repetative confusing maths near printouts.  Move that
stuff to a function.

This change also fixes --snet-alarms option counting issue in range that
were not part of any shared network were ignored.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-05 16:21:20 +00:00
Sami Kerola
05f8208518
getdata: fix typo
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-05 10:01:07 +00:00
Sami Kerola
abf5d04736
output: make output_analysis() to be regular function
This commit makes it possible to define alarming thresholds at the same time
with other output formats.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-11-05 09:51:35 +00:00
Sami Kerola
9deeae8c36
update sitemap
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-23 09:18:35 +01:00
Sami Kerola
548ce63963
release: update web page meta data
This should have been done before tag.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-23 08:53:18 +01:00
Sami Kerola
58a31513fe
release: 2.29
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-23 08:17:38 +01:00
Sami Kerola
804aa3236d
docs: update maintainer gpg key
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-17 09:50:55 +01:00
Sami Kerola
af1ae94112
docs: add build instruction link to the project web page
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-17 09:17:15 +01:00
Sami Kerola
fefd8d26cf
docs: tell what needs to be done when releasing new version
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-17 09:00:25 +01:00
Sami Kerola
1d47eb9a1c
docs: update doxygen configuration file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-17 08:43:19 +01:00
Sami Kerola
0c32a67ff1
build-sys: update bootstrap from gnulib
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-17 08:41:41 +01:00
Sami Kerola
bb0fa9adae
getdata: add cidr range support
This makes 'range6 123::/45' style cidr notation to be understood as address
range.  Earlier ranges that used cidr failed to parse completely.

Reported-by: Jeff Bailey <jeffrey.bailey@bt.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-17 00:03:06 +01:00
Sami Kerola
48d0629881
lib: update .gitignore
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-09 10:29:04 +01:00
Sami Kerola
782f63c3ad
add --ip-version option to force either IPv4 or IPv6 analysis
Proposed-by: Jeff Balley <jeffrey.bailey@bt.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-09-09 10:28:27 +01:00
Boris Lytochkin
b9cff0d814
introduce -A arg: treat single subnets as shared-network with CIDR as their name
Current output makes some false-positives for situations when multiple
ranges are specified inside single network, for example:

subnet 10.0.0.0 netmask 255.255.254.0 {
	...
	range 10.0.0.1 10.0.0.254;
	range 10.0.1.1 10.0.1.253;
	...
}

An alert for range 10.0.0.1 - 10.0.0.254 will be raised even in situations
when range 10.0.1.1 - 10.0.1.253 is completely empty.  To cope with this
issue, an -A option is added to treat all single networks as shared-network.
This option changes output for both range and shared networks output if
specified.  Frankly saying, using network CIDR as network name is much more
sane for me than 'All Networks'.

Signed-off-by: Boris Lytochkin <lytboris@yandex-team.ru>
2017-07-15 17:26:15 +01:00
Sami Kerola
dff991666e
lib: update .gitignore
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-05-21 17:30:24 +01:00
Sami Kerola
242ef3109b
variable: add const to print_mac_addreses_tmp
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-05-21 17:21:57 +01:00
Sami Kerola
1c8b799799
fix typo
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-05-06 16:44:19 +01:00
Sami Kerola
e93fc5dba4
lib: update .gitignore
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-04-15 20:42:58 +01:00
Sami Kerola
c3c3fc6e40
getdata: fpos_t is not easy to print correctly
On some systems fpos_t may be a complex object, so printing it is not as
easy as ftell() position.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-04-15 20:42:07 +01:00
Sami Kerola
e9223a852c
contrib: Klaus Slott told about opensuse package
Add opensuse rpm as an example how to build one.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-04-10 13:12:34 +01:00
Sami Kerola
9a52619385
style: use same argument names in header and source file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-04-07 22:56:19 +01:00
Sami Kerola
2b75a0d78e
getdata: remove POSIX_FADV_NOREUSE
It is too difficult to know what users might want to do.  Maybe some run
this software all the time from a monitoring system, and in cases like that
it is best to have caches helping.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-02-04 23:11:43 +00:00
Sami Kerola
344e01c1f6
output: add include avoid referringt to undefined definition
Reference: c4a654a149
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-02-04 18:00:02 +00:00
Sami Kerola
c4a654a149
output: fix timestamp localization on html page
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-01-12 22:40:33 +00:00
Sami Kerola
a905b50943
getdata: report position in config file when parsing fails
It seems that one can reach the abort() with severely broken configuration
file, that is extremely unlikely to run without parser error when given to
ISC dhcpd.  So such files ought to be impossible, and it is good enough for
this software to report position where parsing cannot be continued.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-01-08 11:49:41 +00:00
Sami Kerola
ae2edb0fbc
man: remove old html table only option argument from manual
Incomplete html page, that was just a html table, was removed some time ago
but deprecated option arguments were unfortunately left to manual that are
now removed.

Reference: 1299737d76
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-01-07 11:01:22 +00:00
Sami Kerola
5eae1b41a7
man: improve synopsis and output limit
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-01-06 23:36:36 +00:00
Sami Kerola
ea7fd91876
remove const and pure function attributes
Most of these functions take pointers as input argument, so they cannot be
considered neiter const or pure.  In same go fix few issues noticed when
compiling with smatch.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-01-06 23:14:28 +00:00
Sami Kerola
11c0b23d77
portability: add gnulib modules earlier missing
Found with help if autoscan.  In same go update lib/.gitignore file.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-01-06 22:33:08 +00:00
Sami Kerola
aaad35a8c9
output: remove unnecessary increment
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2017-01-02 21:21:27 +00:00
Sami Kerola
a6b77ab785
docs: fix couple typos and improve a sentence in README
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-10-02 21:35:29 +01:00
Sami Kerola
7740927721
build-sys: always use restrict found by autoconf
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-08-16 13:25:23 +01:00
Sami Kerola
9bb30b29ca
build-sys: default to ./configure --enable-silent-rules
This makes compiler to options not to be shown when running make, and that
allows noticing warnings more easily.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-08-15 21:18:29 +01:00
Sami Kerola
1b35a16d95
analyze: use while() when for() is less fit to purpose
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-07-03 14:00:00 +01:00
Sami Kerola
d26c858c13
build-sys: update gnulib .gitignore file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-05-29 21:22:13 +01:00
Sami Kerola
840d2143e6
build-sys: update bootstrap from gnulib
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-05-29 21:20:39 +01:00
Sami Kerola
a3ef3d617f
output: check alarming mode can output successfully
Fixes also a resource leak.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-24 12:29:50 +01:00
Sami Kerola
f6e256243d
fix doap file git repository and license section
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-23 22:55:21 +01:00
Sami Kerola
ccd5370d9c
add dhcpd-pools Description Of A Project file
Reference: https://github.com/edumbill/doap/wiki
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-23 22:33:08 +01:00
Sami Kerola
c4ebafb106
argument parsing: fix compiler warning
src/dhcpd-pools.c:193:18: warning: comparison of integers of different
signs: 'int' and 'unsigned long' [-Wsign-compare]

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-23 16:35:38 +01:00
Sami Kerola
87c06a1b13
getdata: get rid of remaining stdbool usage
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-23 16:32:08 +01:00
Sami Kerola
8a8c28a17e
contrib: remove awk file duplicate
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-01 23:11:37 +01:00
Sami Kerola
5a33b619d1
contrib: remove unnecessary cgi script
The html format is done using Bootstrap and DataTables.  That deprecatated
need for having cgi to wrap dhcpd-pools.

Reference: 1299737d76
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-01 23:11:37 +01:00
Sami Kerola
e5f9a77511
contrib: add archlinux package build file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-04-01 23:11:36 +01:00
Manuel Hachtkemper
32e2d399a0
alarming: add additional performance data
Options -p or --perfdata (in alarming mode) now enable the output of
additional performance data, i.e.  used, touched and backup addresses per
subnet.

Signed-off-by: Manuel Hachtkemper <hacman@math.uni-bonn.de>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-03-31 22:34:27 +01:00
Sami Kerola
c305e2f82c
tests: add range definition flip test
This test ensure 10b06d88f0 will not get
regression in future.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-02-18 23:05:24 +00:00
Sami Kerola
10b06d88f0
getdata: flip ranges if they are in greater smaller order
Apparently ISC dhcpd allows marking ranges in order from greater IP to
smaller.  In these cases first and last IPs are fliped, so that the rest of
the processing can be done without alterations.

Reported-by: Ivanov Ivan <mgfnv9@gmail.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2016-02-18 22:35:56 +00:00
Sami Kerola
3d0c510475
webpages: compress sitemap.txt file
More than 90% is hefty pay-off.

$ gzip -v -d  sitemap.txt.gz
sitemap.txt.gz:  93.5% -- replaced with sitemap.txt

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-29 21:52:48 +00:00
Sami Kerola
46641751b4
webpages: make index page mobile device friendly
Use css max-width instead of width this permits narrow screen to wrap lines,
this makes the index page more usable when browsing with a mobile phone or
some other device with limited horizontal dimension.  Also get rid of <pre>
tag, and make the sample usage more realistic.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-29 21:29:32 +00:00
Sami Kerola
d717a043bf
use long options in .indent.pro file
Short options are impossible to understand without looking to manual page.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-10 22:42:54 +00:00
Sami Kerola
03b1edb188
add sitemap url to robots.txt file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-07 10:55:45 +00:00
Sami Kerola
1dcf762967
add dhcpd-pools website content to a subdirectory
Start using git to backup of the website content.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-07 10:32:02 +00:00
Sami Kerola
17f1fb7f5e
tell in README when ./bootstrap is needed
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-06 19:08:08 +00:00
Sami Kerola
4cd85b62ff
release: 2.28
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-06 17:48:56 +00:00
Sami Kerola
ace697b472
fix out of tree build tests
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-06 17:44:30 +00:00
Sami Kerola
1a7d982495
change NAN markup to make tests work on mac
For some unknown reason mac osx does not change NAN to negative in printout
when asking to do so.  To get rid of false positive test results change the
sign of NAN to positive, that may break something for someone if there are
people expecting -NAN when devision with zero happens.  But that sort of
breakage is pretty unlikely because it requires broken dhcpd.conf.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-06 11:46:07 +00:00
Sami Kerola
01aa13cf43
test all sorting options
Not perfect test, but atleast something.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-05 19:51:53 +00:00
Sami Kerola
da4b7a783a
add --warn-count and --crit-count test, and fix related bug
I should consider writing tests before features.  Sadly recently added new
options did not even work.  Oh well, at least I did not release them before
noticing this.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-05 19:38:08 +00:00
Sami Kerola
15802d6648
unify quotation in error messages
Use quote() from gnulib to do this.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-05 19:00:32 +00:00
Sami Kerola
d6486e7730
make usage() easier to read
None-continuous print out blocks are difficult.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-05 18:59:40 +00:00
Sami Kerola
bd45266f74
drop a core when bug condition happens
Having a core will help enormously debugging these issues.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-05 18:50:28 +00:00
Sami Kerola
8fca82f148
print include system error message when output fails
Users want to know why write fail - was it because disk full, or destination
read-only, or IO error, and so on.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-04 20:35:35 +00:00
Sami Kerola
f5cd7383e4
fix improve variable names
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-04 19:32:50 +00:00
Sami Kerola
49835cccb5
fix doxygen build
And .gitignore doxygen related outputs.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-03 21:35:13 +00:00
Sami Kerola
98bcdf9378
simplify output format selection, and passing
Use of enum is a lot more readable than passing strings, and comparing
characters, around.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-01 23:25:54 +00:00
Sami Kerola
b524296016
use bitmap for booleans and other config that has known size
Bitmaps are more c style than bool coming from c++ land.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-01 23:24:14 +00:00
Sami Kerola
5ed9958b69
fix protocol specifier in html output
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-12-01 21:58:52 +00:00
Sami Kerola
0369340710
remove upper limit of sort order definitions
Unlikely to be needed by anyone, but because arbitrary limits are from code
style point of view ugly.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-30 00:50:18 +00:00
Sami Kerola
327691f34a
use more descriptive names in limit bits enum definition
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-29 23:36:19 +00:00
Sami Kerola
4aff49ed80
correct return value FIXME items
Not all markups were quite right.  The output_* functions must return an
int.  The rest were as a matter of fact correct.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-28 21:03:38 +00:00
Sami Kerola
f11ca0bec2
fix typo in README
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-28 20:51:18 +00:00
Sami Kerola
1299737d76
make html output to use Bootstrap and DataTables
This make the table output good looking, and allows users to click table
headings to sort data by column without rerunning the analysis.
Unfortunately this change is breaking change, meaning the old CSS tags are
no longer supported, nor partial html output that printed only the table.

Proposed-by: Aaron Paetznick <aaronp@critd.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-28 20:37:23 +00:00
Sami Kerola
c7917152d3
improve README file instructions
Proposed-by: Derrick Lin <d.lin@garvan.org.au>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-28 11:22:28 +00:00
Sami Kerola
5cede1ff31
add --warn-count and --crit-count options to suppress alarm noise
Alarm criteria based solely on percentage was found to be difficult to be
tricky to setup in environments that has small ranges and big shared-nets
mixed up together.  These two new options should help making alarming more
useful.

Requested-by: Frank Bulk <fbulk@mypremieronline.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-28 00:33:12 +00:00
Sami Kerola
7f3d553c7f
add --snet-alarms option to suppress excess range alarms
Some users may not want to have alarms about ranges that are part of a
shared-network, so allow them to suppress such.

Requested-by: Frank Bulk <fbulk@mypremieronline.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-27 23:42:23 +00:00
Sami Kerola
99b6af70ef
update doxygen.conf file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-25 22:02:41 +00:00
Sami Kerola
2528c4c9d6
make binary exec path dynamic in scripts referring to it
Everything should just work out of the box without poking.  This change
makes that goal to be yet agian one step closer.  In same go make all
autotools related variable substitutions better.

Requested-by: Martijn van Brummelen <martijn@brumit.nl>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-11-25 21:53:29 +00:00
Sami Kerola
c30c122027
fix couple compiler warnings
src/getdata.c:248:22: warning: 'range_p' may be used uninitialized in this
function [-Wmaybe-uninitialized]
src/other.c:383:1: warning: control reaches end of non-void function
[-Wreturn-type]

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-10-26 22:43:31 +00:00
Sami Kerola
535dfc4fc2
portability: Solaris 10 does not have err.h
Use error(3) function, that has gnulib portability fixes, instead of err(3)
and warn(3) family.

Reported-by: Anton Tkachev <antont@bk.ru>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-10-26 22:29:32 +00:00
Sami Kerola
fae20302cf release: 2.27
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-09-05 13:35:44 +01:00
Sami Kerola
167c4b6989 gitignore: update gnulib file list
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-09-05 13:34:41 +01:00
Sami Kerola
d8aef85d01 man: fix character class change
Debian package lint found going back to roman mode was broken.

Reported-by: Martijn van Brummelen <martijn@brumit.nl>
Signed-off-by: Sami Kerola <kerolasa@cloudflare.com>
2015-09-05 13:15:19 +01:00
Sami Kerola
cf26e17fe7 add hint about configure options to README
Proposed-by: Tim Cantin <tcantin@wellesley.edu>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-05-29 09:18:08 +01:00
Sami Kerola
9d1241c006 improve html output
Remove unnecessary html indentation, so that there is less page content
to transfer.  Right align the network names, and IP's so that they are
easier to read.  And ensure quoting is done correctly.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-05-02 19:40:06 +01:00
Sami Kerola
c4e5ef6198 add xml format check
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-05-02 18:51:39 +01:00
Sami Kerola
0d6c61d437 add touched addresses counts to xml and json reports
For some reason missing information has been overlooked for years.
Perhaps there is aren't that many users who are interested of the touched
addresses.

Proposed-by: Aaron Paetznick <aaronp@critd.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-05-02 18:48:52 +01:00
Sami Kerola
73b357484d output: remove empty element from xml
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-05-02 18:00:10 +01:00
Sami Kerola
735c5db817 docs: remove todo items that will never happen
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-04-01 23:15:38 +01:00
Sami Kerola
34dd1dee6e docs: remove very basic git usage info
This is not a git beginner manual project.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2015-04-01 23:11:28 +01:00
Sami Kerola
c7379e3e25 release: 2.26
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-15 10:03:41 +00:00
Sami Kerola
cfbd69c20b maint: remove unnecessary braces, spaces, update gnulib .gitignore
Improve code readability, and small maintenance.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-15 09:44:28 +00:00
Sami Kerola
33894fba74 other: disallow unsigned counter ever to have minus value
src/other.c:398:4: runtime error: unsigned integer overflow: 0 - 1 cannot
be represented in type 'unsigned int'

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-14 21:57:21 +00:00
Sami Kerola
8e076fcc4f output: avoid division by zero
This correction makes the shared networks alarming to work when all
available leases are used.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-14 21:54:27 +00:00
Sami Kerola
0705b0c17f tests: add regression test to avoid shared-net off by one alarming issue
This tests ensures the problem fixed by Wolfgang Steudel cannot reoccur.
See the reference commit for details.

Reference: 5519763ba9
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-14 20:13:08 +00:00
Wolfgang Steudel
5519763ba9 alarming: include last shared network in alarming [off by one]
We have defined some shared networks with a couple of address ranges
and wanted to monitor the availability of free IP addresses in the
shared networks.  We were wondering why in some cases there was no
warning, although one shared network's usage was above the threshold.

We found the reason.  In output_alarming() the code was not skipping
"All networks", but missing the last shared network in the list.
Moving "shared_p++" to the beginning of the loop seems to solve the
bug.

Reviewed-by: Sami Kerola <kerolasa@iki.fi>
Signed-off-by: Wolfgang Steudel <wolfgang.steudel@tu-ilmenau.de>
2014-11-14 19:41:21 +00:00
Sami Kerola
190df198a4 output: prefer thread safe function localtime_r()
While the dhcpd-pools might not be threading there is no reason why
software should use worse function when always correct alternative is
equally easy to use.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-09 22:31:30 +00:00
Sami Kerola
e401c2c7e6 other: reduce variable scope
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-09 22:25:25 +00:00
Sami Kerola
0d2b30b62d getdata: fix buffer overflow [AddressSanitizer]
==12031==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x61900000a980 at pc 0x0000004bca22 bp 0x7fff580dd6d0 sp 0x7fff580dd6c8
WRITE of size 1 at 0x61900000a980 thread T0
    #0 0x4bca21 in parse_config /home/src/dhcpd-pools/src/getdata.c:323:4
    #1 0x4bb332 in main /home/src/dhcpd-pools/src/dhcpd-pools.c:266:2
    #2 0x7fe03ecc403f in __libc_start_main (/usr/lib/libc.so.6+0x2003f)
    #3 0x4b9c0c in _start (/home/src/dhcpd-pools/dhcpd-pools+0x4b9c0c)

0x61900000a980 is located 0 bytes to the right of 1024-byte region
[0x61900000a580,0x61900000a980) allocated by thread T0 here:
    #0 0x49c58b in __interceptor_malloc (/home/src/dhcpd-pools/dhcpd-pools+0x49c58b)
    #1 0x4cbc0d in xmalloc /home/src/dhcpd-pools/lib/xmalloc.c:41:13
    #2 0x4bbed8 in parse_config /home/src/dhcpd-pools/src/getdata.c:195:9
    #3 0x4bb332 in main /home/src/dhcpd-pools/src/dhcpd-pools.c:266:2
    #4 0x7fe03ecc403f in __libc_start_main (/usr/lib/libc.so.6+0x2003f)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/src/dhcpd-pools/src/getdata.c:323 parse_config

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-11-02 21:56:43 +00:00
Sami Kerola
bd5877bf4f update bootstrap from gnulib
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-10-24 20:58:27 +01:00
Sami Kerola
15502d3c97 getdata: fix buffer-overflows reported by address sanitizer
These happen when input configuration or leases files are empty.

==12876==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x61900000a480 at pc 0x000000487442 bp 0x7fffbc3e16b0 sp 0x7fffbc3e0e70
READ of size 1025 at 0x61900000a480 thread T0
    #0 0x487441 in __interceptor_strlen (/home/src/dhcpd-pools/dhcpd-pools+0x487441)
    #1 0x4bbb10 in parse_leases /home/src/dhcpd-pools/src/getdata.c:112:35
    #2 0x4bb337 in main /home/src/dhcpd-pools/src/dhcpd-pools.c:268:2
    #3 0x7f51909bf03f in __libc_start_main (/usr/lib/libc.so.6+0x2003f)
    #4 0x4b9c0c in _start (/home/src/dhcpd-pools/dhcpd-pools+0x4b9c0c)

0x61900000a480 is located 0 bytes to the right of 1024-byte region
[0x61900000a080,0x61900000a480)
allocated by thread T0 here:
    #0 0x49c58b in __interceptor_malloc (/home/src/dhcpd-pools/dhcpd-pools+0x49c58b)
    #1 0x4cbbcd in xmalloc /home/src/dhcpd-pools/lib/xmalloc.c:41:13
    #2 0x4bb801 in parse_leases /home/src/dhcpd-pools/src/getdata.c:96:9
    #3 0x4bb337 in main /home/src/dhcpd-pools/src/dhcpd-pools.c:268:2
    #4 0x7f51909bf03f in __libc_start_main (/usr/lib/libc.so.6+0x2003f)

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-10-24 20:57:57 +01:00
Sami Kerola
74c6ef2566 update kernel.org url in README
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-08-09 19:34:18 +01:00
Sami Kerola
e09f655a7b add appropriate sorting function for struct leases_t
The HASH_SORT in analyze needs this.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-08-09 19:28:23 +01:00
Sami Kerola
965875d20b declare global variables only once
Global variable declarations belong near main, and the header has to have
extern reference to them.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-08-09 19:09:04 +01:00
Sami Kerola
4392a5b917 reindent all files
And update the indent.pro to match with the style I like.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-07-20 18:05:00 +01:00
Sami Kerola
9090cfb1d7 news: add the note about .sig pgp key id
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-05-31 18:54:01 +01:00
Sami Kerola
6b267387cc release: 2.25
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-05-31 18:14:23 +01:00
Sami Kerola
6e680ee04f contrib: add release siging key to contrib/
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-05-31 18:13:21 +01:00
Sami Kerola
502daf8306 build-sys: require automake 1.12 to get working test-driver
With older automake versions one can end up after ./bootstrap with
situation where test-driver script is missing, and subsequent compilation
fails.  Requiring automake 1.12 should usually help, but unfortunately
the case Dennis reported is different.

Something goes wrong with 1.13 and autoconf 2.69, in 32 bit RHEL system.
That sort of system seems to require AM_PROG_CC_C_O, and even when that
is added following error happens.  It is yet unknown to me why this is
the case.

parallel-tests: error: required file 'build-aux/test-driver' not found

Reference: http://git.savannah.gnu.org/cgit/automake.git/tree/NEWS?id=v1.12#n113
Reported-by: Dennis Ortsen <dortsen@gmail.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-04-13 21:14:42 +01:00
Sami Kerola
0f66becd57 build-sys: update bootstrap script
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-04-13 20:55:34 +01:00
Sami Kerola
eb55946595 output: use symbolic exit values for nagios commands
And ensure the exit values are set no matter how user will limit output.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-03-24 21:56:34 +00:00
Sami Kerola
5454ab7086 build-sys: update gitinore file
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-03-24 21:38:10 +00:00
Sami Kerola
f3e282f122 output: make nagios output have performance data
Just in case someone wants to graph what is going on.

Reference: http://nagios.sourceforge.net/docs/3_0/pluginapi.html
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2014-03-24 21:34:35 +00:00
Sami Kerola
ca0b1c3262 tests: fix testing error
The commit 7fc354827a introduced an symlink
that end up to update simple test causing it to break.

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2013-11-17 18:39:47 +00:00
Sami Kerola
d089a19fb5 generic: use pure and const function attributes when possible
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2013-11-17 18:25:52 +00:00
Sami Kerola
affb3d70a3 thanks: add Fredrik Lysén & Conor McCarthy
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2013-11-08 21:01:21 +00:00
Sami Kerola
6b88e8d872 man: add tip analysis of include files can be useful
Reported-by: Fredrik Lysén <fredrik.lysen@uadm.uu.se>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2013-11-08 20:50:26 +00:00
Sami Kerola
7fc354827a getdata: fix consecutive range definition regression
The added test demonstrates the issue.  If a did not end with whitespace
it was skipped.

Reported-by: Fredrik Lysén <fredrik.lysen@uadm.uu.se>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2013-11-08 20:30:28 +00:00
Sami Kerola
48caf5fb42 getdata: add missing HAVE_POSIX_FADVISE protection
Reported-by: Conor McCarthy <mr.spuratic@gmail.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2013-11-08 19:21:19 +00:00
Sami Kerola
631bf0bf7c build-sys: use more strict method to check __builtin_expect
The problem with the detection of gcc's __builtin_expect, the autoconf
set up uses EX_COMPILE_IFELSE which only compiles the test code with gcc
-c, it does not link so a missing __builtin_expect is treated as a
missing symbol and is not detected.

Reported-by: Conor McCarthy <mr.spuratic@gmail.com>
Signed-off-by: Sami Kerola <kerolasa@iki.fi>
2013-11-08 19:19:27 +00:00
132 changed files with 10239 additions and 3509 deletions

3
.gitignore vendored
View file

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

2
.mailmap Normal file
View file

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

View file

@ -1,7 +1,6 @@
## Makefile.am -- Process this file with automake to produce Makefile.in
AUTOMAKE_OPTIONS = gnu
ACLOCAL_AMFLAGS = -I m4
EXTRA_DIST = \
.version \
@ -16,12 +15,40 @@ $(top_srcdir)/.version:
dist-hook:
echo $(VERSION) > $(distdir)/.tarball-version
CLEANFILES =
PATHFILES =
CLEANFILES = $(PATHFILES)
EXTRA_DIST += $(PATHFILES:=.in)
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,6 +5,277 @@ 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,196 +1,62 @@
This is dhcpd-pools which is made for ISC dhcpd pool range analysis.
This is dhcpd-pools - ISC dhcpd lease status utility.
== Quick start
Quick start.
./bootstrap
./configure --prefix=/usr/local
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
make
make check
make install
Notice that there are configuration options for default dhcpd.conf,
dhcpd.leases paths, among other things.
== General information
./configure --help
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.
Remember to read the friendly manual page.
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.
man ./man/dhcpd-pools.1
== Dependencies to other projects
Dependencies to other projects.
http://www.gnu.org/software/gnulib/
https://www.gnu.org/software/gnulib/
If you have gnulib checked out somewhere at file
system you can avoid download by setting
GNULIB_SRCDIR environment variable.
You can avoid repeated gnulib downloads by setting
GNULIB_SRCDIR environment variable. For example:
http://uthash.sourceforge.net/
git clone git://git.savannah.gnu.org/gnulib.git ~/src/gnulib
export GNULIB_SRCDIR="$HOME/src/gnulib"
== Test data wanted
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.
Maintainer is interested to get copy of your dhcpd.conf
and dhcpd.leases file, with includes if you use them.
and dhcpd.leases files, and include files if you use them.
Intention is to collect large set of data to build
realistic regression test environment. By giving your
data to maintainer you can be sure that updates will work
for you.
realistic regression test environment.
If you are interested to help this way put all files into
tar.gz, and send them to kerolasa@iki.fi. It would be nice
that email subject line would have 'dhcpd-pools test data'.
tar.gz, and send them to:
== 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
Sami Kerola <kerolasa@iki.fi>

35
THANKS
View file

@ -5,23 +5,24 @@ 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
Rezso Gajdóczy
Rezső Gajdóczy
Robert Viou
Enno Gröper
Enno Gröper
Troy D. Hanson
Ryan Malek
Cheer Xiao
Gilles Bouthenot
@ -29,3 +30,25 @@ 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,25 +15,19 @@ o When time stamps are part of lease situation evaluation (see
expiry happens.
o Add lease time histogram support.
### Next major version
### When releasing
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.
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

1542
bootstrap

File diff suppressed because it is too large Load diff

View file

@ -1,10 +1,10 @@
# Bootstrap configuration.
# Bootstrap configuration. -*- sh -*-
# Copyright (C) 2006-2012 Free Software Foundation, Inc.
# Copyright (C) 2006-2025 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,13 +13,14 @@
# 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 <http://www.gnu.org/licenses/>.
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# gnulib modules used by this package.
gnulib_modules="
close-stream
closeout
error
fclose
fcntl-h
fdopen
@ -27,9 +28,11 @@ gnulib_modules="
fopen
getopt-gnu
inet_pton
langinfo
isnan
netinet_in
nstrftime
progname
quote
realloc-gnu
stat
stddef
@ -37,8 +40,9 @@ gnulib_modules="
stdlib
stpncpy
strdup-posix
strftime
strstr
strtod
time_r
xalloc
"
@ -60,7 +64,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,5 +1,7 @@
/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=2012-12-31.23; # UTC
scriptversion=2022-01-27.18; # UTC
# Copyright (C) 2007-2013 Free Software Foundation, Inc.
# Copyright (C) 2007-2022 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=2012-12-31.23; # 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 <http://www.gnu.org/licenses/>.
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# This script is derived from GIT-VERSION-GEN from GIT: http://git.or.cz/.
# This script is derived from GIT-VERSION-GEN from GIT: https://git-scm.com/.
# 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,19 +65,21 @@ scriptversion=2012-12-31.23; # 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 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."
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."
usage="\
Usage: $me [OPTION]... \$srcdir/.tarball-version [TAG-NORMALIZATION-SED-SCRIPT]
@ -85,8 +87,9 @@ Print a version string.
Options:
--prefix prefix of git tags (default 'v')
--fallback fallback version to use if \"git --version\" fails
--prefix PREFIX prefix of git tags (default 'v')
--fallback VERSION
fallback version to use if \"git --version\" fails
--help display this help and exit
--version output version information and exit
@ -100,8 +103,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
@ -140,11 +143,9 @@ 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 missing or damaged" 1>&2
&& echo "$0: WARNING: $tarball_version_file is damaged" 1>&2
fi
if test "x$v" != x
@ -166,9 +167,10 @@ then
# tag or the previous older version that did not?
# Newer: v6.10-77-g0f8faeb
# Older: v6.10-g0f8faeb
case $v in
*-*-*) : git describe is okay three part flavor ;;
*-*)
vprefix=`expr "X$v" : 'X\(.*\)-g[^-]*$'` || vprefix=$v
case $vprefix in
*-*) : git describe is probably 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
@ -183,9 +185,9 @@ then
;;
esac
# 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-/'`;
# Change the penultimate "-" to ".", for version-comparing tools.
# Remove the "g" to save a byte.
v=`echo "$v" | sed 's/-\([^-]*\)-g\([^-]*\)$/.\1-\2/'`;
v_from_git=1
elif test "x$fallback" = x || git --version >/dev/null 2>&1; then
v=UNKNOWN
@ -199,7 +201,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 time stamp has changed.
# Don't declare a version "dirty" merely because a timestamp has changed.
git update-index --refresh > /dev/null 2>&1
dirty=`exec 2>/dev/null;git diff-index --name-only HEAD` || dirty=
@ -214,12 +216,12 @@ if test "x$v_from_git" != x; then
fi
# Omit the trailing newline, so that m4_esyscmd can use the result directly.
echo "$v" | tr -d "$nl"
printf %s "$v"
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# eval: (add-hook 'before-save-hook 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-time-zone: "UTC0"
# 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_DIR([m4])
AC_CONFIG_MACRO_DIRS([m4])
AC_INIT([dhcpd-pools],
[m4_esyscmd([build-aux/git-version-gen .tarball-version])],
[kerolasa@iki.fi],[],
[http://dhcpd-pools.sourceforge.net/])
[https://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.10
1.12
foreign
dist-xz
no-dist-gzip
@ -24,6 +24,9 @@ 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
@ -66,11 +69,27 @@ 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_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[
AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[
return __builtin_expect(1, 1) ? 1 : 0
]])],[
have_builtin_expect=yes
@ -134,8 +153,7 @@ 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_CONFIG_FILES([doc/doxy.conf])
AC_MSG_ERROR([doxygen not in path])
)
AC_CHECK_PROGS([DOXYGEN_DOT], [dot])
@ -149,7 +167,6 @@ 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 Normal file
View file

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

View file

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

36
contrib/PKGBUILD Normal file
View file

@ -0,0 +1,36 @@
# 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

@ -1,34 +0,0 @@
#!/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

111
contrib/kerolasa.gpg Normal file
View file

@ -0,0 +1,111 @@
-----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-----

View file

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

1
contrib/nagios.conf.in Normal file
View file

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

4
contrib/rpm.spec Normal file
View file

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

4
contrib/zabbix.txt Normal file
View file

@ -0,0 +1,4 @@
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 Normal file
View file

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

View file

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

File diff suppressed because it is too large Load diff

218
lib/.gitignore vendored
View file

@ -1,45 +1,52 @@
/*.o
/*.lo
/.deps/
/.gitignore~
/.libs/
/arpa/
/Makefile
/Makefile.am
/Makefile.in
/_Exit.c
/alloca.h
/alloca.in.h
/arg-nonnull.h
/arpa/
/arpa_inet.c
/arpa_inet.in.h
/atexit.c
/c++defs.h
/assert.in.h
/attribute.h
/basename-lgpl.c
/basename-lgpl.h
/c32is-impl.h
/c32isprint.c
/calloc.c
/c-ctype.c
/c-ctype.h
/c-strcase.h
/c-strcasecmp.c
/c-strcaseeq.h
/c-strncasecmp.c
/calloc.c
/charset.alias
/close-stream.c
/close-stream.h
/c++defs.h
/cdefs.h
/cloexec.c
/cloexec.h
/close.c
/closeout.c
/closeout.h
/config.charset
/configmake.h
/dosname.h
/close-stream.c
/close-stream.h
/c-strcasecmp.c
/c-strcaseeq.h
/c-strcase.h
/c-strncasecmp.c
/dup2.c
/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
@ -52,91 +59,204 @@
/fstat.c
/ftell.c
/ftello.c
/getopt.c
/getopt.in.h
/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
/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
/langinfo.h
/langinfo.in.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
/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
/memcpy.c
/minmax.h
/mktime.c
/mktime-internal.h
/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
/ref-add.sed
/ref-add.sin
/ref-del.sed
/ref-del.sin
/setenv.c
/setlocale-lock.c
/setlocale_null.c
/setlocale_null.h
/setlocale_null-unlocked.c
/stat.c
/stdalign.h
/stdalign.in.h
/stdarg.in.h
/stdbool.in.h
/stat-time.c
/stat-time.h
/stat-w32.c
/stat-w32.h
/stdckdint.h
/stdckdint.in.h
/stddef.h
/stddef.in.h
/stdio-impl.h
/stdio.c
/stdint.in.h
/stdio.h
/stdio-impl.h
/stdio.in.h
/stdio-read.c
/stdio-write.c
/stdlib.c
/stdlib.h
/stdlib.in.h
/str-two-way.h
/stpncpy.c
/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
/unused-parameter.h
/unitypes.h
/unitypes.in.h
/unsetenv.c
/verify.h
/warn-on-use.h
/wchar.h
/wchar.in.h
/wctype-h.c
/wctype.h
/wctype-h.c
/wctype.in.h
/windows-initguard.h
/xalloc-die.c
/xalloc-oversized.h
/xalloc.h
/xalloc-oversized.h
/xmalloc.c
/xprintf.c
/xprintf.h
/xstrtod.c
/xstrtod.h
/stpncpy.c

View file

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

View file

@ -1,9 +1,28 @@
.TH DHCPD-POOLS "1" "2012-11-25" "@PACKAGE_STRING@" "User Commands"
'\" t
.TH DHCPD-POOLS "1" "2024-08-09" "@VERSION@" "User Commands"
.SH NAME
dhcpd-pools \- ISC dhcpd pools usage analysis
.SH SYNOPSIS
.B dhcpd-pools
[options]
.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
.SH DESCRIPTION
The program analyses ISC dhcpd shared network and pool usage and outputs the
results in a format selected by user.
@ -49,29 +68,29 @@ only if there is failover configuration.
.SH OPTIONS
.TP
\fB\-c\fR, \fB\-\-config\fR=\fIFILE\fR
Path to the dhcpd.conf file.
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.
.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. 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.
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.
.TP
\fB\-r\fR, \fB\-\-reverse\fR
Sort results in reverse order.
.TP
\fB\-f\fR, \fB\-\-format\fR=\fI[thHcxXjJ]\fR
\fB\-f\fR, \fB\-\-format\fR=\fI[tHcxXjJ]\fR
Output format.
Text
.RI ( t ).
Standard html
.RI ( h )
outputs only the HTML tables, and is useful for embedding more complex web
pages. Full-html
Full-html
.RI ( H )
provides complete HTML headers, etc., including in-line CSS. The
page output. In html page critical and warning thresholds can be visualized
with \-\-color=always option. The
.RI ( c )
stands for comma-separated values. Output format xml
.RI ( x )
@ -86,6 +105,18 @@ 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.
@ -104,29 +135,17 @@ 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@ .
.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
.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
.IP
The output limit for total summary has special meaning in
.B \-\-warning
@ -136,6 +155,37 @@ 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
@ -159,12 +209,55 @@ is
If critical percentage is not specified it defaults to
.BR @ALARM_CRIT@ .
.TP
\fB\-\-minsize\fR=\fIsize\f
\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
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 intented to supress for example single host ranges. By default this
will intended to suppress 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
@ -193,7 +286,7 @@ $ dhcpd-pools \-c dhcpd.conf \-l dhcpd.leases \-L 22 \-\-critical 70 \-\-warning
.br
[no-output]
.br
Supress printing OK, and make alarm only to go off if shared networks
Suppress printing OK, and make alarm only to go off if shared networks
exceed critial or warning levels.
.SH FILES
.TP
@ -202,14 +295,23 @@ 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.
.PP
The software has FreeBSD License.
.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.
.SH "REPORTING BUGS"
Report bugs to
.MT @PACKAGE_BUGREPORT@
@ -222,4 +324,6 @@ Home page
.SH "SEE ALSO"
.BR dhcpd.leases (5),
.BR dhcpd.conf (5),
.BR chmod (1)
.BR chmod (1),
.UR https://mustache.github.io/
.UE

38
project.doap Normal file
View file

@ -0,0 +1,38 @@
<?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>

5
samples/Makemodule.am Normal file
View file

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

31
samples/dhcpd.conf Normal file
View file

@ -0,0 +1,31 @@
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;
}
}

210
samples/dhcpd.leases Normal file
View file

@ -0,0 +1,210 @@
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;
}

76
samples/mustach.template Normal file
View file

@ -0,0 +1,76 @@
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

@ -0,0 +1,11 @@
# 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,2 +1,16 @@
-linux -Tuintmax_t -TFILE -Tsize_t -Toff_t -Ttime_t -ppi1
-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

View file

@ -4,11 +4,10 @@ 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
dhcpd_pools_LDADD = $(top_builddir)/lib/libdhcpd_pools.la $(MATH_LIBS)
dhcpd_pools_SOURCES = \
src/analyze.c \
src/defaults.h \
src/dhcpd-pools.c \
src/dhcpd-pools.h \
src/getdata.c \
@ -16,3 +15,10 @@ 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,40 +46,33 @@
#include "dhcpd-pools.h"
/*! \brief Prepare data for analysis. The function will sort leases and
* ranges.
* FIXME: This function should return void. */
int prepare_data(void)
* ranges. */
void prepare_data(struct conf_t *state)
{
/* Sort leases */
HASH_SORT(leases, ipcomp);
HASH_SORT(state->leases, leasecomp);
/* Sort ranges */
qsort(ranges, (size_t)num_ranges, sizeof(struct range_t), &rangecomp);
return 0;
qsort(state->ranges, state->num_ranges, sizeof(struct range_t), &rangecomp);
}
/*! \brief Perform counting. Join leases with ranges, and update counters.
* FIXME: This function should return void. */
int do_counting(void)
/*!\brief Perform counting. Join leases with ranges, and update range and
* shared network counters. */
void do_counting(struct conf_t *state)
{
struct range_t *restrict range_p;
const struct leases_t *restrict l = leases;
unsigned long i, k, block_size;
range_p = ranges;
struct range_t *restrict range_p = state->ranges;
const struct leases_t *restrict l = state->leases;
unsigned long i;
double block_size;
/* Walk through ranges */
for (i = 0; i < num_ranges; i++) {
for (; l != NULL && ipcomp(&range_p->first_ip, &l->ip) < 0;
l = l->hh.prev)
/* rewind */ ;
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 */
if (l == NULL)
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;
}
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? */
/* IP in range */
switch (l->type) {
case FREE:
@ -91,46 +84,23 @@ int do_counting(void)
case BACKUP:
range_p->backups++;
break;
}
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;
default:
abort();
}
}
}
/* Size of range, shared net & all networks */
/* Size of range size. */
block_size = get_range_size(range_p);
if (range_p->shared_net) {
/* 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;
}
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;
}

View file

@ -1,55 +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 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,166 +38,253 @@
*/
#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 "defaults.h"
#include "dhcpd-pools.h"
#include "error.h"
#include "progname.h"
#include "quote.h"
#include "xalloc.h"
/*! \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_WARN = CHAR_MAX + 1,
OPT_CRIT,
OPT_MINSIZE
};
int ret_val;
#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)
{
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_CRIT,
OPT_MINSIZE,
OPT_WARN_COUNT,
OPT_CRIT_COUNT,
OPT_COLOR,
OPT_SKIP,
OPT_SET_IPV,
OPT_MUSTACH
};
/* 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 */
strncpy(config.dhcpdconf_file, optarg, MAXLEN - 1);
state->dhcpdconf_file = optarg;
break;
case 'l':
/* lease file */
strncpy(config.dhcpdlease_file, optarg, MAXLEN - 1);
state->dhcpdlease_file = optarg;
break;
case 'f':
/* Output format */
strncpy(config.output_format, optarg, (size_t)1);
state->output_format = optarg[0];
break;
case 's':
{
/* 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;
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 {
strncpy(config.sort, optarg, (size_t)sorts);
p->next = xcalloc(1, sizeof(struct output_sort));
p = p->next;
}
p->func = field_selector(*ptr++);
}
for (i = 0; i < sorts; i++) {
field_selector(config.sort[i]);
}
break;
case 'r':
/* What ever sort in reverse order */
config.reverse_order = true;
state->reverse_order = 1;
break;
case 'o':
/* Output file */
strncpy(config.output_file, optarg, MAXLEN - 1);
state->output_file = optarg;
break;
case 'L':
/* Specification what will be printed */
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);
}
}
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:
strcpy(config.output_format, "a");
config.warning =
strtod_or_err(optarg, "illegal argument");
alarming = 1;
state->warning = strtod_or_err(optarg, "illegal argument");
break;
case OPT_CRIT:
strcpy(config.output_format, "a");
config.critical =
strtod_or_err(optarg, "illegal argument");
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:
config.minsize =
strtod_or_err(optarg, "illegal argument");
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);
}
break;
case 'p':
/* Print additional performance data in alarming mode */
state->perfdata = 1;
break;
case 'A':
/* Treat single networks as shared with network CIDR as name */
state->all_as_shared = 1;
break;
case 'v':
/* Print version */
@ -206,88 +293,76 @@ int main(int argc, char **argv)
/* Print help */
usage(EXIT_SUCCESS);
default:
errx(EXIT_FAILURE,
"Try `%s --help' for more information.",
program_name);
error(EXIT_FAILURE, 0, "Try %s --help for more information.", program_name);
}
}
/* 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]);
/* 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 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 */
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();
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);
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,8 +35,6 @@
/*! \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
@ -44,7 +42,6 @@
# include <config.h>
# include <arpa/inet.h>
# include <stdbool.h>
# include <stddef.h>
# include <stdio.h>
# include <string.h>
@ -64,23 +61,37 @@
# 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 Indicator which IP version is in use.
* \brief The IP version, IPv4 or IPv6, served by the dhcpd.
*/
enum dhcp_version {
VERSION_4,
VERSION_6,
VERSION_UNKNOWN
IPvUNKNOWN,
IPv4,
IPv6
};
/*! \enum prefix_t
* \brief Enumeration of interesting data in dhcpd.leases file, that has
* to be further examined, and saved.
* \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().
*/
enum prefix_t {
PREFIX_LEASE,
@ -91,29 +102,25 @@ enum prefix_t {
PREFIX_BINDING_STATE_ACTIVE,
PREFIX_BINDING_STATE_BACKUP,
PREFIX_HARDWARE_ETHERNET,
PREFIX_STARTS,
PREFIX_ENDS,
PREFIX_HOSTNAME,
NUM_OF_PREFIX
};
/*! \struct configuration_t
* \brief Runtime configuration.
/*! \enum color_mode
* \brief Enumeration whether to use or not color output.
*/
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;
enum color_mode {
color_unknown,
color_off,
color_on,
color_auto /*!< Default, use colors when output terminal is interactive. */
};
/*! \struct shared_network_t
* \brief Counters for an individual shared network.
* \brief Counters for an individual shared network. This data entry is
* also used for 'all networks' counting.
*/
struct shared_network_t {
char *name;
@ -121,7 +128,10 @@ 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.
*/
@ -133,162 +143,230 @@ struct range_t {
double touched;
double backups;
};
/*! \enum isc_conf_parser
* \brief Configuration file parsing state flags.
/*! \struct output_helper_t
* \brief Various per range and shared net temporary calculation results.
*/
enum isc_conf_parser {
ITS_NOTHING_INTERESTING,
ITS_A_RANGE_FIRST_IP,
ITS_A_RANGE_SECOND_IP,
ITS_A_SHAREDNET,
ITS_AN_INCLUCE
struct output_helper_t {
double range_size;
double percent;
double tc;
double tcp;
double bup;
int status;
};
/*! \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.
* \brief Lease state types. These are the possible values in struct leases_t.
*/
enum ltype {
ACTIVE,
FREE,
BACKUP
};
/*! \struct leases_t
* \brief An individual lease. The leaases are hashed.
* \brief An individual lease. These 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 {
BIT1 = 0x1,
BIT2 = 0x2,
BIT3 = 0x4
R_BIT = (1 << 0), /*!< Range limit. */
S_BIT = (1 << 1), /*!< Shared networks limit. */
A_BIT = (1 << 2) /*!< All networks summary limit. */
};
/* 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;
/*! \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. */
};
/* Function prototypes */
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)
/* 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)
__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);
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 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);
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);
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);
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);
#endif /* DHCPD_POOLS_H */

View file

@ -40,117 +40,143 @@
#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 "defaults.h"
#include "dhcpd-pools.h"
#include "error.h"
#include "xalloc.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
};
/*! \brief Lease file parser. The parser can only read ISC DHCPD
* dhcpd.leases file format. */
int parse_leases(void)
int parse_leases(struct conf_t *state)
{
FILE *dhcpd_leases;
char *line, *ipstring, macstring[20], *stop;
char *line, *ipstring, macstring[20], *stop, endsstr[30], startsstr[30], hostnamestr[MAXLEN];
union ipaddr_t addr;
struct stat lease_file_stats;
bool ethernets = false;
struct leases_t *lease;
dhcpd_leases = fopen(config.dhcpdlease_file, "r");
if (dhcpd_leases == NULL) {
err(EXIT_FAILURE, "parse_leases: %s", config.dhcpdlease_file);
}
dhcpd_leases = fopen(state->dhcpdlease_file, "r");
if (dhcpd_leases == NULL)
error(EXIT_FAILURE, errno, "parse_leases: %s", state->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) {
err(EXIT_FAILURE, "parse_leases: fadvise %s",
config.dhcpdlease_file);
}
if (posix_fadvise(fileno(dhcpd_leases), 0, 0, POSIX_FADV_SEQUENTIAL) != 0)
error(EXIT_FAILURE, errno, "parse_leases: fadvise %s", state->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);
if (config.output_format[0] == 'X' || config.output_format[0] == 'J') {
ethernets = true;
}
ipstring[0] = '\0';
endsstr[0] = '\0';
startsstr[0] = '\0';
hostnamestr[0] = '\0';
while (!feof(dhcpd_leases)) {
if (!fgets(line, MAXLEN, dhcpd_leases) && ferror(dhcpd_leases)) {
err(EXIT_FAILURE, "parse_leases: %s",
config.dhcpdlease_file);
}
switch(xstrstr(line)) {
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 */
case PREFIX_LEASE:
stop = memccpy(ipstring, line + (config.dhcp_version == VERSION_4 ? 6 : 9), ' ', strlen(line));
stop =
memccpy(ipstring,
line + (state->ip_version ==
IPv4 ? 6 : 9), ' ', strlen(line));
if (stop != NULL) {
--stop;
*stop = '\0';
}
parse_ipaddr(ipstring, &addr);
parse_ipaddr(state, 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(&addr)) != NULL) {
delete_lease(lease);
}
add_lease(&addr, FREE);
if ((lease = find_lease(state, &addr)) != NULL)
delete_lease(state, lease);
add_lease(state, &addr, FREE);
break;
case PREFIX_BINDING_STATE_ACTIVE:
/* remove old entry, if exists */
if ((lease = find_lease(&addr)) != NULL) {
delete_lease(lease);
}
add_lease(&addr, ACTIVE);
if ((lease = find_lease(state, &addr)) != NULL)
delete_lease(state, lease);
add_lease(state, &addr, ACTIVE);
break;
case PREFIX_BINDING_STATE_BACKUP:
/* remove old entry, if exists */
if ((lease = find_lease(&addr)) != NULL) {
delete_lease(lease);
}
add_lease(&addr, BACKUP);
config.backups_found = true;
if ((lease = find_lease(state, &addr)) != NULL)
delete_lease(state, lease);
add_lease(state, &addr, BACKUP);
state->backups_found = 1;
break;
case PREFIX_HARDWARE_ETHERNET:
if (ethernets == false)
if (state->print_mac_addreses == 0)
break;
memcpy(macstring, line + 20, 17);
macstring[17] = '\0';
if ((lease = find_lease(&addr)) != NULL) {
if ((lease = find_lease(state, &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
@ -163,70 +189,88 @@ int parse_leases(void)
/*! \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(char const *restrict s)
static int is_interesting_config_clause(struct conf_t *state, 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_INCLUCE;
return ITS_AN_INCLUDE;
return ITS_NOTHING_INTERESTING;
}
/*! \brief The dhcpd.conf file parser.
* FIXME: This spaghetti monster function need to be rewrote at least
* ones.
/*! \brief Flip first and last IP in range if they are in unusual order.
*/
void parse_config(int is_include, const char *restrict config_file,
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.
*/
void parse_config(struct conf_t *state, const int is_include, const char *restrict config_file,
struct shared_network_t *restrict shared_p)
{
FILE *dhcpd_config;
bool newclause = true, comment = false, one_ip_range = false;
int newclause = 1, comment = 0, one_ip_range = 0; /* booleans */
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;
struct range_t *range_p = NULL;
word = xmalloc(sizeof(char) * MAXLEN);
if (is_include) {
if (is_include)
/* Default place holder for ranges "All networks". */
shared_p->name = shared_networks->name;
}
shared_p->name = state->shared_net_root->name;
/* Open configuration file */
dhcpd_config = fopen(config_file, "r");
if (dhcpd_config == NULL) {
err(EXIT_FAILURE, "parse_config: %s", config_file);
if (is_include) {
error(0, errno, "cannot open inlude: %s", config_file);
return;
}
#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);
/* config if from command line, just exit with error */
error(EXIT_FAILURE, errno, "parse_config: %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 */
#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 */
/* Very hairy stuff begins. */
while (unlikely(!feof(dhcpd_config))) {
char c;
int 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 = true;
}
if (quote == 0)
comment = 1;
continue;
case '"':
if (comment == false) {
if (comment == 0) {
quote++;
/* Either one or zero */
quote = quote % 2;
@ -235,22 +279,19 @@ void parse_config(int is_include, const char *restrict config_file,
case '\n':
/* New line resets comment section, but
* not if quoted */
if (quote == 0) {
comment = false;
}
if (quote == 0)
comment = 0;
break;
case ';':
/* Quoted colon does not mean new clause */
if (0 < quote) {
if (0 < quote)
break;
}
if (comment == false
if (comment == 0
&& argument != ITS_A_RANGE_FIRST_IP
&& argument != ITS_A_RANGE_SECOND_IP
&& argument != ITS_AN_INCLUCE) {
newclause = true;
&& argument != ITS_A_RANGE_SECOND_IP && argument != ITS_AN_INCLUDE) {
newclause = 1;
i = 0;
} else if (argument == ITS_A_RANGE_FIRST_IP && one_ip_range == true) {
} else if (argument == ITS_A_RANGE_FIRST_IP && one_ip_range == 1) {
argument = ITS_A_RANGE_SECOND_IP;
c = ' ';
} else if (argument == ITS_A_RANGE_SECOND_IP && 0 < i) {
@ -261,165 +302,178 @@ void parse_config(int is_include, const char *restrict config_file,
*
* ...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 = true;
newclause = 1;
continue;
} else {
break;
}
break;
case '}':
if (0 < quote) {
if (0 < quote)
break;
}
if (comment == false) {
if (comment == 0) {
braces--;
/* End of shared-network */
if (braces_shared == braces) {
/* FIXME: Using 1000 is lame, but
* works. */
braces_shared = 1000;
shared_p = shared_networks;
shared_p = state->shared_net_root;
}
/* Not literally true, but works for this
/* Not literally 1, but works for this
* program */
newclause = true;
newclause = 1;
}
continue;
default:
break;
}
/* Either inside comment or Nth word of clause. */
if (comment == true
|| (newclause == false
&& argument == ITS_NOTHING_INTERESTING)) {
if (comment == 1 || (newclause == 0 && argument == ITS_NOTHING_INTERESTING))
continue;
}
/* Strip white spaces before new clause word. */
if ((newclause == true || argument != ITS_NOTHING_INTERESTING)
&& isspace(c) && i == 0 && one_ip_range == false) {
if ((newclause == 1 || argument != ITS_NOTHING_INTERESTING)
&& isspace(c) && i == 0 && one_ip_range == 0)
continue;
}
/* Save to word which clause this is. */
if ((newclause == true || argument != ITS_NOTHING_INTERESTING)
if ((newclause == 1 || argument != ITS_NOTHING_INTERESTING)
&& (!isspace(c) || 0 < quote)) {
word[i] = c;
word[i] = (char) c;
i++;
/* Long word which is almost causing overflow. None
* of words are this long which the program is
* searching. */
if (MAXLEN < i) {
newclause = false;
if (MAXLEN == i) {
newclause = 0;
i = 0;
continue;
}
}
/* See if clause is something that parser is looking for. */
else if (newclause == true) {
else if (newclause == 1) {
/* Insert string end & set state */
word[i] = '\0';
if (word[i - 1] != '{') {
newclause = false;
}
if (word[i - 1] != '{')
newclause = 0;
i = 0;
argument = is_interesting_config_clause(word);
if (argument == ITS_A_RANGE_FIRST_IP) {
one_ip_range = true;
}
argument = is_interesting_config_clause(state, word);
if (argument == ITS_A_RANGE_FIRST_IP)
one_ip_range = 1;
}
/* words after range, shared-network or include */
else if (argument != ITS_NOTHING_INTERESTING) {
word[i] = '\0';
newclause = false;
newclause = 0;
i = 0;
switch (argument) {
case ITS_A_RANGE_SECOND_IP:
/* printf ("range 2nd ip: %s\n", word); */
range_p = ranges + num_ranges;
range_p = state->ranges + state->num_ranges;
argument = ITS_NOTHING_INTERESTING;
parse_ipaddr(word, &addr);
if (one_ip_range == true) {
one_ip_range = false;
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);
}
newrange:
range_p->count = 0;
range_p->touched = 0;
range_p->backups = 0;
range_p->shared_net = shared_p;
num_ranges++;
if (RANGES < num_ranges + 1) {
RANGES *= 2;
ranges =
xrealloc(ranges,
sizeof(struct
range_t) * RANGES);
range_p = ranges + num_ranges;
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;
}
newclause = true;
newclause = 1;
break;
case ITS_A_RANGE_FIRST_IP:
/* printf ("range 1nd ip: %s\n", word); */
range_p = ranges + num_ranges;
if (!(parse_ipaddr(word, &addr))) {
/* word was not ip, try
* again */
/* 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 */
break;
}
copy_ipaddr(&range_p->first_ip, &addr);
one_ip_range = false;
one_ip_range = 0;
argument = ITS_A_RANGE_SECOND_IP;
break;
case ITS_A_SHAREDNET:
/* printf ("shared-network named: %s\n", word); */
num_shared_networks++;
shared_p =
shared_networks + num_shared_networks;
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;
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_INCLUCE:
case ITS_AN_INCLUDE:
/* printf ("include file: %s\n", word); */
argument = ITS_NOTHING_INTERESTING;
parse_config(false, word, shared_p);
newclause = true;
parse_config(state, 0, word, shared_p);
newclause = 1;
break;
case ITS_NOTHING_INTERESTING:
/* printf ("nothing interesting: %s\n", word); */
argument = ITS_NOTHING_INTERESTING;
break;
default:
warnx("impossible occurred, report a bug");
assert(0);
puts("impossible occurred, report a bug");
abort();
}
}
}

View file

@ -38,90 +38,118 @@
* analysis happen as quick as possible..
*/
#include "dhcpd-pools.h"
#include <config.h>
#include <stdlib.h>
#include "xalloc.h"
#include "dhcpd-pools.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)
/*! \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(union ipaddr_t *addr __attribute__((unused)), enum ltype type __attribute__((unused)))
void add_lease_init(struct conf_t *state __attribute__ ((unused)), union ipaddr_t *addr
__attribute__ ((unused)), enum ltype type __attribute__ ((unused)))
{
}
void add_lease_v4(union ipaddr_t *addr, enum ltype type)
void add_lease_v4(struct conf_t *state, 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(leases, ip.v4, l);
HASH_ADD_INT(state->leases, ip.v4, l);
l->ethernet = NULL;
l->ends = NULL;
l->starts = NULL;
l->hostname = NULL;
}
void add_lease_v6(union ipaddr_t *addr, enum ltype type)
void add_lease_v6(struct conf_t *state, 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(leases, ip.v6, l);
HASH_ADD_V6(state->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(union ipaddr_t *addr __attribute__((unused)))
struct leases_t *find_lease_init(struct conf_t *state __attribute__ ((unused)), union ipaddr_t *addr
__attribute__ ((unused)))
{
return NULL;
}
struct leases_t *find_lease_v4(union ipaddr_t *addr)
struct leases_t *find_lease_v4(struct conf_t *state, union ipaddr_t *addr)
{
struct leases_t *l;
HASH_FIND_INT(leases, &addr->v4, l);
HASH_FIND_INT(state->leases, &addr->v4, l);
return l;
}
struct leases_t *find_lease_v6(union ipaddr_t *addr)
struct leases_t *find_lease_v6(struct conf_t *state, union ipaddr_t *addr)
{
struct leases_t *l;
HASH_FIND_V6(leases, &addr->v4, l);
HASH_FIND_V6(state->leases, &addr->v4, l);
return l;
}
/*! \brief Delete a lease from hash array.
* \param lease Pointer to lease hash. */
void delete_lease(struct leases_t *lease)
void delete_lease(struct conf_t *state, struct leases_t *lease)
{
free(lease->ethernet);
HASH_DEL(leases, lease);
free(lease->ends);
free(lease->starts);
free(lease->hostname);
HASH_DEL(state->leases, lease);
free(lease);
}
/*! \brief Delete all leases from hash array. */
#ifdef HASH_ITER
void delete_all_leases(void)
void delete_all_leases(struct conf_t *state)
{
struct leases_t *l, *tmp;
HASH_ITER(hh, leases, l, tmp) {
HASH_ITER(hh, state->leases, l, tmp) {
free(l->ethernet);
HASH_DEL(leases, l);
free(l->ends);
free(l->starts);
free(l->hostname);
HASH_DEL(state->leases, l);
free(l);
}
}
#else
void delete_all_leases(void)
void delete_all_leases(struct conf_t *state)
{
while (leases) {
while (state->leases) {
struct leases_t *l;
l = leases;
l = state->leases;
free(l->ethernet);
HASH_DEL(leases, l); /* leases advances to next on delete */
free(l->ends);
free(l->starts);
free(l->hostname);
HASH_DEL(state->leases, l); /* leases advances to next on delete */
free(l);
}
}

519
src/mustach-dhcpd-pools.c Normal file
View file

@ -0,0 +1,519 @@
/*
* 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;
}

325
src/mustach.c Normal file
View file

@ -0,0 +1,325 @@
/*
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;
}

120
src/mustach.h Normal file
View file

@ -0,0 +1,120 @@
/*
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,62 +39,75 @@
#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 <limits.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);
/*! \brief Set function pointers depending on IP version.
* \param ip IP version.
*/
void set_ipv_functions(int version)
void set_ipv_functions(struct conf_t *state, int version)
{
switch (version) {
case VERSION_4:
config.dhcp_version = version;
case IPv4:
state->ip_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 VERSION_6:
config.dhcp_version = version;
case IPv6:
state->ip_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 VERSION_UNKNOWN:
config.dhcp_version = version;
case IPvUNKNOWN:
state->ip_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;
@ -110,55 +123,160 @@ void set_ipv_functions(int version)
* \param dst An union which will hold conversion result.
* \return Was parsing successful.
*/
int parse_ipaddr_init(const char *restrict src, union ipaddr_t *restrict dst)
int parse_ipaddr_init(struct conf_t *state, 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(VERSION_4);
} else if (inet_pton(AF_INET6, src, &addr6) == 1) {
set_ipv_functions(VERSION_6);
} else {
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
return 0;
}
return parse_ipaddr(src, dst);
return parse_ipaddr(state, src, dst);
}
int parse_ipaddr_v4(const char *restrict src, union ipaddr_t *restrict dst)
int parse_ipaddr_v4(struct conf_t *state
__attribute__ ((unused)), 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(const char *restrict src, union ipaddr_t *restrict dst)
int parse_ipaddr_v6(struct conf_t *state
__attribute__ ((unused)), 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));
}
@ -171,25 +289,27 @@ void copy_ipaddr_v6(union ipaddr_t *restrict dst,
* \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[sizeof("255.255.255.255")];
static char buffer[INET_ADDRSTRLEN];
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[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
static char buffer[INET6_ADDRSTRLEN];
struct in6_addr addr;
memcpy(addr.s6_addr, ip->v6, sizeof(addr.s6_addr));
return inet_ntop(AF_INET6, &addr, buffer, sizeof(buffer));
}
@ -200,7 +320,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;
}
@ -214,6 +334,7 @@ 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... */
@ -231,17 +352,14 @@ double get_range_size_v6(const struct range_t *r)
* \param str A line from dhcpd.conf
* \return prefix_t enum value
*/
int
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((hot))
#endif
xstrstr_init(const char *restrict str)
int xstrstr_init(struct conf_t *state, const char *restrict str)
{
if (memcmp("lease ", str, 6)) {
set_ipv_functions(VERSION_4);
if (!memcmp("lease ", str, 6)) {
set_ipv_functions(state, IPv4);
return PREFIX_LEASE;
} else if (memcmp(" iaaddr ", str, 9)) {
set_ipv_functions(VERSION_6);
}
if (!memcmp(" iaaddr ", str, 9)) {
set_ipv_functions(state, IPv6);
return PREFIX_LEASE;
}
return NUM_OF_PREFIX;
@ -257,14 +375,14 @@ int
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((hot))
#endif
xstrstr_v4(const char *restrict str)
xstrstr_v4(struct conf_t *state __attribute__ ((unused)), 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':
@ -293,11 +411,18 @@ 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;
}
@ -311,14 +436,14 @@ int
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
__attribute__ ((hot))
#endif
xstrstr_v6(const char *restrict str)
xstrstr_v6(struct conf_t *state __attribute__ ((unused)), 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':
@ -347,14 +472,37 @@ 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.
@ -370,118 +518,142 @@ 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:
if (errno)
err(EXIT_FAILURE, "%s: '%s'", errmesg, str);
errx(EXIT_FAILURE, "%s: '%s'", errmesg, str);
error(EXIT_FAILURE, errno, "%s: %s", errmesg, quote(str));
return 0;
}
/*! \brief Reverse range.
* 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)
* Used before output, if a caller has requested reverse sorting. */
void flip_ranges(struct conf_t *state)
{
unsigned int i = num_ranges - 1, j;
unsigned int i = state->num_ranges - 1, j;
struct range_t *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));
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);
}
/*! \brief Free memory, flush buffers etc. */
void clean_up(void)
void clean_up(struct conf_t *state)
{
unsigned int i;
struct output_sort *cur, *next;
struct shared_network_t *c, *n;
/* Just in case there something in buffers */
if (fflush(NULL)) {
warn("clean_up: fflush");
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);
}
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);
for (c = state->shared_net_root; c; c = n) {
n = c->next;
free(c->name);
free(c);
}
free(shared_networks);
}
/*! \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);
}
}
/*! \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 by Sami Kerola.\n"
"Original design and maintainer Sami Kerola.\n"
"uthash %s by Troy D. Hanson.\n"
"XML support by Dominic Germain, Sogetel inc.\n"
"IPv6 support by Cheer Xiao.\n\n"
"The software has FreeBSD License.\n", PACKAGE_STRING);
"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));
exit(EXIT_SUCCESS);
}
/*! \brief Command line help screen. */
void __attribute__ ((__noreturn__)) usage(int status)
{
FILE *out;
out = status != 0 ? stderr : stdout;
FILE *out = status == EXIT_SUCCESS ? stdout : stderr;
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);
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);
exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
exit(status);
}

File diff suppressed because it is too large Load diff

View file

@ -40,28 +40,30 @@
#include <config.h>
#include <err.h>
#include <errno.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "dhcpd-pools.h"
#include "error.h"
#include "progname.h"
#include "quote.h"
#include "xalloc.h"
#include "dhcpd-pools.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;
@ -70,12 +72,36 @@ int ipcomp_v4(const union ipaddr_t *restrict a,
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.
@ -93,9 +119,14 @@ int rangecomp(const void *restrict r1, const void *restrict r2)
*/
int comp_double(double f1, double f2)
{
return f1 < f2 ? -1 : f1 > f2 ? 1 : 0;
if (isless(f1, f2))
return -1;
else if (isless(f2, f1))
return 1;
return 0;
}
/*! \brief Compare two range_t by their first_ip.
* \param r1,r2 Pointers to data to compare.
* \return Like strcmp.
@ -197,7 +228,7 @@ comparer_t field_selector(char c)
{
switch (c) {
case 'n':
break;
return NULL;
case 'i':
return comp_ip;
case 'm':
@ -213,10 +244,11 @@ comparer_t field_selector(char c)
case 'e':
return comp_tcperc;
default:
clean_up();
warnx("field_selector: unknown sort order `%c'", c);
errx(EXIT_FAILURE, "Try `%s --help' for more information.",
program_name);
{
char str[2] = { c, '\0' };
error(EXIT_FAILURE, 0, "field_selector: unknown sort order: %s",
quote(str));
}
}
return NULL;
}
@ -226,85 +258,69 @@ 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 range_t *restrict left, struct range_t *restrict right)
static int merge(struct conf_t *state, struct range_t *restrict left, struct range_t *restrict right)
{
int i, len, ret;
comparer_t comparer;
int cmp;
struct output_sort *p;
int ret;
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);
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);
}
if (0 < ret)
return (0);
if (ret < 0)
return (1);
continue;
}
/* 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);
}
/* If all comparers where equal */
/* this is reached if nothing was sorted */
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 range_t *restrict orig, int size,
struct range_t *restrict temp)
void mergesort_ranges(struct conf_t *state, struct range_t *restrict orig, unsigned int size,
struct range_t *restrict temp, const int root_call)
{
int left, right, i;
unsigned int left, i, u_right;
struct range_t hold;
/* Merge sort split size */
static const int MIN_MERGE_SIZE = 8;
static const unsigned int MIN_MERGE_SIZE = 8;
if (temp == NULL)
temp = xmalloc(sizeof(struct range_t) * size);
if (size < MIN_MERGE_SIZE) {
for (left = 0; left < size; left++) {
int s_right;
hold = *(orig + left);
for (right = left - 1; 0 <= right; right--) {
if (merge((orig + right), &hold)) {
for (s_right = left - 1; 0 <= s_right; s_right--) {
if (merge(state, (orig + s_right), &hold))
break;
*(orig + s_right + 1) = *(orig + s_right);
}
*(orig + right + 1) = *(orig + right);
}
*(orig + right + 1) = hold;
*(orig + s_right + 1) = hold;
}
if (root_call)
free(temp);
return;
}
mergesort_ranges(orig, size / 2, temp);
mergesort_ranges(orig + size / 2, size - size / 2, temp);
mergesort_ranges(state, orig, size / 2, temp, 0);
mergesort_ranges(state, orig + size / 2, size - size / 2, temp, 0);
left = 0;
right = size / 2;
u_right = size / 2;
i = 0;
while (left < size / 2 && right < size) {
if (merge((orig + left), (orig + right))) {
while (left < size / 2 && u_right < size) {
if (merge(state, (orig + left), (orig + u_right))) {
*(temp + i) = *(orig + left);
left++;
} else {
*(temp + i) = *(orig + right);
right++;
*(temp + i) = *(orig + u_right);
u_right++;
}
i++;
}
@ -313,11 +329,13 @@ void mergesort_ranges(struct range_t *restrict orig, int size,
left++;
i++;
}
while (right < size) {
*(temp + i) = *(orig + right);
right++;
while (u_right < size) {
*(temp + i) = *(orig + u_right);
u_right++;
i++;
}
memcpy(orig, temp, size * sizeof(struct range_t));
if (root_call)
free(temp);
}

View file

@ -1,4 +1,5 @@
TESTS = \
tests/alarm-count-option \
tests/alarm-critical \
tests/alarm-critical-ranges \
tests/alarm-critical-snets \
@ -8,15 +9,38 @@ 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/v6
tests/skip \
tests/sorts \
tests/statuses \
tests/v6 \
tests/v6-perfdata
if ENABLE_MUSTACH
TESTS += \
tests/mustach
endif
EXTRA_DIST += \
tests/confs \

44
tests/alarm-count-option Executable file
View file

@ -0,0 +1,44 @@
#!/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 $?

1
tests/big-small Symbolic link
View file

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

14
tests/binding-states Executable file
View file

@ -0,0 +1,14 @@
#!/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 $?

1
tests/cidr-v4 Symbolic link
View file

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

1
tests/cidr-v6 Symbolic link
View file

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

16
tests/complete-perfdata Executable file
View file

@ -0,0 +1,16 @@
#!/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 $?

5
tests/confs/big-small Normal file
View file

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

1
tests/confs/binding-states Symbolic link
View file

@ -0,0 +1 @@
complete

31
tests/confs/cidr-v4 Normal file
View file

@ -0,0 +1,31 @@
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;
}
}

10
tests/confs/cidr-v6 Normal file
View file

@ -0,0 +1,10 @@
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;
}

1
tests/confs/formats Symbolic link
View file

@ -0,0 +1 @@
complete

1
tests/confs/one-line Normal file
View file

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

31
tests/confs/range4 Normal file
View file

@ -0,0 +1,31 @@
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;
}
}

4
tests/confs/range6 Normal file
View file

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

1
tests/confs/shnet-alarm Symbolic link
View file

@ -0,0 +1 @@
complete

1
tests/confs/shufled Symbolic link
View file

@ -0,0 +1 @@
complete

1
tests/confs/statuses Symbolic link
View file

@ -0,0 +1 @@
complete

48
tests/errors Executable file
View file

@ -0,0 +1,48 @@
#!/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

@ -0,0 +1,34 @@
== 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,2 +1,3 @@
CRITICAL: dhcpd-pools: Ranges; crit: 1 warn: 0 ok: 4 Shared nets; crit: 1 warn: 0 ok: 1
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
2

View file

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

View file

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

View file

@ -1 +1,2 @@
OK: Ranges; crit: 0 warn: 0 ok: 0 ignored: 1 Shared nets; crit: 0 warn: 0 ok: 0
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

View file

@ -1,2 +1,3 @@
OK: Ranges; crit: 0 warn: 0 ok: 5 Shared nets; crit: 0 warn: 0 ok: 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
0

View file

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

View file

@ -1,2 +1,3 @@
WARNING: dhcpd-pools: Ranges; crit: 0 warn: 1 ok: 4 Shared nets; crit: 0 warn: 1 ok: 1
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
1

View file

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

View file

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

1
tests/expected/big-small Symbolic link
View file

@ -0,0 +1 @@
simple

View file

@ -0,0 +1,16 @@
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,10 +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.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

1
tests/expected/bootp Symbolic link
View file

@ -0,0 +1 @@
simple

16
tests/expected/cidr-v4 Normal file
View file

@ -0,0 +1,16 @@
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

11
tests/expected/cidr-v6 Normal file
View file

@ -0,0 +1,11 @@
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

@ -0,0 +1,3 @@
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

27
tests/expected/errors Normal file
View file

@ -0,0 +1,27 @@
=== 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'

284
tests/expected/formats Normal file
View file

@ -0,0 +1,284 @@
=== 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

317
tests/expected/mustach Normal file
View file

@ -0,0 +1,317 @@
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

11
tests/expected/one-line Normal file
View file

@ -0,0 +1,11 @@
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

1
tests/expected/parser Symbolic link
View file

@ -0,0 +1 @@
complete

16
tests/expected/range4 Normal file
View file

@ -0,0 +1,16 @@
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

10
tests/expected/range6 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 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" }
{ "ip":"10.0.0.5", "macaddress":"00:00:00:00:00:00", "starts":"", "ends":"", "hostname":"" }
],
"subnets": [
{ "location":"All networks", "range":"10.0.0.1 - 10.0.0.10", "defined":10, "used":1, "free":9 }
{ "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 }
],
"shared-networks": [
],
@ -11,6 +11,13 @@
"location":"All networks",
"defined":10,
"used":1,
"free":9
"touched":0,
"free":9,
"percent":10,
"touch_count":1,
"touch_percent":10,
"status":0
},
"trivia": {
}
}

View file

@ -0,0 +1,24 @@
<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

@ -0,0 +1,3 @@
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

16
tests/expected/shufled Normal file
View file

@ -0,0 +1,16 @@
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

80
tests/expected/skip Normal file
View file

@ -0,0 +1,80 @@
--- 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

168
tests/expected/sorts Normal file
View file

@ -0,0 +1,168 @@
== 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

29
tests/expected/statuses Normal file
View file

@ -0,0 +1,29 @@
{
"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 }
]
}

View file

@ -0,0 +1,3 @@
OK: Ranges - crit: 0 warn: 0 ok: 2; | range_crit=0 range_warn=0 range_ok=2 dead:abba:4000::2_r=1;203.2;228.6;0;254 dead:abba:4000::2_rt=0 dead:abba:1000::2_r=2;3.77789e+21;4.25013e+21;0;4.72237e+21 dead:abba:1000::2_rt=1
Shared nets - crit: 0 warn: 0 ok: 0; | snet_crit=0 snet_warn=0 snet_ok=0

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