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.
.PHONY: all clean realclean distclean dist install
PACKAGE:=secnet
-VERSION:=0.1.12
+VERSION:=0.1.13
@SET_MAKE@
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 \
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
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
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.
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
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
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
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
-/*
- * $Log$
- */
-
/* conffile.c - process the configuration file */
/* #define DUMP_PARSE_TREE */
-/*
- * $Log$
- */
-
#ifndef conffile_h
#define conffile_h
-/*
- * $Log$
- */
-
#ifndef conffile_internal_h
#define conffile_internal_h
-/* 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
-# 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.
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
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>
#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>
#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
{ 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. */
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
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
{ 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>
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
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
{ 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>
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
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
{ 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>
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
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
{ 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>
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
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
{ 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>
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
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
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
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
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
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
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
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
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
__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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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. */
; 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
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. */
; 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
# 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
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__
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
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
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. */
; 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
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
ac_cv_c_stack_direction=0
else
cat > conftest.$ac_ext <<EOF
-#line 2237 "configure"
+#line 2317 "configure"
#include "confdefs.h"
find_stack_direction ()
{
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
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
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)
-secnet (0.1.12-1) unstable; urgency=low
+secnet (0.1.13-1) unstable; urgency=low
* New upstream version.
-/***************************************************************************
- *
- * 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>
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++) {
* 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
--- /dev/null
+/* 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 */
sys.path.append("/usr/share/secnet")
import ipaddr
-VERSION="0.1.10"
+VERSION="0.1.13"
class vpn:
def __init__(self,name):
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)
/* 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)
{
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)
{
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);
/* 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;
/*
* 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?
*
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 {
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) {
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);
}
}
/* 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;
}
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);
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;
}
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);
}
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)
-/* $Log$
- */
-
#include "secnet.h"
#include <stdio.h>
#include <fcntl.h>
-/***************************************************************************
- *
- * 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"
-/* $Log: secnet.c,v $
- * Revision 1.1 1996/03/13 22:27:41 sde1000
- * Initial revision
- *
- */
-
extern char version[];
#include "secnet.h"
/* 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");
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;
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 *****/
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);
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;
(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
}
}
-#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
{ "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 }
};
/* 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;
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
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 */
uint64_t timeout; /* Timeout for current state */
uint8_t *dhsecret;
uint8_t *sharedsecret;
-
struct transform_inst_if *new_transform; /* For key setup/verify */
};
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)
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;
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);
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;
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;
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);
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;
}
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;
/* 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)
{
/* 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)) {
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;
}
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;
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);
} 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;
}
{
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;
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;
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)
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;
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);
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;
}
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. */
"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)");
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 */
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");
}
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");
}
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");
}
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");
}
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"),
/* 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);
#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 */
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)
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)
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");
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
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);
}
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
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);
}
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");
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);
}
* 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. */
#include <sys/wait.h>
#include "util.h"
#include "unaligned.h"
+#include "ipaddr.h"
static beforepoll_fn udp_beforepoll;
static afterpoll_fn udp_afterpoll;
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;
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,
(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)) {
}
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);
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;
}
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;
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) {
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);
-/* $Log: util.h,v $
- * Revision 1.1 1996/03/14 17:05:12 sde1000
- * Initial revision
- *
- */
-
#ifndef util_h
#define util_h