chiark / gitweb /
Import release 0.1.11 v0.1.11
authorStephen Early <steve@greenend.org.uk>
Sat, 27 Oct 2001 14:29:00 +0000 (15:29 +0100)
committerStephen Early <steve@greenend.org.uk>
Wed, 18 May 2011 17:38:55 +0000 (18:38 +0100)
27 files changed:
BUGS [new file with mode: 0644]
INSTALL
Makefile.in
NEWS
NOTES
TODO
conffile.c
config.h.bot
config.h.in
debian/changelog
debian/files [deleted file]
debian/postinst.debhelper [deleted file]
debian/postrm.debhelper [deleted file]
debian/prerm.debhelper [deleted file]
debian/rules
debian/substvars [deleted file]
ipaddr.c
ipaddr.h
netlink.c
netlink.h
process.c
secnet.c
secnet.h
site.c
slip.c
tun.c
udp.c

diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..7145f3a
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,2 @@
+Known bugs in secnet
+
diff --git a/INSTALL b/INSTALL
index ab4debdc87ab6f59e04b0741ed64c024a85fbbf0..f41b4ba253b320f4ef518170280782eb0b56f991 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -32,11 +32,11 @@ linux/Documentation/networking/tuntap.txt
 If you're using TUN/TAP on a platform other than Linux-2.4, see
 http://vtun.sourceforge.net/tun/
 
 If you're using TUN/TAP on a platform other than Linux-2.4, see
 http://vtun.sourceforge.net/tun/
 
-Note than TUN comes in two flavours, one (called 'tun' in the secnet
-config file) which has only one device file (usually /dev/net/tun) and
-the other (called 'tun-old') which has many device files (/dev/tun*).
-Linux-2.4 has new-style TUN, Linux-2.2, BSD and Solaris have old-style
-TUN.
+Note than TUN comes in several flavours.  Their names in the
+configuration file are:
+ tun:  Linux-2.4; only one device file (usually /dev/net/tun)
+ tun-old:  Linux-2.2, BSD; device files /dev/tun*
+ tun-solaris:  Solaris (not yet implemented)
 
 ** System and network configuration
 
 
 ** System and network configuration
 
@@ -54,18 +54,18 @@ modify the routing table.)
 If you are joining an existing VPN, read that VPN's documentation now.
 It may supersede the next paragraph.
 
 If you are joining an existing VPN, read that VPN's documentation now.
 It may supersede the next paragraph.
 
-You will need to allocate two IP addresses for use by secnet.  One
-will be for the tunnel interface on your tunnel endpoint machine (i.e.
-the address you see in 'ifconfig' when you look at the tunnel
-interface).  The other will be for secnet itself.  These addresses
-should probably be allocated from the range used by your internal
-network: if you do this, you should provide appropriate proxy-ARP on
-the internal network interface of the machine running secnet (eg. add
-an entry net/ipv4/conf/eth_whatever/proxy_arp = 1 to /etc/sysctl.conf
-on Debian systems and run sysctl -p).  Alternatively the addresses
-could be from some other range - this works well if the machine
-running secnet is the default route out of your network - but this
-requires more thought.
+In most configurations, you will need to allocate two IP addresses for
+use by secnet.  One will be for the tunnel interface on your tunnel
+endpoint machine (i.e. the address you see in 'ifconfig' when you look
+at the tunnel interface).  The other will be for secnet itself.  These
+addresses should probably be allocated from the range used by your
+internal network: if you do this, you should provide appropriate
+proxy-ARP on the internal network interface of the machine running
+secnet (eg. add an entry net/ipv4/conf/eth_whatever/proxy_arp = 1 to
+/etc/sysctl.conf on Debian systems and run sysctl -p).  Alternatively
+the addresses could be from some other range - this works well if the
+machine running secnet is the default route out of your network - but
+this requires more thought.
 
 http://www.ucam.org/cam-grin/ may be useful.
 
 
 http://www.ucam.org/cam-grin/ may be useful.
 
@@ -83,10 +83,32 @@ $ make
 # mkdir /etc/secnet
 
 (Note: you may see the following warning while compiling
 # mkdir /etc/secnet
 
 (Note: you may see the following warning while compiling
-conffile.tab.c; I believe this is a bison bug:
+conffile.tab.c; this is a bug in bison-1.28:
 /usr/share/bison/bison.simple: In function `yyparse':
 /usr/share/bison/bison.simple:285: warning: `yyval' might be used
  uninitialized in this function
 /usr/share/bison/bison.simple: In function `yyparse':
 /usr/share/bison/bison.simple:285: warning: `yyval' might be used
  uninitialized in this function
+
+You may if you wish apply the following patch to bison.simple:
+diff -pu -r1.28.0.1 -r1.28.0.3
+--- bison.s1    1999/08/30 19:23:24     1.28.0.1
++++ bison.s1    1999/08/30 21:15:18     1.28.0.3
+@@ -523,8 +523,14 @@ yydefault:
+ /* Do a reduction.  yyn is the number of a rule to reduce with.  */
+ yyreduce:
+   yylen = yyr2[yyn];
+-  if (yylen > 0)
+-    yyval = yyvsp[1-yylen]; /* implement default value of the action */
++
++  /* If yylen is nonzero, implement the default value of the action.
++     Otherwise, the following line sets yyval to the semantic value of
++     the lookahead token.  This behavior is undocumented and bison
++     users should not rely upon it.  Assigning to yyval
++     unconditionally makes the parser a bit smaller, and it avoids a
++     GCC warning that yyval may be used uninitialized.  */
++  yyval = yyvsp[1-yylen];
+ #if YYDEBUG != 0
+   if (yydebug)
 )
 
 Any other warnings or errors should be reported to
 )
 
 Any other warnings or errors should be reported to
@@ -103,22 +125,23 @@ $ LDFLAGS="-L/usr/local/lib" ./configure
 $ gmake CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"
 XXX this should eventually be worked out automatically by 'configure'.]
 
 $ gmake CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"
 XXX this should eventually be worked out automatically by 'configure'.]
 
-Generate a site file fragment for your site (see below), and submit it
-for inclusion in your VPN's 'sites' file.  Download the vpn-sites file
-to /etc/secnet/sites - MAKE SURE YOU GET AN AUTHENTIC COPY because the
-sites file contains public keys for all the sites in the VPN.  Use the
-make-secnet-sites program provided with the secnet distribution to
-convert the distributed sites file into one that can be included in a
-secnet configuration file:
+Generate a site file fragment for your site (see your VPN's
+documentation, or see below), and submit it for inclusion in your
+VPN's 'sites' file.  Download the vpn-sites file to /etc/secnet/sites
+- MAKE SURE YOU GET AN AUTHENTIC COPY because the sites file contains
+public keys for all the sites in the VPN.  Use the make-secnet-sites
+program provided with the secnet distribution to convert the
+distributed sites file into one that can be included in a secnet
+configuration file:
 
 
-# make-secnet-sites sites sites.conf
+# make-secnet-sites /etc/secnet/sites /etc/secnet/sites.conf
 
 * Configuration
 
 Should be reasonably obvious - edit /etc/secnet/secnet.conf as
 
 * Configuration
 
 Should be reasonably obvious - edit /etc/secnet/secnet.conf as
-prompted by the comments.  XXX Fuller documentation of the
-configuration file format should be forthcoming in time.  Its syntax
-is described in the README file at the moment.
+prompted by the comments in example.conf.  XXX Fuller documentation of
+the configuration file format should be forthcoming in time.  Its
+syntax is described in the README file at the moment.
 
 * Constructing your site file fragment
 
 
 * Constructing your site file fragment
 
index 0e4926c0b590a311c88336ffdb141678c0ac7fcc..9a912b5d455b25d3370451b6580aef396a9b4be2 100644 (file)
@@ -18,7 +18,7 @@
 .PHONY:        all clean realclean dist install distclean
 
 PACKAGE:=secnet
 .PHONY:        all clean realclean dist install distclean
 
 PACKAGE:=secnet
-VERSION:=0.1.10
+VERSION:=0.1.11
 
 @SET_MAKE@
 
 
 @SET_MAKE@
 
@@ -48,7 +48,7 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \
        serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \
        process.o @LIBOBJS@
 
        serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \
        process.o @LIBOBJS@
 
-DISTFILES:=COPYING CREDITS INSTALL LICENSE.txt Makefile.in \
+DISTFILES:=BUGS COPYING CREDITS INSTALL LICENSE.txt Makefile.in \
        NEWS NOTES README TODO \
        alloca.c \
        conffile.c conffile.fl conffile.h conffile.y \
        NEWS NOTES README TODO \
        alloca.c \
        conffile.c conffile.fl conffile.h conffile.y \
diff --git a/NEWS b/NEWS
index be5c38ac77ff2b5a351976a472919920002a7fcc..60cf744e04edcf090abda86ddb185346b07c23b1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,7 +5,41 @@ Netlink device that implements an Ethernet bridge.
 Modular transform code: choice of block ciphers, modes, sequence
 numbers / timestamps, etc. similar to IWJ's udptunnel
 
 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.11
+
+Lists of IP addresses in the configuration file can now include
+exclusions as well as inclusions.  For example, you can specify all
+the hosts on a subnet except one as follows:
+
+networks "192.168.73.0/24","!192.168.73.70";
+
+(If you were only allowed inclusions, you'd have to specify that like
+this:
+networks "192.168.73.71/32","192.168.73.68/31","192.168.73.64/30",
+       "192.168.73.72/29","192.168.73.80/28","192.168.73.96/27",
+       "192.168.73.0/26","192.168.73.128/25";
+)
+
+secnet now ensures that it invokes userv-ipif with a non-overlapping
+list of subnets.
+
+There is a new command-line option, --sites-key or -s, that enables
+the configuration file key that's checked to determine the list of
+active sites (default "sites") to be changed.  This enables a single
+configuration file to contain multiple cofigurations conveniently.
+
+NAKs are now sent when packets arrive that are not understood.  The
+tunnel code initiates a key setup if it sees a NAK.  Future
+developments should include configuration options that control this.
+
+The tunnel code notifies its peer when secnet is terminating, so the
+peer can close the session.
+
+The netlink "exclude-remote-networks" option has now been replaced by
+a "remote-networks" option; instead of specifying networks that no
+site may access, you specify the set of networks that remote sites are
+allowed to access. A sensible example: "192.168.0.0/16",
+"172.16.0.0/12", "10.0.0.0/8", "!your-local-network"
 
 * New in version 0.1.10
 
 
 * New in version 0.1.10
 
diff --git a/NOTES b/NOTES
index 2443549cb67232ce64fe9b8f127ba20a31e32019..485443b1c13320836b6b1d7c0acd9a25e13dea1b 100644 (file)
--- a/NOTES
+++ b/NOTES
@@ -231,9 +231,7 @@ retransmit or confirm reception. It is suggested that this message be
 sent when a key times out, or the tunnel is forcibly terminated for
 some reason.
 
 sent when a key times out, or the tunnel is forcibly terminated for
 some reason.
 
-XXX not yet implemented.
-
-8) i?,i?,NAK/msg8
+8) i?,i?,NAK (encoded as zero)
 
 If the link-layer can't work out what to do with a packet (session has
 gone away, etc.) it can transmit a NAK back to the sender.  The sender
 
 If the link-layer can't work out what to do with a packet (session has
 gone away, etc.) it can transmit a NAK back to the sender.  The sender
diff --git a/TODO b/TODO
index 5ae53cf8cf4070b270c44950698b472112c63da6..e02c6279dd20ea5ae65abac430a61594d2647de7 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,16 +1,18 @@
 Makefile.in: autodep stuff
 Makefile.in: autodep stuff
+Make it work using the distributed install.sh (which doesn't support -D)
 
 dh.c: change format to binary from decimal string (without introducing
 endianness problems)
 
 
 dh.c: change format to binary from decimal string (without introducing
 endianness problems)
 
-ipaddr.c: implement the useful functionality from ipaddr.py
+netlink.c: test the 'allow_route' option properly.
 
 
-netlink.c: investigate why 'default' routes don't appear to work
-(reported by JDA).
-Test the 'allow_route' option properly.
+process.c: capture output from children in sys_cmd() and log it
 
 random.c: test
 
 
 random.c: test
 
+resolver.c: ought to return a list of addresses for each address; the
+site code ought to remember them and try contacting them in turn.
+
 rsa.c: check padding type, change format to binary from decimal string
 (without introducing endianness problems)
 
 rsa.c: check padding type, change format to binary from decimal string
 (without introducing endianness problems)
 
@@ -24,14 +26,8 @@ does it take to prompt a key exchange?)
 
 slip.c: restart userv-ipif to cope with soft routes? Restart it if it
 fails in use?
 
 slip.c: restart userv-ipif to cope with soft routes? Restart it if it
 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.
-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.
 
 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.
index f33354e6e075b36b38e2d20ad21c3c6ab9f2d5e1..3c629e4eeb6b361bfa2ae9e60f494391bfc86ec5 100644 (file)
@@ -717,101 +717,6 @@ bool_t dict_read_bool(dict_t *dict, string_t key, bool_t required,
     return r;
 }
 
     return r;
 }
 
-static struct subnet string_to_subnet(item_t *i, string_t desc)
-{
-    struct subnet s;
-    uint32_t a, b, c, d, n;
-    uint32_t match;
-
-    /* i is not guaranteed to be a string */
-    if (i->type!=t_string) {
-       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. */
-    match=sscanf(i->data.string,"%u.%u.%u.%u/%u", &a, &b, &c, &d, &n);
-    if (match<4) {
-       cfgfatal(i->loc,desc,"\"%s\" is not a valid "
-                "subnet specification\n",i->data.string);
-    }
-    if (match<5) {
-       n=32;
-    }
-    if (a>255 || b>255 || c>255 || d>255 || n>32) {
-       cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
-    }
-    s.prefix=(a<<24)|(b<<16)|(c<<8)|(d);
-    s.mask=n?(~0UL << (32-n)):0;
-    s.len=n;
-    if (s.prefix & ~s.mask) {
-       cfgfatal(i->loc,desc,"\"%s\": prefix not fully contained "
-                "in mask\n",i->data.string);
-    }
-    return s;
-}
-
-uint32_t string_to_ipaddr(item_t *i, string_t desc)
-{
-    uint32_t a, b, c, d;
-    uint32_t match;
-
-    /* i is not guaranteed to be a string */
-    if (i->type!=t_string) {
-       cfgfatal(i->loc,desc,"expecting a string (IP address)\n");
-    }
-
-    match=sscanf(i->data.string,"%u.%u.%u.%u", &a, &b, &c, &d);
-    if (match<4) {
-       cfgfatal(i->loc,desc,"\"%s\" is not a valid "
-                "IP address\n",i->data.string);
-    }
-    if (a>255 || b>255 || c>255 || d>255) {
-       cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
-    }
-    return (a<<24)|(b<<16)|(c<<8)|(d);
-}
-
-void dict_read_subnet_list(dict_t *dict, string_t key, bool_t required,
-                          string_t desc, struct cloc loc,
-                          struct subnet_list *sl)
-{
-    list_t *l, *li;
-    item_t *i;
-    uint32_t e=0;
-
-    sl->entries=0;
-    sl->list=NULL;
-    l=dict_lookup(dict, key);
-    if (!l) {
-       if (!required) return;
-       cfgfatal(loc,desc,"required parameter \"%s\" not found\n",key);
-    }
-    /* Count the items in the list */
-    e=list_length(l);
-    if (e==0) return;
-    sl->entries=e;
-    sl->list=safe_malloc(sizeof(struct subnet)*e, "dict_read_subnet_list");
-    e=0;
-    /* Fill in the list */
-    for (li=l; li; li=li->next) {
-       i=li->item;
-       if (i->type!=t_string) {
-           cfgfatal(loc,desc,"parameter \"%s\": all elements must "
-                    "be strings\n",key);
-       }
-       sl->list[e++]=string_to_subnet(i,desc);
-    }
-}
-
 uint32_t string_to_word(string_t s, struct cloc loc,
                        struct flagstr *f, string_t desc)
 {
 uint32_t string_to_word(string_t s, struct cloc loc,
                        struct flagstr *f, string_t desc)
 {
index 889736c5ee511249344e0b743ddecdaa1eda6805..cf288bdfd7beee3e854e3c2e0666b5665ddc5146 100644 (file)
 #else
 #if SIZEOF_UNSIGNED_LONG_LONG==8
 typedef unsigned long long uint64_t;
 #else
 #if SIZEOF_UNSIGNED_LONG_LONG==8
 typedef unsigned long long uint64_t;
+typedef long long int64_t;
 #elif SIZEOF_UNSIGNED_LONG==8
 typedef unsigned long uint64_t;
 #elif SIZEOF_UNSIGNED_LONG==8
 typedef unsigned long uint64_t;
+typedef long int64_t;
 #else
 #error I do not know what to use for a uint64_t.
 #endif
 #else
 #error I do not know what to use for a uint64_t.
 #endif
@@ -19,8 +21,10 @@ typedef unsigned long uint64_t;
 /* Give us an unsigned 32-bit data type. */
 #if SIZEOF_UNSIGNED_LONG==4
 typedef unsigned long uint32_t;
 /* Give us an unsigned 32-bit data type. */
 #if SIZEOF_UNSIGNED_LONG==4
 typedef unsigned long uint32_t;
+typedef long int32_t;
 #elif SIZEOF_UNSIGNED_INT==4
 typedef unsigned int uint32_t;
 #elif SIZEOF_UNSIGNED_INT==4
 typedef unsigned int uint32_t;
+typedef int int32_t;
 #else
 #error I do not know what to use for a uint32_t.
 #endif
 #else
 #error I do not know what to use for a uint32_t.
 #endif
@@ -28,8 +32,10 @@ typedef unsigned int uint32_t;
 /* An unsigned 16-bit data type. */
 #if SIZEOF_UNSIGNED_INT==2
 typedef unsigned int uint16_t;
 /* An unsigned 16-bit data type. */
 #if SIZEOF_UNSIGNED_INT==2
 typedef unsigned int uint16_t;
+typedef int int16_t;
 #elif SIZEOF_UNSIGNED_SHORT==2
 typedef unsigned short uint16_t;
 #elif SIZEOF_UNSIGNED_SHORT==2
 typedef unsigned short uint16_t;
+typedef short int16_t;
 #else
 #error I do not know what to use for a uint16_t.
 #endif
 #else
 #error I do not know what to use for a uint16_t.
 #endif
index d7044fcaab104aae7523d80cfd3c0909d9137f7f..76d28f01d2ff82045afa26d9e863a3b66ce030b0 100644 (file)
 #else
 #if SIZEOF_UNSIGNED_LONG_LONG==8
 typedef unsigned long long uint64_t;
 #else
 #if SIZEOF_UNSIGNED_LONG_LONG==8
 typedef unsigned long long uint64_t;
+typedef long long int64_t;
 #elif SIZEOF_UNSIGNED_LONG==8
 typedef unsigned long uint64_t;
 #elif SIZEOF_UNSIGNED_LONG==8
 typedef unsigned long uint64_t;
+typedef long int64_t;
 #else
 #error I do not know what to use for a uint64_t.
 #endif
 #else
 #error I do not know what to use for a uint64_t.
 #endif
@@ -109,8 +111,10 @@ typedef unsigned long uint64_t;
 /* Give us an unsigned 32-bit data type. */
 #if SIZEOF_UNSIGNED_LONG==4
 typedef unsigned long uint32_t;
 /* Give us an unsigned 32-bit data type. */
 #if SIZEOF_UNSIGNED_LONG==4
 typedef unsigned long uint32_t;
+typedef long int32_t;
 #elif SIZEOF_UNSIGNED_INT==4
 typedef unsigned int uint32_t;
 #elif SIZEOF_UNSIGNED_INT==4
 typedef unsigned int uint32_t;
+typedef int int32_t;
 #else
 #error I do not know what to use for a uint32_t.
 #endif
 #else
 #error I do not know what to use for a uint32_t.
 #endif
@@ -118,8 +122,10 @@ typedef unsigned int uint32_t;
 /* An unsigned 16-bit data type. */
 #if SIZEOF_UNSIGNED_INT==2
 typedef unsigned int uint16_t;
 /* An unsigned 16-bit data type. */
 #if SIZEOF_UNSIGNED_INT==2
 typedef unsigned int uint16_t;
+typedef int int16_t;
 #elif SIZEOF_UNSIGNED_SHORT==2
 typedef unsigned short uint16_t;
 #elif SIZEOF_UNSIGNED_SHORT==2
 typedef unsigned short uint16_t;
+typedef short int16_t;
 #else
 #error I do not know what to use for a uint16_t.
 #endif
 #else
 #error I do not know what to use for a uint16_t.
 #endif
index 2011174b03830a6df4aba366c9878633049c5774..8ac52602899500cae82abd79c20efc42e06ea0b8 100644 (file)
@@ -1,5 +1,8 @@
-secnet (0.1.10-1) unstable; urgency=low
+secnet (0.1.11-1) unstable; urgency=low
 
   * New upstream version.
 
 
   * New upstream version.
 
- -- Stephen Early <steve@greenend.org.uk>  Sat, 29 Jun 2001 15:21:25 +0100
+  * Note configuration file format has changed slightly; re-run
+    make-secnet-sites to fix it
+
+ -- Stephen Early <steve@greenend.org.uk>  Sat, 27 Oct 2001 15:00:00 +0100
diff --git a/debian/files b/debian/files
deleted file mode 100644 (file)
index 1638b95..0000000
+++ /dev/null
@@ -1 +0,0 @@
-secnet_0.1.9-1_i386.deb net extra
diff --git a/debian/postinst.debhelper b/debian/postinst.debhelper
deleted file mode 100644 (file)
index 2ebe82f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Automatically added by dh_installdocs
-if [ "$1" = "configure" ]; then
-       if [ -d /usr/doc -a ! -e /usr/doc/secnet -a -d /usr/share/doc/secnet ]; then
-               ln -sf ../share/doc/secnet /usr/doc/secnet
-       fi
-fi
-# End automatically added section
-# Automatically added by dh_installinit
-if [ -e "/etc/init.d/secnet" ]; then
-       update-rc.d secnet defaults >/dev/null
-       /etc/init.d/secnet start
-fi
-# End automatically added section
diff --git a/debian/postrm.debhelper b/debian/postrm.debhelper
deleted file mode 100644 (file)
index 5f1bce9..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# Automatically added by dh_installinit
-if [ "$1" = "purge" ] ; then
-       update-rc.d secnet remove >/dev/null
-fi
-# End automatically added section
diff --git a/debian/prerm.debhelper b/debian/prerm.debhelper
deleted file mode 100644 (file)
index 23a07d7..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# Automatically added by dh_installdocs
-if [ \( "$1" = "upgrade" -o "$1" = "remove" \) -a -L /usr/doc/secnet ]; then
-       rm -f /usr/doc/secnet
-fi
-# End automatically added section
-# Automatically added by dh_installinit
-if [ -e "/etc/init.d/secnet" ]; then
-       /etc/init.d/secnet stop
-fi
-# End automatically added section
index a85db21905e6704de6645a4342bd1fbab0d53b73..d9d1dd51650c37f32a3d7106d562a6afce9ab017 100755 (executable)
@@ -46,7 +46,7 @@ binary-arch: build install
        dh_testdir
        dh_testroot
 #      dh_installdebconf       
        dh_testdir
        dh_testroot
 #      dh_installdebconf       
-       dh_installdocs INSTALL README NOTES TODO NEWS
+       dh_installdocs INSTALL README NOTES TODO NEWS BUGS CREDITS
        dh_installexamples example.conf
 #      dh_installmenu
 #      dh_installlogrotate
        dh_installexamples example.conf
 #      dh_installmenu
 #      dh_installlogrotate
diff --git a/debian/substvars b/debian/substvars
deleted file mode 100644 (file)
index aa787d5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-shlibs:Depends=libc6 (>= 2.2.3-7), libgmp2
index f42e82016319b702cd31b88e9075e8663d2ee04b..1edc334e46fc28be2b20b0e41e16920509c06346 100644 (file)
--- a/ipaddr.c
+++ b/ipaddr.c
+/* The 'ipset' data structure and related algorithms in this file were
+   inspired by the 'ipaddr.py' library from Cendio Systems AB. */
+
 #include "secnet.h"
 #include <stdio.h>
 #include "secnet.h"
 #include <stdio.h>
+#include "ipaddr.h"
+
+#define DEFAULT_ALLOC 2
+#define EXTEND_ALLOC_BY 4
+
+struct subnet_list *subnet_list_new(void)
+{
+    struct subnet_list *r;
+    r=safe_malloc(sizeof(*r),"subnet_list_new:list");
+    r->entries=0;
+    r->alloc=DEFAULT_ALLOC;
+    r->list=safe_malloc(sizeof(*r->list)*r->alloc,"subnet_list_new:data");
+    return r;
+}
+
+void subnet_list_free(struct subnet_list *a)
+{
+    if (a->list) free(a->list);
+    free(a);
+}
+
+static void subnet_list_set_len(struct subnet_list *a, uint32_t l)
+{
+    struct subnet *nd;
+    uint32_t na;
+
+    if (l>a->alloc) {
+       na=a->alloc+EXTEND_ALLOC_BY;
+       nd=realloc(a->list,sizeof(*nd)*na);
+       if (!nd) {
+           fatal_perror("subnet_list_set_len: realloc");
+       }
+       a->alloc=na;
+       a->list=nd;
+    }
+    a->entries=l;
+}
+
+void subnet_list_append(struct subnet_list *a, uint32_t prefix, uint32_t len)
+{
+    struct subnet *sn;
+    subnet_list_set_len(a,a->entries+1);
+    sn=&a->list[a->entries-1];
+    sn->prefix=prefix;
+    sn->len=len;
+    sn->mask=len?(0xffffffff << (32-len)):0;
+}
 
 
-/* This file should eventually incorporate all the functionality of
-   ipaddr.py */
+struct ipset *ipset_new(void)
+{
+    struct ipset *r;
+    r=safe_malloc(sizeof(*r),"ipset_new:set");
+    r->l=0;
+    r->a=DEFAULT_ALLOC;
+    r->d=safe_malloc(sizeof(*r->d)*r->a,"ipset_new:data");
+    return r;
+}
 
 
-bool_t subnet_match(struct subnet *s, uint32_t address)
+void ipset_free(struct ipset *a)
 {
 {
-    return (s->prefix==(address&s->mask));
+    if (a->d) free(a->d);
+    free(a);
 }
 
 }
 
-bool_t subnet_matches_list(struct subnet_list *list, uint32_t address)
+#ifdef DEBUG
+static void ipset_dump(struct ipset *a, string_t name)
 {
     uint32_t i;
 {
     uint32_t i;
-    for (i=0; i<list->entries; i++) {
-       if (list->list[i].prefix == (address&list->list[i].mask)) return True;
+
+    printf("%s: ",name);
+    for (i=0; i<a->l; i++) {
+       printf("[%08x-%08x] ",a->d[i].a,a->d[i].b);
     }
     }
-    return False;
+    printf("\n");
 }
 }
+#endif
 
 
-bool_t subnets_intersect(struct subnet a, struct subnet b)
+struct ipset *ipset_from_subnet(struct subnet s)
 {
 {
-    uint32_t mask=a.mask&b.mask;
-    return ((a.prefix&mask)==(b.prefix&mask));
+    struct ipset *r;
+
+    r=ipset_new();
+    r->l=1;
+    r->d[0].a=s.prefix;
+    r->d[0].b=s.prefix | (~s.mask);
+    return r;
 }
 
 }
 
-bool_t subnet_intersects_with_list(struct subnet a, struct subnet_list *b)
+struct ipset *ipset_from_subnet_list(struct subnet_list *l)
 {
 {
+    struct ipset *r, *a, *b;
     uint32_t i;
 
     uint32_t i;
 
-    for (i=0; i<b->entries; i++) {
-       if (subnets_intersect(a,b->list[i])) return True;
+    r=ipset_new();
+    for (i=0; i<l->entries; i++) {
+       a=ipset_from_subnet(l->list[i]);
+       b=ipset_union(r,a);
+       ipset_free(a);
+       ipset_free(r);
+       r=b;
     }
     }
-    return False;
+    return r;
 }
 
 }
 
-bool_t subnet_lists_intersect(struct subnet_list *a, struct subnet_list *b)
+static void ipset_set_len(struct ipset *a, uint32_t l)
+{
+    struct iprange *nd;
+    uint32_t na;
+
+    if (l>a->a) {
+       na=a->a+EXTEND_ALLOC_BY;
+       nd=realloc(a->d,sizeof(*nd)*na);
+       if (!nd) {
+           fatal_perror("ipset_set_len: realloc");
+       }
+       a->a=na;
+       a->d=nd;
+    }
+    a->l=l;
+}
+
+static void ipset_append_range(struct ipset *a, struct iprange r)
+{
+    ipset_set_len(a,a->l+1);
+    a->d[a->l-1]=r;
+}
+
+#define max(a,b) (a>b?a:b)
+struct ipset *ipset_union(struct ipset *a, struct ipset *b)
+{
+    struct ipset *c;
+    struct iprange r;
+    uint32_t ia,ib;
+
+    c=ipset_new();
+    ia=0; ib=0;
+    while (ia<a->l || ib<b->l) {
+       if (ia<a->l)
+           if (ib<b->l)
+               if (a->d[ia].a < b->d[ib].a)
+                   r=a->d[ia++];
+               else
+                   r=b->d[ib++];
+           else
+               r=a->d[ia++];
+       else
+           r=b->d[ib++];
+
+       if (c->l==0)
+           ipset_append_range(c,r);
+       else if (r.a <= c->d[c->l-1].b+1)
+           /* Extends (or is consumed by) the last range */
+           c->d[c->l-1].b=max(c->d[c->l-1].b, r.b);
+       else
+           ipset_append_range(c,r);
+    }
+    return c;
+}
+
+struct ipset *ipset_intersection(struct ipset *a, struct ipset *b)
+{
+    struct ipset *r;
+    struct iprange ra, rb;
+    uint32_t ia,ib;
+
+    r=ipset_new();
+    ia=0; ib=0;
+
+    while (ia<a->l && ib<b->l) {
+       ra=a->d[ia];
+       rb=b->d[ib];
+       if (ra.b < rb.a)
+           /* The first entry of a doesn't overlap with any part of b */
+           ia++;
+       else if (ra.a > rb.b)
+           /* The first entry of b doesn't overlap with any part of a */
+           ib++;
+       else {
+           /* Trim away any leading edges */
+           if (ra.a < rb.a)
+               /* a starts before b */
+               ra.a=rb.a;
+           else if (ra.a > rb.a)
+               /* b starts before a */
+               rb.a=ra.a;
+
+           /* Now the ranges start at the same point */
+           if (ra.b == rb.b) {
+               /* The ranges are equal */
+               ipset_append_range(r,ra);
+               ia++;
+               ib++;
+           } else if (ra.b < rb.b) {
+               /* a is the smaller range */
+               ipset_append_range(r,ra);
+               ia++;
+           } else {
+               /* y is the smaller range */
+               ipset_append_range(r,rb);
+               ib++;
+           }
+       }
+    }
+    return r;
+}
+
+struct ipset *ipset_complement(struct ipset *a)
+{
+    struct ipset *r;
+    struct iprange n;
+    int64_t pre;
+    uint32_t i,lo,hi;
+
+    r=ipset_new();
+    pre=-1;
+    for (i=0; i<a->l; i++) {
+       lo=a->d[i].a;
+       hi=a->d[i].b;
+       if (lo!=0) {
+           n.a=pre+1;
+           n.b=lo-1;
+           ipset_append_range(r,n);
+       }
+       pre=hi;
+    }
+    if (pre!=0xffffffff) {
+       n.a=pre+1;
+       n.b=0xffffffff;
+       ipset_append_range(r,n);
+    }
+    return r;
+}
+
+/* Return a-b */
+struct ipset *ipset_subtract(struct ipset *a, struct ipset *b)
+{
+    struct ipset *c, *r;
+    c=ipset_complement(b);
+    r=ipset_intersection(a,c);
+    ipset_free(c);
+    return r;
+}
+
+bool_t ipset_is_empty(struct ipset *a)
+{
+   return (a->l==0);
+}
+
+bool_t ipset_contains_addr(struct ipset *a, uint32_t addr)
 {
     uint32_t i;
 {
     uint32_t i;
-    for (i=0; i<a->entries; i++) {
-       if (subnet_intersects_with_list(a->list[i],b)) return True;
+    struct iprange r;
+
+    for (i=0; i<a->l; i++) {
+       r=a->d[i];
+       if (addr>=r.a && addr<=r.b) return True;
+       if (addr<r.a) return False;
     }
     return False;
 }
 
     }
     return False;
 }
 
+/* sub is a subset of super if it does not intersect with the complement 
+   of super */
+bool_t ipset_is_subset(struct ipset *super, struct ipset *sub)
+{
+    struct ipset *superc;
+    struct ipset *inter;
+    bool_t empty;
+
+    superc=ipset_complement(super);
+    inter=ipset_intersection(superc,sub);
+    empty=ipset_is_empty(inter);
+    ipset_free(inter);
+    ipset_free(superc);
+    return empty;
+}
+
+struct subnet_list *ipset_to_subnet_list(struct ipset *is)
+{
+    struct subnet_list *r;
+    int64_t a,b;
+    uint32_t i;
+    uint32_t lomask,lobit,himask,bits;
+
+    r=subnet_list_new();
+    for (i=0; i<is->l; i++) {
+       a=is->d[i].a;
+       b=is->d[i].b;
+
+       lomask=1;
+       lobit=1;
+       himask=0xfffffffe;
+       bits=32;
+       while (a<=b) {
+           if ((a & lomask) != 0) {
+               subnet_list_append(r,a,bits);
+               a=a+lobit;
+           } else if ((b & lomask) != lomask) {
+               subnet_list_append(r,b&himask,bits);
+               b=b-lobit;
+           } else {
+               lomask = (lomask << 1) | 1;
+               lobit = (lobit << 1);
+               himask = himask ^ lobit;
+               bits = bits - 1;
+               ASSERT(bits>=0);
+           }
+       }
+    }
+    /* Sort the list? */
+    return r;
+}
+
 /* The string buffer must be at least 16 bytes long */
 string_t ipaddr_to_string(uint32_t addr)
 {
 /* The string buffer must be at least 16 bytes long */
 string_t ipaddr_to_string(uint32_t addr)
 {
@@ -58,25 +331,114 @@ string_t ipaddr_to_string(uint32_t addr)
     return s;
 }
 
     return s;
 }
 
-string_t subnet_to_string(struct subnet *sn)
+string_t subnet_to_string(struct subnet sn)
 {
 {
-    uint32_t mask=sn->mask, addr=sn->prefix;
+    uint32_t addr=sn.prefix;
     uint8_t a,b,c,d;
     string_t s;
     uint8_t a,b,c,d;
     string_t s;
-    int i;
 
     s=safe_malloc(19,"subnet_to_string");
     a=addr>>24;
     b=addr>>16;
     c=addr>>8;
     d=addr;
 
     s=safe_malloc(19,"subnet_to_string");
     a=addr>>24;
     b=addr>>16;
     c=addr>>8;
     d=addr;
-    for (i=0; mask; i++) {
-       mask=(mask<<1);
+    snprintf(s, 19, "%d.%d.%d.%d/%d", a, b, c, d, sn.len);
+    return s;
+}
+
+static struct subnet string_item_to_subnet(item_t *i, string_t desc,
+                                          bool_t *invert)
+{
+    struct subnet s;
+    uint32_t a, b, c, d, n;
+    uint32_t match;
+    string_t in;
+
+    *invert=False;
+
+    /* i is not guaranteed to be a string */
+    if (i->type!=t_string) {
+       cfgfatal(i->loc,desc,"expecting a string (subnet specification)\n");
+    }
+    in=i->data.string;
+
+    if (strcmp(in,"default")==0) {
+       s.prefix=0;
+       s.mask=0;
+       s.len=0;
+       return s;
+    }
+
+    if (*in=='!') {
+       *invert=True;
+       in++;
+    }
+    /* 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. */
+    match=sscanf(in,"%u.%u.%u.%u/%u", &a, &b, &c, &d, &n);
+    if (match<4) {
+       cfgfatal(i->loc,desc,"\"%s\" is not a valid "
+                "subnet specification\n",in);
+    }
+    if (match<5) {
+       n=32;
     }
     }
-    if (i!=sn->len) {
-       fatal("subnet_to_string: invalid subnet structure "
-             "(i=%d sn->len=%d mask=0x%08x)!\n",i,sn->len,sn->mask);
+    if (a>255 || b>255 || c>255 || d>255 || n>32) {
+       cfgfatal(i->loc,desc,"\"%s\": range error\n",in);
+    }
+    s.prefix=(a<<24)|(b<<16)|(c<<8)|(d);
+    s.mask=n?(~0UL << (32-n)):0;
+    s.len=n;
+    if (s.prefix & ~s.mask) {
+       cfgfatal(i->loc,desc,"\"%s\": prefix not fully contained "
+                "in mask\n",in);
     }
     }
-    snprintf(s, 19, "%d.%d.%d.%d/%d", a, b, c, d, sn->len);
     return s;
 }
     return s;
 }
+
+uint32_t string_item_to_ipaddr(item_t *i, string_t desc)
+{
+    uint32_t a, b, c, d;
+    uint32_t match;
+
+    /* i is not guaranteed to be a string */
+    if (i->type!=t_string) {
+       cfgfatal(i->loc,desc,"expecting a string (IP address)\n");
+    }
+
+    match=sscanf(i->data.string,"%u.%u.%u.%u", &a, &b, &c, &d);
+    if (match<4) {
+       cfgfatal(i->loc,desc,"\"%s\" is not a valid "
+                "IP address\n",i->data.string);
+    }
+    if (a>255 || b>255 || c>255 || d>255) {
+       cfgfatal(i->loc,desc,"\"%s\": range error\n",i->data.string);
+    }
+    return (a<<24)|(b<<16)|(c<<8)|(d);
+}
+
+struct ipset *string_list_to_ipset(list_t *l, struct cloc loc,
+                                  string_t module, string_t param)
+{
+    struct ipset *r, *n, *isn;
+    uint32_t e,i;
+    item_t *item;
+    bool_t inv;
+
+    r=ipset_new();
+    e=list_length(l);
+    for (i=0; i<e; i++) {
+       item=list_elem(l,i);
+       isn=ipset_from_subnet(string_item_to_subnet(item,param,&inv));
+       if (inv) {
+           n=ipset_subtract(r,isn);
+       } else {
+           n=ipset_union(r,isn);
+       }
+       ipset_free(r);
+       ipset_free(isn);
+       r=n;
+    }
+    return r;
+}
index 99cd1ed4ea1cbfd0da4ade67f37c4bfc76db2683..8c262bfb3a899cb092cdf422761052e5b543f57e 100644 (file)
--- a/ipaddr.h
+++ b/ipaddr.h
@@ -1,18 +1,59 @@
+/* Useful functions for dealing with collections of IP addresses */
+
 #ifndef ipaddr_h
 #define ipaddr_h
 
 #ifndef ipaddr_h
 #define ipaddr_h
 
-/* Match an address (in HOST byte order) with a subnet list.
-   Returns True if matched. */
-extern bool_t subnet_match(struct subnet *s, uint32_t address);
-extern bool_t subnet_matches_list(struct subnet_list *list, uint32_t address);
-extern bool_t subnets_intersect(struct subnet a, struct subnet b);
-extern bool_t subnet_intersects_with_list(struct subnet a,
-                                         struct subnet_list *b);
-extern bool_t subnet_lists_intersect(struct subnet_list *a,
-                                    struct subnet_list *b);
+struct subnet {
+    uint32_t prefix;
+    uint32_t mask;
+    uint32_t len;
+};
+
+struct subnet_list {
+    uint32_t entries;
+    uint32_t alloc;
+    struct subnet *list;
+};
+
+struct iprange {
+    uint32_t a,b;
+};
+
+struct ipset {
+    uint32_t l; /* Number of entries in list */
+    uint32_t a; /* Allocated space in list */
+    struct iprange *d;
+};
 
 
+extern struct subnet_list *subnet_list_new(void);
+extern void subnet_list_free(struct subnet_list *a);
+extern void subnet_list_append(struct subnet_list *a, uint32_t prefix,
+                              uint32_t len);
+
+static inline bool_t subnet_match(struct subnet s, uint32_t address)
+{
+    return (s.prefix==(address&s.mask));
+}
+
+extern struct ipset *ipset_new(void);
+extern void ipset_free(struct ipset *a);
+extern struct ipset *ipset_from_subnet(struct subnet s);
+extern struct ipset *ipset_from_subnet_list(struct subnet_list *l);
+extern struct ipset *ipset_union(struct ipset *a, struct ipset *b);
+extern struct ipset *ipset_intersection(struct ipset *a, struct ipset *b);
+extern struct ipset *ipset_complement(struct ipset *a);
+extern struct ipset *ipset_subtract(struct ipset *a, struct ipset *b);
+extern bool_t ipset_is_empty(struct ipset *a);
+extern bool_t ipset_contains_addr(struct ipset *a, uint32_t addr);
+extern bool_t ipset_is_subset(struct ipset *super, struct ipset *sub);
+extern struct subnet_list *ipset_to_subnet_list(struct ipset *is);
 
 extern string_t ipaddr_to_string(uint32_t addr);
 
 extern string_t ipaddr_to_string(uint32_t addr);
-extern string_t subnet_to_string(struct subnet *sn);
+extern string_t subnet_to_string(struct subnet sn);
+
+extern struct ipset *string_list_to_ipset(list_t *l,struct cloc loc,
+                                         string_t module,string_t param);
+                                         
+extern uint32_t string_item_to_ipaddr(item_t *i, string_t desc);
 
 #endif /* ipaddr_h */
 
 #endif /* ipaddr_h */
index 4426a7c3575d31f79d1a8293a135d5cfe9d9cd02..e41445cb47c147929e6c3f6f84e7a6691fa03144 100644 (file)
--- a/netlink.c
+++ b/netlink.c
@@ -302,7 +302,7 @@ static void netlink_packet_deliver(struct netlink *st,
     best_quality=0;
     best_match=-1;
     for (i=0; i<st->n_routes; i++) {
     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].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? */
 
            /* It's an available route to the correct destination. But is
               it better than the one we already have? */
 
@@ -334,7 +334,7 @@ static void netlink_packet_deliver(struct netlink *st,
     if (best_match==-1) {
        /* The packet's not going down a tunnel.  It might (ought to)
           be for the host.   */
     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)) {
+       if (ipset_contains_addr(st->networks,dest)) {
            st->deliver_to_host(st->dst,buf);
            st->outcount++;
            BUF_ASSERT_FREE(buf);
            st->deliver_to_host(st->dst,buf);
            st->outcount++;
            BUF_ASSERT_FREE(buf);
@@ -466,10 +466,12 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client,
     dest=ntohl(iph->daddr);
 
     /* Check source */
     dest=ntohl(iph->daddr);
 
     /* Check source */
+    /* XXX consider generating ICMP if we're not point-to-point and we
+       don't like the packet */
     if (client) {
        /* Check that the packet source is appropriate for the tunnel
           it came down */
     if (client) {
        /* Check that the packet source is appropriate for the tunnel
           it came down */
-       if (!subnet_matches_list(&client->networks,source)) {
+       if (!ipset_contains_addr(client->networks,source)) {
            string_t s,d;
            s=ipaddr_to_string(source);
            d=ipaddr_to_string(dest);
            string_t s,d;
            s=ipaddr_to_string(source);
            d=ipaddr_to_string(dest);
@@ -483,7 +485,7 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client,
        /* Check that the packet originates in our configured local
           network, and hasn't been forwarded from elsewhere or
           generated with the wrong source address */
        /* Check that the packet originates in our configured local
           network, and hasn't been forwarded from elsewhere or
           generated with the wrong source address */
-       if (!subnet_matches_list(&st->networks,source)) {
+       if (!ipset_contains_addr(st->networks,source)) {
            string_t s,d;
            s=ipaddr_to_string(source);
            d=ipaddr_to_string(dest);
            string_t s,d;
            s=ipaddr_to_string(source);
            d=ipaddr_to_string(dest);
@@ -495,9 +497,11 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client,
        }
     }
 
        }
     }
 
-    /* If this is a point-to-point device we don't examine the packet at
-       all; we blindly send it down our one-and-only registered tunnel,
-       or to the host, depending on where it came from. */
+    /* If this is a point-to-point device we don't examine the
+       destination address at all; we blindly send it down our
+       one-and-only registered tunnel, or to the host, depending on
+       where it came from. */
+    /* XXX I think we should check destination addresses */
     if (st->ptp) {
        if (client) {
            st->deliver_to_host(st->dst,buf);
     if (st->ptp) {
        if (client) {
            st->deliver_to_host(st->dst,buf);
@@ -515,20 +519,6 @@ static void netlink_incoming(struct netlink *st, struct netlink_client *client,
        BUF_ASSERT_FREE(buf);
        return;
     }
        BUF_ASSERT_FREE(buf);
        return;
     }
-    if (client) {
-       /* Check for free routing */
-       if (!subnet_matches_list(&st->networks,dest)) {
-           string_t s,d;
-           s=ipaddr_to_string(source);
-           d=ipaddr_to_string(dest);
-           Message(M_WARNING,"%s: incoming packet from tunnel %s "
-                   "with bad destination address "
-                   "(s=%s,d=%s)\n",st->name,client->name,s,d);
-           free(s); free(d);
-           BUF_FREE(buf);
-           return;
-       }
-    }
     netlink_packet_forward(st,client,buf);
     BUF_ASSERT_FREE(buf);
 }
     netlink_packet_forward(st,client,buf);
     BUF_ASSERT_FREE(buf);
 }
@@ -591,7 +581,7 @@ static void netlink_dump_routes(struct netlink *st, bool_t requested)
                st->name, net);
        free(net);
        for (i=0; i<st->n_routes; i++) {
                st->name, net);
        free(net);
        for (i=0; i<st->n_routes; i++) {
-           net=subnet_to_string(&st->routes[i].net);
+           net=subnet_to_string(st->routes[i].net);
            Message(c,"%s ",net);
            free(net);
        }
            Message(c,"%s ",net);
            free(net);
        }
@@ -599,7 +589,7 @@ static void netlink_dump_routes(struct netlink *st, bool_t requested)
     } else {
        Message(c,"%s: routing table:\n",st->name);
        for (i=0; i<st->n_routes; i++) {
     } 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);
+           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",
            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",
@@ -613,11 +603,13 @@ static void netlink_dump_routes(struct netlink *st, bool_t requested)
        Message(c,"%s/32 -> netlink \"%s\" (use %d)\n",
                net,st->name,st->localcount);
        free(net);
        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);
+       for (i=0; i<st->subnets->entries; i++) {
+           net=subnet_to_string(st->subnets->list[i]);
+           Message(c,"%s ",net);
            free(net);
        }
            free(net);
        }
+       if (i>0)
+           Message(c,"-> host (use %d)\n",st->outcount);
     }
 }
 
     }
 }
 
@@ -645,8 +637,8 @@ static void netlink_phase_hook(void *sst, uint32_t new_phase)
     /* Fill the table */
     i=0;
     for (c=st->clients; c; c=c->next) {
     /* 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->subnets->entries; j++) {
+           st->routes[i].net=c->subnets->list[j];
            st->routes[i].c=c;
            /* Hard routes are always up;
               soft routes default to down; routes with no 'deliver' function
            st->routes[i].c=c;
            /* Hard routes are always up;
               soft routes default to down; routes with no 'deliver' function
@@ -682,6 +674,27 @@ static void netlink_signal_handler(void *sst, int signum)
     netlink_dump_routes(st,True);
 }
 
     netlink_dump_routes(st,True);
 }
 
+static void netlink_inst_output_config(void *sst, struct buffer_if *buf)
+{
+/*    struct netlink_client *c=sst; */
+/*    struct netlink *st=c->nst; */
+
+    /* For now we don't output anything */
+    BUF_ASSERT_USED(buf);
+}
+
+static bool_t netlink_inst_check_config(void *sst, struct buffer_if *buf)
+{
+/*    struct netlink_client *c=sst; */
+/*    struct netlink *st=c->nst; */
+
+    BUF_ASSERT_USED(buf);
+    /* We need to eat all of the configuration information from the buffer
+       for backward compatibility. */
+    buf->size=0;
+    return True;
+}
+
 static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver, 
                             void *dst, uint32_t max_start_pad,
                             uint32_t max_end_pad)
 static void netlink_inst_reg(void *sst, netlink_deliver_fn *deliver, 
                             void *dst, uint32_t max_start_pad,
                             uint32_t max_end_pad)
@@ -710,13 +723,16 @@ static closure_t *netlink_inst_create(struct netlink *st,
 {
     struct netlink_client *c;
     string_t name;
 {
     struct netlink_client *c;
     string_t name;
-    struct subnet_list networks;
+    struct ipset *networks;
     uint32_t options;
     uint32_t options;
+    list_t *l;
 
     name=dict_read_string(dict, "name", True, st->name, loc);
 
 
     name=dict_read_string(dict, "name", True, st->name, loc);
 
-    dict_read_subnet_list(dict, "routes", True, st->name, loc,
-                         &networks);
+    l=dict_lookup(dict,"routes");
+    if (!l)
+       cfgfatal(loc,st->name,"required parameter \"routes\" not found\n");
+    networks=string_list_to_ipset(l,loc,st->name,"routes");
     options=string_list_to_word(dict_lookup(dict,"options"),
                                netlink_option_table,st->name);
 
     options=string_list_to_word(dict_lookup(dict,"options"),
                                netlink_option_table,st->name);
 
@@ -738,11 +754,10 @@ static closure_t *netlink_inst_create(struct netlink *st,
        }
     }
 
        }
     }
 
-    /* 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");
+    /* Check that nets are a subset of st->remote_networks;
+       refuse to register if they are not. */
+    if (!ipset_is_subset(st->remote_networks,networks)) {
+       cfgfatal(loc,st->name,"routes are not allowed\n");
        return NULL;
     }
 
        return NULL;
     }
 
@@ -755,9 +770,12 @@ static closure_t *netlink_inst_create(struct netlink *st,
     c->ops.reg=netlink_inst_reg;
     c->ops.deliver=netlink_inst_incoming;
     c->ops.set_quality=netlink_set_quality;
     c->ops.reg=netlink_inst_reg;
     c->ops.deliver=netlink_inst_incoming;
     c->ops.set_quality=netlink_set_quality;
+    c->ops.output_config=netlink_inst_output_config;
+    c->ops.check_config=netlink_inst_check_config;
     c->nst=st;
 
     c->networks=networks;
     c->nst=st;
 
     c->networks=networks;
+    c->subnets=ipset_to_subnet_list(networks);
     c->deliver=NULL;
     c->dst=NULL;
     c->name=name;
     c->deliver=NULL;
     c->dst=NULL;
     c->name=name;
@@ -765,7 +783,7 @@ static closure_t *netlink_inst_create(struct netlink *st,
     c->link_quality=LINK_QUALITY_DOWN;
     c->next=st->clients;
     st->clients=c;
     c->link_quality=LINK_QUALITY_DOWN;
     c->next=st->clients;
     st->clients=c;
-    st->n_routes+=networks.entries;
+    st->n_routes+=c->subnets->entries;
 
     return &c->cl;
 }
 
     return &c->cl;
 }
@@ -779,8 +797,6 @@ static list_t *netlink_inst_apply(closure_t *self, struct cloc loc,
     item_t *item;
     closure_t *cl;
 
     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");
     item=list_elem(args,0);
     if (!item || item->type!=t_dict) {
        cfgfatal(loc,st->name,"must have a dictionary argument\n");
@@ -799,6 +815,7 @@ netlink_deliver_fn *netlink_init(struct netlink *st,
                                 netlink_deliver_fn *to_host)
 {
     item_t *sa, *ptpa;
                                 netlink_deliver_fn *to_host)
 {
     item_t *sa, *ptpa;
+    list_t *l;
 
     st->dst=dst;
     st->cl.description=description;
 
     st->dst=dst;
     st->cl.description=description;
@@ -811,12 +828,27 @@ netlink_deliver_fn *netlink_init(struct netlink *st,
     st->set_route=set_route;
     st->deliver_to_host=to_host;
 
     st->set_route=set_route;
     st->deliver_to_host=to_host;
 
-    st->name=dict_read_string(dict,"name",False,"netlink",loc);
+    st->name=dict_read_string(dict,"name",False,description,loc);
     if (!st->name) st->name=description;
     if (!st->name) st->name=description;
-    dict_read_subnet_list(dict, "networks", True, "netlink", loc,
-                         &st->networks);
-    dict_read_subnet_list(dict, "exclude-remote-networks", False, "netlink",
-                         loc, &st->exclude_remote_networks);
+    l=dict_lookup(dict,"networks");
+    if (l) 
+       st->networks=string_list_to_ipset(l,loc,st->name,"networks");
+    else {
+       Message(M_WARNING,"%s: no local networks (parameter \"networks\") "
+               "defined\n",st->name);
+       st->networks=ipset_new();
+    }
+    l=dict_lookup(dict,"remote-networks");
+    if (l) {
+       st->remote_networks=string_list_to_ipset(l,loc,st->name,
+                                                "remote-networks");
+    } else {
+       struct ipset *empty;
+       empty=ipset_new();
+       st->remote_networks=ipset_complement(empty);
+       ipset_free(empty);
+    }
+
     sa=dict_find_item(dict,"secnet-address",False,"netlink",loc);
     ptpa=dict_find_item(dict,"ptp-address",False,"netlink",loc);
     if (sa && ptpa) {
     sa=dict_find_item(dict,"secnet-address",False,"netlink",loc);
     ptpa=dict_find_item(dict,"ptp-address",False,"netlink",loc);
     if (sa && ptpa) {
@@ -828,12 +860,16 @@ netlink_deliver_fn *netlink_init(struct netlink *st,
                 "ptp-address for this netlink device\n");
     }
     if (sa) {
                 "ptp-address for this netlink device\n");
     }
     if (sa) {
-       st->secnet_address=string_to_ipaddr(sa,"netlink");
+       st->secnet_address=string_item_to_ipaddr(sa,"netlink");
        st->ptp=False;
     } else {
        st->ptp=False;
     } else {
-       st->secnet_address=string_to_ipaddr(ptpa,"netlink");
+       st->secnet_address=string_item_to_ipaddr(ptpa,"netlink");
        st->ptp=True;
     }
        st->ptp=True;
     }
+    /* XXX we may want to subtract secnet_address from networks here, to
+       be strictly correct.  It shouldn't make any practical difference,
+       though, and will make the route dump look complicated... */
+    st->subnets=ipset_to_subnet_list(st->networks);
     st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
     buffer_new(&st->icmp,ICMP_BUFSIZE);
     st->n_routes=0;
     st->mtu=dict_read_number(dict, "mtu", False, "netlink", loc, DEFAULT_MTU);
     buffer_new(&st->icmp,ICMP_BUFSIZE);
     st->n_routes=0;
@@ -868,7 +904,7 @@ static bool_t null_set_route(void *sst, struct netlink_route *route)
     string_t t;
 
     if (route->up!=route->kup) {
     string_t t;
 
     if (route->up!=route->kup) {
-       t=subnet_to_string(&route->net);
+       t=subnet_to_string(route->net);
        Message(M_INFO,"%s: setting route %s to state %s\n",st->nl.name,
                t, route->up?"up":"down");
        free(t);
        Message(M_INFO,"%s: setting route %s to state %s\n",st->nl.name,
                t, route->up?"up":"down");
        free(t);
index c13b0ae44cce6c58fa8488c4c25848639f29df96..9f46fa8807a5951160e4b9f661250096369eece4 100644 (file)
--- a/netlink.h
+++ b/netlink.h
@@ -13,7 +13,8 @@ struct netlink_client {
     closure_t cl;
     struct netlink_if ops;
     struct netlink *nst;
     closure_t cl;
     struct netlink_if ops;
     struct netlink *nst;
-    struct subnet_list networks;
+    struct ipset *networks;
+    struct subnet_list *subnets; /* Same information as 'networks' */
     netlink_deliver_fn *deliver;
     void *dst;
     string_t name;
     netlink_deliver_fn *deliver;
     void *dst;
     string_t name;
@@ -45,8 +46,9 @@ struct netlink {
     string_t name;
     uint32_t max_start_pad;
     uint32_t max_end_pad;
     string_t name;
     uint32_t max_start_pad;
     uint32_t max_end_pad;
-    struct subnet_list networks;
-    struct subnet_list exclude_remote_networks;
+    struct ipset *networks; /* Local networks */
+    struct subnet_list *subnets; /* Same information as networks */
+    struct ipset *remote_networks; /* Allowable remote networks */
     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 secnet_address; /* our own address, or the address of the
                                other end of a point-to-point link */
     bool_t ptp;
index d9d01cec2c1abc090e8c4911482c071664f3d514..8e464beb464707b5761338b0b29b81f62bacdfde 100644 (file)
--- a/process.c
+++ b/process.c
@@ -5,6 +5,23 @@
 #include <sys/wait.h>
 #include "process.h"
 
 #include <sys/wait.h>
 #include "process.h"
 
+/* Advice about children from Peter:
+Better way: before the fork, make a pipe. In the child close the
++reading end. Make the writing end close-on-exec. If the dup2 or exec fails,
++write the errno value. In the parent, close the writing end. Now you can read
++from it. If you get an errno value from the pipe, the process failed and you
++know why. If you get EOF, the exec succeeded.
+
+<Senji> So, close on exec only closes if exec isn't going to return then?
+<Diziet> qu: I wouldn't bother with all that with pipes.  Remember that the
++runtime system can still make exec fail when it's `too late'.
+<Senji> Diz - I would rather have a coherant error message than 'child failed'
+<Diziet> The child, if it fails to exec, should print a message to stderr
++(giving errno and what it was trying to execute, most likely), and exit
++nonzero.
+<Diziet> It should exit calling _exit.
+*/
+
 /* Process handling - subprocesses, signals, etc. */
 
 static bool_t signal_handling=False;
 /* Process handling - subprocesses, signals, etc. */
 
 static bool_t signal_handling=False;
index a3cf15334d32e60fd2122567878982203693b283..20f9999ed43834eb21d599ddb958a78162287d54 100644 (file)
--- a/secnet.c
+++ b/secnet.c
@@ -22,6 +22,7 @@ extern char version[];
 
 /* XXX should be from autoconf */
 static char *configfile="/etc/secnet/secnet.conf";
 
 /* XXX should be from autoconf */
 static char *configfile="/etc/secnet/secnet.conf";
+static char *sites_key="sites";
 bool_t just_check_config=False;
 static char *userid=NULL;
 static uid_t uid=0;
 bool_t just_check_config=False;
 static char *userid=NULL;
 static uid_t uid=0;
@@ -73,10 +74,11 @@ static void parse_options(int argc, char **argv)
            {"debug", 1, 0, 'd'},
            {"config", 1, 0, 'c'},
            {"just-check-config", 0, 0, 'j'},
            {"debug", 1, 0, 'd'},
            {"config", 1, 0, 'c'},
            {"just-check-config", 0, 0, 'j'},
+           {"sites-key", 1, 0, 's'},
            {0,0,0,0}
        };
 
            {0,0,0,0}
        };
 
-       c=getopt_long(argc, argv, "vwdnjc:ft:",
+       c=getopt_long(argc, argv, "vwdnjc:ft:s:",
                      long_options, &option_index);
        if (c==-1)
            break;
                      long_options, &option_index);
        if (c==-1)
            break;
@@ -90,11 +92,15 @@ static void parse_options(int argc, char **argv)
                    "  -w, --nowarnings        suppress warnings\n"
                    "  -v, --verbose           output extra diagnostics\n"
                    "  -c, --config=filename   specify a configuration file\n"
                    "  -w, --nowarnings        suppress warnings\n"
                    "  -v, --verbose           output extra diagnostics\n"
                    "  -c, --config=filename   specify a configuration file\n"
-                   "  -j, --just-check-config stop after reading configfile\n"
+                   "  -j, --just-check-config stop after reading "
+                   "configuration file\n"
+                   "  -s, --sites-key=name    configuration key that "
+                   "specifies active sites\n"
                    "  -n, --nodetach          do not run in background\n"
                    "  -d, --debug=item,...    set debug options\n"
                    "      --help              display this help and exit\n"
                    "  -n, --nodetach          do not run in background\n"
                    "  -d, --debug=item,...    set debug options\n"
                    "      --help              display this help and exit\n"
-                   "      --version           output version information and exit\n"
+                   "      --version           output version information "
+                   "and exit\n"
                );
            exit(0);
            break;
                );
            exit(0);
            break;
@@ -137,6 +143,13 @@ static void parse_options(int argc, char **argv)
            just_check_config=True;
            break;
 
            just_check_config=True;
            break;
 
+       case 's':
+           if (optarg)
+               sites_key=safe_strdup(optarg,"sites-key");
+           else
+               fatal("secnet: no sites key specified");
+           break;
+
        case '?':
            break;
 
        case '?':
            break;
 
@@ -202,10 +215,10 @@ static void setup(dict_t *config)
     }
 
     /* Go along site list, starting sites */
     }
 
     /* Go along site list, starting sites */
-    l=dict_lookup(config,"sites");
+    l=dict_lookup(config,sites_key);
     if (!l) {
     if (!l) {
-       Message(M_WARNING,"secnet: configuration did not define any "
-               "remote sites\n");
+       Message(M_WARNING,"secnet: configuration key \"%s\" is missing; no "
+               "remote sites are defined\n",sites_key);
     } else {
        i=0;
        while ((site=list_elem(l, i++))) {
     } else {
        i=0;
        while ((site=list_elem(l, i++))) {
index 3821b81cddf2386592409754f78f70a9d4ee75e1..c40ed1bddd70cf03b54b3de13ca71d9cde954453 100644 (file)
--- a/secnet.h
+++ b/secnet.h
 typedef char *string_t;
 typedef enum {False,True} bool_t;
 
 typedef char *string_t;
 typedef enum {False,True} bool_t;
 
-#define ASSERT(x) do { if (!(x)) { fatal("assertion failed line " __LINE__ \
-                                        " file " __FILE__ "\n"); } while(0)
-
-/***** SHARED types *****/
-
-/* These are stored in HOST byte order */
-struct subnet {
-    uint32_t prefix;
-    uint32_t mask;
-    uint32_t len;
-};
-
-struct subnet_list {
-    uint32_t entries;
-    struct subnet *list;
-};
-
-/***** END of shared types *****/
+#define ASSERT(x) do { if (!(x)) { fatal("assertion failed line %d file " \
+                                        __FILE__ "\n",__LINE__); } } while(0)
 
 /***** CONFIGURATION support *****/
 
 
 /***** CONFIGURATION support *****/
 
@@ -112,10 +96,6 @@ extern uint32_t dict_read_number(dict_t *dict, string_t key, bool_t required,
                                 string_t desc, struct cloc loc, uint32_t def);
 extern bool_t dict_read_bool(dict_t *dict, string_t key, bool_t required,
                             string_t desc, struct cloc loc, bool_t def);
                                 string_t desc, struct cloc loc, uint32_t def);
 extern bool_t dict_read_bool(dict_t *dict, string_t key, bool_t required,
                             string_t desc, struct cloc loc, bool_t def);
-extern void dict_read_subnet_list(dict_t *dict, string_t key, bool_t required,
-                                 string_t desc, struct cloc loc,
-                                 struct subnet_list *sl);
-extern uint32_t string_to_ipaddr(item_t *i, string_t desc);
 struct flagstr {
     string_t name;
     uint32_t value;
 struct flagstr {
     string_t name;
     uint32_t value;
@@ -386,12 +366,15 @@ 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);
 typedef void netlink_register_fn(void *st, netlink_deliver_fn *deliver,
                                 void *dst, uint32_t max_start_pad,
                                 uint32_t max_end_pad);
-
+typedef void netlink_output_config_fn(void *st, struct buffer_if *buf);
+typedef bool_t netlink_check_config_fn(void *st, struct buffer_if *buf);
 struct netlink_if {
     void *st;
     netlink_register_fn *reg;
     netlink_deliver_fn *deliver;
     netlink_link_quality_fn *set_quality;
 struct netlink_if {
     void *st;
     netlink_register_fn *reg;
     netlink_deliver_fn *deliver;
     netlink_link_quality_fn *set_quality;
+    netlink_output_config_fn *output_config;
+    netlink_check_config_fn *check_config;
 };
 
 /* DH interface */
 };
 
 /* DH interface */
diff --git a/site.c b/site.c
index fc045c9098c5ebfc57cfc9604a5f0d3394d4a7bd..cb0e0aa858813eae3c95e2f415054daa92b36e57 100644 (file)
--- a/site.c
+++ b/site.c
@@ -221,7 +221,8 @@ static void slog(struct site *st, uint32_t event, string_t msg, ...)
 }
 
 static void set_link_quality(struct site *st);
 }
 
 static void set_link_quality(struct site *st);
-static bool_t initiate_key_setup(struct site *st);
+static void delete_key(struct site *st, string_t reason, uint32_t loglevel);
+static bool_t initiate_key_setup(struct site *st, string_t reason);
 static void enter_state_run(struct site *st);
 static bool_t enter_state_resolve(struct site *st);
 static bool_t enter_state_sentmsg1(struct site *st);
 static void enter_state_run(struct site *st);
 static bool_t enter_state_resolve(struct site *st);
 static bool_t enter_state_sentmsg1(struct site *st);
@@ -516,6 +517,9 @@ static bool_t generate_msg5(struct site *st)
     /* We are going to add three words to the transformed message */
     buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
     buf_append_uint32(&st->buffer,LABEL_MSG5);
     /* We are going to add three words to the transformed message */
     buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
     buf_append_uint32(&st->buffer,LABEL_MSG5);
+    /* Give the netlink code an opportunity to put its own stuff in the
+       message (configuration information, etc.) */
+    st->netlink->output_config(st->netlink->st,&st->buffer);
     st->new_transform->forwards(st->new_transform->st,&st->buffer,
                                &transform_err);
     buf_prepend_uint32(&st->buffer,LABEL_MSG5);
     st->new_transform->forwards(st->new_transform->st,&st->buffer,
                                &transform_err);
     buf_prepend_uint32(&st->buffer,LABEL_MSG5);
@@ -565,6 +569,10 @@ static bool_t process_msg5(struct site *st, struct buffer_if *msg5,
        slog(st,LOG_SEC,"MSG5/PING packet contained invalid data");
        return False;
     }
        slog(st,LOG_SEC,"MSG5/PING packet contained invalid data");
        return False;
     }
+    if (!st->netlink->check_config(st->netlink->st,msg5)) {
+       slog(st,LOG_SEC,"MSG5/PING packet contained bad netlink config");
+       return False;
+    }
     CHECK_EMPTY(msg5);
     return True;
 }
     CHECK_EMPTY(msg5);
     return True;
 }
@@ -577,6 +585,9 @@ static bool_t generate_msg6(struct site *st)
     /* We are going to add three words to the transformed message */
     buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
     buf_append_uint32(&st->buffer,LABEL_MSG6);
     /* We are going to add three words to the transformed message */
     buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
     buf_append_uint32(&st->buffer,LABEL_MSG6);
+    /* Give the netlink code an opportunity to put its own stuff in the
+       message (configuration information, etc.) */
+    st->netlink->output_config(st->netlink->st,&st->buffer);
     st->new_transform->forwards(st->new_transform->st,&st->buffer,
                                &transform_err);
     buf_prepend_uint32(&st->buffer,LABEL_MSG6);
     st->new_transform->forwards(st->new_transform->st,&st->buffer,
                                &transform_err);
     buf_prepend_uint32(&st->buffer,LABEL_MSG6);
@@ -607,6 +618,10 @@ static bool_t process_msg6(struct site *st, struct buffer_if *msg6,
        slog(st,LOG_SEC,"MSG6/PONG packet contained invalid data");
        return False;
     }
        slog(st,LOG_SEC,"MSG6/PONG packet contained invalid data");
        return False;
     }
+    if (!st->netlink->check_config(st->netlink->st,msg6)) {
+       slog(st,LOG_SEC,"MSG6/PONG packet contained bad netlink config");
+       return False;
+    }
     CHECK_EMPTY(msg6);
     return True;
 }
     CHECK_EMPTY(msg6);
     return True;
 }
@@ -620,7 +635,7 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0,
 
     if (!st->current_valid) {
        slog(st,LOG_DROP,"incoming message but no current key -> dropping");
 
     if (!st->current_valid) {
        slog(st,LOG_DROP,"incoming message but no current key -> dropping");
-       return initiate_key_setup(st);
+       return initiate_key_setup(st,"incoming message but no current key");
     }
 
     if (!unpick_msg0(st,msg0,&m)) return False;
     }
 
     if (!unpick_msg0(st,msg0,&m)) return False;
@@ -629,11 +644,16 @@ static bool_t process_msg0(struct site *st, struct buffer_if *msg0,
                                       msg0,&transform_err)) {
        /* There's a problem */
        slog(st,LOG_SEC,"transform: %s",transform_err);
                                       msg0,&transform_err)) {
        /* There's a problem */
        slog(st,LOG_SEC,"transform: %s",transform_err);
-       return initiate_key_setup(st);
+       return initiate_key_setup(st,"incoming message would not decrypt");
     }
     CHECK_AVAIL(msg0,4);
     type=buf_unprepend_uint32(msg0);
     switch(type) {
     }
     CHECK_AVAIL(msg0,4);
     type=buf_unprepend_uint32(msg0);
     switch(type) {
+    case LABEL_MSG7:
+       /* We must forget about the current session. */
+       delete_key(st,"request from peer",LOG_SEC);
+       return True;
+       break;
     case LABEL_MSG9:
        /* Deliver to netlink layer */
        st->netlink->deliver(st->netlink->st,msg0);
     case LABEL_MSG9:
        /* Deliver to netlink layer */
        st->netlink->deliver(st->netlink->st,msg0);
@@ -701,15 +721,15 @@ static void site_resolve_callback(void *sst, struct in_addr *address)
     }
 }
 
     }
 }
 
-static bool_t initiate_key_setup(struct site *st)
+static bool_t initiate_key_setup(struct site *st,string_t reason)
 {
     if (st->state!=SITE_RUN) return False;
 {
     if (st->state!=SITE_RUN) return False;
+    slog(st,LOG_SETUP_INIT,"initiating key exchange (%s)",reason);
     if (st->address) {
     if (st->address) {
-       slog(st,LOG_SETUP_INIT,"initiating key exchange; resolving address");
+       slog(st,LOG_SETUP_INIT,"resolving peer address");
        return enter_state_resolve(st);
     } else if (st->peer_valid) {
        return enter_state_resolve(st);
     } else if (st->peer_valid) {
-       slog(st,LOG_SETUP_INIT,"initiating key exchange using old "
-            "peer address");
+       slog(st,LOG_SETUP_INIT,"using old peer address");
        st->setup_peer=st->peer;
        return enter_state_sentmsg1(st);
     }
        st->setup_peer=st->peer;
        return enter_state_sentmsg1(st);
     }
@@ -736,6 +756,18 @@ static void activate_new_key(struct site *st)
     enter_state_run(st);
 }
 
     enter_state_run(st);
 }
 
+static void delete_key(struct site *st, string_t reason, uint32_t loglevel)
+{
+    if (st->current_valid) {
+       slog(st,loglevel,"session closed (%s)",reason);
+
+       st->current_valid=False;
+       st->current_transform->delkey(st->current_transform->st);
+       st->current_key_timeout=0;
+       set_link_quality(st);
+    }
+}
+
 static void state_assert(struct site *st, bool_t ok)
 {
     if (!ok) fatal("state_assert\n");
 static void state_assert(struct site *st, bool_t ok)
 {
     if (!ok) fatal("state_assert\n");
@@ -745,14 +777,7 @@ static void enter_state_stop(struct site *st)
 {
     st->state=SITE_STOP;
     st->timeout=0;
 {
     st->state=SITE_STOP;
     st->timeout=0;
-    st->current_transform->delkey(st->current_transform->st);
-    st->current_valid=False;
-    st->current_key_timeout=0;
-    
-    st->peer_valid=False;
-
-    set_link_quality(st);
-    
+    delete_key(st,"entering state STOP",LOG_TIMEOUT_KEY);
     st->new_transform->delkey(st->new_transform->st);
 }
 
     st->new_transform->delkey(st->new_transform->st);
 }
 
@@ -887,6 +912,27 @@ static bool_t send_msg6(struct site *st)
     return False;
 }
 
     return False;
 }
 
+static bool_t send_msg7(struct site *st,string_t reason)
+{
+    string_t transform_err;
+
+    if (st->current_valid && st->peer_valid && st->buffer.free) {
+       BUF_ALLOC(&st->buffer,"site:MSG7");
+       buffer_init(&st->buffer,st->transform->max_start_pad+(4*3));
+       buf_append_uint32(&st->buffer,LABEL_MSG7);
+       buf_append_string(&st->buffer,reason);
+       st->current_transform->forwards(st->current_transform->st,
+                                       &st->buffer, &transform_err);
+       buf_prepend_uint32(&st->buffer,LABEL_MSG0);
+       buf_prepend_uint32(&st->buffer,(uint32_t)st);
+       buf_prepend_uint32(&st->buffer,st->remote_session_id);
+       st->comm->sendmsg(st->comm->st,&st->buffer,&st->peer);
+       BUF_FREE(&st->buffer);
+       return True;
+    }
+    return False;
+}
+
 /* We go into this state if our peer becomes uncommunicative. Similar to
    the "stop" state, we forget all session keys for a while, before
    re-entering the "run" state. */
 /* We go into this state if our peer becomes uncommunicative. Similar to
    the "stop" state, we forget all session keys for a while, before
    re-entering the "run" state. */
@@ -943,11 +989,7 @@ static void site_afterpoll(void *sst, struct pollfd *fds, int nfds,
        }
     }
     if (st->current_key_timeout && *now>st->current_key_timeout) {
        }
     }
     if (st->current_key_timeout && *now>st->current_key_timeout) {
-       slog(st,LOG_TIMEOUT_KEY,"maximum key life exceeded; session closed");
-       st->current_valid=False;
-       st->current_transform->delkey(st->current_transform->st);
-       st->current_key_timeout=0;
-       set_link_quality(st);
+       delete_key(st,"maximum key life exceeded",LOG_TIMEOUT_KEY);
     }
 }
 
     }
 }
 
@@ -983,7 +1025,7 @@ static void site_outgoing(void *sst, struct buffer_if *buf)
 
     slog(st,LOG_DROP,"discarding outgoing packet of size %d",buf->size);
     BUF_FREE(buf);
 
     slog(st,LOG_DROP,"discarding outgoing packet of size %d",buf->size);
     BUF_FREE(buf);
-    initiate_key_setup(st);
+    initiate_key_setup(st,"outgoing packet");
 }
 
 /* This function is called by the communication device to deliver
 }
 
 /* This function is called by the communication device to deliver
@@ -1045,10 +1087,19 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
        return False; /* Not for us. */
     }
     if (dest==(uint32_t)st) {
        return False; /* Not for us. */
     }
     if (dest==(uint32_t)st) {
-       uint32_t msgtype=ntohl(*(uint32_t *)(buf->start+8));
+       uint32_t msgtype=ntohl(get_uint32(buf->start+8));
        /* Explicitly addressed to us */
        if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True);
        switch (msgtype) {
        /* Explicitly addressed to us */
        if (msgtype!=LABEL_MSG0) dump_packet(st,buf,source,True);
        switch (msgtype) {
+       case 0: /* NAK */
+           /* If the source is our current peer then initiate a key setup,
+              because our peer's forgotten the key */
+           if (get_uint32(buf->start+4)==st->remote_session_id) {
+               initiate_key_setup(st,"received a NAK");
+           } else {
+               slog(st,LOG_SEC,"bad incoming NAK");
+           }
+           break;
        case LABEL_MSG0:
            process_msg0(st,buf,source);
            break;
        case LABEL_MSG0:
            process_msg0(st,buf,source);
            break;
@@ -1113,10 +1164,6 @@ static bool_t site_incoming(void *sst, struct buffer_if *buf,
                slog(st,LOG_SEC,"invalid MSG6");
            }
            break;
                slog(st,LOG_SEC,"invalid MSG6");
            }
            break;
-       case LABEL_MSG8:
-           /* NAK packet: enter state where we ping and check for response */
-           slog(st,LOG_ERROR,"received a NAK");
-           break;
        default:
            slog(st,LOG_SEC,"received message of unknown type 0x%08x",
                 msgtype);
        default:
            slog(st,LOG_SEC,"received message of unknown type 0x%08x",
                 msgtype);
@@ -1136,6 +1183,14 @@ static void site_control(void *vst, bool_t run)
     else enter_state_stop(st);
 }
 
     else enter_state_stop(st);
 }
 
+static void site_phase_hook(void *sst, uint32_t newphase)
+{
+    struct site *st=sst;
+
+    /* The program is shutting down; tell our peer */
+    send_msg7(st,"shutting down");
+}
+
 static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
                          list_t *args)
 {
 static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
                          list_t *args)
 {
@@ -1254,6 +1309,8 @@ static list_t *site_apply(closure_t *self, struct cloc loc, dict_t *context,
 
     enter_state_stop(st);
 
 
     enter_state_stop(st);
 
+    add_hook(PHASE_SHUTDOWN,site_phase_hook,st);
+
     return new_closure(&st->cl);
 }
 
     return new_closure(&st->cl);
 }
 
diff --git a/slip.c b/slip.c
index d0a77c0b7a118ee7c63fa25c6216d105f2adffd7..60152c9a984deea96a8839e89d6222fd346660a4 100644 (file)
--- a/slip.c
+++ b/slip.c
@@ -114,7 +114,7 @@ static void slip_init(struct slip *st, struct cloc loc, dict_t *dict,
        netlink_init(&st->nl,st,loc,dict,
                     "netlink-userv-ipif",NULL,to_host);
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"name",loc);
        netlink_init(&st->nl,st,loc,dict,
                     "netlink-userv-ipif",NULL,to_host);
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"name",loc);
-    st->local_address=string_to_ipaddr(
+    st->local_address=string_item_to_ipaddr(
        dict_find_item(dict,"local-address", True, name, loc),"netlink");
     BUF_ALLOC(st->buff,"slip_init");
     st->pending_esc=False;
        dict_find_item(dict,"local-address", True, name, loc),"netlink");
     BUF_ALLOC(st->buff,"slip_init");
     st->pending_esc=False;
@@ -240,6 +240,8 @@ static void userv_invoke_userv(struct userv *st)
     string_t nets;
     string_t s;
     struct netlink_route *r;
     string_t nets;
     string_t s;
     struct netlink_route *r;
+    struct ipset *isnets;
+    struct subnet_list *snets;
     int i;
     uint8_t confirm;
 
     int i;
     uint8_t confirm;
 
@@ -255,19 +257,31 @@ static void userv_invoke_userv(struct userv *st)
             ipaddr_to_string(st->slip.local_address),
             ipaddr_to_string(st->slip.nl.secnet_address),st->slip.nl.mtu);
 
             ipaddr_to_string(st->slip.local_address),
             ipaddr_to_string(st->slip.nl.secnet_address),st->slip.nl.mtu);
 
-    nets=safe_malloc(1024,"userv_invoke_userv:nets");
-    *nets=0;
     r=st->slip.nl.routes;
     r=st->slip.nl.routes;
+    isnets=ipset_new();
     for (i=0; i<st->slip.nl.n_routes; i++) {
        if (r[i].up) {
     for (i=0; i<st->slip.nl.n_routes; i++) {
        if (r[i].up) {
+           struct ipset *sn,*nis;
            r[i].kup=True;
            r[i].kup=True;
-           s=subnet_to_string(&r[i].net);
-           strcat(nets,s);
-           strcat(nets,",");
-           free(s);
+           sn=ipset_from_subnet(r[i].net);
+           nis=ipset_union(isnets,sn);
+           ipset_free(sn);
+           ipset_free(isnets);
+           isnets=nis;
        }
     }
        }
     }
+    snets=ipset_to_subnet_list(isnets);
+    ipset_free(isnets);
+    nets=safe_malloc(20*snets->entries,"userv_invoke_userv:nets");
+    *nets=0;
+    for (i=0; i<snets->entries; i++) {
+       s=subnet_to_string(snets->list[i]);
+       strcat(nets,s);
+       strcat(nets,",");
+       free(s);
+    }
     nets[strlen(nets)-1]=0;
     nets[strlen(nets)-1]=0;
+    subnet_list_free(snets);
 
     Message(M_INFO,"%s: about to invoke: %s %s %s %s %s\n",st->slip.nl.name,
            st->userv_path,st->service_user,st->service_name,addrs,nets);
 
     Message(M_INFO,"%s: about to invoke: %s %s %s %s %s\n",st->slip.nl.name,
            st->userv_path,st->service_user,st->service_name,addrs,nets);
diff --git a/tun.c b/tun.c
index 90b9161022abc0d5c268702733ee1db7190cfb92..20ae29b130bd79306cd05fc7e52fc01f28266890 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -233,7 +233,7 @@ static list_t *tun_apply(closure_t *self, struct cloc loc, dict_t *context,
     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
     if (!st->route_path) st->route_path="route";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
     if (!st->route_path) st->route_path="route";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
-    st->local_address=string_to_ipaddr(
+    st->local_address=string_item_to_ipaddr(
        dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
 
     add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
        dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
 
     add_hook(PHASE_GETRESOURCES,tun_phase_hook,st);
@@ -276,7 +276,7 @@ static list_t *tun_old_apply(closure_t *self, struct cloc loc, dict_t *context,
     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
     if (!st->route_path) st->route_path="route";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
     if (!st->ifconfig_path) st->ifconfig_path="ifconfig";
     if (!st->route_path) st->route_path="route";
     st->buff=find_cl_if(dict,"buffer",CL_BUFFER,True,"tun-netlink",loc);
-    st->local_address=string_to_ipaddr(
+    st->local_address=string_item_to_ipaddr(
        dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
 
     /* Old TUN interface: the network interface name depends on which
        dict_find_item(dict,"local-address", True, "netlink", loc),"netlink");
 
     /* Old TUN interface: the network interface name depends on which
diff --git a/udp.c b/udp.c
index 307a67a9f7d67cdb8dd42758040d3435e054d070..65208650f998a7cbc5f670a1d7114ae40adc677b 100644 (file)
--- a/udp.c
+++ b/udp.c
@@ -21,6 +21,7 @@
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include "util.h"
 #include <sys/socket.h>
 #include <sys/wait.h>
 #include "util.h"
+#include "unaligned.h"
 
 static beforepoll_fn udp_beforepoll;
 static afterpoll_fn udp_afterpoll;
 
 static beforepoll_fn udp_beforepoll;
 static afterpoll_fn udp_afterpoll;
@@ -91,8 +92,17 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds,
                    }
                }
                if (!done) {
                    }
                }
                if (!done) {
+                   uint32_t source,dest;
                    /* XXX manufacture and send NAK packet */
                    /* XXX manufacture and send NAK packet */
-                   Message(M_WARNING,"Need to send NAK\n");
+                   source=get_uint32(st->rbuf->start); /* Us */
+                   dest=get_uint32(st->rbuf->start+4); /* Them */
+                   Message(M_INFO,"udp (port %d): sending NAK\n",st->port);
+                   buffer_init(st->rbuf,0);
+                   buf_append_uint32(st->rbuf,dest);
+                   buf_append_uint32(st->rbuf,source);
+                   buf_append_uint32(st->rbuf,0); /* NAK is msg type 0 */
+                   sendto(st->fd, st->rbuf->start, st->rbuf->size, 0,
+                          (struct sockaddr *)&from, sizeof(from));
                    BUF_FREE(st->rbuf);
                }
                BUF_ASSERT_FREE(st->rbuf);
                    BUF_FREE(st->rbuf);
                }
                BUF_ASSERT_FREE(st->rbuf);