# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-.PHONY: all clean realclean dist install
+.PHONY: all clean realclean dist install distclean
PACKAGE:=secnet
-VERSION:=0.1.9
+VERSION:=0.1.10
@SET_MAKE@
config.log config.status config.cache \
stamp-h Makefile.bak
+distclean: realclean
+
pfname:=$(PACKAGE)-$(VERSION)
dist:
$(RM) -rf $(pfname)
* Planned for the future
-New configuration syntax for netlinks: basic 'netlink' closure yields
-a pure closure that can be applied in each site() to generate a
-netlink for that site (with routes, options, etc.). Works well for
-point-to-point: that netlink can be used directly by just one site.
-Much cleaner separation between site() and netlink code this way.
+Netlink device that implements an Ethernet bridge.
-(Backward compatibility will be kept for a while.)
+Modular transform code: choice of block ciphers, modes, sequence
+numbers / timestamps, etc. similar to IWJ's udptunnel
+* New in versino 0.1.11
+
+* New in version 0.1.10
+
+WARNING: THIS VERSION MAKES A CHANGE TO THE CONFIGURATION FILE FORMAT
+THAT IS NOT BACKWARD COMPATIBLE. However, in most configurations the
+change only affects the sites.conf file, which is generated by the
+make-secnet-sites script; after you regenerate your sites.conf using
+version 0.1.10, everything should continue to work.
+
+Netlink devices now interact slightly differently with the 'site'
+code. When you invoke a netlink closure like 'tun' or 'userv-ipif',
+you get another closure back. You then invoke this closure (usually
+in the site definitions) to specify things like routes and options.
+The result of this invocation should be used as the 'link' option in
+site configurations.
+
+All this really means is that instead of site configurations looking
+like this:
+
+foo {
+ name "foo";
+ networks "a", "b", "c";
+ etc.
+};
+
+...they look like this:
+
+foo {
+ name "foo";
+ link netlink { routes "a", "b", "c"; };
+ etc.
+};
+
+This change was made to enable the 'site' code to be completely free
+of any knowledge of the contents of the packets it transmits. It
+should now be possible in the future to tunnel other protocols like
+IPv6, IPX, raw Ethernet frames, etc. without changing the 'site' code
+at all.
+
+Point-to-point netlink devices work slightly differently; when you
+apply the 'tun', 'userv-ipif', etc. closure and specify the
+ptp-address option, you must also specify the 'routes' option. The
+result of this invocation should be passed directly to the 'link'
+option of the site configuration. You can do things like this:
+
+sites site {
+ name "foo";
+ link tun {
+ networks "192.168.73.76/32";
+ local-address "192.168.73.76"; # IP address of interface
+ ptp-address "192.168.73.75"; # IP address of other end of link
+ routes "192.168.73.74/32";
+ mtu 1400;
+ buffer sysbuffer();
+ };
+ etc.
+};
+
+The route dump obtained by sending SIGUSR1 to secnet now includes
+packet counts.
+
+Point-to-point mode has now been tested.
+
+tun-old has now been tested, and the annoying 'untested' message has
+been removed. Thanks to SGT and JDA.
+
+secnet now closes its stdin, stdout and stderr just after
+backgrounding.
+
+Bugfix: specifying network "0.0.0.0/0" (or "default") now works
+correctly.
+
* New in version 0.1.9
The netlink code may now generate ICMP responses to ICMP messages that
laptop-to-host link), read the section in this file on 'Creating a
VPN'.
+* Mailing lists and bug reporting
+
+There are two mailing lists associated with secnet: an 'announce' list
+and a 'discuss' list. Their addresses are:
+http://www.chiark.greenend.org.uk/mailman/listinfo/secnet-announce
+http://www.chiark.greenend.org.uk/mailman/listinfo/secnet-discuss
+
+The -announce list receives one message per secnet release. The
+-discuss list is for general discussion, including help with
+configuration, bug reports, feature requests, etc.
+
+Bug reports should be sent to <steve@greenend.org.uk>; they will be
+forwarded to the -discuss list by me.
+
* Creating a VPN
XXX TODO
* secnet command line options
-XXX TODO
+Usage: secnet [OPTION]...
+
+ -f, --silent, --quiet suppress error messages
+ -w, --nowarnings suppress warnings
+ -v, --verbose output extra diagnostics
+ -c, --config=filename specify a configuration file
+ -j, --just-check-config stop after reading configfile
+ -n, --nodetach do not run in background
+ -d, --debug=item,... set debug options
+ --help display this help and exit
+ --version output version information and exit
* secnet builtin modules
site: dict argument
local-name (string): this site's name for itself
name (string): the name of the site's peer
- netlink (netlink closure)
+ link (netlink closure)
comm (comm closure)
resolver (resolver closure)
random (randomsrc closure)
address (string): optional, DNS name used to find our peer
port (integer): mandatory if 'address' is specified: the port used
to contact our peer
- networks (string list): networks that our peer may claim traffic for
key (rsapubkey closure): our peer's public key
transform (transform closure): how to mangle packets sent between sites
dh (dh closure)
dump-packets: every key setup packet we see
errors: failure of name resolution, internal errors
all: everything (too much!)
- netlink-options (string list): options to pass to netlink device when
- registering remote networks
- soft: create 'soft' routes that go away when there's no key established
- with the peer
- allow-route: allow packets from our peer to be sent down other tunnels,
- as well as to the host
** transform
** netlink
Defines:
- null-netlink (closure => netlink closure)
+ null-netlink (closure => closure or netlink closure)
null-netlink: dict argument
name (string): name for netlink device, used in log messages
ptp-address (string): IP address of the other end of a point-to-point link
mtu (integer): MTU of host's tunnel interface
-Only one of secnet-address or ptp-address may be specified. If
-point-to-point mode is in use then precisely one tunnel must register
-with the netlink device.
+Only one of secnet-address or ptp-address may be specified. If
+point-to-point mode is in use then the "routes" option must also be
+specified, and netlink returns a netlink closure that should be used
+directly with the "link" option to the site closure. If
+point-to-point mode is not in use then netlink returns a closure that
+may be invoked using a dict argument with the following keys to yield
+a netlink closure:
+ routes (string list): networks reachable down the tunnel attached to
+ this instance of netlink
+ options (string list):
+ allow-route: allow packets coming from this tunnel to be routed to
+ 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
Netlink will dump its current routing table to the system/log on
receipt of SIGUSR1.
netlink.c: investigate why 'default' routes don't appear to work
(reported by JDA).
-Implement the 'allow_route' option properly.
+Test the 'allow_route' option properly.
random.c: test
userv-ipif doesn't like the same bit of network to be specified
twice. Use the new functionality in ipaddr.c once it's done to prevent
this.
-
-tun.c: jdamery reports tun-old code works on Linux-2.2.
-Unresolved problem with ioctl(TUNSETIFF) sometimes returning EINVAL, seems
-to be related to early 2.4.x (x<=5) series kernels. 2.4.9 and above seem ok;
-2.4.[678] untested.
+Work out why slip.c doesn't compile on Solaris-2.5.1
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.
+
+udp.c: actually send NAKs rather than just complaining.
if (cl->type != t_closure) {
cfgfatal(i->l->loc,"conffile","only closures can be invoked\n");
}
+ if (!cl->data.closure->apply) {
+ cfgfatal(i->l->loc,"conffile","this closure cannot be invoked\n");
+ }
args=process_ilist(context, i->r);
return cl->data.closure->apply(cl->data.closure, i->loc, context, args);
}
cfgfatal(i->loc,desc,"expecting a string (subnet specification)\n");
}
+ if (strcmp(i->data.string,"default")==0) {
+ s.prefix=0;
+ s.mask=0;
+ s.len=0;
+ return s;
+ }
+
/* We expect strings of the form "a.b.c.d[/n]", i.e. the dots are
NOT optional. The subnet mask is optional; if missing it is assumed
to be /32. */
cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
}
s.prefix=(a<<24)|(b<<16)|(c<<8)|(d);
- s.mask=(~0UL << (32-n));
+ s.mask=n?(~0UL << (32-n)):0;
s.len=n;
if (s.prefix & ~s.mask) {
cfgfatal(i->loc,desc,"\"%s\": prefix not fully contained "
#endif
#ifndef HAVE_SNPRINTF
+#include <stdio.h>
+#include <stdarg.h>
#include "snprintf.h"
#endif
/* Define if you have the gnugetopt library (-lgnugetopt). */
#undef HAVE_LIBGNUGETOPT
+
+/* Define if you have the nsl library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the resolv library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
/* -*- c -*- */
/* These are from config.h.bot, pasted onto the end of config.h.in. */
#endif
#ifndef HAVE_SNPRINTF
+#include <stdio.h>
+#include <stdarg.h>
#include "snprintf.h"
#endif
echo "$ac_t""no" 1>&6
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
+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
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lgmp $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1562 "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
+ builtin and then its argument prototype would still apply. */
+char __gmpz_init_set_str();
+
+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
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo gmp | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lgmp $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
echo $ac_n "checking for yywrap in -lfl""... $ac_c" 1>&6
-echo "configure:1554: checking for yywrap in -lfl" >&5
+echo "configure:1601: 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 1562 "configure"
+#line 1609 "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:1573: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1620: \"$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
echo "$ac_t""no" 1>&6
fi
-echo $ac_n "checking for adns_init in -ladns""... $ac_c" 1>&6
-echo "configure:1601: checking for adns_init in -ladns" >&5
-ac_lib_var=`echo adns'_'adns_init | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for inet_ntoa in -lnsl""... $ac_c" 1>&6
+echo "configure:1648: 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
else
ac_save_LIBS="$LIBS"
-LIBS="-ladns $LIBS"
+LIBS="-lnsl $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 1609 "configure"
+#line 1656 "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
builtin and then its argument prototype would still apply. */
-char adns_init();
+char inet_ntoa();
int main() {
-adns_init()
+inet_ntoa()
; 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:1667: \"$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
if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
echo "$ac_t""yes" 1>&6
- ac_tr_lib=HAVE_LIB`echo adns | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \
-e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
cat >> confdefs.h <<EOF
#define $ac_tr_lib 1
EOF
- LIBS="-ladns $LIBS"
+ LIBS="-lnsl $LIBS"
else
echo "$ac_t""no" 1>&6
fi
echo $ac_n "checking for getopt_long in -lgetopt""... $ac_c" 1>&6
-echo "configure:1648: checking for getopt_long in -lgetopt" >&5
+echo "configure:1695: 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 1656 "configure"
+#line 1703 "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:1667: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1714: \"$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:1695: checking for getopt_long in -lgnugetopt" >&5
+echo "configure:1742: 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 1703 "configure"
+#line 1750 "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:1761: \"$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
echo "$ac_t""no" 1>&6
fi
+echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6
+echo "configure:1789: 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
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lsocket $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1797 "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
+ builtin and then its argument prototype would still apply. */
+char socket();
+
+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
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lsocket $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for inet_aton in -lresolv""... $ac_c" 1>&6
+echo "configure:1836: 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
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lresolv $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1844 "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
+ builtin and then its argument prototype would still apply. */
+char inet_aton();
+
+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
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo resolv | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-lresolv $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+echo $ac_n "checking for adns_init in -ladns""... $ac_c" 1>&6
+echo "configure:1883: 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
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-ladns $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1891 "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
+ builtin and then its argument prototype would still apply. */
+char adns_init();
+
+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
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_lib=HAVE_LIB`echo adns | sed -e 's/[^a-zA-Z0-9_]/_/g' \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_lib 1
+EOF
+
+ LIBS="-ladns $LIBS"
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+
for ac_func in getopt_long
do
echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:1746: checking for $ac_func" >&5
+echo "configure:1934: 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 1751 "configure"
+#line 1939 "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:1774: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:1962: \"$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:1802: checking for $ac_func" >&5
+echo "configure:1990: 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 1807 "configure"
+#line 1995 "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:1830: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2018: \"$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:1858: checking for working alloca.h" >&5
+echo "configure:2046: 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 1863 "configure"
+#line 2051 "configure"
#include "confdefs.h"
#include <alloca.h>
int main() {
char *p = alloca(2 * sizeof(int));
; return 0; }
EOF
-if { (eval echo configure:1870: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2058: \"$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:1891: checking for alloca" >&5
+echo "configure:2079: 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 1896 "configure"
+#line 2084 "configure"
#include "confdefs.h"
#ifdef __GNUC__
char *p = (char *) alloca(1);
; return 0; }
EOF
-if { (eval echo configure:1924: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2112: \"$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:1956: checking whether alloca needs Cray hooks" >&5
+echo "configure:2144: 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 1961 "configure"
+#line 2149 "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:1986: checking for $ac_func" >&5
+echo "configure:2174: 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 1991 "configure"
+#line 2179 "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:2014: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2202: \"$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:2041: checking stack direction for C alloca" >&5
+echo "configure:2229: 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 2049 "configure"
+#line 2237 "configure"
#include "confdefs.h"
find_stack_direction ()
{
exit (find_stack_direction() < 0);
}
EOF
-if { (eval echo configure:2068: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
+if { (eval echo configure:2256: \"$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_CHECK_SIZEOF(unsigned short)
AC_CHECK_SIZEOF(unsigned char)
+dnl the order in which libraries is checked is important
+dnl eg. adns on Solaris 2.5.1 depends on -lnsl and -lsocket
AC_CHECK_LIB(gmp,mpz_init_set_str)
AC_CHECK_LIB(gmp2,mpz_init_set_str)
+AC_CHECK_LIB(gmp,__gmpz_init_set_str)
AC_CHECK_LIB(fl,yywrap)
-AC_CHECK_LIB(adns,adns_init)
+AC_CHECK_LIB(nsl,inet_ntoa)
AC_CHECK_LIB(getopt,getopt_long)
AC_CHECK_LIB(gnugetopt,getopt_long)
+AC_CHECK_LIB(socket,socket)
+AC_CHECK_LIB(resolv,inet_aton)
+AC_CHECK_LIB(adns,adns_init)
dnl check for getopt in standard library
AC_SUBST(LIBOBJS)
-secnet (0.1.9-1) unstable; urgency=low
+secnet (0.1.10-1) unstable; urgency=low
* New upstream version.
name "netlink-tun"; # Printed in log messages from this netlink
# interface "tun0"; # You may set your own interface name if you wish;
# if you don't one will be chosen for you.
+# device "/dev/net/tun";
# local networks served by this netlink device
# incoming tunneled packets for other networks will be discarded
# host and port for your site end up on this machine at the port you
# specify here.
comm udp {
- port xxxx;
+ port 410;
buffer sysbuffer(4096);
};
mask=(mask<<1);
}
if (i!=sn->len) {
- fatal("subnet_to_string: invalid subnet structure!\n");
+ fatal("subnet_to_string: invalid subnet structure "
+ "(i=%d sn->len=%d mask=0x%08x)!\n",i,sn->len,sn->mask);
}
snprintf(s, 19, "%d.%d.%d.%d/%d", a, b, c, d, sn->len);
return s;
#include "process.h"
bool_t secnet_is_daemon=False;
-uint32_t message_level=M_WARNING|M_ERROR|M_SECURITY|M_FATAL;
+uint32_t message_level=M_WARNING|M_ERR|M_SECURITY|M_FATAL;
struct log_if *system_log=NULL;
static void vMessage(uint32_t class, char *message, va_list args)
} else {
/* Messages go to stdout/stderr */
if (class & message_level) {
- if (class&M_FATAL || class&M_ERROR || class&M_WARNING) {
+ if (class&M_FATAL || class&M_ERR || class&M_WARNING) {
dest=stderr;
}
vfprintf(dest,message,args);
{ "info", M_INFO },
{ "notice", M_NOTICE },
{ "warning", M_WARNING },
- { "error", M_ERROR },
+ { "error", M_ERR },
{ "security", M_SECURITY },
{ "fatal", M_FATAL },
- { "default", M_WARNING|M_ERROR|M_SECURITY|M_FATAL },
- { "verbose", M_INFO|M_NOTICE|M_WARNING|M_ERROR|M_SECURITY|M_FATAL },
+ { "default", M_WARNING|M_ERR|M_SECURITY|M_FATAL },
+ { "verbose", M_INFO|M_NOTICE|M_WARNING|M_ERR|M_SECURITY|M_FATAL },
{ "quiet", M_FATAL },
{ NULL, 0 }
};
case M_INFO: return LOG_INFO;
case M_NOTICE: return LOG_NOTICE;
case M_WARNING: return LOG_WARNING;
- case M_ERROR: return LOG_ERR;
+ case M_ERR: return LOG_ERR;
case M_SECURITY: return LOG_CRIT;
case M_FATAL: return LOG_EMERG;
default: return LOG_NOTICE;
sys.path.append("/usr/share/secnet")
import ipaddr
-VERSION="0.1.9"
+VERSION="0.1.10"
class vpn:
def __init__(self,name):
i=sc.intersection(self.set)
return i.is_empty()
def out(self):
- rn=''
- if (self.w[0]=='restrict-nets'): rn='# '
- return '%s%s %s;'%(rn,self.w[0],
- string.join(map(lambda x:'"%s/%s"'%(x.ip_str(),
+ if (self.w[0]=='restrict-nets'): pattern="# restrict-nets %s;"
+ else:
+ pattern="link netlink { routes %s; };"
+ return pattern%string.join(map(lambda x:'"%s/%s"'%(x.ip_str(),
x.mask.netmask_bits_str),
- self.set.as_list_of_networks()),","))
+ self.set.as_list_of_networks()),",")
class dhgroup:
def __init__(self,w):
#include "netlink.h"
#include "process.h"
+#define OPT_SOFTROUTE 1
+#define OPT_ALLOWROUTE 2
+
/* Generic IP checksum routine */
static inline uint16_t ip_csum(uint8_t *iph,uint32_t count)
{
return True;
}
-/* Deliver a packet. "client" points to the _origin_ of the packet, not
- its destination. (May be used when sending ICMP response - avoid
- asymmetric routing.) */
+/* Deliver a packet. "client" is the _origin_ of the packet, not its
+destination. */
static void netlink_packet_deliver(struct netlink *st,
struct netlink_client *client,
struct buffer_if *buf)
uint32_t dest=ntohl(iph->daddr);
uint32_t source=ntohl(iph->saddr);
uint32_t best_quality;
+ bool_t allow_route=False;
+ bool_t found_allowed=False;
int best_match;
int i;
BUF_ASSERT_USED(buf);
if (dest==st->secnet_address) {
- Message(M_ERROR,"%s: trying to deliver a packet to myself!\n");
+ Message(M_ERR,"%s: trying to deliver a packet to myself!\n");
BUF_FREE(buf);
return;
}
- /* XXX we're going to need an extra value 'allow_route' for the
- source of the packet. It's always True for packets from the
- host. For packets from tunnels, we consult the client
- options. If !allow_route and the destination is a tunnel that
- also doesn't allow routing, we must reject the packet with an
- 'administratively prohibited' or something similar ICMP. */
- if (!client) {
- /* Origin of packet is host or secnet. Might be for a tunnel. */
- best_quality=0;
- best_match=-1;
- for (i=0; i<st->n_routes; i++) {
- if (st->routes[i].up && subnet_match(&st->routes[i].net,dest)) {
- if (st->routes[i].c->link_quality>best_quality
- || best_quality==0) {
- best_quality=st->routes[i].c->link_quality;
- best_match=i;
- /* If quality isn't perfect we may wish to
- consider kicking the tunnel with a 0-length
- packet to prompt it to perform a key setup.
- Then it'll eventually decide it's up or
- down. */
- /* If quality is perfect we don't need to search
- any more. */
- if (best_quality>=MAXIMUM_LINK_QUALITY) break;
- }
- }
- }
- if (best_match==-1) {
- /* Not going down a tunnel. Might be for the host.
- XXX think about this - only situation should be if we're
- sending ICMP. */
- if (source!=st->secnet_address) {
- Message(M_ERROR,"netlink_packet_deliver: outgoing packet "
- "from host that won't fit down any of our tunnels!\n");
- /* XXX I think this could also occur if a soft tunnel just
- went down, but still had packets queued in the kernel. */
- BUF_FREE(buf);
- } else {
- st->deliver_to_host(st->dst,NULL,buf);
- BUF_ASSERT_FREE(buf);
+ /* Packets from the host (client==NULL) will always be routed. Packets
+ from clients with the allow_route option will also be routed. */
+ if (!client || (client && (client->options & OPT_ALLOWROUTE)))
+ allow_route=True;
+
+ /* If !allow_route, we check the routing table anyway, and if
+ there's a suitable route with OPT_ALLOWROUTE set we use it. If
+ there's a suitable route, but none with OPT_ALLOWROUTE set then
+ we generate ICMP 'communication with destination network
+ administratively prohibited'. */
+
+ best_quality=0;
+ best_match=-1;
+ for (i=0; i<st->n_routes; i++) {
+ if (st->routes[i].up && subnet_match(&st->routes[i].net,dest)) {
+ /* It's an available route to the correct destination. But is
+ it better than the one we already have? */
+
+ /* If we have already found an allowed route then we don't
+ bother looking at routes we're not allowed to use. If
+ we don't yet have an allowed route we'll consider any. */
+ if (!allow_route && found_allowed) {
+ if (!(st->routes[i].c->options&OPT_ALLOWROUTE)) continue;
}
- } else {
- if (best_quality>0) {
- st->routes[best_match].c->deliver(
- st->routes[best_match].c->dst,
- st->routes[best_match].c, buf);
- BUF_ASSERT_FREE(buf);
- } else {
- /* Generate ICMP destination unreachable */
- netlink_icmp_simple(st,buf,client,3,0); /* client==NULL */
- BUF_FREE(buf);
+
+ if (st->routes[i].c->link_quality>best_quality
+ || best_quality==0) {
+ best_quality=st->routes[i].c->link_quality;
+ best_match=i;
+ if (st->routes[i].c->options&OPT_ALLOWROUTE)
+ found_allowed=True;
+ /* If quality isn't perfect we may wish to
+ consider kicking the tunnel with a 0-length
+ packet to prompt it to perform a key setup.
+ Then it'll eventually decide it's up or
+ down. */
+ /* If quality is perfect and we're allowed to use the
+ route we don't need to search any more. */
+ if (best_quality>=MAXIMUM_LINK_QUALITY &&
+ (allow_route || found_allowed)) break;
}
}
- } else { /* client is set */
- /* We know the origin is a tunnel - packet must be for the host */
- /* XXX THIS IS NOT NECESSARILY TRUE, AND NEEDS FIXING */
- /* THIS FUNCTION MUST JUST DELIVER THE PACKET: IT MUST ASSUME
- THE PACKET HAS ALREADY BEEN CHECKED */
+ }
+ if (best_match==-1) {
+ /* The packet's not going down a tunnel. It might (ought to)
+ be for the host. */
if (subnet_matches_list(&st->networks,dest)) {
- st->deliver_to_host(st->dst,NULL,buf);
+ st->deliver_to_host(st->dst,buf);
+ st->outcount++;
BUF_ASSERT_FREE(buf);
} else {
- Message(M_ERROR,"%s: packet from tunnel %s can't be delivered "
- "to the host\n",st->name,client->name);
+ 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 "
+ "(s=%s, d=%s)\n", st->name, s, d);
+ free(s); free(d);
netlink_icmp_simple(st,buf,client,3,0);
BUF_FREE(buf);
}
+ } else {
+ if (!allow_route &&
+ !(st->routes[best_match].c->options&OPT_ALLOWROUTE)) {
+ string_t s,d;
+ s=ipaddr_to_string(source);
+ d=ipaddr_to_string(dest);
+ /* We have a usable route but aren't allowed to use it.
+ Generate ICMP destination unreachable: communication
+ with destination network administratively prohibited */
+ Message(M_NOTICE,"%s: denied forwarding for packet (s=%s, d=%s)\n",
+ st->name,s,d);
+ free(s); free(d);
+
+ netlink_icmp_simple(st,buf,client,3,9);
+ BUF_FREE(buf);
+ }
+ if (best_quality>0) {
+ st->routes[best_match].c->deliver(
+ st->routes[best_match].c->dst, buf);
+ st->routes[best_match].outcount++;
+ BUF_ASSERT_FREE(buf);
+ } else {
+ /* Generate ICMP destination unreachable */
+ netlink_icmp_simple(st,buf,client,3,0); /* client==NULL */
+ BUF_FREE(buf);
+ }
}
BUF_ASSERT_FREE(buf);
}
{
struct icmphdr *h;
+ st->localcount++;
+
h=(struct icmphdr *)buf->start;
if ((ntohs(h->iph.frag_off)&0xbfff)!=0) {
/* If cid==NULL packet is from host, otherwise cid specifies which tunnel
it came from. */
-static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf)
+static void netlink_incoming(struct netlink *st, struct netlink_client *client,
+ struct buffer_if *buf)
{
- struct netlink *st=sst;
- struct netlink_client *client=cid;
uint32_t source,dest;
struct iphdr *iph;
if (client) {
/* Check that the packet source is appropriate for the tunnel
it came down */
- if (!subnet_matches_list(client->networks,source)) {
+ if (!subnet_matches_list(&client->networks,source)) {
string_t s,d;
s=ipaddr_to_string(source);
d=ipaddr_to_string(dest);
or to the host, depending on where it came from. */
if (st->ptp) {
if (client) {
- st->deliver_to_host(st->dst,NULL,buf);
+ st->deliver_to_host(st->dst,buf);
} else {
- st->clients->deliver(st->clients->dst,NULL,buf);
+ st->clients->deliver(st->clients->dst,buf);
}
BUF_ASSERT_FREE(buf);
return;
BUF_ASSERT_FREE(buf);
}
+static void netlink_inst_incoming(void *sst, struct buffer_if *buf)
+{
+ struct netlink_client *c=sst;
+ struct netlink *st=c->nst;
+
+ netlink_incoming(st,c,buf);
+}
+
+static void netlink_dev_incoming(void *sst, struct buffer_if *buf)
+{
+ struct netlink *st=sst;
+
+ netlink_incoming(st,NULL,buf);
+}
+
static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c,
bool_t up, uint32_t quality)
{
}
}
-static void netlink_set_quality(void *sst, void *cid, uint32_t quality)
+static void netlink_set_quality(void *sst, uint32_t quality)
{
- struct netlink *st=sst;
- struct netlink_client *c=cid;
+ struct netlink_client *c=sst;
+ struct netlink *st=c->nst;
c->link_quality=quality;
if (c->link_quality==LINK_QUALITY_DOWN) {
}
}
-static void *netlink_regnets(void *sst, struct subnet_list *nets,
- netlink_deliver_fn *deliver, void *dst,
- uint32_t max_start_pad, uint32_t max_end_pad,
- uint32_t options, string_t client_name)
-{
- struct netlink *st=sst;
- struct netlink_client *c;
-
- Message(M_DEBUG_CONFIG,"netlink_regnets: request for %d networks, "
- "max_start_pad=%d, max_end_pad=%d\n",
- nets->entries,max_start_pad,max_end_pad);
-
- if ((options&NETLINK_OPTION_SOFTROUTE) && !st->set_route) {
- Message(M_ERROR,"%s: this netlink device does not support "
- "soft routes.\n");
- return NULL;
- }
-
- if (options&NETLINK_OPTION_SOFTROUTE) {
- /* XXX for now we assume that soft routes require root privilege;
- this may not always be true. The device driver can tell us. */
- require_root_privileges=True;
- require_root_privileges_explanation="netlink: soft routes";
- }
-
- /* Check that nets do not intersect st->exclude_remote_networks;
- refuse to register if they do. */
- if (subnet_lists_intersect(&st->exclude_remote_networks,nets)) {
- Message(M_ERROR,"%s: site %s specifies networks that "
- "intersect with the explicitly excluded remote networks\n",
- st->name,client_name);
- return NULL;
- }
-
- if (st->clients && st->ptp) {
- fatal("%s: only one site may use a point-to-point netlink device\n",
- st->name);
- return NULL;
- }
-
- c=safe_malloc(sizeof(*c),"netlink_regnets");
- c->networks=nets;
- c->deliver=deliver;
- c->dst=dst;
- c->name=client_name;
- c->options=options;
- c->link_quality=LINK_QUALITY_DOWN;
- c->next=st->clients;
- st->clients=c;
- if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
- if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
- st->n_routes+=nets->entries;
-
- return c;
-}
-
static void netlink_dump_routes(struct netlink *st, bool_t requested)
{
int i;
uint32_t c=M_INFO;
if (requested) c=M_WARNING;
- Message(c,"%s: routing table:\n",st->name);
- for (i=0; i<st->n_routes; i++) {
- net=subnet_to_string(&st->routes[i].net);
- Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d)\n",net,
- st->routes[i].c->name,
- st->routes[i].hard?"hard":"soft",
- st->routes[i].allow_route?"free":"restricted",
- st->routes[i].up?"up":"down",
- st->routes[i].quality);
+ if (st->ptp) {
+ net=ipaddr_to_string(st->secnet_address);
+ Message(c,"%s: point-to-point (remote end is %s); routes:\n",
+ st->name, net);
free(net);
- }
- Message(c,"%s/32 -> netlink \"%s\"\n",
- ipaddr_to_string(st->secnet_address),st->name);
- for (i=0; i<st->networks.entries; i++) {
- net=subnet_to_string(&st->networks.list[i]);
- Message(c,"%s -> host\n",net);
+ for (i=0; i<st->n_routes; i++) {
+ net=subnet_to_string(&st->routes[i].net);
+ Message(c,"%s ",net);
+ free(net);
+ }
+ Message(c,"\n");
+ } else {
+ Message(c,"%s: routing table:\n",st->name);
+ for (i=0; i<st->n_routes; i++) {
+ net=subnet_to_string(&st->routes[i].net);
+ Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d,use %d)\n",net,
+ st->routes[i].c->name,
+ st->routes[i].hard?"hard":"soft",
+ st->routes[i].allow_route?"free":"restricted",
+ st->routes[i].up?"up":"down",
+ st->routes[i].quality,
+ st->routes[i].outcount);
+ free(net);
+ }
+ net=ipaddr_to_string(st->secnet_address);
+ Message(c,"%s/32 -> netlink \"%s\" (use %d)\n",
+ net,st->name,st->localcount);
free(net);
+ for (i=0; i<st->networks.entries; i++) {
+ net=subnet_to_string(&st->networks.list[i]);
+ Message(c,"%s -> host (use %d)\n",net,st->outcount);
+ free(net);
+ }
}
}
struct netlink_client *c;
uint32_t i,j;
- if (!st->clients && st->ptp) {
- /* Point-to-point netlink devices must have precisely one
- client. If none has registered by now, complain. */
- fatal("%s: point-to-point netlink devices must have precisely "
- "one client. This one doesn't have any.\n",st->name);
- }
-
/* All the networks serviced by the various tunnels should now
* have been registered. We build a routing table by sorting the
* routes into most-specific-first order. */
/* Fill the table */
i=0;
for (c=st->clients; c; c=c->next) {
- for (j=0; j<c->networks->entries; j++) {
- st->routes[i].net=c->networks->list[j];
+ for (j=0; j<c->networks.entries; j++) {
+ st->routes[i].net=c->networks.list[j];
st->routes[i].c=c;
/* Hard routes are always up;
- soft routes default to down */
- st->routes[i].up=c->options&NETLINK_OPTION_SOFTROUTE?False:True;
+ soft routes default to down; routes with no 'deliver' function
+ default to down */
+ st->routes[i].up=c->deliver?
+ (c->options&OPT_SOFTROUTE?False:True):
+ False;
st->routes[i].kup=False;
- st->routes[i].hard=c->options&NETLINK_OPTION_SOFTROUTE?False:True;
- st->routes[i].allow_route=c->options&NETLINK_OPTION_ALLOW_ROUTE?
+ st->routes[i].hard=c->options&OPT_SOFTROUTE?False:True;
+ st->routes[i].allow_route=c->options&OPT_ALLOWROUTE?
True:False;
st->routes[i].quality=c->link_quality;
+ st->routes[i].outcount=0;
i++;
}
}
netlink_dump_routes(st,True);
}
+static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver,
+ void *dst, uint32_t max_start_pad,
+ uint32_t max_end_pad)
+{
+ struct netlink_client *c=sst;
+ struct netlink *st=c->nst;
+
+ if (max_start_pad > st->max_start_pad) st->max_start_pad=max_start_pad;
+ if (max_end_pad > st->max_end_pad) st->max_end_pad=max_end_pad;
+ c->deliver=deliver;
+ c->dst=dst;
+}
+
+static struct flagstr netlink_option_table[]={
+ { "soft", OPT_SOFTROUTE },
+ { "allow-route", OPT_ALLOWROUTE },
+ { NULL, 0}
+};
+/* This is the routine that gets called when the closure that's
+ returned by an invocation of a netlink device closure (eg. tun,
+ userv-ipif) is invoked. It's used to create routes and pass in
+ information about them; the closure it returns is used by site
+ code. */
+static closure_t *netlink_inst_create(struct netlink *st,
+ struct cloc loc, dict_t *dict)
+{
+ struct netlink_client *c;
+ string_t name;
+ struct subnet_list networks;
+ uint32_t options;
+
+ name=dict_read_string(dict, "name", True, st->name, loc);
+
+ dict_read_subnet_list(dict, "routes", True, st->name, loc,
+ &networks);
+ options=string_list_to_word(dict_lookup(dict,"options"),
+ netlink_option_table,st->name);
+
+ if ((options&OPT_SOFTROUTE) && !st->set_route) {
+ cfgfatal(loc,st->name,"this netlink device does not support "
+ "soft routes.\n");
+ return NULL;
+ }
+
+ if (options&OPT_SOFTROUTE) {
+ /* XXX for now we assume that soft routes require root privilege;
+ this may not always be true. The device driver can tell us. */
+ require_root_privileges=True;
+ require_root_privileges_explanation="netlink: soft routes";
+ if (st->ptp) {
+ cfgfatal(loc,st->name,"point-to-point netlinks do not support "
+ "soft routes.\n");
+ return NULL;
+ }
+ }
+
+ /* Check that nets do not intersect st->exclude_remote_networks;
+ refuse to register if they do. */
+ if (subnet_lists_intersect(&st->exclude_remote_networks,&networks)) {
+ cfgfatal(loc,st->name,"networks intersect with the explicitly "
+ "excluded remote networks\n");
+ return NULL;
+ }
+
+ c=safe_malloc(sizeof(*c),"netlink_inst_create");
+ c->cl.description=name;
+ c->cl.type=CL_NETLINK;
+ c->cl.apply=NULL;
+ c->cl.interface=&c->ops;
+ c->ops.st=c;
+ c->ops.reg=netlink_inst_reg;
+ c->ops.deliver=netlink_inst_incoming;
+ c->ops.set_quality=netlink_set_quality;
+ c->nst=st;
+
+ c->networks=networks;
+ c->deliver=NULL;
+ c->dst=NULL;
+ c->name=name;
+ c->options=options;
+ c->link_quality=LINK_QUALITY_DOWN;
+ c->next=st->clients;
+ st->clients=c;
+ st->n_routes+=networks.entries;
+
+ return &c->cl;
+}
+
+static list_t *netlink_inst_apply(closure_t *self, struct cloc loc,
+ dict_t *context, list_t *args)
+{
+ struct netlink *st=self->interface;
+
+ dict_t *dict;
+ item_t *item;
+ closure_t *cl;
+
+ Message(M_DEBUG_CONFIG,"netlink_inst_apply\n");
+
+ item=list_elem(args,0);
+ if (!item || item->type!=t_dict) {
+ cfgfatal(loc,st->name,"must have a dictionary argument\n");
+ }
+ dict=item->data.dict;
+
+ cl=netlink_inst_create(st,loc,dict);
+
+ return new_closure(cl);
+}
+
netlink_deliver_fn *netlink_init(struct netlink *st,
void *dst, struct cloc loc,
dict_t *dict, string_t description,
st->dst=dst;
st->cl.description=description;
- st->cl.type=CL_NETLINK;
- st->cl.apply=NULL;
- st->cl.interface=&st->ops;
- st->ops.st=st;
- st->ops.regnets=netlink_regnets;
- st->ops.deliver=netlink_incoming;
- st->ops.set_quality=netlink_set_quality;
+ st->cl.type=CL_PURE;
+ st->cl.apply=netlink_inst_apply;
+ st->cl.interface=st;
st->max_start_pad=0;
st->max_end_pad=0;
st->clients=NULL;
&st->networks);
dict_read_subnet_list(dict, "exclude-remote-networks", False, "netlink",
loc, &st->exclude_remote_networks);
- /* secnet-address does not have to be in local-networks;
- however, it should be advertised in the 'sites' file for the
- local site. */
sa=dict_find_item(dict,"secnet-address",False,"netlink",loc);
- ptpa=dict_find_item(dict,"ptp-address", False, "netlink", loc);
+ ptpa=dict_find_item(dict,"ptp-address",False,"netlink",loc);
if (sa && ptpa) {
cfgfatal(loc,st->name,"you may not specify secnet-address and "
"ptp-address in the same netlink device\n");
buffer_new(&st->icmp,ICMP_BUFSIZE);
st->n_routes=0;
st->routes=NULL;
+ st->outcount=0;
+ st->localcount=0;
add_hook(PHASE_SETUP,netlink_phase_hook,st);
request_signal_notification(SIGUSR1, netlink_signal_handler, st);
- return netlink_incoming;
+ /* If we're point-to-point then we return a CL_NETLINK directly,
+ rather than a CL_NETLINK_OLD or pure closure (depending on
+ compatibility). This CL_NETLINK is for our one and only
+ client. Our cl.apply function is NULL. */
+ if (st->ptp) {
+ closure_t *cl;
+ cl=netlink_inst_create(st,loc,dict);
+ st->cl=*cl;
+ }
+ return netlink_dev_incoming;
}
/* No connection to the kernel at all... */
return False;
}
-static void null_deliver(void *sst, void *cid, struct buffer_if *buf)
+static void null_deliver(void *sst, struct buffer_if *buf)
{
return;
}
#define DEFAULT_MTU 1000
#define ICMP_BUFSIZE 1024
+struct netlink;
+
struct netlink_client {
- struct subnet_list *networks;
+ closure_t cl;
+ struct netlink_if ops;
+ struct netlink *nst;
+ struct subnet_list networks;
netlink_deliver_fn *deliver;
void *dst;
string_t name;
bool_t up;
bool_t kup;
uint32_t quality; /* provided by client */
+ uint32_t outcount;
struct netlink_client *c;
};
struct netlink {
closure_t cl;
- struct netlink_if ops;
void *dst; /* Pointer to host interface state */
string_t name;
uint32_t max_start_pad;
uint32_t max_end_pad;
struct subnet_list networks;
struct subnet_list exclude_remote_networks;
- uint32_t secnet_address; /* our own address, or possibly the address of
- the other end of a point-to-point link */
+ uint32_t secnet_address; /* our own address, or the address of the
+ other end of a point-to-point link */
bool_t ptp;
uint32_t mtu;
struct netlink_client *clients;
struct buffer_if icmp; /* Buffer for assembly of outgoing ICMP */
uint32_t n_routes; /* How many routes do we know about? */
struct netlink_route *routes;
+ uint32_t outcount; /* Packets sent to host */
+ uint32_t localcount; /* Packets sent to secnet */
};
extern netlink_deliver_fn *netlink_init(struct netlink *st,
break;
case 'v':
- message_level|=M_INFO|M_NOTICE|M_WARNING|M_ERROR|M_SECURITY|
+ message_level|=M_INFO|M_NOTICE|M_WARNING|M_ERR|M_SECURITY|
M_FATAL;
break;
break;
default:
- Message(M_ERROR,"secnet: Unknown getopt code %c\n",c);
+ Message(M_ERR,"secnet: Unknown getopt code %c\n",c);
}
}
if (argc-optind != 0) {
- Message(M_ERROR,"secnet: You gave extra command line parameters, "
+ Message(M_ERR,"secnet: You gave extra command line parameters, "
"which were ignored.\n");
}
}
#define M_INFO 0x008
#define M_NOTICE 0x010
#define M_WARNING 0x020
-#define M_ERROR 0x040
+#define M_ERR 0x040
#define M_SECURITY 0x080
#define M_FATAL 0x100
/* Module initialisation function type - modules export one function of
this type which is called to initialise them. For dynamically loaded
modules it's called "secnet_module". */
-typedef void (init_module)(dict_t *dict);
+typedef void init_module(dict_t *dict);
/***** END of module support *****/
/***** CLOSURE TYPES and interface definitions *****/
-#define CL_PURE 0
-#define CL_RESOLVER 1
-#define CL_RANDOMSRC 2
-#define CL_RSAPUBKEY 3
-#define CL_RSAPRIVKEY 4
-#define CL_COMM 5
-#define CL_IPIF 6
-#define CL_LOG 7
-#define CL_SITE 8
-#define CL_TRANSFORM 9
-#define CL_NETLINK 10
-#define CL_DH 11
-#define CL_HASH 12
-#define CL_BUFFER 13
+#define CL_PURE 0
+#define CL_RESOLVER 1
+#define CL_RANDOMSRC 2
+#define CL_RSAPUBKEY 3
+#define CL_RSAPRIVKEY 4
+#define CL_COMM 5
+#define CL_IPIF 6
+#define CL_LOG 7
+#define CL_SITE 8
+#define CL_TRANSFORM 9
+#define CL_DH 11
+#define CL_HASH 12
+#define CL_BUFFER 13
+#define CL_NETLINK 14
struct buffer_if;
netlink_regnets_fn. If buf has size 0 then the function is just
being called for its site-effects (eg. making the site code attempt
to bring up a network link) */
-typedef void netlink_deliver_fn(void *st, void *cid, struct buffer_if *buf);
+typedef void netlink_deliver_fn(void *st, struct buffer_if *buf);
/* site code can tell netlink when outgoing packets will be dropped,
so netlink can generate appropriate ICMP and make routing decisions */
#define LINK_QUALITY_DOWN 0 /* No chance of a packet being delivered */
#define LINK_QUALITY_DOWN_CURRENT_ADDRESS 2 /* Link down, current address information */
#define LINK_QUALITY_UP 3 /* Link active */
#define MAXIMUM_LINK_QUALITY 3
-typedef void netlink_link_quality_fn(void *st, void *cid, uint32_t quality);
-/* Register for packets from specified networks. Return value is
- client identifier. 'hard_route' indicates whether the routes being
- registered are permanent (hard) or temporary (soft); some types of
- netlink device can only cope with hard routes. */
-#define NETLINK_OPTION_SOFTROUTE 1
-#define NETLINK_OPTION_ALLOW_ROUTE 2
-typedef void *netlink_regnets_fn(void *st, struct subnet_list *networks,
- netlink_deliver_fn *deliver, void *dst,
- uint32_t max_start_pad, uint32_t max_end_pad,
- uint32_t options, string_t client_name);
+typedef void netlink_link_quality_fn(void *st, uint32_t quality);
+typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver,
+ void *dst, uint32_t max_start_pad,
+ uint32_t max_end_pad);
struct netlink_if {
void *st;
- netlink_regnets_fn *regnets;
+ netlink_register_fn *reg;
netlink_deliver_fn *deliver;
netlink_link_quality_fn *set_quality;
};
/* site.c - manage communication with a remote network site */
+/* The 'site' code doesn't know anything about the structure of the
+ packets it's transmitting. In fact, under the new netlink
+ configuration scheme it doesn't need to know anything at all about
+ IP addresses, except how to contact its peer. This means it could
+ potentially be used to tunnel other protocols too (IPv6, IPX, plain
+ old Ethernet frames) if appropriate netlink code can be written
+ (and that ought not to be too hard, eg. using the TUN/TAP device to
+ pretend to be an Ethernet interface). */
+
#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 "ipaddr.h"
#include "unaligned.h"
#define SETUP_BUFFER_LEN 2048
{ NULL, 0 }
};
-static struct flagstr netlink_option_table[]={
- { "soft", NETLINK_OPTION_SOFTROUTE },
- { "allow-route", NETLINK_OPTION_ALLOW_ROUTE },
- { NULL, 0}
-};
-
struct site {
closure_t cl;
struct site_if ops;
struct log_if *log;
struct random_if *random;
struct rsaprivkey_if *privkey;
- struct subnet_list remotenets;
struct rsapubkey_if *pubkey;
struct transform_if *transform;
struct dh_if *dh;
uint32_t state;
uint64_t now; /* Most recently seen time */
- void *netlink_cid;
-
uint32_t remote_session_id;
struct transform_inst_if *current_transform;
bool_t current_valid;
case LOG_STATE: class=M_DEBUG; break;
case LOG_DROP: class=M_DEBUG; break;
case LOG_DUMP: class=M_DEBUG; break;
- case LOG_ERROR: class=M_ERROR; break;
- default: class=M_ERROR; break;
+ case LOG_ERROR: class=M_ERR; break;
+ default: class=M_ERR; break;
}
vsnprintf(buf,240,msg,ap);
switch(type) {
case LABEL_MSG9:
/* Deliver to netlink layer */
- st->netlink->deliver(st->netlink->st,st->netlink_cid,msg0);
+ st->netlink->deliver(st->netlink->st,msg0);
return True;
break;
default:
else
quality=LINK_QUALITY_DOWN;
- st->netlink->set_quality(st->netlink->st,st->netlink_cid,quality);
+ st->netlink->set_quality(st->netlink->st,quality);
}
static void enter_state_run(struct site *st)
/* This function is called by the netlink device to deliver packets
intended for the remote network. The packet is in "raw" wire
format, but is guaranteed to be word-aligned. */
-static void site_outgoing(void *sst, void *cid, struct buffer_if *buf)
+static void site_outgoing(void *sst, struct buffer_if *buf)
{
struct site *st=sst;
string_t transform_err;
struct site *st;
item_t *item;
dict_t *dict;
- uint32_t netlink_options;
st=safe_malloc(sizeof(*st),"site_apply");
free(st);
return NULL;
}
- st->netlink=find_cl_if(dict,"netlink",CL_NETLINK,True,"site",loc);
+ st->netlink=find_cl_if(dict,"link",CL_NETLINK,True,"site",loc);
st->comm=find_cl_if(dict,"comm",CL_COMM,True,"site",loc);
st->resolver=find_cl_if(dict,"resolver",CL_RESOLVER,True,"site",loc);
st->log=find_cl_if(dict,"log",CL_LOG,True,"site",loc);
if (st->address)
st->remoteport=dict_read_number(dict,"port",True,"site",loc,0);
else st->remoteport=0;
- dict_read_subnet_list(dict, "networks", True, "site", loc,
- &st->remotenets);
st->pubkey=find_cl_if(dict,"key",CL_RSAPUBKEY,True,"site",loc);
st->transform=
st->log_events=string_list_to_word(dict_lookup(dict,"log-events"),
log_event_table,"site");
- netlink_options=string_list_to_word(dict_lookup(dict,"netlink-options"),
- netlink_option_table,"site");
-
st->tunname=safe_malloc(strlen(st->localname)+strlen(st->remotename)+5,
"site_apply");
sprintf(st->tunname,"%s<->%s",st->localname,st->remotename);
st->sharedsecret=safe_malloc(st->transform->keylen,"site:sharedsecret");
/* We need to register the remote networks with the netlink device */
- st->netlink_cid=st->netlink->regnets(st->netlink->st, &st->remotenets,
- site_outgoing, st,
- st->transform->max_start_pad+(4*4),
- st->transform->max_end_pad,
- netlink_options, st->tunname);
- if (!st->netlink_cid) {
- Message(M_WARNING,"%s: netlink device did not let us register "
- "our remote networks. This site will not start.\n",
- st->tunname);
- return NULL; /* XXX should free site first */
- }
+ st->netlink->reg(st->netlink->st, site_outgoing, st,
+ st->transform->max_start_pad+(4*4),
+ st->transform->max_end_pad);
st->comm->request_notify(st->comm->st, st, site_incoming);
switch (buf[i]) {
case SLIP_END:
if (st->buff->size>0) {
- st->netlink_to_tunnel(&st->nl,NULL,
- st->buff);
+ st->netlink_to_tunnel(&st->nl,st->buff);
BUF_ALLOC(st->buff,"userv_afterpoll");
}
buffer_init(st->buff,st->nl.max_start_pad);
if (nfds==0) return;
if (fds[1].revents&POLLERR) {
- Message(M_ERROR,"%s: userv_afterpoll: POLLERR!\n",st->slip.nl.name);
+ Message(M_ERR,"%s: userv_afterpoll: POLLERR!\n",st->slip.nl.name);
}
if (fds[1].revents&POLLIN) {
l=read(st->rxfd,rxbuf,DEFAULT_BUFSIZE);
}
/* Send buf to the kernel. Free buf before returning. */
-static void userv_deliver_to_kernel(void *sst, void *cid,
- struct buffer_if *buf)
+static void userv_deliver_to_kernel(void *sst, struct buffer_if *buf)
{
struct userv *st=sst;
struct userv_entry_rec {
string_t path;
char **argv;
- int stdin;
- int stdout;
+ int in;
+ int out;
/* XXX perhaps we should collect and log stderr? */
};
{
struct userv_entry_rec *st=sst;
- dup2(st->stdin,0);
- dup2(st->stdout,1);
+ dup2(st->in,0);
+ dup2(st->out,1);
/* XXX close all other fds */
setsid();
er=safe_malloc(sizeof(*r),"userv_invoke_userv: er");
- er->stdin=c_stdin[0];
- er->stdout=c_stdout[1];
+ er->in=c_stdin[0];
+ er->out=c_stdout[1];
/* The arguments are:
userv
service-user
st->pid=makesubproc(userv_entry, userv_userv_callback,
er, st, st->slip.nl.name);
- close(er->stdin);
- close(er->stdout);
+ close(er->in);
+ close(er->out);
free(er->argv);
free(er);
free(addrs);
the packets sent over the wire. */
#include <stdio.h>
+#include <string.h>
#include "secnet.h"
#include "util.h"
#include "serpent.h"
struct transform_inst *ti=sst;
if (keylen<REQUIRED_KEYLEN) {
- Message(M_ERROR,"transform_create: insufficient key material supplied "
+ Message(M_ERR,"transform_create: insufficient key material supplied "
"(need %d bytes, got %d)\n",REQUIRED_KEYLEN,keylen);
return False;
}
}
if (l>0) {
st->buff->size=l;
- st->netlink_to_tunnel(&st->nl,NULL,st->buff);
+ st->netlink_to_tunnel(&st->nl,st->buff);
BUF_ASSERT_FREE(st->buff);
}
}
}
-static void tun_deliver_to_kernel(void *sst, void *cid,
- struct buffer_if *buf)
+static void tun_deliver_to_kernel(void *sst, struct buffer_if *buf)
{
struct tun *st=sst;
st->netlink_to_tunnel=
netlink_init(&st->nl,st,loc,dict,
- "netlink-tun",NULL,tun_deliver_to_kernel);
+ "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);