Pull in darkstat-3.0.718
authorEmil Mikulic <emikulic@gmail.com>
Sat, 10 Oct 2015 10:20:24 +0000 (21:20 +1100)
committerEmil Mikulic <emikulic@gmail.com>
Sat, 10 Oct 2015 10:20:24 +0000 (21:20 +1100)
$ apt-get source darkstat

51 files changed:
ChangeLog
Makefile.in
NEWS
acct.c
acct.h
bsd.c
bsd.h
cap.c
cap.h
cdefs.h
config.h.in
configure
configure.ac
contrib/darkstat_export [new file with mode: 0644]
conv.c
darkstat.8.in
darkstat.c
daylog.c
db.c
db.h
debian/README.Source [deleted file]
debian/changelog
debian/compat
debian/control
debian/patches/CorrectTcmpdump-section [new file with mode: 0644]
debian/patches/FixHURDsFTBS.patch [new file with mode: 0644]
debian/patches/series [new file with mode: 0644]
debian/rpack.sh [deleted file]
debian/rules
debian/watch
decode.c
decode.h
dns.c
err.c
err.h
graph_db.c
hosts_db.c
hosts_db.h
hosts_sort.c
http.c
http.h
localip.c
localip.h
ncache.c
now.c
now.h
opt.h
pidfile.c
str.c
str.h
tree.h

index 561c567..1a6e982 100644 (file)
--- 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.
 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.
        - 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.
 
 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.
        - 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)
 
 
 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:
 
 vim:set noet ts=8 sw=8 tw=72:
index b0dbf2e..6aa57d1 100644 (file)
@@ -1,5 +1,5 @@
 # darkstat 3
 # 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)
 #
 # 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 \
  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 \
 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
 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
 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
 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 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 Changes to defaults, most recent first:
 
 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
 - 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.
   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 (file)
--- a/acct.c
+++ b/acct.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * acct.c: traffic accounting
  *
  *
  * acct.c: traffic accounting
  *
diff --git a/acct.h b/acct.h
index b4edb7f..0a4b261 100644 (file)
--- a/acct.h
+++ b/acct.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * acct.h: traffic accounting
  */
  *
  * acct.h: traffic accounting
  */
diff --git a/bsd.c b/bsd.c
index 9a9f156..0b9c316 100644 (file)
--- a/bsd.c
+++ b/bsd.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2011 Emil Mikulic.
  *
  * bsd.c: *BSD compatibility.
  *
  *
  * bsd.c: *BSD compatibility.
  *
diff --git a/bsd.h b/bsd.h
index 3426add..6939f59 100644 (file)
--- a/bsd.h
+++ b/bsd.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2011-2014 Emil Mikulic.
  *
  * bsd.h: *BSD compatibility.
  */
  *
  * bsd.h: *BSD compatibility.
  */
@@ -22,7 +22,7 @@ size_t strlcat(char *dst, const char *src, size_t siz);
 #endif
 
 #ifndef HAVE_SETPROCTITLE
 #endif
 
 #ifndef HAVE_SETPROCTITLE
-#define setproctitle(fmt, ...) /* no-op */
+#define setproctitle(fmt) /* no-op */
 #endif
 
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
 #endif
 
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
diff --git a/cap.c b/cap.c
index 7e1c41b..62da77d 100644 (file)
--- a/cap.c
+++ b/cap.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* 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.
  *
  *
  * 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;
 /* 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);
 
    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;
 
       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 */
                -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;
          }
 
          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 */
 
 #ifdef linux
          /* keep looping until we've dispatched all the outstanding packets */
diff --git a/cap.h b/cap.h
index e1a77cf..f9f455a 100644 (file)
--- a/cap.h
+++ b/cap.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * cap.h: interface to libpcap.
  */
  *
  * cap.h: interface to libpcap.
  */
diff --git a/cdefs.h b/cdefs.h
index a0405eb..2bcdf31 100644 (file)
--- a/cdefs.h
+++ b/cdefs.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * cdefs.h: compiler-specific defines
  *
  *
  * cdefs.h: compiler-specific defines
  *
@@ -26,7 +26,7 @@
 #endif
 
 #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901
 #endif
 
 #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901
-#define restrict __restrict
+# define restrict __restrict
 #endif
 
 #ifndef MAX
 #endif
 
 #ifndef MAX
 # define MIN(a,b) ((a) < (b) ? (a) : (b))
 #endif
 
 # 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: */
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
index 6a34856..f0e3e7f 100644 (file)
@@ -1,8 +1,5 @@
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
-/* Default chroot directory. */
-#undef CHROOT_DIR
-
 /* Define to 1 if you have the <bsd/string.h> header file. */
 #undef HAVE_BSD_STRING_H
 
 /* Define to 1 if you have the <bsd/string.h> header file. */
 #undef HAVE_BSD_STRING_H
 
index 520dc65..dd5e415 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
 #! /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.
 #
 #
 # 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'
 # 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/'
 
 PACKAGE_BUGREPORT=''
 PACKAGE_URL='http://unix4lyfe.org/darkstat/'
 
@@ -676,7 +676,6 @@ SHELL'
 ac_subst_files=''
 ac_user_opts='
 enable_option_checking
 ac_subst_files=''
 ac_user_opts='
 enable_option_checking
-with_chroot_dir
 with_privdrop_user
 enable_silent_rules
 enable_debug
 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
   # 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]...
 
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1293,7 +1292,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
 
 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
 
    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)
 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
   --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
 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.
 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.
 
 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 $@
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2044,45 +2042,6 @@ ac_config_headers="$ac_config_headers config.h"
 
 RULE="------------------------------------------------------------"
 
 
 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.
 # 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="
 # 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
 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="\\
 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\\"
 
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 7af8316..2c22002 100644 (file)
@@ -1,36 +1,11 @@
 # Need at least 2.64 for PACKAGE_URL
 AC_PREREQ([2.64])
 # 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="------------------------------------------------------------"
 
 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)]),
 # 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 (file)
index 0000000..f0dacec
--- /dev/null
@@ -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<count; c++)
+      retval = retval array[address+c]
+    return retval
+  }
+  function read_number(address, count,         retval, c) {
+    retval=0
+    for (c=0; c<count; c++)
+      retval = retval*256 + dec[address+c]
+    return retval
+  }
+  function read_text(address, count,           retval, c) {
+    retval=""
+    for (c=0; c<count; c++)
+      retval = retval ascii[address+c]
+    return retval
+  }
+  function quit(reason, terminate, retval) {
+    if (length(reason) > 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<ip_proto_count; pi++) {
+      ip_proto_type=read_number(ai, 1)
+      ai += 1
+      IPprotos = IPprotos " " ip_proto_type
+      ip_proto_in  += read_number(ai, 8)
+      ai += 8
+      ip_proto_out += read_number(ai, 8)
+      ai += 8
+    }
+  }
+  function readTCPsection() {
+    tcp_protos_data=read_bytes(ascii, ai, 1)
+    if (tcp_protos_data != "T") 
+      quit("expected tcp_protos_data T, found " tcp_protos_data, 1, 1)
+    ai += 1
+    tcp_proto_count=read_number(ai, 2)
+    ai += 2
+    for (ti=0; ti<tcp_proto_count; ti++) {
+      tcp_proto_port=read_number(ai, 2)
+      ai += 2
+      TCPports = TCPports " " tcp_proto_port
+      tcp_proto_syn=read_number(ai, 8)
+      ai += 8
+      tcp_proto_in  += read_number(ai, 8)
+      ai += 8
+      tcp_proto_out += read_number(ai, 8)
+      ai += 8
+      if (tcp_proto_port == 22) {
+        ssh_in  += tcp_proto_in
+        ssh_out += tcp_proto_out
+      }
+      if (tcp_proto_port == 3389) {
+        rdp_in  += tcp_proto_in
+        rdp_out += tcp_proto_out
+      }
+    }
+  }
+  function readUDPsection() {
+    udp_protos_data=read_bytes(ascii, ai, 1)
+    if (udp_protos_data != "U") 
+      quit("expected udp_protos_data U, found " udp_protos_data, 1, 1)
+    ai += 1
+    udp_proto_count=read_number(ai, 2)
+    ai += 2
+    for (ui=0; ui<udp_proto_count; ui++) {
+      udp_proto_port=read_number(ai, 2)
+      ai += 2
+      UDPports = UDPports " " udp_proto_port
+      udp_proto_in  += read_number(ai, 8)
+      ai += 8
+      udp_proto_out += read_number(ai, 8)
+      ai += 8
+      if (udp_proto_port == 22) {
+        ssh_in  += udp_proto_in
+        ssh_out += udp_proto_out
+      }
+      if (udp_proto_port == 3389) {
+        rdp_in  += udp_proto_in
+        rdp_out += udp_proto_out
+      }
+    }
+  }
+  function readGraphsection(interval) {
+    n_bars=read_number(ai++, 1)
+    i_bars=read_number(ai++, 1)
+    for (bi=0; bi<n_bars; bi++) {
+      graph_bytes_in=read_number(ai, 8)
+      ai += 8
+      graph_bytes_out=read_number(ai, 8)
+      ai += 8
+    }
+  }
+
+  END {
+    file_header=read_bytes(hex, 0, 4)
+    if (file_header != "da314159")
+      quit("input data is not an exported darkstat .db file, wrong header: " file_header, 1, 1)
+    section_header=read_bytes(hex, 4, 3)
+    if (section_header != "da4853")
+      quit("section header da4853 expected: " section_header, 1, 1)
+    db_version=read_bytes(hex, 7, 1)
+    if (db_version != "01")
+      quit("file format supported only in version 01", 1, 1)
+    host_count=read_number(8, 4)
+    ai=12
+    # Print a header into the .csv file.
+    printf("IP address;MAC address;host in bytes;host out bytes;IP protos;IP in bytes;IP out bytes;TCP port count;TCP in bytes;TCP out bytes;UDP port count;UDP in bytes;UDP out bytes;ssh in bytes;ssh out bytes;rdp in bytes;rdp out bytes;TCP ports;UDP ports\n")
+    for (hi=1; hi<=host_count; hi++) {
+      # Make sure all variables to be printed are initially empty.
+      ip_address=mac_address=""
+      host_bytes_in=host_bytes_out=ip_proto_in=ip_proto_out=tcp_proto_in=tcp_proto_out=udp_proto_in=udp_proto_out=ssh_in=ssh_out=rdp_in=rdp_out=0
+      IPprotos=TCPports=UDPports=""
+      tcp_proto_count=udp_proto_count=0
+      host_header=read_bytes(hex, ai, 3)
+      host_version=read_bytes(hex, ai+3, 1)
+      ai += 4
+      if (host_version == "02") {
+        ip_address=read_number(ai+0,1) "." read_number(ai+1,1) "." read_number(ai+2,1) "." read_number(ai+3,1)
+        ai += 4
+        if ((host_version+0) > 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 (file)
--- a/conv.c
+++ b/conv.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * conv.c: convenience functions.
  *
  *
  * 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.
  */
  * 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;
    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);
    }
       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);
       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 );
 }
       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: */
index e786af3..9b5a0b4 100644 (file)
@@ -1,6 +1,6 @@
 .\"
 .\" darkstat 3
 .\"
 .\" 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)
 .\"
 .\" 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 \-b " bindaddr"
 ] [
+.BI \-\-base " path"
+] [
 .BI \-f " filter"
 ] [
 .BI \-l " network/netmask"
 .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
 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
 .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
 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
 .PP
 .\"
 (For a full reference on filter syntax, refer to the
-.BR tcpdump (1)
+.BR tcpdump (8)
 manpage)
 .PP
 .\"
 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
 an appropriate netmask.
 .\"
 .SH SEE ALSO
-.BR tcpdump (1)
+.BR tcpdump (8)
 .\"
 .SH HISTORY
 .I darkstat
 .\"
 .SH HISTORY
 .I darkstat
index 2213986..c65631e 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * darkstat.c: signals, cmdline parsing, program body.
  *
  *
  * darkstat.c: signals, cmdline parsing, program body.
  *
 #include "db.h"
 #include "dns.h"
 #include "err.h"
 #include "db.h"
 #include "dns.h"
 #include "err.h"
-#include "http.h"
 #include "hosts_db.h"
 #include "hosts_db.h"
+#include "http.h"
 #include "localip.h"
 #include "ncache.h"
 #include "now.h"
 #include "pidfile.h"
 #include "localip.h"
 #include "ncache.h"
 #include "now.h"
 #include "pidfile.h"
+#include "str.h"
 
 #include <assert.h>
 #include <errno.h>
 
 #include <assert.h>
 #include <errno.h>
@@ -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_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 *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;
 
 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;
 
 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 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)
 
 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},
    {"-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},
    {"--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);
 
    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;
 
    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",
    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 --- */
 }
 
 /* --- 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 */
    /* 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() */
 
    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();
 
    /* 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);
    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 (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");
    ncache_free();
    if (pid_fn) pidfile_unlink();
    verbosef("shut down");
index fe1928f..080f11f 100644 (file)
--- a/daylog.c
+++ b/daylog.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2007-2011 Emil Mikulic.
+ * copyright (c) 2007-2014 Emil Mikulic.
  *
  * daylog.c: daily usage log
  *
  *
  * daylog.c: daily usage log
  *
@@ -9,6 +9,7 @@
 
 #define _GNU_SOURCE 1 /* for O_NOFOLLOW on Linux */
 
 
 #define _GNU_SOURCE 1 /* for O_NOFOLLOW on Linux */
 
+#include "cdefs.h"
 #include "err.h"
 #include "daylog.h"
 #include "str.h"
 #include "err.h"
 #include "daylog.h"
 #include "str.h"
@@ -23,7 +24,7 @@
 #include <unistd.h>
 
 static const char *daylog_fn = NULL;
 #include <unistd.h>
 
 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 */
 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. */
 }
 
 /* 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;
 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",
 
 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);
 }
 
 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",
    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",
 }
 
 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) {
 }
 
 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;
       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. */
    }
 
    /* Accounting. */
diff --git a/db.c b/db.c
index cf50da9..cadd26e 100644 (file)
--- a/db.c
+++ b/db.c
@@ -1,7 +1,7 @@
 /* darkstat 3
  *
  * db.c: load and save in-memory database from/to file
 /* 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)
  *
  * 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 (file)
--- a/db.h
+++ b/db.h
@@ -1,7 +1,7 @@
 /* darkstat 3
  *
  * db.h: load and save in-memory database from/to file
 /* 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 <sys/types.h> /* for size_t */
  */
 
 #include <sys/types.h> /* for size_t */
diff --git a/debian/README.Source b/debian/README.Source
deleted file mode 100644 (file)
index 10a1ce4..0000000
+++ /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.
index dfd5e0e..ca4bc75 100644 (file)
@@ -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 <emikulic@gmail.com>  Sun, 18 Aug 2013 16:37:10 +1000
+ -- Rene Mayorga <rmayorga@debian.org>  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 <rmayorga@debian.org>  Sun, 23 Mar 2014 12:36:51 +0000
 
 darkstat (3.0.715-1) unstable; urgency=low
 
 
 darkstat (3.0.715-1) unstable; urgency=low
 
index 7f8f011..ec63514 100644 (file)
@@ -1 +1 @@
-7
+9
index 17cc6ad..ff0da4c 100644 (file)
@@ -3,9 +3,9 @@ Section: net
 Priority: optional
 Maintainer: Rene Mayorga <rmayorga@debian.org>
 Uploaders: Emil Mikulic <emikulic@gmail.com>
 Priority: optional
 Maintainer: Rene Mayorga <rmayorga@debian.org>
 Uploaders: Emil Mikulic <emikulic@gmail.com>
-Build-Depends: debhelper (>= 7), libpcap-dev, autotools-dev, po-debconf,
+Build-Depends: debhelper (>= 9), libpcap-dev, autotools-dev, po-debconf,
  zlib1g-dev
  zlib1g-dev
-Standards-Version: 3.9.2
+Standards-Version: 3.9.5
 Homepage: http://unix4lyfe.org/darkstat/
 
 Package: darkstat
 Homepage: http://unix4lyfe.org/darkstat/
 
 Package: darkstat
diff --git a/debian/patches/CorrectTcmpdump-section b/debian/patches/CorrectTcmpdump-section
new file mode 100644 (file)
index 0000000..68ab15b
--- /dev/null
@@ -0,0 +1,36 @@
+Description: Correct tcpdump section number
+ Use tcpdump section number 8 for debian systems.
+Author: Rene Mayorga <rmayorga@debian.org>
+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 (file)
index 0000000..1a05c77
--- /dev/null
@@ -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 <rmayorga@debian.org>
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+--- a/now.c
++++ b/now.c
+@@ -23,7 +23,7 @@
+ #include <string.h>
+ #include <time.h>
+-#ifdef __MACH__
++#ifdef __APPLE__
+ /* Fake up clock_gettime() on OS X. */
+ # include <sys/time.h>
+ # include <inttypes.h>
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644 (file)
index 0000000..c58bf3c
--- /dev/null
@@ -0,0 +1,2 @@
+CorrectTcmpdump-section
+FixHURDsFTBS.patch
diff --git a/debian/rpack.sh b/debian/rpack.sh
deleted file mode 100755 (executable)
index 3f2a823..0000000
+++ /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"
index f01ccfd..514a26e 100755 (executable)
@@ -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)
 
 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 .
 
 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
        touch $@
 
 build: configure-stamp build-stamp
+build-arch: build
+build-indep: build 
 
 build-stamp: configure-stamp
        dh_testdir
 
 build-stamp: configure-stamp
        dh_testdir
index d99b761..a7c078b 100644 (file)
@@ -1,4 +1,2 @@
 version=3
 version=3
-options=dversionmangle=s/\+dfsg// \
-       http://unix4lyfe.org/darkstat/darkstat-(.*)\.tar\.bz2 \
-       debian debian/rpack.sh
+http://unix4lyfe.org/darkstat/darkstat-(.*)\.tar\.bz2 
index e8e5f35..efa6b00 100644 (file)
--- a/decode.c
+++ b/decode.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * decode.c: packet decoding.
  *
  *
  * decode.c: packet decoding.
  *
index cc4bd55..827c0ad 100644 (file)
--- a/decode.h
+++ b/decode.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * decode.h: packet decoding.
  *
  *
  * decode.h: packet decoding.
  *
diff --git a/dns.c b/dns.c
index c89dc1b..5b6d95b 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * dns.c: synchronous DNS in a child process.
  *
  *
  * 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
 
 #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 {
 static pid_t pid = -1;
 
 struct dns_reply {
@@ -50,7 +50,7 @@ struct dns_reply {
 void
 dns_init(const char *privdrop_user)
 {
 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();
       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);
    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();
       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. */
       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);
    }
 }
       verbosef("DNS child has PID %d", pid);
    }
 }
@@ -82,7 +81,7 @@ dns_stop(void)
 {
    if (pid == -1)
       return; /* no child was started */
 {
    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");
    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);
 }
 
 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)
 
 void
 dns_queue(const struct addr *const ipaddr)
@@ -144,7 +138,7 @@ dns_queue(const struct addr *const ipaddr)
       return;
    }
 
       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)
    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;
 
    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 */
    if (numread == -1) {
       if (errno == EAGAIN)
          return (0); /* no input waiting */
@@ -256,7 +250,7 @@ struct qitem {
    struct addr ip;
 };
 
    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)
 
 static void
 enqueue(const struct addr *const ip)
@@ -302,23 +296,23 @@ dns_main(void)
    struct addr ip;
 
    setproctitle("DNS child");
    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;
    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;
          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... */
          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) {
          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;
              * 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;
          }
             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));
       }
          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 (file)
--- a/err.c
+++ b/err.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * err.c: BSD-like err() and warn() functions
  *
  *
  * err.c: BSD-like err() and warn() functions
  *
diff --git a/err.h b/err.h
index 842595a..b93f2ec 100644 (file)
--- a/err.h
+++ b/err.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * err.h: BSD-like err() and warn() functions
  *
  *
  * 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 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: */
 
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
index c0875d4..4485d45 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2006-2011 Emil Mikulic.
+ * copyright (c) 2006-2014 Emil Mikulic.
  *
  * graph_db.c: round robin database for graph data
  *
  *
  * 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 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;
 
 void graph_init(void) {
    unsigned int i;
@@ -57,6 +57,7 @@ void graph_init(void) {
    }
    start_mono = now_mono();
    start_real = now_real();
    }
    start_mono = now_mono();
    start_real = now_real();
+   last_real = 0;
    graph_reset();
 }
 
    graph_reset();
 }
 
@@ -127,6 +128,7 @@ static void rotate(struct graph *g, const unsigned int pos) {
    memcpy(g->out, tmp, size);
 
    free(tmp);
    memcpy(g->out, tmp, size);
 
    free(tmp);
+   assert(g->num_bars > 0);
    assert(pos == ( (g->pos + ofs) % g->num_bars ));
    g->pos = pos;
 }
    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) {
 }
 
 void graph_rotate(void) {
-   long t, td;
+   time_t t, td;
    struct tm *tm;
    unsigned int i;
 
    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];
    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);
 
    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, "</span>");
    if (abs(d_real - d_mono) > 1)
       str_appendf(buf, " (real time is off by %qd sec)",
    str_append(buf, "</span>");
    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)
 
    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) {
       "(<span id=\"pc\">%'u</span> <b>captured,</b> "
       "<span id=\"pd\">%'u</span> <b>dropped)</b><br>\n"
       "</p>\n",
       "(<span id=\"pc\">%'u</span> <b>captured,</b> "
       "<span id=\"pd\">%'u</span> <b>dropped)</b><br>\n"
       "</p>\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,
       "<div id=\"graphs\">\n"
 
    str_append(buf,
       "<div id=\"graphs\">\n"
@@ -361,7 +364,10 @@ struct str *xml_graphs(void) {
    struct str *buf = str_make(), *rf;
 
    str_appendf(buf, "<graphs tp=\"%qu\" tb=\"%qu\" pc=\"%u\" pd=\"%u\" rf=\"",
    struct str *buf = str_make(), *rf;
 
    str_appendf(buf, "<graphs tp=\"%qu\" tb=\"%qu\" pc=\"%u\" pd=\"%u\" rf=\"",
-      acct_total_packets, acct_total_bytes, cap_pkts_recv, cap_pkts_drop);
+      (qu)acct_total_packets,
+      (qu)acct_total_bytes,
+      cap_pkts_recv,
+      cap_pkts_drop);
    rf = length_of_time(now_real() - start_real);
    str_appendstr(buf, rf);
    str_free(rf);
    rf = length_of_time(now_real() - start_real);
    str_appendstr(buf, rf);
    str_free(rf);
@@ -376,7 +382,9 @@ struct str *xml_graphs(void) {
          j = (j + 1) % g->num_bars;
          /* <element pos="" in="" out=""/> */
          str_appendf(buf, "<e p=\"%u\" i=\"%qu\" o=\"%qu\"/>\n",
          j = (j + 1) % g->num_bars;
          /* <element pos="" in="" out=""/> */
          str_appendf(buf, "<e p=\"%u\" i=\"%qu\" o=\"%qu\"/>\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, "</%s>\n", g->unit);
    }
       } while (j != g->pos);
       str_appendf(buf, "</%s>\n", g->unit);
    }
index c2d7ae4..3058d65 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * hosts_db.c: database of hosts, ports, protocols.
  *
  *
  * hosts_db.c: database of hosts, ports, protocols.
  *
@@ -20,7 +20,7 @@
 #include "opt.h"
 #include "str.h"
 
 #include "opt.h"
 #include "str.h"
 
-#include <netdb.h>     /* struct addrinfo */
+#include <netdb.h>  /* struct addrinfo */
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <assert.h>
 #include <errno.h>
 #include <stdio.h>
@@ -342,10 +342,12 @@ format_row_host(struct str *buf, const struct bucket *b,
       " <td class=\"num\">%'qu</td>\n"
       " <td class=\"num\">%'qu</td>\n"
       " <td class=\"num\">%'qu</td>\n",
       " <td class=\"num\">%'qu</td>\n"
       " <td class=\"num\">%'qu</td>\n"
       " <td class=\"num\">%'qu</td>\n",
-      b->in, b->out, b->total);
+      (qu)b->in,
+      (qu)b->out,
+      (qu)b->total);
 
    if (opt_want_lastseen) {
 
    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))
       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
          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);
       } 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,
       " <td class=\"num\">%'qu</td>\n"
       "</tr>\n",
       css_class,
       " <td class=\"num\">%'qu</td>\n"
       "</tr>\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,
       " <td class=\"num\">%'qu</td>\n"
       "</tr>\n",
       css_class,
       " <td class=\"num\">%'qu</td>\n"
       "</tr>\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,
       " <td class=\"num\">%'qu</td>\n"
       "</tr>\n",
       css_class,
       " <td class=\"num\">%'qu</td>\n"
       "</tr>\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;
    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)
 
    h = host_search(ip);
    if (h == NULL)
@@ -1065,9 +1081,9 @@ static struct str *html_hosts_detail(const char *ip) {
       "<p>\n"
       "<b>Last seen:</b> ");
 
       "<p>\n"
       "<b>Last seen:</b> ");
 
-   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),
    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()) {
          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) {
       " <b>Out:</b> %'qu<br>\n"
       " <b>Total:</b> %'qu<br>\n"
       "</p>\n",
       " <b>Out:</b> %'qu<br>\n"
       " <b>Total:</b> %'qu<br>\n"
       "</p>\n",
-      h->in, h->out, h->total);
+      (qu)h->in,
+      (qu)h->out,
+      (qu)h->total);
 
    str_append(buf, "<h3>TCP ports</h3>\n");
    format_table(buf, h->u.host.ports_tcp, 0,TOTAL,0);
 
    str_append(buf, "<h3>TCP ports</h3>\n");
    format_table(buf, h->u.host.ports_tcp, 0,TOTAL,0);
index 3f869f1..109f373 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * hosts_db.h: database of hosts, ports, protocols.
  *
  *
  * hosts_db.h: database of hosts, ports, protocols.
  *
@@ -19,7 +19,7 @@ struct host {
    struct addr addr;
    char *dns;
    uint8_t mac_addr[6];
    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;
 };
 
    struct hashtable *ports_tcp, *ports_udp, *ip_protos;
 };
 
index b6f32dd..bb88581 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * hosts_sort.c: quicksort a table of buckets.
  *
  *
  * hosts_sort.c: quicksort a table of buckets.
  *
diff --git a/http.c b/http.c
index e39f16b..0cd6133 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* 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.
  *
  * http.c: embedded webserver.
  * This borrows a lot of code from darkhttpd.
@@ -37,6 +37,9 @@
 #include <unistd.h>
 #include <zlib.h>
 
 #include <unistd.h>
 #include <zlib.h>
 
+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";
 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;
 
     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 */
     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;
 
     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"
     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"
         "Content-Encoding: %s\r\n"
         "X-Robots-Tag: noindex, noarchive\r\n"
         "%s"
-        "\r\n"
-        ,
+        "\r\n",
         code, text,
         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;
 }
         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.
  */
 /* ---------------------------------------------------------------------------
  * 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, ...)
 {
 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;
 
     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;
 
     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);
     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;
     }
 
         return;
     }
 
@@ -605,22 +621,32 @@ process_gzip(struct connection *conn)
  */
 static void process_get(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);
 
 
     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) {
     }
 
     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;
 }
 
     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.
 /* 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");
 
     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) ? "]" : "",
         (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));
 
     /* 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;
 
     struct connection *conn;
     unsigned int i;
 
+    free(http_base_url);
+
     /* Close listening sockets. */
     for (i=0; i<insock_num; i++)
         close(insocks[i]);
     /* Close listening sockets. */
     for (i=0; i<insock_num; i++)
         close(insocks[i]);
diff --git a/http.h b/http.h
index 567d048..e8c815d 100644 (file)
--- a/http.h
+++ b/http.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * http.h: embedded webserver.
  */
  *
  * http.h: embedded webserver.
  */
@@ -8,6 +8,7 @@
 #include <sys/select.h>
 #include <netinet/in.h>
 
 #include <sys/select.h>
 #include <netinet/in.h>
 
+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,
 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,
index f7b7f93..24951c6 100644 (file)
--- a/localip.c
+++ b/localip.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * localip.c: determine local IPs of an interface
  *
  *
  * localip.c: determine local IPs of an interface
  *
index a5b48ea..2625ada 100644 (file)
--- a/localip.h
+++ b/localip.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * localip.h: determine the local IPs of an interface
  *
  *
  * localip.h: determine the local IPs of an interface
  *
@@ -13,7 +13,7 @@
 
 struct local_ips {
    int is_valid;
 
 struct local_ips {
    int is_valid;
-   long last_update_mono;
+   time_t last_update_mono;
    int num_addrs;
    struct addr *addrs;
 };
    int num_addrs;
    struct addr *addrs;
 };
index 96e052f..1d23d1c 100644 (file)
--- a/ncache.c
+++ b/ncache.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * ncache.c: cache of protocol and service names.
  *
  *
  * 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_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),
 
 static struct nc_tree
    t_proto   = RB_INITIALIZER(&name_rec),
diff --git a/now.c b/now.c
index f0751a8..95ab2a2 100644 (file)
--- a/now.c
+++ b/now.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2012 Emil Mikulic.
+ * copyright (c) 2012-2014 Emil Mikulic.
  *
  * now.c: a cache of the current time.
  *
  *
  * now.c: a cache of the current time.
  *
  */
 #include "err.h"
 #include "now.h"
  */
 #include "err.h"
 #include "now.h"
+#include "str.h"
 
 #include <assert.h>
 #include <string.h>
 #include <time.h>
 
 
 #include <assert.h>
 #include <string.h>
 #include <time.h>
 
-#ifdef __MACH__
+#ifdef __APPLE__
 /* Fake up clock_gettime() on OS X. */
 # include <sys/time.h>
 # include <inttypes.h>
 /* Fake up clock_gettime() on OS X. */
 # include <sys/time.h>
 # include <inttypes.h>
@@ -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;
 
 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;
 }
 
    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;
 }
    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;
 }
 
    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) {
 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)) {
 
    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));
 }
    }
    memcpy(dest, &t, sizeof(t));
 }
@@ -113,12 +120,12 @@ void now_update(void) {
    all_clocks_update();
 }
 
    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;
 }
 
    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;
 }
    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;
 }
 
           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) {
                 const int64_t nsec,
                 const char *warning) {
-   struct timespec t2;
+   struct timespec t1;
    int64_t diff;
 
    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,
       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: */
 }
 
 /* vim:set ts=3 sw=3 tw=80 et: */
diff --git a/now.h b/now.h
index 9c61f45..03366e7 100644 (file)
--- a/now.h
+++ b/now.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2006 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * now.h: a cache of the current time.
  *
  *
  * now.h: a cache of the current time.
  *
 void now_init(void);
 void now_update(void); /* once per event loop (in darkstat.c) */
 
 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;
 
 /* Emits warnings if a call is too slow. */
 struct timespec;
diff --git a/opt.h b/opt.h
index 34afc36..dfbd384 100644 (file)
--- a/opt.h
+++ b/opt.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * opt.h: global options
  */
  *
  * opt.h: global options
  */
index 044c574..92403cd 100644 (file)
--- a/pidfile.c
+++ b/pidfile.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2007-2011 Emil Mikulic.
+ * copyright (c) 2007-2014 Emil Mikulic.
  *
  * pidfile.h: pidfile manglement
  *
  *
  * pidfile.h: pidfile manglement
  *
 static int pidfd = -1;
 static const char *pidname = NULL;
 
 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)
    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);
    }
 
          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)
    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 (file)
--- a/str.c
+++ b/str.c
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * str.c: string buffer with pool-based reallocation
  *
  *
  * str.c: string buffer with pool-based reallocation
  *
diff --git a/str.h b/str.h
index 92cb78f..c6cb197 100644 (file)
--- a/str.h
+++ b/str.h
@@ -1,5 +1,5 @@
 /* darkstat 3
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * str.h: string buffer with pool-based reallocation
  *
  *
  * str.h: string buffer with pool-based reallocation
  *
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
  * 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 <sys/types.h>
 #include <stdarg.h>
 
 #include <sys/types.h>
 #include <stdarg.h>
+#include <stdint.h>  /* 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! */
 
 
 /* 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
 
 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);
 
 
 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: */
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
diff --git a/tree.h b/tree.h
index f533547..6ee1af6 100644 (file)
--- 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 <provos@citi.umich.edu>
  * All rights reserved.
  *
  * Copyright 2002 Niels Provos <provos@citi.umich.edu>
  * All rights reserved.
  *
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
  * 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_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
 
 #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_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;                                 \
 
 #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)
 
        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);                                   \
 
 #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)
 
                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 <assert.h>
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
 #define        RB_GENERATE(name, type, field, cmp)                             \
 #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)            \
 #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);                     \
        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) {    \
                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);          \
                        }                                               \
                                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 ||            \
                        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);           \
                        }                                               \
                                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 ||            \
                        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;                            \
                        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;   \
                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);                                                  \
 }                                                                      \
                                                                        \
        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)                                       \
 /* ARGSUSED */                                                         \
 attr struct type *                                                     \
 name##_RB_NEXT(struct type *elm)                                       \
@@ -370,6 +429,28 @@ name##_RB_NEXT(struct type *elm)                                   \
        return (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)                           \
 {                                                                      \
 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_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_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_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_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_ */