From 469fd1d95b2528212a46b155cb115c078de4228f Mon Sep 17 00:00:00 2001 From: Stephen Early Date: Mon, 22 Oct 2001 14:13:00 +0100 Subject: [PATCH] Import release 0.1.10 --- Makefile.in | 6 +- NEWS | 82 ++++++++- README | 54 ++++-- TODO | 10 +- conffile.c | 12 +- config.h.bot | 2 + config.h.in | 11 ++ configure | 266 +++++++++++++++++++++++---- configure.in | 8 +- debian/changelog | 2 +- example.conf | 3 +- ipaddr.c | 3 +- log.c | 12 +- make-secnet-sites | 12 +- netlink.c | 446 +++++++++++++++++++++++++++++----------------- netlink.h | 15 +- secnet.c | 6 +- secnet.h | 51 +++--- site.c | 52 ++---- slip.c | 24 ++- transform.c | 3 +- tun.c | 7 +- 22 files changed, 749 insertions(+), 338 deletions(-) diff --git a/Makefile.in b/Makefile.in index c8a67ad..0e4926c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -15,10 +15,10 @@ # 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@ @@ -132,6 +132,8 @@ realclean: clean config.log config.status config.cache \ stamp-h Makefile.bak +distclean: realclean + pfname:=$(PACKAGE)-$(VERSION) dist: $(RM) -rf $(pfname) diff --git a/NEWS b/NEWS index c26e086..be5c38a 100644 --- a/NEWS +++ b/NEWS @@ -1,13 +1,83 @@ * 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 diff --git a/README b/README index 255892d..4fe279d 100644 --- a/README +++ b/README @@ -34,6 +34,20 @@ providing complete links between multiple sites to a simple 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 ; they will be +forwarded to the -discuss list by me. + * Creating a VPN XXX TODO @@ -151,7 +165,17 @@ in configuration space to tell it what to do: * 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 @@ -247,7 +271,7 @@ Defines: 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) @@ -255,7 +279,6 @@ site: dict argument 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) @@ -282,12 +305,6 @@ site: dict argument 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 @@ -297,7 +314,7 @@ Defines: ** 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 @@ -309,9 +326,20 @@ null-netlink: dict argument 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. diff --git a/TODO b/TODO index f32d109..5ae53cf 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,7 @@ ipaddr.c: implement the useful functionality from ipaddr.py 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 @@ -27,13 +27,11 @@ fails in use? 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. diff --git a/conffile.c b/conffile.c index e9c84d3..f33354e 100644 --- a/conffile.c +++ b/conffile.c @@ -335,6 +335,9 @@ static list_t *process_invocation(dict_t *context, struct p_node *i) 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); } @@ -725,6 +728,13 @@ static struct subnet string_to_subnet(item_t *i, string_t desc) 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. */ @@ -740,7 +750,7 @@ static struct subnet string_to_subnet(item_t *i, string_t desc) 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 " diff --git a/config.h.bot b/config.h.bot index 68a2684..889736c 100644 --- a/config.h.bot +++ b/config.h.bot @@ -44,6 +44,8 @@ typedef unsigned char uint8_t; #endif #ifndef HAVE_SNPRINTF +#include +#include #include "snprintf.h" #endif diff --git a/config.h.in b/config.h.in index 1984cee..d7044fc 100644 --- a/config.h.in +++ b/config.h.in @@ -79,6 +79,15 @@ /* 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. */ @@ -125,6 +134,8 @@ typedef unsigned char uint8_t; #endif #ifndef HAVE_SNPRINTF +#include +#include #include "snprintf.h" #endif diff --git a/configure b/configure index fb7aef3..3c5ffcb 100755 --- a/configure +++ b/configure @@ -1549,8 +1549,55 @@ else 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 <&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 <&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 @@ -1558,7 +1605,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lfl $LIBS" cat > conftest.$ac_ext <&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 @@ -1596,27 +1643,27 @@ 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 <&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 @@ -1631,20 +1678,20 @@ 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' \ + ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` cat >> confdefs.h <&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 @@ -1652,7 +1699,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lgetopt $LIBS" cat > conftest.$ac_ext <&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 @@ -1691,7 +1738,7 @@ 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 @@ -1699,7 +1746,7 @@ else ac_save_LIBS="$LIBS" LIBS="-lgnugetopt $LIBS" cat > conftest.$ac_ext <&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 @@ -1737,17 +1784,158 @@ 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 <&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 <&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 <&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 <&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 <&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 <&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 <&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 @@ -1798,12 +1986,12 @@ done 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 <&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 @@ -1854,19 +2042,19 @@ done # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6 -echo "configure: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 < 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 @@ -1887,12 +2075,12 @@ EOF 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 <&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 @@ -1952,12 +2140,12 @@ EOF 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 <&6 if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure: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 <&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 @@ -2037,7 +2225,7 @@ done 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 @@ -2045,7 +2233,7 @@ else ac_cv_c_stack_direction=0 else cat > conftest.$ac_ext <&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 diff --git a/configure.in b/configure.in index 3fc0cd2..8bc960e 100644 --- a/configure.in +++ b/configure.in @@ -21,12 +21,18 @@ AC_CHECK_SIZEOF(unsigned int) 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) diff --git a/debian/changelog b/debian/changelog index 23f75ae..2011174 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -secnet (0.1.9-1) unstable; urgency=low +secnet (0.1.10-1) unstable; urgency=low * New upstream version. diff --git a/example.conf b/example.conf index 189b442..49f2540 100644 --- a/example.conf +++ b/example.conf @@ -69,6 +69,7 @@ netlink tun { 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 @@ -109,7 +110,7 @@ netlink tun { # 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); }; diff --git a/ipaddr.c b/ipaddr.c index 2dc5928..f42e820 100644 --- a/ipaddr.c +++ b/ipaddr.c @@ -74,7 +74,8 @@ string_t subnet_to_string(struct subnet *sn) 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; diff --git a/log.c b/log.c index dd51b25..32f0901 100644 --- a/log.c +++ b/log.c @@ -8,7 +8,7 @@ #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) @@ -32,7 +32,7 @@ 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); @@ -271,11 +271,11 @@ static struct flagstr message_class_table[]={ { "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 } }; @@ -334,7 +334,7 @@ static int msgclass_to_syslogpriority(uint32_t m) 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; diff --git a/make-secnet-sites b/make-secnet-sites index fb88028..5d6de21 100755 --- a/make-secnet-sites +++ b/make-secnet-sites @@ -58,7 +58,7 @@ sys.path.append("/usr/local/share/secnet") sys.path.append("/usr/share/secnet") import ipaddr -VERSION="0.1.9" +VERSION="0.1.10" class vpn: def __init__(self,name): @@ -100,12 +100,12 @@ class nets: 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): diff --git a/netlink.c b/netlink.c index b7cdb4c..4426a7c 100644 --- a/netlink.c +++ b/netlink.c @@ -14,6 +14,9 @@ #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) { @@ -262,9 +265,8 @@ static bool_t netlink_check(struct netlink *st, struct buffer_if *buf) 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) @@ -273,84 +275,105 @@ static void netlink_packet_deliver(struct netlink *st, 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; in_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; in_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); } @@ -385,6 +408,8 @@ static void netlink_packet_local(struct netlink *st, { struct icmphdr *h; + st->localcount++; + h=(struct icmphdr *)buf->start; if ((ntohs(h->iph.frag_off)&0xbfff)!=0) { @@ -422,10 +447,9 @@ static void netlink_packet_local(struct netlink *st, /* 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; @@ -445,7 +469,7 @@ static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf) 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); @@ -476,9 +500,9 @@ static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf) 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; @@ -509,6 +533,21 @@ static void netlink_incoming(void *sst, void *cid, struct buffer_if *buf) 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) { @@ -526,10 +565,10 @@ static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c, } } -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) { @@ -539,62 +578,6 @@ static void netlink_set_quality(void *sst, void *cid, uint32_t quality) } } -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; @@ -602,23 +585,39 @@ static void netlink_dump_routes(struct netlink *st, bool_t requested) uint32_t c=M_INFO; if (requested) c=M_WARNING; - Message(c,"%s: routing table:\n",st->name); - for (i=0; in_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; inetworks.entries; i++) { - net=subnet_to_string(&st->networks.list[i]); - Message(c,"%s -> host\n",net); + for (i=0; in_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; in_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; inetworks.entries; i++) { + net=subnet_to_string(&st->networks.list[i]); + Message(c,"%s -> host (use %d)\n",net,st->outcount); + free(net); + } } } @@ -638,13 +637,6 @@ static void netlink_phase_hook(void *sst, uint32_t new_phase) 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. */ @@ -653,17 +645,21 @@ static void netlink_phase_hook(void *sst, uint32_t new_phase) /* Fill the table */ i=0; for (c=st->clients; c; c=c->next) { - for (j=0; jnetworks->entries; j++) { - st->routes[i].net=c->networks->list[j]; + for (j=0; jnetworks.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++; } } @@ -686,6 +682,116 @@ static void netlink_signal_handler(void *sst, int signum) 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, @@ -696,13 +802,9 @@ netlink_deliver_fn *netlink_init(struct netlink *st, 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; @@ -715,11 +817,8 @@ netlink_deliver_fn *netlink_init(struct netlink *st, &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"); @@ -739,11 +838,22 @@ netlink_deliver_fn *netlink_init(struct netlink *st, 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... */ @@ -768,7 +878,7 @@ static bool_t null_set_route(void *sst, struct netlink_route *route) 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; } diff --git a/netlink.h b/netlink.h index 4cc80af..c13b0ae 100644 --- a/netlink.h +++ b/netlink.h @@ -7,8 +7,13 @@ #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; @@ -24,6 +29,7 @@ struct netlink_route { bool_t up; bool_t kup; uint32_t quality; /* provided by client */ + uint32_t outcount; struct netlink_client *c; }; @@ -35,15 +41,14 @@ typedef bool_t netlink_route_fn(void *cst, struct netlink_route *route); 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; @@ -52,6 +57,8 @@ struct netlink { 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, diff --git a/secnet.c b/secnet.c index 57b4f05..a3cf153 100644 --- a/secnet.c +++ b/secnet.c @@ -106,7 +106,7 @@ static void parse_options(int argc, char **argv) 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; @@ -141,12 +141,12 @@ static void parse_options(int argc, char **argv) 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"); } } diff --git a/secnet.h b/secnet.h index 2535030..3821b81 100644 --- a/secnet.h +++ b/secnet.h @@ -135,7 +135,7 @@ extern uint32_t string_list_to_word(list_t *l, struct flagstr *f, #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 @@ -220,26 +220,26 @@ extern string_t require_root_privileges_explanation; /* 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; @@ -374,7 +374,7 @@ struct transform_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 */ @@ -382,21 +382,14 @@ typedef void netlink_deliver_fn(void *st, void *cid, struct buffer_if *buf); #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; }; diff --git a/site.c b/site.c index 8223fb3..fc045c9 100644 --- a/site.c +++ b/site.c @@ -1,13 +1,22 @@ /* 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 +#include /* MBM asserts the next one is needed for compilation under BSD. */ #include #include #include "util.h" -#include "ipaddr.h" #include "unaligned.h" #define SETUP_BUFFER_LEN 2048 @@ -120,12 +129,6 @@ static struct flagstr log_event_table[]={ { 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; @@ -141,7 +144,6 @@ struct site { 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; @@ -168,8 +170,6 @@ struct site { 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; @@ -210,8 +210,8 @@ static void slog(struct site *st, uint32_t event, string_t msg, ...) 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); @@ -636,7 +636,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0, 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: @@ -770,7 +770,7 @@ static void set_link_quality(struct site *st) 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) @@ -954,7 +954,7 @@ static void site_afterpoll(void *sst, struct pollfd *fds, int nfds, /* 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; @@ -1142,7 +1142,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, struct site *st; item_t *item; dict_t *dict; - uint32_t netlink_options; st=safe_malloc(sizeof(*st),"site_apply"); @@ -1171,7 +1170,7 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, 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); @@ -1182,8 +1181,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, 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= @@ -1216,9 +1213,6 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, 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); @@ -1249,17 +1243,9 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context, 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); diff --git a/slip.c b/slip.c index cff8f63..d0a77c0 100644 --- a/slip.c +++ b/slip.c @@ -91,8 +91,7 @@ static void slip_unstuff(struct slip *st, uint8_t *buf, uint32_t l) 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); @@ -162,7 +161,7 @@ static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds, 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); @@ -178,8 +177,7 @@ static void userv_afterpoll(void *sst, struct pollfd *fds, int nfds, } /* 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; @@ -214,8 +212,8 @@ static void userv_userv_callback(void *sst, pid_t pid, int status) 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? */ }; @@ -223,8 +221,8 @@ static void userv_entry(void *sst) { 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(); @@ -288,8 +286,8 @@ static void userv_invoke_userv(struct userv *st) 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 @@ -307,8 +305,8 @@ static void userv_invoke_userv(struct userv *st) 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); diff --git a/transform.c b/transform.c index 4c55b45..dba0ef8 100644 --- a/transform.c +++ b/transform.c @@ -8,6 +8,7 @@ the packets sent over the wire. */ #include +#include #include "secnet.h" #include "util.h" #include "serpent.h" @@ -53,7 +54,7 @@ static bool_t transform_setkey(void *sst, uint8_t *key, uint32_t keylen) struct transform_inst *ti=sst; if (keylen0) { 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; @@ -261,7 +260,7 @@ static list_t *tun_old_apply(closure_t *self, struct cloc loc, dict_t *context, 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); -- 2.30.2