chiark / gitweb /
Import release 0.1.13 v0.1.13
authorStephen Early <steve@greenend.org.uk>
Thu, 6 Dec 2001 17:36:00 +0000 (17:36 +0000)
committerStephen Early <steve@greenend.org.uk>
Wed, 18 May 2011 17:47:17 +0000 (18:47 +0100)
28 files changed:
INSTALL
Makefile.in
NEWS
NOTES
README
TODO
conffile.c
conffile.h
conffile_internal.h
config.h.in
configure
configure.in
debian/changelog
dh.c
ipaddr.c
linux/if_tun.h
magic.h [new file with mode: 0644]
make-secnet-sites
netlink.c
process.c
random.c
rsa.c
secnet.c
secnet.h
site.c
tun.c
udp.c
util.h

diff --git a/INSTALL b/INSTALL
index f41b4ba..49476d8 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -167,8 +167,7 @@ is running secnet.
 port number on the front-end machine, and does not necessarily have to
 match the port number on the machine running secnet.  If you want to
 use a privileged port number we suggest 410.  An appropriate
-unprivileged port number is 51396.  (These numbers were picked at
-random.)
+unprivileged port number is 51396.
 
 6. the list of networks accessible at your site over the VPN.
 
index 80db7d9..f8b37af 100644 (file)
@@ -18,7 +18,7 @@
 .PHONY:        all clean realclean distclean dist install
 
 PACKAGE:=secnet
-VERSION:=0.1.12
+VERSION:=0.1.13
 
 @SET_MAKE@
 
@@ -57,7 +57,8 @@ DISTFILES:=BUGS COPYING CREDITS INSTALL LICENSE.txt Makefile.in \
        configure.in debian depend.sh dh.c \
        example.conf \
        getopt.c getopt1.c getopt.h \
-       install-sh ipaddr.c ipaddr.h ipaddr.py linux log.c md5.c md5.h \
+       install-sh ipaddr.c ipaddr.h ipaddr.py linux log.c \
+       magic.h md5.c md5.h \
        make-secnet-sites \
        modules.c netlink.c netlink.h process.c process.h \
        random.c resolver.c rsa.c \
diff --git a/NEWS b/NEWS
index 4ad6647..79cb772 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,80 @@ numbers / timestamps, etc. similar to IWJ's udptunnel
 Path-MTU discovery for each tunnel, and fragmentation/DF support in
 netlink code.
 
+Separation of device drivers from IP router code - driver produces a
+stream of packets (which has a tag indicating type and parameters).
+Router module can be connected to stream to multiplex it between
+different tunnels.
+
+Support for dynamic creation of streams/tunnels to cope with laptops,
+etc.
+
+See also file "TODO".
+
+* Planned for version 0.1.14
+
+RFC1812-compliance in netlink.c
+
+* New in version 0.1.13
+
+site.c code cleaned up; no externally visible changes
+
+secnet now calls setsid() after becoming a daemon.
+
+secnet now supports TUN on Solaris 2.5 and above (and possibly other
+STREAMS-based systems as well).
+
+The TUN code now tries to auto-detect the type of "TUN" in use
+(BSD-style, Linux-style or STREAMS-style).  If your configuration file
+specifies "tun-old" then it defaults to BSD-style; however, since
+"tun-old" will be removed in a future release, you should change your
+configuration file to specify "tun" and if there's a problem also
+specify the flavour in use.
+
+Example:
+netlink tun-old {
+       ...
+};
+should be rewritten as
+netlink tun {
+       flavour "bsd";
+       ...
+};
+
+The flavours currently defined are "bsd", "linux" and "streams".
+
+The TUN code can now be configured to configure interfaces and
+add/delete routes using one of several methods: invoking a
+"linux"-style ifconfig/route command, a "bsd"-style ifconfig/route
+command, "solaris-2.5"-style ifconfig/route command or calling ioctl()
+directly.  These methods can be selected using the "ifconfig-type" and
+"route-type" options.
+
+Example:
+netlink tun {
+       ifconfig-type "ioctl";
+       route-type "ioctl";
+       ...
+};
+
+The ioctl-based method is now the default for Linux systems.
+
+Magic numbers used within secnet are now collected in the header file
+"magic.h".
+
+netlink now uses ICMP type=0 code=13 for 'administratively prohibited'
+instead of code 9. See RFC1812 section 5.2.7.1.
+
+The UDP comm module now supports a proxy server, "udpforward".  This
+runs on a machine which is directly accessible by secnet and which can
+send packets to appropriate destinations.  It's useful when the proxy
+machine doesn't support source- and destination-NAT.  The proxy server
+is specified using the "proxy" key in the UDP module configuration;
+parameters are IP address (string) and port number.
+
+Bugfix: ipset_to_subnet_list() in ipaddr.c now believed to work in all
+cases, including 0.0.0.0/0
+
 * New in version 0.1.12
 
 IMPORTANT: fix calculation of 'now' in secnet.c; necessary for correct
diff --git a/NOTES b/NOTES
index 485443b..dd78b12 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -182,6 +182,11 @@ i? is appropriate index for receiver
 Note that 'i' may be re-used from one session to the next, whereas 'n'
 is always fresh.
 
+The protocol version selection stuff is not yet implemented: I'm not
+yet convinced it's a good idea.  Instead, the initiator could try
+using its preferred protocol (which starts with a different magic
+number) and fall back if there's no reply.
+
 Messages:
 
 1) A->B: *,iA,msg1,A,B,protorange-A,nA
diff --git a/README b/README
index 4fe279d..3c1df8b 100644 (file)
--- a/README
+++ b/README
@@ -340,6 +340,7 @@ a netlink closure:
       other tunnels as well as the host (used for mobile devices like laptops)
     soft-route: remove these routes from the host's routing table when
       the tunnel link quality is zero
+  mtu (integer): default MTU over this link; may be updated by tunnel code
 
 Netlink will dump its current routing table to the system/log on
 receipt of SIGUSR1.
@@ -363,24 +364,20 @@ Defines:
   tun-old (closure => netlink closure)
 
 tun: dict argument
+  flavour (string): optional, type of TUN interface to use
+    ("guess","linux","bsd","streams")
   device (string): optional, path of TUN/TAP device file ["/dev/net/tun"]
   interface (string): optional, name of tunnel network interface
   ifconfig-path (string): optional, path to ifconfig command
   route-path (string): optional, path to route command
+  ifconfig-type (string): optional, how to perform ifconfig
+  route-type (string): optional, how to add and remove routes
+   types are: "guess", "ioctl", "bsd", "linux", "solaris-2.5"
   buffer (buffer closure): buffer for host->secnet packets
  plus generic netlink options, as for 'null-netlink'
 
-tun-old: dict argument
-  device (string): optional, path of TUN/TAP device file ["/dev/tun*"]
-  interface (string): optional, name of tunnel network interface
-  interface-search (bool): optional, whether to search for a free tunnel
-    interface (True if 'device' not specified, otherwise False)
-  ifconfig-path (string): optional, path to ifconfig command
-  route-path (string): optional, path to route command
- plus generic netlink options, as for 'null-netlink'
-
- I recommend you don't specify the 'interface' option unless you're
- doing something that requires the interface name to be constant.
+I recommend you don't specify the 'interface' option unless you're
+doing something that requires the interface name to be constant.
 
 ** rsa
 
diff --git a/TODO b/TODO
index c7d8248..aea076b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -2,6 +2,7 @@ dh.c: change format to binary from decimal string (without introducing
 endianness problems)
 
 netlink.c: test the 'allow_route' option properly.
+Add fragmentation code.  Check that we comply with RFC1812.
 
 process.c: capture output from children in sys_cmd() and log it
 
@@ -13,9 +14,10 @@ site code ought to remember them and try contacting them in turn.
 rsa.c: check padding type, change format to binary from decimal string
 (without introducing endianness problems)
 
-site.c: the site_incoming() routing could be implemented much more
-cleanly using a table. There's still quite a lot of redundancy in this
-file. Abandon key exchanges when a bad packet is received. Modify
+secnet.c: optionally pipe stderr to a log when we become a daemon.
+Don't just close it.
+
+site.c: Abandon key exchanges when a bad packet is received. Modify
 protocol to include version fields, as described in the NOTES
 file. Implement keepalive mode. Make policy about when to initiate key
 exchanges more configurable (how many NAKs / bad reverse-transforms
@@ -27,4 +29,14 @@ fails in use?
 transform.c: separate the transforms into multiple parts, which can
 then be combined in the configuration file.  Will allow the user to
 plug in different block ciphers, invent an authenticity-only mode,
-etc.
+etc. (similar to udptunnel)
+
+tun.c: Solaris support, and configuring the interface and
+creating/deleting routes using ioctl()
+
+udp.c: option for path-MTU discovery (once fragmentation support is
+implemented in netlink)
+
+
+global:
+consider using liboop for the event loop
index 318d608..9c373c2 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Log$
- */
-
 /* conffile.c - process the configuration file */
 
 /* #define DUMP_PARSE_TREE */
index d7468a5..ee1194c 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Log$
- */
-
 #ifndef conffile_h
 #define conffile_h
 
index 710fd96..4c2cb36 100644 (file)
@@ -1,7 +1,3 @@
-/*
- * $Log$
- */
-
 #ifndef conffile_internal_h
 #define conffile_internal_h
 
index 76d28f0..508a8a8 100644 (file)
@@ -1,4 +1,4 @@
-/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+/* config.h.in.  Generated automatically from configure.in by autoheader 2.13.  */
 #ifndef _CONFIG_H
 #define _CONFIG_H
 
 /* Define if you have the <linux/if.h> header file.  */
 #undef HAVE_LINUX_IF_H
 
+/* Define if you have the <net/if.h> header file.  */
+#undef HAVE_NET_IF_H
+
+/* Define if you have the <net/if_tun.h> header file.  */
+#undef HAVE_NET_IF_TUN_H
+
+/* Define if you have the <net/route.h> header file.  */
+#undef HAVE_NET_ROUTE_H
+
 /* Define if you have the <stdint.h> header file.  */
 #undef HAVE_STDINT_H
 
+/* Define if you have the <stropts.h> header file.  */
+#undef HAVE_STROPTS_H
+
+/* Define if you have the <sys/sockio.h> header file.  */
+#undef HAVE_SYS_SOCKIO_H
+
 /* Define if you have the adns library (-ladns).  */
 #undef HAVE_LIBADNS
 
index 3c5ffcb..4fe9e2f 100755 (executable)
--- a/configure
+++ b/configure
@@ -523,7 +523,7 @@ fi
 
 
 
-# From configure.in Id
+# From configure.in Id: configure.in
 
 ac_ext=c
 # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@@ -1124,7 +1124,7 @@ else
 fi
 done
 
-for ac_hdr in linux/if.h
+for ac_hdr in net/if.h net/route.h
 do
 ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
 echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
@@ -1164,15 +1164,95 @@ else
 fi
 done
 
+for ac_hdr in linux/if.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1172: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1177 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1182: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
+for ac_hdr in stropts.h sys/sockio.h net/if_tun.h
+do
+ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
+echo "configure:1212: checking for $ac_hdr" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+  echo $ac_n "(cached) $ac_c" 1>&6
+else
+  cat > conftest.$ac_ext <<EOF
+#line 1217 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1222: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=yes"
+else
+  echo "$ac_err" >&5
+  echo "configure: failed program was:" >&5
+  cat conftest.$ac_ext >&5
+  rm -rf conftest*
+  eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+  echo "$ac_t""yes" 1>&6
+    ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'`
+  cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+else
+  echo "$ac_t""no" 1>&6
+fi
+done
+
 echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6
-echo "configure:1169: checking whether byte ordering is bigendian" >&5
+echo "configure:1249: checking whether byte ordering is bigendian" >&5
 if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   ac_cv_c_bigendian=unknown
 # See if sys/param.h defines the BYTE_ORDER macro.
 cat > conftest.$ac_ext <<EOF
-#line 1176 "configure"
+#line 1256 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -1183,11 +1263,11 @@ int main() {
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:1187: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1267: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   # It does; now see whether it defined to BIG_ENDIAN or not.
 cat > conftest.$ac_ext <<EOF
-#line 1191 "configure"
+#line 1271 "configure"
 #include "confdefs.h"
 #include <sys/types.h>
 #include <sys/param.h>
@@ -1198,7 +1278,7 @@ int main() {
 #endif
 ; return 0; }
 EOF
-if { (eval echo configure:1202: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:1282: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
   rm -rf conftest*
   ac_cv_c_bigendian=yes
 else
@@ -1218,7 +1298,7 @@ if test "$cross_compiling" = yes; then
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1222 "configure"
+#line 1302 "configure"
 #include "confdefs.h"
 main () {
   /* Are we little or big endian?  From Harbison&Steele.  */
@@ -1231,7 +1311,7 @@ main () {
   exit (u.c[sizeof (long) - 1] == 1);
 }
 EOF
-if { (eval echo configure:1235: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1315: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_bigendian=no
 else
@@ -1255,7 +1335,7 @@ EOF
 fi
 
 echo $ac_n "checking size of unsigned long long""... $ac_c" 1>&6
-echo "configure:1259: checking size of unsigned long long" >&5
+echo "configure:1339: checking size of unsigned long long" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_long_long'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1263,7 +1343,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1267 "configure"
+#line 1347 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 #include <sys/types.h>
@@ -1275,7 +1355,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1279: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_unsigned_long_long=`cat conftestval`
 else
@@ -1295,7 +1375,7 @@ EOF
 
 
 echo $ac_n "checking size of unsigned long""... $ac_c" 1>&6
-echo "configure:1299: checking size of unsigned long" >&5
+echo "configure:1379: checking size of unsigned long" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_long'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1303,7 +1383,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1307 "configure"
+#line 1387 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 #include <sys/types.h>
@@ -1315,7 +1395,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1319: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1399: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_unsigned_long=`cat conftestval`
 else
@@ -1335,7 +1415,7 @@ EOF
 
 
 echo $ac_n "checking size of unsigned int""... $ac_c" 1>&6
-echo "configure:1339: checking size of unsigned int" >&5
+echo "configure:1419: checking size of unsigned int" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_int'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1343,7 +1423,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1347 "configure"
+#line 1427 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 #include <sys/types.h>
@@ -1355,7 +1435,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1359: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1439: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_unsigned_int=`cat conftestval`
 else
@@ -1375,7 +1455,7 @@ EOF
 
 
 echo $ac_n "checking size of unsigned short""... $ac_c" 1>&6
-echo "configure:1379: checking size of unsigned short" >&5
+echo "configure:1459: checking size of unsigned short" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_short'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1383,7 +1463,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1387 "configure"
+#line 1467 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 #include <sys/types.h>
@@ -1395,7 +1475,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1399: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_unsigned_short=`cat conftestval`
 else
@@ -1415,7 +1495,7 @@ EOF
 
 
 echo $ac_n "checking size of unsigned char""... $ac_c" 1>&6
-echo "configure:1419: checking size of unsigned char" >&5
+echo "configure:1499: checking size of unsigned char" >&5
 if eval "test \"`echo '$''{'ac_cv_sizeof_unsigned_char'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -1423,7 +1503,7 @@ else
     { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; }
 else
   cat > conftest.$ac_ext <<EOF
-#line 1427 "configure"
+#line 1507 "configure"
 #include "confdefs.h"
 #include <stdio.h>
 #include <sys/types.h>
@@ -1435,7 +1515,7 @@ main()
   exit(0);
 }
 EOF
-if { (eval echo configure:1439: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:1519: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_sizeof_unsigned_char=`cat conftestval`
 else
@@ -1456,7 +1536,7 @@ EOF
 
 
 echo $ac_n "checking for mpz_init_set_str in -lgmp""... $ac_c" 1>&6
-echo "configure:1460: checking for mpz_init_set_str in -lgmp" >&5
+echo "configure:1540: checking for mpz_init_set_str in -lgmp" >&5
 ac_lib_var=`echo gmp'_'mpz_init_set_str | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1464,7 +1544,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lgmp  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1468 "configure"
+#line 1548 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1475,7 +1555,7 @@ int main() {
 mpz_init_set_str()
 ; return 0; }
 EOF
-if { (eval echo configure:1479: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1559: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1503,7 +1583,7 @@ else
 fi
 
 echo $ac_n "checking for mpz_init_set_str in -lgmp2""... $ac_c" 1>&6
-echo "configure:1507: checking for mpz_init_set_str in -lgmp2" >&5
+echo "configure:1587: checking for mpz_init_set_str in -lgmp2" >&5
 ac_lib_var=`echo gmp2'_'mpz_init_set_str | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1511,7 +1591,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lgmp2  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1515 "configure"
+#line 1595 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1522,7 +1602,7 @@ int main() {
 mpz_init_set_str()
 ; return 0; }
 EOF
-if { (eval echo configure:1526: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1606: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1550,7 +1630,7 @@ else
 fi
 
 echo $ac_n "checking for __gmpz_init_set_str in -lgmp""... $ac_c" 1>&6
-echo "configure:1554: checking for __gmpz_init_set_str in -lgmp" >&5
+echo "configure:1634: checking for __gmpz_init_set_str in -lgmp" >&5
 ac_lib_var=`echo gmp'_'__gmpz_init_set_str | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1558,7 +1638,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lgmp  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1562 "configure"
+#line 1642 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1569,7 +1649,7 @@ int main() {
 __gmpz_init_set_str()
 ; return 0; }
 EOF
-if { (eval echo configure:1573: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1653: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1597,7 +1677,7 @@ else
 fi
 
 echo $ac_n "checking for yywrap in -lfl""... $ac_c" 1>&6
-echo "configure:1601: checking for yywrap in -lfl" >&5
+echo "configure:1681: checking for yywrap in -lfl" >&5
 ac_lib_var=`echo fl'_'yywrap | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1605,7 +1685,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lfl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1609 "configure"
+#line 1689 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1616,7 +1696,7 @@ int main() {
 yywrap()
 ; return 0; }
 EOF
-if { (eval echo configure:1620: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1700: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1644,7 +1724,7 @@ else
 fi
 
 echo $ac_n "checking for inet_ntoa in -lnsl""... $ac_c" 1>&6
-echo "configure:1648: checking for inet_ntoa in -lnsl" >&5
+echo "configure:1728: checking for inet_ntoa in -lnsl" >&5
 ac_lib_var=`echo nsl'_'inet_ntoa | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1652,7 +1732,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lnsl  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1656 "configure"
+#line 1736 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1663,7 +1743,7 @@ int main() {
 inet_ntoa()
 ; return 0; }
 EOF
-if { (eval echo configure:1667: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1747: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1691,7 +1771,7 @@ else
 fi
 
 echo $ac_n "checking for getopt_long in -lgetopt""... $ac_c" 1>&6
-echo "configure:1695: checking for getopt_long in -lgetopt" >&5
+echo "configure:1775: checking for getopt_long in -lgetopt" >&5
 ac_lib_var=`echo getopt'_'getopt_long | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1699,7 +1779,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lgetopt  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1703 "configure"
+#line 1783 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1710,7 +1790,7 @@ int main() {
 getopt_long()
 ; return 0; }
 EOF
-if { (eval echo configure:1714: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1794: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1738,7 +1818,7 @@ else
 fi
 
 echo $ac_n "checking for getopt_long in -lgnugetopt""... $ac_c" 1>&6
-echo "configure:1742: checking for getopt_long in -lgnugetopt" >&5
+echo "configure:1822: checking for getopt_long in -lgnugetopt" >&5
 ac_lib_var=`echo gnugetopt'_'getopt_long | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1746,7 +1826,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lgnugetopt  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1750 "configure"
+#line 1830 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1757,7 +1837,7 @@ int main() {
 getopt_long()
 ; return 0; }
 EOF
-if { (eval echo configure:1761: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1841: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1785,7 +1865,7 @@ else
 fi
 
 echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
-echo "configure:1789: checking for socket in -lsocket" >&5
+echo "configure:1869: checking for socket in -lsocket" >&5
 ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1793,7 +1873,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lsocket  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1797 "configure"
+#line 1877 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1804,7 +1884,7 @@ int main() {
 socket()
 ; return 0; }
 EOF
-if { (eval echo configure:1808: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1888: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1832,7 +1912,7 @@ else
 fi
 
 echo $ac_n "checking for inet_aton in -lresolv""... $ac_c" 1>&6
-echo "configure:1836: checking for inet_aton in -lresolv" >&5
+echo "configure:1916: checking for inet_aton in -lresolv" >&5
 ac_lib_var=`echo resolv'_'inet_aton | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1840,7 +1920,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-lresolv  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1844 "configure"
+#line 1924 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1851,7 +1931,7 @@ int main() {
 inet_aton()
 ; return 0; }
 EOF
-if { (eval echo configure:1855: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1879,7 +1959,7 @@ else
 fi
 
 echo $ac_n "checking for adns_init in -ladns""... $ac_c" 1>&6
-echo "configure:1883: checking for adns_init in -ladns" >&5
+echo "configure:1963: checking for adns_init in -ladns" >&5
 ac_lib_var=`echo adns'_'adns_init | sed 'y%./+-%__p_%'`
 if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
@@ -1887,7 +1967,7 @@ else
   ac_save_LIBS="$LIBS"
 LIBS="-ladns  $LIBS"
 cat > conftest.$ac_ext <<EOF
-#line 1891 "configure"
+#line 1971 "configure"
 #include "confdefs.h"
 /* Override any gcc2 internal prototype to avoid an error.  */
 /* We use char because int might match the return type of a gcc2
@@ -1898,7 +1978,7 @@ int main() {
 adns_init()
 ; return 0; }
 EOF
-if { (eval echo configure:1902: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1982: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_lib_$ac_lib_var=yes"
 else
@@ -1930,12 +2010,12 @@ fi
 for ac_func in getopt_long 
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1934: checking for $ac_func" >&5
+echo "configure:2014: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1939 "configure"
+#line 2019 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -1958,7 +2038,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:1962: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2042: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -1986,12 +2066,12 @@ done
 for ac_func in snprintf 
 do
 echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1990: checking for $ac_func" >&5
+echo "configure:2070: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 1995 "configure"
+#line 2075 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2014,7 +2094,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:2018: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2098: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2042,19 +2122,19 @@ done
 # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
 # for constant arguments.  Useless!
 echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
-echo "configure:2046: checking for working alloca.h" >&5
+echo "configure:2126: checking for working alloca.h" >&5
 if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2051 "configure"
+#line 2131 "configure"
 #include "confdefs.h"
 #include <alloca.h>
 int main() {
 char *p = alloca(2 * sizeof(int));
 ; return 0; }
 EOF
-if { (eval echo configure:2058: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2138: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_header_alloca_h=yes
 else
@@ -2075,12 +2155,12 @@ EOF
 fi
 
 echo $ac_n "checking for alloca""... $ac_c" 1>&6
-echo "configure:2079: checking for alloca" >&5
+echo "configure:2159: checking for alloca" >&5
 if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2084 "configure"
+#line 2164 "configure"
 #include "confdefs.h"
 
 #ifdef __GNUC__
@@ -2108,7 +2188,7 @@ int main() {
 char *p = (char *) alloca(1);
 ; return 0; }
 EOF
-if { (eval echo configure:2112: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2192: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   ac_cv_func_alloca_works=yes
 else
@@ -2140,12 +2220,12 @@ EOF
 
 
 echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
-echo "configure:2144: checking whether alloca needs Cray hooks" >&5
+echo "configure:2224: checking whether alloca needs Cray hooks" >&5
 if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2149 "configure"
+#line 2229 "configure"
 #include "confdefs.h"
 #if defined(CRAY) && ! defined(CRAY2)
 webecray
@@ -2170,12 +2250,12 @@ echo "$ac_t""$ac_cv_os_cray" 1>&6
 if test $ac_cv_os_cray = yes; then
 for ac_func in _getb67 GETB67 getb67; do
   echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2174: checking for $ac_func" >&5
+echo "configure:2254: checking for $ac_func" >&5
 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
   cat > conftest.$ac_ext <<EOF
-#line 2179 "configure"
+#line 2259 "configure"
 #include "confdefs.h"
 /* System header to define __stub macros and hopefully few prototypes,
     which can conflict with char $ac_func(); below.  */
@@ -2198,7 +2278,7 @@ $ac_func();
 
 ; return 0; }
 EOF
-if { (eval echo configure:2202: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2282: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
   rm -rf conftest*
   eval "ac_cv_func_$ac_func=yes"
 else
@@ -2225,7 +2305,7 @@ done
 fi
 
 echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
-echo "configure:2229: checking stack direction for C alloca" >&5
+echo "configure:2309: checking stack direction for C alloca" >&5
 if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
   echo $ac_n "(cached) $ac_c" 1>&6
 else
@@ -2233,7 +2313,7 @@ else
   ac_cv_c_stack_direction=0
 else
   cat > conftest.$ac_ext <<EOF
-#line 2237 "configure"
+#line 2317 "configure"
 #include "confdefs.h"
 find_stack_direction ()
 {
@@ -2252,7 +2332,7 @@ main ()
   exit (find_stack_direction() < 0);
 }
 EOF
-if { (eval echo configure:2256: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2336: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
 then
   ac_cv_c_stack_direction=1
 else
index 8bc960e..cff1044 100644 (file)
@@ -3,7 +3,7 @@ dnl Process this file with autoconf to produce a configure script.
 AC_INIT(secnet.c)
 AC_CONFIG_HEADER(config.h)
 
-AC_REVISION($Id$)
+AC_REVISION($Id: configure.in,v 1.2 2001/12/06 17:36:27 steve Exp $)
 
 AC_LANG_C
 
@@ -13,7 +13,9 @@ AC_PROG_INSTALL
 AC_PATH_PROG(RM,rm)
 AC_STDC_HEADERS
 AC_CHECK_HEADERS(stdint.h inttypes.h)
+AC_CHECK_HEADERS(net/if.h net/route.h)
 AC_CHECK_HEADERS(linux/if.h)
+AC_CHECK_HEADERS(stropts.h sys/sockio.h net/if_tun.h)
 AC_C_BIGENDIAN
 AC_CHECK_SIZEOF(unsigned long long)
 AC_CHECK_SIZEOF(unsigned long)
index 9931c97..1327d12 100644 (file)
@@ -1,4 +1,4 @@
-secnet (0.1.12-1) unstable; urgency=low
+secnet (0.1.13-1) unstable; urgency=low
 
   * New upstream version.
 
diff --git a/dh.c b/dh.c
index 67ebd50..5917d39 100644 (file)
--- a/dh.c
+++ b/dh.c
@@ -1,36 +1,3 @@
-/***************************************************************************
- *
- *              Part II Project, "A secure, private IP network"
- *              Stephen Early <sde1000@cam.ac.uk>
- *   
- *
- *     $RCSfile: dh.c,v $
- *
- *  Description: Diffie-Hellman implementation
- *
- *    Copyright: (C) Stephen Early 1995
- *
- *    $Revision: 1.3 $
- *
- *        $Date: 1996/05/16 18:38:54 $
- *
- *       $State: Exp $
- *
- ***************************************************************************/
-
-/*
- * $Log: dh.c,v $
- * Revision 1.3  1996/05/16 18:38:54  sde1000
- * Removed unused hexdigits variable.
- *
- * Revision 1.2  1996/04/14 16:33:52  sde1000
- * Moved mpbin/mpstring functions into util.c
- *
- * Revision 1.1  1996/04/14 16:21:47  sde1000
- * Initial revision
- *
- */
-
 #include <stdio.h>
 #include <gmp.h>
 
index 1edc334..b941295 100644 (file)
--- a/ipaddr.c
+++ b/ipaddr.c
@@ -283,9 +283,9 @@ bool_t ipset_is_subset(struct ipset *super, struct ipset *sub)
 struct subnet_list *ipset_to_subnet_list(struct ipset *is)
 {
     struct subnet_list *r;
-    int64_t a,b;
+    int64_t a,b,lobit,himask,lomask;
+    int32_t bits;
     uint32_t i;
-    uint32_t lomask,lobit,himask,bits;
 
     r=subnet_list_new();
     for (i=0; i<is->l; i++) {
index 0cfd692..ec4e9db 100644 (file)
@@ -12,7 +12,7 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  *  GNU General Public License for more details.
  *
- *  $Id: if_tun.h,v 1.2 2001/06/01 18:39:47 davem Exp $
+ *  $Id: if_tun.h,v 1.1 2001/11/21 14:54:03 steve Exp $
  */
 
 #ifndef __IF_TUN_H
diff --git a/magic.h b/magic.h
new file mode 100644 (file)
index 0000000..5ac1e34
--- /dev/null
+++ b/magic.h
@@ -0,0 +1,17 @@
+/* Magic numbers used within secnet */
+
+#ifndef magic_h
+#define magic_h
+
+#define LABEL_MSG0 0x00020200
+#define LABEL_MSG1 0x01010101
+#define LABEL_MSG2 0x02020202
+#define LABEL_MSG3 0x03030303
+#define LABEL_MSG4 0x04040404
+#define LABEL_MSG5 0x05050505
+#define LABEL_MSG6 0x06060606
+#define LABEL_MSG7 0x07070707
+#define LABEL_MSG8 0x08080808
+#define LABEL_MSG9 0x09090909
+
+#endif /* magic_h */
index 5d6de21..682840f 100755 (executable)
@@ -58,7 +58,7 @@ sys.path.append("/usr/local/share/secnet")
 sys.path.append("/usr/share/secnet")
 import ipaddr
 
-VERSION="0.1.10"
+VERSION="0.1.13"
 
 class vpn:
        def __init__(self,name):
@@ -477,10 +477,10 @@ if service:
        f.close()
        os.rename(groupfiledir+"/T"+group,groupfiledir+"/R"+group)
        f=open(sitesfile+"-tmp",'w')
-       f.write("# sites file autogenerated by make-secnet-sites.py\n")
+       f.write("# sites file autogenerated by make-secnet-sites\n")
        f.write("# generated %s, invoked by %s\n"%
                (time.asctime(time.localtime(time.time())),user))
-       f.write("# use make-secnet-sites.py to turn this file into a\n")
+       f.write("# use make-secnet-sites to turn this file into a\n")
        f.write("# valid /etc/secnet/sites.conf file\n\n")
        for i in headerinput: f.write(i)
        files=os.listdir(groupfiledir)
index b6650eb..704dcf6 100644 (file)
--- a/netlink.c
+++ b/netlink.c
 /* User-kernel network link */
 
-/* Each netlink device is actually a router, with its own IP address.
-   We do things like decreasing the TTL and recalculating the header
-   checksum, generating ICMP, responding to pings, etc. */
+/* See RFCs 791, 792, 1123 and 1812 */
 
-/* This is where we have the anti-spoofing paranoia - before sending a
-   packet to the kernel we check that the tunnel it came over could
-   reasonably have produced it. */
+/* The netlink device is actually a router.  Tunnels are unnumbered
+   point-to-point lines (RFC1812 section 2.2.7); the router has a
+   single address (the 'router-id'). */
+
+/* This is where we currently have the anti-spoofing paranoia - before
+   sending a packet to the kernel we check that the tunnel it came
+   over could reasonably have produced it. */
+
+
+/* Points to note from RFC1812 (which may require changes in this
+   file):
+
+3.3.4 Maximum Transmission Unit - MTU
+
+   The MTU of each logical interface MUST be configurable within the
+   range of legal MTUs for the interface.
+
+   Many Link Layer protocols define a maximum frame size that may be
+   sent.  In such cases, a router MUST NOT allow an MTU to be set which
+   would allow sending of frames larger than those allowed by the Link
+   Layer protocol.  However, a router SHOULD be willing to receive a
+   packet as large as the maximum frame size even if that is larger than
+   the MTU.
+
+4.2.1  A router SHOULD count datagrams discarded.
+
+4.2.2.1 Source route options - we probably should implement processing
+of source routes, even though mostly the security policy will prevent
+their use.
+
+5.3.13.4 Source Route Options
+
+   A router MUST implement support for source route options in forwarded
+   packets.  A router MAY implement a configuration option that, when
+   enabled, causes all source-routed packets to be discarded.  However,
+   such an option MUST NOT be enabled by default.
+
+5.3.13.5 Record Route Option
+
+   Routers MUST support the Record Route option in forwarded packets.
+
+   A router MAY provide a configuration option that, if enabled, will
+   cause the router to ignore (i.e., pass through unchanged) Record
+   Route options in forwarded packets.  If provided, such an option MUST
+   default to enabling the record-route.  This option should not affect
+   the processing of Record Route options in datagrams received by the
+   router itself (in particular, Record Route options in ICMP echo
+   requests will still be processed according to Section [4.3.3.6]).
+
+5.3.13.6 Timestamp Option
+
+   Routers MUST support the timestamp option in forwarded packets.  A
+   timestamp value MUST follow the rules given [INTRO:2].
+
+   If the flags field = 3 (timestamp and prespecified address), the
+   router MUST add its timestamp if the next prespecified address
+   matches any of the router's IP addresses.  It is not necessary that
+   the prespecified address be either the address of the interface on
+   which the packet arrived or the address of the interface over which
+   it will be sent.
+
+
+4.2.2.7 Fragmentation: RFC 791 Section 3.2
+
+   Fragmentation, as described in [INTERNET:1], MUST be supported by a
+   router.
+
+4.2.2.8 Reassembly: RFC 791 Section 3.2
+
+   As specified in the corresponding section of [INTRO:2], a router MUST
+   support reassembly of datagrams that it delivers to itself.
+
+4.2.2.9 Time to Live: RFC 791 Section 3.2
+
+   Note in particular that a router MUST NOT check the TTL of a packet
+   except when forwarding it.
+
+   A router MUST NOT discard a datagram just because it was received
+   with TTL equal to zero or one; if it is to the router and otherwise
+   valid, the router MUST attempt to receive it.
+
+   On messages the router originates, the IP layer MUST provide a means
+   for the transport layer to set the TTL field of every datagram that
+   is sent.  When a fixed TTL value is used, it MUST be configurable.
+
+
+8.1 The Simple Network Management Protocol - SNMP
+8.1.1 SNMP Protocol Elements
+
+   Routers MUST be manageable by SNMP [MGT:3].  The SNMP MUST operate
+   using UDP/IP as its transport and network protocols.
+
+
+*/
 
 #include "secnet.h"
 #include "util.h"
 #define OPT_SOFTROUTE   1
 #define OPT_ALLOWROUTE  2
 
+#define ICMP_TYPE_ECHO_REPLY             0
+
+#define ICMP_TYPE_UNREACHABLE            3
+#define ICMP_CODE_NET_UNREACHABLE        0
+#define ICMP_CODE_PROTOCOL_UNREACHABLE   2
+#define ICMP_CODE_FRAGMENTATION_REQUIRED 4
+#define ICMP_CODE_NET_PROHIBITED        13
+
+#define ICMP_TYPE_ECHO_REQUEST           8
+
+#define ICMP_TYPE_TIME_EXCEEDED         11
+#define ICMP_CODE_TTL_EXCEEDED           0
+
 /* Generic IP checksum routine */
 static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
 {
@@ -122,6 +224,13 @@ static void netlink_packet_deliver(struct netlink *st,
                                   struct netlink_client *client,
                                   struct buffer_if *buf);
 
+/* XXX RFC1812 4.3.2.5:
+   All other ICMP error messages (Destination Unreachable,
+   Redirect, Time Exceeded, and Parameter Problem) SHOULD have their
+   precedence value set to 6 (INTERNETWORK CONTROL) or 7 (NETWORK
+   CONTROL).  The IP Precedence value for these error messages MAY be
+   settable.
+   */
 static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
                                         uint32_t dest,uint16_t len)
 {
@@ -137,7 +246,7 @@ static struct icmphdr *netlink_icmp_tmpl(struct netlink *st,
     h->iph.tot_len=htons(len+(h->iph.ihl*4)+8);
     h->iph.id=0;
     h->iph.frag_off=0;
-    h->iph.ttl=255;
+    h->iph.ttl=255; /* XXX should be configurable */
     h->iph.protocol=1;
     h->iph.saddr=htonl(st->secnet_address);
     h->iph.daddr=htonl(dest);
@@ -206,6 +315,26 @@ static bool_t netlink_icmp_may_reply(struct buffer_if *buf)
 
 /* How much of the original IP packet do we include in its ICMP
    response? The header plus up to 64 bits. */
+
+/* XXX TODO RFC1812:
+4.3.2.3 Original Message Header
+
+   Historically, every ICMP error message has included the Internet
+   header and at least the first 8 data bytes of the datagram that
+   triggered the error.  This is no longer adequate, due to the use of
+   IP-in-IP tunneling and other technologies.  Therefore, the ICMP
+   datagram SHOULD contain as much of the original datagram as possible
+   without the length of the ICMP datagram exceeding 576 bytes.  The
+   returned IP header (and user data) MUST be identical to that which
+   was received, except that the router is not required to undo any
+   modifications to the IP header that are normally performed in
+   forwarding that were performed before the error was detected (e.g.,
+   decrementing the TTL, or updating options).  Note that the
+   requirements of Section [4.3.3.5] supersede this requirement in some
+   cases (i.e., for a Parameter Problem message, if the problem is in a
+   modified field, the router must undo the modification).  See Section
+   [4.3.3.5]).
+   */
 static uint16_t netlink_icmp_reply_len(struct buffer_if *buf)
 {
     struct iphdr *iph=(struct iphdr *)buf->start;
@@ -242,6 +371,7 @@ static void netlink_icmp_simple(struct netlink *st, struct buffer_if *buf,
 /*
  * RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the
  * checksum.
+ * RFC1812: 4.2.2.5 MUST discard messages containing invalid checksums.
  *
  * Is the datagram acceptable?
  *
@@ -344,10 +474,11 @@ static void netlink_packet_deliver(struct netlink *st,
            string_t s,d;
            s=ipaddr_to_string(source);
            d=ipaddr_to_string(dest);
-           Message(M_ERR,"%s: don't know where to deliver packet "
+           Message(M_DEBUG,"%s: don't know where to deliver packet "
                    "(s=%s, d=%s)\n", st->name, s, d);
            free(s); free(d);
-           netlink_icmp_simple(st,buf,client,3,0);
+           netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
+                               ICMP_CODE_NET_UNREACHABLE);
            BUF_FREE(buf);
        }
     } else {
@@ -363,7 +494,8 @@ static void netlink_packet_deliver(struct netlink *st,
                    st->name,s,d);
            free(s); free(d);
                    
-           netlink_icmp_simple(st,buf,client,3,9);
+           netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
+                               ICMP_CODE_NET_PROHIBITED);
            BUF_FREE(buf);
        }
        if (best_quality>0) {
@@ -374,7 +506,8 @@ static void netlink_packet_deliver(struct netlink *st,
            BUF_ASSERT_FREE(buf);
        } else {
            /* Generate ICMP destination unreachable */
-           netlink_icmp_simple(st,buf,client,3,0); /* client==NULL */
+           netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
+                               ICMP_CODE_NET_UNREACHABLE); /* client==NULL */
            BUF_FREE(buf);
        }
     }
@@ -392,7 +525,8 @@ static void netlink_packet_forward(struct netlink *st,
     /* Packet has already been checked */
     if (iph->ttl<=1) {
        /* Generate ICMP time exceeded */
-       netlink_icmp_simple(st,buf,client,11,0);
+       netlink_icmp_simple(st,buf,client,ICMP_TYPE_TIME_EXCEEDED,
+                           ICMP_CODE_TTL_EXCEEDED);
        BUF_FREE(buf);
        return;
     }
@@ -424,13 +558,13 @@ static void netlink_packet_local(struct netlink *st,
 
     if (h->iph.protocol==1) {
        /* It's ICMP */
-       if (h->type==8 && h->code==0) {
+       if (h->type==ICMP_TYPE_ECHO_REQUEST && h->code==0) {
            /* ICMP echo-request. Special case: we re-use the buffer
               to construct the reply. */
-           h->type=0;
+           h->type=ICMP_TYPE_ECHO_REPLY;
            h->iph.daddr=h->iph.saddr;
            h->iph.saddr=htonl(st->secnet_address);
-           h->iph.ttl=255; /* Be nice and bump it up again... */
+           h->iph.ttl=255;
            h->iph.check=0;
            h->iph.check=ip_fast_csum((uint8_t *)h,h->iph.ihl);
            netlink_icmp_csum(h);
@@ -440,7 +574,8 @@ static void netlink_packet_local(struct netlink *st,
        Message(M_WARNING,"%s: unknown incoming ICMP\n",st->name);
     } else {
        /* Send ICMP protocol unreachable */
-       netlink_icmp_simple(st,buf,client,3,2);
+       netlink_icmp_simple(st,buf,client,ICMP_TYPE_UNREACHABLE,
+                           ICMP_CODE_PROTOCOL_UNREACHABLE);
        BUF_FREE(buf);
        return;
     }
@@ -584,11 +719,13 @@ static void netlink_dump_routes(struct netlink *st, bool_t requested)
        Message(c,"%s: routing table:\n",st->name);
        for (i=0; i<st->n_clients; i++) {
            netlink_output_subnets(st,c,st->routes[i]->subnets);
-           Message(c,"-> tunnel %s (%s,%s routes,%s,quality %d,use %d)\n",
+           Message(c,"-> tunnel %s (%s,mtu %d,%s routes,%s,"
+                   "quality %d,use %d)\n",
                    st->routes[i]->name,
+                   st->routes[i]->up?"up":"down",
+                   st->routes[i]->mtu,
                    st->routes[i]->options&OPT_SOFTROUTE?"soft":"hard",
                    st->routes[i]->options&OPT_ALLOWROUTE?"free":"restricted",
-                   st->routes[i]->up?"up":"down",
                    st->routes[i]->link_quality,
                    st->routes[i]->outcount);
        }
index 8e464be..0c6d443 100644 (file)
--- a/process.c
+++ b/process.c
@@ -234,11 +234,21 @@ static void set_default_signals(void)
 
 static void signal_handler(int signum)
 {
+    int saved_errno;
     uint8_t thing=0;
     sigaddset(&pending,signum);
+    /* XXX the write() may set errno, which can make the main program fail.
+       However, signal handlers aren't allowed to modify anything which
+       is not of type sig_atomic_t.  The world is broken. */
+    /* I have decided to save and restore errno anyway; on most
+       architectures on which secnet can run modifications to errno
+       will be atomic, and it seems to be the lesser of the two
+       evils. */
+    saved_errno=errno;
     write(spw,&thing,1); /* We don't care if this fails (i.e. the pipe
                            is full) because the service routine will
                            spot the pending signal anyway */
+    errno=saved_errno;
 }
 
 static void register_signal_handler(struct signotify *s)
index c481527..3fc2314 100644 (file)
--- a/random.c
+++ b/random.c
@@ -1,6 +1,3 @@
-/* $Log$
- */
-
 #include "secnet.h"
 #include <stdio.h>
 #include <fcntl.h>
diff --git a/rsa.c b/rsa.c
index 81fb1b5..2b4c729 100644 (file)
--- a/rsa.c
+++ b/rsa.c
@@ -1,29 +1,3 @@
-/***************************************************************************
- *
- *              Part II Project, "A secure, private IP network"
- *              Stephen Early <sde1000@cam.ac.uk>
- *   
- *
- *     $RCSfile: rsa.c,v $
- *
- *  Description: RSA signature making and checking functions
- *
- *    Copyright: (C) Stephen Early 1995
- *
- *    $Revision: 1.1 $
- *
- *        $Date: 1996/05/16 18:40:14 $
- *
- *       $State: Exp $
- *
- ***************************************************************************/
-
-/* $Log: rsa.c,v $
- * Revision 1.1  1996/05/16 18:40:14  sde1000
- * Initial revision
- *
- */
-
 #include <stdio.h>
 #include <gmp.h>
 #include "secnet.h"
index 39a635a..8987af3 100644 (file)
--- a/secnet.c
+++ b/secnet.c
@@ -1,9 +1,3 @@
-/* $Log: secnet.c,v $
- * Revision 1.1  1996/03/13 22:27:41  sde1000
- * Initial revision
- *
- */
-
 extern char version[];
 
 #include "secnet.h"
@@ -357,10 +351,14 @@ static void droppriv(void)
            /* Child process - all done, just carry on */
            if (pf) fclose(pf);
            /* Close stdin, stdout and stderr; we don't need them any more */
+           /* XXX we must leave stderr pointing to something useful -
+               a pipe to a log destination, for example, or just leave
+               it alone. */
            close(0);
            close(1);
-           close(2);
+           /* XXX close(2); */
            secnet_is_daemon=True;
+           setsid();
        } else {
            /* Error */
            fatal_perror("cannot fork");
index 7cdeeda..7eed367 100644 (file)
--- a/secnet.h
+++ b/secnet.h
@@ -59,6 +59,8 @@ struct item {
     struct cloc loc;
 };
 
+/* Note that it is unwise to use this structure directly; use the list
+   manipulation functions instead. */
 struct list {
     item_t *item;
     struct list *next;
@@ -185,12 +187,10 @@ bool_t remove_hook(uint32_t phase, hook_fn *f, void *state);
 extern uint32_t current_phase;
 extern void enter_phase(uint32_t new_phase);
 
-extern bool_t require_root_privileges; /* Some features (like netlink
-                                         'soft' routes) require that
-                                         secnet retain root
-                                         privileges.  They should
-                                         indicate that here when
-                                         appropriate. */
+/* Some features (like netlink 'soft' routes) require that secnet
+   retain root privileges.  They should indicate that here when
+   appropriate. */
+extern bool_t require_root_privileges;
 extern string_t require_root_privileges_explanation;
 
 /***** END of program lifetime support *****/
@@ -231,6 +231,7 @@ struct buffer_if;
    type. 'address' will be NULL if there was a problem with the query. It
    will be freed once resolve_answer_fn returns. It is in network byte
    order. */
+/* XXX extend to be able to provide multiple answers */
 typedef void resolve_answer_fn(void *st, struct in_addr *addr);
 typedef bool_t resolve_request_fn(void *st, string_t name,
                                  resolve_answer_fn *cb, void *cst);
@@ -281,6 +282,8 @@ typedef bool_t comm_sendmsg_fn(void *commst, struct buffer_if *buf,
                               struct sockaddr_in *dest);
 struct comm_if {
     void *st;
+    uint32_t min_start_pad;
+    uint32_t min_end_pad;
     comm_request_notify_fn *request_notify;
     comm_release_notify_fn *release_notify;
     comm_sendmsg_fn *sendmsg;
diff --git a/site.c b/site.c
index cb0e0aa..2b51a5d 100644 (file)
--- a/site.c
+++ b/site.c
@@ -9,15 +9,19 @@
    (and that ought not to be too hard, eg. using the TUN/TAP device to
    pretend to be an Ethernet interface).  */
 
+/* At some point in the future the netlink code will be asked for
+   configuration information to go in the PING/PONG packets at the end
+   of the key exchange. */
+
 #include "secnet.h"
 #include <stdio.h>
 #include <string.h>
-/* MBM asserts the next one is needed for compilation under BSD. */
 #include <sys/socket.h>
 
 #include <sys/mman.h>
 #include "util.h"
 #include "unaligned.h"
+#include "magic.h"
 
 #define SETUP_BUFFER_LEN 2048
 
@@ -90,17 +94,6 @@ static string_t state_name(uint32_t state)
     }
 }
 
-#define LABEL_MSG0 0x00020200
-#define LABEL_MSG1 0x01010101
-#define LABEL_MSG2 0x02020202
-#define LABEL_MSG3 0x03030303
-#define LABEL_MSG4 0x04040404
-#define LABEL_MSG5 0x05050505
-#define LABEL_MSG6 0x06060606
-#define LABEL_MSG7 0x07070707
-#define LABEL_MSG8 0x08080808
-#define LABEL_MSG9 0x09090909
-
 #define NONCELEN 8
 
 #define LOG_UNEXPECTED    0x00000001
@@ -125,6 +118,8 @@ static struct flagstr log_event_table[]={
     { "packet-drop", LOG_DROP },
     { "dump-packets", LOG_DUMP },
     { "errors", LOG_ERROR },
+    { "default", LOG_SETUP_INIT|LOG_SETUP_TIMEOUT|
+      LOG_ACTIVATE_KEY|LOG_TIMEOUT_KEY|LOG_SEC|LOG_ERROR },
     { "all", 0xffffffff },
     { NULL, 0 }
 };
@@ -135,9 +130,9 @@ struct site {
 /* configuration information */
     string_t localname;
     string_t remotename;
-    string_t tunname; /* localname<->remotename by default */
+    string_t tunname; /* localname<->remotename by default, used in logs */
     string_t address; /* DNS name for bootstrapping, optional */
-    int remoteport;
+    int remoteport; /* Port for bootstrapping, optional */
     struct netlink_if *netlink;
     struct comm_if *comm;
     struct resolver_if *resolver;
@@ -156,8 +151,8 @@ struct site {
     uint32_t key_renegotiate_time; /* If we see traffic (or a keepalive)
                                      after this time, initiate a new
                                      key exchange */
-
-    bool_t keepalive; /* Always keep the tunnel up */
+    bool_t keepalive; /* Send keepalives to detect peer failure (not yet
+                        implemented) */
 
     uint8_t *setupsig; /* Expected signature of incoming MSG1 packets */
     uint32_t setupsiglen; /* Allows us to discard packets quickly if
@@ -170,14 +165,22 @@ struct site {
     uint32_t state;
     uint64_t now; /* Most recently seen time */
 
+    /* The currently established session */
     uint32_t remote_session_id;
     struct transform_inst_if *current_transform;
     bool_t current_valid;
     uint64_t current_key_timeout; /* End of life of current key */
+    uint64_t renegotiate_key_time; /* When we can negotiate a new key */
     struct sockaddr_in peer; /* Current address of peer */
     bool_t peer_valid; /* Peer address becomes invalid when key times out,
                          but only if we have a DNS name for our peer */
 
+    /* The current key setup protocol exchange.  We can only be
+       involved in one of these at a time.  There's a potential for
+       denial of service here (the attacker keeps sending a setup
+       packet; we keep trying to continue the exchange, and have to
+       timeout before we can listen for another setup packet); perhaps
+       we should keep a list of 'bad' sources for setup packets. */
     uint32_t setup_session_id;
     struct sockaddr_in setup_peer;
     uint8_t localN[NONCELEN]; /* Nonces for key exchange */
@@ -187,7 +190,6 @@ struct site {
     uint64_t timeout; /* Timeout for current state */
     uint8_t *dhsecret;
     uint8_t *sharedsecret;
-
     struct transform_inst_if *new_transform; /* For key setup/verify */
 };
 
@@ -225,11 +227,7 @@ static void delete_key(struct site *st, string_t reason, uint32_t loglevel);
 static bool_t initiate_key_setup(struct site *st, string_t reason);
 static void enter_state_run(struct site *st);
 static bool_t enter_state_resolve(struct site *st);
-static bool_t enter_state_sentmsg1(struct site *st);
-static bool_t enter_state_sentmsg2(struct site *st);
-static bool_t enter_state_sentmsg3(struct site *st);
-static bool_t enter_state_sentmsg4(struct site *st);
-static bool_t enter_state_sentmsg5(struct site *st);
+static bool_t enter_new_state(struct site *st,uint32_t next);
 static void enter_state_wait(struct site *st);
 
 #define CHECK_AVAIL(b,l) do { if ((b)->size<(l)) return False; } while(0)
@@ -256,8 +254,8 @@ struct msg {
     uint8_t *sig;
 };
 
-/* Build any of msg1 to msg4. msg5 and msg6 are built from the inside out
-   using a transform. */
+/* Build any of msg1 to msg4. msg5 and msg6 are built from the inside
+   out using a transform of config data supplied by netlink */
 static bool_t generate_msg(struct site *st, uint32_t type, string_t what)
 {
     void *hst;
@@ -331,6 +329,36 @@ static bool_t unpick_msg(struct site *st, uint32_t type,
     return True;
 }
 
+static bool_t check_msg(struct site *st, uint32_t type, struct msg *m,
+                       string_t *error)
+{
+    if (type==LABEL_MSG1) return True;
+
+    /* Check that the site names and our nonce have been sent
+       back correctly, and then store our peer's nonce. */ 
+    if (memcmp(m->remote,st->remotename,strlen(st->remotename)!=0)) {
+       *error="wrong remote site name";
+       return False;
+    }
+    if (memcmp(m->local,st->localname,strlen(st->localname)!=0)) {
+       *error="wrong local site name";
+       return False;
+    }
+    if (memcmp(m->nL,st->localN,NONCELEN)!=0) {
+       *error="wrong locally-generated nonce";
+       return False;
+    }
+    if (type==LABEL_MSG2) return True;
+    if (memcmp(m->nR,st->remoteN,NONCELEN)!=0) {
+       *error="wrong remotely-generated nonce";
+       return False;
+    }
+    if (type==LABEL_MSG3) return True;
+    if (type==LABEL_MSG4) return True;
+    *error="unknown message type";
+    return False;
+}
+
 static bool_t generate_msg1(struct site *st)
 {
     st->random->generate(st->random->st,NONCELEN,st->localN);
@@ -348,9 +376,7 @@ static bool_t process_msg1(struct site *st, struct buffer_if *msg1,
 
     if (!unpick_msg(st,LABEL_MSG1,msg1,&m)) return False;
 
-    /* XXX save src as our peer address here? */
     st->setup_peer=*src;
-
     st->setup_session_id=m.source;
     memcpy(st->remoteN,m.nR,NONCELEN);
     return True;
@@ -366,21 +392,11 @@ static bool_t process_msg2(struct site *st, struct buffer_if *msg2,
                           struct sockaddr_in *src)
 {
     struct msg m;
+    string_t err;
 
     if (!unpick_msg(st,LABEL_MSG2,msg2,&m)) return False;
-
-    /* Check that the site names and our nonce have been sent
-       back correctly, and then store our peer's nonce. */ 
-    if (memcmp(m.remote,st->remotename,strlen(st->remotename)!=0)) {
-       slog(st,LOG_SEC,"msg2: bad B (remote site name)");
-       return False;
-    }
-    if (memcmp(m.local,st->localname,strlen(st->localname)!=0)) {
-       slog(st,LOG_SEC,"msg2: bad A (local site name)");
-       return False;
-    }
-    if (memcmp(m.nL,st->localN,NONCELEN)!=0) {
-       slog(st,LOG_SEC,"msg2: bad nA (locally generated nonce)");
+    if (!check_msg(st,LABEL_MSG2,&m,&err)) {
+       slog(st,LOG_SEC,"msg2: %s",err);
        return False;
     }
     st->setup_session_id=m.source;
@@ -402,28 +418,14 @@ static bool_t process_msg3(struct site *st, struct buffer_if *msg3,
     struct msg m;
     uint8_t *hash=alloca(st->hash->len);
     void *hst;
+    string_t err;
 
     if (!unpick_msg(st,LABEL_MSG3,msg3,&m)) return False;
-
-    /* Check that the site names and nonces have been sent back
-       correctly */
-    if (memcmp(m.remote,st->remotename,strlen(st->remotename)!=0)) {
-       slog(st,LOG_SEC,"msg3: bad A (remote site name)");
-       return False;
-    }
-    if (memcmp(m.local,st->localname,strlen(st->localname)!=0)) {
-       slog(st,LOG_SEC,"msg3: bad B (local site name)");
-       return False;
-    }
-    if (memcmp(m.nR,st->remoteN,NONCELEN)!=0) {
-       slog(st,LOG_SEC,"msg3: bad nA (remotely generated nonce)");
-       return False;
-    }
-    if (memcmp(m.nL,st->localN,NONCELEN)!=0) {
-       slog(st,LOG_SEC,"msg3: bad nB (locally generated nonce)");
+    if (!check_msg(st,LABEL_MSG3,&m,&err)) {
+       slog(st,LOG_SEC,"msg3: %s",err);
        return False;
     }
-    
+
     /* Check signature and store g^x mod m */
     hst=st->hash->init();
     st->hash->update(hst,m.hashstart,m.hashlen);
@@ -464,25 +466,11 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
     struct msg m;
     uint8_t *hash=alloca(st->hash->len);
     void *hst;
+    string_t err;
 
     if (!unpick_msg(st,LABEL_MSG4,msg4,&m)) return False;
-
-    /* Check that the site names and nonces have been sent back
-       correctly */
-    if (memcmp(m.remote,st->remotename,strlen(st->remotename)!=0)) {
-       slog(st,LOG_SEC,"msg4: bad B (remote site name)");
-       return False;
-    }
-    if (memcmp(m.local,st->localname,strlen(st->localname)!=0)) {
-       slog(st,LOG_SEC,"msg4: bad A (local site name)");
-       return False;
-    }
-    if (memcmp(m.nR,st->remoteN,NONCELEN)!=0) {
-       slog(st,LOG_SEC,"msg4: bad nB (remotely generated nonce)");
-       return False;
-    }
-    if (memcmp(m.nL,st->localN,NONCELEN)!=0) {
-       slog(st,LOG_SEC,"msg4: bad nA (locally generated nonce)");
+    if (!check_msg(st,LABEL_MSG4,&m,&err)) {
+       slog(st,LOG_SEC,"msg4: %s",err);
        return False;
     }
     
@@ -509,27 +497,6 @@ static bool_t process_msg4(struct site *st, struct buffer_if *msg4,
     return True;
 }
 
-static bool_t generate_msg5(struct site *st)
-{
-    string_t transform_err;
-
-    BUF_ALLOC(&st->buffer,"site:MSG5");
-    /* We are going to add three words to the transformed message */
-    buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
-    buf_append_uint32(&st->buffer,LABEL_MSG5);
-    /* Give the netlink code an opportunity to put its own stuff in the
-       message (configuration information, etc.) */
-    st->netlink->output_config(st->netlink->st,&st->buffer);
-    st->new_transform->forwards(st->new_transform->st,&st->buffer,
-                               &transform_err);
-    buf_prepend_uint32(&st->buffer,LABEL_MSG5);
-    buf_prepend_uint32(&st->buffer,(uint32_t)st);
-    buf_prepend_uint32(&st->buffer,st->setup_session_id);
-
-    st->retries=st->setup_retries;
-    return True;
-}
-
 struct msg0 {
     uint32_t dest;
     uint32_t source;
@@ -549,6 +516,27 @@ static bool_t unpick_msg0(struct site *st, struct buffer_if *msg0,
     /* Leaves transformed part of buffer untouched */
 }
 
+static bool_t generate_msg5(struct site *st)
+{
+    string_t transform_err;
+
+    BUF_ALLOC(&st->buffer,"site:MSG5");
+    /* We are going to add four words to the message */
+    buffer_init(&st->buffer,st->transform->max_start_pad+(4*4));
+    /* Give the netlink code an opportunity to put its own stuff in the
+       message (configuration information, etc.) */
+    st->netlink->output_config(st->netlink->st,&st->buffer);
+    buf_prepend_uint32(&st->buffer,LABEL_MSG5);
+    st->new_transform->forwards(st->new_transform->st,&st->buffer,
+                               &transform_err);
+    buf_prepend_uint32(&st->buffer,LABEL_MSG5);
+    buf_prepend_uint32(&st->buffer,(uint32_t)st);
+    buf_prepend_uint32(&st->buffer,st->setup_session_id);
+
+    st->retries=st->setup_retries;
+    return True;
+}
+
 static bool_t process_msg5(struct site *st, struct buffer_if *msg5,
                           struct sockaddr_in *src)
 {
@@ -566,7 +554,7 @@ static bool_t process_msg5(struct site *st, struct buffer_if *msg5,
     /* Buffer should now contain untransformed PING packet data */
     CHECK_AVAIL(msg5,4);
     if (buf_unprepend_uint32(msg5)!=LABEL_MSG5) {
-       slog(st,LOG_SEC,"MSG5/PING packet contained invalid data");
+       slog(st,LOG_SEC,"MSG5/PING packet contained wrong label");
        return False;
     }
     if (!st->netlink->check_config(st->netlink->st,msg5)) {
@@ -582,19 +570,19 @@ static bool_t generate_msg6(struct site *st)
     string_t transform_err;
 
     BUF_ALLOC(&st->buffer,"site:MSG6");
-    /* We are going to add three words to the transformed message */
-    buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
-    buf_append_uint32(&st->buffer,LABEL_MSG6);
+    /* We are going to add four words to the message */
+    buffer_init(&st->buffer,st->transform->max_start_pad+(4*4));
     /* Give the netlink code an opportunity to put its own stuff in the
        message (configuration information, etc.) */
     st->netlink->output_config(st->netlink->st,&st->buffer);
+    buf_prepend_uint32(&st->buffer,LABEL_MSG6);
     st->new_transform->forwards(st->new_transform->st,&st->buffer,
                                &transform_err);
     buf_prepend_uint32(&st->buffer,LABEL_MSG6);
     buf_prepend_uint32(&st->buffer,(uint32_t)st);
     buf_prepend_uint32(&st->buffer,st->setup_session_id);
 
-    st->retries=1; /* Peer will retransmit MSG5 if necessary */
+    st->retries=1; /* Peer will retransmit MSG5 if this packet gets lost */
     return True;
 }
 
@@ -660,7 +648,8 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0,
        return True;
        break;
     default:
-       slog(st,LOG_SEC,"incoming message of type %08x (unknown)",type);
+       slog(st,LOG_SEC,"incoming encrypted message of type %08x "
+            "(unknown)",type);
        break;
     }
     return False;
@@ -713,7 +702,7 @@ static void site_resolve_callback(void *sst, struct in_addr *address)
        st->setup_peer.sin_family=AF_INET;
        st->setup_peer.sin_port=htons(st->remoteport);
        st->setup_peer.sin_addr=*address;
-       enter_state_sentmsg1(st);
+       enter_new_state(st,SITE_SENTMSG1);
     } else {
        /* Resolution failed */
        slog(st,LOG_ERROR,"resolution of %s failed",st->address);
@@ -731,8 +720,9 @@ static bool_t initiate_key_setup(struct site *st,string_t reason)
     } else if (st->peer_valid) {
        slog(st,LOG_SETUP_INIT,"using old peer address");
        st->setup_peer=st->peer;
-       return enter_state_sentmsg1(st);
+       return enter_new_state(st,SITE_SENTMSG1);
     }
+    slog(st,LOG_SETUP_INIT,"key exchange failed: no address for peer");
     return False;
 }
 
@@ -740,6 +730,8 @@ static void activate_new_key(struct site *st)
 {
     struct transform_inst_if *t;
 
+    /* We have two transform instances, which we swap between active
+       and setup */
     t=st->current_transform;
     st->current_transform=st->new_transform;
     st->new_transform=t;
@@ -748,6 +740,7 @@ static void activate_new_key(struct site *st)
     st->timeout=0;
     st->current_valid=True;
     st->current_key_timeout=st->now+st->key_lifetime;
+    st->renegotiate_key_time=st->now+st->key_renegotiate_time;
     st->peer=st->setup_peer;
     st->peer_valid=True;
     st->remote_session_id=st->setup_session_id;
@@ -804,8 +797,14 @@ static void enter_state_run(struct site *st)
     st->state=SITE_RUN;
     st->timeout=0;
 
+    st->setup_session_id=0;
+    memset(&st->setup_peer,0,sizeof(st->setup_peer));
+    memset(st->localN,0,NONCELEN);
+    memset(st->remoteN,0,NONCELEN);
+    st->new_transform->delkey(st->new_transform->st);
+    memset(st->dhsecret,0,st->dh->len);
+    memset(st->sharedsecret,0,st->transform->keylen);
     set_link_quality(st);
-    /* XXX get rid of key setup data */
 }
 
 static bool_t enter_state_resolve(struct site *st)
@@ -818,100 +817,64 @@ static bool_t enter_state_resolve(struct site *st)
     return True;
 }
 
-static bool_t enter_state_sentmsg1(struct site *st)
-{
-    state_assert(st,st->state==SITE_RUN || st->state==SITE_RESOLVE);
-    slog(st,LOG_STATE,"entering state SENTMSG1");
-    if (generate_msg1(st) && send_msg(st)) {
-       st->state=SITE_SENTMSG1;
-       return True;
-    }
-    slog(st,LOG_ERROR,"error entering state SENTMSG1");
-    st->buffer.free=False; /* Can't tell which it was, but enter_state_wait()
-                             will do a BUF_FREE() */
-    enter_state_wait(st);
-    return False;
-}
-
-static bool_t enter_state_sentmsg2(struct site *st)
-{
-    state_assert(st,st->state==SITE_RUN || st->state==SITE_RESOLVE ||
-                st->state==SITE_SENTMSG1 || st->state==SITE_WAIT);
-    slog(st,LOG_STATE,"entering state SENTMSG2");
-    if (generate_msg2(st) && send_msg(st)) {
-       st->state=SITE_SENTMSG2;
-       return True;
-    }
-    slog(st,LOG_ERROR,"error entering state SENTMSG2");
-    st->buffer.free=False;
-    enter_state_wait(st);
-    return False;
-}
-
-static bool_t enter_state_sentmsg3(struct site *st)
-{
-    state_assert(st,st->state==SITE_SENTMSG1);
-    slog(st,LOG_STATE,"entering state SENTMSG3");
-    BUF_FREE(&st->buffer); /* Free message 1 */
-    if (generate_msg3(st) && send_msg(st)) {
-       st->state=SITE_SENTMSG3;
-       return True;
-    }
-    slog(st,LOG_ERROR,"error entering state SENTMSG3");
-    st->buffer.free=False;
-    enter_state_wait(st);
-    return False;
-}
-
-static bool_t enter_state_sentmsg4(struct site *st)
-{
-    state_assert(st,st->state==SITE_SENTMSG2);
-    slog(st,LOG_STATE,"entering state SENTMSG4");
-    BUF_FREE(&st->buffer); /* Free message 2 */
-    if (generate_msg4(st) && send_msg(st)) {
-       st->state=SITE_SENTMSG4;
-       return True;
-    }
-    slog(st,LOG_ERROR,"error entering state SENTMSG4");
-    st->buffer.free=False;
-    enter_state_wait(st);
-    return False;
-}
-
-static bool_t enter_state_sentmsg5(struct site *st)
+static bool_t enter_new_state(struct site *st, uint32_t next)
 {
-    state_assert(st,st->state==SITE_SENTMSG3);
-    slog(st,LOG_STATE,"entering state SENTMSG5");
-    BUF_FREE(&st->buffer); /* Free message 3 */
-
-    if (generate_msg5(st) && send_msg(st)) {
-       st->state=SITE_SENTMSG5;
-       return True;
+    bool_t (*gen)(struct site *st);
+    slog(st,LOG_STATE,"entering state %s",state_name(next));
+    switch(next) {
+    case SITE_SENTMSG1:
+       state_assert(st,st->state==SITE_RUN || st->state==SITE_RESOLVE);
+       gen=generate_msg1;
+       break;
+    case SITE_SENTMSG2:
+       state_assert(st,st->state==SITE_RUN || st->state==SITE_RESOLVE ||
+                    st->state==SITE_SENTMSG1 || st->state==SITE_WAIT);
+       gen=generate_msg2;
+       break;
+    case SITE_SENTMSG3:
+       state_assert(st,st->state==SITE_SENTMSG1);
+       BUF_FREE(&st->buffer);
+       gen=generate_msg3;
+       break;
+    case SITE_SENTMSG4:
+       state_assert(st,st->state==SITE_SENTMSG2);
+       BUF_FREE(&st->buffer);
+       gen=generate_msg4;
+       break;
+    case SITE_SENTMSG5:
+       state_assert(st,st->state==SITE_SENTMSG3);
+       BUF_FREE(&st->buffer);
+       gen=generate_msg5;
+       break;
+    case SITE_RUN:
+       state_assert(st,st->state==SITE_SENTMSG4);
+       BUF_FREE(&st->buffer);
+       gen=generate_msg6;
+       break;
+    default:
+       gen=NULL;
+       fatal("enter_new_state(%s): invalid new state\n",state_name(next));
+       break;
     }
-    slog(st,LOG_ERROR,"error entering state SENTMSG5");
-    st->buffer.free=False;
-    enter_state_wait(st);
-    
-    return False;
-}
 
-static bool_t send_msg6(struct site *st)
-{
-    state_assert(st,st->state==SITE_SENTMSG4);
-    slog(st,LOG_STATE,"entering state RUN after sending msg6");
-    BUF_FREE(&st->buffer); /* Free message 4 */
-    if (generate_msg6(st) && send_msg(st)) {
-       BUF_FREE(&st->buffer); /* Never reused */
-       st->timeout=0; /* Never retransmit */
-       activate_new_key(st);
+    if (gen(st) && send_msg(st)) {
+       st->state=next;
+       if (next==SITE_RUN) {
+           BUF_FREE(&st->buffer); /* Never reused */
+           st->timeout=0; /* Never retransmit */
+           activate_new_key(st);
+       }
        return True;
     }
-    slog(st,LOG_ERROR,"error entering state RUN after sending msg6");
-    st->buffer.free=False;
+    slog(st,LOG_ERROR,"error entering state %s",state_name(next));
+    st->buffer.free=False; /* Unconditionally use the buffer; it may be
+                             in either state, and enter_state_wait() will
+                             do a BUF_FREE() */
     enter_state_wait(st);
     return False;
 }
 
+/* msg7 tells our peer that we're about to forget our key */
 static bool_t send_msg7(struct site *st,string_t reason)
 {
     string_t transform_err;
@@ -977,7 +940,6 @@ static void site_afterpoll(void *sst, struct pollfd *fds, int nfds,
 
     st->now=*now;
     if (st->timeout && *now>st->timeout) {
-       /* Do stuff */
        st->timeout=0;
        if (st->state>=SITE_SENTMSG1 && st->state<=SITE_SENTMSG5)
            send_msg(st);
@@ -1020,6 +982,9 @@ static void site_outgoing(void *sst, struct buffer_if *buf)
            st->comm->sendmsg(st->comm->st,buf,&st->peer);
        }
        BUF_FREE(buf);
+       /* See whether we should start negotiating a new key */
+       if (st->now > st->renegotiate_key_time)
+           initiate_key_setup(st,"outgoing packet in renegotiation window");
        return;
     }
 
@@ -1037,25 +1002,24 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
     uint32_t dest=ntohl(*(uint32_t *)buf->start);
 
     if (dest==0) {
-       if (buf->size<(st->setupsiglen+8+NONCELEN)) return False;
        /* It could be for any site - it should have LABEL_MSG1 and
           might have our name and our peer's name in it */
+       if (buf->size<(st->setupsiglen+8+NONCELEN)) return False;
        if (memcmp(buf->start+8,st->setupsig,st->setupsiglen)==0) {
-           dump_packet(st,buf,source,True);
            /* It's addressed to us. Decide what to do about it. */
+           dump_packet(st,buf,source,True);
            if (st->state==SITE_RUN || st->state==SITE_RESOLVE ||
                st->state==SITE_WAIT) {
                /* We should definitely process it */
                if (process_msg1(st,buf,source)) {
                    slog(st,LOG_SETUP_INIT,"key setup initiated by peer");
-                   enter_state_sentmsg2(st);
+                   enter_new_state(st,SITE_SENTMSG2);
                } else {
                    slog(st,LOG_ERROR,"failed to process incoming msg1");
                }
                BUF_FREE(buf);
                return True;
-           }
-           if (st->state==SITE_SENTMSG1) {
+           } else if (st->state==SITE_SENTMSG1) {
                /* We've just sent a message 1! They may have crossed on
                   the wire. If we have priority then we ignore the
                   incoming one, otherwise we process it as usual. */
@@ -1069,7 +1033,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
                         "priority => use incoming msg1");
                    if (process_msg1(st,buf,source)) {
                        BUF_FREE(&st->buffer); /* Free our old message 1 */
-                       enter_state_sentmsg2(st);
+                       enter_new_state(st,SITE_SENTMSG2);
                    } else {
                        slog(st,LOG_ERROR,"failed to process an incoming "
                             "crossed msg1 (we have low priority)");
@@ -1087,8 +1051,8 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
        return False; /* Not for us. */
     }
     if (dest==(uint32_t)st) {
-       uint32_t msgtype=ntohl(get_uint32(buf->start+8));
        /* Explicitly addressed to us */
+       uint32_t msgtype=ntohl(get_uint32(buf->start+8));
        if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True);
        switch (msgtype) {
        case 0: /* NAK */
@@ -1113,7 +1077,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            if (st->state!=SITE_SENTMSG1) {
                slog(st,LOG_UNEXPECTED,"unexpected MSG2");
            } else if (process_msg2(st,buf,source))
-               enter_state_sentmsg3(st);
+               enter_new_state(st,SITE_SENTMSG3);
            else {
                slog(st,LOG_SEC,"invalid MSG2");
            }
@@ -1123,7 +1087,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            if (st->state!=SITE_SENTMSG2) {
                slog(st,LOG_UNEXPECTED,"unexpected MSG3");
            } else if (process_msg3(st,buf,source))
-               enter_state_sentmsg4(st);
+               enter_new_state(st,SITE_SENTMSG4);
            else {
                slog(st,LOG_SEC,"invalid MSG3");
            }
@@ -1133,7 +1097,7 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
            if (st->state!=SITE_SENTMSG3) {
                slog(st,LOG_UNEXPECTED,"unexpected MSG4");
            } else if (process_msg4(st,buf,source))
-               enter_state_sentmsg5(st);
+               enter_new_state(st,SITE_SENTMSG5);
            else {
                slog(st,LOG_SEC,"invalid MSG4");
            }
@@ -1144,11 +1108,11 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
               and the new key has already been activated. In that
               case we should treat it as an ordinary PING packet. We
               can't pass it to process_msg5() because the
-              new_transform will now be null. XXX) */
+              new_transform will now be unkeyed. XXX) */
            if (st->state!=SITE_SENTMSG4) {
                slog(st,LOG_UNEXPECTED,"unexpected MSG5");
            } else if (process_msg5(st,buf,source)) {
-               send_msg6(st);
+               enter_new_state(st,SITE_RUN);
            } else {
                slog(st,LOG_SEC,"invalid MSG5");
            }
@@ -1262,7 +1226,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
        cfgfatal(loc,"site",
                 "renegotiate-time must be less than key-lifetime\n");
     }
-    /* XXX keepalive will eventually default to True */
     st->keepalive=dict_read_bool(dict,"keepalive",False,"site",loc,False);
 
     st->log_events=string_list_to_word(dict_lookup(dict,"log-events"),
@@ -1299,9 +1262,10 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
 
     /* We need to register the remote networks with the netlink device */
     st->netlink->reg(st->netlink->st, site_outgoing, st,
-                    st->transform->max_start_pad+(4*4),
-                    st->transform->max_end_pad);
-
+                    st->transform->max_start_pad+(4*4)+
+                    st->comm->min_start_pad,
+                    st->transform->max_end_pad+st->comm->min_end_pad);
+    
     st->comm->request_notify(st->comm->st, st, site_incoming);
 
     st->current_transform=st->transform->create(st->transform->st);
diff --git a/tun.c b/tun.c
index 74247f5..63aa1f1 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -6,13 +6,62 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
+#include <sys/utsname.h>
+#include <sys/socket.h>
 
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
 #ifdef HAVE_LINUX_IF_H
-#include <linux/if.h>
 #include <linux/if_tun.h>
+#define LINUX_TUN_SUPPORTED
 #endif
+#endif
+
+#ifdef HAVE_NET_ROUTE_H
+#include <net/route.h>
+#endif
+
+#if defined(HAVE_STROPTS_H) && defined(HAVE_SYS_SOCKIO_H) && \
+defined(HAVE_NET_IF_TUN_H)
+#define HAVE_TUN_STREAMS
+#endif
+
+#ifdef HAVE_TUN_STREAMS
+#include <stropts.h>
+#include <sys/sockio.h>
+#include <net/if_tun.h>
+#endif
+
+#define TUN_FLAVOUR_GUESS   0
+#define TUN_FLAVOUR_BSD     1
+#define TUN_FLAVOUR_LINUX   2
+#define TUN_FLAVOUR_STREAMS 3
+
+static struct flagstr flavours[]={
+    {"guess", TUN_FLAVOUR_GUESS},
+    {"bsd", TUN_FLAVOUR_BSD},
+    {"BSD", TUN_FLAVOUR_BSD},
+    {"linux", TUN_FLAVOUR_LINUX},
+    {"streams", TUN_FLAVOUR_STREAMS},
+    {"STREAMS", TUN_FLAVOUR_STREAMS},
+    {NULL, 0}
+};
 
-/* Where do we find if_tun on other platforms? */
+#define TUN_CONFIG_GUESS      0
+#define TUN_CONFIG_IOCTL      1
+#define TUN_CONFIG_BSD        2
+#define TUN_CONFIG_LINUX      3
+#define TUN_CONFIG_SOLARIS25  4
+
+static struct flagstr config_types[]={
+    {"guess", TUN_CONFIG_GUESS},
+    {"ioctl", TUN_CONFIG_IOCTL},
+    {"bsd", TUN_CONFIG_BSD},
+    {"BSD", TUN_CONFIG_BSD},
+    {"linux", TUN_CONFIG_LINUX},
+    {"solaris-2.5", TUN_CONFIG_SOLARIS25},
+    {NULL, 0}
+};
 
 /* Connection to the kernel through the universal TUN/TAP driver */
 
@@ -20,17 +69,31 @@ struct tun {
     struct netlink nl;
     int fd;
     string_t device_path;
+    string_t ip_path;
     string_t interface_name;
     string_t ifconfig_path;
+    uint32_t ifconfig_type;
     string_t route_path;
-    bool_t tun_old;
-    bool_t search_for_if; /* Applies to tun-old only */
+    uint32_t route_type;
+    uint32_t tun_flavour;
+    bool_t search_for_if; /* Applies to tun-BSD only */
     struct buffer_if *buff; /* We receive packets into here
                               and send them to the netlink code. */
     netlink_deliver_fn *netlink_to_tunnel;
     uint32_t local_address; /* host interface address */
 };
 
+static string_t tun_flavour_str(uint32_t flavour)
+{
+    switch (flavour) {
+    case TUN_FLAVOUR_GUESS: return "guess";
+    case TUN_FLAVOUR_BSD: return "BSD";
+    case TUN_FLAVOUR_LINUX: return "linux";
+    case TUN_FLAVOUR_STREAMS: return "STREAMS";
+    default: return "unknown";
+    }
+}
+
 static int tun_beforepoll(void *sst, struct pollfd *fds, int *nfds_io,
                          int *timeout_io, const struct timeval *tv_now,
                          uint64_t *now)
@@ -87,24 +150,83 @@ static bool_t tun_set_route(void *sst, struct netlink_client *routes)
     string_t network, mask, secnetaddr;
     struct subnet_list *nets;
     uint32_t i;
-
-    if (routes->up != routes->kup) {
-       nets=routes->subnets;
-       for (i=0; i<nets->entries; i++) {
-           network=ipaddr_to_string(nets->list[i].prefix);
-           mask=ipaddr_to_string(nets->list[i].mask);
-           secnetaddr=ipaddr_to_string(st->nl.secnet_address);
-           Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
-                   st->nl.name,routes->up?"adding":"deleting",network,
-                   nets->list[i].len,routes->up?"to":"from");
+    int fd=-1;
+
+    if (routes->up == routes->kup) return False;
+    if (st->route_type==TUN_CONFIG_IOCTL) {
+       if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
+           fd=open(st->ip_path,O_RDWR);
+           if (fd<0) {
+               fatal_perror("tun_set_route: can't open %s",st->ip_path);
+           }
+       } else {
+           fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+           if (fd<0) {
+               fatal_perror("tun_set_route: socket()");
+           }
+       }
+    }
+    nets=routes->subnets;
+    secnetaddr=ipaddr_to_string(st->nl.secnet_address);
+    for (i=0; i<nets->entries; i++) {
+       network=ipaddr_to_string(nets->list[i].prefix);
+       mask=ipaddr_to_string(nets->list[i].mask);
+       Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
+               st->nl.name,routes->up?"adding":"deleting",network,
+               nets->list[i].len,routes->up?"to":"from");
+       switch (st->route_type) {
+       case TUN_CONFIG_LINUX:
+           sys_cmd(st->route_path,"route",routes->up?"add":"del",
+                   "-net",network,"netmask",mask,
+                   "gw",secnetaddr,(char *)0);
+           break;
+       case TUN_CONFIG_BSD:
            sys_cmd(st->route_path,"route",routes->up?"add":"del",
-                   "-net",network,"netmask",mask,"gw",secnetaddr,(char *)0);
-           free(network); free(mask); free(secnetaddr);
+                   "-net",network,secnetaddr,mask,(char *)0);
+           break;
+       case TUN_CONFIG_SOLARIS25:
+           sys_cmd(st->route_path,"route",routes->up?"add":"del",
+                   network,secnetaddr,(char *)0);
+           break;
+       case TUN_CONFIG_IOCTL:
+       {
+#ifdef HAVE_NET_ROUTE_H
+           struct rtentry rt;
+           struct sockaddr_in *sa;
+           int action;
+           
+           memset(&rt,0,sizeof(rt));
+           sa=(struct sockaddr_in *)&rt.rt_dst;
+           sa->sin_family=AF_INET;
+           sa->sin_addr.s_addr=htonl(nets->list[i].prefix);
+           sa=(struct sockaddr_in *)&rt.rt_genmask;
+           sa->sin_family=AF_INET;
+           sa->sin_addr.s_addr=htonl(nets->list[i].mask);
+           sa=(struct sockaddr_in *)&rt.rt_gateway;
+           sa->sin_family=AF_INET;
+           sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
+           rt.rt_flags=RTF_UP|RTF_GATEWAY;
+           action=routes->up?SIOCADDRT:SIOCDELRT;
+           if (ioctl(fd,action,&rt)<0) {
+               fatal_perror("tun_set_route: ioctl()");
+           }
+#else
+           fatal("tun_set_route: ioctl method not supported\n");
+#endif
        }
-       routes->kup=routes->up;
-       return True;
+       break;
+       default:
+           fatal("tun_set_route: unsupported route command type\n");
+           break;
+       }
+       free(network); free(mask);
+    }
+    free(secnetaddr);
+    if (st->route_type==TUN_CONFIG_IOCTL) {
+       close(fd);
     }
-    return False;
+    routes->kup=routes->up;
+    return True;
 }
 
 static void tun_phase_hook(void *sst, uint32_t newphase)
@@ -114,12 +236,11 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
     uint8_t mtu[6];
     struct netlink_client *r;
 
-    if (st->tun_old) {
+    if (st->tun_flavour==TUN_FLAVOUR_BSD) {
        if (st->search_for_if) {
            string_t dname;
            int i;
 
-           /* ASSERT st->interface_name */
            dname=safe_malloc(strlen(st->device_path)+4,"tun_old_apply");
            st->interface_name=safe_malloc(8,"tun_phase_hook");
        
@@ -144,8 +265,8 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
                             st->nl.name,st->device_path);
            }
        }
-    } else {
-#ifdef HAVE_LINUX_IF_H
+    } else if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
+#ifdef LINUX_TUN_SUPPORTED
        struct ifreq ifr;
 
        /* New TUN interface: open the device, then do ioctl TUNSETIFF
@@ -160,7 +281,6 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
                                                no extra headers */
        if (st->interface_name)
            strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
-       Message(M_DEBUG,"%s: about to ioctl(TUNSETIFF)...\n",st->nl.name);
        if (ioctl(st->fd,TUNSETIFF,&ifr)<0) {
            fatal_perror("%s: ioctl(TUNSETIFF)",st->nl.name);
        }
@@ -171,8 +291,41 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
                    st->interface_name);
        }
 #else
-       fatal("netlink.c:tun_phase_hook:!tun_old unexpected\n");
-#endif /* HAVE_LINUX_IF_H */
+       fatal("tun_phase_hook: TUN_FLAVOUR_LINUX unexpected\n");
+#endif /* LINUX_TUN_SUPPORTED */
+    } else if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
+#ifdef HAVE_TUN_STREAMS
+       int tun_fd, if_fd, ppa=-1, ip_fd;
+
+       if ((ip_fd=open(st->ip_path, O_RDWR)) < 0) {
+           fatal_perror("%s: can't open %s",st->nl.name,st->ip_path);
+       }
+       if ((tun_fd=open(st->device_path,O_RDWR)) < 0) {
+           fatal_perror("%s: can't open %s",st->nl.name,st->device_path);
+       }
+       if ((ppa=ioctl(tun_fd,TUNNEWPPA,ppa)) < 0) {
+           fatal_perror("%s: can't assign new interface");
+       }
+       if ((if_fd=open(st->device_path,O_RDWR)) < 0) {
+           fatal_perror("%s: can't open %s (2)",st->nl.name,st->device_path);
+       }
+       if (ioctl(if_fd,I_PUSH,"ip") < 0) {
+           fatal_perror("%s: can't push IP module",st->nl.name);
+       }
+       if (ioctl(if_fd,IF_UNITSEL,(char *)&ppa) < 0) {
+           fatal_perror("%s: can't set ppa %d",st->nl.name,ppa);
+       }
+       if (ioctl(ip_fd, I_LINK, if_fd) < 0) {
+           fatal_perror("%s: can't link TUN device to IP",st->nl.name);
+       }
+       st->interface_name=safe_malloc(10,"tun_apply");
+       sprintf(st->interface_name,"tun%d",ppa);
+       st->fd=tun_fd;
+#else
+       fatal("tun_phase_hook: TUN_FLAVOUR_STREAMS unexpected\n");
+#endif /* HAVE_TUN_STREAMS */
+    } else {
+       fatal("tun_phase_hook: unknown flavour of TUN\n");
     }
     /* All the networks we'll be using have been registered. Invoke ifconfig
        to set the TUN device's address, and route to add routes to all
@@ -183,13 +336,83 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
     snprintf(mtu,6,"%d",st->nl.mtu);
     mtu[5]=0;
 
-    /* XXX on FreeBSD the "-broadcast" and "pointopoint" must be left
-       out. It assumes a point-to-point interface if two IP addresses
-       are specified. */
-    sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
-           hostaddr,"netmask","255.255.255.255","-broadcast",
-           "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
+    switch (st->route_type) {
+    case TUN_CONFIG_LINUX:
+       sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
+               hostaddr,"netmask","255.255.255.255","-broadcast",
+               "-multicast",
+               "pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
+       break;
+    case TUN_CONFIG_BSD:
+       sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
+               hostaddr,"netmask","255.255.255.255",
+               secnetaddr,"mtu",mtu,"up",(char *)0);
+       break;
+    case TUN_CONFIG_SOLARIS25:
+       sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
+               hostaddr,secnetaddr,"mtu",mtu,"up",(char *)0);
+       break;
+    case TUN_CONFIG_IOCTL:
+#ifdef HAVE_NET_IF_H
+    {
+       int fd;
+       struct ifreq ifr;
+       struct sockaddr_in *sa;
+       fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
+
+       /* Interface address */
+       strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
+       sa=(struct sockaddr_in *)&ifr.ifr_addr;
+       memset(sa,0,sizeof(*sa));
+       sa->sin_family=AF_INET;
+       sa->sin_addr.s_addr=htonl(st->local_address);
+       if (ioctl(fd,SIOCSIFADDR, &ifr)!=0) {
+           fatal_perror("tun_apply: SIOCSIFADDR");
+       }
+#ifdef SIOCSIFNETMASK
+       /* Netmask */
+       strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
+       sa=(struct sockaddr_in *)&ifr.ifr_netmask;
+       memset(sa,0,sizeof(*sa));
+       sa->sin_family=AF_INET;
+       sa->sin_addr.s_addr=htonl(0xffffffff);
+       if (ioctl(fd,SIOCSIFNETMASK, &ifr)!=0) {
+           fatal_perror("tun_apply: SIOCSIFNETMASK");
+       }
+#endif
+       /* Destination address (point-to-point) */
+       strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
+       sa=(struct sockaddr_in *)&ifr.ifr_dstaddr;
+       memset(sa,0,sizeof(*sa));
+       sa->sin_family=AF_INET;
+       sa->sin_addr.s_addr=htonl(st->nl.secnet_address);
+       if (ioctl(fd,SIOCSIFDSTADDR, &ifr)!=0) {
+           fatal_perror("tun_apply: SIOCSIFDSTADDR");
+       }
+       /* MTU */
+       strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
+       ifr.ifr_mtu=st->nl.mtu;
+       if (ioctl(fd,SIOCSIFMTU, &ifr)!=0) {
+           fatal_perror("tun_apply: SIOCSIFMTU");
+       }
+       /* Flags */
+       strncpy(ifr.ifr_name,st->interface_name,IFNAMSIZ);
+       ifr.ifr_flags=IFF_UP|IFF_POINTOPOINT|IFF_RUNNING|IFF_NOARP;
+       if (ioctl(fd,SIOCSIFFLAGS, &ifr)!=0) {
+           fatal_perror("tun_apply: SIOCSIFFLAGS");
+       }
 
+       close(fd);
+    }
+#else
+    fatal("tun_apply: ifconfig by ioctl() not supported\n");
+#endif /* HAVE_NET_IF_H */
+    break;
+    default:
+       fatal("tun_apply: unsupported ifconfig method\n");
+       break;
+    }
+       
     for (r=st->nl.clients; r; r=r->next) {
        tun_set_route(st,r);
     }
@@ -198,13 +421,13 @@ static void tun_phase_hook(void *sst, uint32_t newphase)
     register_for_poll(st, tun_beforepoll, tun_afterpoll, 1, st->nl.name);
 }
 
-#ifdef HAVE_LINUX_IF_H
-static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
-                        list_t *args)
+static list_t *tun_create(closure_t *self, struct cloc loc, dict_t *context,
+                         list_t *args,uint32_t default_flavour)
 {
     struct tun *st;
     item_t *item;
     dict_t *dict;
+    string_t flavour,type;
 
     st=safe_malloc(sizeof(*st),"tun_apply");
 
@@ -219,90 +442,162 @@ static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
        netlink_init(&st->nl,st,loc,dict,
                     "netlink-tun",tun_set_route,tun_deliver_to_kernel);
 
-    st->tun_old=False;
+    flavour=dict_read_string(dict,"flavour",False,"tun-netlink",loc);
+    if (flavour)
+       st->tun_flavour=string_to_word(flavour,loc,flavours,"tun-flavour");
+    else
+       st->tun_flavour=default_flavour;
+
     st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
+    st->ip_path=dict_read_string(dict,"ip-path",False,"tun-netlink",loc);
     st->interface_name=dict_read_string(dict,"interface",False,
                                        "tun-netlink",loc);
-    st->ifconfig_path=dict_read_string(dict,"ifconfig-path",
-                                      False,"tun-netlink",loc);
-    st->route_path=dict_read_string(dict,"route-path",
-                                   False,"tun-netlink",loc);
+    st->search_for_if=dict_read_bool(dict,"interface-search",False,
+                                    "tun-netlink",loc,st->device_path==NULL);
+
+    type=dict_read_string(dict,"ifconfig-type",False,"tun-netlink",loc);
+    if (type) st->ifconfig_type=string_to_word(type,loc,config_types,
+                                              "ifconfig-type");
+    else st->ifconfig_type=TUN_CONFIG_GUESS;
+    st->ifconfig_path=dict_read_string(dict,"ifconfig-path",False,
+                                      "tun-netlink",loc);
+
+    type=dict_read_string(dict,"route-type",False,"tun-netlink",loc);
+    if (type) st->route_type=string_to_word(type,loc,config_types,
+                                           "route-type");
+    else st->route_type=TUN_CONFIG_GUESS;
+    st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
 
-    if (!st->device_path) st->device_path="/dev/net/tun";
-    if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
-    if (!st->route_path) st->route_path="route";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
     st->local_address=string_item_to_ipaddr(
        dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
 
-    add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
+    if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
+       /* If we haven't been told what type of TUN we're using, take
+          a guess based on the system details. */
+       struct utsname u;
+       if (uname(&u)<0) {
+           fatal_perror("tun_create: uname");
+       }
+       if (strcmp(u.sysname,"Linux")==0) {
+           if (u.release[0]=='2' && u.release[1]=='.' && u.release[3]=='.') {
+               if (u.release[2]=='2') st->tun_flavour=TUN_FLAVOUR_BSD;
+               else if (u.release[2]=='4') st->tun_flavour=TUN_FLAVOUR_LINUX;
+           }
+       } else if (strcmp(u.sysname,"SunOS")==0) {
+           st->tun_flavour=TUN_FLAVOUR_STREAMS;
+       } else if (strcmp(u.sysname,"FreeBSD")==0) {
+           st->tun_flavour=TUN_FLAVOUR_BSD;
+       }
+    }
+    if (st->tun_flavour==TUN_FLAVOUR_GUESS) {
+       cfgfatal(loc,"tun","cannot guess which type of TUN is in use; "
+                "specify the flavour explicitly\n");
+    }
 
-    return new_closure(&st->nl.cl);
-}
-#endif /* HAVE_LINUX_IF_H */
+    if (st->ifconfig_type==TUN_CONFIG_GUESS) {
+       switch (st->tun_flavour) {
+       case TUN_FLAVOUR_LINUX:
+           st->ifconfig_type=TUN_CONFIG_IOCTL;
+           break;
+       case TUN_FLAVOUR_BSD:
+           st->ifconfig_type=TUN_CONFIG_BSD;
+           break;
+       case TUN_FLAVOUR_STREAMS:
+           st->ifconfig_type=TUN_CONFIG_BSD;
+           break;
+       }
+    }
+    if (st->route_type==TUN_CONFIG_GUESS)
+       st->route_type=st->ifconfig_type;
 
-static list_t *tun_old_apply(closure_t *self, struct cloc loc, dict_t *context,
-                            list_t *args)
-{
-    struct tun *st;
-    item_t *item;
-    dict_t *dict;
+    if (st->ifconfig_type==TUN_CONFIG_GUESS) {
+       cfgfatal(loc,"tun","cannot guess which ifconfig method to use\n");
+    }
+    if (st->route_type==TUN_CONFIG_GUESS) {
+       cfgfatal(loc,"tun","cannot guess which route method to use\n");
+    }
 
-    st=safe_malloc(sizeof(*st),"tun_old_apply");
+    if (st->ifconfig_type==TUN_CONFIG_IOCTL && st->ifconfig_path) {
+       cfgfatal(loc,"tun","ifconfig-type \"ioctl\" is incompatible with "
+                "ifconfig-path\n");
+    }
+    if (st->route_type==TUN_CONFIG_IOCTL && st->route_path) {
+       cfgfatal(loc,"tun","route-type \"ioctl\" is incompatible with "
+                "route-path\n");
+    }
 
-    /* First parameter must be a dict */
-    item=list_elem(args,0);
-    if (!item || item->type!=t_dict)
-       cfgfatal(loc,"tun","parameter must be a dictionary\n");
+    Message(M_DEBUG_CONFIG,"%s: tun flavour %s\n",st->nl.name,
+           tun_flavour_str(st->tun_flavour));
+    switch (st->tun_flavour) {
+    case TUN_FLAVOUR_BSD:
+       if (!st->device_path) st->device_path="/dev/tun";
+       break;
+    case TUN_FLAVOUR_LINUX:
+       if (!st->device_path) st->device_path="/dev/net/tun";
+       break;
+    case TUN_FLAVOUR_STREAMS:
+       if (!st->device_path) st->device_path="/dev/tun";
+       if (st->interface_name) cfgfatal(loc,"tun","interface name cannot "
+                                        "be specified with STREAMS TUN\n");
+       break;
+    }
     
-    dict=item->data.dict;
-
-    st->netlink_to_tunnel=
-       netlink_init(&st->nl,st,loc,dict,
-                    "netlink-tun",tun_set_route,tun_deliver_to_kernel);
-
-    st->tun_old=True;
-    st->device_path=dict_read_string(dict,"device",False,"tun-netlink",loc);
-    st->interface_name=dict_read_string(dict,"interface",False,
-                                       "tun-netlink",loc);
-    st->search_for_if=dict_read_bool(dict,"interface-search",False,
-                                    "tun-netlink",loc,st->device_path==NULL);
-    st->ifconfig_path=dict_read_string(dict,"ifconfig-path",False,
-                                      "tun-netlink",loc);
-    st->route_path=dict_read_string(dict,"route-path",False,"tun-netlink",loc);
-
-    if (!st->device_path) st->device_path="/dev/tun";
+    if (!st->ip_path) st->ip_path="/dev/ip";
     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
     if (!st->route_path) st->route_path="route";
-    st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
-    st->local_address=string_item_to_ipaddr(
-       dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
+
+#ifndef HAVE_TUN_STREAMS
+    if (st->tun_flavour==TUN_FLAVOUR_STREAMS) {
+       cfgfatal(loc,"tun","TUN flavour STREAMS unsupported in this build "
+                "of secnet\n");
+    }
+#endif
+#ifndef LINUX_TUN_SUPPORTED
+    if (st->tun_flavour==TUN_FLAVOUR_LINUX) {
+       cfgfatal(loc,"tun","TUN flavour LINUX unsupported in this build "
+                "of secnet\n");
+    }
+#endif
 
     /* Old TUN interface: the network interface name depends on which
        /dev/tunX file we open. If 'interface-search' is set to true, treat
        'device' as the prefix and try numbers from 0--255. If it's set
        to false, treat 'device' as the whole name, and require than an
        appropriate interface name be specified. */
-    if (st->search_for_if && st->interface_name) {
-       cfgfatal(loc,"tun-old","you may not specify an interface name "
-                "in interface-search mode\n");
-    }
-    if (!st->search_for_if && !st->interface_name) {
-       cfgfatal(loc,"tun-old","you must specify an interface name "
-                "when you explicitly specify a TUN device file\n");
+    if (st->tun_flavour==TUN_FLAVOUR_BSD) {
+       if (st->search_for_if && st->interface_name) {
+           cfgfatal(loc,"tun","you may not specify an interface name "
+                    "in interface-search mode\n");
+       }
+       if (!st->search_for_if && !st->interface_name) {
+           cfgfatal(loc,"tun","you must specify an interface name "
+                    "when you explicitly specify a TUN device file\n");
+       }
     }
 
-
     add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
 
     return new_closure(&st->nl.cl);
 }
 
+static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
+                        list_t *args)
+{
+    return tun_create(self,loc,context,args,TUN_FLAVOUR_GUESS);
+}
+
+static list_t *tun_bsd_apply(closure_t *self, struct cloc loc, dict_t *context,
+                            list_t *args)
+{
+    Message(M_WARNING,"(%s,%d): obsolete use of tun-old; replace with tun "
+           "and specify flavour \"bsd\".\n",loc.file,loc.line);
+    return tun_create(self,loc,context,args,TUN_FLAVOUR_BSD);
+}
+
 init_module tun_module;
 void tun_module(dict_t *dict)
 {
-#ifdef HAVE_LINUX_IF_H
     add_closure(dict,"tun",tun_apply);
-#endif
-    add_closure(dict,"tun-old",tun_old_apply);
+    add_closure(dict,"tun-old",tun_bsd_apply);
 }
diff --git a/udp.c b/udp.c
index 6520865..3988826 100644 (file)
--- a/udp.c
+++ b/udp.c
@@ -5,10 +5,6 @@
  * optionally bind to a particular local IP address (not implemented
  * yet).
  *
- * Sites register an interest in local port numbers for receiving
- * packets, and can also send packets. We don't care about the source
- * port number for sending packets. 
- *
  * Packets are offered to registered receivers in turn. Once one
  * accepts it, it isn't offered to any more. */
 
@@ -22,6 +18,7 @@
 #include <sys/wait.h>
 #include "util.h"
 #include "unaligned.h"
+#include "ipaddr.h"
 
 static beforepoll_fn udp_beforepoll;
 static afterpoll_fn udp_afterpoll;
@@ -29,10 +26,6 @@ static comm_request_notify_fn request_notify;
 static comm_release_notify_fn release_notify;
 static comm_sendmsg_fn udp_sendmsg;
 
-/* The UDP module exports a pure closure which can be used to construct a
- * UDP send/receive module. Arguments:
- */
-
 struct notify_list {
     comm_notify_fn *fn;
     void *state;
@@ -48,6 +41,8 @@ struct udp {
     string_t authbind;
     struct buffer_if *rbuf;
     struct notify_list *notify;
+    bool_t use_proxy;
+    struct sockaddr_in proxy;
 };
 
 static int udp_beforepoll(void *state, struct pollfd *fds, int *nfds_io,
@@ -84,6 +79,21 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds,
                        (struct sockaddr *)&from, &fromlen);
            if (rv>0) {
                st->rbuf->size=rv;
+               if (st->use_proxy) {
+                   /* Check that the packet came from our poxy server;
+                      we shouldn't be contacted directly by anybody else
+                      (since they can trivially forge source addresses) */
+                   if (memcmp(&from.sin_addr,&st->proxy.sin_addr,4)!=0 ||
+                       memcmp(&from.sin_port,&st->proxy.sin_port,2)!=0) {
+                       Message(M_INFO,"udp: received packet that's not "
+                               "from the proxy\n");
+                       BUF_FREE(st->rbuf);
+                       continue;
+                   }
+                   memcpy(&from.sin_addr,buf_unprepend(st->rbuf,4),4);
+                   buf_unprepend(st->rbuf,2);
+                   memcpy(&from.sin_port,buf_unprepend(st->rbuf,2),2);
+               }
                done=False;
                for (n=st->notify; n; n=n->next) {
                    if (n->fn(n->state, st->rbuf, &from)) {
@@ -93,7 +103,7 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds,
                }
                if (!done) {
                    uint32_t source,dest;
-                   /* XXX manufacture and send NAK packet */
+                   /* Manufacture and send NAK packet */
                    source=get_uint32(st->rbuf->start); /* Us */
                    dest=get_uint32(st->rbuf->start+4); /* Them */
                    Message(M_INFO,"udp (port %d): sending NAK\n",st->port);
@@ -150,10 +160,19 @@ static bool_t udp_sendmsg(void *commst, struct buffer_if *buf,
                          struct sockaddr_in *dest)
 {
     struct udp *st=commst;
+    uint8_t *sa;
 
-    /* XXX fix error reporting */
-    sendto(st->fd, buf->start, buf->size, 0,
-          (struct sockaddr *)dest, sizeof(*dest));
+    if (st->use_proxy) {
+       sa=buf->start-8;
+       memcpy(sa,&dest->sin_addr,4);
+       memset(sa+4,0,4);
+       memcpy(sa+6,&dest->sin_port,2);
+       sendto(st->fd,sa,buf->size+8,0,(struct sockaddr *)&st->proxy,
+              sizeof(st->proxy));
+    } else {
+       sendto(st->fd, buf->start, buf->size, 0,
+              (struct sockaddr *)dest, sizeof(*dest));
+    }
 
     return True;
 }
@@ -221,6 +240,8 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
     struct udp *st;
     item_t *i;
     dict_t *d;
+    list_t *l;
+    uint32_t a;
 
     st=safe_malloc(sizeof(*st),"udp_apply(st)");
     st->loc=loc;
@@ -229,10 +250,13 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->cl.apply=NULL;
     st->cl.interface=&st->ops;
     st->ops.st=st;
+    st->ops.min_start_pad=0;
+    st->ops.min_end_pad=0;
     st->ops.request_notify=request_notify;
     st->ops.release_notify=release_notify;
     st->ops.sendmsg=udp_sendmsg;
     st->port=0;
+    st->use_proxy=False;
 
     i=list_elem(args,0);
     if (!i || i->type!=t_dict) {
@@ -243,6 +267,24 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
     st->port=dict_read_number(d,"port",True,"udp",st->loc,0);
     st->rbuf=find_cl_if(d,"buffer",CL_BUFFER,True,"udp",st->loc);
     st->authbind=dict_read_string(d,"authbind",False,"udp",st->loc);
+    l=dict_lookup(d,"proxy");
+    if (l) {
+       st->use_proxy=True;
+       memset(&st->proxy,0,sizeof(st->proxy));
+       st->proxy.sin_family=AF_INET;
+       i=list_elem(l,0);
+       if (!i || i->type!=t_string) {
+           cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
+       }
+       a=string_item_to_ipaddr(i,"proxy");
+       st->proxy.sin_addr.s_addr=htonl(a);
+       i=list_elem(l,1);
+       if (!i || i->type!=t_number) {
+           cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
+       }
+       st->proxy.sin_port=htons(i->data.number);
+       st->ops.min_start_pad=8;
+    }
 
     add_hook(PHASE_GETRESOURCES,udp_phase_hook,st);
 
diff --git a/util.h b/util.h
index d272a59..878d665 100644 (file)
--- a/util.h
+++ b/util.h
@@ -1,9 +1,3 @@
-/* $Log: util.h,v $
- * Revision 1.1  1996/03/14 17:05:12  sde1000
- * Initial revision
- *
- */
-
 #ifndef util_h
 #define util_h