Stephen Early <steve@greenend.org.uk> - original author
Ross Anderson, Eli Biham, Lars Knudsen - serpent
Colin Plumb, Ian Jackson - MD5 implementation
+Ian Jackson - hacky parallelism, serpent keying and endianness bugfixes
Steve Reid <sreid@sea-to-sky.net>, James H. Brown <jbrown@burgoyne.com> -
SHA1 implementation
Cendio Systems AB - ipaddr.py
Simon Tatham, Jonathan Amery, Ian Jackson - testing and debugging
Simon Tatham - RSA signatures using Chinese Remainder Theorem
-Richard Kettlewell - assorted bugfixes
+Simon Tatham - endianness cleanups in transform.c
+Richard Kettlewell, Peter Benie - assorted bugfixes
GUARANTEE THAT THERE WILL BE PROTOCOL COMPATIBILITY BETWEEN DIFFERENT
VERSIONS.
-PROTOCOL COMPATIBILITY WAS BROKEN BETWEEN secnet-0.06, secnet-0.07 AND
-secnet-0.08 FOR ENDIANNESS FIXES.
-
-THERE WILL BE ANOTHER CHANGE IN PROTOCOL IN THE secnet-0.1.x SERIES
-
* Preparation
** System software support
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 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
If you intend to start secnet as root, I suggest you create a userid
# cp example.conf /etc/secnet/secnet.conf
# cd /etc/secnet
-# ssh-keygen -f key -N ""
+# ssh-keygen -f key -t rsa1 -N ""
[On BSD use
$ LDFLAGS="-L/usr/local/lib" ./configure
.PHONY: all clean realclean distclean dist install
PACKAGE:=secnet
-VERSION:=0.1.15
+VERSION:=0.1.16
@SET_MAKE@
INSTALL:=@INSTALL@
INSTALL_PROGRAM:=@INSTALL_PROGRAM@
+# Use -DHACKY_PARALLEL if you are compiling secnet for an extremely
+# slow machine
+#CFLAGS:=-Wall @WRITESTRINGS@ @CFLAGS@ -DHACKY_PARALLEL
CFLAGS:=-Wall @WRITESTRINGS@ @CFLAGS@
ALL_CFLAGS:=@DEFS@ -I$(srcdir) -I. $(CFLAGS)
LDFLAGS:=@LDFLAGS@
OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \
resolver.o random.o udp.o site.o transform.o netlink.o rsa.o dh.o \
serpent.o md5.o version.o tun.o slip.o sha1.o ipaddr.o log.o \
- process.o @LIBOBJS@
+ process.o @LIBOBJS@ \
+ hackypar.o
+DISTDIRS:=debian
DISTFILES:=BUGS COPYING CREDITS INSTALL LICENSE.txt Makefile.in \
NEWS NOTES README TODO \
- alloca.c \
+ ac_prog_cc_no_writeable_strings.m4 \
conffile.c conffile.fl conffile.h conffile.y \
conffile_internal.h config.h.bot \
config.h.in config.h.top configure \
- configure.in debian depend.sh dh.c \
+ configure.in depend.sh dh.c \
example.conf \
getopt.c getopt1.c getopt.h \
install-sh ipaddr.c ipaddr.h ipaddr.py linux log.c \
secnet.c secnet.h serpent.c serpent.h serpentsboxes.h \
snprintf.c snprintf.h \
sha1.c site.c slip.c stamp-h.in transform.c tun.c udp.c \
- unaligned.h util.c util.h
+ unaligned.h util.c util.h \
+ hackypar.c hackypar.h
+DISTSUBDIRS:=debian/conffiles debian/copyright debian/changelog \
+ debian/control debian/init debian/rules
%.c: %.y
dist:
$(RM) -rf $(pfname)
mkdir $(pfname)
+ for i in $(DISTDIRS) ; do mkdir $(pfname)/$$i ; done
for i in $(DISTFILES) ; do ln -s ../$(srcdir)/$$i $(pfname)/ ; done
+ for i in $(DISTSUBDIRS) ; do ln -s ../../$(srcdir)/$$i $(pfname)/$$i ; done
tar hcf ../$(pfname).tar --exclude=CVS --exclude=.cvsignore $(pfname)
gzip -9f ../$(pfname).tar
$(RM) -rf $(pfname)
* Planned for the future
-Netlink device that implements an Ethernet bridge.
-
-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.
-
-Separation of device drivers from IP router code - driver produces a
-stream of packets (which has a tag indicating type and parameters).
-Router module can be connected to stream to multiplex it between
-different tunnels.
-
-Support for dynamic creation of streams/tunnels to cope with laptops,
-etc.
-
-See also file "TODO".
+Please note that the 0.1 series of secnet releases is now 'maintenance
+only'; further development continues in secnet-0.2.
+
+* Planned for version 0.1.17
+
+Debconf support - if you are using the Debian packaged version and
+your secnet configuration is autogenerated using debconf then the
+upgrade to version 0.2.0 should just involve installing the package;
+an appropriate 0.2-style configuration file will be generated
+automatically.
+
+* New in version 0.1.16
+
+XXX XXX PROTOCOL COMPATIBILITY IS BROKEN BETWEEN VERSION 0.1.16 AND
+XXX XXX ALL PREVIOUS VERSIONS.
+
+Bugfix: rsa.c private-key now works properly when you choose not to
+verify it.
+
+Bugfix: serpent key setup was only using the first 8 bytes of the key
+material. (Oops!) Ian Jackson contributed a fix so the full 32 bytes
+are used, in big-endian mode.
+
+Debatable-bugfix: RSA operations now use PKCS1 v1.5-style padding
+
+"Hacky parallelism" contributed by Ian Jackson; this permits
+public-key operations to be performed in a subprocess during key
+exchange, to make secnet more usable on very slow machines. This is
+not compiled in by default; if you find you need it (because key
+exchanges are taking more than a second or two) then add
+-DHACKY_PARALLEL to FLAGS in the Makefile.in and recompile.
+
+udp module updates from Peter Benie:
+ 1) Handle the case where authbind-helper terminates with a signal
+ 2) Cope with signals being delivered during waitpid
+ 3) Add 'address' (optional) to the udp settings. This is an IP address
+ that the socket will be bound to.
+ 4) Change the endianess of the arguments to authbind-helper.
+ sprintf("%04X") already translates from machine repesentation to most
+ significant octet first so htons reversed it again.
+
+All uses of alloca() expunged by Peter Benie.
+
+make-secnet-sites now supports configurations where each tunnel gets
+its own interface on the host, and the IP router code in secnet is
+disabled. make-secnet-sites has been rewritten for clarity. For
+information on how to configure secnet for one-interface-per-tunnel,
+see the example.conf file.
* New in version 0.1.15
* Copying
-secnet is Copyright (C) 1995--2001 Stephen Early <steve@greenend.org.uk>
+secnet is Copyright (C) 1995--2003 Stephen Early <steve@greenend.org.uk>
It is distributed under the terms of the GNU General Public License,
version 2 or later. See the file COPYING for more information.
makelist: turns a dictionary (arg1) into a list of definitions
(ignoring the keys)
readfile: reads a file (arg1) and returns it as a string
+ map: applies the closure specified as arg1 to each of the
+ remaining elements in the list in turn. Returns a list
+ made up of the outputs of the closure.
Keys defined by modules are described below, in the module
documentation.
udp (closure => comm closure)
udp: dict argument
+ address (string): IP address to listen and send on
port (integer): UDP port to listen and send on
buffer (buffer closure): buffer for incoming packets
authbind (string): optional, path to authbind-helper program
dh.c: change format to binary from decimal string (without introducing
endianness problems)
-log.c: implement a file-descriptor-to-log module
-
netlink.c: test the 'allow_route' option properly.
Add fragmentation code. Check that we comply with RFC1812.
-process.c: capture output from children in sys_cmd() and log it
-
random.c: test properly
resolver.c: ought to return a list of addresses for each address; the
rsa.c: check padding type, change format to binary from decimal string
(without introducing endianness problems)
-secnet.c: optionally pipe stderr to a log when we become a daemon.
-Don't just close it.
-
site.c: Abandon key exchanges when a bad packet is received. Modify
protocol to include version fields, as described in the NOTES
file. Implement keepalive mode. Make policy about when to initiate key
--- /dev/null
+dnl @synopsis AC_PROG_CC_NO_WRITEABLE_STRINGS(substvar [,hard])
+dnl
+dnl Try to find a compiler option that warns when a stringliteral is
+dnl used in a place that could potentially modify the address. This
+dnl should warn on giving an stringliteral to a function that asks of
+dnl a non-const-modified char-pointer.
+dnl
+dnl The sanity check is done by looking at string.h which has a set
+dnl of strcpy definitions that should be defined with const-modifiers
+dnl to not emit a warning in all so many places.
+dnl
+dnl Currently this macro knows about GCC.
+dnl hopefully will evolve to use: Solaris C compiler,
+dnl Digital Unix C compiler, C for AIX Compiler, HP-UX C compiler,
+dnl and IRIX C compiler.
+dnl
+dnl @version $Id: ac_prog_cc_no_writeable_strings.m4,v 1.1 2002/02/20 16:18:18 steve Exp $
+dnl @author Guido Draheim <guidod@gmx.de>
+dnl
+AC_DEFUN([AC_PROG_CC_NO_WRITEABLE_STRINGS], [
+ pushdef([CV],ac_cv_prog_cc_no_writeable_strings)dnl
+ hard=$2
+ if test -z "$hard"; then
+ msg="C to warn about writing to stringliterals"
+ else
+ msg="C to prohibit any write to stringliterals"
+ fi
+ AC_CACHE_CHECK($msg, CV, [
+ cat > conftest.c <<EOF
+#include <string.h>
+int main (void)
+{
+ char test[[16]];
+ if (strcpy (test, "test")) return 0;
+ return 1;
+}
+EOF
+ dnl GCC
+ if test "$GCC" = "yes";
+ then
+ if test -z "$hard"; then
+ CV="-Wwrite-strings"
+ else
+ CV="-fno-writable-strings -Wwrite-strings"
+ fi
+
+ if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+ CV="suppressed: string.h"
+ fi
+
+ dnl Solaris C compiler
+ elif $CC -flags 2>&1 | grep "Xc.*strict ANSI C" > /dev/null 2>&1 &&
+ $CC -c -xstrconst conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o
+ then
+ # strings go into readonly segment
+ CV="-xstrconst"
+
+ rm conftest.o
+ if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+ CV="suppressed: string.h"
+ fi
+
+ dnl HP-UX C compiler
+ elif $CC > /dev/null 2>&1 &&
+ $CC -c +ESlit conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o
+ then
+ # strings go into readonly segment
+ CV="+ESlit"
+
+ rm conftest.o
+ if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+ CV="suppressed: string.h"
+ fi
+
+ dnl Digital Unix C compiler
+ elif ! $CC > /dev/null 2>&1 &&
+ $CC -c -readonly_strings conftest.c > /dev/null 2>&1 &&
+ test -f conftest.o
+ then
+ # strings go into readonly segment
+ CV="-readonly_strings"
+
+ rm conftest.o
+ if test -n "`${CC-cc} -c $CV conftest.c 2>&1`" ; then
+ CV="suppressed: string.h"
+ fi
+
+ dnl C for AIX Compiler
+
+ dnl IRIX C compiler
+ # -use_readonly_const is the default for IRIX C,
+ # puts them into .rodata, but they are copied later.
+ # need to be "-G0 -rdatashared" for strictmode but
+ # I am not sure what effect that has really.
+
+ fi
+ rm -f conftest.*
+ ])
+ if test -z "[$]$1" ; then
+ if test -n "$CV" ; then
+ case "$CV" in
+ suppressed*) $1="" ;; # known but suppressed
+ *) $1="$CV" ;;
+ esac
+ fi
+ fi
+ AC_SUBST($1)
+ popdef([CV])dnl
+])
+
+
+++ /dev/null
-/* alloca.c -- allocate automatically reclaimed memory
- (Mostly) portable public-domain implementation -- D A Gwyn
-
- This implementation of the PWB library alloca function,
- which is used to allocate space off the run-time stack so
- that it is automatically reclaimed upon procedure exit,
- was inspired by discussions with J. Q. Johnson of Cornell.
- J.Otto Tennant <jot@cray.com> contributed the Cray support.
-
- There are some preprocessor constants that can
- be defined when compiling for your specific system, for
- improved efficiency; however, the defaults should be okay.
-
- The general concept of this implementation is to keep
- track of all alloca-allocated blocks, and reclaim any
- that are found to be deeper in the stack than the current
- invocation. This heuristic does not reclaim storage as
- soon as it becomes invalid, but it will do so eventually.
-
- As a special case, alloca(0) reclaims storage without
- allocating any. It is a good idea to use alloca(0) in
- your main control loop, etc. to force garbage collection. */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* If compiling with GCC, this file's not needed. */
-#ifndef alloca
-
-#ifdef emacs
-#ifdef static
-/* actually, only want this if static is defined as ""
- -- this is for usg, in which emacs must undefine static
- in order to make unexec workable
- */
-#ifndef STACK_DIRECTION
-you
-lose
--- must know STACK_DIRECTION at compile-time
-#endif /* STACK_DIRECTION undefined */
-#endif /* static */
-#endif /* emacs */
-
-/* If your stack is a linked list of frames, you have to
- provide an "address metric" ADDRESS_FUNCTION macro. */
-
-#ifdef CRAY
-long i00afunc ();
-#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
-#else
-#define ADDRESS_FUNCTION(arg) &(arg)
-#endif
-
-#if __STDC__
-typedef void *pointer;
-#else
-typedef char *pointer;
-#endif
-
-#define NULL 0
-
-/* Define STACK_DIRECTION if you know the direction of stack
- growth for your system; otherwise it will be automatically
- deduced at run-time.
-
- STACK_DIRECTION > 0 => grows toward higher addresses
- STACK_DIRECTION < 0 => grows toward lower addresses
- STACK_DIRECTION = 0 => direction of growth unknown */
-
-#ifndef STACK_DIRECTION
-#define STACK_DIRECTION 0 /* Direction unknown. */
-#endif
-
-#if STACK_DIRECTION != 0
-
-#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
-
-#else /* STACK_DIRECTION == 0; need run-time code. */
-
-static int stack_dir; /* 1 or -1 once known. */
-#define STACK_DIR stack_dir
-
-static void
-find_stack_direction ()
-{
- static char *addr = NULL; /* Address of first `dummy', once known. */
- auto char dummy; /* To get stack address. */
-
- if (addr == NULL)
- { /* Initial entry. */
- addr = ADDRESS_FUNCTION (dummy);
-
- find_stack_direction (); /* Recurse once. */
- }
- else
- {
- /* Second entry. */
- if (ADDRESS_FUNCTION (dummy) > addr)
- stack_dir = 1; /* Stack grew upward. */
- else
- stack_dir = -1; /* Stack grew downward. */
- }
-}
-
-#endif /* STACK_DIRECTION == 0 */
-
-/* An "alloca header" is used to:
- (a) chain together all alloca'ed blocks;
- (b) keep track of stack depth.
-
- It is very important that sizeof(header) agree with malloc
- alignment chunk size. The following default should work okay. */
-
-#ifndef ALIGN_SIZE
-#define ALIGN_SIZE sizeof(double)
-#endif
-
-typedef union hdr
-{
- char align[ALIGN_SIZE]; /* To force sizeof(header). */
- struct
- {
- union hdr *next; /* For chaining headers. */
- char *deep; /* For stack depth measure. */
- } h;
-} header;
-
-static header *last_alloca_header = NULL; /* -> last alloca header. */
-
-/* Return a pointer to at least SIZE bytes of storage,
- which will be automatically reclaimed upon exit from
- the procedure that called alloca. Originally, this space
- was supposed to be taken from the current stack frame of the
- caller, but that method cannot be made to work for some
- implementations of C, for example under Gould's UTX/32. */
-
-pointer
-alloca (size)
- unsigned size;
-{
- auto char probe; /* Probes stack depth: */
- register char *depth = ADDRESS_FUNCTION (probe);
-
-#if STACK_DIRECTION == 0
- if (STACK_DIR == 0) /* Unknown growth direction. */
- find_stack_direction ();
-#endif
-
- /* Reclaim garbage, defined as all alloca'd storage that
- was allocated from deeper in the stack than currently. */
-
- {
- register header *hp; /* Traverses linked list. */
-
- for (hp = last_alloca_header; hp != NULL;)
- if ((STACK_DIR > 0 && hp->h.deep > depth)
- || (STACK_DIR < 0 && hp->h.deep < depth))
- {
- register header *np = hp->h.next;
-
- free ((pointer) hp); /* Collect garbage. */
-
- hp = np; /* -> next header. */
- }
- else
- break; /* Rest are not deeper. */
-
- last_alloca_header = hp; /* -> last valid storage. */
- }
-
- if (size == 0)
- return NULL; /* No allocation required. */
-
- /* Allocate combined header + user data storage. */
-
- {
- register pointer new = malloc (sizeof (header) + size);
- /* Address of header. */
-
- ((header *) new)->h.next = last_alloca_header;
- ((header *) new)->h.deep = depth;
-
- last_alloca_header = (header *) new;
-
- /* User storage begins just after header. */
-
- return (pointer) ((char *) new + sizeof (header));
- }
-}
-
-#ifdef CRAY
-
-#ifdef DEBUG_I00AFUNC
-#include <stdio.h>
-#endif
-
-#ifndef CRAY_STACK
-#define CRAY_STACK
-#ifndef CRAY2
-/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
-struct stack_control_header
- {
- long shgrow:32; /* Number of times stack has grown. */
- long shaseg:32; /* Size of increments to stack. */
- long shhwm:32; /* High water mark of stack. */
- long shsize:32; /* Current size of stack (all segments). */
- };
-
-/* The stack segment linkage control information occurs at
- the high-address end of a stack segment. (The stack
- grows from low addresses to high addresses.) The initial
- part of the stack segment linkage control information is
- 0200 (octal) words. This provides for register storage
- for the routine which overflows the stack. */
-
-struct stack_segment_linkage
- {
- long ss[0200]; /* 0200 overflow words. */
- long sssize:32; /* Number of words in this segment. */
- long ssbase:32; /* Offset to stack base. */
- long:32;
- long sspseg:32; /* Offset to linkage control of previous
- segment of stack. */
- long:32;
- long sstcpt:32; /* Pointer to task common address block. */
- long sscsnm; /* Private control structure number for
- microtasking. */
- long ssusr1; /* Reserved for user. */
- long ssusr2; /* Reserved for user. */
- long sstpid; /* Process ID for pid based multi-tasking. */
- long ssgvup; /* Pointer to multitasking thread giveup. */
- long sscray[7]; /* Reserved for Cray Research. */
- long ssa0;
- long ssa1;
- long ssa2;
- long ssa3;
- long ssa4;
- long ssa5;
- long ssa6;
- long ssa7;
- long sss0;
- long sss1;
- long sss2;
- long sss3;
- long sss4;
- long sss5;
- long sss6;
- long sss7;
- };
-
-#else /* CRAY2 */
-/* The following structure defines the vector of words
- returned by the STKSTAT library routine. */
-struct stk_stat
- {
- long now; /* Current total stack size. */
- long maxc; /* Amount of contiguous space which would
- be required to satisfy the maximum
- stack demand to date. */
- long high_water; /* Stack high-water mark. */
- long overflows; /* Number of stack overflow ($STKOFEN) calls. */
- long hits; /* Number of internal buffer hits. */
- long extends; /* Number of block extensions. */
- long stko_mallocs; /* Block allocations by $STKOFEN. */
- long underflows; /* Number of stack underflow calls ($STKRETN). */
- long stko_free; /* Number of deallocations by $STKRETN. */
- long stkm_free; /* Number of deallocations by $STKMRET. */
- long segments; /* Current number of stack segments. */
- long maxs; /* Maximum number of stack segments so far. */
- long pad_size; /* Stack pad size. */
- long current_address; /* Current stack segment address. */
- long current_size; /* Current stack segment size. This
- number is actually corrupted by STKSTAT to
- include the fifteen word trailer area. */
- long initial_address; /* Address of initial segment. */
- long initial_size; /* Size of initial segment. */
- };
-
-/* The following structure describes the data structure which trails
- any stack segment. I think that the description in 'asdef' is
- out of date. I only describe the parts that I am sure about. */
-
-struct stk_trailer
- {
- long this_address; /* Address of this block. */
- long this_size; /* Size of this block (does not include
- this trailer). */
- long unknown2;
- long unknown3;
- long link; /* Address of trailer block of previous
- segment. */
- long unknown5;
- long unknown6;
- long unknown7;
- long unknown8;
- long unknown9;
- long unknown10;
- long unknown11;
- long unknown12;
- long unknown13;
- long unknown14;
- };
-
-#endif /* CRAY2 */
-#endif /* not CRAY_STACK */
-
-#ifdef CRAY2
-/* Determine a "stack measure" for an arbitrary ADDRESS.
- I doubt that "lint" will like this much. */
-
-static long
-i00afunc (long *address)
-{
- struct stk_stat status;
- struct stk_trailer *trailer;
- long *block, size;
- long result = 0;
-
- /* We want to iterate through all of the segments. The first
- step is to get the stack status structure. We could do this
- more quickly and more directly, perhaps, by referencing the
- $LM00 common block, but I know that this works. */
-
- STKSTAT (&status);
-
- /* Set up the iteration. */
-
- trailer = (struct stk_trailer *) (status.current_address
- + status.current_size
- - 15);
-
- /* There must be at least one stack segment. Therefore it is
- a fatal error if "trailer" is null. */
-
- if (trailer == 0)
- abort ();
-
- /* Discard segments that do not contain our argument address. */
-
- while (trailer != 0)
- {
- block = (long *) trailer->this_address;
- size = trailer->this_size;
- if (block == 0 || size == 0)
- abort ();
- trailer = (struct stk_trailer *) trailer->link;
- if ((block <= address) && (address < (block + size)))
- break;
- }
-
- /* Set the result to the offset in this segment and add the sizes
- of all predecessor segments. */
-
- result = address - block;
-
- if (trailer == 0)
- {
- return result;
- }
-
- do
- {
- if (trailer->this_size <= 0)
- abort ();
- result += trailer->this_size;
- trailer = (struct stk_trailer *) trailer->link;
- }
- while (trailer != 0);
-
- /* We are done. Note that if you present a bogus address (one
- not in any segment), you will get a different number back, formed
- from subtracting the address of the first block. This is probably
- not what you want. */
-
- return (result);
-}
-
-#else /* not CRAY2 */
-/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
- Determine the number of the cell within the stack,
- given the address of the cell. The purpose of this
- routine is to linearize, in some sense, stack addresses
- for alloca. */
-
-static long
-i00afunc (long address)
-{
- long stkl = 0;
-
- long size, pseg, this_segment, stack;
- long result = 0;
-
- struct stack_segment_linkage *ssptr;
-
- /* Register B67 contains the address of the end of the
- current stack segment. If you (as a subprogram) store
- your registers on the stack and find that you are past
- the contents of B67, you have overflowed the segment.
-
- B67 also points to the stack segment linkage control
- area, which is what we are really interested in. */
-
- stkl = CRAY_STACKSEG_END ();
- ssptr = (struct stack_segment_linkage *) stkl;
-
- /* If one subtracts 'size' from the end of the segment,
- one has the address of the first word of the segment.
-
- If this is not the first segment, 'pseg' will be
- nonzero. */
-
- pseg = ssptr->sspseg;
- size = ssptr->sssize;
-
- this_segment = stkl - size;
-
- /* It is possible that calling this routine itself caused
- a stack overflow. Discard stack segments which do not
- contain the target address. */
-
- while (!(this_segment <= address && address <= stkl))
- {
-#ifdef DEBUG_I00AFUNC
- fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
-#endif
- if (pseg == 0)
- break;
- stkl = stkl - pseg;
- ssptr = (struct stack_segment_linkage *) stkl;
- size = ssptr->sssize;
- pseg = ssptr->sspseg;
- this_segment = stkl - size;
- }
-
- result = address - this_segment;
-
- /* If you subtract pseg from the current end of the stack,
- you get the address of the previous stack segment's end.
- This seems a little convoluted to me, but I'll bet you save
- a cycle somewhere. */
-
- while (pseg != 0)
- {
-#ifdef DEBUG_I00AFUNC
- fprintf (stderr, "%011o %011o\n", pseg, size);
-#endif
- stkl = stkl - pseg;
- ssptr = (struct stack_segment_linkage *) stkl;
- size = ssptr->sssize;
- pseg = ssptr->sspseg;
- result += size;
- }
- return (result);
-}
-
-#endif /* not CRAY2 */
-#endif /* CRAY */
-
-#endif /* no alloca */
context=root;
/* Predefined keys for boolean values */
+ /* "nowise" and "verily" have the advantage of being the same
+ length, so they line up nicely... thanks VKC and SGT (who also
+ point out that "mayhap" is a good "maybe" value as well) */
i=new_item(t_bool,no_loc);
i->data.bool=False;
false=list_append(NULL,i);
dict_add(root,"no",false);
dict_add(root,"No",false);
dict_add(root,"NO",false);
+ dict_add(root,"nowise",false);
+ dict_add(root,"Nowise",false);
+ dict_add(root,"NOWISE",false);
dict_add(root,"true",true);
dict_add(root,"True",true);
dict_add(root,"TRUE",true);
dict_add(root,"yes",true);
dict_add(root,"Yes",true);
dict_add(root,"YES",true);
+ dict_add(root,"verily",true);
+ dict_add(root,"Verily",true);
+ dict_add(root,"VERILY",true);
add_closure(root,"makelist",makelist);
add_closure(root,"readfile",readfile);
closure_t *c;
c=safe_malloc(sizeof(*c),"add_closure");
c->description=name;
+ c->type=CL_PURE;
c->apply=apply;
c->interface=NULL;
#define _CONFIG_H
-/* Define if using alloca.c. */
-#undef C_ALLOCA
-
-/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
- This function is required for alloca.c support on those systems. */
-#undef CRAY_STACKSEG_END
-
-/* Define if you have alloca, as a function or macro. */
-#undef HAVE_ALLOCA
-
-/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
-#undef HAVE_ALLOCA_H
-
-/* If using the C implementation of alloca, define if you know the
- direction of stack growth for your system; otherwise it will be
- automatically deduced at run-time.
- STACK_DIRECTION > 0 => grows toward higher addresses
- STACK_DIRECTION < 0 => grows toward lower addresses
- STACK_DIRECTION = 0 => direction of growth unknown
- */
-#undef STACK_DIRECTION
-
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
fi
done
-# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
-# for constant arguments. Useless!
-echo $ac_n "checking for working alloca.h""... $ac_c" 1>&6
-echo "configure:2218: checking for working alloca.h" >&5
-if eval "test \"`echo '$''{'ac_cv_header_alloca_h'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2223 "configure"
-#include "confdefs.h"
-#include <alloca.h>
-int main() {
-char *p = alloca(2 * sizeof(int));
-; return 0; }
-EOF
-if { (eval echo configure:2230: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- ac_cv_header_alloca_h=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_header_alloca_h=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_header_alloca_h" 1>&6
-if test $ac_cv_header_alloca_h = yes; then
- cat >> confdefs.h <<\EOF
-#define HAVE_ALLOCA_H 1
-EOF
-
-fi
-
-echo $ac_n "checking for alloca""... $ac_c" 1>&6
-echo "configure:2251: checking for alloca" >&5
-if eval "test \"`echo '$''{'ac_cv_func_alloca_works'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2256 "configure"
-#include "confdefs.h"
-
-#ifdef __GNUC__
-# define alloca __builtin_alloca
-#else
-# ifdef _MSC_VER
-# include <malloc.h>
-# define alloca _alloca
-# else
-# if HAVE_ALLOCA_H
-# include <alloca.h>
-# else
-# ifdef _AIX
- #pragma alloca
-# else
-# ifndef alloca /* predefined by HP cc +Olibcalls */
-char *alloca ();
-# endif
-# endif
-# endif
-# endif
-#endif
-
-int main() {
-char *p = (char *) alloca(1);
-; return 0; }
-EOF
-if { (eval echo configure:2284: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- ac_cv_func_alloca_works=yes
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- ac_cv_func_alloca_works=no
-fi
-rm -f conftest*
-fi
-
-echo "$ac_t""$ac_cv_func_alloca_works" 1>&6
-if test $ac_cv_func_alloca_works = yes; then
- cat >> confdefs.h <<\EOF
-#define HAVE_ALLOCA 1
-EOF
-
-fi
-
-if test $ac_cv_func_alloca_works = no; then
- # The SVR3 libPW and SVR4 libucb both contain incompatible functions
- # that cause trouble. Some versions do not even contain alloca or
- # contain a buggy version. If you still want to use their alloca,
- # use ar to extract alloca.o from them instead of compiling alloca.c.
- ALLOCA=alloca.${ac_objext}
- cat >> confdefs.h <<\EOF
-#define C_ALLOCA 1
-EOF
-
-
-echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&6
-echo "configure:2316: checking whether alloca needs Cray hooks" >&5
-if eval "test \"`echo '$''{'ac_cv_os_cray'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2321 "configure"
-#include "confdefs.h"
-#if defined(CRAY) && ! defined(CRAY2)
-webecray
-#else
-wenotbecray
-#endif
-
-EOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- egrep "webecray" >/dev/null 2>&1; then
- rm -rf conftest*
- ac_cv_os_cray=yes
-else
- rm -rf conftest*
- ac_cv_os_cray=no
-fi
-rm -f conftest*
-
-fi
-
-echo "$ac_t""$ac_cv_os_cray" 1>&6
-if test $ac_cv_os_cray = yes; then
-for ac_func in _getb67 GETB67 getb67; do
- echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
-echo "configure:2346: checking for $ac_func" >&5
-if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- cat > conftest.$ac_ext <<EOF
-#line 2351 "configure"
-#include "confdefs.h"
-/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $ac_func(); below. */
-#include <assert.h>
-/* Override any gcc2 internal prototype to avoid an error. */
-/* We use char because int might match the return type of a gcc2
- builtin and then its argument prototype would still apply. */
-char $ac_func();
-
-int main() {
-
-/* The GNU C library defines this for functions which it implements
- to always fail with ENOSYS. Some functions are actually named
- something starting with __ and the normal name is an alias. */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
-choke me
-#else
-$ac_func();
-#endif
-
-; return 0; }
-EOF
-if { (eval echo configure:2374: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
- rm -rf conftest*
- eval "ac_cv_func_$ac_func=yes"
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -rf conftest*
- eval "ac_cv_func_$ac_func=no"
-fi
-rm -f conftest*
-fi
-
-if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
- echo "$ac_t""yes" 1>&6
- cat >> confdefs.h <<EOF
-#define CRAY_STACKSEG_END $ac_func
-EOF
-
- break
-else
- echo "$ac_t""no" 1>&6
-fi
-
-done
-fi
-
-echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&6
-echo "configure:2401: checking stack direction for C alloca" >&5
-if eval "test \"`echo '$''{'ac_cv_c_stack_direction'+set}'`\" = set"; then
- echo $ac_n "(cached) $ac_c" 1>&6
-else
- if test "$cross_compiling" = yes; then
- ac_cv_c_stack_direction=0
-else
- cat > conftest.$ac_ext <<EOF
-#line 2409 "configure"
-#include "confdefs.h"
-find_stack_direction ()
-{
- static char *addr = 0;
- auto char dummy;
- if (addr == 0)
- {
- addr = &dummy;
- return find_stack_direction ();
- }
- else
- return (&dummy > addr) ? 1 : -1;
-}
-main ()
-{
- exit (find_stack_direction() < 0);
-}
-EOF
-if { (eval echo configure:2428: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
-then
- ac_cv_c_stack_direction=1
-else
- echo "configure: failed program was:" >&5
- cat conftest.$ac_ext >&5
- rm -fr conftest*
- ac_cv_c_stack_direction=-1
-fi
-rm -fr conftest*
-fi
-
-fi
-
-echo "$ac_t""$ac_cv_c_stack_direction" 1>&6
-cat >> confdefs.h <<EOF
-#define STACK_DIRECTION $ac_cv_c_stack_direction
-EOF
-
-fi
-
trap '' 1 2 15
cat > confcache <<\EOF
s%@CPP@%$CPP%g
s%@WRITESTRINGS@%$WRITESTRINGS%g
s%@LIBOBJS@%$LIBOBJS%g
-s%@ALLOCA@%$ALLOCA%g
CEOF
EOF
AC_INIT(secnet.c)
AC_CONFIG_HEADER(config.h)
-AC_REVISION($Id: configure.in,v 1.3 2002/02/20 16:18:18 steve Exp $)
+AC_REVISION($Id: configure.in,v 1.4 2002/09/09 22:05:02 steve Exp $)
AC_LANG_C
dnl check for getopt in standard library
AC_SUBST(LIBOBJS)
AC_CHECK_FUNCS(getopt_long , , [LIBOBJS="$LIBOBJS getopt.o getopt1.o"] )
-dnl check for alloca
AC_CHECK_FUNCS(snprintf , , [LIBOBJS="$LIBOBJS snprintf.o"] )
-AC_FUNC_ALLOCA()
AC_OUTPUT(Makefile,echo timestamp >stamp-h)
-secnet (0.1.15-1) unstable; urgency=low
+secnet (0.1.16-1) unstable; urgency=high
* New upstream version.
- -- Stephen Early <steve@greenend.org.uk> Thu, 21 Feb 2002 13:40:00 +0000
+ -- Stephen Early <steve@greenend.org.uk> Sat, 19 Jul 2003 17:00:00 +0100
+++ /dev/null
-etc/secnet
-usr/sbin
# secnet example configuration file
# Log facility
+# If you use this unaltered you should consider providing automatic log
+# rotation for /var/log/secnet. secnet will close and re-open its logfiles
+# when it receives SIGHUP.
log logfile {
filename "/var/log/secnet";
class "info","notice","warning","error","security","fatal";
# 'quiet' -> fatal
};
-# Alternatively you could log to syslog:
+# Alternatively you could log through syslog:
# log syslog {
# ident "secnet";
# facility "local0";
# userid who we try to run as after setup
# pidfile
system {
+ # Note that you should not specify 'userid' here unless secnet
+ # is being invoked as root.
userid "secnet";
pidfile "/var/run/secnet.pid";
};
# wait-time wait between unsuccessful key setup attempts, in ms
# renegotiate-time set up a new key if we see any traffic after this time
+# Defaults that may be overridden on a per-site basis:
setup-retries 10;
setup-timeout 2000;
-# Use the universal TUN/TAP driver to get packets to and from the kernel
+# Use the universal TUN/TAP driver to get packets to and from the kernel,
+# through a single interface. secnet will act as a router; it requires
+# its own IP address which is specified below (you'll see it on traceroute,
+# etc. for routes that go via tunnels). If you don't want secnet to act
+# as a router, and instead want a separate kernel network interface per
+# tunnel, then see the alternative configuration below
+
+# If you want to use userv-ipif to manage interfaces then replace the
+# word "tun" with "userv-ipif".
netlink tun {
name "netlink-tun"; # Printed in log messages from this netlink
# interface "tun0"; # You may set your own interface name if you wish;
buffer sysbuffer(2048);
};
-# Alternatively (or additionally, if you like) use userv-ipif to get
-# packets to and from the kernel.
-#netlink userv-ipif {
-# name "netlink-userv-ipif";
-# # userv-path "/usr/bin/userv";
-# # service-user "root";
-# # service-name "ipif";
-# networks "whatever";
-# local-address "whatever";
-# secnet-address "whatever";
-# mtu 1400;
-# buffer sysbuffer(2048);
-#};
+# This alternative configuration allows you to create one kernel network
+# interface per tunnel. IT WILL ONLY WORK WITH "tun" - IT WILL NOT
+# WORK WITH "userv-ipif". This is because "tun" can share a single
+# buffer between multiple network interfaces, but userv-ipif can't.
+# To use userv-ipif in this style, process the sites.conf file so that
+# each "netlink" section contains a "buffer sysbuffer(2048);" line.
+#netlink tun;
+#local-address "192.168.x.x"; # Address of local interfaces - all the same
+#mtu 1400;
+#buffer sysbuffer(2048);
+
# This defines the port that this instance of secnet will listen on, and
# originate packets on. It does not _have_ to correspond to the advertised
include /etc/secnet/sites.conf
-# Here you must list all the VPN sites that you wish to communicate with.
# The /etc/secnet/sites file contains information on all reachable sites;
# if the site you want to communicate with isn't listed, you should get
# a newer version. MAKE SURE YOU GET AN AUTHENTIC COPY OF THE FILE - it
# contains public keys for all sites.
-sites map(site,
- vpn-data/example/location1/site1,
- vpn-data/example/location2/site1,
- vpn-data/example/location2/site2);
-
# If you want to communicate with all the VPN sites, you can use something
-# like the following instead:
+# like the following:
-# sites map(site,vpn/example/all-sites);
+sites map(site,vpn/example/all-sites);
+
+# If you only want to communicate with a subset of the VPN sites, list
+# them explicitly:
+
+# sites map(site,
+# vpn-data/example/location1/site1,
+# vpn-data/example/location2/site1,
+# vpn-data/example/location2/site2);
# If you want to communicate with a subset of locations, try the following:
# sites map(site,vpn/example/location1,vpn/example/location2);
+
along with this program; if not, write to the Free Software
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
\f
-/* NOTE!!! AIX requires this to be the first thing in the file.
- Do not put ANYTHING before it! */
-#if !defined (__GNUC__) && defined (_AIX)
- #pragma alloca
-#endif
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#ifdef __GNUC__
-#define alloca __builtin_alloca
-#else /* not __GNUC__ */
-#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
-#include <alloca.h>
-#else
-#ifndef _AIX
-char *alloca ();
-#endif
-#endif /* alloca.h */
-#endif /* not __GNUC__ */
-
#if !__STDC__ && !defined(const) && IN_GCC
#define const
#endif
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
-#undef alloca
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
#include <stdlib.h>
-#else /* Not GNU C library. */
-#define __alloca alloca
#endif /* GNU C library. */
/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
char **argv;
{
int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
- char **temp = (char **) __alloca (nonopts_size);
+ char **temp = (char **) safe_malloc (nonopts_size, "getopt");
/* Interchange the two blocks of data in ARGV. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
+ free(temp);
}
\f
/* Scan elements of ARGV (whose length is ARGC) for option characters
--- /dev/null
+/* Hacky parallelism; Ian Jackson */
+
+#define _GNU_SOURCE
+
+#include "secnet.h"
+#include "util.h"
+#include "hackypar.h"
+
+#ifdef HACKY_PARALLEL
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <assert.h>
+#include <sys/wait.h>
+
+#define HASHSIZE 16
+#define CACHESIZE 16
+
+typedef enum { hp_idle, hp_compute, hp_deferring, hp_fail } HPState;
+
+static HPState state;
+static pid_t child;
+
+static void checkchild(void) {
+ int r, status;
+
+ if (!child) return;
+
+ r= waitpid(child,&status,WNOHANG); if (!r) return;
+ if (r==-1) {
+ Message(M_ERR,"hacky_par: waitpid: %s\n",strerror(errno));
+ return;
+ }
+ child= 0;
+
+ if (WIFSIGNALED(status)) {
+ Message(M_ERR,"hacky_par: signaled! %s\n",strsignal(WTERMSIG(status)));
+ } else if (!WIFEXITED(status)) {
+ Message(M_ERR,"hacky_par: unexpected status! %d\n", r);
+ }
+}
+
+static HPState start(void) {
+ assert(!child);
+
+ child= fork();
+ if (child == -1) {
+ Message(M_ERR,"hacky_par: fork failed: %s\n",strerror(errno));
+ return hp_fail;
+ }
+
+ if (!child) { /* we are the child */
+ return hp_compute;
+ }
+
+ Message(M_INFO,"hacky_par: started, punting\n");
+ return hp_deferring;
+}
+
+int hacky_par_start_failnow(void) {
+ state= hp_idle;
+ checkchild();
+ if (child) {
+ state= hp_deferring;
+ Message(M_INFO,"hacky_par: busy, punting\n");
+ return 1;
+ }
+ return 0;
+}
+
+int hacky_par_mid_failnow(void) {
+ state= start();
+ return state != hp_compute;
+}
+
+bool_t (*packy_par_gen)(struct site *st);
+
+void hacky_par_end(int *ok,
+ uint32_t retries, uint32_t timeout,
+ bool_t (*send_msg)(struct site *st), struct site *st) {
+ int i;
+
+ switch (state) {
+ case hp_deferring:
+ assert(!*ok);
+ *ok= 1;
+ return;
+ case hp_fail:
+ assert(!*ok);
+ return;
+ case hp_idle:
+ return;
+ case hp_compute:
+ if (!ok) {
+ Message(M_ERR,"hacky_par: compute failed\n");
+ _exit(2);
+ }
+ Message(M_INFO,"hacky_par: got result, sending\n");
+ for (i=1; i<retries; i++) {
+ sleep((timeout + 999)/1000);
+ if (!send_msg(st)) {
+ Message(M_ERR,"hacky_par: retry failed\n");
+ _exit(1);
+ }
+ }
+ _exit(0);
+ }
+}
+
+#else /*!HACKY_PARALLEL*/
+
+int hacky_par_start_failnow(void) { return 0; }
+int hacky_par_mid_failnow(void) { return 0; }
+void hacky_par_end(int *ok,
+ uint32_t retries, uint32_t timeout,
+ bool_t (*send_msg)(struct site *st), struct site *st) { }
+
+#endif /*HACKY_PARALLEL...else*/
--- /dev/null
+/* Hacky parallelism
+ * Ian Jackson
+ * We fork, and return false !
+ */
+
+#ifndef hackympzpar_h
+#define hackympzpar_h
+
+struct site;
+
+int hacky_par_start_failnow(void);
+int hacky_par_mid_failnow(void);
+void hacky_par_end(int *ok,
+ uint32_t retries, uint32_t timeout,
+ bool_t (*send_msg)(struct site *st), struct site *st);
+
+#endif /* hackympzpar_h */
#include "secnet.h"
#include <stdio.h>
+#include <string.h>
#include "ipaddr.h"
#define DEFAULT_ALLOC 2
#! /usr/bin/env python
-# Copyright (C) 2001 Stephen Early <steve@greenend.org.uk>
+# Copyright (C) 2001-2002 Stephen Early <steve@greenend.org.uk>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
import time
import sys
import os
+import getopt
+# The ipaddr library is installed as part of secnet
sys.path.append("/usr/local/share/secnet")
sys.path.append("/usr/share/secnet")
import ipaddr
-VERSION="0.1.13"
-
-class vpn:
- def __init__(self,name):
- self.name=name
- self.allow_defs=0
- self.locations={}
- self.defs={}
-
-class location:
- def __init__(self,name,vpn):
- self.group=None
- self.name=name
- self.allow_defs=1
- self.vpn=vpn
- self.sites={}
- self.defs={}
-
-class site:
- def __init__(self,name,location):
- self.name=name
- self.allow_defs=1
- self.location=location
- self.defs={}
-
-class nets:
+VERSION="0.1.16"
+
+# Classes describing possible datatypes in the configuration file
+
+class single_ipaddr:
+ "An IP address"
+ def __init__(self,w):
+ self.addr=ipaddr.ipaddr(w[1])
+ def __str__(self):
+ return '"%s"'%self.addr.ip_str()
+
+class networks:
+ "A set of IP addresses specified as a list of networks"
def __init__(self,w):
- self.w=w
self.set=ipaddr.ip_set()
for i in w[1:]:
x=string.split(i,"/")
self.set.append(ipaddr.network(x[0],x[1],
ipaddr.DEMAND_NETWORK))
- def subsetof(self,s):
- # I'd like to do this:
- # return self.set.is_subset(s)
- # but there isn't an is_subset() method
- # Instead we see if we intersect with the complement of s
- sc=s.set.complement()
- i=sc.intersection(self.set)
- return i.is_empty()
- def out(self):
- if (self.w[0]=='restrict-nets'): pattern="# restrict-nets %s;"
- else:
- pattern="link netlink { routes %s; };"
- return pattern%string.join(map(lambda x:'"%s/%s"'%(x.ip_str(),
- x.mask.netmask_bits_str),
- self.set.as_list_of_networks()),",")
+ def __str__(self):
+ return string.join(map(lambda x:'"%s/%s"'%(x.ip_str(),
+ x.mask.netmask_bits_str),
+ self.set.as_list_of_networks()),",")
class dhgroup:
+ "A Diffie-Hellman group"
def __init__(self,w):
self.mod=w[1]
self.gen=w[2]
- def out(self):
- return 'dh diffie-hellman("%s","%s");'%(self.mod,self.gen)
+ def __str__(self):
+ return 'diffie-hellman("%s","%s")'%(self.mod,self.gen)
class hash:
+ "A choice of hash function"
def __init__(self,w):
self.ht=w[1]
if (self.ht!='md5' and self.ht!='sha1'):
complain("unknown hash type %s"%(self.ht))
- def out(self):
- return 'hash %s;'%(self.ht)
+ def __str__(self):
+ return '%s'%(self.ht)
class email:
+ "An email address"
def __init__(self,w):
self.addr=w[1]
- def out(self):
- return '# Contact email address: <%s>'%(self.addr)
+ def __str__(self):
+ return '<%s>'%(self.addr)
class num:
+ "A decimal number"
def __init__(self,w):
- self.what=w[0]
self.n=string.atol(w[1])
- def out(self):
- return '%s %d;'%(self.what,self.n)
+ def __str__(self):
+ return '%d'%(self.n)
class address:
+ "A DNS name and UDP port number"
def __init__(self,w):
- self.w=w
self.adr=w[1]
self.port=string.atoi(w[2])
if (self.port<1 or self.port>65535):
complain("invalid port number")
- def out(self):
- return 'address "%s"; port %d;'%(self.adr,self.port)
+ def __str__(self):
+ return '"%s"; port %d'%(self.adr,self.port)
class rsakey:
+ "An RSA public key"
def __init__(self,w):
self.l=string.atoi(w[1])
self.e=w[2]
self.n=w[3]
- def out(self):
- return 'key rsa-public("%s","%s");'%(self.e,self.n)
-
-class mobileoption:
+ def __str__(self):
+ return 'rsa-public("%s","%s")'%(self.e,self.n)
+
+# Possible properties of configuration nodes
+keywords={
+ 'contact':(email,"Contact address"),
+ 'dh':(dhgroup,"Diffie-Hellman group"),
+ 'hash':(hash,"Hash function"),
+ 'key-lifetime':(num,"Maximum key lifetime (ms)"),
+ 'setup-timeout':(num,"Key setup timeout (ms)"),
+ 'setup-retries':(num,"Maximum key setup packet retries"),
+ 'wait-time':(num,"Time to wait after unsuccessful key setup (ms)"),
+ 'renegotiate-time':(num,"Time after key setup to begin renegotiation (ms)"),
+ 'restrict-nets':(networks,"Allowable networks"),
+ 'networks':(networks,"Claimed networks"),
+ 'pubkey':(rsakey,"RSA public site key"),
+ 'peer':(single_ipaddr,"Tunnel peer IP address"),
+ 'address':(address,"External contact address and port")
+}
+
+def sp(name,value):
+ "Simply output a property - the default case"
+ return "%s %s;\n"%(name,value)
+
+# All levels support these properties
+global_properties={
+ 'contact':(lambda name,value:"# Contact email address: %s\n"%(value)),
+ 'dh':sp,
+ 'hash':sp,
+ 'key-lifetime':sp,
+ 'setup-timeout':sp,
+ 'setup-retries':sp,
+ 'wait-time':sp,
+ 'renegotiate-time':sp,
+ 'restrict-nets':(lambda name,value:"# restrict-nets %s\n"%value)
+}
+
+class level:
+ "A level in the configuration hierarchy"
+ depth=0
+ leaf=0
+ allow_properties={}
+ require_properties={}
+ def __init__(self,w):
+ self.name=w[1]
+ self.properties={}
+ self.children={}
+ def indent(self,w,t):
+ w.write(" "[:t])
+ def prop_out(self,n):
+ return self.allow_properties[n](n,str(self.properties[n]))
+ def output_props(self,w,ind):
+ for i in self.properties.keys():
+ if self.allow_properties[i]:
+ self.indent(w,ind)
+ w.write("%s"%self.prop_out(i))
+ def output_data(self,w,ind,np):
+ self.indent(w,ind)
+ w.write("%s {\n"%(self.name))
+ self.output_props(w,ind+2)
+ if self.depth==1: w.write("\n");
+ for c in self.children.values():
+ c.output_data(w,ind+2,np+self.name+"/")
+ self.indent(w,ind)
+ w.write("};\n")
+
+class vpnlevel(level):
+ "VPN level in the configuration hierarchy"
+ depth=1
+ leaf=0
+ type="vpn"
+ allow_properties=global_properties.copy()
+ require_properties={
+ 'contact':"VPN admin contact address"
+ }
+ def __init__(self,w):
+ level.__init__(self,w)
+ def output_vpnflat(self,w,ind,h):
+ "Output flattened list of site names for this VPN"
+ self.indent(w,ind)
+ w.write("%s {\n"%(self.name))
+ for i in self.children.keys():
+ self.children[i].output_vpnflat(w,ind+2,
+ h+"/"+self.name+"/"+i)
+ w.write("\n")
+ self.indent(w,ind+2)
+ w.write("all-sites %s;\n"%
+ string.join(self.children.keys(),','))
+ self.indent(w,ind)
+ w.write("};\n")
+
+class locationlevel(level):
+ "Location level in the configuration hierarchy"
+ depth=2
+ leaf=0
+ type="location"
+ allow_properties=global_properties.copy()
+ require_properties={
+ 'contact':"Location admin contact address",
+ }
+ def __init__(self,w):
+ level.__init__(self,w)
+ self.group=w[2]
+ def output_vpnflat(self,w,ind,h):
+ self.indent(w,ind)
+ # The "h=h,self=self" abomination below exists because
+ # Python didn't support nested_scopes until version 2.1
+ w.write("%s %s;\n"%(self.name,string.join(
+ map(lambda x,h=h,self=self:
+ h+"/"+x,self.children.keys()),',')))
+
+class sitelevel(level):
+ "Site level (i.e. a leafnode) in the configuration hierarchy"
+ depth=3
+ leaf=1
+ type="site"
+ allow_properties=global_properties.copy()
+ allow_properties.update({
+ 'address':sp,
+ 'networks':None,
+ 'peer':None,
+ 'pubkey':(lambda n,v:"key %s;\n"%v)
+ })
+ require_properties={
+ 'dh':"Diffie-Hellman group",
+ 'contact':"Site admin contact address",
+ 'address':"Site external access address",
+ 'networks':"Networks claimed by the site",
+ 'hash':"hash function",
+ 'peer':"Gateway address of the site",
+ 'pubkey':"RSA public key of the site"
+ }
def __init__(self,w):
- self.w=w
- def out(self):
- return '# netlink-options "soft";'
+ level.__init__(self,w)
+ def output_data(self,w,ind,np):
+ self.indent(w,ind)
+ w.write("%s {\n"%(self.name))
+ self.indent(w,ind+2)
+ w.write("name \"%s\";\n"%(np+self.name))
+ self.output_props(w,ind+2)
+ self.indent(w,ind+2)
+ w.write("link netlink {\n");
+ self.indent(w,ind+4)
+ w.write("routes %s;\n"%str(self.properties["networks"]))
+ self.indent(w,ind+4)
+ w.write("ptp-address %s;\n"%str(self.properties["peer"]))
+ self.indent(w,ind+2)
+ w.write("};\n")
+ self.indent(w,ind)
+ w.write("};\n")
+
+# Levels in the configuration file
+# (depth,properties)
+levels={'vpn':vpnlevel, 'location':locationlevel, 'site':sitelevel}
+
+# Reserved vpn/location/site names
+reserved={'all-sites':None}
+reserved.update(keywords)
+reserved.update(levels)
def complain(msg):
+ "Complain about a particular input line"
global complaints
print ("%s line %d: "%(file,line))+msg
complaints=complaints+1
def moan(msg):
+ "Complain about something in general"
global complaints
print msg;
complaints=complaints+1
-# We don't allow redefinition of properties (because that would allow things
-# like restrict-nets to be redefined, which would be bad)
-def set(obj,defs,w):
- if (obj.allow_defs | allow_defs):
- if (obj.defs.has_key(w[0])):
- complain("%s is already defined"%(w[0]))
- else:
- t=defs[w[0]]
- obj.defs[w[0]]=t(w)
+root=level(['root','root']) # All vpns are children of this node
+obstack=[root]
+allow_defs=0 # Level above which new definitions are permitted
+
+def set_property(obj,w):
+ "Set a property on a configuration node"
+ if obj.properties.has_key(w[0]):
+ complain("%s %s already has property %s defined"%
+ (obj.type,obj.name,w[0]))
+ else:
+ obj.properties[w[0]]=keywords[w[0]][0](w)
-# Process a line of configuration file
def pline(i):
- global allow_defs, group, current_vpn, current_location, current_object
+ "Process a configuration file line"
+ global allow_defs, obstack, root
w=string.split(i)
if len(w)==0: return
keyword=w[0]
+ current=obstack[len(obstack)-1]
if keyword=='end-definitions':
- allow_defs=0
- current_vpn=None
- current_location=None
- current_object=None
+ allow_defs=sitelevel.depth
+ obstack=[root]
return
- if keyword=='vpn':
- if vpns.has_key(w[1]):
- current_vpn=vpns[w[1]]
- current_object=current_vpn
+ if levels.has_key(keyword):
+ # We may go up any number of levels, but only down by one
+ newdepth=levels[keyword].depth
+ currentdepth=len(obstack) # actually +1...
+ if newdepth<=currentdepth:
+ obstack=obstack[:newdepth]
+ if newdepth>currentdepth:
+ complain("May not go from level %d to level %d"%
+ (currentdepth-1,newdepth))
+ # See if it's a new one (and whether that's permitted)
+ # or an existing one
+ current=obstack[len(obstack)-1]
+ if current.children.has_key(w[1]):
+ # Not new
+ current=current.children[w[1]]
+ if service and group and current.depth==2:
+ if group!=current.group:
+ complain("Incorrect group!")
else:
- if allow_defs:
- current_vpn=vpn(w[1])
- vpns[w[1]]=current_vpn
- current_object=current_vpn
- else:
- complain("no new VPN definitions allowed")
+ # New
+ # Ignore depth check for now
+ nl=levels[keyword](w)
+ if nl.depth<allow_defs:
+ complain("New definitions not allowed at "
+ "level %d"%nl.depth)
+ current.children[w[1]]=nl
+ current=nl
+ obstack.append(current)
return
- if (current_vpn==None):
- complain("no VPN defined yet")
- return
- # Keywords that can apply at all levels
- if mldefs.has_key(w[0]):
- set(current_object,mldefs,w)
- return
- if keyword=='location':
- if (current_vpn.locations.has_key(w[1])):
- current_location=current_vpn.locations[w[1]]
- current_object=current_location
- if (group and not allow_defs and
- current_location.group!=group):
- complain(("must be group %s to access "+
- "location %s")%(current_location.group,
- w[1]))
- else:
- if allow_defs:
- if reserved.has_key(w[1]):
- complain("reserved location name")
- return
- current_location=location(w[1],current_vpn)
- current_vpn.locations[w[1]]=current_location
- current_object=current_location
- else:
- complain("no new location definitions allowed")
+ if current.allow_properties.has_key(keyword):
+ set_property(current,w)
return
- if (current_location==None):
- complain("no locations defined yet")
- return
- if keyword=='group':
- current_location.group=w[1]
- return
- if keyword=='site':
- if (current_location.sites.has_key(w[1])):
- current_object=current_location.sites[w[1]]
- else:
- if reserved.has_key(w[1]):
- complain("reserved site name")
- return
- current_object=site(w[1],current_location)
- current_location.sites[w[1]]=current_object
- return
- if keyword=='endsite':
- if isinstance(current_object,site):
- current_object=current_object.location
- else:
- complain("not currently defining a site")
- return
- # Keywords that can only apply to sites
- if isinstance(current_object,site):
- if sitedefs.has_key(w[0]):
- set(current_object,sitedefs,w)
- return
else:
- if sitedefs.has_key(w[0]):
- complain("keyword '%s' can only be used in the "
- "context of a site definition"%(w[0]))
- return
- complain("unknown keyword '%s'"%(w[0]))
+ complain("Property %s not allowed at %s level"%
+ (keyword,current.type))
+ return
+
+ complain("unknown keyword '%s'"%(keyword))
def pfile(name,lines):
+ "Process a file"
global file,line
file=name
line=0
pline(i)
def outputsites(w):
- w.write("# secnet sites file autogenerated by make-secnet-sites.py "
+ "Output include file for secnet configuration"
+ w.write("# secnet sites file autogenerated by make-secnet-sites "
+"version %s\n"%VERSION)
- w.write("# %s\n\n"%time.asctime(time.localtime(time.time())))
+ w.write("# %s\n"%time.asctime(time.localtime(time.time())))
+ w.write("# Command line: %s\n\n"%string.join(sys.argv))
# Raw VPN data section of file
w.write("vpn-data {\n")
- for i in vpns.values():
- w.write(" %s {\n"%i.name)
- for d in i.defs.values():
- w.write(" %s\n"%d.out())
- w.write("\n")
- for l in i.locations.values():
- w.write(" %s {\n"%l.name)
- for d in l.defs.values():
- w.write(" %s\n"%d.out())
- for s in l.sites.values():
- w.write(" %s {\n"%s.name)
- w.write(' name "%s/%s/%s";\n'%
- (i.name,l.name,s.name))
- for d in s.defs.values():
- w.write(" %s\n"%d.out())
- w.write(" };\n")
- w.write(" };\n")
- w.write(" };\n")
+ for i in root.children.values():
+ i.output_data(w,2,"")
w.write("};\n")
# Per-VPN flattened lists
w.write("vpn {\n")
- for i in vpns.values():
- w.write(" %s {\n"%(i.name))
- for l in i.locations.values():
- tmpl="vpn-data/%s/%s/%%s"%(i.name,l.name)
- slist=[]
- for s in l.sites.values(): slist.append(tmpl%s.name)
- w.write(" %s %s;\n"%(l.name,string.join(slist,",")))
- w.write("\n all-sites %s;\n"%
- string.join(i.locations.keys(),","))
- w.write(" };\n")
+ for i in root.children.values():
+ i.output_vpnflat(w,2,"vpn-data")
w.write("};\n")
# Flattened list of sites
w.write("all-sites %s;\n"%string.join(map(lambda x:"vpn/%s/all-sites"%
- x,vpns.keys()),","))
+ x,root.children.keys()),","))
# Are we being invoked from userv?
service=0
# If we are, which group does the caller want to modify?
group=None
-vpns={}
-allow_defs=1
-current_vpn=None
-current_location=None
-current_object=None
-
line=0
file=None
complaints=0
-# Things that can be defined at any level
-mldefs={
- 'dh':dhgroup,
- 'hash':hash,
- 'contact':email,
- 'key-lifetime':num,
- 'setup-retries':num,
- 'setup-timeout':num,
- 'wait-time':num,
- 'renegotiate-time':num,
- 'restrict-nets':nets
- }
-
-# Things that can only be defined for sites
-sitedefs={
- 'address':address,
- 'networks':nets,
- 'pubkey':rsakey,
- 'mobile':mobileoption
- }
-
-# Reserved vpn/location/site names
-reserved={'all-sites':None}
-reserved.update(mldefs)
-reserved.update(sitedefs)
-
-# Each site must have the following defined at some level:
-required={
- 'dh':"Diffie-Hellman group",
- 'networks':"network list",
- 'pubkey':"public key",
- 'hash':"hash function"
- }
-
if len(sys.argv)<2:
pfile("stdin",sys.stdin.readlines())
of=sys.stdout
of=open(sys.argv[2],'w')
# Sanity check section
-
-# Delete locations that have no sites defined
-for i in vpns.values():
- for l in i.locations.keys():
- if (len(i.locations[l].sites.values())==0):
- del i.locations[l]
-
-# Delete VPNs that have no locations with sites defined
-for i in vpns.keys():
- if (len(vpns[i].locations.values())==0):
- del vpns[i]
-
-# Check all sites
-for i in vpns.values():
- if i.defs.has_key('restrict-nets'):
- vr=i.defs['restrict-nets']
+# Delete nodes where leaf=0 that have no children
+
+def live(n):
+ "Number of leafnodes below node n"
+ if n.leaf: return 1
+ for i in n.children.keys():
+ if live(n.children[i]): return 1
+ return 0
+def delempty(n):
+ "Delete nodes that have no leafnode children"
+ for i in n.children.keys():
+ delempty(n.children[i])
+ if not live(n.children[i]):
+ del n.children[i]
+delempty(root)
+
+# Check that all constraints are met (as far as I can tell
+# restrict-nets/networks/peer are the only special cases)
+
+def checkconstraints(n,p,ra):
+ new_p=p.copy()
+ new_p.update(n.properties)
+ for i in n.require_properties.keys():
+ if not new_p.has_key(i):
+ moan("%s %s is missing property %s"%
+ (n.type,n.name,i))
+ for i in new_p.keys():
+ if not n.allow_properties.has_key(i):
+ moan("%s %s has forbidden property %s"%
+ (n.type,n.name,i))
+ # Check address range restrictions
+ if n.properties.has_key("restrict-nets"):
+ new_ra=ra.intersection(n.properties["restrict-nets"].set)
else:
- vr=None
- for l in i.locations.values():
- if l.defs.has_key('restrict-nets'):
- lr=l.defs['restrict-nets']
- if (not lr.subsetof(vr)):
- moan("location %s/%s restrict-nets is invalid"%
- (i.name,l.name))
- else:
- lr=vr
- for s in l.sites.values():
- sn="%s/%s/%s"%(i.name,l.name,s.name)
- for r in required.keys():
- if (not (s.defs.has_key(r) or
- l.defs.has_key(r) or
- i.defs.has_key(r))):
- moan("site %s missing parameter %s"%
- (sn,r))
- if s.defs.has_key('restrict-nets'):
- sr=s.defs['restrict-nets']
- if (not sr.subsetof(lr)):
- moan("site %s restrict-nets not valid"%
- sn)
- else:
- sr=lr
- if not s.defs.has_key('networks'): continue
- nets=s.defs['networks']
- if (not nets.subsetof(sr)):
- moan("site %s networks exceed restriction"%sn)
-
+ new_ra=ra
+ if n.properties.has_key("networks"):
+ # I'd like to do this:
+ # n.properties["networks"].set.is_subset(new_ra)
+ # but there isn't an is_subset() method
+ # Instead we see if we intersect with the complement of new_ra
+ rac=new_ra.complement()
+ i=rac.intersection(n.properties["networks"].set)
+ if not i.is_empty():
+ moan("%s %s networks out of bounds"%(n.type,n.name))
+ if n.properties.has_key("peer"):
+ if not n.properties["networks"].set.contains(
+ n.properties["peer"].addr):
+ moan("%s %s peer not in networks"%(n.type,n.name))
+ for i in n.children.keys():
+ checkconstraints(n.children[i],new_p,new_ra)
+
+checkconstraints(root,{},ipaddr.complete_set)
if complaints>0:
if complaints==1: print "There was 1 problem."
f=open(groupfiledir+"/T"+group,'w')
f.write("# Section submitted by user %s, %s\n"%
(user,time.asctime(time.localtime(time.time()))))
- f.write("# Checked by make-secnet-sites.py version %s\n\n"%VERSION)
+ f.write("# Checked by make-secnet-sites version %s\n\n"%VERSION)
for i in userinput: f.write(i)
f.write("\n")
f.close()
*/
+#include <string.h>
#include "secnet.h"
#include "util.h"
#include "ipaddr.h"
-/* CRT work by Simon Tatham */
+/* This file is part of secnet, and is distributed under the terms of
+ the GNU General Public License version 2 or later.
+
+ Copyright (C) 1995-2002 Stephen Early
+ Copyright (C) 2001 Simon Tatham
+ Copyright (C) 2002 Ian Jackson
+ */
#include <stdio.h>
+#include <string.h>
#include <gmp.h>
#include "secnet.h"
#include "util.h"
mpz_init(&a);
mpz_init(&b);
+ /* RSA PKCS#1 v1.5 signature padding:
+ *
+ * <------------ msize hex digits ---------->
+ *
+ * 00 01 ff ff .... ff ff 00 vv vv vv .... vv
+ *
+ * <--- datalen -->
+ * bytes
+ * = datalen*2 hex digits
+ *
+ * NB that according to PKCS#1 v1.5 we're supposed to include a
+ * hash function OID in the data. We don't do that (because we
+ * don't have the hash function OID to hand here), thus violating
+ * the spec in a way that affects interop but not security.
+ *
+ * -iwj 17.9.2002
+ */
+
msize=mpz_sizeinbase(&st->n, 16);
- if (datalen*2+4>=msize) {
+ if (datalen*2+6>=msize) {
fatal("rsa_sign: message too big");
}
strcpy(buff,"0001");
for (i=0; i<datalen; i++) {
- buff[4+i*2]=hexchars[(data[i]&0xf0)>>4];
- buff[5+i*2]=hexchars[data[i]&0xf];
+ buff[msize+(-datalen+i)*2]=hexchars[(data[i]&0xf0)>>4];
+ buff[msize+(-datalen+i)*2+1]=hexchars[data[i]&0xf];
}
- buff[4+datalen*2]=0;
- for (i=datalen*2+4; i<msize; i++)
- buff[i]='f';
+ buff[msize-datalen*2-2]= '0';
+ buff[msize-datalen*2-1]= '0';
+
+ for (i=4; i<msize-datalen*2-2; i++)
+ buff[i]='f';
buff[msize]=0;
strcpy(buff,"0001");
for (i=0; i<datalen; i++) {
- buff[4+i*2]=hexchars[(data[i]&0xf0)>>4];
- buff[5+i*2]=hexchars[data[i]&0xf];
+ buff[msize+(-datalen+i)*2]=hexchars[(data[i]&0xf0)>>4];
+ buff[msize+(-datalen+i)*2+1]=hexchars[data[i]&0xf];
}
- buff[4+datalen*2]=0;
- for (i=datalen*2+4; i<msize; i++)
+ buff[msize-datalen*2-2]= '0';
+ buff[msize-datalen*2-1]= '0';
+
+ for (i=4; i<msize-datalen*2-2; i++)
buff[i]='f';
buff[msize]=0;
uint8_t *b, *c;
int cipher_type;
MP_INT e,d,iqmp,tmp,tmp2,tmp3;
+ bool_t valid;
st=safe_malloc(sizeof(*st),"rsapriv_apply");
st->cl.description="rsapriv";
* Now verify the validity of the key, and set up the auxiliary
* values for fast CRT signing.
*/
+ valid=False;
i=list_elem(args,1);
+ mpz_init(&tmp);
+ mpz_init(&tmp2);
+ mpz_init(&tmp3);
if (i && i->type==t_bool && i->data.bool==False) {
Message(M_INFO,"rsa-private (%s:%d): skipping RSA key validity "
"check\n",loc.file,loc.line);
} else {
- int valid = 0;
- mpz_init(&tmp);
- mpz_init(&tmp2);
- mpz_init(&tmp3);
-
/* Verify that p*q is equal to n. */
mpz_mul(&tmp, &st->p, &st->q);
if (mpz_cmp(&tmp, &st->n) != 0)
mpz_mod(&tmp2, &tmp, &st->p);
if (mpz_cmp_si(&tmp2, 1) != 0)
goto done_checks;
-
- /* Now we know the key is valid. */
- valid = 1;
-
- /*
- * Now we compute auxiliary values dp, dq and w to allow us
- * to use the CRT optimisation when signing.
- *
- * dp == d mod (p-1) so that a^dp == a^d mod p, for all a
- * dq == d mod (q-1) similarly mod q
- * w == iqmp * q so that w == 0 mod q, and w == 1 mod p
- */
- mpz_sub_ui(&tmp, &st->p, 1);
- mpz_mod(&st->dp, &d, &tmp);
- mpz_sub_ui(&tmp, &st->q, 1);
- mpz_mod(&st->dq, &d, &tmp);
- mpz_mul(&st->w, &iqmp, &st->q);
-
- done_checks:
- if (!valid) {
- cfgfatal(loc,"rsa-private","file \"%s\" does not contain a "
- "valid RSA key!\n",filename);
- }
- mpz_clear(&tmp);
- mpz_clear(&tmp2);
- mpz_clear(&tmp3);
}
+ /* Now we know the key is valid (or we don't care). */
+ valid = True;
+
+ /*
+ * Now we compute auxiliary values dp, dq and w to allow us
+ * to use the CRT optimisation when signing.
+ *
+ * dp == d mod (p-1) so that a^dp == a^d mod p, for all a
+ * dq == d mod (q-1) similarly mod q
+ * w == iqmp * q so that w == 0 mod q, and w == 1 mod p
+ */
+ mpz_init(&st->dp);
+ mpz_init(&st->dq);
+ mpz_init(&st->w);
+ mpz_sub_ui(&tmp, &st->p, 1);
+ mpz_mod(&st->dp, &d, &tmp);
+ mpz_sub_ui(&tmp, &st->q, 1);
+ mpz_mod(&st->dq, &d, &tmp);
+ mpz_mul(&st->w, &iqmp, &st->q);
+
+done_checks:
+ if (!valid) {
+ cfgfatal(loc,"rsa-private","file \"%s\" does not contain a "
+ "valid RSA key!\n",filename);
+ }
+ mpz_clear(&tmp);
+ mpz_clear(&tmp2);
+ mpz_clear(&tmp3);
free(c);
mpz_clear(&e);
int timeout;
struct pollfd *fds;
- fds=alloca(sizeof(*fds)*total_nfds);
- if (!fds) {
- fatal("run: couldn't alloca");
- }
+ fds=safe_malloc(sizeof(*fds)*total_nfds, "run");
Message(M_NOTICE,"%s [%d]: starting\n",version,secnet_pid);
}
} while (rv<0);
} while (!finished);
+ free(fds);
}
static void droppriv(void)
#include <sys/time.h>
#include <netinet/in.h>
+/*
+ * Macros added by SGT for endianness-independence
+ */
+#define GET_32BIT_MSB_FIRST(cp) \
+ (((unsigned long)(unsigned char)(cp)[0] << 24) | \
+ ((unsigned long)(unsigned char)(cp)[1] << 16) | \
+ ((unsigned long)(unsigned char)(cp)[2] << 8) | \
+ ((unsigned long)(unsigned char)(cp)[3]))
+
+#define PUT_32BIT_MSB_FIRST(cp, value) ( \
+ (cp)[0] = (char)((value) >> 24), \
+ (cp)[1] = (char)((value) >> 16), \
+ (cp)[2] = (char)((value) >> 8), \
+ (cp)[3] = (char)(value) )
+
typedef char *string_t;
typedef const char *cstring_t;
typedef enum {False,True} bool_t;
uint32_t w[132],k[132];
for(i=0; i<keyLen/32; i++)
- w[i]=keyMaterial[i];
+ w[i]=GET_32BIT_MSB_FIRST(keyMaterial + (keyLen/8 - i*4) - 4);
if(keyLen<256)
- w[i]=(keyMaterial[i]&((1L<<((keyLen&31)))-1))|(1L<<((keyLen&31)));
+ w[i]=(GET_32BIT_MSB_FIRST(keyMaterial + (keyLen/8 - i*4) - 4)
+ & ((1L<<((keyLen&31)))-1)) | (1L<<((keyLen&31)));
for(i++; i<8; i++)
w[i]=0;
for(i=8; i<16; i++)
}
void serpent_encrypt(struct keyInstance *key,
- uint32_t plaintext[4],
- uint32_t ciphertext[4])
+ uint8_t plaintext[16],
+ uint8_t ciphertext[16])
{
register uint32_t x0, x1, x2, x3;
register uint32_t y0, y1, y2, y3;
- x0=plaintext[0];
- x1=plaintext[1];
- x2=plaintext[2];
- x3=plaintext[3];
+ x0=GET_32BIT_MSB_FIRST(plaintext+12);
+ x1=GET_32BIT_MSB_FIRST(plaintext+8);
+ x2=GET_32BIT_MSB_FIRST(plaintext+4);
+ x3=GET_32BIT_MSB_FIRST(plaintext);
/* Start to encrypt the plaintext x */
keying(x0, x1, x2, x3, key->subkeys[ 0]);
keying(x0, x1, x2, x3, key->subkeys[32]);
/* The ciphertext is now in x */
- ciphertext[0] = x0;
- ciphertext[1] = x1;
- ciphertext[2] = x2;
- ciphertext[3] = x3;
+ PUT_32BIT_MSB_FIRST(ciphertext+12, x0);
+ PUT_32BIT_MSB_FIRST(ciphertext+8, x1);
+ PUT_32BIT_MSB_FIRST(ciphertext+4, x2);
+ PUT_32BIT_MSB_FIRST(ciphertext, x3);
}
void serpent_decrypt(struct keyInstance *key,
- uint32_t ciphertext[4],
- uint32_t plaintext[4])
+ uint8_t ciphertext[16],
+ uint8_t plaintext[16])
{
register uint32_t x0, x1, x2, x3;
register uint32_t y0, y1, y2, y3;
- x0=ciphertext[0];
- x1=ciphertext[1];
- x2=ciphertext[2];
- x3=ciphertext[3];
+ x0=GET_32BIT_MSB_FIRST(ciphertext+12);
+ x1=GET_32BIT_MSB_FIRST(ciphertext+8);
+ x2=GET_32BIT_MSB_FIRST(ciphertext+4);
+ x3=GET_32BIT_MSB_FIRST(ciphertext);
/* Start to decrypt the ciphertext x */
keying(x0, x1, x2, x3, key->subkeys[32]);
keying(x0, x1, x2, x3, key->subkeys[ 0]);
/* The plaintext is now in x */
- plaintext[0] = x0;
- plaintext[1] = x1;
- plaintext[2] = x2;
- plaintext[3] = x3;
+ PUT_32BIT_MSB_FIRST(plaintext+12, x0);
+ PUT_32BIT_MSB_FIRST(plaintext+8, x1);
+ PUT_32BIT_MSB_FIRST(plaintext+4, x2);
+ PUT_32BIT_MSB_FIRST(plaintext, x3);
}
void serpent_makekey(struct keyInstance *key, int keyLen,
uint8_t *keyMaterial);
-void serpent_encrypt(struct keyInstance *key, uint32_t plaintext[4],
- uint32_t ciphertext[4]);
+void serpent_encrypt(struct keyInstance *key, uint8_t plaintext[16],
+ uint8_t ciphertext[16]);
-void serpent_decrypt(struct keyInstance *key, uint32_t ciphertext[4],
- uint32_t plaintext[4]);
+void serpent_decrypt(struct keyInstance *key, uint8_t ciphertext[16],
+ uint8_t plaintext[16]);
#endif /* serpent_h */
static bool_t generate_msg(struct site *st, uint32_t type, cstring_t what)
{
void *hst;
- uint8_t *hash=alloca(st->hash->len);
+ uint8_t *hash;
string_t dhpub, sig;
st->retries=st->setup_retries;
if (type==LABEL_MSG1) return True;
memcpy(buf_append(&st->buffer,NONCELEN),st->remoteN,NONCELEN);
if (type==LABEL_MSG2) return True;
+
+ if (hacky_par_mid_failnow()) return False;
+
dhpub=st->dh->makepublic(st->dh->st,st->dhsecret,st->dh->len);
buf_append_string(&st->buffer,dhpub);
free(dhpub);
+ hash=safe_malloc(st->hash->len, "generate_msg");
hst=st->hash->init();
st->hash->update(hst,st->buffer.start,st->buffer.size);
st->hash->final(hst,hash);
sig=st->privkey->sign(st->privkey->st,hash,st->hash->len);
buf_append_string(&st->buffer,sig);
free(sig);
+ free(hash);
return True;
}
struct sockaddr_in *src)
{
struct msg m;
- uint8_t *hash=alloca(st->hash->len);
+ uint8_t *hash;
void *hst;
cstring_t err;
}
/* Check signature and store g^x mod m */
+ hash=safe_malloc(st->hash->len, "process_msg3");
hst=st->hash->init();
st->hash->update(hst,m.hashstart,m.hashlen);
st->hash->final(hst,hash);
m.sig[m.siglen]=0;
if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
slog(st,LOG_SEC,"msg3 signature failed check!");
+ free(hash);
return False;
}
+ free(hash);
/* Terminate their DH public key with a '0' */
m.pk[m.pklen]=0;
struct sockaddr_in *src)
{
struct msg m;
- uint8_t *hash=alloca(st->hash->len);
+ uint8_t *hash;
void *hst;
cstring_t err;
}
/* Check signature and store g^x mod m */
+ hash=safe_malloc(st->hash->len, "process_msg4");
hst=st->hash->init();
st->hash->update(hst,m.hashstart,m.hashlen);
st->hash->final(hst,hash);
m.sig[m.siglen]=0;
if (!st->pubkey->check(st->pubkey->st,hash,st->hash->len,m.sig)) {
slog(st,LOG_SEC,"msg4 signature failed check!");
+ free(hash);
return False;
}
+ free(hash);
/* Terminate their DH public key with a '0' */
m.pk[m.pklen]=0;
static bool_t enter_new_state(struct site *st, uint32_t next)
{
bool_t (*gen)(struct site *st);
+ int r;
+
slog(st,LOG_STATE,"entering state %s",state_name(next));
switch(next) {
case SITE_SENTMSG1:
break;
}
- if (gen(st) && send_msg(st)) {
+ if (hacky_par_start_failnow()) return False;
+
+ r= gen(st) && send_msg(st);
+
+ hacky_par_end(&r,
+ st->setup_retries, st->setup_timeout,
+ send_msg, st);
+
+ if (r) {
st->state=next;
if (next==SITE_RUN) {
BUF_FREE(&st->buffer); /* Never reused */
st->now=*now;
if (st->timeout && *now>st->timeout) {
st->timeout=0;
- if (st->state>=SITE_SENTMSG1 && st->state<=SITE_SENTMSG5)
- send_msg(st);
- else if (st->state==SITE_WAIT) {
+ if (st->state>=SITE_SENTMSG1 && st->state<=SITE_SENTMSG5) {
+ if (!hacky_par_start_failnow())
+ send_msg(st);
+ } else if (st->state==SITE_WAIT) {
enter_state_run(st);
} else {
slog(st,LOG_ERROR,"site_afterpoll: unexpected timeout, state=%d",
/* Required key length in bytes */
#define REQUIRED_KEYLEN ((512+64+32)/8)
-#ifdef WORDS_BIGENDIAN
-static inline uint32_t byteswap(uint32_t a)
-{
- return
- ((a&0x000000ff)<<24) |
- ((a&0x0000ff00)<<8) |
- ((a&0x00ff0000)>>8) |
- ((a&0xff000000)>>24);
-}
-#endif
-
struct transform {
closure_t cl;
uint32_t line;
serpent_makekey(&ti->cryptkey,256,key);
serpent_makekey(&ti->mackey,256,key+32);
- ti->cryptiv=ntohl(*(uint32_t *)(key+64));
- ti->maciv=ntohl(*(uint32_t *)(key+68));
- ti->sendseq=ntohl(*(uint32_t *)(key+72));
+ ti->cryptiv=GET_32BIT_MSB_FIRST(key+64);
+ ti->maciv=GET_32BIT_MSB_FIRST(key+68);
+ ti->sendseq=GET_32BIT_MSB_FIRST(key+72);
ti->lastrecvseq=ti->sendseq;
ti->keyed=True;
struct transform_inst *ti=sst;
uint8_t *padp;
int padlen;
- uint32_t iv[4];
- uint32_t macplain[4];
- uint32_t macacc[4];
- uint32_t *n, *p;
+ uint8_t iv[16];
+ uint8_t macplain[16];
+ uint8_t macacc[16];
+ uint8_t *p, *n;
+ int i;
if (!ti->keyed) {
*errmsg="transform unkeyed";
it we've have to add 16 bytes to each message, not 4, so that the
message stays a multiple of 16 bytes long.) */
memset(iv,0,16);
- iv[0]=ti->maciv;
+ PUT_32BIT_MSB_FIRST(iv, ti->maciv);
serpent_encrypt(&ti->mackey,iv,macacc);
/* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
block encrypted once again. */
- for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+ for (n=buf->start; n<buf->start+buf->size; n+=16)
{
-#ifdef WORDS_BIGENDIAN
- macplain[0]=macacc[0]^byteswap(n[0]);
- macplain[1]=macacc[1]^byteswap(n[1]);
- macplain[2]=macacc[2]^byteswap(n[2]);
- macplain[3]=macacc[3]^byteswap(n[3]);
-#else
- macplain[0]=macacc[0]^n[0];
- macplain[1]=macacc[1]^n[1];
- macplain[2]=macacc[2]^n[2];
- macplain[3]=macacc[3]^n[3];
-#endif
+ for (i = 0; i < 16; i++)
+ macplain[i] = macacc[i] ^ n[i];
serpent_encrypt(&ti->mackey,macplain,macacc);
}
serpent_encrypt(&ti->mackey,macacc,macacc);
-#ifdef WORDS_BIGENDIAN
- macacc[0]=byteswap(macacc[0]);
- macacc[1]=byteswap(macacc[1]);
- macacc[2]=byteswap(macacc[2]);
- macacc[3]=byteswap(macacc[3]);
-#endif
memcpy(buf_append(buf,16),macacc,16);
/* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption,
and prepend the IV before increasing it. */
memset(iv,0,16);
- iv[0]=ti->cryptiv;
+ PUT_32BIT_MSB_FIRST(iv, ti->cryptiv);
serpent_encrypt(&ti->cryptkey,iv,iv);
/* CBC: each block is XORed with the previous encrypted block (or the IV)
before being encrypted. */
p=iv;
-#ifdef WORDS_BIGENDIAN
- /* This counters the byteswap() in the first half of the loop, which in
- turn counters the byteswap() in the second half of the loop. Ick. */
- iv[0]=byteswap(iv[0]);
- iv[1]=byteswap(iv[1]);
- iv[2]=byteswap(iv[2]);
- iv[3]=byteswap(iv[3]);
-#endif
- for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+
+ for (n=buf->start; n<buf->start+buf->size; n+=16)
{
-#ifdef WORDS_BIGENDIAN
- /* Think of this as byteswap(p[x])^byteswap(n[x]) */
- n[0]=byteswap(p[0]^n[0]);
- n[1]=byteswap(p[1]^n[1]);
- n[2]=byteswap(p[2]^n[2]);
- n[3]=byteswap(p[3]^n[3]);
-#else
- n[0]=p[0]^n[0];
- n[1]=p[1]^n[1];
- n[2]=p[2]^n[2];
- n[3]=p[3]^n[3];
-#endif
+ for (i = 0; i < 16; i++)
+ n[i] ^= p[i];
serpent_encrypt(&ti->cryptkey,n,n);
-#ifdef WORDS_BIGENDIAN
- n[0]=byteswap(n[0]);
- n[1]=byteswap(n[1]);
- n[2]=byteswap(n[2]);
- n[3]=byteswap(n[3]);
-#endif
p=n;
}
unsigned padlen;
int i;
uint32_t seqnum, skew;
- uint32_t iv[4];
- uint32_t pct[4];
- uint32_t macplain[4];
- uint32_t macacc[4];
- uint32_t *n;
- uint32_t *macexpected;
+ uint8_t iv[16];
+ uint8_t pct[16];
+ uint8_t macplain[16];
+ uint8_t macacc[16];
+ uint8_t *n;
+ uint8_t *macexpected;
if (!ti->keyed) {
*errmsg="transform unkeyed";
/* CBC */
memset(iv,0,16);
- iv[0]=buf_unprepend_uint32(buf);
+ {
+ uint32_t ivword = buf_unprepend_uint32(buf);
+ PUT_32BIT_MSB_FIRST(iv, ivword);
+ }
/* Assert bufsize is multiple of blocksize */
if (buf->size&0xf) {
*errmsg="msg not multiple of cipher blocksize";
}
serpent_encrypt(&ti->cryptkey,iv,iv);
- for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+ for (n=buf->start; n<buf->start+buf->size; n+=16)
{
-#ifdef WORDS_BIGENDIAN
- n[0]=byteswap(n[0]);
- n[1]=byteswap(n[1]);
- n[2]=byteswap(n[2]);
- n[3]=byteswap(n[3]);
-#endif
- pct[0]=n[0]; pct[1]=n[1]; pct[2]=n[2]; pct[3]=n[3];
+ for (i = 0; i < 16; i++)
+ pct[i] = n[i];
serpent_decrypt(&ti->cryptkey,n,n);
-#ifdef WORDS_BIGENDIAN
- n[0]=byteswap(iv[0]^n[0]);
- n[1]=byteswap(iv[1]^n[1]);
- n[2]=byteswap(iv[2]^n[2]);
- n[3]=byteswap(iv[3]^n[3]);
-#else
- n[0]=iv[0]^n[0];
- n[1]=iv[1]^n[1];
- n[2]=iv[2]^n[2];
- n[3]=iv[3]^n[3];
-#endif
- iv[0]=pct[0]; iv[1]=pct[1]; iv[2]=pct[2]; iv[3]=pct[3];
+ for (i = 0; i < 16; i++)
+ n[i] ^= iv[i];
+ memcpy(iv, pct, 16);
}
/* CBCMAC */
macexpected=buf_unappend(buf,16);
memset(iv,0,16);
- iv[0]=ti->maciv;
+ PUT_32BIT_MSB_FIRST(iv, ti->maciv);
serpent_encrypt(&ti->mackey,iv,macacc);
/* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
block encrypted once again. */
- for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
+ for (n=buf->start; n<buf->start+buf->size; n+=16)
{
-#ifdef WORDS_BIGENDIAN
- macplain[0]=macacc[0]^byteswap(n[0]);
- macplain[1]=macacc[1]^byteswap(n[1]);
- macplain[2]=macacc[2]^byteswap(n[2]);
- macplain[3]=macacc[3]^byteswap(n[3]);
-#else
- macplain[0]=macacc[0]^n[0];
- macplain[1]=macacc[1]^n[1];
- macplain[2]=macacc[2]^n[2];
- macplain[3]=macacc[3]^n[3];
-#endif
+ for (i = 0; i < 16; i++)
+ macplain[i] = macacc[i] ^ n[i];
serpent_encrypt(&ti->mackey,macplain,macacc);
}
serpent_encrypt(&ti->mackey,macacc,macacc);
-#ifdef WORDS_BIGENDIAN
- macacc[0]=byteswap(macacc[0]);
- macacc[1]=byteswap(macacc[1]);
- macacc[2]=byteswap(macacc[2]);
- macacc[3]=byteswap(macacc[3]);
-#endif
if (memcmp(macexpected,macacc,16)!=0) {
*errmsg="invalid MAC";
return 1;
{
struct keyInstance k;
uint8_t data[32];
- uint32_t plaintext[4];
- uint32_t ciphertext[4];
+ uint8_t plaintext[16];
+ uint8_t ciphertext[16];
+
+ /*
+ * Serpent self-test.
+ *
+ * This test pattern is taken directly from the Serpent test
+ * vectors, to ensure we have all endianness issues correct. -sgt
+ */
/* Serpent self-test */
- memset(data,0,32);
+ memcpy(data,
+ "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
+ "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00",
+ 32);
serpent_makekey(&k,256,data);
- plaintext[0]=0x00000000;
- plaintext[1]=0x00000001;
- plaintext[2]=0x00000002;
- plaintext[3]=0x00000003;
+
+ memcpy(plaintext,
+ "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10",
+ 16);
serpent_encrypt(&k,plaintext,ciphertext);
- if (ciphertext[3]!=0x7ca73bb0 ||
- ciphertext[2]!=0x83C31E69 ||
- ciphertext[1]!=0xec52bd82 ||
- ciphertext[0]!=0x27a46120) {
+
+ if (memcmp(ciphertext, "\xca\x7f\xa1\x93\xe3\xeb\x9e\x99"
+ "\xbd\x87\xe3\xaf\x3c\x9a\xdf\x93", 16)) {
fatal("transform_module: serpent failed self-test (encrypt)");
}
serpent_decrypt(&k,ciphertext,plaintext);
- if (plaintext[0]!=0 ||
- plaintext[1]!=1 ||
- plaintext[2]!=2 ||
- plaintext[3]!=3) {
+ if (memcmp(plaintext, "\x01\x23\x45\x67\x89\xab\xcd\xef"
+ "\xfe\xdc\xba\x98\x76\x54\x32\x10", 16)) {
fatal("transform_module: serpent failed self-test (decrypt)");
}
add_closure(dict,"serpent256-cbc",transform_apply);
+
+#ifdef TEST_WHOLE_TRANSFORM
+ {
+ struct transform *tr;
+ void *ti;
+ struct buffer_if buf;
+ const char text[] = "This is a piece of test text.";
+ char keymaterial[76] =
+ "Seventy-six bytes i"
+ "n four rows of 19; "
+ "this looks almost l"
+ "ike a poem but not.";
+ const char *errmsg;
+ int i;
+
+ tr = malloc(sizeof(struct transform));
+ tr->max_seq_skew = 20;
+ ti = transform_create(tr);
+
+ transform_setkey(ti, keymaterial, 76);
+
+ buf.base = malloc(4096);
+ buffer_init(&buf, 2048);
+ memcpy(buf_append(&buf, sizeof(text)), text, sizeof(text));
+ if (transform_forward(ti, &buf, &errmsg)) {
+ fatal("transform_forward test: %s", errmsg);
+ }
+ printf("transformed text is:\n");
+ for (i = 0; i < buf.size; i++)
+ printf("%02x%c", buf.start[i],
+ (i%16==15 || i==buf.size-1 ? '\n' : ' '));
+ if (transform_reverse(ti, &buf, &errmsg)) {
+ fatal("transform_reverse test: %s", errmsg);
+ }
+ printf("transform reversal worked OK\n");
+ }
+#endif
}
}
static void tun_afterpoll(void *sst, struct pollfd *fds, int nfds,
- const struct timeval *tv_now, uint64_t *now)
+ const struct timeval *tv_now, uint64_t *now)
{
struct tun *st=sst;
int l;
closure_t cl;
struct comm_if ops;
struct cloc loc;
+ uint32_t addr;
uint16_t port;
int fd;
string_t authbind;
struct udp *st=sst;
struct sockaddr_in addr;
- st->fd=socket(AF_INET, SOCK_DGRAM, 0);
+ st->fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (st->fd<0) {
fatal_perror("udp (%s:%d): socket",st->loc.file,st->loc.line);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family=AF_INET;
+ addr.sin_addr.s_addr=htonl(st->addr);
addr.sin_port=htons(st->port);
if (st->authbind) {
pid_t c;
fatal_perror("udp_phase_hook: fork() for authbind");
}
if (c==0) {
- char *argv[4];
+ char *argv[4], addrstr[9], portstr[5];
+ sprintf(addrstr,"%08lX",(long)st->addr);
+ sprintf(portstr,"%04X",st->port);
argv[0]=st->authbind;
- argv[1]=strdup("00000000");
- if (!argv[1]) exit(ENOMEM);
- argv[2]=alloca(8);
- if (!argv[2]) exit(ENOMEM);
- sprintf(argv[2],"%04X",htons(st->port));
+ argv[1]=addrstr;
+ argv[2]=portstr;
argv[3]=NULL;
dup2(st->fd,0);
execvp(st->authbind,argv);
- exit(ENOEXEC);
+ _exit(255);
}
- waitpid(c,&status,0);
- if (WEXITSTATUS(status)!=0) {
- errno=WEXITSTATUS(status);
+ while (waitpid(c,&status,0)==-1) {
+ if (errno==EINTR) continue;
fatal_perror("udp (%s:%d): authbind",st->loc.file,st->loc.line);
}
+ if (WIFSIGNALED(status)) {
+ fatal("udp (%s:%d): authbind died on signal %d",st->loc.file,
+ st->loc.line, WTERMSIG(status));
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
+ fatal("udp (%s:%d): authbind died with status %d",st->loc.file,
+ st->loc.line, WEXITSTATUS(status));
+ }
} else {
if (bind(st->fd, (struct sockaddr *)&addr, sizeof(addr))!=0) {
fatal_perror("udp (%s:%d): bind",st->loc.file,st->loc.line);
list_t *args)
{
struct udp *st;
- item_t *i;
+ item_t *i,*j;
dict_t *d;
list_t *l;
uint32_t a;
}
d=i->data.dict;
+ j=dict_find_item(d,"address",False,"udp",st->loc);
+ st->addr=j?st->addr=string_item_to_ipaddr(j, "udp"):INADDR_ANY;
st->port=dict_read_number(d,"port",True,"udp",st->loc,0);
st->rbuf=find_cl_if(d,"buffer",CL_BUFFER,True,"udp",st->loc);
st->authbind=dict_read_string(d,"authbind",False,"udp",st->loc);
#include "secnet.h"
#include <gmp.h>
+#include "hackypar.h"
+
#define BUF_ASSERT_FREE(buf) do { buffer_assert_free((buf), \
__FILE__,__LINE__); } \
while(0)