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.
@@ -29,15 +41,17 @@ v3.0.714 (June 2011)
        - Allow sort on last-seen, thanks to Dirk Koopman.
        - Support multiple bind addresses.
        - Add --disable-debug configure flag, thanks to Malte S. Stretz.
-       - Make it possible to save the DB without resetting it (SIGUSR2).
-       - Web: Use relative URLs, so darkstat works properly behind mod_proxy,
-         thanks to Malte S. Stretz.
+       - Make it possible to export the database without resetting it:
+         by sending SIGUSR2.
+       - Web: Use relative URLs, so darkstat works properly
+         behind mod_proxy, thanks to Malte S. Stretz.
 
 v3.0.713 (March 2010)
        - Don't require --verbose for pcap_stats.
        - Survive interface going down on Linux.
        - Support DLT_RAW, implemented by Anton S. Ustyuzhanin.
-       - Skip accounting for hosts or ports if their max is set to zero.
+       - Skip accounting for hosts or ports if their max
+         is set to zero.
        - Implement --hexdump for troubleshooting.
        - Web: Implement --no-lastseen
        - Implement --snaplen manual override.
@@ -177,6 +191,6 @@ v3.0.471 (Jun 2006)
 
 v2.6 (Nov 2003)
 
-       End of the line for darkstat 2
+       End of the line for darkstat 2.
 
 vim:set noet ts=8 sw=8 tw=72:
index b0dbf2e..6aa57d1 100644 (file)
@@ -1,5 +1,5 @@
 # darkstat 3
-# copyright (c) 2001-2011 Emil Mikulic.
+# copyright (c) 2001-2014 Emil Mikulic.
 #
 # You may use, modify and redistribute this file under the terms of the
 # GNU General Public License version 2. (see COPYING.GPL)
@@ -129,9 +129,9 @@ cap.o: cap.c acct.h cdefs.h cap.h config.h conv.h decode.h addr.h err.h \
  hosts_db.h localip.h now.h opt.h queue.h str.h
 conv.o: conv.c conv.h err.h cdefs.h
 darkstat.o: darkstat.c acct.h cap.h cdefs.h config.h conv.h daylog.h \
- graph_db.h db.h dns.h err.h http.h hosts_db.h addr.h localip.h ncache.h \
- now.h pidfile.h
-daylog.o: daylog.c err.h cdefs.h daylog.h graph_db.h str.h now.h
+ graph_db.h db.h dns.h err.h hosts_db.h addr.h http.h localip.h ncache.h \
+ now.h pidfile.h str.h
+daylog.o: daylog.c cdefs.h err.h daylog.h graph_db.h str.h now.h
 db.o: db.c cdefs.h err.h hosts_db.h addr.h graph_db.h db.h
 decode.o: decode.c cdefs.h decode.h addr.h err.h opt.h
 dns.o: dns.c cdefs.h conv.h decode.h addr.h dns.h err.h hosts_db.h \
@@ -142,12 +142,12 @@ graph_db.o: graph_db.c cap.h conv.h db.h acct.h err.h cdefs.h str.h \
 hosts_db.o: hosts_db.c cdefs.h conv.h decode.h addr.h dns.h err.h \
  hosts_db.h db.h html.h ncache.h now.h opt.h str.h
 hosts_sort.o: hosts_sort.c cdefs.h err.h hosts_db.h addr.h
-html.o: html.c config.h str.h html.h opt.h
+html.o: html.c config.h str.h cdefs.h html.h opt.h
 http.o: http.c cdefs.h config.h conv.h err.h graph_db.h hosts_db.h addr.h \
  http.h now.h queue.h str.h stylecss.h graphjs.h
 localip.o: localip.c addr.h bsd.h config.h conv.h err.h cdefs.h localip.h \
  now.h
 ncache.o: ncache.c conv.h err.h cdefs.h ncache.h tree.h bsd.h config.h
-now.o: now.c err.h cdefs.h now.h
+now.o: now.c err.h cdefs.h now.h str.h
 pidfile.o: pidfile.c err.h cdefs.h str.h pidfile.h
 str.o: str.c conv.h err.h cdefs.h str.h
diff --git a/NEWS b/NEWS
index c40c9de..5c4af07 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 Changes to defaults, most recent first:
 
+- After v3.0.717, the user must specify a --chroot dir for chroot() to happen.
+  We don't set a default in the configure script anymore.
+
 - After v3.0.708, --debug was split into --verbose and --no-daemon.
 
 - Since v3.0.694, darkstat is able to save its internal database into a file and
@@ -17,3 +20,5 @@ Changes to defaults, most recent first:
   terminal, and run in the background.
 
   After 540, the default has been inverted.  darkstat will daemonize by default.
+
+vim:set noet ts=8 sw=8 tw=80:
diff --git a/acct.c b/acct.c
index 17aa4f0..3605674 100644 (file)
--- a/acct.c
+++ b/acct.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * acct.c: traffic accounting
  *
diff --git a/acct.h b/acct.h
index b4edb7f..0a4b261 100644 (file)
--- a/acct.h
+++ b/acct.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * acct.h: traffic accounting
  */
diff --git a/bsd.c b/bsd.c
index 9a9f156..0b9c316 100644 (file)
--- a/bsd.c
+++ b/bsd.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2011 Emil Mikulic.
  *
  * bsd.c: *BSD compatibility.
  *
diff --git a/bsd.h b/bsd.h
index 3426add..6939f59 100644 (file)
--- a/bsd.h
+++ b/bsd.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2011-2014 Emil Mikulic.
  *
  * bsd.h: *BSD compatibility.
  */
@@ -22,7 +22,7 @@ size_t strlcat(char *dst, const char *src, size_t siz);
 #endif
 
 #ifndef HAVE_SETPROCTITLE
-#define setproctitle(fmt, ...) /* no-op */
+#define setproctitle(fmt) /* no-op */
 #endif
 
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
diff --git a/cap.c b/cap.c
index 7e1c41b..62da77d 100644 (file)
--- a/cap.c
+++ b/cap.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * cap.c: capture packets, and hand them off to decode and acct.
  *
@@ -398,12 +398,21 @@ static void callback(u_char *user,
 /* Process any packets currently in the capture buffer. */
 void cap_poll(fd_set *read_set _unused_on_linux_) {
    struct cap_iface *iface;
+   static int told = 0;
 
    STAILQ_FOREACH(iface, &cap_ifs, entries) {
       /* Once per capture poll, check our IP address.  It's used in accounting
        * for traffic graphs.
        */
       localip_update(iface->name, &iface->local_ips);
+      if (!told && iface->local_ips.num_addrs == 0) {
+         verbosef("interface '%s' has no addresses, "
+                  "your graphs will be blank",
+                  iface->name);
+         verbosef("please read the darkstat manpage, "
+                  "and consider using the -l option");
+         told = 1;
+      }
 
       for (;;) {
          struct timespec t;
@@ -415,18 +424,19 @@ void cap_poll(fd_set *read_set _unused_on_linux_) {
                -1, /* count = entire buffer */
                callback,
                (u_char*)iface); /* user = struct to pass to callback */
+         timer_stop(&t,
+                    2 * CAP_TIMEOUT_MSEC * 1000000,
+                    "pcap_dispatch took too long");
 
          if (ret < 0) {
             warnx("pcap_dispatch('%s'): %s",
                iface->name, pcap_geterr(iface->pcap));
             continue;
          }
-         timer_stop(&t,
-                    2 * CAP_TIMEOUT_MSEC * 1000000,
-                    "pcap_dispatch took too long");
 
-         if (0) /* debugging */
-            verbosef("iface '%s' got %d pkts", iface->name, ret);
+#if 0 /* debugging */
+         verbosef("iface '%s' got %d pkts", iface->name, ret);
+#endif
 
 #ifdef linux
          /* keep looping until we've dispatched all the outstanding packets */
diff --git a/cap.h b/cap.h
index e1a77cf..f9f455a 100644 (file)
--- a/cap.h
+++ b/cap.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * cap.h: interface to libpcap.
  */
diff --git a/cdefs.h b/cdefs.h
index a0405eb..2bcdf31 100644 (file)
--- a/cdefs.h
+++ b/cdefs.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * cdefs.h: compiler-specific defines
  *
@@ -26,7 +26,7 @@
 #endif
 
 #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901
-#define restrict __restrict
+# define restrict __restrict
 #endif
 
 #ifndef MAX
 # 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: */
index 6a34856..f0e3e7f 100644 (file)
@@ -1,8 +1,5 @@
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
-/* Default chroot directory. */
-#undef CHROOT_DIR
-
 /* Define to 1 if you have the <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.
-# Generated by GNU Autoconf 2.69 for darkstat 3.0.717.
+# Generated by GNU Autoconf 2.69 for darkstat 3.0.718.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='darkstat'
 PACKAGE_TARNAME='darkstat'
-PACKAGE_VERSION='3.0.717'
-PACKAGE_STRING='darkstat 3.0.717'
+PACKAGE_VERSION='3.0.718'
+PACKAGE_STRING='darkstat 3.0.718'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL='http://unix4lyfe.org/darkstat/'
 
@@ -676,7 +676,6 @@ SHELL'
 ac_subst_files=''
 ac_user_opts='
 enable_option_checking
-with_chroot_dir
 with_privdrop_user
 enable_silent_rules
 enable_debug
@@ -1232,7 +1231,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures darkstat 3.0.717 to adapt to many kinds of systems.
+\`configure' configures darkstat 3.0.718 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1293,7 +1292,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of darkstat 3.0.717:";;
+     short | recursive ) echo "Configuration of darkstat 3.0.718:";;
    esac
   cat <<\_ACEOF
 
@@ -1310,7 +1309,6 @@ Optional Features:
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
   --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
-  --with-chroot-dir       specify the chroot directory (default: /var/empty)
   --with-privdrop-user    specify which user to drop privileges to (default:
                           nobody)
   --with-pcap=DIR         prefix to libpcap installation
@@ -1392,7 +1390,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-darkstat configure 3.0.717
+darkstat configure 3.0.718
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1690,7 +1688,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by darkstat $as_me 3.0.717, which was
+It was created by darkstat $as_me 3.0.718, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2044,45 +2042,6 @@ ac_config_headers="$ac_config_headers config.h"
 
 RULE="------------------------------------------------------------"
 
-# Let user specify CHROOT_DIR, or else autodetect it, or else die.
-
-# Check whether --with-chroot-dir was given.
-if test "${with_chroot_dir+set}" = set; then :
-  withval=$with_chroot_dir; if test "x$withval" = "xyes"; then
-   as_fn_error $? "please specify --with-chroot-dir=/path/to/darkstat/chroot" "$LINENO" 5
-  fi
-  _chd="$withval"
-else
-  # Find an "empty" directory to serve as the chroot.
-  _chd="/var/empty"
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $_chd" >&5
-$as_echo_n "checking for $_chd... " >&6; }
-  if test -d $_chd ; then
-   { $as_echo "$as_me:${as_lineno-$LINENO}: result: found it" >&5
-$as_echo "found it" >&6; }
-  else
-   { $as_echo "$as_me:${as_lineno-$LINENO}: result: not there" >&5
-$as_echo "not there" >&6; }
-   _chd="/var/lib/empty"
-   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $_chd" >&5
-$as_echo_n "checking for $_chd... " >&6; }
-   if test -d $_chd ; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: found it" >&5
-$as_echo "found it" >&6; }
-   else
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: not there either" >&5
-$as_echo "not there either" >&6; }
-    as_fn_error $? "please specify --with-chroot-dir=/path/to/darkstat/chroot" "$LINENO" 5
-   fi
-  fi
-fi
-
-
-cat >>confdefs.h <<_ACEOF
-#define CHROOT_DIR "$_chd"
-_ACEOF
-
-
 # Allow configure-time override of PRIVDROP_USER.
 
 # Check whether --with-privdrop-user was given.
@@ -4746,7 +4705,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by darkstat $as_me 3.0.717, which was
+This file was extended by darkstat $as_me 3.0.718, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -4809,7 +4768,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-darkstat config.status 3.0.717
+darkstat config.status 3.0.718
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
index 7af8316..2c22002 100644 (file)
@@ -1,36 +1,11 @@
 # Need at least 2.64 for PACKAGE_URL
 AC_PREREQ([2.64])
-AC_INIT(darkstat, 3.0.717, , , http://unix4lyfe.org/darkstat/)
+AC_INIT(darkstat, 3.0.718, , , http://unix4lyfe.org/darkstat/)
 AC_CONFIG_SRCDIR([darkstat.c])
 AC_CONFIG_HEADER([config.h])
 
 RULE="------------------------------------------------------------"
 
-# Let user specify CHROOT_DIR, or else autodetect it, or else die.
-AC_ARG_WITH(chroot-dir, AS_HELP_STRING([--with-chroot-dir],
- [specify the chroot directory (default: /var/empty)]),
- [if test "x$withval" = "xyes"; then
-   AC_MSG_ERROR([please specify --with-chroot-dir=/path/to/darkstat/chroot])
-  fi
-  _chd="$withval"],
- [# Find an "empty" directory to serve as the chroot.
-  _chd="/var/empty"
-  AC_MSG_CHECKING([for $_chd])
-  if test -d $_chd ; then
-   AC_MSG_RESULT(found it)
-  else
-   AC_MSG_RESULT(not there)
-   _chd="/var/lib/empty"
-   AC_MSG_CHECKING([for $_chd])
-   if test -d $_chd ; then
-    AC_MSG_RESULT(found it)
-   else
-    AC_MSG_RESULT(not there either)
-    AC_MSG_ERROR([please specify --with-chroot-dir=/path/to/darkstat/chroot])
-   fi
-  fi])
-AC_DEFINE_UNQUOTED(CHROOT_DIR, "$_chd", [Default chroot directory.])
-
 # Allow configure-time override of PRIVDROP_USER.
 AC_ARG_WITH(privdrop-user, AS_HELP_STRING([--with-privdrop-user],
  [specify which user to drop privileges to (default: nobody)]),
diff --git a/contrib/darkstat_export b/contrib/darkstat_export
new file mode 100644 (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
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * conv.c: convenience functions.
  *
@@ -288,9 +288,7 @@ daemonize_finish(void)
  * For security, chroot (optionally) and drop privileges.
  * Pass a NULL chroot_dir to disable chroot() behaviour.
  */
-void
-privdrop(const char *chroot_dir, const char *privdrop_user)
-{
+void privdrop(const char *chroot_dir, const char *privdrop_user) {
    struct passwd *pw;
 
    errno = 0;
@@ -302,7 +300,9 @@ privdrop(const char *chroot_dir, const char *privdrop_user)
       else
          err(1, "getpwnam(\"%s\") failed", privdrop_user);
    }
-   if (chroot_dir != NULL) {
+   if (chroot_dir == NULL) {
+      verbosef("no --chroot dir specified, darkstat will not chroot()");
+   } else {
       tzset(); /* read /etc/localtime before we chroot */
       if (chdir(chroot_dir) == -1)
          err(1, "chdir(\"%s\") failed", chroot_dir);
@@ -344,3 +344,5 @@ fd_set_block(const int fd)
       err(1, "fcntl(fd %d) to unset O_NONBLOCK", fd);
    assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == 0 );
 }
+
+/* vim:set ts=3 sw=3 tw=78 expandtab: */
index e786af3..9b5a0b4 100644 (file)
@@ -1,6 +1,6 @@
 .\"
 .\" darkstat 3
-.\" Copyright 2001-2011, Emil Mikulic.
+.\" Copyright 2001-2014, Emil Mikulic.
 .\"
 .\" You may use, modify and redistribute this file under the terms of the
 .\" GNU General Public License version 2. (see COPYING.GPL)
@@ -38,6 +38,8 @@ darkstat \- network statistics gatherer
 ] [
 .BI \-b " bindaddr"
 ] [
+.BI \-\-base " path"
+] [
 .BI \-f " filter"
 ] [
 .BI \-l " network/netmask"
@@ -169,11 +171,30 @@ Bind the web interface to the specified address.
 The default is to listen on all interfaces.
 .\"
 .TP
+.BI \-\-base " path"
+.RS
+Specify the path of the base URL.
+This can be useful if \fIdarkstat\fR is accessed via a reverse proxy.
+
+For example, if you use Apache's \fImod_proxy\fR and want to avoid a
+complicated setup with \fImod_proxy_html\fR (and \fImod_header\fR to unset
+the \fIAccept-Encoding\fR header), just set the base path to something like
+\fIstats\fR and use a config similar to the following snippet:
+
+.IP
+ ProxyPass /stats/ http://localhost:667/stats/
+ ProxyPassReverse /stats/ http://localhost:667/stats/
+.PP
+
+The default is \fI/\fR (i.e. the root).
+.RE
+.\"
+.TP
 .BI \-f " filter"
 Use the specified filter expression when capturing traffic.
 The filter syntax is beyond the scope of this manual page;
 please refer to the
-.BR tcpdump (1)
+.BR tcpdump (8)
 documentation.
 .\"
 .TP
@@ -381,7 +402,7 @@ darkstat \-i fxp0 \-f "not (src net 192.168.0 and dst net 192.168.0)"
 .PP
 .\"
 (For a full reference on filter syntax, refer to the
-.BR tcpdump (1)
+.BR tcpdump (8)
 manpage)
 .PP
 .\"
@@ -439,7 +460,7 @@ You can also use it to do accounting for a whole subnet by specifying
 an appropriate netmask.
 .\"
 .SH SEE ALSO
-.BR tcpdump (1)
+.BR tcpdump (8)
 .\"
 .SH HISTORY
 .I darkstat
index 2213986..c65631e 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * darkstat.c: signals, cmdline parsing, program body.
  *
 #include "db.h"
 #include "dns.h"
 #include "err.h"
-#include "http.h"
 #include "hosts_db.h"
+#include "http.h"
 #include "localip.h"
 #include "ncache.h"
 #include "now.h"
 #include "pidfile.h"
+#include "str.h"
 
 #include <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_base = NULL;
+static void cb_base(const char *arg) { opt_base = arg; }
+
 const char *opt_privdrop_user = NULL;
 static void cb_user(const char *arg) { opt_privdrop_user = arg; }
 
-const char *daylog_fn = NULL;
-static void cb_daylog(const char *arg)
-{
-   if (opt_chroot_dir == NULL)
-      errx(1, "the daylog file is relative to the chroot.\n"
-      "You must specify a --chroot dir before you can use --daylog.");
-   else
-      daylog_fn = arg;
-}
+const char *opt_daylog_fn = NULL;
+static void cb_daylog(const char *arg) { opt_daylog_fn = arg; }
 
 const char *import_fn = NULL;
-static void cb_import(const char *arg)
-{
-   if (opt_chroot_dir == NULL)
-      errx(1, "the import file is relative to the chroot.\n"
-      "You must specify a --chroot dir before you can use --import.");
-   else
-      import_fn = arg;
-}
+static void cb_import(const char *arg) { import_fn = arg; }
 
 const char *export_fn = NULL;
-static void cb_export(const char *arg)
-{
-   if ((opt_chroot_dir == NULL) && (opt_capfile == NULL))
-      errx(1, "the export file is relative to the chroot.\n"
-      "You must specify a --chroot dir before you can use --export.");
-   else
-      export_fn = arg;
-}
+static void cb_export(const char *arg) { export_fn = arg; }
 
 static const char *pid_fn = NULL;
-static void cb_pidfile(const char *arg)
-{
-   if (opt_chroot_dir == NULL)
-      errx(1, "the pidfile is relative to the chroot.\n"
-      "You must specify a --chroot dir before you can use --pidfile.");
-   else
-      pid_fn = arg;
-}
+static void cb_pidfile(const char *arg) { pid_fn = arg; }
 
 unsigned int opt_hosts_max = 1000;
 static void cb_hosts_max(const char *arg)
@@ -218,6 +194,7 @@ static struct cmdline_arg cmdline_args[] = {
    {"-p",             "port",            cb_port,         0},
    {"-b",             "bindaddr",        cb_bindaddr,    -1},
    {"-l",             "network/netmask", cb_local,        0},
+   {"--base",         "path",            cb_base,         0},
    {"--local-only",   NULL,              cb_local_only,   0},
    {"--snaplen",      "bytes",           cb_snaplen,      0},
    {"--pppoe",        NULL,              cb_pppoe,        0},
@@ -329,9 +306,7 @@ static void parse_cmdline(const int argc, char * const *argv) {
    if (opt_want_syslog)
       openlog("darkstat", LOG_NDELAY | LOG_PID, LOG_DAEMON);
 
-   /* some default values */
-   if (opt_chroot_dir == NULL)
-      opt_chroot_dir = CHROOT_DIR;
+   /* default value */
    if (opt_privdrop_user == NULL)
       opt_privdrop_user = PRIVDROP_USER;
 
@@ -381,8 +356,8 @@ static void run_from_capfile(void) {
    hosts_db_free();
    graph_free();
    verbosef("Total packets: %llu, bytes: %llu",
-            (unsigned long long)acct_total_packets,
-            (unsigned long long)acct_total_bytes);
+            (llu)acct_total_packets,
+            (llu)acct_total_bytes);
 }
 
 /* --- Program body --- */
@@ -411,6 +386,7 @@ main(int argc, char **argv)
    /* do this first as it forks - minimize memory use */
    if (opt_want_dns) dns_init(opt_privdrop_user);
    cap_start(opt_want_promisc); /* needs root */
+   http_init_base(opt_base);
    http_listen(opt_bindport);
    ncache_init(); /* must do before chroot() */
 
@@ -418,7 +394,7 @@ main(int argc, char **argv)
 
    /* Don't need root privs for these: */
    now_init();
-   if (daylog_fn != NULL) daylog_init(daylog_fn);
+   if (opt_daylog_fn != NULL) daylog_init(opt_daylog_fn);
    graph_init();
    hosts_db_init();
    if (import_fn != NULL) db_import(import_fn);
@@ -490,7 +466,7 @@ main(int argc, char **argv)
    if (export_fn != NULL) db_export(export_fn);
    hosts_db_free();
    graph_free();
-   if (daylog_fn != NULL) daylog_free();
+   if (opt_daylog_fn != NULL) daylog_free();
    ncache_free();
    if (pid_fn) pidfile_unlink();
    verbosef("shut down");
index fe1928f..080f11f 100644 (file)
--- a/daylog.c
+++ b/daylog.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2007-2011 Emil Mikulic.
+ * copyright (c) 2007-2014 Emil Mikulic.
  *
  * daylog.c: daily usage log
  *
@@ -9,6 +9,7 @@
 
 #define _GNU_SOURCE 1 /* for O_NOFOLLOW on Linux */
 
+#include "cdefs.h"
 #include "err.h"
 #include "daylog.h"
 #include "str.h"
@@ -23,7 +24,7 @@
 #include <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 */
@@ -55,6 +56,7 @@ static time_t tomorrow(time_t t_before) {
 }
 
 /* Warns on error. */
+static void daylog_write(const char *format, ...) _printflike_(1, 2);
 static void daylog_write(const char *format, ...) {
    int fd;
    ssize_t wr;
@@ -87,27 +89,32 @@ static void daylog_write(const char *format, ...) {
 
 static void daylog_emit(void) {
    daylog_write("%s|%qu|%qu|%qu|%qu|%qu\n",
-                fmt_date(today_real), (uint64_t)today_real,
-                bytes_in, bytes_out, pkts_in, pkts_out);
+                fmt_date(today_real),
+                (qu)today_real,
+                (qu)bytes_in,
+                (qu)bytes_out,
+                (qu)pkts_in,
+                (qu)pkts_out);
 }
 
 void daylog_init(const char *filename) {
    daylog_fn = filename;
    today_real = now_real();
    tomorrow_real = tomorrow(today_real);
-   verbosef("today is %ld, tomorrow is %ld",
-            (long)today_real, (long)tomorrow_real);
+   verbosef("today is %llu, tomorrow is %llu",
+            (llu)today_real,
+            (llu)tomorrow_real);
    bytes_in = bytes_out = pkts_in = pkts_out = 0;
 
    daylog_write("# logging started at %s (%qu)\n",
-                fmt_date(today_real), (uint64_t)today_real);
+                fmt_date(today_real), (qu)today_real);
 }
 
 void daylog_free(void) {
    today_real = now_real();
    daylog_emit(); /* Emit what's currently accumulated before we exit. */
    daylog_write("# logging stopped at %s (%qu)\n",
-                fmt_date(today_real), (uint64_t)today_real);
+                fmt_date(today_real), (qu)today_real);
 }
 
 void daylog_acct(uint64_t amount, enum graph_dir dir) {
@@ -121,7 +128,7 @@ void daylog_acct(uint64_t amount, enum graph_dir dir) {
       today_real = now_real();
       tomorrow_real = tomorrow(today_real);
       bytes_in = bytes_out = pkts_in = pkts_out = 0;
-      verbosef("updated daylog, tomorrow = %ld", (long)tomorrow_real);
+      verbosef("updated daylog, tomorrow = %llu", (llu)tomorrow_real);
    }
 
    /* Accounting. */
diff --git a/db.c b/db.c
index cf50da9..cadd26e 100644 (file)
--- a/db.c
+++ b/db.c
@@ -1,7 +1,7 @@
 /* darkstat 3
  *
  * db.c: load and save in-memory database from/to file
- * copyright (c) 2007-2011 Ben Stewart, Emil Mikulic.
+ * copyright (c) 2007-2012 Ben Stewart, Emil Mikulic.
  *
  * You may use, modify and redistribute this file under the terms of the
  * GNU General Public License version 2. (see COPYING.GPL)
diff --git a/db.h b/db.h
index 6f9d28a..8fde50d 100644 (file)
--- a/db.h
+++ b/db.h
@@ -1,7 +1,7 @@
 /* darkstat 3
  *
  * db.h: load and save in-memory database from/to file
- * copyright (c) 2007-2011 Ben Stewart, Emil Mikulic.
+ * copyright (c) 2007-2012 Ben Stewart, Emil Mikulic.
  */
 
 #include <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
 
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>
-Build-Depends: debhelper (>= 7), libpcap-dev, autotools-dev, po-debconf,
+Build-Depends: debhelper (>= 9), libpcap-dev, autotools-dev, po-debconf,
  zlib1g-dev
-Standards-Version: 3.9.2
+Standards-Version: 3.9.5
 Homepage: http://unix4lyfe.org/darkstat/
 
 Package: darkstat
diff --git a/debian/patches/CorrectTcmpdump-section b/debian/patches/CorrectTcmpdump-section
new file mode 100644 (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)
 
-CFLAGS += -Wall -g
+# CFLAGS += -Wall -g
+# 
+
+DPKG_EXPORT_BUILDFLAGS = 1
+include /usr/share/dpkg/buildflags.mk
 
 configure: configure-stamp
 configure-stamp: 
        dh_testdir
        cp /usr/share/misc/config.sub /usr/share/misc/config.guess .
-       CFLAGS="$(CFLAGS)" LDFLAGS="$(INSTALL_PROGRAM)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --with-chroot-dir=/var/lib/darkstat
+       CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man
        touch $@
 
 build: configure-stamp build-stamp
+build-arch: build
+build-indep: build 
 
 build-stamp: configure-stamp
        dh_testdir
index d99b761..a7c078b 100644 (file)
@@ -1,4 +1,2 @@
 version=3
-options=dversionmangle=s/\+dfsg// \
-       http://unix4lyfe.org/darkstat/darkstat-(.*)\.tar\.bz2 \
-       debian debian/rpack.sh
+http://unix4lyfe.org/darkstat/darkstat-(.*)\.tar\.bz2 
index e8e5f35..efa6b00 100644 (file)
--- a/decode.c
+++ b/decode.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * decode.c: packet decoding.
  *
index cc4bd55..827c0ad 100644 (file)
--- a/decode.h
+++ b/decode.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * decode.h: packet decoding.
  *
diff --git a/dns.c b/dns.c
index c89dc1b..5b6d95b 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * dns.c: synchronous DNS in a child process.
  *
@@ -38,7 +38,7 @@ static void dns_main(void) _noreturn_; /* the child process runs this */
 
 #define CHILD 0 /* child process uses this socket */
 #define PARENT 1
-static int sock[2];
+static int dns_sock[2];
 static pid_t pid = -1;
 
 struct dns_reply {
@@ -50,7 +50,7 @@ struct dns_reply {
 void
 dns_init(const char *privdrop_user)
 {
-   if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1)
+   if (socketpair(AF_UNIX, SOCK_STREAM, 0, dns_sock) == -1)
       err(1, "socketpair");
 
    pid = fork();
@@ -60,19 +60,18 @@ dns_init(const char *privdrop_user)
    if (pid == 0) {
       /* We are the child. */
       privdrop(NULL /* don't chroot */, privdrop_user);
-      close(sock[PARENT]);
-      sock[PARENT] = -1;
+      close(dns_sock[PARENT]);
+      dns_sock[PARENT] = -1;
       daemonize_finish(); /* drop our copy of the lifeline! */
       if (signal(SIGUSR1, SIG_IGN) == SIG_ERR)
          errx(1, "signal(SIGUSR1, ignore) failed");
       dns_main();
-      verbosef("fell out of dns_main()");
       exit(0);
    } else {
       /* We are the parent. */
-      close(sock[CHILD]);
-      sock[CHILD] = -1;
-      fd_set_nonblock(sock[PARENT]);
+      close(dns_sock[CHILD]);
+      dns_sock[CHILD] = -1;
+      fd_set_nonblock(dns_sock[PARENT]);
       verbosef("DNS child has PID %d", pid);
    }
 }
@@ -82,7 +81,7 @@ dns_stop(void)
 {
    if (pid == -1)
       return; /* no child was started */
-   close(sock[PARENT]);
+   close(dns_sock[PARENT]);
    if (kill(pid, SIGINT) == -1)
       err(1, "kill");
    verbosef("dns_stop() waiting for child");
@@ -112,12 +111,7 @@ tree_cmp(struct tree_rec *a, struct tree_rec *b)
 }
 
 static RB_HEAD(tree_t, tree_rec) ip_tree = RB_INITIALIZER(&tree_rec);
-/* Quiet warnings. */
-static struct tree_rec * tree_t_RB_NEXT(struct tree_rec *elm)
-   _unused_;
-static struct tree_rec * tree_t_RB_MINMAX(struct tree_t *head, int val)
-   _unused_;
-RB_GENERATE(tree_t, tree_rec, ptree, tree_cmp)
+RB_GENERATE_STATIC(tree_t, tree_rec, ptree, tree_cmp)
 
 void
 dns_queue(const struct addr *const ipaddr)
@@ -144,7 +138,7 @@ dns_queue(const struct addr *const ipaddr)
       return;
    }
 
-   num_w = write(sock[PARENT], ipaddr, sizeof(*ipaddr)); /* won't block */
+   num_w = write(dns_sock[PARENT], ipaddr, sizeof(*ipaddr)); /* won't block */
    if (num_w == 0)
       warnx("dns_queue: write: ignoring end of file");
    else if (num_w == -1)
@@ -177,7 +171,7 @@ dns_get_result(struct addr *ipaddr, char **name)
    struct dns_reply reply;
    ssize_t numread;
 
-   numread = read(sock[PARENT], &reply, sizeof(reply));
+   numread = read(dns_sock[PARENT], &reply, sizeof(reply));
    if (numread == -1) {
       if (errno == EAGAIN)
          return (0); /* no input waiting */
@@ -256,7 +250,7 @@ struct qitem {
    struct addr ip;
 };
 
-STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue);
+static STAILQ_HEAD(qhead, qitem) queue = STAILQ_HEAD_INITIALIZER(queue);
 
 static void
 enqueue(const struct addr *const ip)
@@ -302,23 +296,23 @@ dns_main(void)
    struct addr ip;
 
    setproctitle("DNS child");
-   fd_set_nonblock(sock[CHILD]);
+   fd_set_nonblock(dns_sock[CHILD]);
    verbosef("DNS child entering main DNS loop");
    for (;;) {
       int blocking;
 
       if (STAILQ_EMPTY(&queue)) {
          blocking = 1;
-         fd_set_block(sock[CHILD]);
+         fd_set_block(dns_sock[CHILD]);
          verbosef("entering blocking read loop");
       } else {
          blocking = 0;
-         fd_set_nonblock(sock[CHILD]);
+         fd_set_nonblock(dns_sock[CHILD]);
          verbosef("non-blocking poll");
       }
       for (;;) {
          /* While we have input to process... */
-         ssize_t numread = read(sock[CHILD], &ip, sizeof(ip));
+         ssize_t numread = read(dns_sock[CHILD], &ip, sizeof(ip));
          if (numread == 0)
             exit(0); /* end of file, nothing more to do here. */
          if (numread == -1) {
@@ -336,7 +330,7 @@ dns_main(void)
              * run out of input we fall through to queue processing.
              */
             blocking = 0;
-            fd_set_nonblock(sock[CHILD]);
+            fd_set_nonblock(dns_sock[CHILD]);
          }
       }
 
@@ -392,8 +386,8 @@ dns_main(void)
             strlcpy(reply.name, host, sizeof(reply.name));
             reply.error = 0;
          }
-         fd_set_block(sock[CHILD]);
-         xwrite(sock[CHILD], &reply, sizeof(reply));
+         fd_set_block(dns_sock[CHILD]);
+         xwrite(dns_sock[CHILD], &reply, sizeof(reply));
          verbosef("DNS: %s is \"%s\".", addr_to_str(&reply.addr),
             (ret == 0) ? reply.name : gai_strerror(ret));
       }
diff --git a/err.c b/err.c
index 3b42d18..bee8234 100644 (file)
--- a/err.c
+++ b/err.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * err.c: BSD-like err() and warn() functions
  *
diff --git a/err.h b/err.h
index 842595a..b93f2ec 100644 (file)
--- a/err.h
+++ b/err.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * err.h: BSD-like err() and warn() functions
  *
@@ -27,6 +27,6 @@ void warn(const char *format, ...) _printflike_(1, 2);
 void warnx(const char *format, ...) _printflike_(1, 2);
 
 void verbosef(const char *format, ...) _printflike_(1, 2);
-void dverbosef(const char *format _unused_, ...);
+void dverbosef(const char *format _unused_, ...) _printflike_(1, 2);
 
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
index c0875d4..4485d45 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2006-2011 Emil Mikulic.
+ * copyright (c) 2006-2014 Emil Mikulic.
  *
  * graph_db.c: round robin database for graph data
  *
@@ -47,7 +47,7 @@ static struct graph *graph_db[] = {
 };
 
 static unsigned int graph_db_size = sizeof(graph_db)/sizeof(*graph_db);
-static long start_mono, start_real, last_real;
+static time_t start_mono, start_real, last_real;
 
 void graph_init(void) {
    unsigned int i;
@@ -57,6 +57,7 @@ void graph_init(void) {
    }
    start_mono = now_mono();
    start_real = now_real();
+   last_real = 0;
    graph_reset();
 }
 
@@ -127,6 +128,7 @@ static void rotate(struct graph *g, const unsigned int pos) {
    memcpy(g->out, tmp, size);
 
    free(tmp);
+   assert(g->num_bars > 0);
    assert(pos == ( (g->pos + ofs) % g->num_bars ));
    g->pos = pos;
 }
@@ -169,7 +171,7 @@ static void graph_resync(const time_t new_real) {
 }
 
 void graph_rotate(void) {
-   long t, td;
+   time_t t, td;
    struct tm *tm;
    unsigned int i;
 
@@ -287,7 +289,7 @@ struct str *html_front_page(void) {
    struct str *buf, *rf;
    unsigned int i;
    char start_when[100];
-   long d_real, d_mono;
+   time_t d_real, d_mono;
 
    buf = str_make();
    html_open(buf, "Graphs", /*path_depth=*/0, /*want_graph_js=*/1);
@@ -302,7 +304,7 @@ struct str *html_front_page(void) {
    str_append(buf, "</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)
@@ -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",
-      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"
@@ -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=\"",
-      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);
@@ -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",
-            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);
    }
index c2d7ae4..3058d65 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * hosts_db.c: database of hosts, ports, protocols.
  *
@@ -20,7 +20,7 @@
 #include "opt.h"
 #include "str.h"
 
-#include <netdb.h>     /* struct addrinfo */
+#include <netdb.h>  /* struct addrinfo */
 #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",
-      b->in, b->out, b->total);
+      (qu)b->in,
+      (qu)b->out,
+      (qu)b->total);
 
    if (opt_want_lastseen) {
-      long last = b->u.host.last_seen_mono;
+      time_t last = b->u.host.last_seen_mono;
       struct str *last_str = NULL;
 
       if ((now_mono() >= last) && (last > 0))
@@ -356,7 +358,9 @@ format_row_host(struct str *buf, const struct bucket *b,
          if (last == 0)
             str_append(buf, "(never)");
          else
-            str_append(buf, "(clock error)");
+            str_appendf(buf, "(clock error: now = %qu, last = %qu)",
+                        (qu)now_mono(),
+                        (qu)last);
       } else {
          str_appendstr(buf, last_str);
          str_free(last_str);
@@ -403,7 +407,12 @@ format_row_port_tcp(struct str *buf, const struct bucket *b,
       " <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,
-      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,
-      p->proto, getproto(p->proto),
-      b->in, b->out, b->total
+      p->proto,
+      getproto(p->proto),
+      (qu)b->in,
+      (qu)b->out,
+      (qu)b->total
    );
 }
 
@@ -1027,7 +1043,7 @@ static struct str *html_hosts_detail(const char *ip) {
    struct str *buf, *ls_len;
    char ls_when[100];
    const char *canonical;
-   time_t last_real;
+   time_t last_seen_real;
 
    h = host_search(ip);
    if (h == NULL)
@@ -1065,9 +1081,9 @@ static struct str *html_hosts_detail(const char *ip) {
       "<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),
-      "%Y-%m-%d %H:%M:%S %Z%z", localtime(&last_real)) != 0)
+      "%Y-%m-%d %H:%M:%S %Z%z", localtime(&last_seen_real)) != 0)
          str_append(buf, ls_when);
 
    if (h->u.host.last_seen_mono <= now_mono()) {
@@ -1087,7 +1103,9 @@ static struct str *html_hosts_detail(const char *ip) {
       " <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);
index 3f869f1..109f373 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * hosts_db.h: database of hosts, ports, protocols.
  *
@@ -19,7 +19,7 @@ struct host {
    struct addr addr;
    char *dns;
    uint8_t mac_addr[6];
-   long last_seen_mono;
+   time_t last_seen_mono;
    struct hashtable *ports_tcp, *ports_udp, *ip_protos;
 };
 
index b6f32dd..bb88581 100644 (file)
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * hosts_sort.c: quicksort a table of buckets.
  *
diff --git a/http.c b/http.c
index e39f16b..0cd6133 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2012 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * http.c: embedded webserver.
  * This borrows a lot of code from darkhttpd.
@@ -37,6 +37,9 @@
 #include <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";
@@ -56,7 +59,7 @@ struct connection {
 
     int socket;
     struct sockaddr_storage client;
-    long last_active_mono;
+    time_t last_active_mono;
     enum {
         RECV_REQUEST,          /* receiving request */
         SEND_HEADER_AND_REPLY, /* try to send header+reply together */
@@ -381,23 +384,28 @@ static void generate_header(struct connection *conn,
     if (conn->encoding == NULL)
         conn->encoding = encoding_identity;
 
-    verbosef("http: %d %s (%s: %zu bytes)", code, text,
-        conn->encoding, conn->reply_length);
+    verbosef("http: %d %s (%s: %zu bytes)",
+             code,
+             text,
+             conn->encoding,
+             conn->reply_length);
     conn->header_length = xasprintf(&(conn->header),
         "HTTP/1.1 %d %s\r\n"
         "Date: %s\r\n"
         "Server: %s\r\n"
         "Vary: Accept-Encoding\r\n"
         "Content-Type: %s\r\n"
-        "Content-Length: %d\r\n"
+        "Content-Length: %qu\r\n"
         "Content-Encoding: %s\r\n"
         "X-Robots-Tag: noindex, noarchive\r\n"
         "%s"
-        "\r\n"
-        ,
+        "\r\n",
         code, text,
-        rfc1123_date(date, now_real()), server,
-        conn->mime_type, conn->reply_length, conn->encoding,
+        rfc1123_date(date, now_real()),
+        server,
+        conn->mime_type,
+        (qu)conn->reply_length,
+        conn->encoding,
         conn->header_extra);
     conn->http_code = code;
 }
@@ -407,6 +415,9 @@ static void generate_header(struct connection *conn,
 /* ---------------------------------------------------------------------------
  * A default reply for any (erroneous) occasion.
  */
+static void default_reply(struct connection *conn,
+    const int errcode, const char *errname, const char *format, ...)
+    _printflike_(4, 5);
 static void default_reply(struct connection *conn,
     const int errcode, const char *errname, const char *format, ...)
 {
@@ -571,11 +582,16 @@ process_gzip(struct connection *conn)
     zs.zfree = Z_NULL;
     zs.opaque = Z_NULL;
 
-    if (deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED,
-        15+16, /* 15 = biggest window, 16 = add gzip header+trailer */
-        8 /* default */,
-        Z_DEFAULT_STRATEGY) != Z_OK)
-       return;
+    if (deflateInit2(&zs,
+                     Z_BEST_COMPRESSION,
+                     Z_DEFLATED,
+                     15+16, /* 15 = biggest window,
+                               16 = add gzip header+trailer */
+                     8 /* default */,
+                     Z_DEFAULT_STRATEGY) != Z_OK) {
+        free(buf);
+        return;
+    }
 
     zs.avail_in = conn->reply_length;
     zs.next_in = (unsigned char *)conn->reply;
@@ -586,7 +602,7 @@ process_gzip(struct connection *conn)
     if (deflate(&zs, Z_FINISH) != Z_STREAM_END) {
         deflateEnd(&zs);
         free(buf);
-        verbosef("failed to compress %u bytes", (unsigned int)len);
+        verbosef("failed to compress %zu bytes", len);
         return;
     }
 
@@ -605,22 +621,32 @@ process_gzip(struct connection *conn)
  */
 static void process_get(struct connection *conn)
 {
-    char *decoded_url, *safe_url;
+    char *safe_url;
 
     verbosef("http: %s \"%s\" %s", conn->method, conn->uri,
         (conn->query == NULL)?"":conn->query);
 
-    /* work out path of file being requested */
-    decoded_url = urldecode(conn->uri);
-
-    /* make sure it's safe */
-    safe_url = make_safe_uri(decoded_url);
-    free(decoded_url);
-    if (safe_url == NULL)
     {
-        default_reply(conn, 400, "Bad Request",
-                "You requested an invalid URI: %s", conn->uri);
-        return;
+        /* Decode the URL being requested. */
+        char *decoded_url;
+        char *decoded_url_offset;
+
+        decoded_url = urldecode(conn->uri);
+
+        /* Optionally strip the base. */
+        decoded_url_offset = decoded_url;
+        if (str_starts_with(decoded_url, http_base_url)) {
+            decoded_url_offset += http_base_len - 1;
+        }
+
+        /* Make sure it's safe. */
+        safe_url = make_safe_uri(decoded_url_offset);
+        free(decoded_url);
+        if (safe_url == NULL) {
+            default_reply(conn, 400, "Bad Request",
+                    "You requested an invalid URI: %s", conn->uri);
+            return;
+        }
     }
 
     if (strcmp(safe_url, "/") == 0) {
@@ -873,6 +899,40 @@ static void poll_send_reply(struct connection *conn)
     if (conn->reply_sent == conn->reply_length) conn->state = DONE;
 }
 
+
+
+/* --------------------------------------------------------------------------
+ * Initialize the base url.
+ */
+void http_init_base(const char *url) {
+    char *slashed_url, *safe_url;
+    size_t urllen;
+
+    if (url == NULL) {
+        http_base_url = strdup("/");
+    } else {
+        /* Make sure that the url has leading and trailing slashes. */
+        urllen = strlen(url);
+        slashed_url = xmalloc(urllen+3);
+        slashed_url[0] = '/';
+        memcpy(slashed_url+1, url, urllen); /* don't copy NUL */
+        slashed_url[urllen+1] = '/';
+        slashed_url[urllen+2] = '\0';
+
+        /* Clean the url. */
+        safe_url = make_safe_uri(slashed_url);
+        free(slashed_url);
+        if (safe_url == NULL) {
+            verbosef("invalid base \"%s\", ignored", url);
+            http_base_url = strdup("/"); /* set to default */
+        } else {
+            http_base_url = safe_url;
+        }
+    }
+    http_base_len = strlen(http_base_url);
+    verbosef("set base url to \"%s\"", http_base_url);
+}
+
 /* Use getaddrinfo to figure out what type of socket to create and
  * what to bind it to.  "bindaddr" can be NULL.  Remember to freeaddrinfo()
  * the result.
@@ -962,11 +1022,12 @@ static void http_listen_one(struct addrinfo *ai,
     if (listen(sockin, 128) == -1)
         err(1, "listen() failed");
 
-    verbosef("listening on http://%s%s%s:%u/",
+    verbosef("listening on http://%s%s%s:%u%s",
         (ai->ai_family == AF_INET6) ? "[" : "",
         ipaddr,
         (ai->ai_family == AF_INET6) ? "]" : "",
-        bindport);
+        bindport,
+        http_base_url);
 
     /* add to insocks */
     insocks = xrealloc(insocks, sizeof(*insocks) * (insock_num + 1));
@@ -1122,6 +1183,8 @@ void http_stop(void) {
     struct connection *conn;
     unsigned int i;
 
+    free(http_base_url);
+
     /* Close listening sockets. */
     for (i=0; i<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
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * http.h: embedded webserver.
  */
@@ -8,6 +8,7 @@
 #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,
index f7b7f93..24951c6 100644 (file)
--- a/localip.c
+++ b/localip.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * localip.c: determine local IPs of an interface
  *
index a5b48ea..2625ada 100644 (file)
--- a/localip.h
+++ b/localip.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * localip.h: determine the local IPs of an interface
  *
@@ -13,7 +13,7 @@
 
 struct local_ips {
    int is_valid;
-   long last_update_mono;
+   time_t last_update_mono;
    int num_addrs;
    struct addr *addrs;
 };
index 96e052f..1d23d1c 100644 (file)
--- a/ncache.c
+++ b/ncache.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * ncache.c: cache of protocol and service names.
  *
@@ -33,7 +33,7 @@ rec_cmp(struct name_rec *a, struct name_rec *b)
 }
 
 RB_HEAD(nc_tree, name_rec);
-RB_GENERATE(nc_tree, name_rec, ptree, rec_cmp)
+RB_GENERATE_STATIC(nc_tree, name_rec, ptree, rec_cmp)
 
 static struct nc_tree
    t_proto   = RB_INITIALIZER(&name_rec),
diff --git a/now.c b/now.c
index f0751a8..95ab2a2 100644 (file)
--- a/now.c
+++ b/now.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2012 Emil Mikulic.
+ * copyright (c) 2012-2014 Emil Mikulic.
  *
  * now.c: a cache of the current time.
  *
  */
 #include "err.h"
 #include "now.h"
+#include "str.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>
@@ -62,12 +63,12 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp) {
 static struct timespec clock_real, clock_mono;
 static int now_initialized = 0;
 
-long now_real(void) {
+time_t now_real(void) {
    assert(now_initialized);
    return clock_real.tv_sec;
 }
 
-long now_mono(void) {
+time_t now_mono(void) {
    assert(now_initialized);
    return clock_mono.tv_sec;
 }
@@ -80,6 +81,17 @@ static int before(const struct timespec *a, const struct timespec *b) {
    return 0;
 }
 
+static void warn_backwards(const char *name,
+                           const struct timespec * const t0,
+                           const struct timespec * const t1) {
+   verbosef("%s clock went backwards from %lld.%09lld to %lld.%09lld",
+            name,
+            (lld)t0->tv_sec,
+            (lld)t0->tv_nsec,
+            (lld)t1->tv_sec,
+            (lld)t1->tv_nsec);
+}
+
 static void clock_update(const clockid_t clk_id,
                          struct timespec *dest,
                          const char *name) {
@@ -87,12 +99,7 @@ static void clock_update(const clockid_t clk_id,
 
    clock_gettime(clk_id, &t);
    if (now_initialized && before(&t, dest)) {
-      verbosef("%s clock went backwards from %ld.%09ld to %ld.%09ld",
-               name,
-               (long)dest->tv_sec,
-               (long)dest->tv_nsec,
-               (long)t.tv_sec,
-               (long)t.tv_nsec);
+      warn_backwards(name, &t, dest);
    }
    memcpy(dest, &t, sizeof(t));
 }
@@ -113,12 +120,12 @@ void now_update(void) {
    all_clocks_update();
 }
 
-long mono_to_real(const long t) {
+time_t mono_to_real(const time_t t) {
    assert(now_initialized);
    return t - clock_mono.tv_sec + clock_real.tv_sec;
 }
 
-long real_to_mono(const long t) {
+time_t real_to_mono(const time_t t) {
    assert(now_initialized);
    return t - clock_real.tv_sec + clock_mono.tv_sec;
 }
@@ -133,20 +140,24 @@ static int64_t ts_diff(const struct timespec * const a,
           a->tv_nsec - b->tv_nsec;
 }
 
-void timer_stop(const struct timespec * const t,
+void timer_stop(const struct timespec * const t0,
                 const int64_t nsec,
                 const char *warning) {
-   struct timespec t2;
+   struct timespec t1;
    int64_t diff;
 
-   clock_gettime(CLOCK_MONOTONIC, &t2);
-   diff = ts_diff(&t2, t);
-   assert(diff > 0);
-   if (diff > nsec)
+   clock_gettime(CLOCK_MONOTONIC, &t1);
+   if (before(&t1, t0)) {
+      warn_backwards("monotonic timer", t0, &t1);
+      return;
+   }
+   diff = ts_diff(&t1, t0);
+   if (diff > nsec) {
       warnx("%s (took %lld nsec, over threshold of %lld nsec)",
             warning,
-            (long long)diff,
-            (long long)nsec);
+            (lld)diff,
+            (lld)nsec);
+   }
 }
 
 /* vim:set ts=3 sw=3 tw=80 et: */
diff --git a/now.h b/now.h
index 9c61f45..03366e7 100644 (file)
--- a/now.h
+++ b/now.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2006 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * now.h: a cache of the current time.
  *
 void now_init(void);
 void now_update(void); /* once per event loop (in darkstat.c) */
 
-long now_real(void);
-long now_mono(void);
+time_t now_real(void);
+time_t now_mono(void);
 
-long mono_to_real(const long t);
-long real_to_mono(const long t);
+time_t mono_to_real(const time_t t);
+time_t real_to_mono(const time_t t);
 
 /* Emits warnings if a call is too slow. */
 struct timespec;
diff --git a/opt.h b/opt.h
index 34afc36..dfbd384 100644 (file)
--- a/opt.h
+++ b/opt.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * opt.h: global options
  */
index 044c574..92403cd 100644 (file)
--- a/pidfile.c
+++ b/pidfile.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2007-2011 Emil Mikulic.
+ * copyright (c) 2007-2014 Emil Mikulic.
  *
  * pidfile.h: pidfile manglement
  *
 static int pidfd = -1;
 static const char *pidname = NULL;
 
-void
-pidfile_create(const char *chroot_dir, const char *filename,
-   const char *privdrop_user)
-{
+void pidfile_create(const char *chroot_dir,
+                    const char *filename,
+                    const char *privdrop_user) {
    struct passwd *pw;
 
    if (pidfd != -1)
@@ -48,8 +47,11 @@ pidfile_create(const char *chroot_dir, const char *filename,
          err(1, "getpwnam(\"%s\") failed", privdrop_user);
    }
 
-   if (chdir(chroot_dir) == -1)
-      err(1, "chdir(\"%s\") failed", chroot_dir);
+   if (chroot_dir != NULL) {
+      if (chdir(chroot_dir) == -1) {
+         err(1, "chdir(\"%s\") failed", chroot_dir);
+      }
+   }
    pidname = filename;
    pidfd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600);
    if (pidfd == -1)
diff --git a/str.c b/str.c
index 852a24d..a73f387 100644 (file)
--- a/str.c
+++ b/str.c
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2012 Emil Mikulic.
  *
  * str.c: string buffer with pool-based reallocation
  *
diff --git a/str.h b/str.h
index 92cb78f..c6cb197 100644 (file)
--- a/str.h
+++ b/str.h
@@ -1,5 +1,5 @@
 /* darkstat 3
- * copyright (c) 2001-2011 Emil Mikulic.
+ * copyright (c) 2001-2014 Emil Mikulic.
  *
  * str.h: string buffer with pool-based reallocation
  *
  * 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 <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! */
 
@@ -39,13 +54,16 @@ void str_appendstr(struct str *buf, const struct str *s);
 void str_append(struct str *buf, const char *s);
 #endif
 
-size_t xvasprintf(char **result, const char *format, va_list va);
-size_t xasprintf(char **result, const char *format, ...);
-void str_appendf(struct str *buf, const char *format, ...);
-void str_vappendf(struct str *s, const char *format, va_list va);
+size_t xvasprintf(char **result, const char *format, va_list va)
+   _printflike_(2, 0);
+size_t xasprintf(char **result, const char *format, ...) _printflike_(2, 3);
+void str_vappendf(struct str *s, const char *format, va_list va)
+   _printflike_(2, 0);
+void str_appendf(struct str *s, const char *format, ...) _printflike_(2, 3);
 
 struct str *length_of_time(const time_t t);
 ssize_t str_write(const struct str * const buf, const int fd);
 size_t str_len(const struct str * const buf);
 
+#endif  /* __DARKSTAT_STR_H */
 /* vim:set ts=3 sw=3 tw=78 expandtab: */
diff --git a/tree.h b/tree.h
index f533547..6ee1af6 100644 (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.
  *
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#ifndef        _SYS_TREE_H_
+#define        _SYS_TREE_H_
+
+#include "cdefs.h"
+
+/* Macros that define a red-black tree */
 #define RB_HEAD(name, type)                                            \
 struct name {                                                          \
        struct type *rbh_root; /* root of the tree */                   \
 }
 
-#define RB_INITIALIZER(root) { NULL }
+#define RB_INITIALIZER(root)                                           \
+       { NULL }
+
+#define RB_INIT(root) do {                                             \
+       (root)->rbh_root = NULL;                                        \
+} while (/*CONSTCOND*/ 0)
 
 #define RB_BLACK       0
 #define RB_RED         1
@@ -53,6 +60,7 @@ struct {                                                              \
 #define RB_PARENT(elm, field)          (elm)->field.rbe_parent
 #define RB_COLOR(elm, field)           (elm)->field.rbe_color
 #define RB_ROOT(head)                  (head)->rbh_root
+#define RB_EMPTY(head)                 (RB_ROOT(head) == NULL)
 
 #define RB_SET(elm, parent, field) do {                                        \
        RB_PARENT(elm, field) = parent;                                 \
@@ -65,7 +73,9 @@ struct {                                                              \
        RB_COLOR(red, field) = RB_RED;                                  \
 } while (/*CONSTCOND*/ 0)
 
-#define RB_AUGMENT(x)  do {} while (0)
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x)  do {} while (/*CONSTCOND*/ 0)
+#endif
 
 #define RB_ROTATE_LEFT(head, elm, tmp, field) do {                     \
        (tmp) = RB_RIGHT(elm, field);                                   \
@@ -107,8 +117,32 @@ struct {                                                           \
                RB_AUGMENT(RB_PARENT(tmp, field));                      \
 } while (/*CONSTCOND*/ 0)
 
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp)                           \
+       RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define        RB_PROTOTYPE_STATIC(name, type, field, cmp)                     \
+       RB_PROTOTYPE_INTERNAL(name, type, field, cmp, _unused_ static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr)            \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *);                \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *);      \
+attr struct type *name##_RB_INSERT(struct name *, struct type *);      \
+attr struct type *name##_RB_FIND(struct name *, struct type *);                \
+attr struct type *name##_RB_NFIND(struct name *, struct type *);       \
+attr struct type *name##_RB_NEXT(struct type *);                       \
+attr struct type *name##_RB_PREV(struct type *);                       \
+attr struct type *name##_RB_MINMAX(struct name *, int);                        \
+                                                                       \
+
+#include <assert.h>
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
 #define        RB_GENERATE(name, type, field, cmp)                             \
-       RB_GENERATE_INTERNAL(name, type, field, cmp, static)
+       RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define        RB_GENERATE_STATIC(name, type, field, cmp)                      \
+       RB_GENERATE_INTERNAL(name, type, field, cmp, _unused_ static)
 #define RB_GENERATE_INTERNAL(name, type, field, cmp, attr)             \
 attr void                                                              \
 name##_RB_INSERT_COLOR(struct name *head, struct type *elm)            \
@@ -117,6 +151,7 @@ name##_RB_INSERT_COLOR(struct name *head, struct type *elm)         \
        while ((parent = RB_PARENT(elm, field)) != NULL &&              \
            RB_COLOR(parent, field) == RB_RED) {                        \
                gparent = RB_PARENT(parent, field);                     \
+    assert(gparent != NULL); \
                if (parent == RB_LEFT(gparent, field)) {                \
                        tmp = RB_RIGHT(gparent, field);                 \
                        if (tmp && RB_COLOR(tmp, field) == RB_RED) {    \
@@ -167,6 +202,7 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
                                RB_ROTATE_LEFT(head, parent, tmp, field);\
                                tmp = RB_RIGHT(parent, field);          \
                        }                                               \
+      assert(tmp != NULL); \
                        if ((RB_LEFT(tmp, field) == NULL ||             \
                            RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
                            (RB_RIGHT(tmp, field) == NULL ||            \
@@ -200,6 +236,7 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
                                RB_ROTATE_RIGHT(head, parent, tmp, field);\
                                tmp = RB_LEFT(parent, field);           \
                        }                                               \
+      assert(tmp != NULL); \
                        if ((RB_LEFT(tmp, field) == NULL ||             \
                            RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
                            (RB_RIGHT(tmp, field) == NULL ||            \
@@ -270,6 +307,7 @@ name##_RB_REMOVE(struct name *head, struct type *elm)                       \
                        RB_AUGMENT(RB_PARENT(old, field));              \
                } else                                                  \
                        RB_ROOT(head) = elm;                            \
+    assert(RB_LEFT(old, field) != NULL); \
                RB_PARENT(RB_LEFT(old, field), field) = elm;            \
                if (RB_RIGHT(old, field))                               \
                        RB_PARENT(RB_RIGHT(old, field), field) = elm;   \
@@ -348,6 +386,27 @@ name##_RB_FIND(struct name *head, struct type *elm)                        \
        return (NULL);                                                  \
 }                                                                      \
                                                                        \
+/* Finds the first node greater than or equal to the search key */     \
+attr struct type *                                                     \
+name##_RB_NFIND(struct name *head, struct type *elm)                   \
+{                                                                      \
+       struct type *tmp = RB_ROOT(head);                               \
+       struct type *res = NULL;                                        \
+       int comp;                                                       \
+       while (tmp) {                                                   \
+               comp = cmp(elm, tmp);                                   \
+               if (comp < 0) {                                         \
+                       res = tmp;                                      \
+                       tmp = RB_LEFT(tmp, field);                      \
+               }                                                       \
+               else if (comp > 0)                                      \
+                       tmp = RB_RIGHT(tmp, field);                     \
+               else                                                    \
+                       return (tmp);                                   \
+       }                                                               \
+       return (res);                                                   \
+}                                                                      \
+                                                                       \
 /* ARGSUSED */                                                         \
 attr struct type *                                                     \
 name##_RB_NEXT(struct type *elm)                                       \
@@ -370,6 +429,28 @@ name##_RB_NEXT(struct type *elm)                                   \
        return (elm);                                                   \
 }                                                                      \
                                                                        \
+/* ARGSUSED */                                                         \
+attr struct type *                                                     \
+name##_RB_PREV(struct type *elm)                                       \
+{                                                                      \
+       if (RB_LEFT(elm, field)) {                                      \
+               elm = RB_LEFT(elm, field);                              \
+               while (RB_RIGHT(elm, field))                            \
+                       elm = RB_RIGHT(elm, field);                     \
+       } else {                                                        \
+               if (RB_PARENT(elm, field) &&                            \
+                   (elm == RB_RIGHT(RB_PARENT(elm, field), field)))    \
+                       elm = RB_PARENT(elm, field);                    \
+               else {                                                  \
+                       while (RB_PARENT(elm, field) &&                 \
+                           (elm == RB_LEFT(RB_PARENT(elm, field), field)))\
+                               elm = RB_PARENT(elm, field);            \
+                       elm = RB_PARENT(elm, field);                    \
+               }                                                       \
+       }                                                               \
+       return (elm);                                                   \
+}                                                                      \
+                                                                       \
 attr struct type *                                                     \
 name##_RB_MINMAX(struct name *head, int val)                           \
 {                                                                      \
@@ -386,9 +467,45 @@ name##_RB_MINMAX(struct name *head, int val)                               \
 }
 
 #define RB_NEGINF      -1
+#define RB_INF 1
 
 #define RB_INSERT(name, x, y)  name##_RB_INSERT(x, y)
 #define RB_REMOVE(name, x, y)  name##_RB_REMOVE(x, y)
 #define RB_FIND(name, x, y)    name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y)   name##_RB_NFIND(x, y)
 #define RB_NEXT(name, x, y)    name##_RB_NEXT(y)
+#define RB_PREV(name, x, y)    name##_RB_PREV(y)
 #define RB_MIN(name, x)                name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x)                name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head)                                      \
+       for ((x) = RB_MIN(name, head);                                  \
+            (x) != NULL;                                               \
+            (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_FROM(x, name, y)                                    \
+       for ((x) = (y);                                                 \
+           ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL);    \
+            (x) = (y))
+
+#define RB_FOREACH_SAFE(x, name, head, y)                              \
+       for ((x) = RB_MIN(name, head);                                  \
+           ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL);    \
+            (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head)                              \
+       for ((x) = RB_MAX(name, head);                                  \
+            (x) != NULL;                                               \
+            (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_FROM(x, name, y)                            \
+       for ((x) = (y);                                                 \
+           ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL);    \
+            (x) = (y))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y)                      \
+       for ((x) = RB_MAX(name, head);                                  \
+           ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL);    \
+            (x) = (y))
+
+#endif /* _SYS_TREE_H_ */