From 3c6b3682c70be84db86e70c191016913a9836c31 Mon Sep 17 00:00:00 2001 From: Emil Mikulic Date: Sat, 10 Oct 2015 21:20:24 +1100 Subject: [PATCH] Pull in darkstat-3.0.718 $ apt-get source darkstat --- ChangeLog | 24 ++- Makefile.in | 12 +- NEWS | 5 + acct.c | 2 +- acct.h | 2 +- bsd.c | 2 +- bsd.h | 4 +- cap.c | 22 ++- cap.h | 2 +- cdefs.h | 14 +- config.h.in | 3 - configure | 59 +----- configure.ac | 27 +-- contrib/darkstat_export | 257 +++++++++++++++++++++++++ conv.c | 12 +- darkstat.8.in | 29 ++- darkstat.c | 60 ++---- daylog.c | 25 ++- db.c | 2 +- db.h | 2 +- debian/README.Source | 10 - debian/changelog | 26 ++- debian/compat | 2 +- debian/control | 4 +- debian/patches/CorrectTcmpdump-section | 36 ++++ debian/patches/FixHURDsFTBS.patch | 17 ++ debian/patches/series | 2 + debian/rpack.sh | 36 ---- debian/rules | 10 +- debian/watch | 4 +- decode.c | 2 +- decode.h | 2 +- dns.c | 46 ++--- err.c | 2 +- err.h | 4 +- graph_db.c | 28 ++- hosts_db.c | 44 +++-- hosts_db.h | 4 +- hosts_sort.c | 2 +- http.c | 119 +++++++++--- http.h | 3 +- localip.c | 2 +- localip.h | 4 +- ncache.c | 4 +- now.c | 51 +++-- now.h | 10 +- opt.h | 2 +- pidfile.c | 16 +- str.c | 2 +- str.h | 28 ++- tree.h | 141 ++++++++++++-- 51 files changed, 863 insertions(+), 365 deletions(-) create mode 100644 contrib/darkstat_export delete mode 100644 debian/README.Source create mode 100644 debian/patches/CorrectTcmpdump-section create mode 100644 debian/patches/FixHURDsFTBS.patch create mode 100644 debian/patches/series delete mode 100755 debian/rpack.sh diff --git a/ChangeLog b/ChangeLog index 561c567..1a6e982 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +v3.0.718 (25 January 2014) + - (SECURITY!) Don't chroot() by default. The user must specify + a --chroot dir for this to happen now. + - Bring back the "--base /path" functionality. + - Add explicit warning about graphs being blank if we can't get + local IPs on an interface. + - Don't crash in timer_stop() if monotonic time stops or goes + backwards. + - Lots of internal cleanups. + - Use time_t instead of "long" for time. This is more correct + and should fix darkstat on OpenBSD 5.5 on 32-bit systems. + v3.0.717 (14 August 2013) - (OS X only) Work around lack of clock_gettime(). - Fix crash due to str_appendf() not understanding %ld. @@ -29,15 +41,17 @@ v3.0.714 (June 2011) - Allow sort on last-seen, thanks to Dirk Koopman. - Support multiple bind addresses. - Add --disable-debug configure flag, thanks to Malte S. Stretz. - - Make it possible to save the DB without resetting it (SIGUSR2). - - Web: Use relative URLs, so darkstat works properly behind mod_proxy, - thanks to Malte S. Stretz. + - Make it possible to export the database without resetting it: + by sending SIGUSR2. + - Web: Use relative URLs, so darkstat works properly + behind mod_proxy, thanks to Malte S. Stretz. v3.0.713 (March 2010) - Don't require --verbose for pcap_stats. - Survive interface going down on Linux. - Support DLT_RAW, implemented by Anton S. Ustyuzhanin. - - Skip accounting for hosts or ports if their max is set to zero. + - Skip accounting for hosts or ports if their max + is set to zero. - Implement --hexdump for troubleshooting. - Web: Implement --no-lastseen - Implement --snaplen manual override. @@ -177,6 +191,6 @@ v3.0.471 (Jun 2006) v2.6 (Nov 2003) - End of the line for darkstat 2 + End of the line for darkstat 2. vim:set noet ts=8 sw=8 tw=72: diff --git a/Makefile.in b/Makefile.in index b0dbf2e..6aa57d1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,5 @@ # darkstat 3 -# copyright (c) 2001-2011 Emil Mikulic. +# copyright (c) 2001-2014 Emil Mikulic. # # You may use, modify and redistribute this file under the terms of the # GNU General Public License version 2. (see COPYING.GPL) @@ -129,9 +129,9 @@ cap.o: cap.c acct.h cdefs.h cap.h config.h conv.h decode.h addr.h err.h \ hosts_db.h localip.h now.h opt.h queue.h str.h conv.o: conv.c conv.h err.h cdefs.h darkstat.o: darkstat.c acct.h cap.h cdefs.h config.h conv.h daylog.h \ - graph_db.h db.h dns.h err.h http.h hosts_db.h addr.h localip.h ncache.h \ - now.h pidfile.h -daylog.o: daylog.c err.h cdefs.h daylog.h graph_db.h str.h now.h + graph_db.h db.h dns.h err.h hosts_db.h addr.h http.h localip.h ncache.h \ + now.h pidfile.h str.h +daylog.o: daylog.c cdefs.h err.h daylog.h graph_db.h str.h now.h db.o: db.c cdefs.h err.h hosts_db.h addr.h graph_db.h db.h decode.o: decode.c cdefs.h decode.h addr.h err.h opt.h dns.o: dns.c cdefs.h conv.h decode.h addr.h dns.h err.h hosts_db.h \ @@ -142,12 +142,12 @@ graph_db.o: graph_db.c cap.h conv.h db.h acct.h err.h cdefs.h str.h \ hosts_db.o: hosts_db.c cdefs.h conv.h decode.h addr.h dns.h err.h \ hosts_db.h db.h html.h ncache.h now.h opt.h str.h hosts_sort.o: hosts_sort.c cdefs.h err.h hosts_db.h addr.h -html.o: html.c config.h str.h html.h opt.h +html.o: html.c config.h str.h cdefs.h html.h opt.h http.o: http.c cdefs.h config.h conv.h err.h graph_db.h hosts_db.h addr.h \ http.h now.h queue.h str.h stylecss.h graphjs.h localip.o: localip.c addr.h bsd.h config.h conv.h err.h cdefs.h localip.h \ now.h ncache.o: ncache.c conv.h err.h cdefs.h ncache.h tree.h bsd.h config.h -now.o: now.c err.h cdefs.h now.h +now.o: now.c err.h cdefs.h now.h str.h pidfile.o: pidfile.c err.h cdefs.h str.h pidfile.h str.o: str.c conv.h err.h cdefs.h str.h diff --git a/NEWS b/NEWS index c40c9de..5c4af07 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ Changes to defaults, most recent first: +- After v3.0.717, the user must specify a --chroot dir for chroot() to happen. + We don't set a default in the configure script anymore. + - After v3.0.708, --debug was split into --verbose and --no-daemon. - Since v3.0.694, darkstat is able to save its internal database into a file and @@ -17,3 +20,5 @@ Changes to defaults, most recent first: terminal, and run in the background. After 540, the default has been inverted. darkstat will daemonize by default. + +vim:set noet ts=8 sw=8 tw=80: diff --git a/acct.c b/acct.c index 17aa4f0..3605674 100644 --- a/acct.c +++ b/acct.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * acct.c: traffic accounting * diff --git a/acct.h b/acct.h index b4edb7f..0a4b261 100644 --- a/acct.h +++ b/acct.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * acct.h: traffic accounting */ diff --git a/bsd.c b/bsd.c index 9a9f156..0b9c316 100644 --- a/bsd.c +++ b/bsd.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2011 Emil Mikulic. * * bsd.c: *BSD compatibility. * diff --git a/bsd.h b/bsd.h index 3426add..6939f59 100644 --- a/bsd.h +++ b/bsd.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2011-2014 Emil Mikulic. * * bsd.h: *BSD compatibility. */ @@ -22,7 +22,7 @@ size_t strlcat(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_SETPROCTITLE -#define setproctitle(fmt, ...) /* no-op */ +#define setproctitle(fmt) /* no-op */ #endif /* vim:set ts=3 sw=3 tw=78 expandtab: */ diff --git a/cap.c b/cap.c index 7e1c41b..62da77d 100644 --- a/cap.c +++ b/cap.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * cap.c: capture packets, and hand them off to decode and acct. * @@ -398,12 +398,21 @@ static void callback(u_char *user, /* Process any packets currently in the capture buffer. */ void cap_poll(fd_set *read_set _unused_on_linux_) { struct cap_iface *iface; + static int told = 0; STAILQ_FOREACH(iface, &cap_ifs, entries) { /* Once per capture poll, check our IP address. It's used in accounting * for traffic graphs. */ localip_update(iface->name, &iface->local_ips); + if (!told && iface->local_ips.num_addrs == 0) { + verbosef("interface '%s' has no addresses, " + "your graphs will be blank", + iface->name); + verbosef("please read the darkstat manpage, " + "and consider using the -l option"); + told = 1; + } for (;;) { struct timespec t; @@ -415,18 +424,19 @@ void cap_poll(fd_set *read_set _unused_on_linux_) { -1, /* count = entire buffer */ callback, (u_char*)iface); /* user = struct to pass to callback */ + timer_stop(&t, + 2 * CAP_TIMEOUT_MSEC * 1000000, + "pcap_dispatch took too long"); if (ret < 0) { warnx("pcap_dispatch('%s'): %s", iface->name, pcap_geterr(iface->pcap)); continue; } - timer_stop(&t, - 2 * CAP_TIMEOUT_MSEC * 1000000, - "pcap_dispatch took too long"); - if (0) /* debugging */ - verbosef("iface '%s' got %d pkts", iface->name, ret); +#if 0 /* debugging */ + verbosef("iface '%s' got %d pkts", iface->name, ret); +#endif #ifdef linux /* keep looping until we've dispatched all the outstanding packets */ diff --git a/cap.h b/cap.h index e1a77cf..f9f455a 100644 --- a/cap.h +++ b/cap.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * cap.h: interface to libpcap. */ diff --git a/cdefs.h b/cdefs.h index a0405eb..2bcdf31 100644 --- a/cdefs.h +++ b/cdefs.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * cdefs.h: compiler-specific defines * @@ -26,7 +26,7 @@ #endif #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901 -#define restrict __restrict +# define restrict __restrict #endif #ifndef MAX @@ -37,4 +37,14 @@ # define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L +# ifdef __COUNTER__ +# define _Static_assert(x, y) __Static_assert(x, __COUNTER__) +# else +# define _Static_assert(x, y) __Static_assert(x, __LINE__) +# endif +# define __Static_assert(x, y) ___Static_assert(x, y) +# define ___Static_assert(x, y) typedef char __assert_ ## y[(x) ? 1 : -1] +#endif + /* vim:set ts=3 sw=3 tw=78 expandtab: */ diff --git a/config.h.in b/config.h.in index 6a34856..f0e3e7f 100644 --- a/config.h.in +++ b/config.h.in @@ -1,8 +1,5 @@ /* config.h.in. Generated from configure.ac by autoheader. */ -/* Default chroot directory. */ -#undef CHROOT_DIR - /* Define to 1 if you have the header file. */ #undef HAVE_BSD_STRING_H diff --git a/configure b/configure index 520dc65..dd5e415 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for darkstat 3.0.717. +# Generated by GNU Autoconf 2.69 for darkstat 3.0.718. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='darkstat' PACKAGE_TARNAME='darkstat' -PACKAGE_VERSION='3.0.717' -PACKAGE_STRING='darkstat 3.0.717' +PACKAGE_VERSION='3.0.718' +PACKAGE_STRING='darkstat 3.0.718' PACKAGE_BUGREPORT='' PACKAGE_URL='http://unix4lyfe.org/darkstat/' @@ -676,7 +676,6 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking -with_chroot_dir with_privdrop_user enable_silent_rules enable_debug @@ -1232,7 +1231,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures darkstat 3.0.717 to adapt to many kinds of systems. +\`configure' configures darkstat 3.0.718 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1293,7 +1292,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of darkstat 3.0.717:";; + short | recursive ) echo "Configuration of darkstat 3.0.718:";; esac cat <<\_ACEOF @@ -1310,7 +1309,6 @@ Optional Features: Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-chroot-dir specify the chroot directory (default: /var/empty) --with-privdrop-user specify which user to drop privileges to (default: nobody) --with-pcap=DIR prefix to libpcap installation @@ -1392,7 +1390,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -darkstat configure 3.0.717 +darkstat configure 3.0.718 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1690,7 +1688,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by darkstat $as_me 3.0.717, which was +It was created by darkstat $as_me 3.0.718, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2044,45 +2042,6 @@ ac_config_headers="$ac_config_headers config.h" RULE="------------------------------------------------------------" -# Let user specify CHROOT_DIR, or else autodetect it, or else die. - -# Check whether --with-chroot-dir was given. -if test "${with_chroot_dir+set}" = set; then : - withval=$with_chroot_dir; if test "x$withval" = "xyes"; then - as_fn_error $? "please specify --with-chroot-dir=/path/to/darkstat/chroot" "$LINENO" 5 - fi - _chd="$withval" -else - # Find an "empty" directory to serve as the chroot. - _chd="/var/empty" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $_chd" >&5 -$as_echo_n "checking for $_chd... " >&6; } - if test -d $_chd ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found it" >&5 -$as_echo "found it" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not there" >&5 -$as_echo "not there" >&6; } - _chd="/var/lib/empty" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $_chd" >&5 -$as_echo_n "checking for $_chd... " >&6; } - if test -d $_chd ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: found it" >&5 -$as_echo "found it" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: not there either" >&5 -$as_echo "not there either" >&6; } - as_fn_error $? "please specify --with-chroot-dir=/path/to/darkstat/chroot" "$LINENO" 5 - fi - fi -fi - - -cat >>confdefs.h <<_ACEOF -#define CHROOT_DIR "$_chd" -_ACEOF - - # Allow configure-time override of PRIVDROP_USER. # Check whether --with-privdrop-user was given. @@ -4746,7 +4705,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by darkstat $as_me 3.0.717, which was +This file was extended by darkstat $as_me 3.0.718, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4809,7 +4768,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -darkstat config.status 3.0.717 +darkstat config.status 3.0.718 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 7af8316..2c22002 100644 --- a/configure.ac +++ b/configure.ac @@ -1,36 +1,11 @@ # Need at least 2.64 for PACKAGE_URL AC_PREREQ([2.64]) -AC_INIT(darkstat, 3.0.717, , , http://unix4lyfe.org/darkstat/) +AC_INIT(darkstat, 3.0.718, , , http://unix4lyfe.org/darkstat/) AC_CONFIG_SRCDIR([darkstat.c]) AC_CONFIG_HEADER([config.h]) RULE="------------------------------------------------------------" -# Let user specify CHROOT_DIR, or else autodetect it, or else die. -AC_ARG_WITH(chroot-dir, AS_HELP_STRING([--with-chroot-dir], - [specify the chroot directory (default: /var/empty)]), - [if test "x$withval" = "xyes"; then - AC_MSG_ERROR([please specify --with-chroot-dir=/path/to/darkstat/chroot]) - fi - _chd="$withval"], - [# Find an "empty" directory to serve as the chroot. - _chd="/var/empty" - AC_MSG_CHECKING([for $_chd]) - if test -d $_chd ; then - AC_MSG_RESULT(found it) - else - AC_MSG_RESULT(not there) - _chd="/var/lib/empty" - AC_MSG_CHECKING([for $_chd]) - if test -d $_chd ; then - AC_MSG_RESULT(found it) - else - AC_MSG_RESULT(not there either) - AC_MSG_ERROR([please specify --with-chroot-dir=/path/to/darkstat/chroot]) - fi - fi]) -AC_DEFINE_UNQUOTED(CHROOT_DIR, "$_chd", [Default chroot directory.]) - # Allow configure-time override of PRIVDROP_USER. AC_ARG_WITH(privdrop-user, AS_HELP_STRING([--with-privdrop-user], [specify which user to drop privileges to (default: nobody)]), diff --git a/contrib/darkstat_export b/contrib/darkstat_export new file mode 100644 index 0000000..f0dacec --- /dev/null +++ b/contrib/darkstat_export @@ -0,0 +1,257 @@ +#!/bin/sh + +# Copyright 2013 MediaMobil Communication GmbH +# +# 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 +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# This script converts a binary .db file into a .csv file. +# The .db file was generated by darkstat with the --export option. +# The .csv file shall be read by any spreadsheet application. +SCRIPTNAME=$( basename $0) +if test -z "$( type -P awk )" ; then + echo "${SCRIPTNAME}: missing AWK interpreter, at least not found in PATH" + echo "${SCRIPTNAME}: every POSIX compliant OS has one; add the location to PATH" + exit 1 +fi +if test -z "$( type -P od )" ; then + echo "${SCRIPTNAME}: missing od file dump tool, at least not found in PATH" + echo "${SCRIPTNAME}: every POSIX compliant OS has one; add the location to PATH" + exit 1 +fi +if test $# -ne 1; then + echo "${SCRIPTNAME}: missing parameter; need file name of .db file" + exit 1 +fi +DBFILENAME=$1 +if test -r ${DBFILENAME}; then + echo ${SCRIPTNAME}: Found file ${DBFILENAME} +else + echo ${SCRIPTNAME}: file ${DBFILENAME} does not exist + exit 1 +fi +CSVFILENAME=${DBFILENAME%%.*}.csv +echo ${SCRIPTNAME}: Writing output into ${CSVFILENAME} + +# The spec of the .db export format exists for different versions: +# http://unix4lyfe.org/gitweb/darkstat/blob/0a152e51f5d9c1771308caa7135d363a722aee18:/export-format.txt +# http://git.msquadrat.de/darkstat.git/blob_plain/master:/export-format.txt +# http://phil.lavin.me.uk/downloads/parse.phps +# Only file format version 1 is supported by us. +# Obviously, darkstat itself distinguishes 3 different host format versions. +# Only host format version 2 is supported by us. +# The darkstat database file is converted from binary format +# to ASCII by the standard Unix command od. + +# Some things don't work correctly yet. +# Probably because there is no DNS server configured in our embedded device +# that produces .db files within OpenWRT. +# - host name contains nonsense at constant length 5 +# - "last seen" timing information contains always 0 +# - we read the graphics section of the file but ignore it + +# Let the od tool convert each binary byte into several textual formats. +# The AWK script reads all variants and later picks the format it needs. +od -Ad -v -tx1 -tu1 -ta -w1 < ${DBFILENAME} | +awk ' + NF==2 { addr = 0 + $1; hex[addr] = $2; next } + NF==1 && addr in dec { ascii[addr]=$1; next } + NF==1 && ! (addr in dec) { dec[addr]=$1; next } + # Now all variants of the bytes are available in certain arrays. + # The array indices cover the range 0 .. addr. + + function read_bytes(array, address, count, retval, c) { + retval="" + for (c=0; c 0) + print reason + if (terminate != 0) { + # Any remaining bytes in the file shall be dumped. + for (i=ai; i<=addr; i++) + print i, hex[i], ascii[i] + exit(retval) + } + } + function readIPsection() { + ip_protos_data=read_bytes(ascii, ai, 1) + if (ip_protos_data != "P") + quit("expected ip_protos_data P, found " ip_protos_data, 1, 1) + ai += 1 + ip_proto_count=read_number(ai, 1) + ai += 1 + for (pi=0; pi 1) { + last_seen=read_number(ai, 4) + # This value is always 0 in our files. + ai += 4 + } + mac_address=hex[ai+0] ":" hex[ai+1] ":" hex[ai+2] ":" hex[ai+3] ":" hex[ai+4] ":" hex[ai+5] + ai += 6 + # Weird stuff: the host name should be read. + # But there are only 5 bytes of nonsense. + # The first byte should be the length counter, but it isnt. + # The last byte is in fact a 0 byte. + # Probably caused by the missing DNS server. + # ignore 5 bytes with nonsense + nonsense=read_text(ai, 5) + ai += 5 + host_bytes_in=read_number(ai, 8) + ai += 8 + host_bytes_out=read_number(ai, 8) + ai += 8 + readIPsection() + readTCPsection() + readUDPsection() + } else { + quit("host format supported only in version 02: " host_version, 1, 1) + #address_familiy=read_bytes(hex, ai, 1) + #print "address familiy = " address_familiy + } + printf("\"%s\";\"%s\";%d;%d;%s;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%d;%s;%s\n", + ip_address, mac_address, host_bytes_in, host_bytes_out, + IPprotos, ip_proto_in, ip_proto_out, + tcp_proto_count, tcp_proto_in, tcp_proto_out, + udp_proto_count, udp_proto_in, udp_proto_out, + ssh_in, ssh_out, rdp_in, rdp_out, + TCPports, UDPports) + } + section_header=read_bytes(hex, ai, 3) + if (section_header != "da4752") + quit("section header da4752 expected: " section_header, 1, 1) + ai += 3 + db_version=read_bytes(hex, ai, 1) + if (db_version != "01") + quit("file format supported only in version 01", 1, 1) + ai += 1 + last_time=read_number(ai, 8) + ai += 8 + readGraphsection("60 seconds") + readGraphsection("60 minutes") + readGraphsection("24 hours") + readGraphsection("31 days") + # The complete file has been parsed, no bytes should be left over. + # Terminate with return value 0 if the byte numbers match. + quit("", (addr != ai+1) ?0:1, addr != ai+1) + } + ' > ${CSVFILENAME} diff --git a/conv.c b/conv.c index 4ff95ae..265f864 100644 --- a/conv.c +++ b/conv.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * conv.c: convenience functions. * @@ -288,9 +288,7 @@ daemonize_finish(void) * For security, chroot (optionally) and drop privileges. * Pass a NULL chroot_dir to disable chroot() behaviour. */ -void -privdrop(const char *chroot_dir, const char *privdrop_user) -{ +void privdrop(const char *chroot_dir, const char *privdrop_user) { struct passwd *pw; errno = 0; @@ -302,7 +300,9 @@ privdrop(const char *chroot_dir, const char *privdrop_user) else err(1, "getpwnam(\"%s\") failed", privdrop_user); } - if (chroot_dir != NULL) { + if (chroot_dir == NULL) { + verbosef("no --chroot dir specified, darkstat will not chroot()"); + } else { tzset(); /* read /etc/localtime before we chroot */ if (chdir(chroot_dir) == -1) err(1, "chdir(\"%s\") failed", chroot_dir); @@ -344,3 +344,5 @@ fd_set_block(const int fd) err(1, "fcntl(fd %d) to unset O_NONBLOCK", fd); assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == 0 ); } + +/* vim:set ts=3 sw=3 tw=78 expandtab: */ diff --git a/darkstat.8.in b/darkstat.8.in index e786af3..9b5a0b4 100644 --- a/darkstat.8.in +++ b/darkstat.8.in @@ -1,6 +1,6 @@ .\" .\" darkstat 3 -.\" Copyright 2001-2011, Emil Mikulic. +.\" Copyright 2001-2014, Emil Mikulic. .\" .\" You may use, modify and redistribute this file under the terms of the .\" GNU General Public License version 2. (see COPYING.GPL) @@ -38,6 +38,8 @@ darkstat \- network statistics gatherer ] [ .BI \-b " bindaddr" ] [ +.BI \-\-base " path" +] [ .BI \-f " filter" ] [ .BI \-l " network/netmask" @@ -169,11 +171,30 @@ Bind the web interface to the specified address. The default is to listen on all interfaces. .\" .TP +.BI \-\-base " path" +.RS +Specify the path of the base URL. +This can be useful if \fIdarkstat\fR is accessed via a reverse proxy. + +For example, if you use Apache's \fImod_proxy\fR and want to avoid a +complicated setup with \fImod_proxy_html\fR (and \fImod_header\fR to unset +the \fIAccept-Encoding\fR header), just set the base path to something like +\fIstats\fR and use a config similar to the following snippet: + +.IP + ProxyPass /stats/ http://localhost:667/stats/ + ProxyPassReverse /stats/ http://localhost:667/stats/ +.PP + +The default is \fI/\fR (i.e. the root). +.RE +.\" +.TP .BI \-f " filter" Use the specified filter expression when capturing traffic. The filter syntax is beyond the scope of this manual page; please refer to the -.BR tcpdump (1) +.BR tcpdump (8) documentation. .\" .TP @@ -381,7 +402,7 @@ darkstat \-i fxp0 \-f "not (src net 192.168.0 and dst net 192.168.0)" .PP .\" (For a full reference on filter syntax, refer to the -.BR tcpdump (1) +.BR tcpdump (8) manpage) .PP .\" @@ -439,7 +460,7 @@ You can also use it to do accounting for a whole subnet by specifying an appropriate netmask. .\" .SH SEE ALSO -.BR tcpdump (1) +.BR tcpdump (8) .\" .SH HISTORY .I darkstat diff --git a/darkstat.c b/darkstat.c index 2213986..c65631e 100644 --- a/darkstat.c +++ b/darkstat.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * darkstat.c: signals, cmdline parsing, program body. * @@ -16,12 +16,13 @@ #include "db.h" #include "dns.h" #include "err.h" -#include "http.h" #include "hosts_db.h" +#include "http.h" #include "localip.h" #include "ncache.h" #include "now.h" #include "pidfile.h" +#include "str.h" #include #include @@ -126,48 +127,23 @@ static void cb_local_only(const char *arg _unused_) const char *opt_chroot_dir = NULL; static void cb_chroot(const char *arg) { opt_chroot_dir = arg; } +const char *opt_base = NULL; +static void cb_base(const char *arg) { opt_base = arg; } + const char *opt_privdrop_user = NULL; static void cb_user(const char *arg) { opt_privdrop_user = arg; } -const char *daylog_fn = NULL; -static void cb_daylog(const char *arg) -{ - if (opt_chroot_dir == NULL) - errx(1, "the daylog file is relative to the chroot.\n" - "You must specify a --chroot dir before you can use --daylog."); - else - daylog_fn = arg; -} +const char *opt_daylog_fn = NULL; +static void cb_daylog(const char *arg) { opt_daylog_fn = arg; } const char *import_fn = NULL; -static void cb_import(const char *arg) -{ - if (opt_chroot_dir == NULL) - errx(1, "the import file is relative to the chroot.\n" - "You must specify a --chroot dir before you can use --import."); - else - import_fn = arg; -} +static void cb_import(const char *arg) { import_fn = arg; } const char *export_fn = NULL; -static void cb_export(const char *arg) -{ - if ((opt_chroot_dir == NULL) && (opt_capfile == NULL)) - errx(1, "the export file is relative to the chroot.\n" - "You must specify a --chroot dir before you can use --export."); - else - export_fn = arg; -} +static void cb_export(const char *arg) { export_fn = arg; } static const char *pid_fn = NULL; -static void cb_pidfile(const char *arg) -{ - if (opt_chroot_dir == NULL) - errx(1, "the pidfile is relative to the chroot.\n" - "You must specify a --chroot dir before you can use --pidfile."); - else - pid_fn = arg; -} +static void cb_pidfile(const char *arg) { pid_fn = arg; } unsigned int opt_hosts_max = 1000; static void cb_hosts_max(const char *arg) @@ -218,6 +194,7 @@ static struct cmdline_arg cmdline_args[] = { {"-p", "port", cb_port, 0}, {"-b", "bindaddr", cb_bindaddr, -1}, {"-l", "network/netmask", cb_local, 0}, + {"--base", "path", cb_base, 0}, {"--local-only", NULL, cb_local_only, 0}, {"--snaplen", "bytes", cb_snaplen, 0}, {"--pppoe", NULL, cb_pppoe, 0}, @@ -329,9 +306,7 @@ static void parse_cmdline(const int argc, char * const *argv) { if (opt_want_syslog) openlog("darkstat", LOG_NDELAY | LOG_PID, LOG_DAEMON); - /* some default values */ - if (opt_chroot_dir == NULL) - opt_chroot_dir = CHROOT_DIR; + /* default value */ if (opt_privdrop_user == NULL) opt_privdrop_user = PRIVDROP_USER; @@ -381,8 +356,8 @@ static void run_from_capfile(void) { hosts_db_free(); graph_free(); verbosef("Total packets: %llu, bytes: %llu", - (unsigned long long)acct_total_packets, - (unsigned long long)acct_total_bytes); + (llu)acct_total_packets, + (llu)acct_total_bytes); } /* --- Program body --- */ @@ -411,6 +386,7 @@ main(int argc, char **argv) /* do this first as it forks - minimize memory use */ if (opt_want_dns) dns_init(opt_privdrop_user); cap_start(opt_want_promisc); /* needs root */ + http_init_base(opt_base); http_listen(opt_bindport); ncache_init(); /* must do before chroot() */ @@ -418,7 +394,7 @@ main(int argc, char **argv) /* Don't need root privs for these: */ now_init(); - if (daylog_fn != NULL) daylog_init(daylog_fn); + if (opt_daylog_fn != NULL) daylog_init(opt_daylog_fn); graph_init(); hosts_db_init(); if (import_fn != NULL) db_import(import_fn); @@ -490,7 +466,7 @@ main(int argc, char **argv) if (export_fn != NULL) db_export(export_fn); hosts_db_free(); graph_free(); - if (daylog_fn != NULL) daylog_free(); + if (opt_daylog_fn != NULL) daylog_free(); ncache_free(); if (pid_fn) pidfile_unlink(); verbosef("shut down"); diff --git a/daylog.c b/daylog.c index fe1928f..080f11f 100644 --- a/daylog.c +++ b/daylog.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2007-2011 Emil Mikulic. + * copyright (c) 2007-2014 Emil Mikulic. * * daylog.c: daily usage log * @@ -9,6 +9,7 @@ #define _GNU_SOURCE 1 /* for O_NOFOLLOW on Linux */ +#include "cdefs.h" #include "err.h" #include "daylog.h" #include "str.h" @@ -23,7 +24,7 @@ #include static const char *daylog_fn = NULL; -static long today_real, tomorrow_real; +static time_t today_real, tomorrow_real; static uint64_t bytes_in, bytes_out, pkts_in, pkts_out; #define DAYLOG_DATE_LEN 26 /* strlen("1900-01-01 00:00:00 +1234") + 1 */ @@ -55,6 +56,7 @@ static time_t tomorrow(time_t t_before) { } /* Warns on error. */ +static void daylog_write(const char *format, ...) _printflike_(1, 2); static void daylog_write(const char *format, ...) { int fd; ssize_t wr; @@ -87,27 +89,32 @@ static void daylog_write(const char *format, ...) { static void daylog_emit(void) { daylog_write("%s|%qu|%qu|%qu|%qu|%qu\n", - fmt_date(today_real), (uint64_t)today_real, - bytes_in, bytes_out, pkts_in, pkts_out); + fmt_date(today_real), + (qu)today_real, + (qu)bytes_in, + (qu)bytes_out, + (qu)pkts_in, + (qu)pkts_out); } void daylog_init(const char *filename) { daylog_fn = filename; today_real = now_real(); tomorrow_real = tomorrow(today_real); - verbosef("today is %ld, tomorrow is %ld", - (long)today_real, (long)tomorrow_real); + verbosef("today is %llu, tomorrow is %llu", + (llu)today_real, + (llu)tomorrow_real); bytes_in = bytes_out = pkts_in = pkts_out = 0; daylog_write("# logging started at %s (%qu)\n", - fmt_date(today_real), (uint64_t)today_real); + fmt_date(today_real), (qu)today_real); } void daylog_free(void) { today_real = now_real(); daylog_emit(); /* Emit what's currently accumulated before we exit. */ daylog_write("# logging stopped at %s (%qu)\n", - fmt_date(today_real), (uint64_t)today_real); + fmt_date(today_real), (qu)today_real); } void daylog_acct(uint64_t amount, enum graph_dir dir) { @@ -121,7 +128,7 @@ void daylog_acct(uint64_t amount, enum graph_dir dir) { today_real = now_real(); tomorrow_real = tomorrow(today_real); bytes_in = bytes_out = pkts_in = pkts_out = 0; - verbosef("updated daylog, tomorrow = %ld", (long)tomorrow_real); + verbosef("updated daylog, tomorrow = %llu", (llu)tomorrow_real); } /* Accounting. */ diff --git a/db.c b/db.c index cf50da9..cadd26e 100644 --- a/db.c +++ b/db.c @@ -1,7 +1,7 @@ /* darkstat 3 * * db.c: load and save in-memory database from/to file - * copyright (c) 2007-2011 Ben Stewart, Emil Mikulic. + * copyright (c) 2007-2012 Ben Stewart, Emil Mikulic. * * You may use, modify and redistribute this file under the terms of the * GNU General Public License version 2. (see COPYING.GPL) diff --git a/db.h b/db.h index 6f9d28a..8fde50d 100644 --- a/db.h +++ b/db.h @@ -1,7 +1,7 @@ /* darkstat 3 * * db.h: load and save in-memory database from/to file - * copyright (c) 2007-2011 Ben Stewart, Emil Mikulic. + * copyright (c) 2007-2012 Ben Stewart, Emil Mikulic. */ #include /* for size_t */ diff --git a/debian/README.Source b/debian/README.Source deleted file mode 100644 index 10a1ce4..0000000 --- a/debian/README.Source +++ /dev/null @@ -1,10 +0,0 @@ -Repackaged upstream source: -=========================== - -The original darkstat tarball includes contrib/darkproxy.php, this file -does not have any valid license that allow us o modify and redistribute it -so the file is being removed from the original tarball to fulfill the DFSG. - -If you need to recreate the tarball you can execute -uuscan --verbose --no-symlink this will download the current version and -it will create the +dfsg.orig.tar.gz file. diff --git a/debian/changelog b/debian/changelog index dfd5e0e..ca4bc75 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,28 @@ -darkstat (3.0.717-1) UNRELEASED; urgency=low +darkstat (3.0.718-2) unstable; urgency=low - * Imported Upstream version 3.0.717 + * Fix FTBFS on Hurd - -- Emil Mikulic Sun, 18 Aug 2013 16:37:10 +1000 + -- Rene Mayorga Sun, 13 Apr 2014 18:41:00 +0000 + +darkstat (3.0.718-1) unstable; urgency=low + + * New upstream release (Closes: #737857) + + Fix IPv6 error on start (Closes: 687967) + + Fix exits when monitoring ppp0 (Closes: #663515) + * debian/watch - remove dversionmangle and repack script + * debian/rpack.sh deleted. + * README.Source deleted + * Add Emil as a co-maint + * debian/rules + + remove not needed options on configure-stamp + + use dpkg-buildflags + * use dh compat 9, debhelper B-D updated + * Update debian policy to 3.9.5 + + use mandatory build-arch and build-indep targets + * Convert to dpkg-source 3.0 quilt format + * Correct tcpdump's section number on the manpage (Closes: #671442) + + -- Rene Mayorga Sun, 23 Mar 2014 12:36:51 +0000 darkstat (3.0.715-1) unstable; urgency=low diff --git a/debian/compat b/debian/compat index 7f8f011..ec63514 100644 --- a/debian/compat +++ b/debian/compat @@ -1 +1 @@ -7 +9 diff --git a/debian/control b/debian/control index 17cc6ad..ff0da4c 100644 --- a/debian/control +++ b/debian/control @@ -3,9 +3,9 @@ Section: net Priority: optional Maintainer: Rene Mayorga Uploaders: Emil Mikulic -Build-Depends: debhelper (>= 7), libpcap-dev, autotools-dev, po-debconf, +Build-Depends: debhelper (>= 9), libpcap-dev, autotools-dev, po-debconf, zlib1g-dev -Standards-Version: 3.9.2 +Standards-Version: 3.9.5 Homepage: http://unix4lyfe.org/darkstat/ Package: darkstat diff --git a/debian/patches/CorrectTcmpdump-section b/debian/patches/CorrectTcmpdump-section new file mode 100644 index 0000000..68ab15b --- /dev/null +++ b/debian/patches/CorrectTcmpdump-section @@ -0,0 +1,36 @@ +Description: Correct tcpdump section number + Use tcpdump section number 8 for debian systems. +Author: Rene Mayorga +Forwarded: not-needed +Last-Update: 2014-03-23 +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +--- a/darkstat.8.in ++++ b/darkstat.8.in +@@ -194,7 +194,7 @@ + Use the specified filter expression when capturing traffic. + The filter syntax is beyond the scope of this manual page; + please refer to the +-.BR tcpdump (1) ++.BR tcpdump (8) + documentation. + .\" + .TP +@@ -402,7 +402,7 @@ + .PP + .\" + (For a full reference on filter syntax, refer to the +-.BR tcpdump (1) ++.BR tcpdump (8) + manpage) + .PP + .\" +@@ -460,7 +460,7 @@ + an appropriate netmask. + .\" + .SH SEE ALSO +-.BR tcpdump (1) ++.BR tcpdump (8) + .\" + .SH HISTORY + .I darkstat diff --git a/debian/patches/FixHURDsFTBS.patch b/debian/patches/FixHURDsFTBS.patch new file mode 100644 index 0000000..1a05c77 --- /dev/null +++ b/debian/patches/FixHURDsFTBS.patch @@ -0,0 +1,17 @@ +Description: Use the correct macro for OS X + The OS X fix use the macro __MACH__, this catch up on Hurd, so + better use __APPLE__ +Author: René Mayorga +--- +This patch header follows DEP-3: http://dep.debian.net/deps/dep3/ +--- a/now.c ++++ b/now.c +@@ -23,7 +23,7 @@ + #include + #include + +-#ifdef __MACH__ ++#ifdef __APPLE__ + /* Fake up clock_gettime() on OS X. */ + # include + # include diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..c58bf3c --- /dev/null +++ b/debian/patches/series @@ -0,0 +1,2 @@ +CorrectTcmpdump-section +FixHURDsFTBS.patch diff --git a/debian/rpack.sh b/debian/rpack.sh deleted file mode 100755 index 3f2a823..0000000 --- a/debian/rpack.sh +++ /dev/null @@ -1,36 +0,0 @@ -set -e -set -u - -VER="3.0.714" -FILE="../darkstat-3.0.714.tar.bz2" -PKG="darkstat" - -SUFFIX="+dfsg" - -echo -echo "Repackaging $FILE" -echo - -DIR=`mktemp -d ./tmpRepackXXXXXX` -DIR=$(readlink -f "$DIR") -trap "/bin/rm -rf \"$DIR\"" QUIT INT EXIT - - -UP_BASE="$DIR/unpack" -mkdir "$UP_BASE" -tar -xvjf "$FILE" -C /"$UP_BASE" - -set -f -MYORIGPWD=$(pwd) -cd "$UP_BASE" -rm "$PKG-$VER/contrib/darkproxy.php" -tar -cvzf "$PKG-$VER$SUFFIX.orig.tar.gz" "$PKG-$VER/" -mv "$PKG-$VER$SUFFIX.orig.tar.gz" "$MYORIGPWD/../" -cd "$MYORIGPWD" - -echo -echo "done" -echo - -rm "$FILE" -rm -rf "$DIR" diff --git a/debian/rules b/debian/rules index f01ccfd..514a26e 100755 --- a/debian/rules +++ b/debian/rules @@ -3,16 +3,22 @@ DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) -CFLAGS += -Wall -g +# CFLAGS += -Wall -g +# + +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/buildflags.mk configure: configure-stamp configure-stamp: dh_testdir cp /usr/share/misc/config.sub /usr/share/misc/config.guess . - CFLAGS="$(CFLAGS)" LDFLAGS="$(INSTALL_PROGRAM)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --with-chroot-dir=/var/lib/darkstat + CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man touch $@ build: configure-stamp build-stamp +build-arch: build +build-indep: build build-stamp: configure-stamp dh_testdir diff --git a/debian/watch b/debian/watch index d99b761..a7c078b 100644 --- a/debian/watch +++ b/debian/watch @@ -1,4 +1,2 @@ version=3 -options=dversionmangle=s/\+dfsg// \ - http://unix4lyfe.org/darkstat/darkstat-(.*)\.tar\.bz2 \ - debian debian/rpack.sh +http://unix4lyfe.org/darkstat/darkstat-(.*)\.tar\.bz2 diff --git a/decode.c b/decode.c index e8e5f35..efa6b00 100644 --- a/decode.c +++ b/decode.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * decode.c: packet decoding. * diff --git a/decode.h b/decode.h index cc4bd55..827c0ad 100644 --- a/decode.h +++ b/decode.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * decode.h: packet decoding. * diff --git a/dns.c b/dns.c index c89dc1b..5b6d95b 100644 --- a/dns.c +++ b/dns.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * dns.c: synchronous DNS in a child process. * @@ -38,7 +38,7 @@ static void dns_main(void) _noreturn_; /* the child process runs this */ #define CHILD 0 /* child process uses this socket */ #define PARENT 1 -static int sock[2]; +static int dns_sock[2]; static pid_t pid = -1; struct dns_reply { @@ -50,7 +50,7 @@ struct dns_reply { void dns_init(const char *privdrop_user) { - if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1) + if (socketpair(AF_UNIX, SOCK_STREAM, 0, dns_sock) == -1) err(1, "socketpair"); pid = fork(); @@ -60,19 +60,18 @@ dns_init(const char *privdrop_user) if (pid == 0) { /* We are the child. */ privdrop(NULL /* don't chroot */, privdrop_user); - close(sock[PARENT]); - sock[PARENT] = -1; + close(dns_sock[PARENT]); + dns_sock[PARENT] = -1; daemonize_finish(); /* drop our copy of the lifeline! */ if (signal(SIGUSR1, SIG_IGN) == SIG_ERR) errx(1, "signal(SIGUSR1, ignore) failed"); dns_main(); - verbosef("fell out of dns_main()"); exit(0); } else { /* We are the parent. */ - close(sock[CHILD]); - sock[CHILD] = -1; - fd_set_nonblock(sock[PARENT]); + close(dns_sock[CHILD]); + dns_sock[CHILD] = -1; + fd_set_nonblock(dns_sock[PARENT]); verbosef("DNS child has PID %d", pid); } } @@ -82,7 +81,7 @@ dns_stop(void) { if (pid == -1) return; /* no child was started */ - close(sock[PARENT]); + close(dns_sock[PARENT]); if (kill(pid, SIGINT) == -1) err(1, "kill"); verbosef("dns_stop() waiting for child"); @@ -112,12 +111,7 @@ tree_cmp(struct tree_rec *a, struct tree_rec *b) } static RB_HEAD(tree_t, tree_rec) ip_tree = RB_INITIALIZER(&tree_rec); -/* Quiet warnings. */ -static struct tree_rec * tree_t_RB_NEXT(struct tree_rec *elm) - _unused_; -static struct tree_rec * tree_t_RB_MINMAX(struct tree_t *head, int val) - _unused_; -RB_GENERATE(tree_t, tree_rec, ptree, tree_cmp) +RB_GENERATE_STATIC(tree_t, tree_rec, ptree, tree_cmp) void dns_queue(const struct addr *const ipaddr) @@ -144,7 +138,7 @@ dns_queue(const struct addr *const ipaddr) return; } - num_w = write(sock[PARENT], ipaddr, sizeof(*ipaddr)); /* won't block */ + num_w = write(dns_sock[PARENT], ipaddr, sizeof(*ipaddr)); /* won't block */ if (num_w == 0) warnx("dns_queue: write: ignoring end of file"); else if (num_w == -1) @@ -177,7 +171,7 @@ dns_get_result(struct addr *ipaddr, char **name) struct dns_reply reply; ssize_t numread; - numread = read(sock[PARENT], &reply, sizeof(reply)); + numread = read(dns_sock[PARENT], &reply, sizeof(reply)); if (numread == -1) { if (errno == EAGAIN) return (0); /* no input waiting */ @@ -256,7 +250,7 @@ struct qitem { struct addr ip; }; -STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue); +static STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue); static void enqueue(const struct addr *const ip) @@ -302,23 +296,23 @@ dns_main(void) struct addr ip; setproctitle("DNS child"); - fd_set_nonblock(sock[CHILD]); + fd_set_nonblock(dns_sock[CHILD]); verbosef("DNS child entering main DNS loop"); for (;;) { int blocking; if (STAILQ_EMPTY(&queue)) { blocking = 1; - fd_set_block(sock[CHILD]); + fd_set_block(dns_sock[CHILD]); verbosef("entering blocking read loop"); } else { blocking = 0; - fd_set_nonblock(sock[CHILD]); + fd_set_nonblock(dns_sock[CHILD]); verbosef("non-blocking poll"); } for (;;) { /* While we have input to process... */ - ssize_t numread = read(sock[CHILD], &ip, sizeof(ip)); + ssize_t numread = read(dns_sock[CHILD], &ip, sizeof(ip)); if (numread == 0) exit(0); /* end of file, nothing more to do here. */ if (numread == -1) { @@ -336,7 +330,7 @@ dns_main(void) * run out of input we fall through to queue processing. */ blocking = 0; - fd_set_nonblock(sock[CHILD]); + fd_set_nonblock(dns_sock[CHILD]); } } @@ -392,8 +386,8 @@ dns_main(void) strlcpy(reply.name, host, sizeof(reply.name)); reply.error = 0; } - fd_set_block(sock[CHILD]); - xwrite(sock[CHILD], &reply, sizeof(reply)); + fd_set_block(dns_sock[CHILD]); + xwrite(dns_sock[CHILD], &reply, sizeof(reply)); verbosef("DNS: %s is \"%s\".", addr_to_str(&reply.addr), (ret == 0) ? reply.name : gai_strerror(ret)); } diff --git a/err.c b/err.c index 3b42d18..bee8234 100644 --- a/err.c +++ b/err.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * err.c: BSD-like err() and warn() functions * diff --git a/err.h b/err.h index 842595a..b93f2ec 100644 --- a/err.h +++ b/err.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * err.h: BSD-like err() and warn() functions * @@ -27,6 +27,6 @@ void warn(const char *format, ...) _printflike_(1, 2); void warnx(const char *format, ...) _printflike_(1, 2); void verbosef(const char *format, ...) _printflike_(1, 2); -void dverbosef(const char *format _unused_, ...); +void dverbosef(const char *format _unused_, ...) _printflike_(1, 2); /* vim:set ts=3 sw=3 tw=78 expandtab: */ diff --git a/graph_db.c b/graph_db.c index c0875d4..4485d45 100644 --- a/graph_db.c +++ b/graph_db.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2006-2011 Emil Mikulic. + * copyright (c) 2006-2014 Emil Mikulic. * * graph_db.c: round robin database for graph data * @@ -47,7 +47,7 @@ static struct graph *graph_db[] = { }; static unsigned int graph_db_size = sizeof(graph_db)/sizeof(*graph_db); -static long start_mono, start_real, last_real; +static time_t start_mono, start_real, last_real; void graph_init(void) { unsigned int i; @@ -57,6 +57,7 @@ void graph_init(void) { } start_mono = now_mono(); start_real = now_real(); + last_real = 0; graph_reset(); } @@ -127,6 +128,7 @@ static void rotate(struct graph *g, const unsigned int pos) { memcpy(g->out, tmp, size); free(tmp); + assert(g->num_bars > 0); assert(pos == ( (g->pos + ofs) % g->num_bars )); g->pos = pos; } @@ -169,7 +171,7 @@ static void graph_resync(const time_t new_real) { } void graph_rotate(void) { - long t, td; + time_t t, td; struct tm *tm; unsigned int i; @@ -287,7 +289,7 @@ struct str *html_front_page(void) { struct str *buf, *rf; unsigned int i; char start_when[100]; - long d_real, d_mono; + time_t d_real, d_mono; buf = str_make(); html_open(buf, "Graphs", /*path_depth=*/0, /*want_graph_js=*/1); @@ -302,7 +304,7 @@ struct str *html_front_page(void) { str_append(buf, ""); if (abs(d_real - d_mono) > 1) str_appendf(buf, " (real time is off by %qd sec)", - (int64_t)d_real - (int64_t)d_mono); + (qd)d_real - (qd)d_mono); if (strftime(start_when, sizeof(start_when), "%Y-%m-%d %H:%M:%S %Z%z", localtime(&start_real)) != 0) @@ -314,9 +316,10 @@ struct str *html_front_page(void) { "(%'u captured, " "%'u dropped)
\n" "

\n", - acct_total_bytes, - acct_total_packets, - cap_pkts_recv, cap_pkts_drop); + (qu)acct_total_bytes, + (qu)acct_total_packets, + cap_pkts_recv, + cap_pkts_drop); str_append(buf, "
\n" @@ -361,7 +364,10 @@ struct str *xml_graphs(void) { struct str *buf = str_make(), *rf; str_appendf(buf, "num_bars; /* */ str_appendf(buf, "\n", - g->offset + j, g->in[j], g->out[j]); + g->offset + j, + (qu)g->in[j], + (qu)g->out[j]); } while (j != g->pos); str_appendf(buf, "\n", g->unit); } diff --git a/hosts_db.c b/hosts_db.c index c2d7ae4..3058d65 100644 --- a/hosts_db.c +++ b/hosts_db.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * hosts_db.c: database of hosts, ports, protocols. * @@ -20,7 +20,7 @@ #include "opt.h" #include "str.h" -#include /* struct addrinfo */ +#include /* struct addrinfo */ #include #include #include @@ -342,10 +342,12 @@ format_row_host(struct str *buf, const struct bucket *b, " %'qu\n" " %'qu\n" " %'qu\n", - b->in, b->out, b->total); + (qu)b->in, + (qu)b->out, + (qu)b->total); if (opt_want_lastseen) { - long last = b->u.host.last_seen_mono; + time_t last = b->u.host.last_seen_mono; struct str *last_str = NULL; if ((now_mono() >= last) && (last > 0)) @@ -356,7 +358,9 @@ format_row_host(struct str *buf, const struct bucket *b, if (last == 0) str_append(buf, "(never)"); else - str_append(buf, "(clock error)"); + str_appendf(buf, "(clock error: now = %qu, last = %qu)", + (qu)now_mono(), + (qu)last); } else { str_appendstr(buf, last_str); str_free(last_str); @@ -403,7 +407,12 @@ format_row_port_tcp(struct str *buf, const struct bucket *b, " %'qu\n" "\n", css_class, - p->port, getservtcp(p->port), b->in, b->out, b->total, p->syn + p->port, + getservtcp(p->port), + (qu)b->in, + (qu)b->out, + (qu)b->total, + (qu)p->syn ); } @@ -437,7 +446,11 @@ format_row_port_udp(struct str *buf, const struct bucket *b, " %'qu\n" "\n", css_class, - p->port, getservudp(p->port), b->in, b->out, b->total + p->port, + getservudp(p->port), + (qu)b->in, + (qu)b->out, + (qu)b->total ); } @@ -471,8 +484,11 @@ format_row_ip_proto(struct str *buf, const struct bucket *b, " %'qu\n" "\n", css_class, - p->proto, getproto(p->proto), - b->in, b->out, b->total + p->proto, + getproto(p->proto), + (qu)b->in, + (qu)b->out, + (qu)b->total ); } @@ -1027,7 +1043,7 @@ static struct str *html_hosts_detail(const char *ip) { struct str *buf, *ls_len; char ls_when[100]; const char *canonical; - time_t last_real; + time_t last_seen_real; h = host_search(ip); if (h == NULL) @@ -1065,9 +1081,9 @@ static struct str *html_hosts_detail(const char *ip) { "

\n" "Last seen: "); - last_real = mono_to_real(h->u.host.last_seen_mono); + last_seen_real = mono_to_real(h->u.host.last_seen_mono); if (strftime(ls_when, sizeof(ls_when), - "%Y-%m-%d %H:%M:%S %Z%z", localtime(&last_real)) != 0) + "%Y-%m-%d %H:%M:%S %Z%z", localtime(&last_seen_real)) != 0) str_append(buf, ls_when); if (h->u.host.last_seen_mono <= now_mono()) { @@ -1087,7 +1103,9 @@ static struct str *html_hosts_detail(const char *ip) { " Out: %'qu
\n" " Total: %'qu
\n" "

\n", - h->in, h->out, h->total); + (qu)h->in, + (qu)h->out, + (qu)h->total); str_append(buf, "

TCP ports

\n"); format_table(buf, h->u.host.ports_tcp, 0,TOTAL,0); diff --git a/hosts_db.h b/hosts_db.h index 3f869f1..109f373 100644 --- a/hosts_db.h +++ b/hosts_db.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * hosts_db.h: database of hosts, ports, protocols. * @@ -19,7 +19,7 @@ struct host { struct addr addr; char *dns; uint8_t mac_addr[6]; - long last_seen_mono; + time_t last_seen_mono; struct hashtable *ports_tcp, *ports_udp, *ip_protos; }; diff --git a/hosts_sort.c b/hosts_sort.c index b6f32dd..bb88581 100644 --- a/hosts_sort.c +++ b/hosts_sort.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * hosts_sort.c: quicksort a table of buckets. * diff --git a/http.c b/http.c index e39f16b..0cd6133 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2012 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * http.c: embedded webserver. * This borrows a lot of code from darkhttpd. @@ -37,6 +37,9 @@ #include #include +static char *http_base_url = NULL; +static int http_base_len = 0; + static const char mime_type_xml[] = "text/xml"; static const char mime_type_html[] = "text/html; charset=us-ascii"; static const char mime_type_css[] = "text/css"; @@ -56,7 +59,7 @@ struct connection { int socket; struct sockaddr_storage client; - long last_active_mono; + time_t last_active_mono; enum { RECV_REQUEST, /* receiving request */ SEND_HEADER_AND_REPLY, /* try to send header+reply together */ @@ -381,23 +384,28 @@ static void generate_header(struct connection *conn, if (conn->encoding == NULL) conn->encoding = encoding_identity; - verbosef("http: %d %s (%s: %zu bytes)", code, text, - conn->encoding, conn->reply_length); + verbosef("http: %d %s (%s: %zu bytes)", + code, + text, + conn->encoding, + conn->reply_length); conn->header_length = xasprintf(&(conn->header), "HTTP/1.1 %d %s\r\n" "Date: %s\r\n" "Server: %s\r\n" "Vary: Accept-Encoding\r\n" "Content-Type: %s\r\n" - "Content-Length: %d\r\n" + "Content-Length: %qu\r\n" "Content-Encoding: %s\r\n" "X-Robots-Tag: noindex, noarchive\r\n" "%s" - "\r\n" - , + "\r\n", code, text, - rfc1123_date(date, now_real()), server, - conn->mime_type, conn->reply_length, conn->encoding, + rfc1123_date(date, now_real()), + server, + conn->mime_type, + (qu)conn->reply_length, + conn->encoding, conn->header_extra); conn->http_code = code; } @@ -407,6 +415,9 @@ static void generate_header(struct connection *conn, /* --------------------------------------------------------------------------- * A default reply for any (erroneous) occasion. */ +static void default_reply(struct connection *conn, + const int errcode, const char *errname, const char *format, ...) + _printflike_(4, 5); static void default_reply(struct connection *conn, const int errcode, const char *errname, const char *format, ...) { @@ -571,11 +582,16 @@ process_gzip(struct connection *conn) zs.zfree = Z_NULL; zs.opaque = Z_NULL; - if (deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, - 15+16, /* 15 = biggest window, 16 = add gzip header+trailer */ - 8 /* default */, - Z_DEFAULT_STRATEGY) != Z_OK) - return; + if (deflateInit2(&zs, + Z_BEST_COMPRESSION, + Z_DEFLATED, + 15+16, /* 15 = biggest window, + 16 = add gzip header+trailer */ + 8 /* default */, + Z_DEFAULT_STRATEGY) != Z_OK) { + free(buf); + return; + } zs.avail_in = conn->reply_length; zs.next_in = (unsigned char *)conn->reply; @@ -586,7 +602,7 @@ process_gzip(struct connection *conn) if (deflate(&zs, Z_FINISH) != Z_STREAM_END) { deflateEnd(&zs); free(buf); - verbosef("failed to compress %u bytes", (unsigned int)len); + verbosef("failed to compress %zu bytes", len); return; } @@ -605,22 +621,32 @@ process_gzip(struct connection *conn) */ static void process_get(struct connection *conn) { - char *decoded_url, *safe_url; + char *safe_url; verbosef("http: %s \"%s\" %s", conn->method, conn->uri, (conn->query == NULL)?"":conn->query); - /* work out path of file being requested */ - decoded_url = urldecode(conn->uri); - - /* make sure it's safe */ - safe_url = make_safe_uri(decoded_url); - free(decoded_url); - if (safe_url == NULL) { - default_reply(conn, 400, "Bad Request", - "You requested an invalid URI: %s", conn->uri); - return; + /* Decode the URL being requested. */ + char *decoded_url; + char *decoded_url_offset; + + decoded_url = urldecode(conn->uri); + + /* Optionally strip the base. */ + decoded_url_offset = decoded_url; + if (str_starts_with(decoded_url, http_base_url)) { + decoded_url_offset += http_base_len - 1; + } + + /* Make sure it's safe. */ + safe_url = make_safe_uri(decoded_url_offset); + free(decoded_url); + if (safe_url == NULL) { + default_reply(conn, 400, "Bad Request", + "You requested an invalid URI: %s", conn->uri); + return; + } } if (strcmp(safe_url, "/") == 0) { @@ -873,6 +899,40 @@ static void poll_send_reply(struct connection *conn) if (conn->reply_sent == conn->reply_length) conn->state = DONE; } + + +/* -------------------------------------------------------------------------- + * Initialize the base url. + */ +void http_init_base(const char *url) { + char *slashed_url, *safe_url; + size_t urllen; + + if (url == NULL) { + http_base_url = strdup("/"); + } else { + /* Make sure that the url has leading and trailing slashes. */ + urllen = strlen(url); + slashed_url = xmalloc(urllen+3); + slashed_url[0] = '/'; + memcpy(slashed_url+1, url, urllen); /* don't copy NUL */ + slashed_url[urllen+1] = '/'; + slashed_url[urllen+2] = '\0'; + + /* Clean the url. */ + safe_url = make_safe_uri(slashed_url); + free(slashed_url); + if (safe_url == NULL) { + verbosef("invalid base \"%s\", ignored", url); + http_base_url = strdup("/"); /* set to default */ + } else { + http_base_url = safe_url; + } + } + http_base_len = strlen(http_base_url); + verbosef("set base url to \"%s\"", http_base_url); +} + /* Use getaddrinfo to figure out what type of socket to create and * what to bind it to. "bindaddr" can be NULL. Remember to freeaddrinfo() * the result. @@ -962,11 +1022,12 @@ static void http_listen_one(struct addrinfo *ai, if (listen(sockin, 128) == -1) err(1, "listen() failed"); - verbosef("listening on http://%s%s%s:%u/", + verbosef("listening on http://%s%s%s:%u%s", (ai->ai_family == AF_INET6) ? "[" : "", ipaddr, (ai->ai_family == AF_INET6) ? "]" : "", - bindport); + bindport, + http_base_url); /* add to insocks */ insocks = xrealloc(insocks, sizeof(*insocks) * (insock_num + 1)); @@ -1122,6 +1183,8 @@ void http_stop(void) { struct connection *conn; unsigned int i; + free(http_base_url); + /* Close listening sockets. */ for (i=0; i #include +void http_init_base(const char *url); void http_add_bindaddr(const char *bindaddr); void http_listen(const unsigned short bindport); void http_fd_set(fd_set *recv_set, fd_set *send_set, int *max_fd, diff --git a/localip.c b/localip.c index f7b7f93..24951c6 100644 --- a/localip.c +++ b/localip.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * localip.c: determine local IPs of an interface * diff --git a/localip.h b/localip.h index a5b48ea..2625ada 100644 --- a/localip.h +++ b/localip.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * localip.h: determine the local IPs of an interface * @@ -13,7 +13,7 @@ struct local_ips { int is_valid; - long last_update_mono; + time_t last_update_mono; int num_addrs; struct addr *addrs; }; diff --git a/ncache.c b/ncache.c index 96e052f..1d23d1c 100644 --- a/ncache.c +++ b/ncache.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * ncache.c: cache of protocol and service names. * @@ -33,7 +33,7 @@ rec_cmp(struct name_rec *a, struct name_rec *b) } RB_HEAD(nc_tree, name_rec); -RB_GENERATE(nc_tree, name_rec, ptree, rec_cmp) +RB_GENERATE_STATIC(nc_tree, name_rec, ptree, rec_cmp) static struct nc_tree t_proto = RB_INITIALIZER(&name_rec), diff --git a/now.c b/now.c index f0751a8..95ab2a2 100644 --- a/now.c +++ b/now.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2012 Emil Mikulic. + * copyright (c) 2012-2014 Emil Mikulic. * * now.c: a cache of the current time. * @@ -17,12 +17,13 @@ */ #include "err.h" #include "now.h" +#include "str.h" #include #include #include -#ifdef __MACH__ +#ifdef __APPLE__ /* Fake up clock_gettime() on OS X. */ # include # include @@ -62,12 +63,12 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp) { static struct timespec clock_real, clock_mono; static int now_initialized = 0; -long now_real(void) { +time_t now_real(void) { assert(now_initialized); return clock_real.tv_sec; } -long now_mono(void) { +time_t now_mono(void) { assert(now_initialized); return clock_mono.tv_sec; } @@ -80,6 +81,17 @@ static int before(const struct timespec *a, const struct timespec *b) { return 0; } +static void warn_backwards(const char *name, + const struct timespec * const t0, + const struct timespec * const t1) { + verbosef("%s clock went backwards from %lld.%09lld to %lld.%09lld", + name, + (lld)t0->tv_sec, + (lld)t0->tv_nsec, + (lld)t1->tv_sec, + (lld)t1->tv_nsec); +} + static void clock_update(const clockid_t clk_id, struct timespec *dest, const char *name) { @@ -87,12 +99,7 @@ static void clock_update(const clockid_t clk_id, clock_gettime(clk_id, &t); if (now_initialized && before(&t, dest)) { - verbosef("%s clock went backwards from %ld.%09ld to %ld.%09ld", - name, - (long)dest->tv_sec, - (long)dest->tv_nsec, - (long)t.tv_sec, - (long)t.tv_nsec); + warn_backwards(name, &t, dest); } memcpy(dest, &t, sizeof(t)); } @@ -113,12 +120,12 @@ void now_update(void) { all_clocks_update(); } -long mono_to_real(const long t) { +time_t mono_to_real(const time_t t) { assert(now_initialized); return t - clock_mono.tv_sec + clock_real.tv_sec; } -long real_to_mono(const long t) { +time_t real_to_mono(const time_t t) { assert(now_initialized); return t - clock_real.tv_sec + clock_mono.tv_sec; } @@ -133,20 +140,24 @@ static int64_t ts_diff(const struct timespec * const a, a->tv_nsec - b->tv_nsec; } -void timer_stop(const struct timespec * const t, +void timer_stop(const struct timespec * const t0, const int64_t nsec, const char *warning) { - struct timespec t2; + struct timespec t1; int64_t diff; - clock_gettime(CLOCK_MONOTONIC, &t2); - diff = ts_diff(&t2, t); - assert(diff > 0); - if (diff > nsec) + clock_gettime(CLOCK_MONOTONIC, &t1); + if (before(&t1, t0)) { + warn_backwards("monotonic timer", t0, &t1); + return; + } + diff = ts_diff(&t1, t0); + if (diff > nsec) { warnx("%s (took %lld nsec, over threshold of %lld nsec)", warning, - (long long)diff, - (long long)nsec); + (lld)diff, + (lld)nsec); + } } /* vim:set ts=3 sw=3 tw=80 et: */ diff --git a/now.h b/now.h index 9c61f45..03366e7 100644 --- a/now.h +++ b/now.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2006 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * now.h: a cache of the current time. * @@ -20,11 +20,11 @@ void now_init(void); void now_update(void); /* once per event loop (in darkstat.c) */ -long now_real(void); -long now_mono(void); +time_t now_real(void); +time_t now_mono(void); -long mono_to_real(const long t); -long real_to_mono(const long t); +time_t mono_to_real(const time_t t); +time_t real_to_mono(const time_t t); /* Emits warnings if a call is too slow. */ struct timespec; diff --git a/opt.h b/opt.h index 34afc36..dfbd384 100644 --- a/opt.h +++ b/opt.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * opt.h: global options */ diff --git a/pidfile.c b/pidfile.c index 044c574..92403cd 100644 --- a/pidfile.c +++ b/pidfile.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2007-2011 Emil Mikulic. + * copyright (c) 2007-2014 Emil Mikulic. * * pidfile.h: pidfile manglement * @@ -29,10 +29,9 @@ static int pidfd = -1; static const char *pidname = NULL; -void -pidfile_create(const char *chroot_dir, const char *filename, - const char *privdrop_user) -{ +void pidfile_create(const char *chroot_dir, + const char *filename, + const char *privdrop_user) { struct passwd *pw; if (pidfd != -1) @@ -48,8 +47,11 @@ pidfile_create(const char *chroot_dir, const char *filename, err(1, "getpwnam(\"%s\") failed", privdrop_user); } - if (chdir(chroot_dir) == -1) - err(1, "chdir(\"%s\") failed", chroot_dir); + if (chroot_dir != NULL) { + if (chdir(chroot_dir) == -1) { + err(1, "chdir(\"%s\") failed", chroot_dir); + } + } pidname = filename; pidfd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600); if (pidfd == -1) diff --git a/str.c b/str.c index 852a24d..a73f387 100644 --- a/str.c +++ b/str.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2012 Emil Mikulic. * * str.c: string buffer with pool-based reallocation * diff --git a/str.h b/str.h index 92cb78f..c6cb197 100644 --- a/str.h +++ b/str.h @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2011 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * str.h: string buffer with pool-based reallocation * @@ -15,9 +15,24 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef __DARKSTAT_STR_H +#define __DARKSTAT_STR_H + +#include "cdefs.h" #include #include +#include /* for uint64_t */ + +typedef long long signed int qd; /* as in appendf("%qd") */ +typedef long long unsigned int qu; /* as in appendf("%qu") */ +typedef long long unsigned int lld; /* as in printf("%lld") */ +typedef long long unsigned int llu; /* as in printf("%llu") */ + +_Static_assert(sizeof(qd) == sizeof(int64_t), "qd must be int64_t sized"); +_Static_assert(sizeof(qu) == sizeof(uint64_t), "qu must be uint64_t sized"); +_Static_assert(sizeof(lld) == sizeof(int64_t), "lld must be int64_t sized"); +_Static_assert(sizeof(llu) == sizeof(uint64_t), "llu must be uint64_t sized"); /* Note: the contents are 8-bit clean and not zero terminated! */ @@ -39,13 +54,16 @@ void str_appendstr(struct str *buf, const struct str *s); void str_append(struct str *buf, const char *s); #endif -size_t xvasprintf(char **result, const char *format, va_list va); -size_t xasprintf(char **result, const char *format, ...); -void str_appendf(struct str *buf, const char *format, ...); -void str_vappendf(struct str *s, const char *format, va_list va); +size_t xvasprintf(char **result, const char *format, va_list va) + _printflike_(2, 0); +size_t xasprintf(char **result, const char *format, ...) _printflike_(2, 3); +void str_vappendf(struct str *s, const char *format, va_list va) + _printflike_(2, 0); +void str_appendf(struct str *s, const char *format, ...) _printflike_(2, 3); struct str *length_of_time(const time_t t); ssize_t str_write(const struct str * const buf, const int fd); size_t str_len(const struct str * const buf); +#endif /* __DARKSTAT_STR_H */ /* vim:set ts=3 sw=3 tw=78 expandtab: */ diff --git a/tree.h b/tree.h index f533547..6ee1af6 100644 --- a/tree.h +++ b/tree.h @@ -1,12 +1,8 @@ -/* This is a cut down version of FreeBSD's - * src/sys/sys/tree.h,v 1.5 - * - * Also tagged - * $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ - * $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ - * - * The original file's license: - * +/* This is a cut down version of NetBSD's /usr/include/sys/tree.h */ + +/* $NetBSD: tree.h,v 1.20 2013/09/14 13:20:45 joerg Exp $ */ +/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ +/* * Copyright 2002 Niels Provos * All rights reserved. * @@ -31,12 +27,23 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +#include "cdefs.h" + +/* Macros that define a red-black tree */ #define RB_HEAD(name, type) \ struct name { \ struct type *rbh_root; /* root of the tree */ \ } -#define RB_INITIALIZER(root) { NULL } +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) #define RB_BLACK 0 #define RB_RED 1 @@ -53,6 +60,7 @@ struct { \ #define RB_PARENT(elm, field) (elm)->field.rbe_parent #define RB_COLOR(elm, field) (elm)->field.rbe_color #define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) #define RB_SET(elm, parent, field) do { \ RB_PARENT(elm, field) = parent; \ @@ -65,7 +73,9 @@ struct { \ RB_COLOR(red, field) = RB_RED; \ } while (/*CONSTCOND*/ 0) -#define RB_AUGMENT(x) do {} while (0) +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (/*CONSTCOND*/ 0) +#endif #define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ (tmp) = RB_RIGHT(elm, field); \ @@ -107,8 +117,32 @@ struct { \ RB_AUGMENT(RB_PARENT(tmp, field)); \ } while (/*CONSTCOND*/ 0) +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, _unused_ static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +#include + +/* Main rb operation. + * Moves node close to the key of elm to top + */ #define RB_GENERATE(name, type, field, cmp) \ - RB_GENERATE_INTERNAL(name, type, field, cmp, static) + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, _unused_ static) #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ attr void \ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ @@ -117,6 +151,7 @@ name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ while ((parent = RB_PARENT(elm, field)) != NULL && \ RB_COLOR(parent, field) == RB_RED) { \ gparent = RB_PARENT(parent, field); \ + assert(gparent != NULL); \ if (parent == RB_LEFT(gparent, field)) { \ tmp = RB_RIGHT(gparent, field); \ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ @@ -167,6 +202,7 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) RB_ROTATE_LEFT(head, parent, tmp, field);\ tmp = RB_RIGHT(parent, field); \ } \ + assert(tmp != NULL); \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ @@ -200,6 +236,7 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) RB_ROTATE_RIGHT(head, parent, tmp, field);\ tmp = RB_LEFT(parent, field); \ } \ + assert(tmp != NULL); \ if ((RB_LEFT(tmp, field) == NULL || \ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ (RB_RIGHT(tmp, field) == NULL || \ @@ -270,6 +307,7 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \ RB_AUGMENT(RB_PARENT(old, field)); \ } else \ RB_ROOT(head) = elm; \ + assert(RB_LEFT(old, field) != NULL); \ RB_PARENT(RB_LEFT(old, field), field) = elm; \ if (RB_RIGHT(old, field)) \ RB_PARENT(RB_RIGHT(old, field), field) = elm; \ @@ -348,6 +386,27 @@ name##_RB_FIND(struct name *head, struct type *elm) \ return (NULL); \ } \ \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ /* ARGSUSED */ \ attr struct type * \ name##_RB_NEXT(struct type *elm) \ @@ -370,6 +429,28 @@ name##_RB_NEXT(struct type *elm) \ return (elm); \ } \ \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ attr struct type * \ name##_RB_MINMAX(struct name *head, int val) \ { \ @@ -386,9 +467,45 @@ name##_RB_MINMAX(struct name *head, int val) \ } #define RB_NEGINF -1 +#define RB_INF 1 #define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#endif /* _SYS_TREE_H_ */ -- 2.17.1