# 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 distclean
+.PHONY: all clean realclean distclean dist install
PACKAGE:=secnet
-VERSION:=0.1.11
+VERSION:=0.1.12
@SET_MAKE@
conffile.c conffile.fl conffile.h conffile.y \
conffile_internal.h config.h.bot \
config.h.in config.h.top configure \
- configure.in debian dh.c \
+ configure.in debian depend.sh dh.c \
example.conf \
getopt.c getopt1.c getopt.h \
- install.sh ipaddr.c ipaddr.h ipaddr.py linux log.c md5.c md5.h \
+ install-sh ipaddr.c ipaddr.h ipaddr.py linux log.c md5.c md5.h \
make-secnet-sites \
modules.c netlink.c netlink.h process.c process.h \
random.c resolver.c rsa.c \
./config.status --recheck
# End of config file remaking rules
-# Manual dependencies section - XXX use autodep eventually
-$(OBJECTS): config.h secnet.h util.h
-conffile.o conffile.tab.o conffile.yy.o: conffile.h conffile_internal.h
-secnet.o: conffile.h process.h
-process.o: process.h
-log.o: process.h
-md5.o: md5.h
-serpent.o transform.o: serpent.h
-serpent.o: serpentsboxes.h
-conffile.o: ipaddr.h
-site.c util.c: unaligned.h
+# C and header file dependency rules
+SOURCES:=$(OBJECTS:.o=.c)
+DEPENDS:=$(OBJECTS:.o=.d)
+
+$(DEPENDS): ${srcdir}/depend.sh
+
+%.d: %.c
+ ${srcdir}/depend.sh $(srcdir) $(CFLAGS) $< > $@
+
+-include $(DEPENDS)
+
+# Manual dependencies section
conffile.yy.c: conffile.fl conffile.tab.c
conffile.tab.c: conffile.y
-netlink.o tun.o slip.o: netlink.h
# End of manual dependencies section
secnet: $(OBJECTS)
echo "char version[]=\"secnet-$(VERSION)\";" >version.c
install: all
- $(INSTALL_PROGRAM) -D secnet $(sbindir)/`echo secnet|sed '$(transform)'`
- $(INSTALL_PROGRAM) -D make-secnet-sites $(sbindir)/`echo make-secnet-sites|sed '$(transform)'`
- $(INSTALL) -D ipaddr.py $(prefix)/share/secnet/ipaddr.py
+ $(INSTALL) -d $(prefix)/share/secnet $(sbindir)
+ $(INSTALL_PROGRAM) secnet $(sbindir)/`echo secnet|sed '$(transform)'`
+ $(INSTALL_PROGRAM) ${srcdir}/make-secnet-sites $(sbindir)/`echo make-secnet-sites|sed '$(transform)'`
+ $(INSTALL) ${srcdir}/ipaddr.py $(prefix)/share/secnet/ipaddr.py
clean:
$(RM) -f *.o *.yy.c *.tab.[ch] $(TARGETS) core version.c
realclean: clean
- $(RM) -f *~ Makefile config.h \
+ $(RM) -f *~ Makefile config.h *.d \
config.log config.status config.cache \
stamp-h Makefile.bak
Modular transform code: choice of block ciphers, modes, sequence
numbers / timestamps, etc. similar to IWJ's udptunnel
+Path-MTU discovery for each tunnel, and fragmentation/DF support in
+netlink code.
+
+* New in version 0.1.12
+
+IMPORTANT: fix calculation of 'now' in secnet.c; necessary for correct
+operation.
+
+(Only interesting for people building and modifying secnet by hand:
+the Makefile now works out most dependencies automatically.)
+
+The netlink code no longer produces an internal routing table sorted
+by netmask length. Instead, netlink instances have a 'priority'; the
+table of routes is sorted by priority. Devices like laptops that have
+tunnels that must sometimes 'mask' parts of other tunnels should be
+given higher priorities. If a priority is not specified it is assumed
+to be zero.
+
+Example usage:
+site laptop { ...
+ link netlink {
+ route "192.168.73.74/31";
+ priority 10;
+ };
+};
+
* New in version 0.1.11
Lists of IP addresses in the configuration file can now include
-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)
process.c: capture output from children in sys_cmd() and log it
-random.c: test
+random.c: test properly
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.
static void dict_iadd(dict_t *dict, atom_t key, list_t *val)
{
struct entry *e;
- /* XXX May want to permit redefinition of keys in the future */
- /* (although it could be very confusing) */
if (dict_ilookup_primitive(dict, key)) {
fatal("duplicate key \"%s\" in dictionary\n",key);
}
-secnet (0.1.11-1) unstable; urgency=low
+secnet (0.1.12-1) unstable; urgency=low
* New upstream version.
- * 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
--- /dev/null
+#!/bin/sh
+
+# For more information see "Recursive Make Considered Harmful" at
+# http://www.canb.auug.org.au/~millerp/rmch/recu-make-cons-harm.html
+
+set -e
+set -u
+
+cutout="$1"
+shift
+
+# cutout may contain the character '.' which means a special thing to sed
+# Escape all '.'s (i.e. '..' -> '\.\.')
+cutout2="`echo ${cutout} | sed -e 's@\.@\\\.@g'`"
+
+# We don't bother depending on system header files (which have names
+# starting with '/'). We arrange for both the .o and the .d file to depend
+# on the appropriate header files. We're using VPATH, so we turn pathnames
+# of the form "${srcdir}/foo" into just "foo" (we expect srcdir to be
+# passed as our first command line argument)
+gcc -M -MG "$@" |
+sed -e 's@ /[^ ]*@@g' -e 's@^\(.*\)\.o:@\1.d \1.o:@' -e "s@${cutout2}/@@g"
# secnet example configuration file
# Log facility
-log syslog {
- ident "secnet";
- facility "local0";
+log logfile {
+ filename "/var/log/secnet";
+ class "info","notice","warning","error","security","fatal";
+ # There are some useful message classes that could replace
+ # this list:
+ # 'default' -> warning,error,security,fatal
+ # 'verbose' -> info,notice,default
+ # 'quiet' -> fatal
};
-# Alternatively you could log to a file:
-# log logfile {
-# filename "/var/log/secnet";
-# class "info","notice","warning","error","security","fatal";
-# # There are some useful message classes that could replace
-# # this list:
-# # 'default' -> warning,error,security,fatal
-# # 'verbose' -> info,notice,default
-# # 'quiet' -> fatal
+# Alternatively you could log to syslog:
+# log syslog {
+# ident "secnet";
+# facility "local0";
# };
+
# Systemwide configuration (all other configuration is per-site):
# log a log facility for program messages
# userid who we try to run as after setup
local-address "192.168.x.x"; # IP address of host's tunnel interface
secnet-address "192.168.x.x"; # IP address of this secnet
+ # Tunnels are only allowed to use these networks; attempts to
+ # claim IP addresses in any other ranges is a configuration error
+ remote-networks "192.168.0.0/24", "172.16.0.0/12", "10.0.0.0/8";
+
# MTU of the tunnel interface. Should be kept under the path-MTU
# (by at least 60 bytes) between this secnet and its peers for
# optimum performance.
# that it's non-blocking. XXX 'yes' isn't implemented yet.
random randomfile("/dev/urandom",no);
-# If you're using the make-secnet-sites.py script then your local-name
+# If you're using the make-secnet-sites script then your local-name
# will be of the form "vpnname/location/site" eg. "sgo/greenend/sinister"
local-name "your-site-name";
local-key rsa-private("/etc/secnet/key");
--- /dev/null
+#!/bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5 (mit/util/scripts/install.sh).
+#
+# Copyright 1991 by the Massachusetts Institute of Technology
+#
+# Permission to use, copy, modify, distribute, and sell this software and its
+# documentation for any purpose is hereby granted without fee, provided that
+# the above copyright notice appear in all copies and that both that
+# copyright notice and this permission notice appear in supporting
+# documentation, and that the name of M.I.T. not be used in advertising or
+# publicity pertaining to distribution of the software without specific,
+# written prior permission. M.I.T. makes no representations about the
+# suitability of this software for any purpose. It is provided "as is"
+# without express or implied warranty.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch. It can only install one file at a time, a restriction
+# shared with many OS's install programs.
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+transformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
+++ /dev/null
-#!/bin/sh
-
-#
-# install - install a program, script, or datafile
-# This comes from X11R5; it is not part of GNU.
-#
-# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
-#
-# This script is compatible with the BSD install script, but was written
-# from scratch.
-#
-
-
-# set DOITPROG to echo to test this script
-
-# Don't use :- since 4.3BSD and earlier shells don't like it.
-doit="${DOITPROG-}"
-
-
-# put in absolute paths if you don't have them in your path; or use env. vars.
-
-mvprog="${MVPROG-mv}"
-cpprog="${CPPROG-cp}"
-chmodprog="${CHMODPROG-chmod}"
-chownprog="${CHOWNPROG-chown}"
-chgrpprog="${CHGRPPROG-chgrp}"
-stripprog="${STRIPPROG-strip}"
-rmprog="${RMPROG-rm}"
-
-instcmd="$mvprog"
-chmodcmd=""
-chowncmd=""
-chgrpcmd=""
-stripcmd=""
-rmcmd="$rmprog -f"
-mvcmd="$mvprog"
-src=""
-dst=""
-
-while [ x"$1" != x ]; do
- case $1 in
- -c) instcmd="$cpprog"
- shift
- continue;;
-
- -m) chmodcmd="$chmodprog $2"
- shift
- shift
- continue;;
-
- -o) chowncmd="$chownprog $2"
- shift
- shift
- continue;;
-
- -g) chgrpcmd="$chgrpprog $2"
- shift
- shift
- continue;;
-
- -s) stripcmd="$stripprog"
- shift
- continue;;
-
- *) if [ x"$src" = x ]
- then
- src=$1
- else
- dst=$1
- fi
- shift
- continue;;
- esac
-done
-
-if [ x"$src" = x ]
-then
- echo "install: no input file specified"
- exit 1
-fi
-
-if [ x"$dst" = x ]
-then
- echo "install: no destination specified"
- exit 1
-fi
-
-
-# If destination is a directory, append the input filename; if your system
-# does not like double slashes in filenames, you may need to add some logic
-
-if [ -d $dst ]
-then
- dst="$dst"/`basename $src`
-fi
-
-# Make a temp file name in the proper directory.
-
-dstdir=`dirname $dst`
-dsttmp=$dstdir/#inst.$$#
-
-# Move or copy the file name to the temp name
-
-$doit $instcmd $src $dsttmp
-
-# and set any options; do chmod last to preserve setuid bits
-
-if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
-if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
-if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
-if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
-
-# Now rename the file to the real destination.
-
-$doit $rmcmd $dst
-$doit $mvcmd $dsttmp $dst
-
-
-exit 0
}
/* Deliver a packet. "client" is the _origin_ of the packet, not its
-destination. */
+ destination, and is NULL for packets from the host and packets
+ generated internally in secnet. */
static void netlink_packet_deliver(struct netlink *st,
struct netlink_client *client,
struct buffer_if *buf)
return;
}
- /* Packets from the host (client==NULL) will always be routed. Packets
+ /* Packets from the host (client==NULL) may 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;
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)) {
+ for (i=0; i<st->n_clients; i++) {
+ if (st->routes[i]->up &&
+ ipset_contains_addr(st->routes[i]->networks,dest)) {
/* It's an available route to the correct destination. But is
it better than the one we already have? */
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;
+ if (!(st->routes[i]->options&OPT_ALLOWROUTE)) continue;
}
- if (st->routes[i].c->link_quality>best_quality
+ if (st->routes[i]->link_quality>best_quality
|| best_quality==0) {
- best_quality=st->routes[i].c->link_quality;
+ best_quality=st->routes[i]->link_quality;
best_match=i;
- if (st->routes[i].c->options&OPT_ALLOWROUTE)
+ if (st->routes[i]->options&OPT_ALLOWROUTE)
found_allowed=True;
/* If quality isn't perfect we may wish to
consider kicking the tunnel with a 0-length
}
} else {
if (!allow_route &&
- !(st->routes[best_match].c->options&OPT_ALLOWROUTE)) {
+ !(st->routes[best_match]->options&OPT_ALLOWROUTE)) {
string_t s,d;
s=ipaddr_to_string(source);
d=ipaddr_to_string(dest);
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++;
+ /* XXX Fragment if required */
+ st->routes[best_match]->deliver(
+ st->routes[best_match]->dst, buf);
+ st->routes[best_match]->outcount++;
BUF_ASSERT_FREE(buf);
} else {
/* Generate ICMP destination unreachable */
source=ntohl(iph->saddr);
dest=ntohl(iph->daddr);
- /* Check source */
- /* XXX consider generating ICMP if we're not point-to-point and we
- don't like the packet */
+ /* Check source. If we don't like the source, there's no point
+ generating ICMP because we won't know how to get it to the
+ source of the packet. */
if (client) {
/* Check that the packet source is appropriate for the tunnel
it came down */
/* 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 */
+ where it came from. It's up to external software to check
+ address validity and generate ICMP, etc. */
if (st->ptp) {
if (client) {
st->deliver_to_host(st->dst,buf);
return;
}
- /* (st->secnet_address needs checking before matching destination
- addresses) */
+ /* st->secnet_address needs checking before matching destination
+ addresses */
if (dest==st->secnet_address) {
netlink_packet_local(st,client,buf);
BUF_ASSERT_FREE(buf);
netlink_incoming(st,NULL,buf);
}
-static void netlink_set_softlinks(struct netlink *st, struct netlink_client *c,
- bool_t up, uint32_t quality)
+static void netlink_set_quality(void *sst, uint32_t quality)
{
- uint32_t i;
+ struct netlink_client *c=sst;
+ struct netlink *st=c->nst;
- if (!st->routes) return; /* Table has not yet been created */
- for (i=0; i<st->n_routes; i++) {
- if (st->routes[i].c==c) {
- st->routes[i].quality=quality;
- if (!st->routes[i].hard) {
- st->routes[i].up=up;
- st->set_route(st->dst,&st->routes[i]);
- }
- }
+ c->link_quality=quality;
+ c->up=(c->link_quality==LINK_QUALITY_DOWN)?False:True;
+ if (c->options&OPT_SOFTROUTE) {
+ st->set_routes(st->dst,c);
}
}
-static void netlink_set_quality(void *sst, uint32_t quality)
+static void netlink_output_subnets(struct netlink *st, uint32_t loglevel,
+ struct subnet_list *snets)
{
- struct netlink_client *c=sst;
- struct netlink *st=c->nst;
+ uint32_t i;
+ string_t net;
- c->link_quality=quality;
- if (c->link_quality==LINK_QUALITY_DOWN) {
- netlink_set_softlinks(st,c,False,c->link_quality);
- } else {
- netlink_set_softlinks(st,c,True,c->link_quality);
+ for (i=0; i<snets->entries; i++) {
+ net=subnet_to_string(snets->list[i]);
+ Message(loglevel,"%s ",net);
+ free(net);
}
}
Message(c,"%s: point-to-point (remote end is %s); routes:\n",
st->name, net);
free(net);
- for (i=0; i<st->n_routes; i++) {
- net=subnet_to_string(st->routes[i].net);
- Message(c,"%s ",net);
- free(net);
- }
+ netlink_output_subnets(st,c,st->clients->subnets);
Message(c,"\n");
} else {
Message(c,"%s: routing table:\n",st->name);
- for (i=0; i<st->n_routes; i++) {
- net=subnet_to_string(st->routes[i].net);
- Message(c,"%s -> tunnel %s (%s,%s route,%s,quality %d,use %d)\n",net,
- st->routes[i].c->name,
- st->routes[i].hard?"hard":"soft",
- st->routes[i].allow_route?"free":"restricted",
- st->routes[i].up?"up":"down",
- st->routes[i].quality,
- st->routes[i].outcount);
- free(net);
+ for (i=0; i<st->n_clients; i++) {
+ netlink_output_subnets(st,c,st->routes[i]->subnets);
+ Message(c,"-> tunnel %s (%s,%s routes,%s,quality %d,use %d)\n",
+ st->routes[i]->name,
+ st->routes[i]->options&OPT_SOFTROUTE?"soft":"hard",
+ st->routes[i]->options&OPT_ALLOWROUTE?"free":"restricted",
+ st->routes[i]->up?"up":"down",
+ st->routes[i]->link_quality,
+ st->routes[i]->outcount);
}
net=ipaddr_to_string(st->secnet_address);
Message(c,"%s/32 -> netlink \"%s\" (use %d)\n",
}
}
-static int netlink_compare_route_specificity(const void *ap, const void *bp)
+/* ap is a pointer to a member of the routes array */
+static int netlink_compare_client_priority(const void *ap, const void *bp)
{
- const struct netlink_route *a=ap;
- const struct netlink_route *b=bp;
+ const struct netlink_client *const*a=ap;
+ const struct netlink_client *const*b=bp;
- if (a->net.len==b->net.len) return 0;
- if (a->net.len<b->net.len) return 1;
+ if ((*a)->priority==(*b)->priority) return 0;
+ if ((*a)->priority<(*b)->priority) return 1;
return -1;
}
{
struct netlink *st=sst;
struct netlink_client *c;
- uint32_t i,j;
+ uint32_t i;
/* 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. */
- st->routes=safe_malloc(st->n_routes*sizeof(*st->routes),
+ * clients by priority. */
+ st->routes=safe_malloc(st->n_clients*sizeof(*st->routes),
"netlink_phase_hook");
/* Fill the table */
i=0;
- for (c=st->clients; c; c=c->next) {
- 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
- 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&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++;
- }
- }
- /* ASSERT i==st->n_routes */
- if (i!=st->n_routes) {
- fatal("netlink: route count error: expected %d got %d\n",
- st->n_routes,i);
- }
- /* Sort the table in descending order of specificity */
- qsort(st->routes,st->n_routes,sizeof(*st->routes),
- netlink_compare_route_specificity);
+ for (c=st->clients; c; c=c->next)
+ st->routes[i++]=c;
+ /* Sort the table in descending order of priority */
+ qsort(st->routes,st->n_clients,sizeof(*st->routes),
+ netlink_compare_client_priority);
netlink_dump_routes(st,False);
}
return True;
}
+static void netlink_inst_set_mtu(void *sst, uint32_t new_mtu)
+{
+ struct netlink_client *c=sst;
+
+ c->mtu=new_mtu;
+}
+
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;
string_t name;
struct ipset *networks;
- uint32_t options;
+ uint32_t options,priority,mtu;
list_t *l;
name=dict_read_string(dict, "name", True, st->name, loc);
options=string_list_to_word(dict_lookup(dict,"options"),
netlink_option_table,st->name);
- if ((options&OPT_SOFTROUTE) && !st->set_route) {
+ priority=dict_read_number(dict,"priority",False,st->name,loc,0);
+ mtu=dict_read_number(dict,"mtu",False,st->name,loc,0);
+
+ if ((options&OPT_SOFTROUTE) && !st->set_routes) {
cfgfatal(loc,st->name,"this netlink device does not support "
"soft routes.\n");
return NULL;
c->ops.set_quality=netlink_set_quality;
c->ops.output_config=netlink_inst_output_config;
c->ops.check_config=netlink_inst_check_config;
+ c->ops.set_mtu=netlink_inst_set_mtu;
c->nst=st;
c->networks=networks;
c->subnets=ipset_to_subnet_list(networks);
+ c->priority=priority;
c->deliver=NULL;
c->dst=NULL;
c->name=name;
- c->options=options;
c->link_quality=LINK_QUALITY_DOWN;
+ c->mtu=mtu?mtu:st->mtu;
+ c->options=options;
+ c->outcount=0;
+ c->up=False;
+ c->kup=False;
c->next=st->clients;
st->clients=c;
- st->n_routes+=c->subnets->entries;
+ st->n_clients++;
return &c->cl;
}
netlink_deliver_fn *netlink_init(struct netlink *st,
void *dst, struct cloc loc,
dict_t *dict, string_t description,
- netlink_route_fn *set_route,
+ netlink_route_fn *set_routes,
netlink_deliver_fn *to_host)
{
item_t *sa, *ptpa;
st->max_start_pad=0;
st->max_end_pad=0;
st->clients=NULL;
- st->set_route=set_route;
+ st->routes=NULL;
+ st->n_clients=0;
+ st->set_routes=set_routes;
st->deliver_to_host=to_host;
st->name=dict_read_string(dict,"name",False,description,loc);
st->secnet_address=string_item_to_ipaddr(ptpa,"netlink");
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,
+ /* To be strictly correct we could subtract secnet_address from
+ networks here. 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->routes=NULL;
st->outcount=0;
st->localcount=0;
struct netlink nl;
};
-static bool_t null_set_route(void *sst, struct netlink_route *route)
+static bool_t null_set_route(void *sst, struct netlink_client *routes)
{
struct null *st=sst;
- string_t t;
-
- if (route->up!=route->kup) {
- 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);
- route->kup=route->up;
+
+ if (routes->up!=routes->kup) {
+ Message(M_INFO,"%s: setting routes for tunnel %s to state %s\n",
+ st->nl.name,routes->name,
+ routes->up?"up":"down");
+ routes->kup=routes->up;
return True;
}
return False;
struct netlink *nst;
struct ipset *networks;
struct subnet_list *subnets; /* Same information as 'networks' */
+ uint32_t priority; /* Higher priority clients have their networks
+ checked first during routing. This allows
+ things like laptops to supersede whole
+ networks. */
netlink_deliver_fn *deliver;
void *dst;
string_t name;
uint32_t link_quality;
+ uint32_t mtu;
uint32_t options;
- struct netlink_client *next;
-};
-
-struct netlink_route {
- struct subnet net;
- bool_t hard;
- bool_t allow_route;
- bool_t up;
- bool_t kup;
- uint32_t quality; /* provided by client */
uint32_t outcount;
- struct netlink_client *c;
+ bool_t up; /* Should these routes exist in the kernel? */
+ bool_t kup; /* Do these routes exist in the kernel? */
+ struct netlink_client *next;
};
-typedef bool_t netlink_route_fn(void *cst, struct netlink_route *route);
+typedef bool_t netlink_route_fn(void *cst, struct netlink_client *routes);
/* Netlink provides one function to the device driver, to call to deliver
a packet from the device. The device driver provides one function to
uint32_t max_start_pad;
uint32_t max_end_pad;
struct ipset *networks; /* Local networks */
- struct subnet_list *subnets; /* Same information as networks */
+ struct subnet_list *subnets; /* Same as networks, for display */
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 mtu;
- struct netlink_client *clients;
+ struct netlink_client *clients; /* Linked list of clients */
+ struct netlink_client **routes; /* Array of clients, sorted by priority */
+ uint32_t n_clients;
netlink_deliver_fn *deliver_to_host; /* Provided by driver */
- netlink_route_fn *set_route; /* Provided by driver */
+ netlink_route_fn *set_routes; /* Provided by driver */
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,
void *dst, struct cloc loc,
dict_t *dict, string_t description,
- netlink_route_fn *set_route,
+ netlink_route_fn *set_routes,
netlink_deliver_fn *to_host);
#endif /* netlink_h */
#include <errno.h>
#include "secnet.h"
+#ifndef HAVE_LIBADNS
+#error secnet requires ADNS version 1.0 or above
+#endif
#include <adns.h>
+
struct adns {
closure_t cl;
struct resolver_if ops;
if (gettimeofday(&tv_now, NULL)!=0) {
fatal_perror("main loop: gettimeofday");
}
- now=(tv_now.tv_sec*1000)+(tv_now.tv_usec/1000);
+ now=((uint64_t)tv_now.tv_sec*(uint64_t)1000)+
+ ((uint64_t)tv_now.tv_usec/(uint64_t)1000);
idx=0;
for (i=reg; i; i=i->next) {
i->after(i->state, fds+idx, i->nfds, &tv_now, &now);
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);
+typedef void netlink_set_mtu_fn(void *st, uint32_t new_mtu);
struct netlink_if {
void *st;
netlink_register_fn *reg;
netlink_link_quality_fn *set_quality;
netlink_output_config_fn *output_config;
netlink_check_config_fn *check_config;
+ netlink_set_mtu_fn *set_mtu;
};
/* DH interface */
BUF_ASSERT_USED(buf);
- /* XXX crunchy bytestuff code */
+ /* There's probably a much more efficient way of implementing this */
txbuf[j++]=SLIP_END;
for (i=buf->start; i<(buf->start+buf->size); i++) {
switch (*i) {
{
uint32_t i;
- /* XXX really crude unstuff code */
- /* XXX check for buffer overflow */
BUF_ASSERT_USED(st->buff);
for (i=0; i<l; i++) {
if (st->pending_esc) {
string_t addrs;
string_t nets;
string_t s;
- struct netlink_route *r;
- struct ipset *isnets;
+ struct netlink_client *r;
+ struct ipset *allnets;
struct subnet_list *snets;
int i;
uint8_t confirm;
ipaddr_to_string(st->slip.local_address),
ipaddr_to_string(st->slip.nl.secnet_address),st->slip.nl.mtu);
- r=st->slip.nl.routes;
- isnets=ipset_new();
- for (i=0; i<st->slip.nl.n_routes; i++) {
- if (r[i].up) {
- struct ipset *sn,*nis;
- r[i].kup=True;
- sn=ipset_from_subnet(r[i].net);
- nis=ipset_union(isnets,sn);
- ipset_free(sn);
- ipset_free(isnets);
- isnets=nis;
+ allnets=ipset_new();
+ for (r=st->slip.nl.clients; r; r=r->next) {
+ if (r->up) {
+ struct ipset *nan;
+ r->kup=True;
+ nan=ipset_union(allnets,r->networks);
+ ipset_free(allnets);
+ allnets=nan;
}
}
- snets=ipset_to_subnet_list(isnets);
- ipset_free(isnets);
+ snets=ipset_to_subnet_list(allnets);
+ ipset_free(allnets);
nets=safe_malloc(20*snets->entries,"userv_invoke_userv:nets");
*nets=0;
for (i=0; i<snets->entries; i++) {
void slip_module(dict_t *dict)
{
add_closure(dict,"userv-ipif",userv_apply);
-#if 0
- /* TODO */
- add_closure(dict,"pty-slip",ptyslip_apply);
- add_closure(dict,"slipd",slipd_apply);
-#endif /* 0 */
}
BUF_FREE(buf);
}
-static bool_t tun_set_route(void *sst, struct netlink_route *route)
+static bool_t tun_set_route(void *sst, struct netlink_client *routes)
{
struct tun *st=sst;
string_t network, mask, secnetaddr;
-
- if (route->up != route->kup) {
- network=ipaddr_to_string(route->net.prefix);
- mask=ipaddr_to_string(route->net.mask);
- secnetaddr=ipaddr_to_string(st->nl.secnet_address);
- Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
- st->nl.name,route->up?"adding":"deleting",network,
- route->net.len,route->up?"to":"from");
- sys_cmd(st->route_path,"route",route->up?"add":"del","-net",network,
- "netmask",mask,"gw",secnetaddr,(char *)0);
- free(network); free(mask); free(secnetaddr);
- route->kup=route->up;
+ struct subnet_list *nets;
+ uint32_t i;
+
+ if (routes->up != routes->kup) {
+ nets=routes->subnets;
+ for (i=0; i<nets->entries; i++) {
+ network=ipaddr_to_string(nets->list[i].prefix);
+ mask=ipaddr_to_string(nets->list[i].mask);
+ secnetaddr=ipaddr_to_string(st->nl.secnet_address);
+ Message(M_INFO,"%s: %s route %s/%d %s kernel routing table\n",
+ st->nl.name,routes->up?"adding":"deleting",network,
+ nets->list[i].len,routes->up?"to":"from");
+ sys_cmd(st->route_path,"route",routes->up?"add":"del",
+ "-net",network,"netmask",mask,"gw",secnetaddr,(char *)0);
+ free(network); free(mask); free(secnetaddr);
+ }
+ routes->kup=routes->up;
return True;
}
return False;
struct tun *st=sst;
string_t hostaddr,secnetaddr;
uint8_t mtu[6];
- string_t network,mask;
- struct netlink_route *r;
- int i;
+ struct netlink_client *r;
if (st->tun_old) {
if (st->search_for_if) {
snprintf(mtu,6,"%d",st->nl.mtu);
mtu[5]=0;
+ /* XXX on FreeBSD the "-broadcast" and "pointopoint" must be left
+ out. It assumes a point-to-point interface if two IP addresses
+ are specified. */
sys_cmd(st->ifconfig_path,"ifconfig",st->interface_name,
hostaddr,"netmask","255.255.255.255","-broadcast",
"pointopoint",secnetaddr,"mtu",mtu,"up",(char *)0);
- r=st->nl.routes;
- for (i=0; i<st->nl.n_routes; i++) {
- if (r[i].up && !r[i].kup) {
- network=ipaddr_to_string(r[i].net.prefix);
- mask=ipaddr_to_string(r[i].net.mask);
- sys_cmd(st->route_path,"route","add","-net",network,
- "netmask",mask,"gw",secnetaddr,(char *)0);
- r[i].kup=True;
- }
+ for (r=st->nl.clients; r; r=r->next) {
+ tun_set_route(st,r);
}
/* Register for poll() */