summaryrefslogtreecommitdiff
path: root/linux/lib/libfreeswan
diff options
context:
space:
mode:
Diffstat (limited to 'linux/lib/libfreeswan')
-rw-r--r--linux/lib/libfreeswan/Makefile.objs18
-rw-r--r--linux/lib/libfreeswan/addrtoa.c68
-rw-r--r--linux/lib/libfreeswan/addrtot.c302
-rw-r--r--linux/lib/libfreeswan/addrtypeof.c94
-rw-r--r--linux/lib/libfreeswan/anyaddr.387
-rw-r--r--linux/lib/libfreeswan/anyaddr.c146
-rw-r--r--linux/lib/libfreeswan/atoaddr.3294
-rw-r--r--linux/lib/libfreeswan/atoaddr.c238
-rw-r--r--linux/lib/libfreeswan/atoasr.3186
-rw-r--r--linux/lib/libfreeswan/atoasr.c212
-rw-r--r--linux/lib/libfreeswan/atosa.3218
-rw-r--r--linux/lib/libfreeswan/atosa.c200
-rw-r--r--linux/lib/libfreeswan/atosubnet.c216
-rw-r--r--linux/lib/libfreeswan/atoul.3161
-rw-r--r--linux/lib/libfreeswan/atoul.c90
-rw-r--r--linux/lib/libfreeswan/copyright.c56
-rw-r--r--linux/lib/libfreeswan/datatot.c233
-rw-r--r--linux/lib/libfreeswan/goodmask.357
-rw-r--r--linux/lib/libfreeswan/goodmask.c97
-rw-r--r--linux/lib/libfreeswan/initaddr.3129
-rw-r--r--linux/lib/libfreeswan/initaddr.c51
-rw-r--r--linux/lib/libfreeswan/initsaid.c33
-rw-r--r--linux/lib/libfreeswan/initsubnet.3137
-rw-r--r--linux/lib/libfreeswan/initsubnet.c95
-rw-r--r--linux/lib/libfreeswan/internal.h81
-rw-r--r--linux/lib/libfreeswan/keyblobtoid.3103
-rw-r--r--linux/lib/libfreeswan/keyblobtoid.c148
-rw-r--r--linux/lib/libfreeswan/optionsfrom.3182
-rw-r--r--linux/lib/libfreeswan/optionsfrom.c301
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_build.c1438
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_debug.c179
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_ext_bits.c803
-rw-r--r--linux/lib/libfreeswan/pfkey_v2_parse.c1832
-rw-r--r--linux/lib/libfreeswan/portof.370
-rw-r--r--linux/lib/libfreeswan/portof.c96
-rw-r--r--linux/lib/libfreeswan/prng.3121
-rw-r--r--linux/lib/libfreeswan/prng.c202
-rw-r--r--linux/lib/libfreeswan/rangetoa.c61
-rw-r--r--linux/lib/libfreeswan/rangetosubnet.359
-rw-r--r--linux/lib/libfreeswan/rangetosubnet.c226
-rw-r--r--linux/lib/libfreeswan/sameaddr.3165
-rw-r--r--linux/lib/libfreeswan/sameaddr.c190
-rw-r--r--linux/lib/libfreeswan/satoa.c102
-rw-r--r--linux/lib/libfreeswan/satot.c132
-rw-r--r--linux/lib/libfreeswan/subnetof.347
-rw-r--r--linux/lib/libfreeswan/subnetof.c60
-rw-r--r--linux/lib/libfreeswan/subnettoa.c62
-rw-r--r--linux/lib/libfreeswan/subnettot.c56
-rw-r--r--linux/lib/libfreeswan/subnettypeof.c109
-rw-r--r--linux/lib/libfreeswan/ttoaddr.3377
-rw-r--r--linux/lib/libfreeswan/ttoaddr.c426
-rw-r--r--linux/lib/libfreeswan/ttodata.3281
-rw-r--r--linux/lib/libfreeswan/ttodata.c722
-rw-r--r--linux/lib/libfreeswan/ttoprotoport.c103
-rw-r--r--linux/lib/libfreeswan/ttosa.3288
-rw-r--r--linux/lib/libfreeswan/ttosa.c280
-rw-r--r--linux/lib/libfreeswan/ttosubnet.c296
-rw-r--r--linux/lib/libfreeswan/ttoul.3192
-rw-r--r--linux/lib/libfreeswan/ttoul.c91
-rw-r--r--linux/lib/libfreeswan/ultoa.c67
-rw-r--r--linux/lib/libfreeswan/ultot.c83
-rw-r--r--linux/lib/libfreeswan/version.344
-rw-r--r--linux/lib/libfreeswan/version.in.c44
63 files changed, 13537 insertions, 0 deletions
diff --git a/linux/lib/libfreeswan/Makefile.objs b/linux/lib/libfreeswan/Makefile.objs
new file mode 100644
index 000000000..41a89dba9
--- /dev/null
+++ b/linux/lib/libfreeswan/Makefile.objs
@@ -0,0 +1,18 @@
+obj-y += ultoa.o
+obj-y += addrtoa.o
+obj-y += subnettoa.o
+obj-y += subnetof.o
+obj-y += goodmask.o
+obj-y += datatot.o
+obj-y += rangetoa.o
+obj-y += satoa.o
+obj-y += prng.o
+obj-y += pfkey_v2_parse.o
+obj-y += pfkey_v2_build.o
+obj-y += pfkey_v2_debug.o
+obj-y += pfkey_v2_ext_bits.o
+obj-y += version.o
+
+
+version.c: ${LIBFREESWANDIR}/version.in.c ${FREESWANSRCDIR}/Makefile.ver
+ sed '/"/s/xxx/$(IPSECVERSION)/' ${LIBFREESWANDIR}/version.in.c >$@
diff --git a/linux/lib/libfreeswan/addrtoa.c b/linux/lib/libfreeswan/addrtoa.c
new file mode 100644
index 000000000..b1cc038ed
--- /dev/null
+++ b/linux/lib/libfreeswan/addrtoa.c
@@ -0,0 +1,68 @@
+/*
+ * addresses to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: addrtoa.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#define NBYTES 4 /* bytes in an address */
+#define PERBYTE 4 /* three digits plus a dot or NUL */
+#define BUFLEN (NBYTES*PERBYTE)
+
+#if BUFLEN != ADDRTOA_BUF
+#error "ADDRTOA_BUF in freeswan.h inconsistent with addrtoa() code"
+#endif
+
+/*
+ - addrtoa - convert binary address to ASCII dotted decimal
+ */
+size_t /* space needed for full conversion */
+addrtoa(addr, format, dst, dstlen)
+struct in_addr addr;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ unsigned long a = ntohl(addr.s_addr);
+ int i;
+ size_t n;
+ unsigned long byte;
+ char buf[BUFLEN];
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ p = buf;
+ for (i = NBYTES-1; i >= 0; i--) {
+ byte = (a >> (i*8)) & 0xff;
+ p += ultoa(byte, 10, p, PERBYTE);
+ if (i != 0)
+ *(p-1) = '.';
+ }
+ n = p - buf;
+
+ if (dstlen > 0) {
+ if (n > dstlen)
+ buf[dstlen - 1] = '\0';
+ strcpy(dst, buf);
+ }
+ return n;
+}
diff --git a/linux/lib/libfreeswan/addrtot.c b/linux/lib/libfreeswan/addrtot.c
new file mode 100644
index 000000000..f229789f0
--- /dev/null
+++ b/linux/lib/libfreeswan/addrtot.c
@@ -0,0 +1,302 @@
+/*
+ * addresses to text
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: addrtot.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#define IP4BYTES 4 /* bytes in an IPv4 address */
+#define PERBYTE 4 /* three digits plus a dot or NUL */
+#define IP6BYTES 16 /* bytes in an IPv6 address */
+
+/* forwards */
+static size_t normal4(const unsigned char *s, size_t len, char *b, char **dp);
+static size_t normal6(const unsigned char *s, size_t len, char *b, char **dp, int squish);
+static size_t reverse4(const unsigned char *s, size_t len, char *b, char **dp);
+static size_t reverse6(const unsigned char *s, size_t len, char *b, char **dp);
+
+/*
+ - addrtot - convert binary address to text (dotted decimal or IPv6 string)
+ */
+size_t /* space needed for full conversion */
+addrtot(src, format, dst, dstlen)
+const ip_address *src;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ const unsigned char *b;
+ size_t n;
+ char buf[1+ADDRTOT_BUF+1]; /* :address: */
+ char *p;
+ int t = addrtypeof(src);
+# define TF(t, f) (((t)<<8) | (f))
+
+ n = addrbytesptr(src, &b);
+ if (n == 0)
+ return 0;
+
+ switch (TF(t, format)) {
+ case TF(AF_INET, 0):
+ n = normal4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 0):
+ n = normal6(b, n, buf, &p, 1);
+ break;
+ case TF(AF_INET, 'Q'):
+ n = normal4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 'Q'):
+ n = normal6(b, n, buf, &p, 0);
+ break;
+ case TF(AF_INET, 'r'):
+ n = reverse4(b, n, buf, &p);
+ break;
+ case TF(AF_INET6, 'r'):
+ n = reverse6(b, n, buf, &p);
+ break;
+ default: /* including (AF_INET, 'R') */
+ return 0;
+ break;
+ }
+
+ if (dstlen > 0) {
+ if (dstlen < n)
+ p[dstlen - 1] = '\0';
+ strcpy(dst, p);
+ }
+ return n;
+}
+
+/*
+ - normal4 - normal IPv4 address-text conversion
+ */
+static size_t /* size of text, including NUL */
+normal4(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ char *p;
+
+ if (srclen != IP4BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = 0; i < IP4BYTES; i++) {
+ p += ultot(srcp[i], 10, p, PERBYTE);
+ if (i != IP4BYTES - 1)
+ *(p-1) = '.'; /* overwrites the NUL */
+ }
+ *dstp = buf;
+ return p - buf;
+}
+
+/*
+ - normal6 - normal IPv6 address-text conversion
+ */
+static size_t /* size of text, including NUL */
+normal6(srcp, srclen, buf, dstp, squish)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough, plus 2 */
+char **dstp; /* where to put result pointer */
+int squish; /* whether to squish out 0:0 */
+{
+ int i;
+ unsigned long piece;
+ char *p;
+ char *q;
+
+ if (srclen != IP6BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ *p++ = ':';
+ for (i = 0; i < IP6BYTES/2; i++) {
+ piece = (srcp[2*i] << 8) + srcp[2*i + 1];
+ p += ultot(piece, 16, p, 5); /* 5 = abcd + NUL */
+ *(p-1) = ':'; /* overwrites the NUL */
+ }
+ *p = '\0';
+ q = strstr(buf, ":0:0:");
+ if (squish && q != NULL) { /* zero squishing is possible */
+ p = q + 1;
+ while (*p == '0' && *(p+1) == ':')
+ p += 2;
+ q++;
+ *q++ = ':'; /* overwrite first 0 */
+ while (*p != '\0')
+ *q++ = *p++;
+ *q = '\0';
+ if (!(*(q-1) == ':' && *(q-2) == ':'))
+ *--q = '\0'; /* strip final : unless :: */
+ p = buf;
+ if (!(*p == ':' && *(p+1) == ':'))
+ p++; /* skip initial : unless :: */
+ } else {
+ q = p;
+ *--q = '\0'; /* strip final : */
+ p = buf + 1; /* skip initial : */
+ }
+ *dstp = p;
+ return q - p + 1;
+}
+
+/*
+ - reverse4 - IPv4 reverse-lookup conversion
+ */
+static size_t /* size of text, including NUL */
+reverse4(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ char *p;
+
+ if (srclen != IP4BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = IP4BYTES-1; i >= 0; i--) {
+ p += ultot(srcp[i], 10, p, PERBYTE);
+ *(p-1) = '.'; /* overwrites the NUL */
+ }
+ strcpy(p, "IN-ADDR.ARPA.");
+ *dstp = buf;
+ return strlen(buf) + 1;
+}
+
+/*
+ - reverse6 - IPv6 reverse-lookup conversion (RFC 1886)
+ * A trifle inefficient, really shouldn't use ultot...
+ */
+static size_t /* size of text, including NUL */
+reverse6(srcp, srclen, buf, dstp)
+const unsigned char *srcp;
+size_t srclen;
+char *buf; /* guaranteed large enough */
+char **dstp; /* where to put result pointer */
+{
+ int i;
+ unsigned long piece;
+ char *p;
+
+ if (srclen != IP6BYTES) /* "can't happen" */
+ return 0;
+ p = buf;
+ for (i = IP6BYTES-1; i >= 0; i--) {
+ piece = srcp[i];
+ p += ultot(piece&0xf, 16, p, 2);
+ *(p-1) = '.';
+ p += ultot(piece>>4, 16, p, 2);
+ *(p-1) = '.';
+ }
+ strcpy(p, "IP6.ARPA.");
+ *dstp = buf;
+ return strlen(buf) + 1;
+}
+
+/*
+ - reverse6 - modern IPv6 reverse-lookup conversion (RFC 2874)
+ * this version removed as it was obsoleted in the end.
+ */
+
+#ifdef ADDRTOT_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
+ argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char format;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0", 0, "1.2.3.0"},
+ {"1:2::3:4", 0, "1:2::3:4"},
+ {"1:2::3:4", 'Q', "1:2:0:0:0:0:3:4"},
+ {"1:2:0:0:3:4:0:0", 0, "1:2::3:4:0:0"},
+ {"1.2.3.4", 'r' , "4.3.2.1.IN-ADDR.ARPA."},
+ /* 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 a b c d e f */
+ {"1:2::3:4", 'r', "4.0.0.0.3.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.0.0.1.0.0.0.IP6.ARPA."},
+ {NULL, 0, NULL}
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ ip_address a;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+
+ /* convert it *to* internal format */
+ oops = ttoaddr(in, strlen(in), 0, &a);
+
+ /* now convert it back */
+
+ n = addrtot(&a, r->format, buf, sizeof(buf));
+
+ if (n == 0 && r->output == NULL)
+ {} /* okay, error expected */
+
+ else if (n == 0) {
+ printf("`%s' atoasr failed\n", r->input);
+ status = 1;
+
+ } else if (r->output == NULL) {
+ printf("`%s' atoasr succeeded unexpectedly '%c'\n",
+ r->input, r->format);
+ status = 1;
+ } else {
+ if (strcasecmp(r->output, buf) != 0) {
+ printf("`%s' '%c' gave `%s', expected `%s'\n",
+ r->input, r->format, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ADDRTOT_MAIN */
diff --git a/linux/lib/libfreeswan/addrtypeof.c b/linux/lib/libfreeswan/addrtypeof.c
new file mode 100644
index 000000000..e63509911
--- /dev/null
+++ b/linux/lib/libfreeswan/addrtypeof.c
@@ -0,0 +1,94 @@
+/*
+ * extract parts of an ip_address
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: addrtypeof.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - addrtypeof - get the type of an ip_address
+ */
+int
+addrtypeof(src)
+const ip_address *src;
+{
+ return src->u.v4.sin_family;
+}
+
+/*
+ - addrbytesptr - get pointer to the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrbytesptr(src, dstp)
+const ip_address *src;
+const unsigned char **dstp; /* NULL means just a size query */
+{
+ const unsigned char *p;
+ size_t n;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ p = (const unsigned char *)&src->u.v4.sin_addr.s_addr;
+ n = 4;
+ break;
+ case AF_INET6:
+ p = (const unsigned char *)&src->u.v6.sin6_addr;
+ n = 16;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ if (dstp != NULL)
+ *dstp = p;
+ return n;
+}
+
+/*
+ - addrlenof - get length of the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrlenof(src)
+const ip_address *src;
+{
+ return addrbytesptr(src, NULL);
+}
+
+/*
+ - addrbytesof - get the address bytes of an ip_address
+ */
+size_t /* 0 for error */
+addrbytesof(src, dst, dstlen)
+const ip_address *src;
+unsigned char *dst;
+size_t dstlen;
+{
+ const unsigned char *p;
+ size_t n;
+ size_t ncopy;
+
+ n = addrbytesptr(src, &p);
+ if (n == 0)
+ return 0;
+
+ if (dstlen > 0) {
+ ncopy = n;
+ if (ncopy > dstlen)
+ ncopy = dstlen;
+ memcpy(dst, p, ncopy);
+ }
+ return n;
+}
diff --git a/linux/lib/libfreeswan/anyaddr.3 b/linux/lib/libfreeswan/anyaddr.3
new file mode 100644
index 000000000..4594a9ff9
--- /dev/null
+++ b/linux/lib/libfreeswan/anyaddr.3
@@ -0,0 +1,87 @@
+.TH IPSEC_ANYADDR 3 "8 Sept 2000"
+.\" RCSID $Id: anyaddr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec anyaddr \- get "any" address
+.br
+ipsec isanyaddr \- test address for equality to "any" address
+.br
+ipsec unspecaddr \- get "unspecified" address
+.br
+ipsec isunspecaddr \- test address for equality to "unspecified" address
+.br
+ipsec loopbackaddr \- get loopback address
+.br
+ipsec isloopbackaddr \- test address for equality to loopback address
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *anyaddr(int af, ip_address *dst);"
+.br
+.B "int isanyaddr(const ip_address *src);"
+.br
+.B "const char *unspecaddr(int af, ip_address *dst);"
+.br
+.B "int isunspecaddr(const ip_address *src);"
+.br
+.B "const char *loopbackaddr(int af, ip_address *dst);"
+.br
+.B "int isloopbackaddr(const ip_address *src);"
+.SH DESCRIPTION
+These functions fill in, and test for, special values of the
+.I ip_address
+type.
+.PP
+.I Anyaddr
+fills in the destination
+.I *dst
+with the ``any'' address of address family
+.IR af
+(normally
+.B AF_INET
+or
+.BR AF_INET6 ).
+The IPv4 ``any'' address is the one embodied in the old
+.B INADDR_ANY
+macro.
+.PP
+.I Isanyaddr
+returns
+.B 1
+if the
+.I src
+address equals the ``any'' address,
+and
+.B 0
+otherwise.
+.PP
+Similarly,
+.I unspecaddr
+supplies, and
+.I isunspecaddr
+tests for,
+the ``unspecified'' address,
+which may be the same as the ``any'' address.
+.PP
+Similarly,
+.I loopbackaddr
+supplies, and
+.I islookbackaddr
+tests for,
+the loopback address.
+.PP
+.IR Anyaddr ,
+.IR unspecaddr ,
+and
+.I loopbackaddr
+return
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.SH SEE ALSO
+inet(3), ipsec_addrtot(3), ipsec_sameaddr(3)
+.SH DIAGNOSTICS
+Fatal errors in the address-supplying functions are:
+unknown address family.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/anyaddr.c b/linux/lib/libfreeswan/anyaddr.c
new file mode 100644
index 000000000..08aae6334
--- /dev/null
+++ b/linux/lib/libfreeswan/anyaddr.c
@@ -0,0 +1,146 @@
+/*
+ * special addresses
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: anyaddr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/* these are mostly fallbacks for the no-IPv6-support-in-library case */
+#ifndef IN6ADDR_ANY_INIT
+#define IN6ADDR_ANY_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}
+#endif
+#ifndef IN6ADDR_LOOPBACK_INIT
+#define IN6ADDR_LOOPBACK_INIT {{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }}
+#endif
+
+static struct in6_addr v6any = IN6ADDR_ANY_INIT;
+static struct in6_addr v6loop = IN6ADDR_LOOPBACK_INIT;
+
+/*
+ - anyaddr - initialize to the any-address value
+ */
+err_t /* NULL for success, else string literal */
+anyaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ uint32_t v4any = htonl(INADDR_ANY);
+
+ switch (af) {
+ case AF_INET:
+ return initaddr((unsigned char *)&v4any, sizeof(v4any), af, dst);
+ break;
+ case AF_INET6:
+ return initaddr((unsigned char *)&v6any, sizeof(v6any), af, dst);
+ break;
+ default:
+ return "unknown address family in anyaddr/unspecaddr";
+ break;
+ }
+}
+
+/*
+ - unspecaddr - initialize to the unspecified-address value
+ */
+err_t /* NULL for success, else string literal */
+unspecaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ return anyaddr(af, dst);
+}
+
+/*
+ - loopbackaddr - initialize to the loopback-address value
+ */
+err_t /* NULL for success, else string literal */
+loopbackaddr(af, dst)
+int af; /* address family */
+ip_address *dst;
+{
+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
+
+ switch (af) {
+ case AF_INET:
+ return initaddr((unsigned char *)&v4loop, sizeof(v4loop), af, dst);
+ break;
+ case AF_INET6:
+ return initaddr((unsigned char *)&v6loop, sizeof(v6loop), af, dst);
+ break;
+ default:
+ return "unknown address family in loopbackaddr";
+ break;
+ }
+}
+
+/*
+ - isanyaddr - test for the any-address value
+ */
+int
+isanyaddr(src)
+const ip_address *src;
+{
+ uint32_t v4any = htonl(INADDR_ANY);
+ int cmp;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4any, sizeof(v4any));
+ break;
+ case AF_INET6:
+ cmp = memcmp(&src->u.v6.sin6_addr, &v6any, sizeof(v6any));
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return (cmp == 0) ? 1 : 0;
+}
+
+/*
+ - isunspecaddr - test for the unspecified-address value
+ */
+int
+isunspecaddr(src)
+const ip_address *src;
+{
+ return isanyaddr(src);
+}
+
+/*
+ - isloopbackaddr - test for the loopback-address value
+ */
+int
+isloopbackaddr(src)
+const ip_address *src;
+{
+ uint32_t v4loop = htonl(INADDR_LOOPBACK);
+ int cmp;
+
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ cmp = memcmp(&src->u.v4.sin_addr.s_addr, &v4loop, sizeof(v4loop));
+ break;
+ case AF_INET6:
+ cmp = memcmp(&src->u.v6.sin6_addr, &v6loop, sizeof(v6loop));
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return (cmp == 0) ? 1 : 0;
+}
diff --git a/linux/lib/libfreeswan/atoaddr.3 b/linux/lib/libfreeswan/atoaddr.3
new file mode 100644
index 000000000..a7dc8dca3
--- /dev/null
+++ b/linux/lib/libfreeswan/atoaddr.3
@@ -0,0 +1,294 @@
+.TH IPSEC_ATOADDR 3 "11 June 2001"
+.\" RCSID $Id: atoaddr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec atoaddr, addrtoa \- convert Internet addresses to and from ASCII
+.br
+ipsec atosubnet, subnettoa \- convert subnet/mask ASCII form to and from addresses
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "struct in_addr *addr);"
+.br
+.B "size_t addrtoa(struct in_addr addr, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "const char *atosubnet(const char *src, size_t srclen,"
+.ti +1c
+.B "struct in_addr *addr, struct in_addr *mask);"
+.br
+.B "size_t subnettoa(struct in_addr addr, struct in_addr mask,"
+.ti +1c
+.B "int format, char *dst, size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttoaddr (3)
+for their replacements.
+.PP
+.I Atoaddr
+converts an ASCII name or dotted-decimal address into a binary address
+(in network byte order).
+.I Addrtoa
+does the reverse conversion, back to an ASCII dotted-decimal address.
+.I Atosubnet
+and
+.I subnettoa
+do likewise for the ``address/mask'' ASCII form used to write a
+specification of a subnet.
+.PP
+An address is specified in ASCII as a
+dotted-decimal address (e.g.
+.BR 1.2.3.4 ),
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+.BR 0x01020304 ,
+which is synonymous with
+.BR 1.2.3.4 ),
+an eight-digit host-order hexadecimal number with a
+.B 0h
+prefix (e.g.
+.BR 0h01020304 ,
+which is synonymous with
+.B 1.2.3.4
+on a big-endian host and
+.B 4.3.2.1
+on a little-endian host),
+a DNS name to be looked up via
+.IR gethostbyname (3),
+or an old-style network name to be looked up via
+.IR getnetbyname (3).
+.PP
+A dotted-decimal address may be incomplete, in which case
+ASCII-to-binary conversion implicitly appends
+as many instances of
+.B .0
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+.B 10
+is synonymous with
+.BR 10.0.0.0 ,
+and
+.B 128.009.000.032
+is synonymous with
+.BR 128.9.0.32
+(the latter example is verbatim from RFC 1166).
+The result of
+.I addrtoa
+is always complete and does not contain leading zeros.
+.PP
+The letters in
+a hexadecimal address may be uppercase or lowercase or any mixture thereof.
+Use of hexadecimal addresses is
+.B strongly
+.BR discouraged ;
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+.PP
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+.IR resolver (5)).
+The
+.I h_addr
+value returned by
+.IR gethostbyname (3)
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+Name lookup resorts to
+.IR getnetbyname (3)
+only if
+.IR gethostbyname (3)
+fails.
+.PP
+A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+The
+.I network
+and
+.I mask
+can be any form acceptable to
+.IR atoaddr .
+In addition, the
+.I mask
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+.B 24
+means
+.BR 255.255.255.0 ).
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+.B %default
+is a synonym for
+.BR 0.0.0.0/0 .
+.PP
+.I Atosubnet
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+.B 10.1.2.3/24
+is synonymous with
+.BR 10.1.2.0/24 ).
+.I Subnettoa
+generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros,
+unless the mask is non-contiguous.
+.PP
+The
+.I srclen
+parameter of
+.I atoaddr
+and
+.I atosubnet
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I addrtoa
+and
+.I subnettoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines constants,
+.B ADDRTOA_BUF
+and
+.BR SUBNETTOA_BUF ,
+which are the sizes of buffers just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I addrtoa
+and
+.I subnettoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+.PP
+The ASCII-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-ASCII functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoaddr
+are:
+empty input;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal form;
+dotted-decimal component too large to fit in 8 bits.
+.PP
+Fatal errors in
+.I atosubnet
+are:
+no
+.B /
+in
+.IR src ;
+.I atoaddr
+error in conversion of
+.I network
+or
+.IR mask ;
+bit-count mask too big;
+mask non-contiguous.
+.PP
+Fatal errors in
+.I addrtoa
+and
+.I subnettoa
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+.B 10/24
+means
+.BR 10.0.0.0/24 )
+differs from that of some older conversion
+functions, e.g. those of
+.IR inet (3).
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+.PP
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+.PP
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+.PP
+.IR Getnetbyname (3)
+is a historical dreg.
+.PP
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atoaddr.c b/linux/lib/libfreeswan/atoaddr.c
new file mode 100644
index 000000000..0c787b10d
--- /dev/null
+++ b/linux/lib/libfreeswan/atoaddr.c
@@ -0,0 +1,238 @@
+/*
+ * conversion from ASCII forms of addresses to internal ones
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atoaddr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * Define NOLEADINGZEROS to interpret 032 as an error, not as 32. There
+ * is deliberately no way to interpret it as 26 (i.e., as octal).
+ */
+
+/*
+ * Legal characters in a domain name. Underscore technically is not,
+ * but is a common misunderstanding.
+ */
+static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
+
+static const char *try8hex(const char *, size_t, struct in_addr *);
+static const char *try8hosthex(const char *, size_t, struct in_addr *);
+static const char *trydotted(const char *, size_t, struct in_addr *);
+static const char *getbyte(const char **, const char *, int *);
+
+/*
+ - atoaddr - convert ASCII name or dotted-decimal address to binary address
+ */
+const char * /* NULL for success, else string literal */
+atoaddr(src, srclen, addrp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct in_addr *addrp;
+{
+ struct hostent *h;
+ struct netent *ne = NULL;
+ const char *oops;
+# define HEXLEN 10 /* strlen("0x11223344") */
+# ifndef ATOADDRBUF
+# define ATOADDRBUF 100
+# endif
+ char namebuf[ATOADDRBUF];
+ char *p = namebuf;
+ char *q;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ /* might it be hex? */
+ if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'x'))
+ return try8hex(src+2, srclen-2, addrp);
+ if (srclen == HEXLEN && *src == '0' && CIEQ(*(src+1), 'h'))
+ return try8hosthex(src+2, srclen-2, addrp);
+
+ /* try it as dotted decimal */
+ oops = trydotted(src, srclen, addrp);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* it *was* probably meant as a d.q. */
+
+ /* try it as a name -- first, NUL-terminate it */
+ if (srclen > sizeof(namebuf)-1) {
+ p = (char *) MALLOC(srclen+1);
+ if (p == NULL)
+ return "unable to allocate temporary space for name";
+ }
+ p[0] = '\0';
+ strncat(p, src, srclen);
+
+ /* next, check that it's a vaguely legal name */
+ for (q = p; *q != '\0'; q++)
+ if (!isprint(*q))
+ return "unprintable character in name";
+ if (strspn(p, namechars) != srclen)
+ return "illegal (non-DNS-name) character in name";
+
+ /* try as host name, failing that as /etc/networks network name */
+ h = gethostbyname(p);
+ if (h == NULL)
+ ne = getnetbyname(p);
+ if (p != namebuf)
+ FREE(p);
+ if (h == NULL && ne == NULL)
+ return "name lookup failed";
+
+ if (h != NULL)
+ memcpy(&addrp->s_addr, h->h_addr, sizeof(addrp->s_addr));
+ else
+ addrp->s_addr = htonl(ne->n_net);
+ return NULL;
+}
+
+/*
+ - try8hosthex - try conversion as an eight-digit host-order hex number
+ */
+const char * /* NULL for success, else string literal */
+try8hosthex(src, srclen, addrp)
+const char *src;
+size_t srclen; /* should be 8 */
+struct in_addr *addrp;
+{
+ const char *oops;
+ unsigned long addr;
+
+ if (srclen != 8)
+ return "internal error, try8hex called with bad length";
+
+ oops = atoul(src, srclen, 16, &addr);
+ if (oops != NULL)
+ return oops;
+
+ addrp->s_addr = addr;
+ return NULL;
+}
+
+/*
+ - try8hex - try conversion as an eight-digit network-order hex number
+ */
+const char * /* NULL for success, else string literal */
+try8hex(src, srclen, addrp)
+const char *src;
+size_t srclen; /* should be 8 */
+struct in_addr *addrp;
+{
+ const char *oops;
+
+ oops = try8hosthex(src, srclen, addrp);
+ if (oops != NULL)
+ return oops;
+
+ addrp->s_addr = htonl(addrp->s_addr);
+ return NULL;
+}
+
+/*
+ - trydotted - try conversion as dotted decimal
+ *
+ * If the first char of a complaint is '?', that means "didn't look like
+ * dotted decimal at all".
+ */
+const char * /* NULL for success, else string literal */
+trydotted(src, srclen, addrp)
+const char *src;
+size_t srclen;
+struct in_addr *addrp;
+{
+ const char *stop = src + srclen; /* just past end */
+ int byte;
+ const char *oops;
+ unsigned long addr;
+ int i;
+# define NBYTES 4
+# define BYTE 8
+
+ addr = 0;
+ for (i = 0; i < NBYTES && src < stop; i++) {
+ oops = getbyte(&src, stop, &byte);
+ if (oops != NULL) {
+ if (*oops != '?')
+ return oops; /* bad number */
+ if (i > 1)
+ return oops+1; /* failed number */
+ return oops; /* with leading '?' */
+ }
+ addr = (addr << BYTE) | byte;
+ if (i < 3 && src < stop && *src++ != '.') {
+ if (i == 0)
+ return "?syntax error in dotted-decimal address";
+ else
+ return "syntax error in dotted-decimal address";
+ }
+ }
+ addr <<= (NBYTES - i) * BYTE;
+ if (src != stop)
+ return "extra garbage on end of dotted-decimal address";
+
+ addrp->s_addr = htonl(addr);
+ return NULL;
+}
+
+/*
+ - getbyte - try to scan a byte in dotted decimal
+ * A subtlety here is that all this arithmetic on ASCII digits really is
+ * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
+ * It's easier to just do it ourselves than set up for a call to atoul().
+ *
+ * If the first char of a complaint is '?', that means "didn't look like a
+ * number at all".
+ */
+const char * /* NULL for success, else string literal */
+getbyte(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+int *retp; /* return-value pointer */
+{
+ char c;
+ const char *p;
+ int no;
+
+ if (*srcp >= stop)
+ return "?empty number in dotted-decimal address";
+
+ if (stop - *srcp >= 3 && **srcp == '0' && CIEQ(*(*srcp+1), 'x'))
+ return "hex numbers not supported in dotted-decimal addresses";
+#ifdef NOLEADINGZEROS
+ if (stop - *srcp >= 2 && **srcp == '0' && isdigit(*(*srcp+1)))
+ return "octal numbers not supported in dotted-decimal addresses";
+#endif /* NOLEADINGZEROS */
+
+ /* must be decimal, if it's numeric at all */
+ no = 0;
+ p = *srcp;
+ while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
+ no = no*10 + (c - '0');
+ p++;
+ }
+ if (p == *srcp)
+ return "?non-numeric component in dotted-decimal address";
+ *srcp = p;
+ if (no > 255)
+ return "byte overflow in dotted-decimal address";
+ *retp = no;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/atoasr.3 b/linux/lib/libfreeswan/atoasr.3
new file mode 100644
index 000000000..1bd805db1
--- /dev/null
+++ b/linux/lib/libfreeswan/atoasr.3
@@ -0,0 +1,186 @@
+.TH IPSEC_ATOASR 3 "11 June 2001"
+.\" RCSID $Id: atoasr.3,v 1.1 2004/03/15 20:35:25 as Exp $
+.SH NAME
+ipsec atoasr \- convert ASCII to Internet address, subnet, or range
+.br
+ipsec rangetoa \- convert Internet address range to ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoasr(const char *src, size_t srclen,"
+.ti +1c
+.B "char *type, struct in_addr *addrs);"
+.br
+.B "size_t rangetoa(struct in_addr *addrs, int format,
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete;
+there is no current equivalent,
+because so far they have not proved useful.
+.PP
+.I Atoasr
+converts an ASCII address, subnet, or address range
+into a suitable combination of binary addresses
+(in network byte order).
+.I Rangetoa
+converts an address range back into ASCII,
+using dotted-decimal form for the addresses
+(the other reverse conversions are handled by
+.IR ipsec_addrtoa (3)
+and
+.IR ipsec_subnettoa (3)).
+.PP
+A single address can be any form acceptable to
+.IR ipsec_atoaddr (3):
+dotted decimal, DNS name, or hexadecimal number.
+A subnet
+specification uses the form \fInetwork\fB/\fImask\fR
+interpreted by
+.IR ipsec_atosubnet (3).
+.PP
+An address range is two
+.IR ipsec_atoaddr (3)
+addresses separated by a
+.B ...
+delimiter.
+If there are four dots rather than three, the first is taken as
+part of the begin address,
+e.g. for a complete DNS name which ends with
+.B .
+to suppress completion attempts.
+The begin address of a range must be
+less than or equal to the end address.
+.PP
+The
+.I srclen
+parameter of
+.I atoasr
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I type
+parameter of
+.I atoasr
+must point to a
+.B char
+variable used to record which form was found.
+The
+.I addrs
+parameter must point to a two-element array of
+.B "struct in_addr"
+which receives the results.
+The values stored into
+.BR *type ,
+and the corresponding values in the array, are:
+.PP
+.ta 3c +2c +3c
+ *type addrs[0] addrs[1]
+.sp 0.8
+address \&\fB'a'\fR address -
+.br
+subnet \&\fB's'\fR network mask
+.br
+range \&\fB'r'\fR begin end
+.PP
+The
+.I dstlen
+parameter of
+.I rangetoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR RANGETOA_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I rangetoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available.
+This parameter is a hedge against future needs.
+.PP
+.I Atoasr
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Rangetoa
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+ipsec_atoaddr(3), ipsec_atosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoasr
+are:
+empty input;
+error in
+.IR ipsec_atoaddr (3)
+or
+.IR ipsec_atosubnet (3)
+during conversion;
+begin address of range exceeds end address.
+.PP
+Fatal errors in
+.I rangetoa
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoasr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atoasr.c b/linux/lib/libfreeswan/atoasr.c
new file mode 100644
index 000000000..a68409bfb
--- /dev/null
+++ b/linux/lib/libfreeswan/atoasr.c
@@ -0,0 +1,212 @@
+/*
+ * convert from ASCII form of address/subnet/range to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atoasr.c,v 1.1 2004/03/15 20:35:25 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - atoasr - convert ASCII to address, subnet, or range
+ */
+const char * /* NULL for success, else string literal */
+atoasr(src, srclen, typep, addrsp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+char *typep; /* return type code: 'a', 's', 'r' */
+struct in_addr addrsp[2];
+{
+ const char *punct;
+ const char *stop;
+ const char *oops;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ /* subnet is easy to spot */
+ punct = memchr(src, '/', srclen);
+ if (punct != NULL) {
+ *typep = 's';
+ return atosubnet(src, srclen, &addrsp[0], &addrsp[1]);
+ }
+
+ /* try for a range */
+ stop = src + srclen;
+ for (punct = src; (punct = memchr(punct, '.', stop - punct)) != NULL;
+ punct++)
+ if (stop - punct > 3 && *(punct+1) == '.' && *(punct+2) == '.')
+ break; /* NOTE BREAK OUT */
+ if (punct == NULL) {
+ /* didn't find the range delimiter, must be plain address */
+ *typep = 'a';
+ return atoaddr(src, srclen, &addrsp[0]);
+ }
+
+ /* looks like a range */
+ *typep = 'r';
+ if (stop - punct > 4 && *(punct+3) == '.')
+ punct++; /* first dot is trailing dot of name */
+ oops = atoaddr(src, punct - src, &addrsp[0]);
+ if (oops != NULL)
+ return oops;
+ oops = atoaddr(punct+3, stop - (punct+3), &addrsp[1]);
+ if (oops != NULL)
+ return oops;
+ if (ntohl(addrsp[0].s_addr) > ntohl(addrsp[1].s_addr))
+ return "invalid range, begin > end";
+ return NULL;
+}
+
+
+
+#ifdef ATOASR_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct in_addr a[2];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ char type;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr|net/mask|begin...end|-r}\n",
+ argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atoasr(argv[1], 0, &type, a);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ switch (type) {
+ case 'a':
+ n = addrtoa(a[0], 0, buf, sizeof(buf));
+ break;
+ case 's':
+ n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
+ break;
+ case 'r':
+ n = rangetoa(a, 0, buf, sizeof(buf));
+ break;
+ default:
+ fprintf(stderr, "%s: unknown type '%c'\n", argv[0], type);
+ exit(1);
+ break;
+ }
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ fprintf(stderr, "%s ", inet_ntoa(a[0]));
+ fprintf(stderr, "%s", inet_ntoa(a[1]));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0", "1.2.3.0"},
+ {"1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {"1.2.3.0...1.2.3.5", "1.2.3.0...1.2.3.5"},
+ {"1.2.3.4.5", NULL},
+ {"1.2.3.4/", NULL},
+ {"1.2.3.4...", NULL},
+ {"1.2.3.4....", NULL},
+ {"localhost/32", "127.0.0.1/32"},
+ {"localhost...127.0.0.3", "127.0.0.1...127.0.0.3"},
+ {"127.0.0.0...localhost", "127.0.0.0...127.0.0.1"},
+ {"127.0.0.3...localhost", NULL},
+ {NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ struct in_addr a[2];
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ char type;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atoasr(in, 0, &type, a);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atoasr failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atoasr succeeded unexpectedly '%c'\n",
+ r->input, type);
+ status = 1;
+ } else {
+ switch (type) {
+ case 'a':
+ n = addrtoa(a[0], 0, buf, sizeof(buf));
+ break;
+ case 's':
+ n = subnettoa(a[0], a[1], 0, buf, sizeof(buf));
+ break;
+ case 'r':
+ n = rangetoa(a, 0, buf, sizeof(buf));
+ break;
+ default:
+ fprintf(stderr, "`%s' unknown type '%c'\n",
+ r->input, type);
+ n = 0;
+ status = 1;
+ break;
+ }
+ if (n > sizeof(buf)) {
+ printf("`%s' '%c' reverse failed: need %ld\n",
+ r->input, type, (long)n);
+ status = 1;
+ } else if (n > 0 && strcmp(r->output, buf) != 0) {
+ printf("`%s' '%c' gave `%s', expected `%s'\n",
+ r->input, type, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOASR_MAIN */
diff --git a/linux/lib/libfreeswan/atosa.3 b/linux/lib/libfreeswan/atosa.3
new file mode 100644
index 000000000..116483a73
--- /dev/null
+++ b/linux/lib/libfreeswan/atosa.3
@@ -0,0 +1,218 @@
+.TH IPSEC_ATOSA 3 "11 June 2001"
+.\" RCSID $Id: atosa.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec atosa, satoa \- convert IPsec Security Association IDs to and from ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atosa(const char *src, size_t srclen,"
+.ti +1c
+.B "struct sa_id *sa);
+.br
+.B "size_t satoa(struct sa_id sa, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "struct sa_id {"
+.ti +1c
+.B "struct in_addr dst;"
+.ti +1c
+.B "ipsec_spi_t spi;"
+.ti +1c
+.B "int proto;"
+.br
+.B "};"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttosa (3)
+for their replacements.
+.PP
+.I Atosa
+converts an ASCII Security Association (SA) specifier into an
+.B sa_id
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+.I Satoa
+does the reverse conversion, back to an ASCII SA specifier.
+.PP
+An SA is specified in ASCII with a mail-like syntax, e.g.
+.BR esp507@1.2.3.4 .
+An SA specifier contains
+a protocol prefix (currently
+.BR ah ,
+.BR esp ,
+or
+.BR tun ),
+an unsigned integer SPI number,
+and an IP address.
+The SPI number can be decimal or hexadecimal
+(with
+.B 0x
+prefix), as accepted by
+.IR ipsec_atoul (3).
+The IP address can be any form accepted by
+.IR ipsec_atoaddr (3),
+e.g. dotted-decimal address or DNS name.
+.PP
+As a special case, the SA specifier
+.B %passthrough
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, this is a synonym for
+.BR tun0x0@0.0.0.0 ,
+but that is subject to change without notice.)
+This form is known to both
+.I atosa
+and
+.IR satoa ,
+so the internal form of
+.B %passthrough
+is never visible.
+.PP
+The
+.B <freeswan.h>
+header file supplies the
+.B sa_id
+structure, as well as a data type
+.B ipsec_spi_t
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+.PP
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+.B <freeswan.h>
+defines the names
+.BR SA_ESP ,
+.BR SA_AH ,
+and
+.B SA_IPIP
+to have the same values as the kernel names
+.BR IPPROTO_ESP ,
+.BR IPPROTO_AH ,
+and
+.BR IPPROTO_IPIP .
+.PP
+The
+.I srclen
+parameter of
+.I atosa
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I satoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR SATOA_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I satoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI, dotted-decimal address).
+The value
+.B d
+causes the SPI to be generated in decimal instead.
+.PP
+.I Atosa
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Satoa
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+ipsec_atoul(3), ipsec_atoaddr(3), inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atosa
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+.B @
+in input;
+unknown protocol prefix;
+conversion error in
+.I atoul
+or
+.IR atoaddr .
+.PP
+Fatal errors in
+.I satoa
+are:
+unknown format; unknown protocol code.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The
+.B tun
+protocol code is a FreeS/WANism which may eventually disappear.
+.PP
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atosa.c b/linux/lib/libfreeswan/atosa.c
new file mode 100644
index 000000000..cc3b055d0
--- /dev/null
+++ b/linux/lib/libfreeswan/atosa.c
@@ -0,0 +1,200 @@
+/*
+ * convert from ASCII form of SA ID to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atosa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct satype {
+ char *prefix;
+ size_t prelen; /* strlen(prefix) */
+ int proto;
+} satypes[] = {
+ { "ah", 2, SA_AH },
+ { "esp", 3, SA_ESP },
+ { "tun", 3, SA_IPIP },
+ { "comp", 4, SA_COMP },
+ { NULL, 0, 0, }
+};
+
+/*
+ - atosa - convert ASCII "ah507@10.0.0.1" to SA identifier
+ */
+const char * /* NULL for success, else string literal */
+atosa(src, srclen, sa)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct sa_id *sa;
+{
+ const char *at;
+ const char *addr;
+ const char *spi = NULL;
+ struct satype *sat;
+ unsigned long ul;
+ const char *oops;
+# define MINLEN 5 /* ah0@0 is as short as it can get */
+ static char ptname[] = PASSTHROUGHNAME;
+# define PTNLEN (sizeof(ptname)-1) /* -1 for NUL */
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ if (srclen < MINLEN)
+ return "string too short to be SA specifier";
+ if (srclen == PTNLEN && memcmp(src, ptname, PTNLEN) == 0) {
+ src = PASSTHROUGHIS;
+ srclen = strlen(src);
+ }
+
+ at = memchr(src, '@', srclen);
+ if (at == NULL)
+ return "no @ in SA specifier";
+
+ for (sat = satypes; sat->prefix != NULL; sat++)
+ if (sat->prelen < srclen &&
+ strncmp(src, sat->prefix, sat->prelen) == 0) {
+ sa->proto = sat->proto;
+ spi = src + sat->prelen;
+ break; /* NOTE BREAK OUT */
+ }
+ if (sat->prefix == NULL)
+ return "SA specifier lacks valid protocol prefix";
+
+ if (spi >= at)
+ return "no SPI in SA specifier";
+ oops = atoul(spi, at - spi, 13, &ul);
+ if (oops != NULL)
+ return oops;
+ sa->spi = htonl(ul);
+
+ addr = at + 1;
+ oops = atoaddr(addr, srclen - (addr - src), &sa->dst);
+ if (oops != NULL)
+ return oops;
+
+ return NULL;
+}
+
+
+
+#ifdef ATOSA_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct sa_id sa;
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atosa(argv[1], 0, &sa);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = satoa(sa, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
+ fprintf(stderr, "%lu@", (long unsigned int)sa.spi);
+ fprintf(stderr, "%s", inet_ntoa(sa.dst));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"esp257@1.2.3.0", "esp257@1.2.3.0"},
+ {"ah0x20@1.2.3.4", "ah32@1.2.3.4"},
+ {"tun011@111.2.3.99", "tun11@111.2.3.99"},
+ {"", NULL},
+ {"_", NULL},
+ {"ah2.2", NULL},
+ {"goo2@1.2.3.4", NULL},
+ {"esp9@1.2.3.4", "esp9@1.2.3.4"},
+ {"espp9@1.2.3.4", NULL},
+ {"es9@1.2.3.4", NULL},
+ {"ah@1.2.3.4", NULL},
+ {"esp7x7@1.2.3.4", NULL},
+ {"esp77@1.0x2.3.4", NULL},
+ {PASSTHROUGHNAME, PASSTHROUGHNAME},
+ {NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ struct sa_id sa;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atosa(in, 0, &sa);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atosa failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atosa succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = satoa(sa, 'd', buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' satoa failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOSA_MAIN */
diff --git a/linux/lib/libfreeswan/atosubnet.c b/linux/lib/libfreeswan/atosubnet.c
new file mode 100644
index 000000000..9300c2895
--- /dev/null
+++ b/linux/lib/libfreeswan/atosubnet.c
@@ -0,0 +1,216 @@
+/*
+ * convert from ASCII form of subnet specification to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#ifndef DEFAULTSUBNET
+#define DEFAULTSUBNET "%default"
+#endif
+
+/*
+ - atosubnet - convert ASCII "addr/mask" to address and mask
+ * Mask can be integer bit count.
+ */
+const char * /* NULL for success, else string literal */
+atosubnet(src, srclen, addrp, maskp)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct in_addr *addrp;
+struct in_addr *maskp;
+{
+ const char *slash;
+ const char *mask;
+ size_t mlen;
+ const char *oops;
+ unsigned long bc;
+ static char def[] = DEFAULTSUBNET;
+# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */
+ static char defis[] = "0/0";
+# define DEFILEN (sizeof(defis) - 1)
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) {
+ src = defis;
+ srclen = DEFILEN;
+ }
+
+ slash = memchr(src, '/', srclen);
+ if (slash == NULL)
+ return "no / in subnet specification";
+ mask = slash + 1;
+ mlen = srclen - (mask - src);
+
+ oops = atoaddr(src, slash-src, addrp);
+ if (oops != NULL)
+ return oops;
+
+ oops = atoul(mask, mlen, 10, &bc);
+ if (oops == NULL) {
+ /* atoul succeeded, it's a bit-count mask */
+ if (bc > ABITS)
+ return "bit-count mask too large";
+#ifdef NOLEADINGZEROS
+ if (mlen > 1 && *mask == '0')
+ return "octal not allowed in mask";
+#endif /* NOLEADINGZEROS */
+ *maskp = bitstomask((int)bc);
+ } else {
+ oops = atoaddr(mask, mlen, maskp);
+ if (oops != NULL)
+ return oops;
+ if (!goodmask(*maskp))
+ return "non-contiguous mask";
+ }
+
+ addrp->s_addr &= maskp->s_addr;
+ return NULL;
+}
+
+
+
+#ifdef ATOSUBNET_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct in_addr a;
+ struct in_addr m;
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {addr/mask|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atosubnet(argv[1], 0, &a, &m);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettoa(a, m, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ fprintf(stderr, "%s/", inet_ntoa(a));
+ fprintf(stderr, "%s", inet_ntoa(m));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {"1.2.3.0/24", "1.2.3.0/24"},
+ {"1.2.3.1/255.255.255.240", "1.2.3.0/28"},
+ {"1.2.3.1/32", "1.2.3.1/32"},
+ {"1.2.3.1/0", "0.0.0.0/0"},
+/* "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0", */
+ {"1.2.3.1/255.255.127.0", NULL},
+ {"128.009.000.032/32", "128.9.0.32/32"},
+ {"128.0x9.0.32/32", NULL},
+ {"0x80090020/32", "128.9.0.32/32"},
+ {"0x800x0020/32", NULL},
+ {"128.9.0.32/0xffFF0000", "128.9.0.0/16"},
+ {"128.9.0.32/0xff0000FF", NULL},
+ {"128.9.0.32/0x0000ffFF", NULL},
+ {"128.9.0.32/0x00ffFF0000", NULL},
+ {"128.9.0.32/0xffFF", NULL},
+ {"128.9.0.32.27/32", NULL},
+ {"128.9.0k32/32", NULL},
+ {"328.9.0.32/32", NULL},
+ {"128.9..32/32", NULL},
+ {"10/8", "10.0.0.0/8"},
+ {"10.0/8", "10.0.0.0/8"},
+ {"10.0.0/8", "10.0.0.0/8"},
+ {"10.0.1/24", "10.0.1.0/24"},
+ {"_", NULL},
+ {"_/_", NULL},
+ {"1.2.3.1", NULL},
+ {"1.2.3.1/_", NULL},
+ {"1.2.3.1/24._", NULL},
+ {"1.2.3.1/99", NULL},
+ {"localhost/32", "127.0.0.1/32"},
+ {"%default", "0.0.0.0/0"},
+ {NULL, NULL}
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ struct in_addr a;
+ struct in_addr m;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atosubnet(in, 0, &a, &m);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atosubnet failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atosubnet succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = subnettoa(a, m, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' subnettoa failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOSUBNET_MAIN */
diff --git a/linux/lib/libfreeswan/atoul.3 b/linux/lib/libfreeswan/atoul.3
new file mode 100644
index 000000000..a606fa4a9
--- /dev/null
+++ b/linux/lib/libfreeswan/atoul.3
@@ -0,0 +1,161 @@
+.TH IPSEC_ATOUL 3 "11 June 2001"
+.\" RCSID $Id: atoul.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec atoul, ultoa \- convert unsigned-long numbers to and from ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atoul(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, unsigned long *n);"
+.br
+.B "size_t ultoa(unsigned long n, int base, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttoul (3)
+for their replacements.
+.PP
+.I Atoul
+converts an ASCII number into a binary
+.B "unsigned long"
+value.
+.I Ultoa
+does the reverse conversion, back to an ASCII version.
+.PP
+Numbers are specified in ASCII as
+decimal (e.g.
+.BR 123 ),
+octal with a leading zero (e.g.
+.BR 012 ,
+which has value 10),
+or hexadecimal with a leading
+.B 0x
+(e.g.
+.BR 0x1f ,
+which has value 31)
+in either upper or lower case.
+.PP
+The
+.I srclen
+parameter of
+.I atoul
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I base
+parameter of
+.I atoul
+can be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 ,
+in which case the number supplied is assumed to be of that form
+(and in the case of
+.BR 16 ,
+to lack any
+.B 0x
+prefix).
+It can also be
+.BR 0 ,
+in which case the number is examined for a leading zero
+or a leading
+.B 0x
+to determine its base,
+or
+.B 13
+(halfway between 10 and 16),
+which has the same effect as
+.B 0
+except that a non-hexadecimal
+number is considered decimal regardless of any leading zero.
+.PP
+The
+.I dstlen
+parameter of
+.I ultoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+.PP
+The
+.I base
+parameter of
+.I ultoa
+must be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 .
+.PP
+.I Atoul
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Ultoa
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+atol(3), strtoul(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atoul
+are:
+empty input;
+unknown
+.IR base ;
+non-digit character found;
+number too large for an
+.BR "unsigned long" .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+There is no provision for reporting an invalid
+.I base
+parameter given to
+.IR ultoa .
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoul( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/atoul.c b/linux/lib/libfreeswan/atoul.c
new file mode 100644
index 000000000..e32a8cdab
--- /dev/null
+++ b/linux/lib/libfreeswan/atoul.c
@@ -0,0 +1,90 @@
+/*
+ * convert from ASCII form of unsigned long to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: atoul.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - atoul - convert ASCII substring to unsigned long number
+ */
+const char * /* NULL for success, else string literal */
+atoul(src, srclen, base, resultp)
+const char *src;
+size_t srclen; /* 0 means strlen(src) */
+int base; /* 0 means figure it out */
+unsigned long *resultp;
+{
+ const char *stop;
+ static char hex[] = "0123456789abcdef";
+ static char uchex[] = "0123456789ABCDEF";
+ int d;
+ char c;
+ char *p;
+ unsigned long r;
+ unsigned long rlimit;
+ int dlimit;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (base == 0 || base == 13) {
+ if (srclen > 2 && *src == '0' && CIEQ(*(src+1), 'x'))
+ return atoul(src+2, srclen-2, 16, resultp);
+ if (srclen > 1 && *src == '0' && base != 13)
+ return atoul(src+1, srclen-1, 8, resultp);
+ return atoul(src, srclen, 10, resultp);
+ }
+ if (base != 8 && base != 10 && base != 16)
+ return "unsupported number base";
+
+ r = 0;
+ stop = src + srclen;
+ if (base == 16) {
+ while (src < stop) {
+ c = *src++;
+ p = strchr(hex, c);
+ if (p != NULL)
+ d = p - hex;
+ else {
+ p = strchr(uchex, c);
+ if (p == NULL)
+ return "non-hex-digit in hex number";
+ d = p - uchex;
+ }
+ r = (r << 4) | d;
+ }
+ /* defer length check to catch invalid digits first */
+ if (srclen > sizeof(unsigned long) * 2)
+ return "hex number too long";
+ } else {
+ rlimit = ULONG_MAX / base;
+ dlimit = (int)(ULONG_MAX - rlimit*base);
+ while (src < stop) {
+ c = *src++;
+ d = c - '0';
+ if (d < 0 || d >= base)
+ return "non-digit in number";
+ if (r > rlimit || (r == rlimit && d > dlimit))
+ return "unsigned-long overflow";
+ r = r*base + d;
+ }
+ }
+
+ *resultp = r;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/copyright.c b/linux/lib/libfreeswan/copyright.c
new file mode 100644
index 000000000..0e836f6c2
--- /dev/null
+++ b/linux/lib/libfreeswan/copyright.c
@@ -0,0 +1,56 @@
+/*
+ * return IPsec copyright notice
+ * Copyright (C) 2001, 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: copyright.c,v 1.6 2005/11/02 21:51:13 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static const char *co[] = {
+ "Copyright (C) 1999-2005 Henry Spencer, Richard Guy Briggs,",
+ " D. Hugh Redelmeier, Sandy Harris, Claudia Schmeing,",
+ " Michael Richardson, Angelos D. Keromytis, John Ioannidis,",
+ "",
+ " Ken Bantoft, Stephen J. Bevan, JuanJo Ciarlante, Mathieu Lafon,",
+ " Stephane Laroche, Kai Martius, Tuomo Soini, Herbert Xu,",
+ "",
+ " Andreas Steffen, Martin Berner, Marco Bertossa, David Buechi,",
+ " Ueli Galizzi, Christoph Gysin, Andreas Hess, Patric Lichtsteiner,",
+ " Michael Meier, Andreas Schleiss, Ariane Seiler,",
+ " Mario Strasser, Lukas Suter, Roger Wegmann, Simon Zwahlen,",
+ " Zuercher Hochschule Winterthur (Switzerland).",
+ "",
+ " Jan Hutter, Martin Willi, Andreas Steffen,",
+ " Hochschule fuer Technik Rapperswil (Switzerland).",
+ "",
+ "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 the",
+ "Free Software Foundation; either version 2 of the License, or (at your",
+ "option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.",
+ "",
+ "This program is distributed in the hope that it will be useful, but",
+ "WITHOUT ANY WARRANTY; without even the implied warranty of",
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General",
+ "Public License (file COPYING in the distribution) for more details.",
+ NULL
+};
+
+/*
+ - ipsec_copyright_notice - return copyright notice, as a vector of strings
+ */
+const char **
+ipsec_copyright_notice()
+{
+ return co;
+}
diff --git a/linux/lib/libfreeswan/datatot.c b/linux/lib/libfreeswan/datatot.c
new file mode 100644
index 000000000..fbeb35fa9
--- /dev/null
+++ b/linux/lib/libfreeswan/datatot.c
@@ -0,0 +1,233 @@
+/*
+ * convert from binary data (e.g. key) to text form
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: datatot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static void convert(const char *src, size_t nreal, int format, char *out);
+
+/*
+ - datatot - convert data bytes to text
+ */
+size_t /* true length (with NUL) for success */
+datatot(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t inblocksize; /* process this many bytes at a time */
+ size_t outblocksize; /* producing this many */
+ size_t breakevery; /* add a _ every this many (0 means don't) */
+ size_t sincebreak; /* output bytes since last _ */
+ char breakchar; /* character used to break between groups */
+ char inblock[10]; /* enough for any format */
+ char outblock[10]; /* enough for any format */
+ char fake[1]; /* fake output area for dstlen == 0 */
+ size_t needed; /* return value */
+ char *stop; /* where the terminating NUL will go */
+ size_t ntodo; /* remaining input */
+ size_t nreal;
+ char *out;
+ char *prefix;
+
+ breakevery = 0;
+ breakchar = '_';
+
+ switch (format) {
+ case 0:
+ case 'h':
+ format = 'x';
+ breakevery = 8;
+ /* FALLTHROUGH */
+ case 'x':
+ inblocksize = 1;
+ outblocksize = 2;
+ prefix = "0x";
+ break;
+ case ':':
+ format = 'x';
+ breakevery = 2;
+ breakchar = ':';
+ /* FALLTHROUGH */
+ case 16:
+ inblocksize = 1;
+ outblocksize = 2;
+ prefix = "";
+ format = 'x';
+ break;
+ case 's':
+ inblocksize = 3;
+ outblocksize = 4;
+ prefix = "0s";
+ break;
+ case 64: /* beware, equals ' ' */
+ inblocksize = 3;
+ outblocksize = 4;
+ prefix = "";
+ format = 's';
+ break;
+ default:
+ return 0;
+ break;
+ }
+ assert(inblocksize < sizeof(inblock));
+ assert(outblocksize < sizeof(outblock));
+ assert(breakevery % outblocksize == 0);
+
+ if (srclen == 0)
+ return 0;
+ ntodo = srclen;
+
+ if (dstlen == 0) { /* dispose of awkward special case */
+ dst = fake;
+ dstlen = 1;
+ }
+ stop = dst + dstlen - 1;
+
+ nreal = strlen(prefix);
+ needed = nreal; /* for starters */
+ if (dstlen <= nreal) { /* prefix won't fit */
+ strncpy(dst, prefix, dstlen - 1);
+ dst += dstlen - 1;
+ } else {
+ strcpy(dst, prefix);
+ dst += nreal;
+ }
+ assert(dst <= stop);
+ sincebreak = 0;
+
+ while (ntodo > 0) {
+ if (ntodo < inblocksize) { /* incomplete input */
+ memset(inblock, 0, sizeof(inblock));
+ memcpy(inblock, src, ntodo);
+ src = inblock;
+ nreal = ntodo;
+ ntodo = inblocksize;
+ } else
+ nreal = inblocksize;
+ out = (outblocksize > stop - dst) ? outblock : dst;
+
+ convert(src, nreal, format, out);
+ needed += outblocksize;
+ sincebreak += outblocksize;
+ if (dst < stop) {
+ if (out != dst) {
+ assert(outblocksize > stop - dst);
+ memcpy(dst, out, stop - dst);
+ dst = stop;
+ } else
+ dst += outblocksize;
+ }
+
+ src += inblocksize;
+ ntodo -= inblocksize;
+ if (breakevery != 0 && sincebreak >= breakevery && ntodo > 0) {
+ if (dst < stop)
+ *dst++ = breakchar;
+ needed++;
+ sincebreak = 0;
+ }
+ }
+
+ assert(dst <= stop);
+ *dst++ = '\0';
+ needed++;
+
+ return needed;
+}
+
+/*
+ - convert - convert one input block to one output block
+ */
+static void
+convert(src, nreal, format, out)
+const char *src;
+size_t nreal; /* how much of the input block is real */
+int format;
+char *out;
+{
+ static char hex[] = "0123456789abcdef";
+ static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+ unsigned char c;
+ unsigned char c1, c2, c3;
+
+ assert(nreal > 0);
+ switch (format) {
+ case 'x':
+ assert(nreal == 1);
+ c = (unsigned char)*src;
+ *out++ = hex[c >> 4];
+ *out++ = hex[c & 0xf];
+ break;
+ case 's':
+ c1 = (unsigned char)*src++;
+ c2 = (unsigned char)*src++;
+ c3 = (unsigned char)*src++;
+ *out++ = base64[c1 >> 2]; /* top 6 bits of c1 */
+ c = (c1 & 0x3) << 4; /* bottom 2 of c1... */
+ c |= c2 >> 4; /* ...top 4 of c2 */
+ *out++ = base64[c];
+ if (nreal == 1)
+ *out++ = '=';
+ else {
+ c = (c2 & 0xf) << 2; /* bottom 4 of c2... */
+ c |= c3 >> 6; /* ...top 2 of c3 */
+ *out++ = base64[c];
+ }
+ if (nreal <= 2)
+ *out++ = '=';
+ else
+ *out++ = base64[c3 & 0x3f]; /* bottom 6 of c3 */
+ break;
+ default:
+ assert(nreal == 0); /* unknown format */
+ break;
+ }
+}
+
+/*
+ - datatoa - convert data to ASCII
+ * backward-compatibility synonym for datatot
+ */
+size_t /* true length (with NUL) for success */
+datatoa(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ return datatot(src, srclen, format, dst, dstlen);
+}
+
+/*
+ - bytestoa - convert data bytes to ASCII
+ * backward-compatibility synonym for datatot
+ */
+size_t /* true length (with NUL) for success */
+bytestoa(src, srclen, format, dst, dstlen)
+const char *src;
+size_t srclen;
+int format; /* character indicating what format */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ return datatot(src, srclen, format, dst, dstlen);
+}
diff --git a/linux/lib/libfreeswan/goodmask.3 b/linux/lib/libfreeswan/goodmask.3
new file mode 100644
index 000000000..4a573e51e
--- /dev/null
+++ b/linux/lib/libfreeswan/goodmask.3
@@ -0,0 +1,57 @@
+.TH IPSEC_GOODMASK 3 "11 June 2001"
+.\" RCSID $Id: goodmask.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec goodmask \- is this Internet subnet mask a valid one?
+.br
+ipsec masktobits \- convert Internet subnet mask to bit count
+.br
+ipsec bitstomask \- convert bit count to Internet subnet mask
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "int goodmask(struct in_addr mask);"
+.br
+.B "int masktobits(struct in_addr mask);"
+.br
+.B "struct in_addr bitstomask(int n);"
+.SH DESCRIPTION
+These functions are obsolete;
+see
+.IR ipsec_masktocount (3)
+for a partial replacement.
+.PP
+.I Goodmask
+reports whether the subnet
+.I mask
+is a valid one,
+i.e. consists of a (possibly empty) sequence of
+.BR 1 s
+followed by a (possibly empty) sequence of
+.BR 0 s.
+.I Masktobits
+takes a (valid) subnet mask and returns the number of
+.B 1
+bits in it.
+.I Bitstomask
+reverses this,
+returning the subnet mask corresponding to bit count
+.IR n .
+.PP
+All masks are in network byte order.
+.SH SEE ALSO
+inet(3), ipsec_atosubnet(3)
+.SH DIAGNOSTICS
+.I Masktobits
+returns
+.B \-1
+for an invalid mask.
+.I Bitstomask
+returns an all-zeros mask for a negative or out-of-range
+.IR n .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The error-reporting convention of
+.I bitstomask
+is less than ideal;
+zero is sometimes a legitimate mask.
diff --git a/linux/lib/libfreeswan/goodmask.c b/linux/lib/libfreeswan/goodmask.c
new file mode 100644
index 000000000..fe7a42335
--- /dev/null
+++ b/linux/lib/libfreeswan/goodmask.c
@@ -0,0 +1,97 @@
+/*
+ * minor utilities for subnet-mask manipulation
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: goodmask.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - goodmask - is this a good (^1*0*$) subnet mask?
+ * You are not expected to understand this. See Henry S. Warren Jr,
+ * "Functions realizable with word-parallel logical and two's-complement
+ * addition instructions", CACM 20.6 (June 1977), p.439.
+ */
+int /* predicate */
+goodmask(mask)
+struct in_addr mask;
+{
+ unsigned long x = ntohl(mask.s_addr);
+ /* clear rightmost contiguous string of 1-bits */
+# define CRCS1B(x) (((x|(x-1))+1)&x)
+# define TOPBIT (1UL << 31)
+
+ /* either zero, or has one string of 1-bits which is left-justified */
+ if (x == 0 || (CRCS1B(x) == 0 && (x&TOPBIT)))
+ return 1;
+ return 0;
+}
+
+/*
+ - masktobits - how many bits in this mask?
+ * The algorithm is essentially a binary search, but highly optimized
+ * for this particular task.
+ */
+int /* -1 means !goodmask() */
+masktobits(mask)
+struct in_addr mask;
+{
+ unsigned long m = ntohl(mask.s_addr);
+ int masklen;
+
+ if (!goodmask(mask))
+ return -1;
+
+ if (m&0x00000001UL)
+ return 32;
+ masklen = 0;
+ if (m&(0x0000ffffUL<<1)) { /* <<1 for 1-origin numbering */
+ masklen |= 0x10;
+ m <<= 16;
+ }
+ if (m&(0x00ff0000UL<<1)) {
+ masklen |= 0x08;
+ m <<= 8;
+ }
+ if (m&(0x0f000000UL<<1)) {
+ masklen |= 0x04;
+ m <<= 4;
+ }
+ if (m&(0x30000000UL<<1)) {
+ masklen |= 0x02;
+ m <<= 2;
+ }
+ if (m&(0x40000000UL<<1))
+ masklen |= 0x01;
+
+ return masklen;
+}
+
+/*
+ - bitstomask - return a mask with this many high bits on
+ */
+struct in_addr
+bitstomask(n)
+int n;
+{
+ struct in_addr result;
+
+ if (n > 0 && n <= ABITS)
+ result.s_addr = htonl(~((1UL << (ABITS - n)) - 1));
+ else if (n == 0)
+ result.s_addr = 0;
+ else
+ result.s_addr = 0; /* best error report we can do */
+ return result;
+}
diff --git a/linux/lib/libfreeswan/initaddr.3 b/linux/lib/libfreeswan/initaddr.3
new file mode 100644
index 000000000..b963f21cc
--- /dev/null
+++ b/linux/lib/libfreeswan/initaddr.3
@@ -0,0 +1,129 @@
+.TH IPSEC_INITADDR 3 "11 Sept 2000"
+.\" RCSID $Id: initaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec initaddr \- initialize an ip_address
+.br
+ipsec addrtypeof \- get address type of an ip_address
+.br
+ipsec addrlenof \- get length of address within an ip_address
+.br
+ipsec addrbytesof \- get copy of address within an ip_address
+.br
+ipsec addrbytesptr \- get pointer to address within an ip_address
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *initaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *dst);"
+.br
+.B "int addrtypeof(const ip_address *src);"
+.br
+.B "size_t addrlenof(const ip_address *src);"
+.br
+.B "size_t addrbytesof(const ip_address *src,"
+.ti +1c
+.B "unsigned char *dst, size_t dstlen);"
+.br
+.B "size_t addrbytesptr(const ip_address *src,"
+.ti +1c
+.B "const unsigned char **dst);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+library uses an internal type
+.I ip_address
+to contain one of the (currently two) types of IP address.
+These functions provide basic tools for creating and examining this type.
+.PP
+.I Initaddr
+initializes a variable
+.I *dst
+of type
+.I ip_address
+from an address
+(in network byte order,
+indicated by a pointer
+.I src
+and a length
+.IR srclen )
+and an address family
+.I af
+(typically
+.B AF_INET
+or
+.BR AF_INET6 ).
+The length must be consistent with the address family.
+.PP
+.I Addrtypeof
+returns the address type of an address,
+normally
+.B AF_INET
+or
+.BR AF_INET6 .
+(The
+.B <freeswan.h>
+header file arranges to include the necessary headers for these
+names to be known.)
+.PP
+.I Addrlenof
+returns the size (in bytes) of the address within an
+.IR ip_address ,
+to permit storage allocation etc.
+.PP
+.I Addrbytesof
+copies the address within the
+.I ip_address
+.I src
+to the buffer indicated by the pointer
+.I dst
+and the length
+.IR dstlen ,
+and returns the address length (in bytes).
+If the address will not fit,
+as many bytes as will fit are copied;
+the returned length is still the full length.
+It is the caller's responsibility to check the
+returned value to ensure that there was enough room.
+.PP
+.I Addrbytesptr
+sets
+.I *dst
+to a pointer to the internal address within the
+.IR ip_address ,
+and returns the address length (in bytes).
+If
+.I dst
+is
+.BR NULL ,
+it just returns the address length.
+The pointer points to
+.B const
+to discourage misuse.
+.PP
+.I Initaddr
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.PP
+The functions which return
+.I size_t
+return
+.B 0
+for a failure.
+.SH SEE ALSO
+inet(3), ipsec_ttoaddr(3)
+.SH DIAGNOSTICS
+An unknown address family is a fatal error for any of these functions
+except
+.IR addrtypeof .
+An address-size mismatch is a fatal error for
+.IR initaddr .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+.I Addrtypeof
+should probably have been named
+.IR addrfamilyof .
diff --git a/linux/lib/libfreeswan/initaddr.c b/linux/lib/libfreeswan/initaddr.c
new file mode 100644
index 000000000..c215f6bdf
--- /dev/null
+++ b/linux/lib/libfreeswan/initaddr.c
@@ -0,0 +1,51 @@
+/*
+ * initialize address structure
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: initaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initaddr - initialize ip_address from bytes
+ */
+err_t /* NULL for success, else string literal */
+initaddr(src, srclen, af, dst)
+const unsigned char *src;
+size_t srclen;
+int af; /* address family */
+ip_address *dst;
+{
+ switch (af) {
+ case AF_INET:
+ if (srclen != 4)
+ return "IPv4 address must be exactly 4 bytes";
+ dst->u.v4.sin_family = af;
+ dst->u.v4.sin_port = 0; /* unused */
+ memcpy((char *)&dst->u.v4.sin_addr.s_addr, src, srclen);
+ break;
+ case AF_INET6:
+ if (srclen != 16)
+ return "IPv6 address must be exactly 16 bytes";
+ dst->u.v6.sin6_family = af;
+ dst->u.v6.sin6_flowinfo = 0; /* unused */
+ dst->u.v6.sin6_port = 0; /* unused */
+ memcpy((char *)&dst->u.v6.sin6_addr, src, srclen);
+ break;
+ default:
+ return "unknown address family in initaddr";
+ break;
+ }
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/initsaid.c b/linux/lib/libfreeswan/initsaid.c
new file mode 100644
index 000000000..4790f6981
--- /dev/null
+++ b/linux/lib/libfreeswan/initsaid.c
@@ -0,0 +1,33 @@
+/*
+ * initialize SA ID structure
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: initsaid.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initsaid - initialize SA ID from bits
+ */
+void
+initsaid(addr, spi, proto, dst)
+const ip_address *addr;
+ipsec_spi_t spi;
+int proto;
+ip_said *dst;
+{
+ dst->dst = *addr;
+ dst->spi = spi;
+ dst->proto = proto;
+}
diff --git a/linux/lib/libfreeswan/initsubnet.3 b/linux/lib/libfreeswan/initsubnet.3
new file mode 100644
index 000000000..670f71778
--- /dev/null
+++ b/linux/lib/libfreeswan/initsubnet.3
@@ -0,0 +1,137 @@
+.TH IPSEC_INITSUBNET 3 "12 March 2002"
+.\" RCSID $Id: initsubnet.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec initsubnet \- initialize an ip_subnet
+.br
+ipsec addrtosubnet \- initialize a singleton ip_subnet
+.br
+ipsec subnettypeof \- get address type of an ip_subnet
+.br
+ipsec masktocount \- convert subnet mask to bit count
+.br
+ipsec networkof \- get base address of an ip_subnet
+.br
+ipsec maskof \- get subnet mask of an ip_subnet
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *initsubnet(const ip_address *addr,"
+.ti +1c
+.B "int maskbits, int clash, ip_subnet *dst);"
+.br
+.B "const char *addrtosubnet(const ip_address *addr,"
+.ti +1c
+.B "ip_subnet *dst);"
+.sp
+.B "int subnettypeof(const ip_subnet *src);"
+.br
+.B "int masktocount(const ip_address *src);"
+.br
+.B "void networkof(const ip_subnet *src, ip_address *dst);"
+.br
+.B "void maskof(const ip_subnet *src, ip_address *dst);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+library uses an internal type
+.I ip_subnet
+to contain a description of an IP subnet
+(base address plus mask).
+These functions provide basic tools for creating and examining this type.
+.PP
+.I Initsubnet
+initializes a variable
+.I *dst
+of type
+.I ip_subnet
+from a base address and
+a count of mask bits.
+The
+.I clash
+parameter specifies what to do if the base address includes
+.B 1
+bits outside the prefix specified by the mask
+(that is, in the ``host number'' part of the address):
+.RS
+.IP '0' 5
+zero out host-number bits
+.IP 'x'
+non-zero host-number bits are an error
+.RE
+.PP
+.I Initsubnet
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.PP
+.I Addrtosubnet
+initializes an
+.I ip_subnet
+variable
+.I *dst
+to a ``singleton subnet'' containing the single address
+.IR *addr .
+It returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure.
+.PP
+.I Subnettypeof
+returns the address type of a subnet,
+normally
+.B AF_INET
+or
+.BR AF_INET6 .
+(The
+.B <freeswan.h>
+header file arranges to include the necessary headers for these
+names to be known.)
+.PP
+.I Masktocount
+converts a subnet mask, expressed as an address, to a bit count
+suitable for use with
+.IR initsubnet .
+It returns
+.B \-1
+for error; see DIAGNOSTICS.
+.PP
+.I Networkof
+fills in
+.I *dst
+with the base address of subnet
+.IR src .
+.PP
+.I Maskof
+fills in
+.I *dst
+with the subnet mask of subnet
+.IR src ,
+expressed as an address.
+.SH SEE ALSO
+inet(3), ipsec_ttosubnet(3), ipsec_rangetosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I initsubnet
+are:
+unknown address family;
+unknown
+.I clash
+value;
+impossible mask bit count;
+non-zero host-number bits and
+.I clash
+is
+.BR 'x' .
+Fatal errors in
+.I addrtosubnet
+are:
+unknown address family.
+Fatal errors in
+.I masktocount
+are:
+unknown address family;
+mask bits not contiguous.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/initsubnet.c b/linux/lib/libfreeswan/initsubnet.c
new file mode 100644
index 000000000..75ca72f36
--- /dev/null
+++ b/linux/lib/libfreeswan/initsubnet.c
@@ -0,0 +1,95 @@
+/*
+ * initialize subnet structure
+ * Copyright (C) 2000, 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: initsubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - initsubnet - initialize ip_subnet from address and count
+ *
+ * The only hard part is checking for host-part bits turned on.
+ */
+err_t /* NULL for success, else string literal */
+initsubnet(addr, count, clash, dst)
+const ip_address *addr;
+int count;
+int clash; /* '0' zero host-part bits, 'x' die on them */
+ip_subnet *dst;
+{
+ unsigned char *p;
+ int n;
+ int c;
+ unsigned m;
+ int die;
+
+ dst->addr = *addr;
+ n = addrbytesptr(&dst->addr, (const unsigned char **)&p);
+ if (n == 0)
+ return "unknown address family";
+
+ switch (clash) {
+ case '0':
+ die = 0;
+ break;
+ case 'x':
+ die = 1;
+ break;
+ default:
+ return "unknown clash-control value in initsubnet";
+ break;
+ }
+
+ c = count / 8;
+ if (c > n)
+ return "impossible mask count";
+ p += c;
+ n -= c;
+
+ m = 0xff;
+ c = count % 8;
+ if (n > 0 && c != 0) /* partial byte */
+ m >>= c;
+ for (; n > 0; n--) {
+ if ((*p & m) != 0) {
+ if (die)
+ return "improper subnet, host-part bits on";
+ *p &= ~m;
+ }
+ m = 0xff;
+ p++;
+ }
+
+ dst->maskbits = count;
+ return NULL;
+}
+
+/*
+ - addrtosubnet - initialize ip_subnet from a single address
+ */
+err_t /* NULL for success, else string literal */
+addrtosubnet(addr, dst)
+const ip_address *addr;
+ip_subnet *dst;
+{
+ int n;
+
+ dst->addr = *addr;
+ n = addrbytesptr(&dst->addr, (const unsigned char **)NULL);
+ if (n == 0)
+ return "unknown address family";
+ dst->maskbits = n*8;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/internal.h b/linux/lib/libfreeswan/internal.h
new file mode 100644
index 000000000..16ad78da0
--- /dev/null
+++ b/linux/lib/libfreeswan/internal.h
@@ -0,0 +1,81 @@
+/*
+ * internal definitions for use within the library; do not export!
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: internal.h,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+#ifndef ABITS
+#define ABITS 32 /* bits in an IPv4 address */
+#endif
+
+/* case-independent ASCII character equality comparison */
+#define CIEQ(c1, c2) ( ((c1)&~040) == ((c2)&~040) )
+
+/* syntax for passthrough SA */
+#ifndef PASSTHROUGHNAME
+#define PASSTHROUGHNAME "%passthrough"
+#define PASSTHROUGH4NAME "%passthrough4"
+#define PASSTHROUGH6NAME "%passthrough6"
+#define PASSTHROUGHIS "tun0@0.0.0.0"
+#define PASSTHROUGH4IS "tun0@0.0.0.0"
+#define PASSTHROUGH6IS "tun0@::"
+#define PASSTHROUGHTYPE "tun"
+#define PASSTHROUGHSPI 0
+#define PASSTHROUGHDST 0
+#endif
+
+/*
+ * Headers, greatly complicated by stupid and unnecessary inconsistencies
+ * between the user environment and the kernel environment. These are done
+ * here so that this mess need exist in only one place.
+ *
+ * It may seem like a -I or two could avoid most of this, but on closer
+ * inspection it is not quite that easy.
+ */
+
+/* things that need to come from one place or the other, depending */
+#ifdef __KERNEL__
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#define assert(foo) /* nothing */
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#endif
+
+/* things that exist only in userland */
+#ifndef __KERNEL__
+
+/* You'd think this would be okay in the kernel too -- it's just a */
+/* bunch of constants -- but no, in RH5.1 it screws up other things. */
+/* (Credit: Mike Warfield tracked this problem down. Thanks Mike!) */
+/* Fortunately, we don't need it in the kernel subset of the library. */
+#include <limits.h>
+
+/* header files for things that should never be called in kernel */
+#include <netdb.h>
+
+/* memory allocation, currently user-only, macro-ized just in case */
+#include <stdlib.h>
+#define MALLOC(n) malloc(n)
+#define FREE(p) free(p)
+
+#endif /* __KERNEL__ */
+
diff --git a/linux/lib/libfreeswan/keyblobtoid.3 b/linux/lib/libfreeswan/keyblobtoid.3
new file mode 100644
index 000000000..be381531a
--- /dev/null
+++ b/linux/lib/libfreeswan/keyblobtoid.3
@@ -0,0 +1,103 @@
+.TH IPSEC_KEYBLOBTOID 3 "25 March 2002"
+.\" RCSID $Id: keyblobtoid.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec keyblobtoid, splitkeytoid \- generate key IDs from RSA keys
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "size_t keyblobtoid(const unsigned char *blob,"
+.ti +1c
+.B "size_t bloblen, char *dst, size_t dstlen);"
+.br
+.B "size_t splitkeytoid(const unsigned char *e, size_t elen,"
+.ti +1c
+.B "const unsigned char *m, size_t mlen, char *dst,
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+.I Keyblobtoid
+and
+.I splitkeytoid
+generate
+key IDs
+from RSA keys,
+for use in messages and reporting,
+writing the result to
+.IR dst .
+A
+.I key ID
+is a short ASCII string identifying a key;
+currently it is just the first nine characters of the base64
+encoding of the RFC 2537/3110 ``byte blob'' representation of the key.
+(Beware that no finite key ID can be collision-proof:
+there is always some small chance of two random keys having the
+same ID.)
+.PP
+.I Keyblobtoid
+generates a key ID from a key which is already in the form of an
+RFC 2537/3110 binary key
+.I blob
+(encoded exponent length, exponent, modulus).
+.PP
+.I Splitkeytoid
+generates a key ID from a key given in the form of a separate
+(binary) exponent
+.I e
+and modulus
+.IR m .
+.PP
+The
+.I dstlen
+parameter of either
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant
+.B KEYID_BUF
+which is the size of a buffer large enough for worst-case results.
+.PP
+Both functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.P
+With keys generated by
+.IR ipsec_rsasigkey (3),
+the first two base64 digits are always the same,
+and the third carries only about one bit of information.
+It's worse with keys using longer fixed exponents,
+e.g. the 24-bit exponent that's common in X.509 certificates.
+However, being able to relate key IDs to the full
+base64 text form of keys by eye is sufficiently useful that this
+waste of space seems justifiable.
+The choice of nine digits is a compromise between bulk and
+probability of collision.
+.SH SEE ALSO
+RFC 3110,
+\fIRSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)\fR,
+Eastlake, 2001
+(superseding the older but better-known RFC 2537).
+.SH DIAGNOSTICS
+Fatal errors are:
+key too short to supply enough bits to construct a complete key ID
+(almost certainly indicating a garbage key);
+exponent too long for its length to be representable.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/keyblobtoid.c b/linux/lib/libfreeswan/keyblobtoid.c
new file mode 100644
index 000000000..7798601cf
--- /dev/null
+++ b/linux/lib/libfreeswan/keyblobtoid.c
@@ -0,0 +1,148 @@
+/*
+ * generate printable key IDs
+ * Copyright (C) 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: keyblobtoid.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - keyblobtoid - generate a printable key ID from an RFC 2537/3110 key blob
+ * Current algorithm is just to use first nine base64 digits.
+ */
+size_t
+keyblobtoid(src, srclen, dst, dstlen)
+const unsigned char *src;
+size_t srclen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[KEYID_BUF];
+ size_t ret;
+# define NDIG 9
+
+ if (srclen < (NDIG*6 + 7)/8) {
+ strcpy(buf, "?len= ?");
+ buf[5] = '0' + srclen;
+ ret = 0;
+ } else {
+ (void) datatot(src, srclen, 64, buf, NDIG+1);
+ ret = NDIG+1;
+ }
+
+ if (dstlen > 0) {
+ if (strlen(buf)+1 > dstlen)
+ *(buf + dstlen - 1) = '\0';
+ strcpy(dst, buf);
+ }
+ return ret;
+}
+
+/*
+ - splitkeytoid - generate a printable key ID from exponent/modulus pair
+ * Just constructs the beginnings of a key blob and calls keyblobtoid().
+ */
+size_t
+splitkeytoid(e, elen, m, mlen, dst, dstlen)
+const unsigned char *e;
+size_t elen;
+const unsigned char *m;
+size_t mlen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ unsigned char buf[KEYID_BUF]; /* ample room */
+ unsigned char *bufend = buf + sizeof(buf);
+ unsigned char *p;
+ size_t n;
+
+ p = buf;
+ if (elen <= 255)
+ *p++ = elen;
+ else if ((elen &~ 0xffff) == 0) {
+ *p++ = 0;
+ *p++ = (elen>>8) & 0xff;
+ *p++ = elen & 0xff;
+ } else
+ return 0; /* unrepresentable exponent length */
+
+ n = bufend - p;
+ if (elen < n)
+ n = elen;
+ memcpy(p, e, n);
+ p += n;
+
+ n = bufend - p;
+ if (n > 0) {
+ if (mlen < n)
+ n = mlen;
+ memcpy(p, m, n);
+ p += n;
+ }
+
+ return keyblobtoid(buf, p - buf, dst, dstlen);
+}
+
+
+
+#ifdef KEYBLOBTOID_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ typedef unsigned char uc;
+ uc hexblob[] = "\x01\x03\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52";
+ uc hexe[] = "\x03";
+ uc hexm[] = "\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52\xef\x85";
+ char b64nine[] = "AQOF8tZ2m";
+ char b64six[] = "AQOF8t";
+ char buf[100];
+ size_t n;
+ char *b = b64nine;
+ size_t bl = strlen(b) + 1;
+ int st = 0;
+
+ n = keyblobtoid(hexblob, strlen(hexblob), buf, sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: keyblobtoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: keyblobtoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ n = splitkeytoid(hexe, strlen(hexe), hexm, strlen(hexm), buf,
+ sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: splitkeytoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: splitkeytoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ exit(st);
+}
+
+#endif /* KEYBLOBTOID_MAIN */
diff --git a/linux/lib/libfreeswan/optionsfrom.3 b/linux/lib/libfreeswan/optionsfrom.3
new file mode 100644
index 000000000..e270475bd
--- /dev/null
+++ b/linux/lib/libfreeswan/optionsfrom.3
@@ -0,0 +1,182 @@
+.TH IPSEC_OPTIONSFROM 3 "16 Oct 1998"
+.\" RCSID $Id: optionsfrom.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec optionsfrom \- read additional ``command-line'' options from file
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *optionsfrom(char *filename, int *argcp,"
+.ti +1c
+.B "char ***argvp, int optind, FILE *errsto);"
+.SH DESCRIPTION
+.I Optionsfrom
+is called from within a
+.IR getopt_long (3)
+scan,
+as the result of the appearance of an option (preferably
+.BR \-\-optionsfrom )
+to insert additional ``command-line'' arguments
+into the scan immediately after
+the option.
+Typically this would be done to pick up options which are
+security-sensitive and should not be visible to
+.IR ps (1)
+and similar commands,
+and hence cannot be supplied as part
+of the actual command line or the environment.
+.PP
+.I Optionsfrom
+reads the additional arguments from the specified
+.IR filename ,
+allocates a new argument vector to hold pointers to the existing
+arguments plus the new ones,
+and amends
+.I argc
+and
+.I argv
+(via the pointers
+.I argcp
+and
+.IR argvp ,
+which must point to the
+.I argc
+and
+.I argv
+being supplied to
+.IR getopt_long (3))
+accordingly.
+.I Optind
+must be the index, in the original argument vector,
+of the next argument.
+.PP
+If
+.I errsto
+is NULL,
+.I optionsfrom
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+If
+.I errsto
+is non-NULL and an error occurs,
+.I optionsfrom
+prints a suitable complaint onto the
+.I errsto
+descriptor and invokes
+.I exit
+with an exit status of 2;
+this is a convenience for cases where more sophisticated
+responses are not required.
+.PP
+The text of existing arguments is not disturbed by
+.IR optionsfrom ,
+so pointers to them and into them remain valid.
+.PP
+The file of additional arguments is an ASCII text file.
+Lines consisting solely of white space,
+and lines beginning with
+.BR # ,
+are comments and are ignored.
+Otherwise, a line which does not begin with
+.BR \-
+is taken to be a single argument;
+if it both begins and ends with double-quote ("),
+those quotes are stripped off (note, no other processing is done within
+the line!).
+A line beginning with
+.B \-
+is considered to contain multiple arguments separated by white space.
+.PP
+Because
+.I optionsfrom
+reads its entire file before the
+.IR getopt_long (3)
+scan is resumed, an
+.I optionsfrom
+file can contain another
+.B \-\-optionsfrom
+option.
+Obviously, infinite loops are possible here.
+If
+.I errsto
+is non-NULL,
+.I optionsfrom
+considers it an error to be called more than 100 times.
+If
+.I errsto
+is NULL,
+loop detection is up to the caller
+(and the internal loop counter is zeroed out).
+.SH EXAMPLE
+A reasonable way to invoke
+.I optionsfrom
+would be like so:
+.PP
+.nf
+.ft B
+#include <getopt.h>
+
+struct option opts[] = {
+ /* ... */
+ "optionsfrom", 1, NULL, '+',
+ /* ... */
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt;
+ extern char *optarg;
+ extern int optind;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ /* ... */
+ case '+': /* optionsfrom */
+ optionsfrom(optarg, &argc, &argv, optind, stderr);
+ /* does not return on error */
+ break;
+ /* ... */
+ }
+ /* ... */
+.ft
+.fi
+.SH SEE ALSO
+getopt_long(3)
+.SH DIAGNOSTICS
+Errors in
+.I optionsfrom
+are:
+unable to open file;
+attempt to allocate temporary storage for argument or
+argument vector failed;
+read error in file;
+line too long.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The double-quote convention is rather simplistic.
+.PP
+Line length is currently limited to 1023 bytes,
+and there is no continuation convention.
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+.PP
+There is a certain element of unwarranted chumminess with
+the insides of
+.IR getopt_long (3)
+here.
+No non-public interfaces are actually used, but
+.IR optionsfrom
+does rely on
+.IR getopt_long (3)
+being well-behaved in certain ways that are not actually
+promised by the specs.
diff --git a/linux/lib/libfreeswan/optionsfrom.c b/linux/lib/libfreeswan/optionsfrom.c
new file mode 100644
index 000000000..d96a3124d
--- /dev/null
+++ b/linux/lib/libfreeswan/optionsfrom.c
@@ -0,0 +1,301 @@
+/*
+ * pick up more options from a file, in the middle of an option scan
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: optionsfrom.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#include <stdio.h>
+
+#define MAX 100 /* loop-detection limit */
+
+/* internal work area */
+struct work {
+# define LOTS 1024
+ char buf[LOTS];
+ char *line;
+ char *pending;
+};
+
+static const char *dowork(const char *, int *, char ***, int);
+static const char *getanarg(FILE *, struct work *, char **);
+static char *getline(FILE *, char *, size_t);
+
+/*
+ - optionsfrom - add some options, taken from a file, to argc/argv
+ * If errsto is non-NULL, does not return in event of error.
+ */
+const char * /* NULL for success, else string literal */
+optionsfrom(filename, argcp, argvp, optind, errsto)
+const char *filename;
+int *argcp; /* pointer to argc */
+char ***argvp; /* pointer to argv */
+int optind; /* current optind, number of next argument */
+FILE *errsto; /* where to report errors (NULL means return) */
+{
+ const char *e;
+ static int nuses = 0;
+
+ if (errsto != NULL) {
+ nuses++;
+ if (nuses >= MAX) {
+ fprintf(errsto,
+ "%s: optionsfrom called %d times, looping?\n",
+ (*argvp)[0], nuses);
+ exit(2);
+ }
+ } else
+ nuses = 0;
+
+ e = dowork(filename, argcp, argvp, optind);
+ if (e != NULL && errsto != NULL) {
+ fprintf(errsto, "%s: optionsfrom failed: %s\n", (*argvp)[0], e);
+ exit(2);
+ }
+ return e;
+}
+
+/*
+ - dowork - do all the real work of optionsfrom
+ * Does not alter the existing arguments, but does relocate and alter
+ * the argv pointer vector.
+ */
+static const char * /* NULL for success, else string literal */
+dowork(filename, argcp, argvp, optind)
+const char *filename;
+int *argcp; /* pointer to argc */
+char ***argvp; /* pointer to argv */
+int optind; /* current optind, number of next argument */
+{
+ char **newargv;
+ char **tmp;
+ int newargc;
+ int next; /* place for next argument */
+ int room; /* how many more new arguments we can hold */
+# define SOME 10 /* first guess at how many we'll need */
+ FILE *f;
+ int i;
+ const char *p;
+ struct work wa; /* for getanarg() */
+
+ f = fopen(filename, "r");
+ if (f == NULL)
+ return "unable to open file";
+
+ newargc = *argcp + SOME;
+ newargv = malloc((newargc+1) * sizeof(char *));
+ if (newargv == NULL)
+ return "unable to allocate memory";
+ memcpy(newargv, *argvp, optind * sizeof(char *));
+ room = SOME;
+ next = optind;
+
+ newargv[next] = NULL;
+ wa.pending = NULL;
+ while ((p = getanarg(f, &wa, &newargv[next])) == NULL) {
+ if (room == 0) {
+ newargc += SOME;
+ tmp = realloc(newargv, (newargc+1) * sizeof(char *));
+ if (tmp == NULL) {
+ p = "out of space for new argv";
+ break; /* NOTE BREAK OUT */
+ }
+ newargv = tmp;
+ room += SOME;
+ }
+ next++;
+ room--;
+ }
+ if (p != NULL && !feof(f)) { /* error of some kind */
+ for (i = optind+1; i <= next; i++)
+ if (newargv[i] != NULL)
+ free(newargv[i]);
+ free(newargv);
+ fclose(f);
+ return p;
+ }
+
+ fclose(f);
+ memcpy(newargv + next, *argvp + optind,
+ (*argcp+1-optind) * sizeof(char *));
+ *argcp += next - optind;
+ *argvp = newargv;
+ return NULL;
+}
+
+/*
+ - getanarg - get a malloced argument from the file
+ */
+static const char * /* NULL for success, else string literal */
+getanarg(f, w, linep)
+FILE *f;
+struct work *w;
+char **linep; /* where to store pointer if successful */
+{
+ size_t len;
+ char *p;
+ char *endp;
+
+ while (w->pending == NULL) { /* no pending line */
+ if ((w->line = getline(f, w->buf, sizeof(w->buf))) == NULL)
+ return "error in line read"; /* caller checks EOF */
+ if (w->line[0] != '#' &&
+ *(w->line + strspn(w->line, " \t")) != '\0')
+ w->pending = w->line;
+ }
+
+ if (w->pending == w->line && w->line[0] != '-') {
+ /* fresh plain line */
+ w->pending = NULL;
+ p = w->line;
+ endp = p + strlen(p);
+ if (*p == '"' && endp > p+1 && *(endp-1) == '"') {
+ p++;
+ endp--;
+ *endp = '\0';
+ }
+ if (w->line == w->buf) {
+ *linep = malloc(endp - p + 1);
+ if (*linep == NULL)
+ return "out of memory for new line";
+ strcpy(*linep, p);
+ } else /* getline already malloced it */
+ *linep = p;
+ return NULL;
+ }
+
+ /* chip off a piece of a pending line */
+ p = w->pending;
+ p += strspn(p, " \t");
+ endp = p + strcspn(p, " \t");
+ len = endp - p;
+ if (*endp != '\0') {
+ *endp++ = '\0';
+ endp += strspn(endp, " \t");
+ }
+ /* endp now points to next real character, or to line-end NUL */
+ *linep = malloc(len + 1);
+ if (*linep == NULL) {
+ if (w->line != w->buf)
+ free(w->line);
+ return "out of memory for new argument";
+ }
+ strcpy(*linep, p);
+ if (*endp == '\0') {
+ w->pending = NULL;
+ if (w->line != w->buf)
+ free(w->line);
+ } else
+ w->pending = endp;
+ return NULL;
+}
+
+/*
+ - getline - read a line from the file, trim newline off
+ */
+static char * /* pointer to line, NULL for eof/error */
+getline(f, buf, bufsize)
+FILE *f;
+char *buf; /* buffer to use, if convenient */
+size_t bufsize; /* size of buf */
+{
+ size_t len;
+
+ if (fgets(buf, bufsize, f) == NULL)
+ return NULL;
+ len = strlen(buf);
+
+ if (len < bufsize-1 || buf[bufsize-1] == '\n') {
+ /* it fit */
+ buf[len-1] = '\0';
+ return buf;
+ }
+
+ /* oh crud, buffer overflow */
+ /* for now, to hell with it */
+ return NULL;
+}
+
+
+
+#ifdef TEST
+
+#include <getopt.h>
+
+char usage[] = "Usage: tester [--foo] [--bar] [--optionsfrom file] arg ...";
+struct option opts[] = {
+ "foo", 0, NULL, 'f',
+ "bar", 0, NULL, 'b',
+ "builtin", 0, NULL, 'B',
+ "optionsfrom", 1, NULL, '+',
+ "help", 0, NULL, 'h',
+ "version", 0, NULL, 'v',
+ 0, 0, NULL, 0,
+};
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int opt;
+ extern char *optarg;
+ extern int optind;
+ int errflg = 0;
+ const char *p;
+ int i;
+ FILE *errs = NULL;
+
+ while ((opt = getopt_long(argc, argv, "", opts, NULL)) != EOF)
+ switch (opt) {
+ case 'f':
+ case 'b':
+ break;
+ case 'B':
+ errs = stderr;
+ break;
+ case '+': /* optionsfrom */
+ p = optionsfrom(optarg, &argc, &argv, optind, errs);
+ if (p != NULL) {
+ fprintf(stderr, "%s: optionsfrom error: %s\n",
+ argv[0], p);
+ exit(1);
+ }
+ break;
+ case 'h': /* help */
+ printf("%s\n", usage);
+ exit(0);
+ break;
+ case 'v': /* version */
+ printf("1\n");
+ exit(0);
+ break;
+ case '?':
+ default:
+ errflg = 1;
+ break;
+ }
+ if (errflg) {
+ fprintf(stderr, "%s\n", usage);
+ exit(2);
+ }
+
+ for (i = 1; i < argc; i++)
+ printf("%d: `%s'\n", i, argv[i]);
+ exit(0);
+}
+
+
+#endif /* TEST */
diff --git a/linux/lib/libfreeswan/pfkey_v2_build.c b/linux/lib/libfreeswan/pfkey_v2_build.c
new file mode 100644
index 000000000..be58c552f
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_build.c
@@ -0,0 +1,1438 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_build.c,v 1.4 2005/04/07 19:43:52 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
+ */
+
+char pfkey_v2_build_c_version[] = "$Id: pfkey_v2_build.c,v 1.4 2005/04/07 19:43:52 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h> /* struct ipv6hdr */
+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
+# define MALLOC(size) kmalloc(size, GFP_ATOMIC)
+# define FREE(obj) kfree(obj)
+# include <freeswan.h>
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+# include <malloc.h>
+# include <string.h> /* memset */
+
+# include <freeswan.h>
+unsigned int pfkey_lib_debug = 0;
+
+void (*pfkey_debug_func)(const char *message, ...) PRINTF_LIKE(1);
+
+/* #define PLUTO */
+
+#define DEBUGGING(args...) if(pfkey_lib_debug) { \
+ if(pfkey_debug_func != NULL) { \
+ (*pfkey_debug_func)("pfkey_lib_debug:" args); \
+ } else { \
+ printf("pfkey_lib_debug:" args); \
+ } }
+# define MALLOC(size) malloc(size)
+# define FREE(obj) free(obj)
+#endif /* __KERNEL__ */
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef __KERNEL__
+
+#include "freeswan/radij.h" /* rd_nodes */
+#include "freeswan/ipsec_encap.h" /* sockaddr_encap */
+
+# define DEBUGGING(args...) \
+ KLIPS_PRINT(debug_pfkey, "klips_debug:" args)
+#endif /* __KERNEL__ */
+
+#include "freeswan/ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+void
+pfkey_extensions_init(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ int i;
+
+ for (i = 0; i != SADB_EXT_MAX + 1; i++) {
+ extensions[i] = NULL;
+ }
+}
+
+void
+pfkey_extensions_free(struct sadb_ext *extensions[SADB_EXT_MAX + 1])
+{
+ int i;
+
+ if (!extensions) {
+ return;
+ }
+
+ if (extensions[0]) {
+ memset(extensions[0], 0, sizeof(struct sadb_msg));
+ FREE(extensions[0]);
+ extensions[0] = NULL;
+ }
+
+ for (i = 1; i != SADB_EXT_MAX + 1; i++) {
+ if(extensions[i]) {
+ memset(extensions[i], 0, extensions[i]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ FREE(extensions[i]);
+ extensions[i] = NULL;
+ }
+ }
+}
+
+void
+pfkey_msg_free(struct sadb_msg **pfkey_msg)
+{
+ if (*pfkey_msg) {
+ memset(*pfkey_msg, 0, (*pfkey_msg)->sadb_msg_len * IPSEC_PFKEYv2_ALIGN);
+ FREE(*pfkey_msg);
+ *pfkey_msg = NULL;
+ }
+}
+
+/* Default extension builders taken from the KLIPS code */
+
+int
+pfkey_msg_hdr_build(struct sadb_ext** pfkey_ext,
+ uint8_t msg_type,
+ uint8_t satype,
+ uint8_t msg_errno,
+ uint32_t seq,
+ uint32_t pid)
+{
+ int error = 0;
+ struct sadb_msg *pfkey_msg = (struct sadb_msg *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_msg_hdr_build:\n");
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "on_entry &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
+ &pfkey_ext,
+ pfkey_ext,
+ *pfkey_ext);
+ /* sanity checks... */
+ if (pfkey_msg) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "why is pfkey_msg already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!msg_type) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "msg type not set, must be non-zero..\n");
+ SENDERR(EINVAL);
+ }
+
+ if (msg_type > SADB_MAX) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "msg type too large:%d.\n",
+ msg_type);
+ SENDERR(EINVAL);
+ }
+
+ if (satype > SADB_SATYPE_MAX) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "satype %d > max %d\n",
+ satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_msg = (struct sadb_msg*)MALLOC(sizeof(struct sadb_msg));
+ *pfkey_ext = (struct sadb_ext*)pfkey_msg;
+
+ if (pfkey_msg == NULL) {
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_msg, 0, sizeof(struct sadb_msg));
+
+ pfkey_msg->sadb_msg_len = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_msg->sadb_msg_type = msg_type;
+ pfkey_msg->sadb_msg_satype = satype;
+
+ pfkey_msg->sadb_msg_version = PF_KEY_V2;
+ pfkey_msg->sadb_msg_errno = msg_errno;
+ pfkey_msg->sadb_msg_reserved = 0;
+ pfkey_msg->sadb_msg_seq = seq;
+ pfkey_msg->sadb_msg_pid = pid;
+ DEBUGGING(
+ "pfkey_msg_hdr_build: "
+ "on_exit &pfkey_ext=0p%p pfkey_ext=0p%p *pfkey_ext=0p%p.\n",
+ &pfkey_ext,
+ pfkey_ext,
+ *pfkey_ext);
+errlab:
+ return error;
+}
+
+int
+pfkey_sa_ref_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi,
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags,
+ uint32_t/*IPsecSAref_t*/ ref)
+{
+ int error = 0;
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "spi=%08x replay=%d sa_state=%d auth=%d encrypt=%d flags=%d\n",
+ ntohl(spi), /* in network order */
+ replay_window,
+ sa_state,
+ auth,
+ encrypt,
+ flags);
+ /* sanity checks... */
+ if (pfkey_sa) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "why is pfkey_sa already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (exttype != SADB_EXT_SA
+ && exttype != SADB_X_EXT_SA2) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "invalid exttype=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ if (replay_window > 64) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ replay_window);
+ SENDERR(EINVAL);
+ }
+
+ if (auth > SADB_AALG_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "auth=%d > SADB_AALG_MAX=%d.\n",
+ auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (encrypt > SADB_EALG_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "encrypt=%d > SADB_EALG_MAX=%d.\n",
+ encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (sa_state > SADB_SASTATE_MAX) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "sa_state=%d exceeds MAX=%d.\n",
+ sa_state,
+ SADB_SASTATE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if (sa_state == SADB_SASTATE_DEAD) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "sa_state=%d is DEAD=%d is not allowed.\n",
+ sa_state,
+ SADB_SASTATE_DEAD);
+ SENDERR(EINVAL);
+ }
+
+ if ((IPSEC_SAREF_NULL != ref) && (ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
+ ref,
+ IPSEC_SAREF_NULL,
+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_sa = (struct sadb_sa*)MALLOC(sizeof(struct sadb_sa));
+ *pfkey_ext = (struct sadb_ext*)pfkey_sa;
+
+ if (pfkey_sa == NULL) {
+ DEBUGGING(
+ "pfkey_sa_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_sa, 0, sizeof(struct sadb_sa));
+
+ pfkey_sa->sadb_sa_len = sizeof(*pfkey_sa) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_sa->sadb_sa_exttype = exttype;
+ pfkey_sa->sadb_sa_spi = spi;
+ pfkey_sa->sadb_sa_replay = replay_window;
+ pfkey_sa->sadb_sa_state = sa_state;
+ pfkey_sa->sadb_sa_auth = auth;
+ pfkey_sa->sadb_sa_encrypt = encrypt;
+ pfkey_sa->sadb_sa_flags = flags;
+ pfkey_sa->sadb_x_sa_ref = ref;
+
+errlab:
+ return error;
+}
+
+int
+pfkey_sa_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t spi,
+ uint8_t replay_window,
+ uint8_t sa_state,
+ uint8_t auth,
+ uint8_t encrypt,
+ uint32_t flags)
+{
+ return pfkey_sa_ref_build(pfkey_ext,
+ exttype,
+ spi,
+ replay_window,
+ sa_state,
+ auth,
+ encrypt,
+ flags,
+ IPSEC_SAREF_NULL);
+}
+
+int
+pfkey_lifetime_build(struct sadb_ext ** pfkey_ext,
+ uint16_t exttype,
+ uint32_t allocations,
+ uint64_t bytes,
+ uint64_t addtime,
+ uint64_t usetime,
+ uint32_t packets)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_lifetime_build:\n");
+ /* sanity checks... */
+ if (pfkey_lifetime) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "why is pfkey_lifetime already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (exttype != SADB_EXT_LIFETIME_CURRENT
+ && exttype != SADB_EXT_LIFETIME_HARD
+ && exttype != SADB_EXT_LIFETIME_SOFT) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "invalid exttype=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_lifetime = (struct sadb_lifetime*)MALLOC(sizeof(struct sadb_lifetime));
+ *pfkey_ext = (struct sadb_ext*)pfkey_lifetime;
+
+ if (pfkey_lifetime == NULL) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_lifetime, 0, sizeof(struct sadb_lifetime));
+
+ pfkey_lifetime->sadb_lifetime_len = sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_lifetime->sadb_lifetime_exttype = exttype;
+ pfkey_lifetime->sadb_lifetime_allocations = allocations;
+ pfkey_lifetime->sadb_lifetime_bytes = bytes;
+ pfkey_lifetime->sadb_lifetime_addtime = addtime;
+ pfkey_lifetime->sadb_lifetime_usetime = usetime;
+ pfkey_lifetime->sadb_x_lifetime_packets = packets;
+
+errlab:
+ return error;
+}
+
+int
+pfkey_address_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint8_t proto,
+ uint8_t prefixlen,
+ struct sockaddr* address)
+{
+ int error = 0;
+ int saddr_len = 0;
+ char ipaddr_txt[ADDRTOT_BUF + 6/*extra for port number*/];
+ struct sadb_address *pfkey_address = (struct sadb_address *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_address_build: "
+ "exttype=%d proto=%d prefixlen=%d\n",
+ exttype,
+ proto,
+ prefixlen);
+ /* sanity checks... */
+ if (pfkey_address) {
+ DEBUGGING(
+ "pfkey_address_build: "
+ "why is pfkey_address already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!address) {
+ DEBUGGING("pfkey_address_build: "
+ "address is NULL\n");
+ SENDERR(EINVAL);
+ }
+
+ switch(exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+#endif
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "unrecognised ext_type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch (address->sa_family) {
+ case AF_INET:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address family AF_INET.\n");
+ saddr_len = sizeof(struct sockaddr_in);
+ sprintf(ipaddr_txt, "%d.%d.%d.%d:%d"
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 0) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 8) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 16) & 0xFF
+ , (((struct sockaddr_in*)address)->sin_addr.s_addr >> 24) & 0xFF
+ , ntohs(((struct sockaddr_in*)address)->sin_port));
+ break;
+ case AF_INET6:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address family AF_INET6.\n");
+ saddr_len = sizeof(struct sockaddr_in6);
+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x-%x"
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[0])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[1])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[2])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[3])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[4])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[5])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[6])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_addr.s6_addr16[7])
+ , ntohs(((struct sockaddr_in6*)address)->sin6_port));
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_address_build: "
+ "address->sa_family=%d not supported.\n",
+ address->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ DEBUGGING(
+ "pfkey_address_build: "
+ "found address=%s.\n",
+ ipaddr_txt);
+ if (prefixlen != 0) {
+ DEBUGGING(
+ "pfkey_address_build: "
+ "address prefixes not supported yet.\n");
+ SENDERR(EAFNOSUPPORT); /* not supported yet */
+ }
+
+ pfkey_address = (struct sadb_address*)
+ MALLOC(ALIGN_N(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN));
+ *pfkey_ext = (struct sadb_ext*)pfkey_address;
+
+ if (pfkey_address == NULL) {
+ DEBUGGING(
+ "pfkey_lifetime_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_address,
+ 0,
+ ALIGN_N(sizeof(struct sadb_address) + saddr_len,
+ IPSEC_PFKEYv2_ALIGN));
+
+ pfkey_address->sadb_address_len = DIVUP(sizeof(struct sadb_address) + saddr_len,
+ IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_address->sadb_address_exttype = exttype;
+ pfkey_address->sadb_address_proto = proto;
+ pfkey_address->sadb_address_prefixlen = prefixlen;
+ pfkey_address->sadb_address_reserved = 0;
+
+ memcpy((char*)pfkey_address + sizeof(struct sadb_address),
+ address,
+ saddr_len);
+
+#if 0
+ for (i = 0; i < sizeof(struct sockaddr_in) - offsetof(struct sockaddr_in, sin_zero); i++) {
+ pfkey_address_s_ska.sin_zero[i] = 0;
+ }
+#endif
+ DEBUGGING(
+ "pfkey_address_build: "
+ "successful.\n");
+
+ errlab:
+ return error;
+}
+
+int
+pfkey_key_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t key_bits,
+ char* key)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_key_build:\n");
+ /* sanity checks... */
+ if (pfkey_key) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "why is pfkey_key already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!key_bits) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "key_bits is zero, it must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_KEY_AUTH) || (exttype == SADB_EXT_KEY_ENCRYPT))) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_key = (struct sadb_key*)
+ MALLOC(sizeof(struct sadb_key) +
+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
+ *pfkey_ext = (struct sadb_ext*)pfkey_key;
+
+ if (pfkey_key == NULL) {
+ DEBUGGING(
+ "pfkey_key_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_key,
+ 0,
+ sizeof(struct sadb_key) +
+ DIVUP(key_bits, 64) * IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_key->sadb_key_len = DIVUP(sizeof(struct sadb_key) * IPSEC_PFKEYv2_ALIGN + key_bits,
+ 64);
+ pfkey_key->sadb_key_exttype = exttype;
+ pfkey_key->sadb_key_bits = key_bits;
+ pfkey_key->sadb_key_reserved = 0;
+ memcpy((char*)pfkey_key + sizeof(struct sadb_key),
+ key,
+ DIVUP(key_bits, 8));
+
+errlab:
+ return error;
+}
+
+int
+pfkey_ident_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t ident_type,
+ uint64_t ident_id,
+ uint8_t ident_len,
+ char* ident_string)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)*pfkey_ext;
+ int data_len = ident_len * IPSEC_PFKEYv2_ALIGN - sizeof(struct sadb_ident);
+
+ DEBUGGING(
+ "pfkey_ident_build:\n");
+ /* sanity checks... */
+ if (pfkey_ident) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "why is pfkey_ident already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_IDENTITY_SRC) ||
+ (exttype == SADB_EXT_IDENTITY_DST))) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ if (ident_type == SADB_IDENTTYPE_RESERVED) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "ident_type must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if (ident_type > SADB_IDENTTYPE_MAX) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "identtype=%d out of range.\n",
+ ident_type);
+ SENDERR(EINVAL);
+ }
+
+ if ((ident_type == SADB_IDENTTYPE_PREFIX ||
+ ident_type == SADB_IDENTTYPE_FQDN) &&
+ !ident_string) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "string required to allocate size of extension.\n");
+ SENDERR(EINVAL);
+ }
+
+#if 0
+ if (ident_type == SADB_IDENTTYPE_USERFQDN) {
+ }
+#endif
+
+ pfkey_ident = (struct sadb_ident*)
+ MALLOC(ident_len * IPSEC_PFKEYv2_ALIGN);
+ *pfkey_ext = (struct sadb_ext*)pfkey_ident;
+
+ if (pfkey_ident == NULL) {
+ DEBUGGING(
+ "pfkey_ident_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_ident, 0, ident_len * IPSEC_PFKEYv2_ALIGN);
+
+ pfkey_ident->sadb_ident_len = ident_len;
+ pfkey_ident->sadb_ident_exttype = exttype;
+ pfkey_ident->sadb_ident_type = ident_type;
+ pfkey_ident->sadb_ident_reserved = 0;
+ pfkey_ident->sadb_ident_id = ident_id;
+ memcpy((char*)pfkey_ident + sizeof(struct sadb_ident),
+ ident_string,
+ data_len);
+
+errlab:
+ return error;
+}
+
+int
+pfkey_sens_build(struct sadb_ext** pfkey_ext,
+ uint32_t dpd,
+ uint8_t sens_level,
+ uint8_t sens_len,
+ uint64_t* sens_bitmap,
+ uint8_t integ_level,
+ uint8_t integ_len,
+ uint64_t* integ_bitmap)
+{
+ int error = 0;
+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)*pfkey_ext;
+ int i;
+ uint64_t* bitmap;
+
+ DEBUGGING(
+ "pfkey_sens_build:\n");
+ /* sanity checks... */
+ if (pfkey_sens) {
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "why is pfkey_sens already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ pfkey_sens = (struct sadb_sens*)
+ MALLOC(sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t));
+ *pfkey_ext = (struct sadb_ext*)pfkey_sens;
+
+ if (pfkey_sens == NULL) {
+ DEBUGGING(
+ "pfkey_sens_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_sens,
+ 0,
+ sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t));
+
+ pfkey_sens->sadb_sens_len = (sizeof(struct sadb_sens) +
+ (sens_len + integ_len) * sizeof(uint64_t)) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_sens->sadb_sens_exttype = SADB_EXT_SENSITIVITY;
+ pfkey_sens->sadb_sens_dpd = dpd;
+ pfkey_sens->sadb_sens_sens_level = sens_level;
+ pfkey_sens->sadb_sens_sens_len = sens_len;
+ pfkey_sens->sadb_sens_integ_level = integ_level;
+ pfkey_sens->sadb_sens_integ_len = integ_len;
+ pfkey_sens->sadb_sens_reserved = 0;
+
+ bitmap = (uint64_t*)((char*)pfkey_ext + sizeof(struct sadb_sens));
+ for (i = 0; i < sens_len; i++) {
+ *bitmap = sens_bitmap[i];
+ bitmap++;
+ }
+ for (i = 0; i < integ_len; i++) {
+ *bitmap = integ_bitmap[i];
+ bitmap++;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_prop_build(struct sadb_ext** pfkey_ext,
+ uint8_t replay,
+ unsigned int comb_num,
+ struct sadb_comb* comb)
+{
+ int error = 0;
+ int i;
+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)*pfkey_ext;
+ struct sadb_comb *combp;
+
+ DEBUGGING(
+ "pfkey_prop_build:\n");
+ /* sanity checks... */
+ if (pfkey_prop) {
+ DEBUGGING(
+ "pfkey_prop_build: "
+ "why is pfkey_prop already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ pfkey_prop = (struct sadb_prop*)
+ MALLOC(sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_prop;
+
+ if (pfkey_prop == NULL) {
+ DEBUGGING(
+ "pfkey_prop_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_prop,
+ 0,
+ sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb));
+
+ pfkey_prop->sadb_prop_len = (sizeof(struct sadb_prop) +
+ comb_num * sizeof(struct sadb_comb)) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_prop->sadb_prop_exttype = SADB_EXT_PROPOSAL;
+ pfkey_prop->sadb_prop_replay = replay;
+
+ for (i=0; i<3; i++) {
+ pfkey_prop->sadb_prop_reserved[i] = 0;
+ }
+
+ combp = (struct sadb_comb*)((char*)*pfkey_ext + sizeof(struct sadb_prop));
+ for (i = 0; i < comb_num; i++) {
+ memcpy (combp, &(comb[i]), sizeof(struct sadb_comb));
+ combp++;
+ }
+
+#if 0
+ uint8_t sadb_comb_auth;
+ uint8_t sadb_comb_encrypt;
+ uint16_t sadb_comb_flags;
+ uint16_t sadb_comb_auth_minbits;
+ uint16_t sadb_comb_auth_maxbits;
+ uint16_t sadb_comb_encrypt_minbits;
+ uint16_t sadb_comb_encrypt_maxbits;
+ uint32_t sadb_comb_reserved;
+ uint32_t sadb_comb_soft_allocations;
+ uint32_t sadb_comb_hard_allocations;
+ uint64_t sadb_comb_soft_bytes;
+ uint64_t sadb_comb_hard_bytes;
+ uint64_t sadb_comb_soft_addtime;
+ uint64_t sadb_comb_hard_addtime;
+ uint64_t sadb_comb_soft_usetime;
+ uint64_t sadb_comb_hard_usetime;
+ uint32_t sadb_comb_soft_packets;
+ uint32_t sadb_comb_hard_packets;
+#endif
+errlab:
+ return error;
+}
+
+int
+pfkey_supported_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ unsigned int alg_num,
+ struct sadb_alg* alg)
+{
+ int error = 0;
+ unsigned int i;
+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)*pfkey_ext;
+ struct sadb_alg *pfkey_alg;
+
+ /* sanity checks... */
+ if (pfkey_supported) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "why is pfkey_supported already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if ( !((exttype == SADB_EXT_SUPPORTED_AUTH) || (exttype == SADB_EXT_SUPPORTED_ENCRYPT))) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "unsupported extension type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_supported = (struct sadb_supported*)
+ MALLOC(sizeof(struct sadb_supported) +
+ alg_num * sizeof(struct sadb_alg));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_supported;
+
+ if (pfkey_supported == NULL) {
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_supported,
+ 0,
+ sizeof(struct sadb_supported) +
+ alg_num *
+ sizeof(struct sadb_alg));
+
+ pfkey_supported->sadb_supported_len = (sizeof(struct sadb_supported) +
+ alg_num *
+ sizeof(struct sadb_alg)) /
+ IPSEC_PFKEYv2_ALIGN;
+ pfkey_supported->sadb_supported_exttype = exttype;
+ pfkey_supported->sadb_supported_reserved = 0;
+
+ pfkey_alg = (struct sadb_alg*)((char*)pfkey_supported + sizeof(struct sadb_supported));
+ for(i = 0; i < alg_num; i++) {
+ memcpy (pfkey_alg, &(alg[i]), sizeof(struct sadb_alg));
+ pfkey_alg->sadb_alg_reserved = 0;
+ pfkey_alg++;
+ }
+
+#if 0
+ DEBUGGING(
+ "pfkey_supported_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ uint8_t sadb_alg_id;
+ uint8_t sadb_alg_ivlen;
+ uint16_t sadb_alg_minbits;
+ uint16_t sadb_alg_maxbits;
+ uint16_t sadb_alg_reserved;
+#endif
+errlab:
+ return error;
+}
+
+int
+pfkey_spirange_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint32_t min, /* in network order */
+ uint32_t max) /* in network order */
+{
+ int error = 0;
+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)*pfkey_ext;
+
+ /* sanity checks... */
+ if (pfkey_spirange) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "why is pfkey_spirange already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (ntohl(max) < ntohl(min)) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "minspi=%08x must be < maxspi=%08x.\n",
+ ntohl(min),
+ ntohl(max));
+ SENDERR(EINVAL);
+ }
+
+ if (ntohl(min) <= 255) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "minspi=%08x must be > 255.\n",
+ ntohl(min));
+ SENDERR(EEXIST);
+ }
+
+ pfkey_spirange = (struct sadb_spirange*)
+ MALLOC(sizeof(struct sadb_spirange));
+ *pfkey_ext = (struct sadb_ext*)pfkey_spirange;
+
+ if (pfkey_spirange == NULL) {
+ DEBUGGING(
+ "pfkey_spirange_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_spirange,
+ 0,
+ sizeof(struct sadb_spirange));
+
+ pfkey_spirange->sadb_spirange_len = sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_spirange->sadb_spirange_exttype = SADB_EXT_SPIRANGE;
+ pfkey_spirange->sadb_spirange_min = min;
+ pfkey_spirange->sadb_spirange_max = max;
+ pfkey_spirange->sadb_spirange_reserved = 0;
+ errlab:
+ return error;
+}
+
+int
+pfkey_x_kmprivate_build(struct sadb_ext** pfkey_ext)
+{
+ int error = 0;
+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)*pfkey_ext;
+
+ /* sanity checks... */
+ if (pfkey_x_kmprivate) {
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "why is pfkey_x_kmprivate already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "Sorry, I can't build exttype=%d yet.\n",
+ (*pfkey_ext)->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+ pfkey_x_kmprivate = (struct sadb_x_kmprivate*)
+ MALLOC(sizeof(struct sadb_x_kmprivate));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_kmprivate;
+
+ if (pfkey_x_kmprivate == NULL) {
+ DEBUGGING(
+ "pfkey_x_kmprivate_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_x_kmprivate,
+ 0,
+ sizeof(struct sadb_x_kmprivate));
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_len =
+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_x_kmprivate->sadb_x_kmprivate_exttype = SADB_X_EXT_KMPRIVATE;
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved = 0;
+errlab:
+ return error;
+}
+
+int
+pfkey_x_satype_build(struct sadb_ext** pfkey_ext,
+ uint8_t satype)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_satype_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_satype) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "why is pfkey_x_satype already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ if (!satype) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "SA type not set, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if (satype > SADB_SATYPE_MAX) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "satype %d > max %d\n",
+ satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ pfkey_x_satype = (struct sadb_x_satype*)
+ MALLOC(sizeof(struct sadb_x_satype));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_satype;
+
+ if (pfkey_x_satype == NULL) {
+ DEBUGGING(
+ "pfkey_x_satype_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ memset(pfkey_x_satype,
+ 0,
+ sizeof(struct sadb_x_satype));
+
+ pfkey_x_satype->sadb_x_satype_len = sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_x_satype->sadb_x_satype_exttype = SADB_X_EXT_SATYPE2;
+ pfkey_x_satype->sadb_x_satype_satype = satype;
+ for (i=0; i<3; i++) {
+ pfkey_x_satype->sadb_x_satype_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+
+int
+pfkey_x_debug_build(struct sadb_ext** pfkey_ext,
+ uint32_t tunnel,
+ uint32_t netlink,
+ uint32_t xform,
+ uint32_t eroute,
+ uint32_t spi,
+ uint32_t radij,
+ uint32_t esp,
+ uint32_t ah,
+ uint32_t rcv,
+ uint32_t pfkey,
+ uint32_t ipcomp,
+ uint32_t verbose)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_debug_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_debug) {
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "why is pfkey_x_debug already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "tunnel=%x netlink=%x xform=%x eroute=%x spi=%x radij=%x esp=%x ah=%x rcv=%x pfkey=%x ipcomp=%x verbose=%x?\n",
+ tunnel, netlink, xform, eroute, spi, radij, esp, ah, rcv, pfkey, ipcomp, verbose);
+
+ pfkey_x_debug = (struct sadb_x_debug*)
+ MALLOC(sizeof(struct sadb_x_debug));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_debug;
+
+ if (pfkey_x_debug == NULL) {
+ DEBUGGING(
+ "pfkey_x_debug_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+#if 0
+ memset(pfkey_x_debug,
+ 0,
+ sizeof(struct sadb_x_debug));
+#endif
+
+ pfkey_x_debug->sadb_x_debug_len = sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_debug->sadb_x_debug_exttype = SADB_X_EXT_DEBUG;
+
+ pfkey_x_debug->sadb_x_debug_tunnel = tunnel;
+ pfkey_x_debug->sadb_x_debug_netlink = netlink;
+ pfkey_x_debug->sadb_x_debug_xform = xform;
+ pfkey_x_debug->sadb_x_debug_eroute = eroute;
+ pfkey_x_debug->sadb_x_debug_spi = spi;
+ pfkey_x_debug->sadb_x_debug_radij = radij;
+ pfkey_x_debug->sadb_x_debug_esp = esp;
+ pfkey_x_debug->sadb_x_debug_ah = ah;
+ pfkey_x_debug->sadb_x_debug_rcv = rcv;
+ pfkey_x_debug->sadb_x_debug_pfkey = pfkey;
+ pfkey_x_debug->sadb_x_debug_ipcomp = ipcomp;
+ pfkey_x_debug->sadb_x_debug_verbose = verbose;
+
+ for (i=0; i<4; i++) {
+ pfkey_x_debug->sadb_x_debug_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+
+#ifdef NAT_TRAVERSAL
+int
+pfkey_x_nat_t_type_build(struct sadb_ext** pfkey_ext,
+ uint8_t type)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_nat_t_type *pfkey_x_nat_t_type = (struct sadb_x_nat_t_type *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_nat_t_type) {
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "why is pfkey_x_nat_t_type already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "type=%d\n", type);
+
+ pfkey_x_nat_t_type = (struct sadb_x_nat_t_type*)
+ MALLOC(sizeof(struct sadb_x_nat_t_type));
+
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_type;
+ if (pfkey_x_nat_t_type == NULL) {
+ DEBUGGING(
+ "pfkey_x_nat_t_type_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_len = sizeof(struct sadb_x_nat_t_type) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE;
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_type = type;
+ for (i=0; i<3; i++) {
+ pfkey_x_nat_t_type->sadb_x_nat_t_type_reserved[i] = 0;
+ }
+
+errlab:
+ return error;
+}
+int
+pfkey_x_nat_t_port_build(struct sadb_ext** pfkey_ext,
+ uint16_t exttype,
+ uint16_t port)
+{
+ int error = 0;
+ struct sadb_x_nat_t_port *pfkey_x_nat_t_port = (struct sadb_x_nat_t_port *)*pfkey_ext;
+
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build:\n");
+ /* sanity checks... */
+ if (pfkey_x_nat_t_port) {
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "why is pfkey_x_nat_t_port already pointing to something?\n");
+ SENDERR(EINVAL);
+ }
+
+ switch (exttype) {
+ case SADB_X_EXT_NAT_T_SPORT:
+ case SADB_X_EXT_NAT_T_DPORT:
+ break;
+ default:
+ DEBUGGING(
+ "pfkey_nat_t_port_build: "
+ "unrecognised ext_type=%d.\n",
+ exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "ext=%d, port=%d\n", exttype, port);
+
+ pfkey_x_nat_t_port = (struct sadb_x_nat_t_port*)
+ MALLOC(sizeof(struct sadb_x_nat_t_port));
+ *pfkey_ext = (struct sadb_ext*)pfkey_x_nat_t_port;
+
+ if (pfkey_x_nat_t_port == NULL) {
+ DEBUGGING(
+ "pfkey_x_nat_t_port_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_len = sizeof(struct sadb_x_nat_t_port) / IPSEC_PFKEYv2_ALIGN;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_exttype = exttype;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_port = port;
+ pfkey_x_nat_t_port->sadb_x_nat_t_port_reserved = 0;
+
+errlab:
+ return error;
+}
+#endif
+
+int pfkey_x_protocol_build(struct sadb_ext **pfkey_ext,
+ uint8_t protocol)
+{
+ int error = 0;
+ struct sadb_protocol * p = (struct sadb_protocol *)*pfkey_ext;
+ DEBUGGING("pfkey_x_protocol_build: protocol=%u\n", protocol);
+ /* sanity checks... */
+ if (p != 0) {
+ DEBUGGING("pfkey_x_protocol_build: bogus protocol pointer\n");
+ SENDERR(EINVAL);
+ }
+ if ((p = (struct sadb_protocol*)MALLOC(sizeof(*p))) == 0) {
+ DEBUGGING("pfkey_build: memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+ *pfkey_ext = (struct sadb_ext *)p;
+ p->sadb_protocol_len = sizeof(*p) / sizeof(uint64_t);
+ p->sadb_protocol_exttype = SADB_X_EXT_PROTOCOL;
+ p->sadb_protocol_proto = protocol;
+ p->sadb_protocol_flags = 0;
+ p->sadb_protocol_reserved2 = 0;
+ errlab:
+ return error;
+}
+
+
+#if I_DONT_THINK_THIS_WILL_BE_USEFUL
+int (*ext_default_builders[SADB_EXT_MAX +1])(struct sadb_msg*, struct sadb_ext*)
+ =
+{
+ NULL, /* pfkey_msg_build, */
+ pfkey_sa_build,
+ pfkey_lifetime_build,
+ pfkey_lifetime_build,
+ pfkey_lifetime_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_key_build,
+ pfkey_key_build,
+ pfkey_ident_build,
+ pfkey_ident_build,
+ pfkey_sens_build,
+ pfkey_prop_build,
+ pfkey_supported_build,
+ pfkey_supported_build,
+ pfkey_spirange_build,
+ pfkey_x_kmprivate_build,
+ pfkey_x_satype_build,
+ pfkey_sa_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_address_build,
+ pfkey_x_ext_debug_build
+};
+#endif
+
+int
+pfkey_msg_build(struct sadb_msg **pfkey_msg, struct sadb_ext *extensions[], int dir)
+{
+ int error = 0;
+ unsigned ext;
+ unsigned total_size;
+ struct sadb_ext *pfkey_ext;
+ int extensions_seen = 0;
+ struct sadb_ext *extensions_check[SADB_EXT_MAX + 1];
+
+ if (!extensions[0]) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "extensions[0] must be specified (struct sadb_msg).\n");
+ SENDERR(EINVAL);
+ }
+
+ total_size = sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+ for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+ if(extensions[ext]) {
+ total_size += (extensions[ext])->sadb_ext_len;
+ }
+ }
+
+ if (!(*pfkey_msg = (struct sadb_msg*)MALLOC(total_size * IPSEC_PFKEYv2_ALIGN))) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "memory allocation failed\n");
+ SENDERR(ENOMEM);
+ }
+
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "pfkey_msg=0p%p allocated %lu bytes, &(extensions[0])=0p%p\n",
+ *pfkey_msg,
+ (unsigned long)(total_size * IPSEC_PFKEYv2_ALIGN),
+ &(extensions[0]));
+ memcpy(*pfkey_msg,
+ extensions[0],
+ sizeof(struct sadb_msg));
+ (*pfkey_msg)->sadb_msg_len = total_size;
+ (*pfkey_msg)->sadb_msg_reserved = 0;
+ extensions_seen = 1 ;
+
+ pfkey_ext = (struct sadb_ext*)(((char*)(*pfkey_msg)) + sizeof(struct sadb_msg));
+
+ for (ext = 1; ext <= SADB_EXT_MAX; ext++) {
+ /* copy from extension[ext] to buffer */
+ if (extensions[ext]) {
+ /* Is this type of extension permitted for this type of message? */
+ if (!(extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type] &
+ 1<<ext)) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "ext type %d not permitted, exts_perm=%08x, 1<<type=%08x\n",
+ ext,
+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
+ 1<<ext);
+ SENDERR(EINVAL);
+ }
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "copying %lu bytes from extensions[%u]=0p%p to=0p%p\n",
+ (unsigned long)(extensions[ext]->sadb_ext_len * IPSEC_PFKEYv2_ALIGN),
+ ext,
+ extensions[ext],
+ pfkey_ext);
+ memcpy(pfkey_ext,
+ extensions[ext],
+ (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ {
+ char *pfkey_ext_c = (char *)pfkey_ext;
+
+ pfkey_ext_c += (extensions[ext])->sadb_ext_len * IPSEC_PFKEYv2_ALIGN;
+ pfkey_ext = (struct sadb_ext *)pfkey_ext_c;
+ }
+ /* Mark that we have seen this extension and remember the header location */
+ extensions_seen |= ( 1 << ext );
+ }
+ }
+
+ /* check required extensions */
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][(*pfkey_msg)->sadb_msg_type],
+ extensions_seen,
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]);
+
+ if ((extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) !=
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "required extensions missing:%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type] -
+ (extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][(*pfkey_msg)->sadb_msg_type]) );
+ SENDERR(EINVAL);
+ }
+
+ error = pfkey_msg_parse(*pfkey_msg, NULL, extensions_check, dir);
+ if (error) {
+ DEBUGGING(
+ "pfkey_msg_build: "
+ "Trouble parsing newly built pfkey message, error=%d.\n",
+ error);
+ SENDERR(-error);
+ }
+
+errlab:
+
+ return error;
+}
diff --git a/linux/lib/libfreeswan/pfkey_v2_debug.c b/linux/lib/libfreeswan/pfkey_v2_debug.c
new file mode 100644
index 000000000..2f2ddd3b1
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_debug.c
@@ -0,0 +1,179 @@
+/*
+ * @(#) pfkey version 2 debugging messages
+ *
+ * Copyright (C) 2001 Richard Guy Briggs <rgb@freeswan.org>
+ * and Michael Richardson <mcr@freeswan.org>
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_debug.c,v 1.2 2004/03/22 21:53:18 as Exp $
+ *
+ */
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+extern int debug_pfkey;
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+
+#endif /* __KERNEL__ */
+
+#include "freeswan.h"
+#include "pfkeyv2.h"
+#include "pfkey.h"
+
+/*
+ * This file provides ASCII translations of PF_KEY magic numbers.
+ *
+ */
+
+static char *pfkey_sadb_ext_strings[]={
+ "reserved", /* SADB_EXT_RESERVED 0 */
+ "security-association", /* SADB_EXT_SA 1 */
+ "lifetime-current", /* SADB_EXT_LIFETIME_CURRENT 2 */
+ "lifetime-hard", /* SADB_EXT_LIFETIME_HARD 3 */
+ "lifetime-soft", /* SADB_EXT_LIFETIME_SOFT 4 */
+ "source-address", /* SADB_EXT_ADDRESS_SRC 5 */
+ "destination-address", /* SADB_EXT_ADDRESS_DST 6 */
+ "proxy-address", /* SADB_EXT_ADDRESS_PROXY 7 */
+ "authentication-key", /* SADB_EXT_KEY_AUTH 8 */
+ "cipher-key", /* SADB_EXT_KEY_ENCRYPT 9 */
+ "source-identity", /* SADB_EXT_IDENTITY_SRC 10 */
+ "destination-identity", /* SADB_EXT_IDENTITY_DST 11 */
+ "sensitivity-label", /* SADB_EXT_SENSITIVITY 12 */
+ "proposal", /* SADB_EXT_PROPOSAL 13 */
+ "supported-auth", /* SADB_EXT_SUPPORTED_AUTH 14 */
+ "supported-cipher", /* SADB_EXT_SUPPORTED_ENCRYPT 15 */
+ "spi-range", /* SADB_EXT_SPIRANGE 16 */
+ "X-kmpprivate", /* SADB_X_EXT_KMPRIVATE 17 */
+ "X-satype2", /* SADB_X_EXT_SATYPE2 18 */
+ "X-security-association", /* SADB_X_EXT_SA2 19 */
+ "X-destination-address2", /* SADB_X_EXT_ADDRESS_DST2 20 */
+ "X-source-flow-address", /* SADB_X_EXT_ADDRESS_SRC_FLOW 21 */
+ "X-dest-flow-address", /* SADB_X_EXT_ADDRESS_DST_FLOW 22 */
+ "X-source-mask", /* SADB_X_EXT_ADDRESS_SRC_MASK 23 */
+ "X-dest-mask", /* SADB_X_EXT_ADDRESS_DST_MASK 24 */
+ "X-set-debug", /* SADB_X_EXT_DEBUG 25 */
+#ifdef NAT_TRAVERSAL
+ "X-NAT-T-type", /* SADB_X_EXT_NAT_T_TYPE 26 */
+ "X-NAT-T-sport", /* SADB_X_EXT_NAT_T_SPORT 27 */
+ "X-NAT-T-dport", /* SADB_X_EXT_NAT_T_DPORT 28 */
+ "X-NAT-T-OA", /* SADB_X_EXT_NAT_T_OA 29 */
+#endif
+};
+
+const char *
+pfkey_v2_sadb_ext_string(int ext)
+{
+ if(ext <= SADB_EXT_MAX) {
+ return pfkey_sadb_ext_strings[ext];
+ } else {
+ return "unknown-ext";
+ }
+}
+
+
+static char *pfkey_sadb_type_strings[]={
+ "reserved", /* SADB_RESERVED */
+ "getspi", /* SADB_GETSPI */
+ "update", /* SADB_UPDATE */
+ "add", /* SADB_ADD */
+ "delete", /* SADB_DELETE */
+ "get", /* SADB_GET */
+ "acquire", /* SADB_ACQUIRE */
+ "register", /* SADB_REGISTER */
+ "expire", /* SADB_EXPIRE */
+ "flush", /* SADB_FLUSH */
+ "dump", /* SADB_DUMP */
+ "x-promisc", /* SADB_X_PROMISC */
+ "x-pchange", /* SADB_X_PCHANGE */
+ "x-groupsa", /* SADB_X_GRPSA */
+ "x-addflow(eroute)", /* SADB_X_ADDFLOW */
+ "x-delflow(eroute)", /* SADB_X_DELFLOW */
+ "x-debug", /* SADB_X_DEBUG */
+};
+
+const char *
+pfkey_v2_sadb_type_string(int sadb_type)
+{
+ if(sadb_type <= SADB_MAX) {
+ return pfkey_sadb_type_strings[sadb_type];
+ } else {
+ return "unknown-sadb-type";
+ }
+}
+
+
+
+
+/*
+ * $Log: pfkey_v2_debug.c,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.7 2002/09/20 05:01:26 rgb
+ * Fixed limit inclusion error in both type and ext string conversion.
+ *
+ * Revision 1.6 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.5 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_debug.c,v
+ *
+ * Revision 1.4 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.3 2002/01/29 01:59:09 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.2 2002/01/20 20:34:50 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.1 2001/11/27 05:30:06 mcr
+ * initial set of debug strings for pfkey debugging.
+ * this will eventually only be included for debug builds.
+ *
+ * Revision 1.1 2001/09/21 04:12:03 mcr
+ * first compilable version.
+ *
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/lib/libfreeswan/pfkey_v2_ext_bits.c b/linux/lib/libfreeswan/pfkey_v2_ext_bits.c
new file mode 100644
index 000000000..fe3f45306
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_ext_bits.c
@@ -0,0 +1,803 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_ext_bits.c,v 1.2 2004/03/22 21:53:18 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parse.c.
+ */
+
+char pfkey_v2_ext_bits_c_version[] = "$Id: pfkey_v2_ext_bits.c,v 1.2 2004/03/22 21:53:18 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+# include "freeswan/ipsec_kversion.h" /* for malloc switch */
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h>
+# endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+#endif
+
+#include <freeswan.h>
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+unsigned int extensions_bitmaps[2/*in/out*/][2/*perm/req*/][SADB_MAX + 1/*ext*/] = {
+
+/* INBOUND EXTENSIONS */
+{
+
+/* PERMITTED IN */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+#endif
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE */
+0
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+},
+
+/* REQUIRED IN */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_SPIRANGE
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_EXT_KEY_AUTH*/
+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_EXT_KEY_AUTH*/
+/*| 1<<SADB_EXT_KEY_ENCRYPT*/
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_EXPIRE */
+0
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+/*| 1<<SADB_X_EXT_SATYPE2*/
+/*| 1<<SADB_X_EXT_SA2*/
+/*| 1<<SADB_X_EXT_ADDRESS_DST2*/
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+/*| 1<<SADB_EXT_SA*/
+#if 0 /* SADB_X_CLREROUTE doesn't need all these... */
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+#endif
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+}
+
+},
+
+/* OUTBOUND EXTENSIONS */
+{
+
+/* PERMITTED OUT */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+#ifdef NAT_TRAVERSAL
+| 1<<SADB_X_EXT_NAT_T_TYPE
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+| 1<<SADB_X_EXT_NAT_T_OA
+#endif
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+,
+/* SADB_EXPIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+| 1<<SADB_X_EXT_PROTOCOL
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+},
+
+/* REQUIRED OUT */
+{
+/* SADB_RESERVED */
+0
+,
+/* SADB_GETSPI */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_UPDATE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_ADD */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_DELETE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_GET */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+/* | 1<<SADB_EXT_KEY_AUTH */
+/* | 1<<SADB_EXT_KEY_ENCRYPT */
+,
+/* SADB_ACQUIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_PROPOSAL
+,
+/* SADB_REGISTER */
+1<<SADB_EXT_RESERVED
+/* | 1<<SADB_EXT_SUPPORTED_AUTH
+ | 1<<SADB_EXT_SUPPORTED_ENCRYPT */
+,
+/* SADB_EXPIRE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+/* | 1<<SADB_EXT_LIFETIME_HARD
+ | 1<<SADB_EXT_LIFETIME_SOFT */
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_FLUSH */
+1<<SADB_EXT_RESERVED
+,
+/* SADB_DUMP */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+,
+/* SADB_X_PROMISC */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_PCHANGE */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_LIFETIME_CURRENT
+| 1<<SADB_EXT_LIFETIME_HARD
+| 1<<SADB_EXT_LIFETIME_SOFT
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_EXT_ADDRESS_PROXY
+| 1<<SADB_EXT_KEY_AUTH
+| 1<<SADB_EXT_KEY_ENCRYPT
+| 1<<SADB_EXT_IDENTITY_SRC
+| 1<<SADB_EXT_IDENTITY_DST
+| 1<<SADB_EXT_SENSITIVITY
+| 1<<SADB_EXT_PROPOSAL
+| 1<<SADB_EXT_SUPPORTED_AUTH
+| 1<<SADB_EXT_SUPPORTED_ENCRYPT
+| 1<<SADB_EXT_SPIRANGE
+| 1<<SADB_X_EXT_KMPRIVATE
+| 1<<SADB_X_EXT_SATYPE2
+| 1<<SADB_X_EXT_SA2
+| 1<<SADB_X_EXT_ADDRESS_DST2
+,
+/* SADB_X_GRPSA */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+,
+/* SADB_X_ADDFLOW */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DELFLOW */
+1<<SADB_EXT_RESERVED
+/*| 1<<SADB_EXT_SA*/
+| 1<<SADB_X_EXT_ADDRESS_SRC_FLOW
+| 1<<SADB_X_EXT_ADDRESS_DST_FLOW
+| 1<<SADB_X_EXT_ADDRESS_SRC_MASK
+| 1<<SADB_X_EXT_ADDRESS_DST_MASK
+,
+/* SADB_X_DEBUG */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_X_EXT_DEBUG
+#ifdef NAT_TRAVERSAL
+,
+/* SADB_X_NAT_T_NEW_MAPPING */
+1<<SADB_EXT_RESERVED
+| 1<<SADB_EXT_SA
+| 1<<SADB_EXT_ADDRESS_SRC
+| 1<<SADB_EXT_ADDRESS_DST
+| 1<<SADB_X_EXT_NAT_T_SPORT
+| 1<<SADB_X_EXT_NAT_T_DPORT
+#endif
+}
+}
+};
+
+/*
+ * $Log: pfkey_v2_ext_bits.c,v $
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.15 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.14 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_ext_bits.c,v
+ *
+ * Revision 1.13 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.12 2002/01/29 01:59:10 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.11 2001/10/18 04:45:24 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.10 2001/09/08 21:13:35 rgb
+ * Added pfkey ident extension support for ISAKMPd. (NetCelo)
+ *
+ * Revision 1.9 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.8 2001/03/26 23:07:36 rgb
+ * Remove requirement for auth and enc key from UPDATE.
+ *
+ * Revision 1.7 2000/09/12 22:35:37 rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.6 2000/09/09 06:39:01 rgb
+ * Added comments for clarity.
+ *
+ * Revision 1.5 2000/06/02 22:54:14 rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.4 2000/01/21 06:27:56 rgb
+ * Added address cases for eroute flows.
+ * Added comments for each message type.
+ * Added klipsdebug switching capability.
+ * Fixed GRPSA bitfields.
+ *
+ * Revision 1.3 1999/12/01 22:20:27 rgb
+ * Remove requirement for a proxy address in an incoming getspi message.
+ *
+ * Revision 1.2 1999/11/27 11:57:06 rgb
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ * Cleaned out unused bits.
+ *
+ */
diff --git a/linux/lib/libfreeswan/pfkey_v2_parse.c b/linux/lib/libfreeswan/pfkey_v2_parse.c
new file mode 100644
index 000000000..bb6962fa8
--- /dev/null
+++ b/linux/lib/libfreeswan/pfkey_v2_parse.c
@@ -0,0 +1,1832 @@
+/*
+ * RFC2367 PF_KEYv2 Key management API message parser
+ * Copyright (C) 1999, 2000, 2001 Richard Guy Briggs.
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: pfkey_v2_parse.c,v 1.4 2004/06/13 20:35:07 as Exp $
+ */
+
+/*
+ * Template from klips/net/ipsec/ipsec/ipsec_parser.c.
+ */
+
+char pfkey_v2_parse_c_version[] = "$Id: pfkey_v2_parse.c,v 1.4 2004/06/13 20:35:07 as Exp $";
+
+/*
+ * Some ugly stuff to allow consistent debugging code for use in the
+ * kernel and in user space
+*/
+
+#ifdef __KERNEL__
+
+# include <linux/kernel.h> /* for printk */
+
+#include "freeswan/ipsec_kversion.h" /* for malloc switch */
+
+# ifdef MALLOC_SLAB
+# include <linux/slab.h> /* kmalloc() */
+# else /* MALLOC_SLAB */
+# include <linux/malloc.h> /* kmalloc() */
+# endif /* MALLOC_SLAB */
+# include <linux/errno.h> /* error codes */
+# include <linux/types.h> /* size_t */
+# include <linux/interrupt.h> /* mark_bh */
+
+# include <linux/netdevice.h> /* struct device, and other headers */
+# include <linux/etherdevice.h> /* eth_type_trans */
+# include <linux/ip.h> /* struct iphdr */
+# if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+# include <linux/ipv6.h> /* struct ipv6hdr */
+# endif /* if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+extern int debug_pfkey;
+
+# include <freeswan.h>
+
+#include "freeswan/ipsec_encap.h"
+
+#else /* __KERNEL__ */
+
+# include <sys/types.h>
+# include <linux/types.h>
+# include <linux/errno.h>
+
+# include <freeswan.h>
+# include "programs/pluto/constants.h"
+# include "programs/pluto/defs.h" /* for PRINTF_LIKE */
+# include "programs/pluto/log.h" /* for debugging and DBG_log */
+
+/* #define PLUTO */
+
+# ifdef PLUTO
+# define DEBUGGING(level, args...) { DBG_log("pfkey_lib_debug:" args); }
+# else
+# define DEBUGGING(level, args...) if(pfkey_lib_debug & level) { printf("pfkey_lib_debug:" args); } else { ; }
+# endif
+
+#endif /* __KERNEL__ */
+
+
+#include <pfkeyv2.h>
+#include <pfkey.h>
+
+#ifdef __KERNEL__
+extern int sysctl_ipsec_debug_verbose;
+# define DEBUGGING(level, args...) \
+ KLIPS_PRINT( \
+ ((debug_pfkey & level & (PF_KEY_DEBUG_PARSE_STRUCT | PF_KEY_DEBUG_PARSE_PROBLEM)) \
+ || (sysctl_ipsec_debug_verbose && (debug_pfkey & level & PF_KEY_DEBUG_PARSE_FLOW))) \
+ , "klips_debug:" args)
+#endif /* __KERNEL__ */
+#include "freeswan/ipsec_sa.h" /* IPSEC_SAREF_NULL, IPSEC_SA_REF_TABLE_IDX_WIDTH */
+
+
+#define SENDERR(_x) do { error = -(_x); goto errlab; } while (0)
+
+struct satype_tbl {
+ uint8_t proto;
+ uint8_t satype;
+ char* name;
+} static satype_tbl[] = {
+#ifdef __KERNEL__
+ { IPPROTO_ESP, SADB_SATYPE_ESP, "ESP" },
+ { IPPROTO_AH, SADB_SATYPE_AH, "AH" },
+ { IPPROTO_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
+#ifdef CONFIG_IPSEC_IPCOMP
+ { IPPROTO_COMP, SADB_X_SATYPE_COMP, "COMP" },
+#endif /* CONFIG_IPSEC_IPCOMP */
+ { IPPROTO_INT, SADB_X_SATYPE_INT, "INT" },
+#else /* __KERNEL__ */
+ { SA_ESP, SADB_SATYPE_ESP, "ESP" },
+ { SA_AH, SADB_SATYPE_AH, "AH" },
+ { SA_IPIP, SADB_X_SATYPE_IPIP, "IPIP" },
+ { SA_COMP, SADB_X_SATYPE_COMP, "COMP" },
+ { SA_INT, SADB_X_SATYPE_INT, "INT" },
+#endif /* __KERNEL__ */
+ { 0, 0, "UNKNOWN" }
+};
+
+uint8_t
+satype2proto(uint8_t satype)
+{
+ int i =0;
+
+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
+ i++;
+ }
+ return satype_tbl[i].proto;
+}
+
+uint8_t
+proto2satype(uint8_t proto)
+{
+ int i = 0;
+
+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
+ i++;
+ }
+ return satype_tbl[i].satype;
+}
+
+char*
+satype2name(uint8_t satype)
+{
+ int i = 0;
+
+ while(satype_tbl[i].satype != satype && satype_tbl[i].satype != 0) {
+ i++;
+ }
+ return satype_tbl[i].name;
+}
+
+char*
+proto2name(uint8_t proto)
+{
+ int i = 0;
+
+ while(satype_tbl[i].proto != proto && satype_tbl[i].proto != 0) {
+ i++;
+ }
+ return satype_tbl[i].name;
+}
+
+/* Default extension parsers taken from the KLIPS code */
+
+DEBUG_NO_STATIC int
+pfkey_sa_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_sa *pfkey_sa = (struct sadb_sa *)pfkey_ext;
+#if 0
+ struct sadb_sa sav2;
+#endif
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_sa_parse: entry\n");
+ /* sanity checks... */
+ if(!pfkey_sa) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+#if 0
+ /* check if this structure is short, and if so, fix it up.
+ * XXX this is NOT the way to do things.
+ */
+ if(pfkey_sa->sadb_sa_len == sizeof(struct sadb_sa_v1)/IPSEC_PFKEYv2_ALIGN) {
+
+ /* yes, so clear out a temporary structure, and copy first */
+ memset(&sav2, 0, sizeof(sav2));
+ memcpy(&sav2, pfkey_sa, sizeof(struct sadb_sa_v1));
+ sav2.sadb_x_sa_ref=-1;
+ sav2.sadb_sa_len = sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_sa = &sav2;
+ }
+#endif
+
+
+ if(pfkey_sa->sadb_sa_len != sizeof(struct sadb_sa) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "length wrong pfkey_sa->sadb_sa_len=%d sizeof(struct sadb_sa)=%d.\n",
+ pfkey_sa->sadb_sa_len,
+ (int)sizeof(struct sadb_sa));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_encrypt > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "pfkey_sa->sadb_sa_encrypt=%d > SADB_EALG_MAX=%d.\n",
+ pfkey_sa->sadb_sa_encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_auth > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "pfkey_sa->sadb_sa_auth=%d > SADB_AALG_MAX=%d.\n",
+ pfkey_sa->sadb_sa_auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_state > SADB_SASTATE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "state=%d exceeds MAX=%d.\n",
+ pfkey_sa->sadb_sa_state,
+ SADB_SASTATE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_state == SADB_SASTATE_DEAD) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "state=%d is DEAD=%d.\n",
+ pfkey_sa->sadb_sa_state,
+ SADB_SASTATE_DEAD);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_sa->sadb_sa_replay > 64) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ pfkey_sa->sadb_sa_replay);
+ SENDERR(EINVAL);
+ }
+
+ if(! ((pfkey_sa->sadb_sa_exttype == SADB_EXT_SA) ||
+ (pfkey_sa->sadb_sa_exttype == SADB_X_EXT_SA2)))
+ {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "unknown exttype=%d, expecting SADB_EXT_SA=%d or SADB_X_EXT_SA2=%d.\n",
+ pfkey_sa->sadb_sa_exttype,
+ SADB_EXT_SA,
+ SADB_X_EXT_SA2);
+ SENDERR(EINVAL);
+ }
+
+ if((IPSEC_SAREF_NULL != pfkey_sa->sadb_x_sa_ref) && (pfkey_sa->sadb_x_sa_ref >= (1 << IPSEC_SA_REF_TABLE_IDX_WIDTH))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sa_parse: "
+ "SAref=%d must be (SAref == IPSEC_SAREF_NULL(%d) || SAref < IPSEC_SA_REF_TABLE_NUM_ENTRIES(%d)).\n",
+ pfkey_sa->sadb_x_sa_ref,
+ IPSEC_SAREF_NULL,
+ IPSEC_SA_REF_TABLE_NUM_ENTRIES);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_sa_parse: "
+ "successfully found len=%d exttype=%d(%s) spi=%08lx replay=%d state=%d auth=%d encrypt=%d flags=%d ref=%d.\n",
+ pfkey_sa->sadb_sa_len,
+ pfkey_sa->sadb_sa_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_sa->sadb_sa_exttype),
+ (long unsigned int)ntohl(pfkey_sa->sadb_sa_spi),
+ pfkey_sa->sadb_sa_replay,
+ pfkey_sa->sadb_sa_state,
+ pfkey_sa->sadb_sa_auth,
+ pfkey_sa->sadb_sa_encrypt,
+ pfkey_sa->sadb_sa_flags,
+ pfkey_sa->sadb_x_sa_ref);
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_lifetime_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_lifetime *pfkey_lifetime = (struct sadb_lifetime *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_lifetime_parse:enter\n");
+ /* sanity checks... */
+ if(!pfkey_lifetime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_lifetime->sadb_lifetime_len !=
+ sizeof(struct sadb_lifetime) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "length wrong pfkey_lifetime->sadb_lifetime_len=%d sizeof(struct sadb_lifetime)=%d.\n",
+ pfkey_lifetime->sadb_lifetime_len,
+ (int)sizeof(struct sadb_lifetime));
+ SENDERR(EINVAL);
+ }
+
+ if((pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_HARD) &&
+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_SOFT) &&
+ (pfkey_lifetime->sadb_lifetime_exttype != SADB_EXT_LIFETIME_CURRENT)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_lifetime_parse: "
+ "unexpected ext_type=%d.\n",
+ pfkey_lifetime->sadb_lifetime_exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_lifetime_parse: "
+ "life_type=%d(%s) alloc=%u bytes=%u add=%u use=%u pkts=%u.\n",
+ pfkey_lifetime->sadb_lifetime_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_lifetime->sadb_lifetime_exttype),
+ pfkey_lifetime->sadb_lifetime_allocations,
+ (unsigned)pfkey_lifetime->sadb_lifetime_bytes,
+ (unsigned)pfkey_lifetime->sadb_lifetime_addtime,
+ (unsigned)pfkey_lifetime->sadb_lifetime_usetime,
+ pfkey_lifetime->sadb_x_lifetime_packets);
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_address_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int saddr_len = 0;
+ struct sadb_address *pfkey_address = (struct sadb_address *)pfkey_ext;
+ struct sockaddr* s = (struct sockaddr*)((char*)pfkey_address + sizeof(*pfkey_address));
+ char ipaddr_txt[ADDRTOT_BUF];
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_address_parse:enter\n");
+ /* sanity checks... */
+ if(!pfkey_address) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_len <
+ (sizeof(struct sadb_address) + sizeof(struct sockaddr))/
+ IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "size wrong 1 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
+ pfkey_address->sadb_address_len,
+ (int)sizeof(struct sadb_address),
+ (int)sizeof(struct sockaddr));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_address->sadb_address_reserved);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_address->sadb_address_exttype) {
+ case SADB_EXT_ADDRESS_SRC:
+ case SADB_EXT_ADDRESS_DST:
+ case SADB_EXT_ADDRESS_PROXY:
+ case SADB_X_EXT_ADDRESS_DST2:
+ case SADB_X_EXT_ADDRESS_SRC_FLOW:
+ case SADB_X_EXT_ADDRESS_DST_FLOW:
+ case SADB_X_EXT_ADDRESS_SRC_MASK:
+ case SADB_X_EXT_ADDRESS_DST_MASK:
+#ifdef NAT_TRAVERSAL
+ case SADB_X_EXT_NAT_T_OA:
+#endif
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "unexpected ext_type=%d.\n",
+ pfkey_address->sadb_address_exttype);
+ SENDERR(EINVAL);
+ }
+
+ switch(s->sa_family) {
+ case AF_INET:
+ saddr_len = sizeof(struct sockaddr_in);
+ sprintf(ipaddr_txt, "%d.%d.%d.%d"
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 0) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 8) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 16) & 0xFF
+ , (((struct sockaddr_in*)s)->sin_addr.s_addr >> 24) & 0xFF);
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_address_parse: "
+ "found exttype=%u(%s) family=%d(AF_INET) address=%s proto=%u port=%u.\n",
+ pfkey_address->sadb_address_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
+ s->sa_family,
+ ipaddr_txt,
+ pfkey_address->sadb_address_proto,
+ ntohs(((struct sockaddr_in*)s)->sin_port));
+ break;
+ case AF_INET6:
+ saddr_len = sizeof(struct sockaddr_in6);
+ sprintf(ipaddr_txt, "%x:%x:%x:%x:%x:%x:%x:%x"
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[0])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[1])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[2])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[3])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[4])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[5])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[6])
+ , ntohs(((struct sockaddr_in6*)s)->sin6_addr.s6_addr16[7]));
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_address_parse: "
+ "found exttype=%u(%s) family=%d(AF_INET6) address=%s proto=%u port=%u.\n",
+ pfkey_address->sadb_address_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_address->sadb_address_exttype),
+ s->sa_family,
+ ipaddr_txt,
+ pfkey_address->sadb_address_proto,
+ ((struct sockaddr_in6*)s)->sin6_port);
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "s->sa_family=%d not supported.\n",
+ s->sa_family);
+ SENDERR(EPFNOSUPPORT);
+ }
+
+ if(pfkey_address->sadb_address_len !=
+ DIVUP(sizeof(struct sadb_address) + saddr_len, IPSEC_PFKEYv2_ALIGN)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "size wrong 2 ext_len=%d, adr_ext_len=%d, saddr_len=%d.\n",
+ pfkey_address->sadb_address_len,
+ (int)sizeof(struct sadb_address),
+ saddr_len);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_address->sadb_address_prefixlen != 0) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_address_parse: "
+ "address prefixes not supported yet.\n");
+ SENDERR(EAFNOSUPPORT); /* not supported yet */
+ }
+
+ /* XXX check if port!=0 */
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_address_parse: successful.\n");
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_key_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_key *pfkey_key = (struct sadb_key *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_key_parse:enter\n");
+ /* sanity checks... */
+
+ if(!pfkey_key) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "NULL pointer passed in.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_len < sizeof(struct sadb_key) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_key->sadb_key_len,
+ (int)sizeof(struct sadb_key));
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_key->sadb_key_bits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "key length set to zero, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_len !=
+ DIVUP(sizeof(struct sadb_key) * OCTETBITS + pfkey_key->sadb_key_bits,
+ PFKEYBITS)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "key length=%d does not agree with extension length=%d.\n",
+ pfkey_key->sadb_key_bits,
+ pfkey_key->sadb_key_len);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_key->sadb_key_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_key->sadb_key_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if(! ( (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_AUTH) ||
+ (pfkey_key->sadb_key_exttype == SADB_EXT_KEY_ENCRYPT))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "expecting extension type AUTH or ENCRYPT, got %d.\n",
+ pfkey_key->sadb_key_exttype);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_key_parse: "
+ "success, found len=%d exttype=%d(%s) bits=%d reserved=%d.\n",
+ pfkey_key->sadb_key_len,
+ pfkey_key->sadb_key_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_key->sadb_key_exttype),
+ pfkey_key->sadb_key_bits,
+ pfkey_key->sadb_key_reserved);
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_ident_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_ident *pfkey_ident = (struct sadb_ident *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_ident->sadb_ident_len < sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_ident->sadb_ident_len,
+ (int)sizeof(struct sadb_ident));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_ident->sadb_ident_type > SADB_IDENTTYPE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "ident_type=%d out of range, must be less than %d.\n",
+ pfkey_ident->sadb_ident_type,
+ SADB_IDENTTYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_ident->sadb_ident_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_ident->sadb_ident_reserved);
+ SENDERR(EINVAL);
+ }
+
+ /* string terminator/padding must be zero */
+ if(pfkey_ident->sadb_ident_len > sizeof(struct sadb_ident) / IPSEC_PFKEYv2_ALIGN) {
+ if(*((char*)pfkey_ident + pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_ident_parse: "
+ "string padding must be zero, last is 0x%02x.\n",
+ *((char*)pfkey_ident +
+ pfkey_ident->sadb_ident_len * IPSEC_PFKEYv2_ALIGN - 1));
+ SENDERR(EINVAL);
+ }
+ }
+
+ if( ! ((pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_SRC) ||
+ (pfkey_ident->sadb_ident_exttype == SADB_EXT_IDENTITY_DST))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_key_parse: "
+ "expecting extension type IDENTITY_SRC or IDENTITY_DST, got %d.\n",
+ pfkey_ident->sadb_ident_exttype);
+ SENDERR(EINVAL);
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_sens_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_sens *pfkey_sens = (struct sadb_sens *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_sens->sadb_sens_len < sizeof(struct sadb_sens) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sens_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_sens->sadb_sens_len,
+ (int)sizeof(struct sadb_sens));
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_sens_parse: "
+ "Sorry, I can't parse exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+#if 0
+ SENDERR(EINVAL); /* don't process these yet */
+#endif
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_prop_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i, num_comb;
+ struct sadb_prop *pfkey_prop = (struct sadb_prop *)pfkey_ext;
+ struct sadb_comb *pfkey_comb = (struct sadb_comb *)((char*)pfkey_ext + sizeof(struct sadb_prop));
+
+ /* sanity checks... */
+ if((pfkey_prop->sadb_prop_len < sizeof(struct sadb_prop) / IPSEC_PFKEYv2_ALIGN) ||
+ (((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) % sizeof(struct sadb_comb))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "size wrong ext_len=%d, prop_ext_len=%d comb_ext_len=%d.\n",
+ pfkey_prop->sadb_prop_len,
+ (int)sizeof(struct sadb_prop),
+ (int)sizeof(struct sadb_comb));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_prop->sadb_prop_replay > 64) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "replay window size: %d -- must be 0 <= size <= 64\n",
+ pfkey_prop->sadb_prop_replay);
+ SENDERR(EINVAL);
+ }
+
+ for(i=0; i<3; i++) {
+ if(pfkey_prop->sadb_prop_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "res[%d]=%d, must be zero.\n",
+ i, pfkey_prop->sadb_prop_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+ num_comb = ((pfkey_prop->sadb_prop_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_prop)) / sizeof(struct sadb_comb);
+
+ for(i = 0; i < num_comb; i++) {
+ if(pfkey_comb->sadb_comb_auth > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth=%d > SADB_AALG_MAX=%d.\n",
+ i,
+ pfkey_comb->sadb_comb_auth,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_auth) {
+ if(!pfkey_comb->sadb_comb_auth_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(!pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_auth_minbits > pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d > maxbits=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_minbits,
+ pfkey_comb->sadb_comb_auth_maxbits);
+ SENDERR(EINVAL);
+ }
+ } else {
+ if(pfkey_comb->sadb_comb_auth_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_minbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_minbits);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_auth_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_auth_maxbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_auth_maxbits);
+ SENDERR(EINVAL);
+ }
+ }
+
+ if(pfkey_comb->sadb_comb_encrypt > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_comb_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt=%d > SADB_EALG_MAX=%d.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_encrypt) {
+ if(!pfkey_comb->sadb_comb_encrypt_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(!pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=0, fatal.\n",
+ i);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_encrypt_minbits > pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d > maxbits=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_minbits,
+ pfkey_comb->sadb_comb_encrypt_maxbits);
+ SENDERR(EINVAL);
+ }
+ } else {
+ if(pfkey_comb->sadb_comb_encrypt_minbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_minbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_minbits);
+ SENDERR(EINVAL);
+ }
+ if(pfkey_comb->sadb_comb_encrypt_maxbits) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_encrypt_maxbits=%d != 0, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_encrypt_maxbits);
+ SENDERR(EINVAL);
+ }
+ }
+
+ /* XXX do sanity check on flags */
+
+ if(pfkey_comb->sadb_comb_hard_allocations && pfkey_comb->sadb_comb_soft_allocations > pfkey_comb->sadb_comb_hard_allocations) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_allocations=%d > hard_allocations=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_comb_soft_allocations,
+ pfkey_comb->sadb_comb_hard_allocations);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_bytes && pfkey_comb->sadb_comb_soft_bytes > pfkey_comb->sadb_comb_hard_bytes) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_bytes=%Ld > hard_bytes=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_bytes,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_bytes);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_addtime && pfkey_comb->sadb_comb_soft_addtime > pfkey_comb->sadb_comb_hard_addtime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_addtime=%Ld > hard_addtime=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_addtime,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_addtime);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_hard_usetime && pfkey_comb->sadb_comb_soft_usetime > pfkey_comb->sadb_comb_hard_usetime) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_comb_soft_usetime=%Ld > hard_usetime=%Ld, fatal.\n",
+ i,
+ (unsigned long long int)pfkey_comb->sadb_comb_soft_usetime,
+ (unsigned long long int)pfkey_comb->sadb_comb_hard_usetime);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_x_comb_hard_packets && pfkey_comb->sadb_x_comb_soft_packets > pfkey_comb->sadb_x_comb_hard_packets) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "pfkey_comb[%d]->sadb_x_comb_soft_packets=%d > hard_packets=%d, fatal.\n",
+ i,
+ pfkey_comb->sadb_x_comb_soft_packets,
+ pfkey_comb->sadb_x_comb_hard_packets);
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_comb->sadb_comb_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_prop_parse: "
+ "comb[%d].res=%d, must be zero.\n",
+ i,
+ pfkey_comb->sadb_comb_reserved);
+ SENDERR(EINVAL);
+ }
+ pfkey_comb++;
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_supported_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ unsigned int i, num_alg;
+ struct sadb_supported *pfkey_supported = (struct sadb_supported *)pfkey_ext;
+ struct sadb_alg *pfkey_alg = (struct sadb_alg*)((char*)pfkey_ext + sizeof(struct sadb_supported));
+
+ /* sanity checks... */
+ if((pfkey_supported->sadb_supported_len <
+ sizeof(struct sadb_supported) / IPSEC_PFKEYv2_ALIGN) ||
+ (((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) -
+ sizeof(struct sadb_supported)) % sizeof(struct sadb_alg))) {
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "size wrong ext_len=%d, supported_ext_len=%d alg_ext_len=%d.\n",
+ pfkey_supported->sadb_supported_len,
+ (int)sizeof(struct sadb_supported),
+ (int)sizeof(struct sadb_alg));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_supported->sadb_supported_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "res=%d, must be zero.\n",
+ pfkey_supported->sadb_supported_reserved);
+ SENDERR(EINVAL);
+ }
+
+ num_alg = ((pfkey_supported->sadb_supported_len * IPSEC_PFKEYv2_ALIGN) - sizeof(struct sadb_supported)) / sizeof(struct sadb_alg);
+
+ for(i = 0; i < num_alg; i++) {
+ /* process algo description */
+ if(pfkey_alg->sadb_alg_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], id=%d, ivlen=%d, minbits=%d, maxbits=%d, res=%d, must be zero.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ pfkey_alg->sadb_alg_ivlen,
+ pfkey_alg->sadb_alg_minbits,
+ pfkey_alg->sadb_alg_maxbits,
+ pfkey_alg->sadb_alg_reserved);
+ SENDERR(EINVAL);
+ }
+
+ /* XXX can alg_id auth/enc be determined from info given?
+ Yes, but OpenBSD's method does not iteroperate with rfc2367.
+ rgb, 2000-04-06 */
+
+ switch(pfkey_supported->sadb_supported_exttype) {
+ case SADB_EXT_SUPPORTED_AUTH:
+ if(pfkey_alg->sadb_alg_id > SADB_AALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_AALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_AALG_MAX);
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_EXT_SUPPORTED_ENCRYPT:
+ if(pfkey_alg->sadb_alg_id > SADB_EALG_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+ break;
+ default:
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_supported_parse: "
+ "alg[%d], alg_id=%d > SADB_EALG_MAX=%d, fatal.\n",
+ i,
+ pfkey_alg->sadb_alg_id,
+ SADB_EALG_MAX);
+ SENDERR(EINVAL);
+ }
+ pfkey_alg++;
+ }
+
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_spirange_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_spirange *pfkey_spirange = (struct sadb_spirange *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_spirange->sadb_spirange_len !=
+ sizeof(struct sadb_spirange) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_spirange->sadb_spirange_len,
+ (int)sizeof(struct sadb_spirange));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_spirange->sadb_spirange_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "reserved=%d must be set to zero.\n",
+ pfkey_spirange->sadb_spirange_reserved);
+ SENDERR(EINVAL);
+ }
+
+ if(ntohl(pfkey_spirange->sadb_spirange_max) < ntohl(pfkey_spirange->sadb_spirange_min)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "minspi=%08x must be < maxspi=%08x.\n",
+ ntohl(pfkey_spirange->sadb_spirange_min),
+ ntohl(pfkey_spirange->sadb_spirange_max));
+ SENDERR(EINVAL);
+ }
+
+ if(ntohl(pfkey_spirange->sadb_spirange_min) <= 255) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_spirange_parse: "
+ "minspi=%08x must be > 255.\n",
+ ntohl(pfkey_spirange->sadb_spirange_min));
+ SENDERR(EEXIST);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_spirange_parse: "
+ "ext_len=%u ext_type=%u(%s) min=%u max=%u res=%u.\n",
+ pfkey_spirange->sadb_spirange_len,
+ pfkey_spirange->sadb_spirange_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_spirange->sadb_spirange_exttype),
+ pfkey_spirange->sadb_spirange_min,
+ pfkey_spirange->sadb_spirange_max,
+ pfkey_spirange->sadb_spirange_reserved);
+ errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_kmprivate_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_x_kmprivate *pfkey_x_kmprivate = (struct sadb_x_kmprivate *)pfkey_ext;
+
+ /* sanity checks... */
+ if(pfkey_x_kmprivate->sadb_x_kmprivate_len <
+ sizeof(struct sadb_x_kmprivate) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_kmprivate->sadb_x_kmprivate_len,
+ (int)sizeof(struct sadb_x_kmprivate));
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_x_kmprivate->sadb_x_kmprivate_reserved) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "reserved=%d must be set to zero.\n",
+ pfkey_x_kmprivate->sadb_x_kmprivate_reserved);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_kmprivate_parse: "
+ "Sorry, I can't parse exttype=%d yet.\n",
+ pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL); /* don't process these yet */
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_satype_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_satype *pfkey_x_satype = (struct sadb_x_satype *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_x_satype_parse: enter\n");
+ /* sanity checks... */
+ if(pfkey_x_satype->sadb_x_satype_len !=
+ sizeof(struct sadb_x_satype) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_satype->sadb_x_satype_len,
+ (int)sizeof(struct sadb_x_satype));
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_x_satype->sadb_x_satype_satype) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "satype is zero, must be non-zero.\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_x_satype->sadb_x_satype_satype > SADB_SATYPE_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "satype %d > max %d, invalid.\n",
+ pfkey_x_satype->sadb_x_satype_satype, SADB_SATYPE_MAX);
+ SENDERR(EINVAL);
+ }
+
+ if(!(satype2proto(pfkey_x_satype->sadb_x_satype_satype))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "proto lookup from satype=%d failed.\n",
+ pfkey_x_satype->sadb_x_satype_satype);
+ SENDERR(EINVAL);
+ }
+
+ for(i = 0; i < 3; i++) {
+ if(pfkey_x_satype->sadb_x_satype_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_satype_parse: "
+ "reserved[%d]=%d must be set to zero.\n",
+ i, pfkey_x_satype->sadb_x_satype_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_x_satype_parse: "
+ "len=%u ext=%u(%s) satype=%u(%s) res=%u,%u,%u.\n",
+ pfkey_x_satype->sadb_x_satype_len,
+ pfkey_x_satype->sadb_x_satype_exttype,
+ pfkey_v2_sadb_ext_string(pfkey_x_satype->sadb_x_satype_exttype),
+ pfkey_x_satype->sadb_x_satype_satype,
+ satype2name(pfkey_x_satype->sadb_x_satype_satype),
+ pfkey_x_satype->sadb_x_satype_reserved[0],
+ pfkey_x_satype->sadb_x_satype_reserved[1],
+ pfkey_x_satype->sadb_x_satype_reserved[2]);
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_debug_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ int i;
+ struct sadb_x_debug *pfkey_x_debug = (struct sadb_x_debug *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_x_debug_parse: enter\n");
+ /* sanity checks... */
+ if(pfkey_x_debug->sadb_x_debug_len !=
+ sizeof(struct sadb_x_debug) / IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_debug_parse: "
+ "size wrong ext_len=%d, key_ext_len=%d.\n",
+ pfkey_x_debug->sadb_x_debug_len,
+ (int)sizeof(struct sadb_x_debug));
+ SENDERR(EINVAL);
+ }
+
+ for(i = 0; i < 4; i++) {
+ if(pfkey_x_debug->sadb_x_debug_reserved[i]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_debug_parse: "
+ "reserved[%d]=%d must be set to zero.\n",
+ i, pfkey_x_debug->sadb_x_debug_reserved[i]);
+ SENDERR(EINVAL);
+ }
+ }
+
+errlab:
+ return error;
+}
+
+DEBUG_NO_STATIC int
+pfkey_x_ext_protocol_parse(struct sadb_ext *pfkey_ext)
+{
+ int error = 0;
+ struct sadb_protocol *p = (struct sadb_protocol *)pfkey_ext;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, "pfkey_x_protocol_parse:\n");
+ /* sanity checks... */
+
+ if (p->sadb_protocol_len != sizeof(*p)/IPSEC_PFKEYv2_ALIGN) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_x_protocol_parse: size wrong ext_len=%d, key_ext_len=%d.\n",
+ p->sadb_protocol_len, (int)sizeof(*p));
+ SENDERR(EINVAL);
+ }
+
+ if (p->sadb_protocol_reserved2 != 0) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_protocol_parse: res=%d, must be zero.\n",
+ p->sadb_protocol_reserved2);
+ SENDERR(EINVAL);
+ }
+
+ errlab:
+ return error;
+}
+
+#ifdef NAT_TRAVERSAL
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_type_parse(struct sadb_ext *pfkey_ext)
+{
+ return 0;
+}
+DEBUG_NO_STATIC int
+pfkey_x_ext_nat_t_port_parse(struct sadb_ext *pfkey_ext)
+{
+ return 0;
+}
+#endif
+
+#define DEFINEPARSER(NAME) static struct pf_key_ext_parsers_def NAME##_def={NAME, #NAME};
+
+DEFINEPARSER(pfkey_sa_parse);
+DEFINEPARSER(pfkey_lifetime_parse);
+DEFINEPARSER(pfkey_address_parse);
+DEFINEPARSER(pfkey_key_parse);
+DEFINEPARSER(pfkey_ident_parse);
+DEFINEPARSER(pfkey_sens_parse);
+DEFINEPARSER(pfkey_prop_parse);
+DEFINEPARSER(pfkey_supported_parse);
+DEFINEPARSER(pfkey_spirange_parse);
+DEFINEPARSER(pfkey_x_kmprivate_parse);
+DEFINEPARSER(pfkey_x_satype_parse);
+DEFINEPARSER(pfkey_x_ext_debug_parse);
+DEFINEPARSER(pfkey_x_ext_protocol_parse);
+#ifdef NAT_TRAVERSAL
+DEFINEPARSER(pfkey_x_ext_nat_t_type_parse);
+DEFINEPARSER(pfkey_x_ext_nat_t_port_parse);
+#endif
+
+struct pf_key_ext_parsers_def *ext_default_parsers[]=
+{
+ NULL, /* pfkey_msg_parse, */
+ &pfkey_sa_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_lifetime_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_key_parse_def,
+ &pfkey_key_parse_def,
+ &pfkey_ident_parse_def,
+ &pfkey_ident_parse_def,
+ &pfkey_sens_parse_def,
+ &pfkey_prop_parse_def,
+ &pfkey_supported_parse_def,
+ &pfkey_supported_parse_def,
+ &pfkey_spirange_parse_def,
+ &pfkey_x_kmprivate_parse_def,
+ &pfkey_x_satype_parse_def,
+ &pfkey_sa_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_address_parse_def,
+ &pfkey_x_ext_debug_parse_def,
+ &pfkey_x_ext_protocol_parse_def
+#ifdef NAT_TRAVERSAL
+ ,
+ &pfkey_x_ext_nat_t_type_parse_def,
+ &pfkey_x_ext_nat_t_port_parse_def,
+ &pfkey_x_ext_nat_t_port_parse_def,
+ &pfkey_address_parse_def
+#endif
+};
+
+int
+pfkey_msg_parse(struct sadb_msg *pfkey_msg,
+ struct pf_key_ext_parsers_def *ext_parsers[],
+ struct sadb_ext *extensions[],
+ int dir)
+{
+ int error = 0;
+ int remain;
+ struct sadb_ext *pfkey_ext;
+ int extensions_seen = 0;
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "parsing message ver=%d, type=%d(%s), errno=%d, satype=%d(%s), len=%d, res=%d, seq=%d, pid=%d.\n",
+ pfkey_msg->sadb_msg_version,
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type),
+ pfkey_msg->sadb_msg_errno,
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_len,
+ pfkey_msg->sadb_msg_reserved,
+ pfkey_msg->sadb_msg_seq,
+ pfkey_msg->sadb_msg_pid);
+
+ if(ext_parsers == NULL) ext_parsers = ext_default_parsers;
+
+ pfkey_extensions_init(extensions);
+
+ remain = pfkey_msg->sadb_msg_len;
+ remain -= sizeof(struct sadb_msg) / IPSEC_PFKEYv2_ALIGN;
+
+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_msg +
+ sizeof(struct sadb_msg));
+
+ extensions[0] = (struct sadb_ext *) pfkey_msg;
+
+
+ if(pfkey_msg->sadb_msg_version != PF_KEY_V2) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "not PF_KEY_V2 msg, found %d, should be %d.\n",
+ pfkey_msg->sadb_msg_version,
+ PF_KEY_V2);
+ SENDERR(EINVAL);
+ }
+
+ if(!pfkey_msg->sadb_msg_type) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "msg type not set, must be non-zero..\n");
+ SENDERR(EINVAL);
+ }
+
+ if(pfkey_msg->sadb_msg_type > SADB_MAX) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "msg type=%d > max=%d.\n",
+ pfkey_msg->sadb_msg_type,
+ SADB_MAX);
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_GETSPI:
+ case SADB_UPDATE:
+ case SADB_ADD:
+ case SADB_DELETE:
+ case SADB_GET:
+ case SADB_X_GRPSA:
+ case SADB_X_ADDFLOW:
+ if(!satype2proto(pfkey_msg->sadb_msg_satype)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype %d conversion to proto failed for msg_type %d (%s).\n",
+ pfkey_msg->sadb_msg_satype,
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ SENDERR(EINVAL);
+ } else {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype %d(%s) conversion to proto gives %d for msg_type %d(%s).\n",
+ pfkey_msg->sadb_msg_satype,
+ satype2name(pfkey_msg->sadb_msg_satype),
+ satype2proto(pfkey_msg->sadb_msg_satype),
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ }
+ case SADB_ACQUIRE:
+ case SADB_REGISTER:
+ case SADB_EXPIRE:
+ if(!pfkey_msg->sadb_msg_satype) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "satype is zero, must be non-zero for msg_type %d(%s).\n",
+ pfkey_msg->sadb_msg_type,
+ pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type));
+ SENDERR(EINVAL);
+ }
+ default:
+ break;
+ }
+
+ /* errno must not be set in downward messages */
+ /* this is not entirely true... a response to an ACQUIRE could return an error */
+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type != SADB_ACQUIRE) && pfkey_msg->sadb_msg_errno) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "errno set to %d.\n",
+ pfkey_msg->sadb_msg_errno);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "remain=%d, ext_type=%d(%s), ext_len=%d.\n",
+ remain,
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ pfkey_ext->sadb_ext_len);
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "extensions permitted=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
+
+ extensions_seen = 1;
+
+ while( (remain * IPSEC_PFKEYv2_ALIGN) >= sizeof(struct sadb_ext) ) {
+ /* Is there enough message left to support another extension header? */
+ if(remain < pfkey_ext->sadb_ext_len) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "remain %d less than ext len %d.\n",
+ remain, pfkey_ext->sadb_ext_len);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "parsing ext type=%d(%s) remain=%d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ remain);
+
+ /* Is the extension header type valid? */
+ if((pfkey_ext->sadb_ext_type > SADB_EXT_MAX) || (!pfkey_ext->sadb_ext_type)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) invalid, SADB_EXT_MAX=%d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ SADB_EXT_MAX);
+ SENDERR(EINVAL);
+ }
+
+ /* Have we already seen this type of extension? */
+ if((extensions_seen & ( 1 << pfkey_ext->sadb_ext_type )) != 0)
+ {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) already seen.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+ SENDERR(EINVAL);
+ }
+
+ /* Do I even know about this type of extension? */
+ if(ext_parsers[pfkey_ext->sadb_ext_type]==NULL) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) unknown, ignoring.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+ goto next_ext;
+ }
+
+ /* Is this type of extension permitted for this type of message? */
+ if(!(extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type] &
+ 1<<pfkey_ext->sadb_ext_type)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ext type %d(%s) not permitted, exts_perm_in=%08x, 1<<type=%08x\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ 1<<pfkey_ext->sadb_ext_type);
+ SENDERR(EINVAL);
+ }
+
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "remain=%d ext_type=%d(%s) ext_len=%d parsing ext 0p%p with parser %s.\n",
+ remain,
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ pfkey_ext->sadb_ext_len,
+ pfkey_ext,
+ ext_parsers[pfkey_ext->sadb_ext_type]->parser_name);
+
+ /* Parse the extension */
+ if((error =
+ (*ext_parsers[pfkey_ext->sadb_ext_type]->parser)(pfkey_ext))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "extension parsing for type %d(%s) failed with error %d.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type),
+ error);
+ SENDERR(-error);
+ }
+ DEBUGGING(PF_KEY_DEBUG_PARSE_FLOW,
+ "pfkey_msg_parse: "
+ "Extension %d(%s) parsed.\n",
+ pfkey_ext->sadb_ext_type,
+ pfkey_v2_sadb_ext_string(pfkey_ext->sadb_ext_type));
+
+ /* Mark that we have seen this extension and remember the header location */
+ extensions_seen |= ( 1 << pfkey_ext->sadb_ext_type );
+ extensions[pfkey_ext->sadb_ext_type] = pfkey_ext;
+
+ next_ext:
+ /* Calculate how much message remains */
+ remain -= pfkey_ext->sadb_ext_len;
+
+ if(!remain) {
+ break;
+ }
+ /* Find the next extension header */
+ pfkey_ext = (struct sadb_ext*)((char*)pfkey_ext +
+ pfkey_ext->sadb_ext_len * IPSEC_PFKEYv2_ALIGN);
+ }
+
+ if(remain) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "unexpected remainder of %d.\n",
+ remain);
+ /* why is there still something remaining? */
+ SENDERR(EINVAL);
+ }
+
+ /* check required extensions */
+ DEBUGGING(PF_KEY_DEBUG_PARSE_STRUCT,
+ "pfkey_msg_parse: "
+ "extensions permitted=%08x, seen=%08x, required=%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_PERM][pfkey_msg->sadb_msg_type],
+ extensions_seen,
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]);
+
+ /* don't check further if it is an error return message since it
+ may not have a body */
+ if(pfkey_msg->sadb_msg_errno) {
+ SENDERR(-error);
+ }
+
+ if((extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) !=
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "required extensions missing:%08x.\n",
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type] -
+ (extensions_seen &
+ extensions_bitmaps[dir][EXT_BITS_REQ][pfkey_msg->sadb_msg_type]));
+ SENDERR(EINVAL);
+ }
+
+ if((dir == EXT_BITS_IN) && (pfkey_msg->sadb_msg_type == SADB_X_DELFLOW)
+ && ((extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW)
+ != SADB_X_EXT_ADDRESS_DELFLOW)
+ && (((extensions_seen & (1<<SADB_EXT_SA)) != (1<<SADB_EXT_SA))
+ || ((((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_flags
+ & SADB_X_SAFLAGS_CLEARFLOW)
+ != SADB_X_SAFLAGS_CLEARFLOW))) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "required SADB_X_DELFLOW extensions missing: either %08x must be present or %08x must be present with SADB_X_SAFLAGS_CLEARFLOW set.\n",
+ SADB_X_EXT_ADDRESS_DELFLOW
+ - (extensions_seen & SADB_X_EXT_ADDRESS_DELFLOW),
+ (1<<SADB_EXT_SA) - (extensions_seen & (1<<SADB_EXT_SA)));
+ SENDERR(EINVAL);
+ }
+
+ switch(pfkey_msg->sadb_msg_type) {
+ case SADB_ADD:
+ case SADB_UPDATE:
+ /* check maturity */
+ if(((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state !=
+ SADB_SASTATE_MATURE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "state=%d for add or update should be MATURE=%d.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_state,
+ SADB_SASTATE_MATURE);
+ SENDERR(EINVAL);
+ }
+
+ /* check AH and ESP */
+ switch(((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype) {
+ case SADB_SATYPE_AH:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_auth !=
+ SADB_AALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "auth alg is zero, must be non-zero for AH SAs.\n");
+ SENDERR(EINVAL);
+ }
+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt !=
+ SADB_EALG_NONE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "AH handed encalg=%d, must be zero.\n",
+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt);
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_SATYPE_ESP:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
+ SADB_EALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "encrypt alg=%d is zero, must be non-zero for ESP=%d SAs.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+ if((((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_encrypt ==
+ SADB_EALG_NULL) &&
+ (((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth ==
+ SADB_AALG_NONE) ) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "ESP handed encNULL+authNONE, illegal combination.\n");
+ SENDERR(EINVAL);
+ }
+ break;
+ case SADB_X_SATYPE_COMP:
+ if(!(((struct sadb_sa*)extensions[SADB_EXT_SA]) &&
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt !=
+ SADB_EALG_NONE)) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "encrypt alg=%d is zero, must be non-zero for COMP=%d SAs.\n",
+ ((struct sadb_sa*)extensions[SADB_EXT_SA])->sadb_sa_encrypt,
+ ((struct sadb_msg*)extensions[SADB_EXT_RESERVED])->sadb_msg_satype);
+ SENDERR(EINVAL);
+ }
+ if(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth !=
+ SADB_AALG_NONE) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "COMP handed auth=%d, must be zero.\n",
+ ((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_auth);
+ SENDERR(EINVAL);
+ }
+ break;
+ default:
+ break;
+ }
+ if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) {
+ DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM,
+ "pfkey_msg_parse: "
+ "spi=%08x must be > 255.\n",
+ ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi));
+ SENDERR(EINVAL);
+ }
+ default:
+ break;
+ }
+errlab:
+
+ return error;
+}
+
+/*
+ * $Log: pfkey_v2_parse.c,v $
+ * Revision 1.4 2004/06/13 20:35:07 as
+ * removed references to ipsec_netlink.h
+ *
+ * Revision 1.3 2004/03/30 10:00:17 as
+ * 64 bit issues
+ *
+ * Revision 1.2 2004/03/22 21:53:18 as
+ * merged alg-0.8.1 branch with HEAD
+ *
+ * Revision 1.1.2.1 2004/03/15 22:30:06 as
+ * nat-0.6c patch merged
+ *
+ * Revision 1.1 2004/03/15 20:35:26 as
+ * added files from freeswan-2.04-x509-1.5.3
+ *
+ * Revision 1.53 2003/01/30 02:32:09 rgb
+ *
+ * Rename SAref table macro names for clarity.
+ * Convert IPsecSAref_t from signed to unsigned to fix apparent SAref exhaustion bug.
+ *
+ * Revision 1.52 2002/12/30 06:53:07 mcr
+ * deal with short SA structures... #if 0 out for now. Probably
+ * not quite the right way.
+ *
+ * Revision 1.51 2002/12/13 18:16:02 mcr
+ * restored sa_ref code
+ *
+ * Revision 1.50 2002/12/13 18:06:52 mcr
+ * temporarily removed sadb_x_sa_ref reference for 2.xx
+ *
+ * Revision 1.49 2002/10/05 05:02:58 dhr
+ *
+ * C labels go on statements
+ *
+ * Revision 1.48 2002/09/20 15:40:45 rgb
+ * Added sadb_x_sa_ref to struct sadb_sa.
+ *
+ * Revision 1.47 2002/09/20 05:01:31 rgb
+ * Fixed usage of pfkey_lib_debug.
+ * Format for function declaration style consistency.
+ * Added text labels to elucidate numeric values presented.
+ * Re-organised debug output to reduce noise in output.
+ *
+ * Revision 1.46 2002/07/24 18:44:54 rgb
+ * Type fiddling to tame ia64 compiler.
+ *
+ * Revision 1.45 2002/05/23 07:14:11 rgb
+ * Cleaned up %p variants to 0p%p for test suite cleanup.
+ *
+ * Revision 1.44 2002/04/24 07:55:32 mcr
+ * #include patches and Makefiles for post-reorg compilation.
+ *
+ * Revision 1.43 2002/04/24 07:36:40 mcr
+ * Moved from ./lib/pfkey_v2_parse.c,v
+ *
+ * Revision 1.42 2002/01/29 22:25:36 rgb
+ * Re-add ipsec_kversion.h to keep MALLOC happy.
+ *
+ * Revision 1.41 2002/01/29 01:59:10 mcr
+ * removal of kversions.h - sources that needed it now use ipsec_param.h.
+ * updating of IPv6 structures to match latest in6.h version.
+ * removed dead code from freeswan.h that also duplicated kversions.h
+ * code.
+ *
+ * Revision 1.40 2002/01/20 20:34:50 mcr
+ * added pfkey_v2_sadb_type_string to decode sadb_type to string.
+ *
+ * Revision 1.39 2001/11/27 05:29:22 mcr
+ * pfkey parses are now maintained by a structure
+ * that includes their name for debug purposes.
+ * DEBUGGING() macro changed so that it takes a debug
+ * level so that pf_key() can use this to decode the
+ * structures without innundanting humans.
+ * Also uses pfkey_v2_sadb_ext_string() in messages.
+ *
+ * Revision 1.38 2001/11/06 19:47:47 rgb
+ * Added packet parameter to lifetime and comb structures.
+ *
+ * Revision 1.37 2001/10/18 04:45:24 rgb
+ * 2.4.9 kernel deprecates linux/malloc.h in favour of linux/slab.h,
+ * lib/freeswan.h version macros moved to lib/kversions.h.
+ * Other compiler directive cleanups.
+ *
+ * Revision 1.36 2001/06/14 19:35:16 rgb
+ * Update copyright date.
+ *
+ * Revision 1.35 2001/05/03 19:44:51 rgb
+ * Standardise on SENDERR() macro.
+ *
+ * Revision 1.34 2001/03/16 07:41:51 rgb
+ * Put freeswan.h include before pluto includes.
+ *
+ * Revision 1.33 2001/02/27 07:13:51 rgb
+ * Added satype2name() function.
+ * Added text to default satype_tbl entry.
+ * Added satype2name() conversions for most satype debug output.
+ *
+ * Revision 1.32 2001/02/26 20:01:09 rgb
+ * Added internal IP protocol 61 for magic SAs.
+ * Ditch unused sadb_satype2proto[], replaced by satype2proto().
+ * Re-formatted debug output (split lines, consistent spacing).
+ * Removed acquire, register and expire requirements for a known satype.
+ * Changed message type checking to a switch structure.
+ * Verify expected NULL auth for IPCOMP.
+ * Enforced spi > 0x100 requirement, now that pass uses a magic SA for
+ * appropriate message types.
+ *
+ * Revision 1.31 2000/12/01 07:09:00 rgb
+ * Added ipcomp sanity check to require encalgo is set.
+ *
+ * Revision 1.30 2000/11/17 18:10:30 rgb
+ * Fixed bugs mostly relating to spirange, to treat all spi variables as
+ * network byte order since this is the way PF_KEYv2 stored spis.
+ *
+ * Revision 1.29 2000/10/12 00:02:39 rgb
+ * Removed 'format, ##' nonsense from debug macros for RH7.0.
+ *
+ * Revision 1.28 2000/09/20 16:23:04 rgb
+ * Remove over-paranoid extension check in the presence of sadb_msg_errno.
+ *
+ * Revision 1.27 2000/09/20 04:04:21 rgb
+ * Changed static functions to DEBUG_NO_STATIC to reveal function names in
+ * oopsen.
+ *
+ * Revision 1.26 2000/09/15 11:37:02 rgb
+ * Merge in heavily modified Svenning Soerensen's <svenning@post5.tele.dk>
+ * IPCOMP zlib deflate code.
+ *
+ * Revision 1.25 2000/09/12 22:35:37 rgb
+ * Restructured to remove unused extensions from CLEARFLOW messages.
+ *
+ * Revision 1.24 2000/09/12 18:59:54 rgb
+ * Added Gerhard's IPv6 support to pfkey parts of libfreeswan.
+ *
+ * Revision 1.23 2000/09/12 03:27:00 rgb
+ * Moved DEBUGGING definition to compile kernel with debug off.
+ *
+ * Revision 1.22 2000/09/09 06:39:27 rgb
+ * Restrict pfkey errno check to downward messages only.
+ *
+ * Revision 1.21 2000/09/08 19:22:34 rgb
+ * Enabled pfkey_sens_parse().
+ * Added check for errno on downward acquire messages only.
+ *
+ * Revision 1.20 2000/09/01 18:48:23 rgb
+ * Fixed reserved check bug and added debug output in
+ * pfkey_supported_parse().
+ * Fixed debug output label bug in pfkey_ident_parse().
+ *
+ * Revision 1.19 2000/08/27 01:55:26 rgb
+ * Define OCTETBITS and PFKEYBITS to avoid using 'magic' numbers in code.
+ *
+ * Revision 1.18 2000/08/24 17:00:36 rgb
+ * Ignore unknown extensions instead of failing.
+ *
+ * Revision 1.17 2000/06/02 22:54:14 rgb
+ * Added Gerhard Gessler's struct sockaddr_storage mods for IPv6 support.
+ *
+ * Revision 1.16 2000/05/10 19:25:11 rgb
+ * Fleshed out proposal and supported extensions.
+ *
+ * Revision 1.15 2000/01/24 21:15:31 rgb
+ * Added disabled pluto pfkey lib debug flag.
+ * Added algo debugging reporting.
+ *
+ * Revision 1.14 2000/01/22 23:24:29 rgb
+ * Added new functions proto2satype() and satype2proto() and lookup
+ * table satype_tbl. Also added proto2name() since it was easy.
+ *
+ * Revision 1.13 2000/01/21 09:43:59 rgb
+ * Cast ntohl(spi) as (unsigned long int) to shut up compiler.
+ *
+ * Revision 1.12 2000/01/21 06:28:19 rgb
+ * Added address cases for eroute flows.
+ * Indented compiler directives for readability.
+ * Added klipsdebug switching capability.
+ *
+ * Revision 1.11 1999/12/29 21:14:59 rgb
+ * Fixed debug text cut and paste typo.
+ *
+ * Revision 1.10 1999/12/10 17:45:24 rgb
+ * Added address debugging.
+ *
+ * Revision 1.9 1999/12/09 23:11:42 rgb
+ * Ditched <string.h> include since we no longer use memset().
+ * Use new pfkey_extensions_init() instead of memset().
+ * Added check for SATYPE in pfkey_msg_build().
+ * Tidy up comments and debugging comments.
+ *
+ * Revision 1.8 1999/12/07 19:55:26 rgb
+ * Removed unused first argument from extension parsers.
+ * Removed static pluto debug flag.
+ * Moved message type and state checking to pfkey_msg_parse().
+ * Changed print[fk] type from lx to x to quiet compiler.
+ * Removed redundant remain check.
+ * Changed __u* types to uint* to avoid use of asm/types.h and
+ * sys/types.h in userspace code.
+ *
+ * Revision 1.7 1999/12/01 22:20:51 rgb
+ * Moved pfkey_lib_debug variable into the library.
+ * Added pfkey version check into header parsing.
+ * Added check for SATYPE only for those extensions that require a
+ * non-zero value.
+ *
+ * Revision 1.6 1999/11/27 11:58:05 rgb
+ * Added ipv6 headers.
+ * Moved sadb_satype2proto protocol lookup table from
+ * klips/net/ipsec/pfkey_v2_parser.c.
+ * Enable lifetime_current checking.
+ * Debugging error messages added.
+ * Add argument to pfkey_msg_parse() for direction.
+ * Consolidated the 4 1-d extension bitmap arrays into one 4-d array.
+ * Add CVS log entry to bottom of file.
+ * Moved auth and enc alg check to pfkey_msg_parse().
+ * Enable accidentally disabled spirange parsing.
+ * Moved protocol/algorithm checks from klips/net/ipsec/pfkey_v2_parser.c
+ *
+ * Local variables:
+ * c-file-style: "linux"
+ * End:
+ *
+ */
diff --git a/linux/lib/libfreeswan/portof.3 b/linux/lib/libfreeswan/portof.3
new file mode 100644
index 000000000..fac0d8bc3
--- /dev/null
+++ b/linux/lib/libfreeswan/portof.3
@@ -0,0 +1,70 @@
+.TH IPSEC_PORTOF 3 "8 Sept 2000"
+.\" RCSID $Id: portof.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec portof \- get port field of an ip_address
+.br
+ipsec setportof \- set port field of an ip_address
+.br
+ipsec sockaddrof \- get pointer to internal sockaddr of an ip_address
+.br
+ipsec sockaddrlenof \- get length of internal sockaddr of an ip_address
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "int portof(const ip_address *src);"
+.br
+.B "void setportof(int port, ip_address *dst);"
+.br
+.B "struct sockaddr *sockaddrof(ip_address *src);"
+.br
+.B "size_t sockaddrlenof(const ip_address *src);"
+.SH DESCRIPTION
+The
+.B <freeswan.h>
+internal type
+.I ip_address
+contains one of the
+.I sockaddr
+types internally.
+\fIReliance on this feature is discouraged\fR,
+but it may occasionally be necessary.
+These functions provide low-level tools for this purpose.
+.PP
+.I Portof
+and
+.I setportof
+respectively read and write the port-number field of the internal
+.IR sockaddr .
+The values are in network byte order.
+.PP
+.I Sockaddrof
+returns a pointer to the internal
+.IR sockaddr ,
+for passing to other functions.
+.PP
+.I Sockaddrlenof
+reports the size of the internal
+.IR sockaddr ,
+for use in storage allocation.
+.SH SEE ALSO
+inet(3), ipsec_initaddr(3)
+.SH DIAGNOSTICS
+.I Portof
+returns
+.BR \-1 ,
+.I sockaddrof
+returns
+.BR NULL ,
+and
+.I sockaddrlenof
+returns
+.B 0
+if an unknown address family is found within the
+.IR ip_address .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+These functions all depend on low-level details of the
+.I ip_address
+type, which are in principle subject to change.
+Avoid using them unless really necessary.
diff --git a/linux/lib/libfreeswan/portof.c b/linux/lib/libfreeswan/portof.c
new file mode 100644
index 000000000..d028ea034
--- /dev/null
+++ b/linux/lib/libfreeswan/portof.c
@@ -0,0 +1,96 @@
+/*
+ * low-level ip_address ugliness
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: portof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - portof - get the port field of an ip_address
+ */
+int /* network order */
+portof(src)
+const ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return src->u.v4.sin_port;
+ break;
+ case AF_INET6:
+ return src->u.v6.sin6_port;
+ break;
+ default:
+ return -1; /* "can't happen" */
+ break;
+ }
+}
+
+/*
+ - setportof - set the port field of an ip_address
+ */
+void
+setportof(port, dst)
+int port; /* network order */
+ip_address *dst;
+{
+ switch (dst->u.v4.sin_family) {
+ case AF_INET:
+ dst->u.v4.sin_port = port;
+ break;
+ case AF_INET6:
+ dst->u.v6.sin6_port = port;
+ break;
+ }
+}
+
+/*
+ - sockaddrof - get a pointer to the sockaddr hiding inside an ip_address
+ */
+struct sockaddr *
+sockaddrof(src)
+ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return (struct sockaddr *)&src->u.v4;
+ break;
+ case AF_INET6:
+ return (struct sockaddr *)&src->u.v6;
+ break;
+ default:
+ return NULL; /* "can't happen" */
+ break;
+ }
+}
+
+/*
+ - sockaddrlenof - get length of the sockaddr hiding inside an ip_address
+ */
+size_t /* 0 for error */
+sockaddrlenof(src)
+const ip_address *src;
+{
+ switch (src->u.v4.sin_family) {
+ case AF_INET:
+ return sizeof(src->u.v4);
+ break;
+ case AF_INET6:
+ return sizeof(src->u.v6);
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
diff --git a/linux/lib/libfreeswan/prng.3 b/linux/lib/libfreeswan/prng.3
new file mode 100644
index 000000000..51f19364f
--- /dev/null
+++ b/linux/lib/libfreeswan/prng.3
@@ -0,0 +1,121 @@
+.TH IPSEC_PRNG 3 "1 April 2002"
+.\" RCSID $Id: prng.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec prng_init \- initialize IPsec pseudorandom-number generator
+.br
+ipsec prng_bytes \- get bytes from IPsec pseudorandom-number generator
+.br
+ipsec prng_final \- close down IPsec pseudorandom-number generator
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "void prng_init(struct prng *prng,"
+.ti +1c
+.B "const unsigned char *key, size_t keylen);"
+.br
+.B "void prng_bytes(struct prng *prng, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.br
+.B "unsigned long prng_count(struct prng *prng);"
+.br
+.B "void prng_final(struct prng *prng);"
+.SH DESCRIPTION
+.I Prng_init
+initializes a crypto-quality pseudo-random-number generator from a key;
+.I prng_bytes
+obtains pseudo-random bytes from it;
+.I prng_count
+reports the number of bytes extracted from it to date;
+.I prng_final
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+.PP
+.I Prng_init
+initializes,
+or re-initializes,
+the specified
+.I prng
+from the
+.IR key ,
+whose length is given by
+.IR keylen .
+The user must allocate the
+.B "struct prng"
+pointed to by
+.IR prng .
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+.PP
+.I Prng_bytes
+obtains
+.I dstlen
+pseudo-random bytes from the PRNG and puts them in
+.IR buf .
+This is quite fast,
+on the order of 10 integer operations per byte.
+.PP
+.I Prng_count
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+.PP
+.I Prng_final
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+.PP
+The
+.B <freeswan.h>
+header file supplies the definition of the
+.B prng
+structure.
+Examination of its innards is discouraged, as they may change.
+.PP
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+.IR random (4)).
+The usual run of software pseudo-random-number generators
+(e.g.
+.IR random (3))
+are
+.I not
+cryptographically strong.
+.PP
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+.SH SEE ALSO
+random(3), random(4)
+.br
+Bruce Schneier,
+\fIApplied Cryptography\fR, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+.IR prng_count 's
+output will stick at
+.BR 4000000000 .
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+.PP
+``RC4'' is a trademark of RSA Data Security, Inc.
diff --git a/linux/lib/libfreeswan/prng.c b/linux/lib/libfreeswan/prng.c
new file mode 100644
index 000000000..e31836783
--- /dev/null
+++ b/linux/lib/libfreeswan/prng.c
@@ -0,0 +1,202 @@
+/*
+ * crypto-class pseudorandom number generator
+ * currently uses same algorithm as RC4(TM), from Schneier 2nd ed p397
+ * Copyright (C) 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: prng.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - prng_init - initialize PRNG from a key
+ */
+void
+prng_init(prng, key, keylen)
+struct prng *prng;
+const unsigned char *key;
+size_t keylen;
+{
+ unsigned char k[256];
+ int i, j;
+ unsigned const char *p;
+ unsigned const char *keyend = key + keylen;
+ unsigned char t;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = i;
+ p = key;
+ for (i = 0; i <= 255; i++) {
+ k[i] = *p++;
+ if (p >= keyend)
+ p = key;
+ }
+ j = 0;
+ for (i = 0; i <= 255; i++) {
+ j = (j + prng->sbox[i] + k[i]) & 0xff;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ k[i] = 0; /* clear out key memory */
+ }
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0;
+}
+
+/*
+ - prng_bytes - get some pseudorandom bytes from PRNG
+ */
+void
+prng_bytes(prng, dst, dstlen)
+struct prng *prng;
+unsigned char *dst;
+size_t dstlen;
+{
+ int i, j, t;
+ unsigned char *p = dst;
+ size_t remain = dstlen;
+# define MAX 4000000000ul
+
+ while (remain > 0) {
+ i = (prng->i + 1) & 0xff;
+ prng->i = i;
+ j = (prng->j + prng->sbox[i]) & 0xff;
+ prng->j = j;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ t = (t + prng->sbox[i]) & 0xff;
+ *p++ = prng->sbox[t];
+ remain--;
+ }
+ if (prng->count < MAX - dstlen)
+ prng->count += dstlen;
+ else
+ prng->count = MAX;
+}
+
+/*
+ - prnt_count - how many bytes have been extracted from PRNG so far?
+ */
+unsigned long
+prng_count(prng)
+struct prng *prng;
+{
+ return prng->count;
+}
+
+/*
+ - prng_final - clear out PRNG to ensure nothing left in memory
+ */
+void
+prng_final(prng)
+struct prng *prng;
+{
+ int i;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = 0;
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0; /* just for good measure */
+}
+
+
+
+#ifdef PRNG_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {key|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ prng_init(&pr, argv[1], strlen(argv[1]));
+ prng_bytes(&pr, buf, 32);
+ printf("0x");
+ for (p = buf, n = 32; n > 0; p++, n--)
+ printf("%02x", *p);
+ printf("\n%lu bytes\n", prng_count(&pr));
+ prng_final(&pr);
+ exit(0);
+}
+
+void
+regress()
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+ /* somewhat non-random sample key */
+ unsigned char key[] = "here we go gathering nuts in May";
+ /* first thirty bytes of output from that key */
+ unsigned char good[] = "\x3f\x02\x8e\x4a\x2a\xea\x23\x18\x92\x7c"
+ "\x09\x52\x83\x61\xaa\x26\xce\xbb\x9d\x71"
+ "\x71\xe5\x10\x22\xaf\x60\x54\x8d\x5b\x28";
+ int nzero, none;
+ int show = 0;
+
+ prng_init(&pr, key, strlen(key));
+ prng_bytes(&pr, buf, sizeof(buf));
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--) {
+ if (*p == 0)
+ nzero++;
+ if (*p == 255)
+ none++;
+ }
+ if (nzero > 3 || none > 3) {
+ fprintf(stderr, "suspiciously non-random output!\n");
+ show = 1;
+ }
+ if (memcmp(buf, good, strlen(good)) != 0) {
+ fprintf(stderr, "incorrect output!\n");
+ show = 1;
+ }
+ if (show) {
+ fprintf(stderr, "0x");
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--)
+ fprintf(stderr, "%02x", *p);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+ if (prng_count(&pr) != sizeof(buf)) {
+ fprintf(stderr, "got %u bytes, but count is %lu\n",
+ sizeof(buf), prng_count(&pr));
+ exit(1);
+ }
+ prng_final(&pr);
+ exit(0);
+}
+
+#endif /* PRNG_MAIN */
diff --git a/linux/lib/libfreeswan/rangetoa.c b/linux/lib/libfreeswan/rangetoa.c
new file mode 100644
index 000000000..e63b432f8
--- /dev/null
+++ b/linux/lib/libfreeswan/rangetoa.c
@@ -0,0 +1,61 @@
+/*
+ * convert binary form of address range to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: rangetoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - rangetoa - convert address range to ASCII
+ */
+size_t /* space needed for full conversion */
+rangetoa(addrs, format, dst, dstlen)
+struct in_addr addrs[2];
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ int n;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtoa(addrs[0], 0, dst, dstlen);
+ if (len < dstlen)
+ for (p = dst + len - 1, n = 3; len < dstlen && n > 0;
+ p++, len++, n--)
+ *p = '.';
+ else
+ p = NULL;
+ if (len < dstlen)
+ rest = dstlen - len;
+ else {
+ if (dstlen > 0)
+ *(dst + dstlen - 1) = '\0';
+ rest = 0;
+ }
+
+ len += addrtoa(addrs[1], 0, p, rest);
+
+ return len;
+}
diff --git a/linux/lib/libfreeswan/rangetosubnet.3 b/linux/lib/libfreeswan/rangetosubnet.3
new file mode 100644
index 000000000..7d707545e
--- /dev/null
+++ b/linux/lib/libfreeswan/rangetosubnet.3
@@ -0,0 +1,59 @@
+.TH IPSEC_RANGETOSUBNET 3 "8 Sept 2000"
+.\" RCSID $Id: rangetosubnet.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec rangetosubnet \- convert address range to subnet
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *rangetosubnet(const ip_address *start,"
+.ti +1c
+.B "const ip_address *stop, ip_subnet *dst);"
+.SH DESCRIPTION
+.I Rangetosubnet
+accepts two IP addresses which define an address range,
+from
+.I start
+to
+.I stop
+inclusive,
+and converts this to a subnet if possible.
+The addresses must both be IPv4 or both be IPv6,
+and the address family of the resulting subnet is the same.
+.PP
+.I Rangetosubnet
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.SH SEE ALSO
+ipsec_initsubnet(3), ipsec_ttosubnet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I rangetosubnet
+are:
+mixed address families;
+unknown address family;
+.I start
+and
+.I stop
+do not define a subnet.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = rangetosubnet( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/rangetosubnet.c b/linux/lib/libfreeswan/rangetosubnet.c
new file mode 100644
index 000000000..048b10556
--- /dev/null
+++ b/linux/lib/libfreeswan/rangetosubnet.c
@@ -0,0 +1,226 @@
+/*
+ * express an address range as a subnet (if possible)
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: rangetosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - rangetosubnet - turn an address range into a subnet, if possible
+ *
+ * A range which is a valid subnet will have a network part which is the
+ * same in the from value and the to value, followed by a host part which
+ * is all 0 in the from value and all 1 in the to value.
+ */
+err_t
+rangetosubnet(from, to, dst)
+const ip_address *from;
+const ip_address *to;
+ip_subnet *dst;
+{
+ unsigned const char *fp;
+ unsigned const char *tp;
+ unsigned fb;
+ unsigned tb;
+ unsigned const char *f;
+ unsigned const char *t;
+ size_t n;
+ size_t n2;
+ int i;
+ int nnet;
+ unsigned m;
+
+ if (addrtypeof(from) != addrtypeof(to))
+ return "mismatched address types";
+ n = addrbytesptr(from, &fp);
+ if (n == 0)
+ return "unknown address type";
+ n2 = addrbytesptr(to, &tp);
+ if (n != n2)
+ return "internal size mismatch in rangetosubnet";
+
+ f = fp;
+ t = tp;
+ nnet = 0;
+ for (i = n; i > 0 && *f == *t; i--, f++, t++)
+ nnet += 8;
+ if (i > 0 && !(*f == 0x00 && *t == 0xff)) { /* mid-byte bdry. */
+ fb = *f++;
+ tb = *t++;
+ i--;
+ m = 0x80;
+ while ((fb&m) == (tb&m)) {
+ fb &= ~m;
+ tb |= m;
+ m >>= 1;
+ nnet++;
+ }
+ if (fb != 0x00 || tb != 0xff)
+ return "not a valid subnet";
+ }
+ for (; i > 0 && *f == 0x00 && *t == 0xff; i--, f++, t++)
+ continue;
+
+ if (i != 0)
+ return "invalid subnet";
+
+ return initsubnet(from, nnet, 'x', dst);
+}
+
+
+
+#ifdef RANGETOSUBNET_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ ip_address start;
+ ip_address stop;
+ ip_subnet sub;
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+ int i;
+
+ if (argc == 2 && strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: %s [-6] start stop\n", argv[0]);
+ fprintf(stderr, " or: %s -r\n", argv[0]);
+ exit(2);
+ }
+
+ af = AF_INET;
+ i = 1;
+ if (strcmp(argv[i], "-6") == 0) {
+ af = AF_INET6;
+ i++;
+ }
+
+ oops = ttoaddr(argv[i], 0, af, &start);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: start conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ oops = ttoaddr(argv[i+1], 0, af, &stop);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: stop conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ oops = rangetosubnet(&start, &stop, &sub);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: rangetosubnet failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettot(&sub, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion", argv[0]);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int family;
+ char *start;
+ char *stop;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {4, "1.2.3.0", "1.2.3.255", "1.2.3.0/24"},
+ {4, "1.2.3.0", "1.2.3.7", "1.2.3.0/29"},
+ {4, "1.2.3.240", "1.2.3.255", "1.2.3.240/28"},
+ {4, "0.0.0.0", "255.255.255.255", "0.0.0.0/0"},
+ {4, "1.2.3.4", "1.2.3.4", "1.2.3.4/32"},
+ {4, "1.2.3.0", "1.2.3.254", NULL},
+ {4, "1.2.3.0", "1.2.3.126", NULL},
+ {4, "1.2.3.0", "1.2.3.125", NULL},
+ {4, "1.2.0.0", "1.2.255.255", "1.2.0.0/16"},
+ {4, "1.2.0.0", "1.2.0.255", "1.2.0.0/24"},
+ {4, "1.2.255.0", "1.2.255.255", "1.2.255.0/24"},
+ {4, "1.2.255.0", "1.2.254.255", NULL},
+ {4, "1.2.255.1", "1.2.255.255", NULL},
+ {4, "1.2.0.1", "1.2.255.255", NULL},
+ {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:ffff", "1:2:3:4:5:6:7:0/112"},
+ {6, "1:2:3:4:5:6:7:0", "1:2:3:4:5:6:7:fff", "1:2:3:4:5:6:7:0/116"},
+ {6, "1:2:3:4:5:6:7:f0", "1:2:3:4:5:6:7:ff", "1:2:3:4:5:6:7:f0/124"},
+ {4, NULL, NULL, NULL},
+};
+
+void
+regress()
+{
+ struct rtab *r;
+ int status = 0;
+ ip_address start;
+ ip_address stop;
+ ip_subnet sub;
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+
+ for (r = rtab; r->start != NULL; r++) {
+ af = (r->family == 4) ? AF_INET : AF_INET6;
+ oops = ttoaddr(r->start, 0, af, &start);
+ if (oops != NULL) {
+ printf("surprise failure converting `%s'\n", r->start);
+ exit(1);
+ }
+ oops = ttoaddr(r->stop, 0, af, &stop);
+ if (oops != NULL) {
+ printf("surprise failure converting `%s'\n", r->stop);
+ exit(1);
+ }
+ oops = rangetosubnet(&start, &stop, &sub);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s'-`%s' rangetosubnet failed: %s\n",
+ r->start, r->stop, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s'-`%s' rangetosubnet succeeded unexpectedly\n",
+ r->start, r->stop);
+ status = 1;
+ } else {
+ n = subnettot(&sub, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s'-`%s' subnettot failed: need %ld\n",
+ r->start, r->stop, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s'-`%s' gave `%s', expected `%s'\n",
+ r->start, r->stop, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* RANGETOSUBNET_MAIN */
diff --git a/linux/lib/libfreeswan/sameaddr.3 b/linux/lib/libfreeswan/sameaddr.3
new file mode 100644
index 000000000..71be10761
--- /dev/null
+++ b/linux/lib/libfreeswan/sameaddr.3
@@ -0,0 +1,165 @@
+.TH IPSEC_ANYADDR 3 "28 Nov 2000"
+.\" RCSID $Id: sameaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec sameaddr \- are two addresses the same?
+.br
+ipsec addrcmp \- ordered comparison of addresses
+.br
+ipsec samesubnet \- are two subnets the same?
+.br
+ipsec addrinsubnet \- is an address within a subnet?
+.br
+ipsec subnetinsubnet \- is a subnet within another subnet?
+.br
+ipsec subnetishost \- is a subnet a single host?
+.br
+ipsec samesaid \- are two SA IDs the same?
+.br
+ipsec sameaddrtype \- are two addresses of the same address family?
+.br
+ipsec samesubnettype \- are two subnets of the same address family?
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "int sameaddr(const ip_address *a, const ip_address *b);"
+.br
+.B "int addrcmp(const ip_address *a, const ip_address *b);"
+.br
+.B "int samesubnet(const ip_subnet *a, const ip_subnet *b);"
+.br
+.B "int addrinsubnet(const ip_address *a, const ip_subnet *s);"
+.br
+.B "int subnetinsubnet(const ip_subnet *a, const ip_subnet *b);"
+.br
+.B "int subnetishost(const ip_subnet *s);"
+.br
+.B "int samesaid(const ip_said *a, const ip_said *b);"
+.br
+.B "int sameaddrtype(const ip_address *a, const ip_address *b);"
+.br
+.B "int samesubnettype(const ip_subnet *a, const ip_subnet *b);"
+.SH DESCRIPTION
+These functions do various comparisons and tests on the
+.I ip_address
+type and
+.I ip_subnet
+types.
+.PP
+.I Sameaddr
+returns
+non-zero
+if addresses
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+Addresses of different families are never identical.
+.PP
+.I Addrcmp
+returns
+.BR \-1 ,
+.BR 0 ,
+or
+.BR 1
+respectively
+if address
+.I a
+is less than, equal to, or greater than
+.IR b .
+If they are not of the same address family,
+they are never equal;
+the ordering reported in this case is arbitrary
+(and probably not useful) but consistent.
+.PP
+.I Samesubnet
+returns
+non-zero
+if subnets
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+Subnets of different address families are never identical.
+.PP
+.I Addrinsubnet
+returns
+non-zero
+if address
+.I a
+is within subnet
+.IR s
+and
+.B 0
+otherwise.
+An address is never within a
+subnet of a different address family.
+.PP
+.I Subnetinsubnet
+returns
+non-zero
+if subnet
+.I a
+is a subset of subnet
+.IR b
+and
+.B 0
+otherwise.
+A subnet is deemed to be a subset of itself.
+A subnet is never a subset of another
+subnet if their address families differ.
+.PP
+.I Subnetishost
+returns
+non-zero
+if subnet
+.I s
+is in fact only a single host,
+and
+.B 0
+otherwise.
+.PP
+.I Samesaid
+returns
+non-zero
+if SA IDs
+.I a
+and
+.IR b
+are identical,
+and
+.B 0
+otherwise.
+.PP
+.I Sameaddrtype
+returns
+non-zero
+if addresses
+.I a
+and
+.IR b
+are of the same address family,
+and
+.B 0
+otherwise.
+.PP
+.I Samesubnettype
+returns
+non-zero
+if subnets
+.I a
+and
+.IR b
+are of the same address family,
+and
+.B 0
+otherwise.
+.SH SEE ALSO
+inet(3), ipsec_initaddr(3)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/sameaddr.c b/linux/lib/libfreeswan/sameaddr.c
new file mode 100644
index 000000000..efc40796e
--- /dev/null
+++ b/linux/lib/libfreeswan/sameaddr.c
@@ -0,0 +1,190 @@
+/*
+ * comparisons
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: sameaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static int samenbits(const ip_address *a, const ip_address *b, int n);
+
+/*
+ - addrcmp - compare two addresses
+ * Caution, the order of the tests is subtle: doing type test before
+ * size test can yield cases where a<b, b<c, but a>c.
+ */
+int /* like memcmp */
+addrcmp(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ int at = addrtypeof(a);
+ int bt = addrtypeof(b);
+ const unsigned char *ap;
+ const unsigned char *bp;
+ size_t as = addrbytesptr(a, &ap);
+ size_t bs = addrbytesptr(b, &bp);
+ size_t n = (as < bs) ? as : bs; /* min(as, bs) */
+ int c = memcmp(ap, bp, n);
+
+ if (c != 0) /* bytes differ */
+ return (c < 0) ? -1 : 1;
+ if (as != bs) /* comparison incomplete: lexical order */
+ return (as < bs) ? -1 : 1;
+ if (at != bt) /* bytes same but not same type: break tie */
+ return (at < bt) ? -1 : 1;
+ return 0;
+}
+
+/*
+ - sameaddr - are two addresses the same?
+ */
+int
+sameaddr(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ return (addrcmp(a, b) == 0) ? 1 : 0;
+}
+
+/*
+ - samesubnet - are two subnets the same?
+ */
+int
+samesubnet(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ if (!sameaddr(&a->addr, &b->addr)) /* also does type check */
+ return 0;
+ if (a->maskbits != b->maskbits)
+ return 0;
+ return 1;
+}
+
+/*
+ - subnetishost - is a subnet in fact a single host?
+ */
+int
+subnetishost(a)
+const ip_subnet *a;
+{
+ return (a->maskbits == addrlenof(&a->addr)*8) ? 1 : 0;
+}
+
+/*
+ - samesaid - are two SA IDs the same?
+ */
+int
+samesaid(a, b)
+const ip_said *a;
+const ip_said *b;
+{
+ if (a->spi != b->spi) /* test first, most likely to be different */
+ return 0;
+ if (!sameaddr(&a->dst, &b->dst))
+ return 0;
+ if (a->proto != b->proto)
+ return 0;
+ return 1;
+}
+
+/*
+ - sameaddrtype - do two addresses have the same type?
+ */
+int
+sameaddrtype(a, b)
+const ip_address *a;
+const ip_address *b;
+{
+ return (addrtypeof(a) == addrtypeof(b)) ? 1 : 0;
+}
+
+/*
+ - samesubnettype - do two subnets have the same type?
+ */
+int
+samesubnettype(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ return (subnettypeof(a) == subnettypeof(b)) ? 1 : 0;
+}
+
+/*
+ - addrinsubnet - is this address in this subnet?
+ */
+int
+addrinsubnet(a, s)
+const ip_address *a;
+const ip_subnet *s;
+{
+ if (addrtypeof(a) != subnettypeof(s))
+ return 0;
+ if (!samenbits(a, &s->addr, s->maskbits))
+ return 0;
+ return 1;
+}
+
+/*
+ - subnetinsubnet - is one subnet within another?
+ */
+int
+subnetinsubnet(a, b)
+const ip_subnet *a;
+const ip_subnet *b;
+{
+ if (subnettypeof(a) != subnettypeof(b))
+ return 0;
+ if (a->maskbits < b->maskbits) /* a is bigger than b */
+ return 0;
+ if (!samenbits(&a->addr, &b->addr, b->maskbits))
+ return 0;
+ return 1;
+}
+
+/*
+ - samenbits - do two addresses have the same first n bits?
+ */
+static int
+samenbits(a, b, nbits)
+const ip_address *a;
+const ip_address *b;
+int nbits;
+{
+ const unsigned char *ap;
+ const unsigned char *bp;
+ size_t n;
+ int m;
+
+ if (addrtypeof(a) != addrtypeof(b))
+ return 0; /* arbitrary */
+ n = addrbytesptr(a, &ap);
+ if (n == 0)
+ return 0; /* arbitrary */
+ (void) addrbytesptr(b, &bp);
+ if (nbits > n*8)
+ return 0; /* "can't happen" */
+
+ for (; nbits >= 8 && *ap == *bp; nbits -= 8, ap++, bp++)
+ continue;
+ if (nbits >= 8)
+ return 0;
+ if (nbits > 0) { /* partial byte */
+ m = ~(0xff >> nbits);
+ if ((*ap & m) != (*bp & m))
+ return 0;
+ }
+ return 1;
+}
diff --git a/linux/lib/libfreeswan/satoa.c b/linux/lib/libfreeswan/satoa.c
new file mode 100644
index 000000000..410fb8437
--- /dev/null
+++ b/linux/lib/libfreeswan/satoa.c
@@ -0,0 +1,102 @@
+/*
+ * convert from binary form of SA ID to ASCII
+ * Copyright (C) 1998, 1999, 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: satoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct typename {
+ char type;
+ char *name;
+} typenames[] = {
+ { SA_AH, "ah" },
+ { SA_ESP, "esp" },
+ { SA_IPIP, "tun" },
+ { SA_COMP, "comp" },
+ { SA_INT, "int" },
+ { 0, NULL }
+};
+
+/*
+ - satoa - convert SA to ASCII "ah507@1.2.3.4"
+ */
+size_t /* space needed for full conversion */
+satoa(sa, format, dst, dstlen)
+struct sa_id sa;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len = 0; /* 0 means not handled yet */
+ int base;
+ struct typename *tn;
+ char buf[30+ADDRTOA_BUF];
+
+ switch (format) {
+ case 0:
+ base = 16; /* temporarily at least */
+ break;
+ case 'd':
+ base = 10;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ for (tn = typenames; tn->name != NULL; tn++)
+ if (sa.proto == tn->type)
+ break;
+ if (tn->name == NULL)
+ return 0;
+
+ if (strcmp(tn->name, PASSTHROUGHTYPE) == 0 &&
+ sa.spi == PASSTHROUGHSPI &&
+ sa.dst.s_addr == PASSTHROUGHDST) {
+ strcpy(buf, PASSTHROUGHNAME);
+ len = strlen(buf);
+ } else if (sa.proto == SA_INT && sa.dst.s_addr == 0) {
+ char *p;
+
+ switch (ntohl(sa.spi)) {
+ case SPI_PASS: p = "%pass"; break;
+ case SPI_DROP: p = "%drop"; break;
+ case SPI_REJECT: p = "%reject"; break;
+ case SPI_HOLD: p = "%hold"; break;
+ case SPI_TRAP: p = "%trap"; break;
+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
+ default: p = NULL; break;
+ }
+ if (p != NULL) {
+ strcpy(buf, p);
+ len = strlen(buf);
+ }
+ }
+
+ if (len == 0) {
+ strcpy(buf, tn->name);
+ len = strlen(buf);
+ len += ultoa(ntohl(sa.spi), base, buf+len, sizeof(buf)-len);
+ *(buf+len-1) = '@';
+ len += addrtoa(sa.dst, 0, buf+len, sizeof(buf)-len);
+ }
+
+ if (dst != NULL) {
+ if (len > dstlen)
+ *(buf+dstlen-1) = '\0';
+ strcpy(dst, buf);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/satot.c b/linux/lib/libfreeswan/satot.c
new file mode 100644
index 000000000..927f4ca1f
--- /dev/null
+++ b/linux/lib/libfreeswan/satot.c
@@ -0,0 +1,132 @@
+/*
+ * convert from binary form of SA ID to text
+ * Copyright (C) 2000, 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: satot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct typename {
+ char type;
+ char *name;
+} typenames[] = {
+ { SA_AH, "ah" },
+ { SA_ESP, "esp" },
+ { SA_IPIP, "tun" },
+ { SA_COMP, "comp" },
+ { SA_INT, "int" },
+ { 0, NULL }
+};
+
+/*
+ - satot - convert SA to text "ah507@1.2.3.4"
+ */
+size_t /* space needed for full conversion */
+satot(sa, format, dst, dstlen)
+const ip_said *sa;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len = 0; /* 0 means "not recognized yet" */
+ int base;
+ int showversion; /* use delimiter to show IP version? */
+ struct typename *tn;
+ char *p;
+ char *pre;
+ char buf[10+1+ULTOT_BUF+ADDRTOT_BUF];
+ char unk[10];
+
+ switch (format) {
+ case 0:
+ base = 16;
+ showversion = 1;
+ break;
+ case 'f':
+ base = 17;
+ showversion = 1;
+ break;
+ case 'x':
+ base = 'x';
+ showversion = 0;
+ break;
+ case 'd':
+ base = 10;
+ showversion = 0;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ pre = NULL;
+ for (tn = typenames; tn->name != NULL; tn++)
+ if (sa->proto == tn->type) {
+ pre = tn->name;
+ break; /* NOTE BREAK OUT */
+ }
+ if (pre == NULL) { /* unknown protocol */
+ strcpy(unk, "unk");
+ (void) ultot((unsigned char)sa->proto, 10, unk+strlen(unk),
+ sizeof(unk)-strlen(unk));
+ pre = unk;
+ }
+
+ if (strcmp(pre, PASSTHROUGHTYPE) == 0 &&
+ sa->spi == PASSTHROUGHSPI &&
+ isunspecaddr(&sa->dst)) {
+ strcpy(buf, (addrtypeof(&sa->dst) == AF_INET) ?
+ PASSTHROUGH4NAME :
+ PASSTHROUGH6NAME);
+ len = strlen(buf);
+ }
+
+ if (sa->proto == SA_INT && addrtypeof(&sa->dst) == AF_INET &&
+ isunspecaddr(&sa->dst)) {
+ switch (ntohl(sa->spi)) {
+ case SPI_PASS: p = "%pass"; break;
+ case SPI_DROP: p = "%drop"; break;
+ case SPI_REJECT: p = "%reject"; break;
+ case SPI_HOLD: p = "%hold"; break;
+ case SPI_TRAP: p = "%trap"; break;
+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
+ default: p = NULL; break;
+ }
+ if (p != NULL) {
+ strcpy(buf, p);
+ len = strlen(buf);
+ }
+ }
+
+ if (len == 0) { /* general case needed */
+ strcpy(buf, pre);
+ len = strlen(buf);
+ if (showversion) {
+ *(buf+len) = (addrtypeof(&sa->dst) == AF_INET) ? '.' :
+ ':';
+ len++;
+ *(buf+len) = '\0';
+ }
+ len += ultot(ntohl(sa->spi), base, buf+len, sizeof(buf)-len);
+ *(buf+len-1) = '@';
+ len += addrtot(&sa->dst, 0, buf+len, sizeof(buf)-len);
+ }
+
+ if (dst != NULL) {
+ if (len > dstlen)
+ *(buf+dstlen-1) = '\0';
+ strcpy(dst, buf);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/subnetof.3 b/linux/lib/libfreeswan/subnetof.3
new file mode 100644
index 000000000..1911e499f
--- /dev/null
+++ b/linux/lib/libfreeswan/subnetof.3
@@ -0,0 +1,47 @@
+.TH IPSEC_SUBNETOF 3 "11 June 2001"
+.\" RCSID $Id: subnetof.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec subnetof \- given Internet address and subnet mask, return subnet number
+.br
+ipsec hostof \- given Internet address and subnet mask, return host part
+.br
+ipsec broadcastof \- given Internet address and subnet mask, return broadcast address
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "struct in_addr subnetof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.br
+.B "struct in_addr hostof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.br
+.B "struct in_addr broadcastof(struct in_addr addr,"
+.ti +1c
+.B "struct in_addr mask);"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_networkof (3)
+for their replacements.
+.PP
+.I Subnetof
+takes an Internet
+.I address
+and a subnet
+.I mask
+and returns the network part of the address
+(all in network byte order).
+.I Hostof
+similarly returns the host part, and
+.I broadcastof
+returns the broadcast address (all-1s convention) for the network.
+.PP
+These functions are provided to hide the Internet bit-munging inside
+an API, in hopes of easing the eventual transition to IPv6.
+.SH SEE ALSO
+inet(3), ipsec_atosubnet(3)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+Calling functions for this is more costly than doing it yourself.
diff --git a/linux/lib/libfreeswan/subnetof.c b/linux/lib/libfreeswan/subnetof.c
new file mode 100644
index 000000000..1b288c591
--- /dev/null
+++ b/linux/lib/libfreeswan/subnetof.c
@@ -0,0 +1,60 @@
+/*
+ * minor network-address manipulation utilities
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnetof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnetof - given address and mask, return subnet part
+ */
+struct in_addr
+subnetof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr & mask.s_addr;
+ return result;
+}
+
+/*
+ - hostof - given address and mask, return host part
+ */
+struct in_addr
+hostof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr & ~mask.s_addr;
+ return result;
+}
+
+/*
+ - broadcastof - given (network) address and mask, return broadcast address
+ */
+struct in_addr
+broadcastof(addr, mask)
+struct in_addr addr;
+struct in_addr mask;
+{
+ struct in_addr result;
+
+ result.s_addr = addr.s_addr | ~mask.s_addr;
+ return result;
+}
diff --git a/linux/lib/libfreeswan/subnettoa.c b/linux/lib/libfreeswan/subnettoa.c
new file mode 100644
index 000000000..36cad8b88
--- /dev/null
+++ b/linux/lib/libfreeswan/subnettoa.c
@@ -0,0 +1,62 @@
+/*
+ * convert binary form of subnet description to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnettoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettoa - convert address and mask to ASCII "addr/mask"
+ * Output expresses the mask as a bit count if possible, else dotted decimal.
+ */
+size_t /* space needed for full conversion */
+subnettoa(addr, mask, format, dst, dstlen)
+struct in_addr addr;
+struct in_addr mask;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ int n;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtoa(addr, 0, dst, dstlen);
+ if (len < dstlen) {
+ dst[len - 1] = '/';
+ p = dst + len;
+ rest = dstlen - len;
+ } else {
+ p = NULL;
+ rest = 0;
+ }
+
+ n = masktobits(mask);
+ if (n >= 0)
+ len += ultoa((unsigned long)n, 10, p, rest);
+ else
+ len += addrtoa(mask, 0, p, rest);
+
+ return len;
+}
diff --git a/linux/lib/libfreeswan/subnettot.c b/linux/lib/libfreeswan/subnettot.c
new file mode 100644
index 000000000..0385d25e5
--- /dev/null
+++ b/linux/lib/libfreeswan/subnettot.c
@@ -0,0 +1,56 @@
+/*
+ * convert binary form of subnet description to text
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnettot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettot - convert subnet to text "addr/bitcount"
+ */
+size_t /* space needed for full conversion */
+subnettot(sub, format, dst, dstlen)
+const ip_subnet *sub;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len;
+ size_t rest;
+ char *p;
+
+ switch (format) {
+ case 0:
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = addrtot(&sub->addr, format, dst, dstlen);
+ if (len < dstlen) {
+ dst[len - 1] = '/';
+ p = dst + len;
+ rest = dstlen - len;
+ } else {
+ p = NULL;
+ rest = 0;
+ }
+
+
+ len += ultoa((unsigned long)sub->maskbits, 10, p, rest);
+
+ return len;
+}
diff --git a/linux/lib/libfreeswan/subnettypeof.c b/linux/lib/libfreeswan/subnettypeof.c
new file mode 100644
index 000000000..6f44b2e4b
--- /dev/null
+++ b/linux/lib/libfreeswan/subnettypeof.c
@@ -0,0 +1,109 @@
+/*
+ * extract parts of an ip_subnet, and related
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: subnettypeof.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - subnettypeof - get the address type of an ip_subnet
+ */
+int
+subnettypeof(src)
+const ip_subnet *src;
+{
+ return src->addr.u.v4.sin_family;
+}
+
+/*
+ - networkof - get the network address of a subnet
+ */
+void
+networkof(src, dst)
+const ip_subnet *src;
+ip_address *dst;
+{
+ *dst = src->addr;
+}
+
+/*
+ - maskof - get the mask of a subnet, as an address
+ */
+void
+maskof(src, dst)
+const ip_subnet *src;
+ip_address *dst;
+{
+ int b;
+ unsigned char buf[16];
+ size_t n = addrlenof(&src->addr);
+ unsigned char *p;
+
+ if (src->maskbits > n*8 || n > sizeof(buf))
+ return; /* "can't happen" */
+
+ p = buf;
+ for (b = src->maskbits; b >= 8; b -= 8)
+ *p++ = 0xff;
+ if (b != 0)
+ *p++ = (0xff << (8 - b)) & 0xff;
+ while (p - buf < n)
+ *p++ = 0;
+
+ (void) initaddr(buf, n, addrtypeof(&src->addr), dst);
+}
+
+/*
+ - masktocount - convert a mask, expressed as an address, to a bit count
+ */
+int /* -1 if not valid mask */
+masktocount(src)
+const ip_address *src;
+{
+ int b;
+ unsigned const char *bp;
+ size_t n;
+ unsigned const char *p;
+ unsigned const char *stop;
+
+ n = addrbytesptr(src, &bp);
+ if (n == 0)
+ return -1;
+
+ p = bp;
+ stop = bp + n;
+
+ n = 0;
+ while (p < stop && *p == 0xff) {
+ p++;
+ n += 8;
+ }
+ if (p < stop && *p != 0) { /* boundary in mid-byte */
+ b = *p++;
+ while (b&0x80) {
+ b <<= 1;
+ n++;
+ }
+ if ((b&0xff) != 0)
+ return -1; /* bits not contiguous */
+ }
+ while (p < stop && *p == 0)
+ p++;
+
+ if (p != stop)
+ return -1;
+
+ return n;
+}
diff --git a/linux/lib/libfreeswan/ttoaddr.3 b/linux/lib/libfreeswan/ttoaddr.3
new file mode 100644
index 000000000..5bf48d4b2
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoaddr.3
@@ -0,0 +1,377 @@
+.TH IPSEC_TTOADDR 3 "28 Sept 2001"
+.\" RCSID $Id: ttoaddr.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttoaddr, tnatoaddr, addrtot \- convert Internet addresses to and from text
+.br
+ipsec ttosubnet, subnettot \- convert subnet/mask text form to and from addresses
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ttoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *addr);"
+.br
+.B "const char *tnatoaddr(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_address *addr);"
+.br
+.B "size_t addrtot(const ip_address *addr, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "const char *ttosubnet(const char *src, size_t srclen,"
+.ti +1c
+.B "int af, ip_subnet *dst);"
+.br
+.B "size_t subnettot(const ip_subnet *sub, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.SH DESCRIPTION
+.I Ttoaddr
+converts a text-string name or numeric address into a binary address
+(in network byte order).
+.I Tnatoaddr
+does the same conversion,
+but the only text forms it accepts are
+the ``official'' forms of
+numeric address (dotted-decimal for IPv4, colon-hex for IPv6).
+.I Addrtot
+does the reverse conversion, from binary address back to a text form.
+.I Ttosubnet
+and
+.I subnettot
+do likewise for the ``address/mask'' form used to write a
+specification of a subnet.
+.PP
+An IPv4 address is specified in text as a
+dotted-decimal address (e.g.
+.BR 1.2.3.4 ),
+an eight-digit network-order hexadecimal number with the usual C prefix (e.g.
+.BR 0x01020304 ,
+which is synonymous with
+.BR 1.2.3.4 ),
+an eight-digit host-order hexadecimal number with a
+.B 0h
+prefix (e.g.
+.BR 0h01020304 ,
+which is synonymous with
+.B 1.2.3.4
+on a big-endian host and
+.B 4.3.2.1
+on a little-endian host),
+a DNS name to be looked up via
+.IR gethostbyname (3),
+or an old-style network name to be looked up via
+.IR getnetbyname (3).
+.PP
+A dotted-decimal address may be incomplete, in which case
+text-to-binary conversion implicitly appends
+as many instances of
+.B .0
+as necessary to bring it up to four components.
+The components of a dotted-decimal address are always taken as
+decimal, and leading zeros are ignored.
+For example,
+.B 10
+is synonymous with
+.BR 10.0.0.0 ,
+and
+.B 128.009.000.032
+is synonymous with
+.BR 128.9.0.32
+(the latter example is verbatim from RFC 1166).
+The result of applying
+.I addrtot
+to an IPv4 address is always complete and does not contain leading zeros.
+.PP
+Use of hexadecimal addresses is
+.B strongly
+.BR discouraged ;
+they are included only to save hassles when dealing with
+the handful of perverted programs which already print
+network addresses in hexadecimal.
+.PP
+An IPv6 address is specified in text with
+colon-hex notation (e.g.
+.BR 0:56:78ab:22:33:44:55:66 ),
+colon-hex with
+.B ::
+abbreviating at most one subsequence of multiple zeros (e.g.
+.BR 99:ab::54:068 ,
+which is synonymous with
+.BR 99:ab:0:0:0:0:54:68 ),
+or a DNS name to be looked up via
+.IR gethostbyname (3).
+The result of applying
+.I addrtot
+to an IPv6 address will use
+.B ::
+abbreviation if possible,
+and will not contain leading zeros.
+.PP
+The letters in hexadecimal
+may be uppercase or lowercase or any mixture thereof.
+.PP
+DNS names may be complete (optionally terminated with a ``.'')
+or incomplete, and are looked up as specified by local system configuration
+(see
+.IR resolver (5)).
+The
+.I h_addr
+value returned by
+.IR gethostbyname2 (3)
+is used,
+so with current DNS implementations,
+the result when the name corresponds to more than one address is
+difficult to predict.
+IPv4 name lookup resorts to
+.IR getnetbyname (3)
+only if
+.IR gethostbyname2 (3)
+fails.
+.PP
+A subnet specification is of the form \fInetwork\fB/\fImask\fR.
+The
+.I network
+and
+.I mask
+can be any form acceptable to
+.IR ttoaddr .
+In addition, and preferably, the
+.I mask
+can be a decimal integer (leading zeros ignored) giving a bit count,
+in which case
+it stands for a mask with that number of high bits on and all others off
+(e.g.,
+.B 24
+in IPv4 means
+.BR 255.255.255.0 ).
+In any case, the mask must be contiguous
+(a sequence of high bits on and all remaining low bits off).
+As a special case, the subnet specification
+.B %default
+is a synonym for
+.B 0.0.0.0/0
+or
+.B ::/0
+in IPv4 or IPv6 respectively.
+.PP
+.I Ttosubnet
+ANDs the mask with the address before returning,
+so that any non-network bits in the address are turned off
+(e.g.,
+.B 10.1.2.3/24
+is synonymous with
+.BR 10.1.2.0/24 ).
+.I Subnettot
+always generates the decimal-integer-bit-count
+form of the mask,
+with no leading zeros.
+.PP
+The
+.I srclen
+parameter of
+.I ttoaddr
+and
+.I ttosubnet
+specifies the length of the text string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I af
+parameter of
+.I ttoaddr
+and
+.I ttosubnet
+specifies the address family of interest.
+It should be either
+.B AF_INET
+or
+.BR AF_INET6 .
+.PP
+The
+.I dstlen
+parameter of
+.I addrtot
+and
+.I subnettot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines constants,
+.B ADDRTOT_BUF
+and
+.BR SUBNETTOT_BUF ,
+which are the sizes of buffers just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I addrtot
+and
+.I subnettot
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default,
+and is in fact the only format currently available in
+.IR subnettot .
+.I Addrtot
+also accepts format values
+.B 'r'
+(signifying a text form suitable for DNS reverse lookups,
+e.g.
+.B 4.3.2.1.IN-ADDR.ARPA.
+for IPv4 and
+RFC 2874 format for IPv6),
+and
+.B 'R'
+(signifying an alternate reverse-lookup form,
+an error for IPv4 and RFC 1886 format for IPv6).
+Reverse-lookup names always end with a ``.''.
+.PP
+The text-to-binary functions return NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+The binary-to-text functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttoaddr
+are:
+empty input;
+unknown address family;
+attempt to allocate temporary storage for a very long name failed;
+name lookup failed;
+syntax error in dotted-decimal or colon-hex form;
+dotted-decimal or colon-hex component too large.
+.PP
+Fatal errors in
+.I ttosubnet
+are:
+no
+.B /
+in
+.IR src ;
+.I ttoaddr
+error in conversion of
+.I network
+or
+.IR mask ;
+bit-count mask too big;
+mask non-contiguous.
+.PP
+Fatal errors in
+.I addrtot
+and
+.I subnettot
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The interpretation of incomplete dotted-decimal addresses
+(e.g.
+.B 10/24
+means
+.BR 10.0.0.0/24 )
+differs from that of some older conversion
+functions, e.g. those of
+.IR inet (3).
+The behavior of the older functions has never been
+particularly consistent or particularly useful.
+.PP
+Ignoring leading zeros in dotted-decimal components and bit counts
+is arguably the most useful behavior in this application,
+but it might occasionally cause confusion with the historical use of leading
+zeros to denote octal numbers.
+.PP
+.I Ttoaddr
+does not support the mixed colon-hex-dotted-decimal
+convention used to embed an IPv4 address in an IPv6 address.
+.PP
+.I Addrtot
+always uses the
+.B ::
+abbreviation (which can appear only once in an address) for the
+.I first
+sequence of multiple zeros in an IPv6 address.
+One can construct addresses (unlikely ones) in which this is suboptimal.
+.PP
+.I Addrtot
+.B 'r'
+conversion of an IPv6 address uses lowercase hexadecimal,
+not the uppercase used in RFC 2874's examples.
+It takes careful reading of RFCs 2874, 2673, and 2234 to realize
+that lowercase is technically legitimate here,
+and there may be software which botches this
+and hence would have trouble with lowercase hex.
+.PP
+Possibly
+.I subnettot
+ought to recognize the
+.B %default
+case and generate that string as its output.
+Currently it doesn't.
+.PP
+It is barely possible that somebody, somewhere,
+might have a legitimate use for non-contiguous subnet masks.
+.PP
+.IR Getnetbyname (3)
+is a historical dreg.
+.PP
+.I Tnatoaddr
+probably should enforce completeness of dotted-decimal addresses.
+.PP
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/ttoaddr.c b/linux/lib/libfreeswan/ttoaddr.c
new file mode 100644
index 000000000..efcb33e9f
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoaddr.c
@@ -0,0 +1,426 @@
+/*
+ * conversion from text forms of addresses to internal ones
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttoaddr.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * Legal ASCII characters in a domain name. Underscore technically is not,
+ * but is a common misunderstanding. Non-ASCII characters are simply
+ * exempted from checking at the moment, to allow for UTF-8 encoded stuff;
+ * the purpose of this check is merely to catch blatant errors.
+ */
+static const char namechars[] = "abcdefghijklmnopqrstuvwxyz0123456789"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ-_.";
+#define ISASCII(c) (((c) & 0x80) == 0)
+
+static err_t tryname(const char *, size_t, int, int, ip_address *);
+static err_t tryhex(const char *, size_t, int, ip_address *);
+static err_t trydotted(const char *, size_t, ip_address *);
+static err_t getbyte(const char **, const char *, int *);
+static err_t colon(const char *, size_t, ip_address *);
+static err_t getpiece(const char **, const char *, unsigned *);
+
+/*
+ - ttoaddr - convert text name or dotted-decimal address to binary address
+ */
+err_t /* NULL for success, else string literal */
+ttoaddr(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* address family */
+ip_address *dst;
+{
+ err_t oops;
+# define HEXLEN 10 /* strlen("0x11223344") */
+ int nultermd;
+
+ if (srclen == 0) {
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ nultermd = 1;
+ } else
+ nultermd = 0; /* at least, not *known* to be terminated */
+
+ switch (af) {
+ case AF_INET:
+ case AF_INET6:
+ case 0: /* guess */
+ break;
+
+ default:
+ return "invalid address family";
+ }
+
+ if (af == AF_INET && srclen == HEXLEN && *src == '0') {
+ if (*(src+1) == 'x' || *(src+1) == 'X')
+ return tryhex(src+2, srclen-2, 'x', dst);
+ if (*(src+1) == 'h' || *(src+1) == 'H')
+ return tryhex(src+2, srclen-2, 'h', dst);
+ }
+
+ if (memchr(src, ':', srclen) != NULL) {
+ if(af == 0)
+ {
+ af = AF_INET6;
+ }
+
+ if (af != AF_INET6)
+ return "non-ipv6 address may not contain `:'";
+ return colon(src, srclen, dst);
+ }
+
+ if (af == 0 || af == AF_INET) {
+ oops = trydotted(src, srclen, dst);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* probably meant as d-d */
+ }
+
+ return tryname(src, srclen, nultermd, af, dst);
+}
+
+/*
+ - tnatoaddr - convert text numeric address (only) to binary address
+ */
+err_t /* NULL for success, else string literal */
+tnatoaddr(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* address family */
+ip_address *dst;
+{
+ err_t oops;
+
+ if (srclen == 0) {
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ }
+
+ switch (af) {
+ case 0: /* guess */
+ oops = colon(src, srclen, dst);
+ if(oops == NULL)
+ {
+ return NULL;
+ }
+ oops = trydotted(src, srclen, dst);
+ if(oops == NULL)
+ {
+ return NULL;
+ }
+ return "does not appear to be either IPv4 or IPv6 numeric address";
+ break;
+
+ case AF_INET6:
+ return colon(src, srclen, dst);
+ break;
+ case AF_INET:
+ oops = trydotted(src, srclen, dst);
+ if (oops == NULL)
+ return NULL; /* it worked */
+ if (*oops != '?')
+ return oops; /* probably meant as d-d */
+ return "does not appear to be numeric address";
+ break;
+ default:
+ return "unknown address family in tnatoaddr";
+ break;
+ }
+}
+
+/*
+ - tryname - try it as a name
+ * Slightly complicated by lack of reliable NUL termination in source.
+ */
+static err_t
+tryname(src, srclen, nultermd, af, dst)
+const char *src;
+size_t srclen;
+int nultermd; /* is it known to be NUL-terminated? */
+int af;
+ip_address *dst;
+{
+ struct hostent *h;
+ struct netent *ne = NULL;
+ char namebuf[100]; /* enough for most DNS names */
+ const char *cp;
+ char *p = namebuf;
+ size_t n;
+
+ for (cp = src, n = srclen; n > 0; cp++, n--)
+ if (ISASCII(*cp) && strchr(namechars, *cp) == NULL)
+ return "illegal (non-DNS-name) character in name";
+
+ if (nultermd)
+ cp = src;
+ else {
+ if (srclen+1 > sizeof(namebuf)) {
+ p = (char *) MALLOC(srclen+1);
+ if (p == NULL)
+ return "unable to get temporary space for name";
+ }
+ p[0] = '\0'; /* strncpy semantics are wrong */
+ strncat(p, src, srclen);
+ cp = (const char *)p;
+ }
+
+ h = gethostbyname2(cp, af);
+ if (h == NULL && af == AF_INET)
+ ne = getnetbyname(cp);
+ if (p != namebuf)
+ FREE(p);
+ if (h == NULL && ne == NULL)
+ return "does not look numeric and name lookup failed";
+
+ if (h != NULL) {
+ if (h->h_addrtype != af)
+ return "address-type mismatch from gethostbyname2!!!";
+ return initaddr((unsigned char *)h->h_addr, h->h_length, af, dst);
+ } else {
+ if (ne->n_addrtype != af)
+ return "address-type mismatch from getnetbyname!!!";
+ ne->n_net = htonl(ne->n_net);
+ return initaddr((unsigned char *)&ne->n_net, sizeof(ne->n_net),
+ af, dst);
+ }
+}
+
+/*
+ - tryhex - try conversion as an eight-digit hex number (AF_INET only)
+ */
+static err_t
+tryhex(src, srclen, flavor, dst)
+const char *src;
+size_t srclen; /* should be 8 */
+int flavor; /* 'x' for network order, 'h' for host order */
+ip_address *dst;
+{
+ err_t oops;
+ unsigned long ul;
+ union {
+ uint32_t addr;
+ unsigned char buf[4];
+ } u;
+
+ if (srclen != 8)
+ return "internal error, tryhex called with bad length";
+
+ oops = ttoul(src, srclen, 16, &ul);
+ if (oops != NULL)
+ return oops;
+
+ u.addr = (flavor == 'h') ? ul : htonl(ul);
+ return initaddr(u.buf, sizeof(u.buf), AF_INET, dst);
+}
+
+/*
+ - trydotted - try conversion as dotted decimal (AF_INET only)
+ *
+ * If the first char of a complaint is '?', that means "didn't look like
+ * dotted decimal at all".
+ */
+static err_t
+trydotted(src, srclen, dst)
+const char *src;
+size_t srclen;
+ip_address *dst;
+{
+ const char *stop = src + srclen; /* just past end */
+ int byte;
+ err_t oops;
+# define NBYTES 4
+ unsigned char buf[NBYTES];
+ int i;
+
+ memset(buf, 0, sizeof(buf));
+ for (i = 0; i < NBYTES && src < stop; i++) {
+ oops = getbyte(&src, stop, &byte);
+ if (oops != NULL) {
+ if (*oops != '?')
+ return oops; /* bad number */
+ if (i > 1)
+ return oops+1; /* failed number */
+ return oops; /* with leading '?' */
+ }
+ buf[i] = byte;
+ if (i < 3 && src < stop && *src++ != '.') {
+ if (i == 0)
+ return "?syntax error in dotted-decimal address";
+ else
+ return "syntax error in dotted-decimal address";
+ }
+ }
+ if (src != stop)
+ return "extra garbage on end of dotted-decimal address";
+
+ return initaddr(buf, sizeof(buf), AF_INET, dst);
+}
+
+/*
+ - getbyte - try to scan a byte in dotted decimal
+ * A subtlety here is that all this arithmetic on ASCII digits really is
+ * highly portable -- ANSI C guarantees that digits 0-9 are contiguous.
+ * It's easier to just do it ourselves than set up for a call to ttoul().
+ *
+ * If the first char of a complaint is '?', that means "didn't look like a
+ * number at all".
+ */
+err_t
+getbyte(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+int *retp; /* return-value pointer */
+{
+ char c;
+ const char *p;
+ int no;
+
+ if (*srcp >= stop)
+ return "?empty number in dotted-decimal address";
+
+ no = 0;
+ p = *srcp;
+ while (p < stop && no <= 255 && (c = *p) >= '0' && c <= '9') {
+ no = no*10 + (c - '0');
+ p++;
+ }
+ if (p == *srcp)
+ return "?non-numeric component in dotted-decimal address";
+ *srcp = p;
+ if (no > 255)
+ return "byte overflow in dotted-decimal address";
+ *retp = no;
+ return NULL;
+}
+
+/*
+ - colon - convert IPv6 "numeric" address
+ */
+static err_t
+colon(src, srclen, dst)
+const char *src;
+size_t srclen; /* known to be >0 */
+ip_address *dst;
+{
+ const char *stop = src + srclen; /* just past end */
+ unsigned piece;
+ int gapat; /* where was empty piece seen */
+ err_t oops;
+# define NPIECES 8
+ unsigned char buf[NPIECES*2]; /* short may have wrong byte order */
+ int i;
+ int j;
+# define IT "IPv6 numeric address"
+ int naftergap;
+
+ /* leading or trailing :: becomes single empty field */
+ if (*src == ':') { /* legal only if leading :: */
+ if (srclen == 1 || *(src+1) != ':')
+ return "illegal leading `:' in " IT;
+ if (srclen == 2) {
+ unspecaddr(AF_INET6, dst);
+ return NULL;
+ }
+ src++; /* past first but not second */
+ srclen--;
+ }
+ if (*(stop-1) == ':') { /* legal only if trailing :: */
+ if (srclen == 1 || *(stop-2) != ':')
+ return "illegal trailing `:' in " IT;
+ srclen--; /* leave one */
+ }
+
+ gapat = -1;
+ for (i = 0; i < NPIECES && src < stop; i++) {
+ oops = getpiece(&src, stop, &piece);
+ if (oops != NULL && *oops == ':') { /* empty field */
+ if (gapat >= 0)
+ return "more than one :: in " IT;
+ gapat = i;
+ } else if (oops != NULL)
+ return oops;
+ buf[2*i] = piece >> 8;
+ buf[2*i + 1] = piece & 0xff;
+ if (i < NPIECES-1) { /* there should be more input */
+ if (src == stop && gapat < 0)
+ return IT " ends prematurely";
+ if (src != stop && *src++ != ':')
+ return "syntax error in " IT;
+ }
+ }
+ if (src != stop)
+ return "extra garbage on end of " IT;
+
+ if (gapat < 0 && i < NPIECES) /* should have been caught earlier */
+ return "incomplete " IT " (internal error)";
+ if (gapat >= 0 && i == NPIECES)
+ return "non-abbreviating empty field in " IT;
+ if (gapat >= 0) {
+ naftergap = i - (gapat + 1);
+ for (i--, j = NPIECES-1; naftergap > 0; i--, j--, naftergap--) {
+ buf[2*j] = buf[2*i];
+ buf[2*j + 1] = buf[2*i + 1];
+ }
+ for (; j >= gapat; j--)
+ buf[2*j] = buf[2*j + 1] = 0;
+ }
+
+ return initaddr(buf, sizeof(buf), AF_INET6, dst);
+}
+
+/*
+ - getpiece - try to scan one 16-bit piece of an IPv6 address
+ */
+err_t /* ":" means "empty field seen" */
+getpiece(srcp, stop, retp)
+const char **srcp; /* *srcp is updated */
+const char *stop; /* first untouchable char */
+unsigned *retp; /* return-value pointer */
+{
+ const char *p;
+# define NDIG 4
+ int d;
+ unsigned long ret;
+ err_t oops;
+
+ if (*srcp >= stop || **srcp == ':') { /* empty field */
+ *retp = 0;
+ return ":";
+ }
+
+ p = *srcp;
+ d = 0;
+ while (p < stop && d < NDIG && isxdigit(*p)) {
+ p++;
+ d++;
+ }
+ if (d == 0)
+ return "non-hex field in IPv6 numeric address";
+ if (p < stop && d == NDIG && isxdigit(*p))
+ return "field in IPv6 numeric address longer than 4 hex digits";
+
+ oops = ttoul(*srcp, d, 16, &ret);
+ if (oops != NULL) /* shouldn't happen, really... */
+ return oops;
+
+ *srcp = p;
+ *retp = ret;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/ttodata.3 b/linux/lib/libfreeswan/ttodata.3
new file mode 100644
index 000000000..98bbe4ab3
--- /dev/null
+++ b/linux/lib/libfreeswan/ttodata.3
@@ -0,0 +1,281 @@
+.TH IPSEC_TTODATA 3 "16 August 2003"
+.\" RCSID $Id: ttodata.3,v 1.2 2005/07/18 20:13:42 as Exp $
+.SH NAME
+ipsec ttodata, datatot \- convert binary data bytes from and to text formats
+.SH SYNOPSIS
+.B "#include <freeswan.h>"
+.sp
+.B "const char *ttodata(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, char *dst, size_t dstlen, size_t *lenp);"
+.br
+.B "const char *ttodatav(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, char *dst, size_t dstlen, size_t *lenp,"
+.ti +1c
+.B "char *errp, size_t errlen, int flags);"
+.br
+.B "size_t datatot(const char *src, size_t srclen,"
+.ti +1c
+.B "int format, char *dst, size_t dstlen);"
+.SH DESCRIPTION
+.IR Ttodata ,
+.IR ttodatav ,
+and
+.I datatot
+convert arbitrary binary data (e.g. encryption or authentication keys)
+from and to more-or-less human-readable text formats.
+.PP
+Currently supported formats are hexadecimal, base64, and characters.
+.PP
+A hexadecimal text value begins with a
+.B 0x
+(or
+.BR 0X )
+prefix and continues with two-digit groups
+of hexadecimal digits (0-9, and a-f or A-F),
+each group encoding the value of one binary byte, high-order digit first.
+A single
+.B _
+(underscore)
+between consecutive groups is ignored, permitting punctuation to improve
+readability; doing this every eight digits seems about right.
+.PP
+A base64 text value begins with a
+.B 0s
+(or
+.BR 0S )
+prefix
+and continues with four-digit groups of base64 digits (A-Z, a-z, 0-9, +, and /),
+each group encoding the value of three binary bytes as described in
+section 6.8 of RFC 2045.
+If
+.B flags
+has the
+.B TTODATAV_IGNORESPACE
+bit on, blanks are ignore (after the prefix).
+Note that the last one or two digits of a base64 group can be
+.B =
+to indicate that fewer than three binary bytes are encoded.
+.PP
+A character text value begins with a
+.B 0t
+(or
+.BR 0T )
+prefix
+and continues with text characters, each being the value of one binary byte.
+.PP
+All these functions basically copy data from
+.I src
+(whose size is specified by
+.IR srclen )
+to
+.I dst
+(whose size is specified by
+.IR dstlen ),
+doing the conversion en route.
+If the result will not fit in
+.IR dst ,
+it is truncated;
+under no circumstances are more than
+.I dstlen
+bytes of result written to
+.IR dst .
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result bytes are written at all.
+.PP
+The
+.I base
+parameter of
+.I ttodata
+and
+.I ttodatav
+specifies what format the input is in;
+normally it should be
+.B 0
+to signify that this gets figured out from the prefix.
+Values of
+.BR 16 ,
+.BR 64 ,
+and
+.BR 256
+respectively signify hexadecimal, base64, and character-text formats
+without prefixes.
+.PP
+The
+.I format
+parameter of
+.IR datatot ,
+a single character used as a type code,
+specifies which text format is wanted.
+The value
+.B 0
+(not ASCII
+.BR '0' ,
+but a zero value) specifies a reasonable default.
+Other currently-supported values are:
+.RS 2
+.TP 4
+.B 'x'
+continuous lower-case hexadecimal with a
+.B 0x
+prefix
+.TP
+.B 'h'
+lower-case hexadecimal with a
+.B 0x
+prefix and a
+.B _
+every eight digits
+.TP
+.B ':'
+lower-case hexadecimal with no prefix and a
+.B :
+(colon) every two digits
+.TP
+.B 16
+lower-case hexadecimal with no prefix or
+.B _
+.TP
+.B 's'
+continuous base64 with a
+.B 0s
+prefix
+.TP
+.B 64
+continuous base64 with no prefix
+.RE
+.PP
+The default format is currently
+.BR 'h' .
+.PP
+.I Ttodata
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+On success,
+if and only if
+.I lenp
+is non-NULL,
+.B *lenp
+is set to the number of bytes required to contain the full untruncated result.
+It is the caller's responsibility to check this against
+.I dstlen
+to determine whether he has obtained a complete result.
+The
+.B *lenp
+value is correct even if
+.I dstlen
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+.PP
+.I Ttodatav
+is just like
+.I ttodata
+except that in certain cases,
+if
+.I errp
+is non-NULL,
+the buffer pointed to by
+.I errp
+(whose length is given by
+.IR errlen )
+is used to hold a more detailed error message.
+The return value is NULL for success,
+and is either
+.I errp
+or a pointer to a string literal for failure.
+If the size of the error-message buffer is
+inadequate for the desired message,
+.I ttodatav
+will fall back on returning a pointer to a literal string instead.
+The
+.I freeswan.h
+header file defines a constant
+.B TTODATAV_BUF
+which is the size of a buffer large enough for worst-case results.
+.PP
+The normal return value of
+.IR datatot
+is the number of bytes required
+to contain the full untruncated result.
+It is the caller's responsibility to check this against
+.I dstlen
+to determine whether he has obtained a complete result.
+The return value is correct even if
+.I dstlen
+is zero, which offers a way to determine how much space would be needed
+before having to allocate any.
+A return value of
+.B 0
+signals a fatal error of some kind
+(see DIAGNOSTICS).
+.PP
+A zero value for
+.I srclen
+in
+.I ttodata
+(but not
+.IR datatot !)
+is synonymous with
+.BR strlen(src) .
+A non-zero
+.I srclen
+in
+.I ttodata
+must not include the terminating NUL.
+.PP
+Unless
+.I dstlen
+is zero,
+the result supplied by
+.I datatot
+is always NUL-terminated,
+and its needed-size return value includes space for the terminating NUL.
+.PP
+Several obsolete variants of these functions
+.RI ( atodata ,
+.IR datatoa ,
+.IR atobytes ,
+and
+.IR bytestoa )
+are temporarily also supported.
+.SH SEE ALSO
+sprintf(3), ipsec_atoaddr(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttodata
+and
+.I ttodatav
+are:
+unknown characters in the input;
+unknown or missing prefix;
+unknown base;
+incomplete digit group;
+non-zero padding in a base64 less-than-three-bytes digit group;
+zero-length input.
+.PP
+Fatal errors in
+.I datatot
+are:
+unknown format code;
+zero-length input.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+.I Datatot
+should have a format code to produce character-text output.
+.PP
+The
+.B 0s
+and
+.B 0t
+prefixes are the author's inventions and are not a standard
+of any kind.
+They have been chosen to avoid collisions with existing practice
+(some C implementations use
+.B 0b
+for binary)
+and possible confusion with unprefixed hexadecimal.
diff --git a/linux/lib/libfreeswan/ttodata.c b/linux/lib/libfreeswan/ttodata.c
new file mode 100644
index 000000000..e1bf7606a
--- /dev/null
+++ b/linux/lib/libfreeswan/ttodata.c
@@ -0,0 +1,722 @@
+/*
+ * convert from text form of arbitrary data (e.g., keys) to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttodata.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/* converters and misc */
+static int unhex(const char *, char *, size_t);
+static int unb64(const char *, char *, size_t);
+static int untext(const char *, char *, size_t);
+static const char *badch(const char *, int, char *, size_t);
+
+/* internal error codes for converters */
+#define SHORT (-2) /* internal buffer too short */
+#define BADPAD (-3) /* bad base64 padding */
+#define BADCH0 (-4) /* invalid character 0 */
+#define BADCH1 (-5) /* invalid character 1 */
+#define BADCH2 (-6) /* invalid character 2 */
+#define BADCH3 (-7) /* invalid character 3 */
+#define BADOFF(code) (BADCH0-(code))
+
+/*
+ - ttodatav - convert text to data, with verbose error reports
+ * If some of this looks slightly odd, it's because it has changed
+ * repeatedly (from the original atodata()) without a major rewrite.
+ */
+const char * /* NULL on success, else literal or errp */
+ttodatav(src, srclen, base, dst, dstlen, lenp, errp, errlen, flags)
+const char *src;
+size_t srclen; /* 0 means apply strlen() */
+int base; /* 0 means figure it out */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp; /* where to record length (NULL is nowhere) */
+char *errp; /* error buffer */
+size_t errlen;
+unsigned int flags;
+{
+ size_t ingroup; /* number of input bytes converted at once */
+ char buf[4]; /* output from conversion */
+ int nbytes; /* size of output */
+ int (*decode)(const char *, char *, size_t);
+ char *stop;
+ int ndone;
+ int i;
+ int underscoreok;
+ int skipSpace = 0;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (dstlen == 0)
+ dst = buf; /* point it somewhere valid */
+ stop = dst + dstlen;
+
+ if (base == 0) {
+ if (srclen < 2)
+ return "input too short to be valid";
+ if (*src++ != '0')
+ return "input does not begin with format prefix";
+ switch (*src++) {
+ case 'x':
+ case 'X':
+ base = 16;
+ break;
+ case 's':
+ case 'S':
+ base = 64;
+ break;
+ case 't':
+ case 'T':
+ base = 256;
+ break;
+ default:
+ return "unknown format prefix";
+ }
+ srclen -= 2;
+ }
+ switch (base) {
+ case 16:
+ decode = unhex;
+ underscoreok = 1;
+ ingroup = 2;
+ break;
+ case 64:
+ decode = unb64;
+ underscoreok = 0;
+ ingroup = 4;
+ if(flags & TTODATAV_IGNORESPACE) {
+ skipSpace = 1;
+ }
+ break;
+
+ case 256:
+ decode = untext;
+ ingroup = 1;
+ underscoreok = 0;
+ break;
+ default:
+ return "unknown base";
+ }
+
+ /* proceed */
+ ndone = 0;
+ while (srclen > 0) {
+ char stage[4]; /* staging area for group */
+ size_t sl = 0;
+
+ /* Grab ingroup characters into stage,
+ * squeezing out blanks if we are supposed to ignore them.
+ */
+ for (sl = 0; sl < ingroup; src++, srclen--) {
+ if (srclen == 0)
+ return "input ends in mid-byte, perhaps truncated";
+ else if (!(skipSpace && (*src == ' ' || *src == '\t')))
+ stage[sl++] = *src;
+ }
+
+ nbytes = (*decode)(stage, buf, sizeof(buf));
+ switch (nbytes) {
+ case BADCH0:
+ case BADCH1:
+ case BADCH2:
+ case BADCH3:
+ return badch(stage, nbytes, errp, errlen);
+ case SHORT:
+ return "internal buffer too short (\"can't happen\")";
+ case BADPAD:
+ return "bad (non-zero) padding at end of base64 input";
+ }
+ if (nbytes <= 0)
+ return "unknown internal error";
+ for (i = 0; i < nbytes; i++) {
+ if (dst < stop)
+ *dst++ = buf[i];
+ ndone++;
+ }
+ while (srclen >= 1 && skipSpace && (*src == ' ' || *src == '\t')){
+ src++;
+ srclen--;
+ }
+ if (underscoreok && srclen > 1 && *src == '_') {
+ /* srclen > 1 means not last character */
+ src++;
+ srclen--;
+ }
+ }
+
+ if (ndone == 0)
+ return "no data bytes specified by input";
+ if (lenp != NULL)
+ *lenp = ndone;
+ return NULL;
+}
+
+/*
+ - ttodata - convert text to data
+ */
+const char * /* NULL on success, else literal */
+ttodata(src, srclen, base, dst, dstlen, lenp)
+const char *src;
+size_t srclen; /* 0 means apply strlen() */
+int base; /* 0 means figure it out */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+size_t *lenp; /* where to record length (NULL is nowhere) */
+{
+ return ttodatav(src, srclen, base, dst, dstlen, lenp, (char *)NULL,
+ (size_t)0, TTODATAV_SPACECOUNTS);
+}
+
+/*
+ - atodata - convert ASCII to data
+ * backward-compatibility interface
+ */
+size_t /* 0 for failure, true length for success */
+atodata(src, srclen, dst, dstlen)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+{
+ size_t len;
+ const char *err;
+
+ err = ttodata(src, srclen, 0, dst, dstlen, &len);
+ if (err != NULL)
+ return 0;
+ return len;
+}
+
+/*
+ - atobytes - convert ASCII to data bytes
+ * another backward-compatibility interface
+ */
+const char *
+atobytes(src, srclen, dst, dstlen, lenp)
+const char *src;
+size_t srclen;
+char *dst;
+size_t dstlen;
+size_t *lenp;
+{
+ return ttodata(src, srclen, 0, dst, dstlen, lenp);
+}
+
+/*
+ - unhex - convert two ASCII hex digits to byte
+ */
+static int /* number of result bytes, or error code */
+unhex(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen; /* not large enough is a failure */
+{
+ char *p;
+ unsigned byte;
+ static char hex[] = "0123456789abcdef";
+
+ if (dstlen < 1)
+ return SHORT;
+
+ p = strchr(hex, *src);
+ if (p == NULL)
+ p = strchr(hex, tolower(*src));
+ if (p == NULL)
+ return BADCH0;
+ byte = (p - hex) << 4;
+ src++;
+
+ p = strchr(hex, *src);
+ if (p == NULL)
+ p = strchr(hex, tolower(*src));
+ if (p == NULL)
+ return BADCH1;
+ byte |= (p - hex);
+
+ *dst = byte;
+ return 1;
+}
+
+/*
+ - unb64 - convert four ASCII base64 digits to three bytes
+ * Note that a base64 digit group is padded out with '=' if it represents
+ * less than three bytes: one byte is dd==, two is ddd=, three is dddd.
+ */
+static int /* number of result bytes, or error code */
+unb64(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen;
+{
+ char *p;
+ unsigned byte1;
+ unsigned byte2;
+ static char base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ if (dstlen < 3)
+ return SHORT;
+
+ p = strchr(base64, *src++);
+
+ if (p == NULL)
+ return BADCH0;
+ byte1 = (p - base64) << 2; /* first six bits */
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ return BADCH1;
+ }
+
+ byte2 = p - base64; /* next six: two plus four */
+ *dst++ = byte1 | (byte2 >> 4);
+ byte1 = (byte2 & 0xf) << 4;
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ if (*(src-1) == '=' && *src == '=') {
+ if (byte1 != 0) /* bad padding */
+ return BADPAD;
+ return 1;
+ }
+ return BADCH2;
+ }
+
+ byte2 = p - base64; /* next six: four plus two */
+ *dst++ = byte1 | (byte2 >> 2);
+ byte1 = (byte2 & 0x3) << 6;
+
+ p = strchr(base64, *src++);
+ if (p == NULL) {
+ if (*(src-1) == '=') {
+ if (byte1 != 0) /* bad padding */
+ return BADPAD;
+ return 2;
+ }
+ return BADCH3;
+ }
+ byte2 = p - base64; /* last six */
+ *dst++ = byte1 | byte2;
+
+ return 3;
+}
+
+/*
+ - untext - convert one ASCII character to byte
+ */
+static int /* number of result bytes, or error code */
+untext(src, dst, dstlen)
+const char *src; /* known to be full length */
+char *dst;
+size_t dstlen; /* not large enough is a failure */
+{
+ if (dstlen < 1)
+ return SHORT;
+
+ *dst = *src;
+ return 1;
+}
+
+/*
+ - badch - produce a nice complaint about an unknown character
+ *
+ * If the compiler complains that the array bigenough[] has a negative
+ * size, that means the TTODATAV_BUF constant has been set too small.
+ */
+static const char * /* literal or errp */
+badch(src, errcode, errp, errlen)
+const char *src;
+int errcode;
+char *errp; /* might be NULL */
+size_t errlen;
+{
+ static const char pre[] = "unknown character (`";
+ static const char suf[] = "') in input";
+ char buf[5];
+# define REQD (sizeof(pre) - 1 + sizeof(buf) - 1 + sizeof(suf))
+ struct sizecheck {
+ char bigenough[TTODATAV_BUF - REQD]; /* see above */
+ };
+ char ch;
+
+ if (errp == NULL || errlen < REQD)
+ return "unknown character in input";
+ strcpy(errp, pre);
+ ch = *(src + BADOFF(errcode));
+ if (isprint(ch)) {
+ buf[0] = ch;
+ buf[1] = '\0';
+ } else {
+ buf[0] = '\\';
+ buf[1] = ((ch & 0700) >> 6) + '0';
+ buf[2] = ((ch & 0070) >> 3) + '0';
+ buf[3] = ((ch & 0007) >> 0) + '0';
+ buf[4] = '\0';
+ }
+ strcat(errp, buf);
+ strcat(errp, suf);
+ return (const char *)errp;
+}
+
+
+
+#ifdef TTODATA_MAIN
+
+#include <stdio.h>
+
+struct artab;
+static void check(struct artab *r, char *buf, size_t n, err_t oops, int *status);
+static void regress(char *pgm);
+static void hexout(const char *s, size_t len, FILE *f);
+
+/*
+ - main - convert first argument to hex, or run regression
+ */
+int
+main(int argc, char *argv[])
+{
+ char buf[1024];
+ char buf2[1024];
+ char err[512];
+ size_t n;
+ size_t i;
+ char *p = buf;
+ char *p2 = buf2;
+ char *pgm = argv[0];
+ const char *oops;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {0x<hex>|0s<base64>|-r}\n", pgm);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress(pgm); /* should not return */
+ fprintf(stderr, "%s: regress() returned?!?\n", pgm);
+ exit(1);
+ }
+
+ oops = ttodatav(argv[1], 0, 0, buf, sizeof(buf), &n,
+ err, sizeof(err), TTODATAV_IGNORESPACE);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: ttodata error `%s' in `%s'\n", pgm,
+ oops, argv[1]);
+ exit(1);
+ }
+
+ if (n > sizeof(buf)) {
+ p = (char *)malloc((size_t)n);
+ if (p == NULL) {
+ fprintf(stderr,
+ "%s: unable to malloc %d bytes for result\n",
+ pgm, n);
+ exit(1);
+ }
+ oops = ttodata(argv[1], 0, 0, p, n, &n);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: error `%s' in ttodata retry?!?\n",
+ pgm, oops);
+ exit(1);
+ }
+ }
+
+ hexout(p, n, stdout);
+ printf("\n");
+
+ i = datatot(buf, n, 'h', buf2, sizeof(buf2));
+ if (i == 0) {
+ fprintf(stderr, "%s: datatot reports error in `%s'\n", pgm,
+ argv[1]);
+ exit(1);
+ }
+
+ if (i > sizeof(buf2)) {
+ p2 = (char *)malloc((size_t)i);
+ if (p == NULL) {
+ fprintf(stderr,
+ "%s: unable to malloc %d bytes for result\n",
+ pgm, i);
+ exit(1);
+ }
+ i = datatot(buf, n, 'h', p2, i);
+ if (i == 0) {
+ fprintf(stderr, "%s: error in datatoa retry?!?\n", pgm);
+ exit(1);
+ }
+ }
+
+ printf("%s\n", p2);
+
+ exit(0);
+}
+
+/*
+ - hexout - output an arbitrary-length string in hex
+ */
+static void
+hexout(s, len, f)
+const char *s;
+size_t len;
+FILE *f;
+{
+ size_t i;
+
+ fprintf(f, "0x");
+ for (i = 0; i < len; i++)
+ fprintf(f, "%02x", (unsigned char)s[i]);
+}
+
+struct artab {
+ int base;
+# define IGNORESPACE_BIAS 1000
+ char *ascii; /* NULL for end */
+ char *data; /* NULL for error expected */
+} atodatatab[] = {
+ { 0, "", NULL, },
+ { 0, "0", NULL, },
+ { 0, "0x", NULL, },
+ { 0, "0xa", NULL, },
+ { 0, "0xab", "\xab", },
+ { 0, "0xabc", NULL, },
+ { 0, "0xabcd", "\xab\xcd", },
+ { 0, "0x0123456789", "\x01\x23\x45\x67\x89", },
+ { 0, "0x01x", NULL, },
+ { 0, "0xabcdef", "\xab\xcd\xef", },
+ { 0, "0xABCDEF", "\xab\xcd\xef", },
+ { 0, "0XaBc0eEd81f", "\xab\xc0\xee\xd8\x1f", },
+ { 0, "0XaBc0_eEd8", "\xab\xc0\xee\xd8", },
+ { 0, "0XaBc0_", NULL, },
+ { 0, "0X_aBc0", NULL, },
+ { 0, "0Xa_Bc0", NULL, },
+ { 16, "aBc0eEd8", "\xab\xc0\xee\xd8", },
+ { 0, "0s", NULL, },
+ { 0, "0sA", NULL, },
+ { 0, "0sBA", NULL, },
+ { 0, "0sCBA", NULL, },
+ { 0, "0sDCBA", "\x0c\x20\x40", },
+ { 0, "0SDCBA", "\x0c\x20\x40", },
+ { 0, "0sDA==", "\x0c", },
+ { 0, "0sDC==", NULL, },
+ { 0, "0sDCA=", "\x0c\x20", },
+ { 0, "0sDCB=", NULL, },
+ { 0, "0sDCAZ", "\x0c\x20\x19", },
+ { 0, "0sDCAa", "\x0c\x20\x1a", },
+ { 0, "0sDCAz", "\x0c\x20\x33", },
+ { 0, "0sDCA0", "\x0c\x20\x34", },
+ { 0, "0sDCA9", "\x0c\x20\x3d", },
+ { 0, "0sDCA+", "\x0c\x20\x3e", },
+ { 0, "0sDCA/", "\x0c\x20\x3f", },
+ { 0, "0sAbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0s AbraCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sA braCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAb raCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbr aCadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbra Cadabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraC adabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCa dabra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCad abra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCada bra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadab ra+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabr a+", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabra +", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { IGNORESPACE_BIAS + 0, "0sAbraCadabra+ ", "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", },
+ { 0, "0t", NULL, },
+ { 0, "0tabc_xyz", "abc_xyz", },
+ { 256, "abc_xyz", "abc_xyz", },
+ { 0, NULL, NULL, },
+};
+
+struct drtab {
+ char *data; /* input; NULL for end */
+ char format;
+ int buflen; /* -1 means big buffer */
+ int outlen; /* -1 means strlen(ascii)+1 */
+ char *ascii; /* NULL for error expected */
+} datatoatab[] = {
+ { "", 'x', -1, -1, NULL, },
+ { "", 'X', -1, -1, NULL, },
+ { "", 'n', -1, -1, NULL, },
+ { "0", 'x', -1, -1, "0x30", },
+ { "0", 'x', 0, 5, "---", },
+ { "0", 'x', 1, 5, "", },
+ { "0", 'x', 2, 5, "0", },
+ { "0", 'x', 3, 5, "0x", },
+ { "0", 'x', 4, 5, "0x3", },
+ { "0", 'x', 5, 5, "0x30", },
+ { "0", 'x', 6, 5, "0x30", },
+ { "\xab\xcd", 'x', -1, -1, "0xabcd", },
+ { "\x01\x23\x45\x67\x89", 'x', -1, -1, "0x0123456789", },
+ { "\xab\xcd\xef", 'x', -1, -1, "0xabcdef", },
+ { "\xab\xc0\xee\xd8\x1f", 'x', -1, -1, "0xabc0eed81f", },
+ { "\x01\x02", 'h', -1, -1, "0x0102", },
+ { "\x01\x02\x03\x04\x05\x06", 'h', -1, -1, "0x01020304_0506", },
+ { "\xab\xc0\xee\xd8\x1f", 16, -1, -1, "abc0eed81f", },
+ { "\x0c\x20\x40", 's', -1, -1, "0sDCBA", },
+ { "\x0c\x20\x40", 's', 0, 7, "---", },
+ { "\x0c\x20\x40", 's', 1, 7, "", },
+ { "\x0c\x20\x40", 's', 2, 7, "0", },
+ { "\x0c\x20\x40", 's', 3, 7, "0s", },
+ { "\x0c\x20\x40", 's', 4, 7, "0sD", },
+ { "\x0c\x20\x40", 's', 5, 7, "0sDC", },
+ { "\x0c\x20\x40", 's', 6, 7, "0sDCB", },
+ { "\x0c\x20\x40", 's', 7, 7, "0sDCBA", },
+ { "\x0c\x20\x40", 's', 8, 7, "0sDCBA", },
+ { "\x0c", 's', -1, -1, "0sDA==", },
+ { "\x0c\x20", 's', -1, -1, "0sDCA=", },
+ { "\x0c\x20\x19", 's', -1, -1, "0sDCAZ", },
+ { "\x0c\x20\x1a", 's', -1, -1, "0sDCAa", },
+ { "\x0c\x20\x33", 's', -1, -1, "0sDCAz", },
+ { "\x0c\x20\x34", 's', -1, -1, "0sDCA0", },
+ { "\x0c\x20\x3d", 's', -1, -1, "0sDCA9", },
+ { "\x0c\x20\x3e", 's', -1, -1, "0sDCA+", },
+ { "\x0c\x20\x3f", 's', -1, -1, "0sDCA/", },
+ { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 's', -1, -1, "0sAbraCadabra+", },
+ { "\x01\xba\xda\x09\xa7\x5a\x6e\xb6\xbe", 64, -1, -1, "AbraCadabra+", },
+ { NULL, 'x', -1, -1, NULL, },
+};
+
+/*
+ - regress - regression-test ttodata() and datatot()
+ */
+static void
+check(r, buf, n, oops, status)
+struct artab *r;
+char *buf;
+size_t n;
+err_t oops;
+int *status;
+{
+ if (oops != NULL && r->data == NULL)
+ {} /* error expected */
+ else if (oops != NULL) {
+ printf("`%s' gave error `%s', expecting %d `", r->ascii,
+ oops, strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ } else if (r->data == NULL) {
+ printf("`%s' gave %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting error\n");
+ *status = 1;
+ } else if (n != strlen(r->data)) {
+ printf("length wrong in `%s': got %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting %d `", strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ } else if (memcmp(buf, r->data, n) != 0) {
+ printf("`%s' gave %d `", r->ascii, n);
+ hexout(buf, n, stdout);
+ printf("', expecting %d `", strlen(r->data));
+ hexout(r->data, strlen(r->data), stdout);
+ printf("'\n");
+ *status = 1;
+ }
+ fflush(stdout);
+}
+
+static void /* should not return at all, in fact */
+regress(pgm)
+char *pgm;
+{
+ struct artab *r;
+ struct drtab *dr;
+ char buf[100];
+ size_t n;
+ int status = 0;
+
+ for (r = atodatatab; r->ascii != NULL; r++) {
+ int base = r->base;
+ int xbase = 0;
+
+ if ((base == 0 || base == IGNORESPACE_BIAS + 0) && r->ascii[0] == '0') {
+ switch (r->ascii[1]) {
+ case 'x':
+ case 'X':
+ xbase = 16;
+ break;
+ case 's':
+ case 'S':
+ xbase = 64;
+ break;
+ case 't':
+ case 'T':
+ xbase = 256;
+ break;
+ }
+ }
+
+ if (base >= IGNORESPACE_BIAS) {
+ base = base - IGNORESPACE_BIAS;
+ check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ if (xbase != 0)
+ check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ } else {
+ check(r, buf, n, ttodata(r->ascii, 0, base, buf, sizeof(buf), &n), &status);
+ if (base == 64 || xbase == 64)
+ check(r, buf, n, ttodatav(r->ascii, 0, base, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ if (xbase != 0) {
+ check(r, buf, n, ttodata(r->ascii+2, 0, xbase, buf, sizeof(buf), &n), &status);
+ if (base == 64 || xbase == 64)
+ check(r, buf, n, ttodatav(r->ascii+2, 0, xbase, buf, sizeof(buf), &n, NULL, 0, TTODATAV_IGNORESPACE), &status);
+ }
+ }
+ }
+ for (dr = datatoatab; dr->data != NULL; dr++) {
+ size_t should;
+
+ strcpy(buf, "---");
+ n = datatot(dr->data, strlen(dr->data), dr->format, buf,
+ (dr->buflen == -1) ? sizeof(buf) : dr->buflen);
+ should = (dr->ascii == NULL) ? 0 : strlen(dr->ascii) + 1;
+ if (dr->outlen != -1)
+ should = dr->outlen;
+ if (n == 0 && dr->ascii == NULL)
+ {} /* error expected */
+ else if (n == 0) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' %c gave error, expecting %d `%s'\n",
+ dr->format, should, dr->ascii);
+ status = 1;
+ } else if (dr->ascii == NULL) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' %c gave %d `%.*s', expecting error\n",
+ dr->format, n, (int)n, buf);
+ status = 1;
+ } else if (n != should) {
+ printf("length wrong in `");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("': got %d `%s'", n, buf);
+ printf(", expecting %d `%s'\n", should, dr->ascii);
+ status = 1;
+ } else if (strcmp(buf, dr->ascii) != 0) {
+ printf("`");
+ hexout(dr->data, strlen(dr->data), stdout);
+ printf("' gave %d `%s'", n, buf);
+ printf(", expecting %d `%s'\n", should, dr->ascii);
+ status = 1;
+ }
+ fflush(stdout);
+ }
+ exit(status);
+}
+
+#endif /* TTODATA_MAIN */
diff --git a/linux/lib/libfreeswan/ttoprotoport.c b/linux/lib/libfreeswan/ttoprotoport.c
new file mode 100644
index 000000000..46321838c
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoprotoport.c
@@ -0,0 +1,103 @@
+/*
+ * conversion from protocol/port string to protocol and port
+ * Copyright (C) 2002 Mario Strasser <mast@gmx.net>,
+ * Zuercher Hochschule Winterthur,
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * RCSID $Id: ttoprotoport.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ * ttoprotoport - converts from protocol/port string to protocol and port
+ */
+err_t
+ttoprotoport(src, src_len, proto, port, has_port_wildcard)
+char *src; /* input string */
+size_t src_len; /* length of input string, use strlen() if 0 */
+u_int8_t *proto; /* extracted protocol number */
+u_int16_t *port; /* extracted port number if it exists */
+int *has_port_wildcard; /* set if port is %any */
+{
+ char *end, *service_name;
+ char proto_name[16];
+ int proto_len;
+ long int l;
+ struct protoent *protocol;
+ struct servent *service;
+
+ /* get the length of the string */
+ if (!src_len) src_len = strlen(src);
+
+ /* locate delimiter '/' between protocol and port */
+ end = strchr(src, '/');
+ if (end != NULL) {
+ proto_len = end - src;
+ service_name = end + 1;
+ } else {
+ proto_len = src_len;
+ service_name = src + src_len;
+ }
+
+ /* copy protocol name*/
+ memset(proto_name, '\0', sizeof(proto_name));
+ memcpy(proto_name, src, proto_len);
+
+ /* extract protocol by trying to resolve it by name */
+ protocol = getprotobyname(proto_name);
+ if (protocol != NULL) {
+ *proto = protocol->p_proto;
+ }
+ else /* failed, now try it by number */
+ {
+ l = strtol(proto_name, &end, 0);
+
+ if (*proto_name && *end)
+ return "<protocol> is neither a number nor a valid name";
+
+ if (l < 0 || l > 0xff)
+ return "<protocol> must be between 0 and 255";
+
+ *proto = (u_int8_t)l;
+ }
+
+ /* is there a port wildcard? */
+ *has_port_wildcard = (strcmp(service_name, "%any") == 0);
+
+ if (*has_port_wildcard)
+ {
+ *port = 0;
+ return NULL;
+ }
+
+ /* extract port by trying to resolve it by name */
+ service = getservbyname(service_name, NULL);
+ if (service != NULL) {
+ *port = ntohs(service->s_port);
+ }
+ else /* failed, now try it by number */
+ {
+ l = strtol(service_name, &end, 0);
+
+ if (*service_name && *end)
+ return "<port> is neither a number nor a valid name";
+
+ if (l < 0 || l > 0xffff)
+ return "<port> must be between 0 and 65535";
+
+ *port = (u_int16_t)l;
+ }
+ return NULL;
+}
+
diff --git a/linux/lib/libfreeswan/ttosa.3 b/linux/lib/libfreeswan/ttosa.3
new file mode 100644
index 000000000..bf918e108
--- /dev/null
+++ b/linux/lib/libfreeswan/ttosa.3
@@ -0,0 +1,288 @@
+.TH IPSEC_TTOSA 3 "26 Nov 2001"
+.\" RCSID $Id: ttosa.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttosa, satot \- convert IPsec Security Association IDs to and from text
+.br
+ipsec initsaid \- initialize an SA ID
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "typedef struct {"
+.ti +1c
+.B "ip_address dst;"
+.ti +1c
+.B "ipsec_spi_t spi;"
+.ti +1c
+.B "int proto;"
+.br
+.B "} ip_said;"
+.sp
+.B "const char *ttosa(const char *src, size_t srclen,"
+.ti +1c
+.B "ip_said *sa);
+.br
+.B "size_t satot(const ip_said *sa, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.br
+.B "void initsaid(const ip_address *addr, ipsec_spi_t spi,"
+.ti +1c
+.B "int proto, ip_said *dst);"
+.SH DESCRIPTION
+.I Ttosa
+converts an ASCII Security Association (SA) specifier into an
+.B ip_said
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+.I Satot
+does the reverse conversion, back to a text SA specifier.
+.I Initsaid
+initializes an
+.B ip_said
+from separate items of information.
+.PP
+An SA is specified in text with a mail-like syntax, e.g.
+.BR esp.5a7@1.2.3.4 .
+An SA specifier contains
+a protocol prefix (currently
+.BR ah ,
+.BR esp ,
+.BR tun ,
+.BR comp ,
+or
+.BR int ),
+a single character indicating the address family
+.RB ( .
+for IPv4,
+.B :
+for IPv6),
+an unsigned integer SPI number in hexadecimal (with no
+.B 0x
+prefix),
+and an IP address.
+The IP address can be any form accepted by
+.IR ipsec_ttoaddr (3),
+e.g. dotted-decimal IPv4 address,
+colon-hex IPv6 address,
+or DNS name.
+.PP
+As a special case, the SA specifier
+.B %passthrough4
+or
+.B %passthrough6
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, these are synonyms for
+.B tun.0@0.0.0.0
+and
+.B tun:0@::
+respectively,
+but that is subject to change without notice.)
+.B %passthrough
+is a historical synonym for
+.BR %passthrough4 .
+These forms are known to both
+.I ttosa
+and
+.IR satot ,
+so the internal representation is never visible.
+.PP
+Similarly, the SA specifiers
+.BR %pass ,
+.BR %drop ,
+.BR %reject ,
+.BR %hold ,
+.BR %trap ,
+and
+.BR %trapsubnet
+signify special ``magic'' SAs used to indicate that packets should be
+passed, dropped, rejected (dropped with ICMP notification),
+held,
+and trapped (sent up to
+.IR ipsec_pluto (8),
+with either of two forms of
+.B %hold
+automatically installed)
+respectively.
+These forms too are known to both routines,
+so the internal representation of the magic SAs should never be visible.
+.PP
+The
+.B <freeswan.h>
+header file supplies the
+.B ip_said
+structure, as well as a data type
+.B ipsec_spi_t
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+.PP
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+.B <freeswan.h>
+defines the names
+.BR SA_ESP ,
+.BR SA_AH ,
+.BR SA_IPIP ,
+and
+.BR SA_COMP
+to have the same values as the kernel names
+.BR IPPROTO_ESP ,
+.BR IPPROTO_AH ,
+.BR IPPROTO_IPIP ,
+and
+.BR IPPROTO_COMP .
+.PP
+.B <freeswan.h>
+also defines
+.BR SA_INT
+to have the value
+.BR 61
+(reserved by IANA for ``any host internal protocol'')
+and
+.BR SPI_PASS ,
+.BR SPI_DROP ,
+.BR SPI_REJECT ,
+.BR SPI_HOLD ,
+and
+.B SPI_TRAP
+to have the values 256-260 (in \fIhost\fR byte order) respectively.
+These are used in constructing the magic SAs
+(which always have address
+.BR 0.0.0.0 ).
+.PP
+If
+.I satot
+encounters an unknown protocol code, e.g. 77,
+it yields output using a prefix
+showing the code numerically, e.g. ``unk77''.
+This form is
+.I not
+recognized by
+.IR ttosa .
+.PP
+The
+.I srclen
+parameter of
+.I ttosa
+specifies the length of the string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I satot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.B <freeswan.h>
+header file defines a constant,
+.BR SATOT_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I satot
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI,
+dotted-decimal or colon-hex address).
+The value
+.B 'f'
+is similar except that the SPI is padded with
+.BR 0 s
+to a fixed 32-bit width, to ease aligning displayed tables.
+.PP
+.I Ttosa
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Satot
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.PP
+There is also, temporarily, support for some obsolete
+forms of SA specifier which lack the address-family indicator.
+.SH SEE ALSO
+ipsec_ttoul(3), ipsec_ttoaddr(3), ipsec_samesaid(3), inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttosa
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+.B @
+in input;
+unknown protocol prefix;
+conversion error in
+.I ttoul
+or
+.IR ttoaddr .
+.PP
+Fatal errors in
+.I satot
+are:
+unknown format.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The restriction of text-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The text-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttosa( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/ttosa.c b/linux/lib/libfreeswan/ttosa.c
new file mode 100644
index 000000000..aa2283694
--- /dev/null
+++ b/linux/lib/libfreeswan/ttosa.c
@@ -0,0 +1,280 @@
+/*
+ * convert from text form of SA ID to binary
+ * Copyright (C) 2000, 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttosa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct satype {
+ char *prefix;
+ size_t prelen; /* strlen(prefix) */
+ int proto;
+} satypes[] = {
+ { "ah", 2, SA_AH },
+ { "esp", 3, SA_ESP },
+ { "tun", 3, SA_IPIP },
+ { "comp", 4, SA_COMP },
+ { "int", 3, SA_INT },
+ { NULL, 0, 0, }
+};
+
+static struct magic {
+ char *name;
+ char *really;
+} magic[] = {
+ { PASSTHROUGHNAME, PASSTHROUGH4IS },
+ { PASSTHROUGH4NAME, PASSTHROUGH4IS },
+ { PASSTHROUGH6NAME, PASSTHROUGH6IS },
+ { "%pass", "int256@0.0.0.0" },
+ { "%drop", "int257@0.0.0.0" },
+ { "%reject", "int258@0.0.0.0" },
+ { "%hold", "int259@0.0.0.0" },
+ { "%trap", "int260@0.0.0.0" },
+ { "%trapsubnet", "int261@0.0.0.0" },
+ { NULL, NULL }
+};
+
+/*
+ - ttosa - convert text "ah507@10.0.0.1" to SA identifier
+ */
+err_t /* NULL for success, else string literal */
+ttosa(src, srclen, sa)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+ip_said *sa;
+{
+ const char *at;
+ const char *addr;
+ size_t alen;
+ const char *spi = NULL;
+ struct satype *sat;
+ unsigned long ul;
+ const char *oops;
+ struct magic *mp;
+ size_t nlen;
+# define MINLEN 5 /* ah0@0 is as short as it can get */
+ int af;
+ int base;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ if (srclen < MINLEN)
+ return "string too short to be SA identifier";
+ if (*src == '%') {
+ for (mp = magic; mp->name != NULL; mp++) {
+ nlen = strlen(mp->name);
+ if (srclen == nlen && memcmp(src, mp->name, nlen) == 0)
+ break;
+ }
+ if (mp->name == NULL)
+ return "unknown % keyword";
+ src = mp->really;
+ srclen = strlen(src);
+ }
+
+ at = memchr(src, '@', srclen);
+ if (at == NULL)
+ return "no @ in SA specifier";
+
+ for (sat = satypes; sat->prefix != NULL; sat++)
+ if (sat->prelen < srclen &&
+ strncmp(src, sat->prefix, sat->prelen) == 0) {
+ sa->proto = sat->proto;
+ spi = src + sat->prelen;
+ break; /* NOTE BREAK OUT */
+ }
+ if (sat->prefix == NULL)
+ return "SA specifier lacks valid protocol prefix";
+
+ if (spi >= at)
+ return "no SPI in SA specifier";
+ switch (*spi) {
+ case '.':
+ af = AF_INET;
+ spi++;
+ base = 16;
+ break;
+ case ':':
+ af = AF_INET6;
+ spi++;
+ base = 16;
+ break;
+ default:
+ af = AF_UNSPEC; /* not known yet */
+ base = 0;
+ break;
+ }
+ if (spi >= at)
+ return "no SPI found in SA specifier";
+ oops = ttoul(spi, at - spi, base, &ul);
+ if (oops != NULL)
+ return oops;
+ sa->spi = htonl(ul);
+
+ addr = at + 1;
+ alen = srclen - (addr - src);
+ if (af == AF_UNSPEC)
+ af = (memchr(addr, ':', alen) != NULL) ? AF_INET6 : AF_INET;
+ oops = ttoaddr(addr, alen, af, &sa->dst);
+ if (oops != NULL)
+ return oops;
+
+ return NULL;
+}
+
+
+
+#ifdef TTOSA_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ ip_said sa;
+ char buf[100];
+ char buf2[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = ttosa(argv[1], 0, &sa);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = satot(&sa, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
+ fprintf(stderr, "%lx@", (long unsigned int)sa.spi);
+ (void) addrtot(&sa.dst, 0, buf2, sizeof(buf2));
+ fprintf(stderr, "%s", buf2);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int format;
+# define FUDGE 0x1000
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {0, "esp257@1.2.3.0", "esp.101@1.2.3.0"},
+ {0, "ah0x20@1.2.3.4", "ah.20@1.2.3.4"},
+ {0, "tun20@1.2.3.4", "tun.14@1.2.3.4"},
+ {0, "comp20@1.2.3.4", "comp.14@1.2.3.4"},
+ {0, "esp257@::1", "esp:101@::1"},
+ {0, "esp257@0bc:12de::1", "esp:101@bc:12de::1"},
+ {0, "esp78@1049:1::8007:2040", "esp:4e@1049:1::8007:2040"},
+ {0, "esp0x78@1049:1::8007:2040", "esp:78@1049:1::8007:2040"},
+ {0, "ah78@1049:1::8007:2040", "ah:4e@1049:1::8007:2040"},
+ {0, "ah0x78@1049:1::8007:2040", "ah:78@1049:1::8007:2040"},
+ {0, "tun78@1049:1::8007:2040", "tun:4e@1049:1::8007:2040"},
+ {0, "tun0x78@1049:1::8007:2040", "tun:78@1049:1::8007:2040"},
+ {0, "duk99@3ffe:370:400:ff::9001:3001", NULL},
+ {0, "esp78x@1049:1::8007:2040", NULL},
+ {0, "esp0x78@1049:1:0xfff::8007:2040", NULL},
+ {0, "es78@1049:1::8007:2040", NULL},
+ {0, "", NULL},
+ {0, "_", NULL},
+ {0, "ah2.2", NULL},
+ {0, "goo2@1.2.3.4", NULL},
+ {0, "esp9@1.2.3.4", "esp.9@1.2.3.4"},
+ {'f', "esp0xa9@1.2.3.4", "esp.000000a9@1.2.3.4"},
+ {0, "espp9@1.2.3.4", NULL},
+ {0, "es9@1.2.3.4", NULL},
+ {0, "ah@1.2.3.4", NULL},
+ {0, "esp7x7@1.2.3.4", NULL},
+ {0, "esp77@1.0x2.3.4", NULL},
+ {0, PASSTHROUGHNAME, PASSTHROUGH4NAME},
+ {0, PASSTHROUGH6NAME, PASSTHROUGH6NAME},
+ {0, "%pass", "%pass"},
+ {0, "int256@0.0.0.0", "%pass"},
+ {0, "%drop", "%drop"},
+ {0, "int257@0.0.0.0", "%drop"},
+ {0, "%reject", "%reject"},
+ {0, "int258@0.0.0.0", "%reject"},
+ {0, "%hold", "%hold"},
+ {0, "int259@0.0.0.0", "%hold"},
+ {0, "%trap", "%trap"},
+ {0, "int260@0.0.0.0", "%trap"},
+ {0, "%trapsubnet", "%trapsubnet"},
+ {0, "int261@0.0.0.0", "%trapsubnet"},
+ {0, "int262@0.0.0.0", "int.106@0.0.0.0"},
+ {FUDGE, "esp9@1.2.3.4", "unk77.9@1.2.3.4"},
+ {0, NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ ip_said sa;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = ttosa(in, 0, &sa);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' ttosa failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' ttosa succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ if (r->format&FUDGE)
+ sa.proto = 77;
+ n = satot(&sa, (char)r->format, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' satot failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* TTOSA_MAIN */
diff --git a/linux/lib/libfreeswan/ttosubnet.c b/linux/lib/libfreeswan/ttosubnet.c
new file mode 100644
index 000000000..7f5cddb82
--- /dev/null
+++ b/linux/lib/libfreeswan/ttosubnet.c
@@ -0,0 +1,296 @@
+/*
+ * convert from text form of subnet specification to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttosubnet.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+#ifndef DEFAULTSUBNET
+#define DEFAULTSUBNET "%default"
+#endif
+
+/*
+ - ttosubnet - convert text "addr/mask" to address and mask
+ * Mask can be integer bit count.
+ */
+err_t
+ttosubnet(src, srclen, af, dst)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+int af; /* AF_INET or AF_INET6 */
+ip_subnet *dst;
+{
+ const char *slash;
+ const char *colon;
+ const char *mask;
+ size_t mlen;
+ const char *oops;
+ unsigned long bc;
+ static char def[] = DEFAULTSUBNET;
+# define DEFLEN (sizeof(def) - 1) /* -1 for NUL */
+ static char defis4[] = "0/0";
+# define DEFIS4LEN (sizeof(defis4) - 1)
+ static char defis6[] = "::/0";
+# define DEFIS6LEN (sizeof(defis6) - 1)
+ ip_address addrtmp;
+ ip_address masktmp;
+ int nbits;
+ int i;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ switch (af) {
+ case AF_INET:
+ nbits = 32;
+ break;
+ case AF_INET6:
+ nbits = 128;
+ break;
+ default:
+ return "unknown address family in ttosubnet";
+ break;
+ }
+
+ if (srclen == DEFLEN && strncmp(src, def, srclen) == 0) {
+ src = (af == AF_INET) ? defis4 : defis6;
+ srclen = (af == AF_INET) ? DEFIS4LEN : DEFIS6LEN;
+ }
+
+ slash = memchr(src, '/', srclen);
+ if (slash == NULL)
+ return "no / in subnet specification";
+ mask = slash + 1;
+ mlen = srclen - (mask - src);
+
+ oops = ttoaddr(src, slash-src, af, &addrtmp);
+ if (oops != NULL)
+ return oops;
+
+ /* extract port */
+ colon = memchr(mask, ':', mlen);
+ if (colon == 0)
+ {
+ setportof(0, &addrtmp);
+ }
+ else
+ {
+ long port;
+
+ oops = ttoul(colon+1, mlen-(colon-mask+1), 10, &port);
+ if (oops != NULL)
+ return oops;
+ setportof(htons(port), &addrtmp);
+ mlen = colon - mask;
+ }
+
+ /*extract mask */
+ oops = ttoul(mask, mlen, 10, &bc);
+ if (oops == NULL) {
+ /* ttoul succeeded, it's a bit-count mask */
+ if (bc > nbits)
+ return "subnet mask bit count too large";
+ i = bc;
+ } else {
+ oops = ttoaddr(mask, mlen, af, &masktmp);
+ if (oops != NULL)
+ return oops;
+ i = masktocount(&masktmp);
+ if (i < 0)
+ return "non-contiguous or otherwise erroneous mask";
+ }
+
+ return initsubnet(&addrtmp, i, '0', dst);
+}
+
+
+
+#ifdef TTOSUBNET_MAIN
+
+#include <stdio.h>
+
+void regress(void);
+
+int main(int argc, char *argv[])
+{
+ ip_subnet s;
+ char buf[100];
+ char buf2[100];
+ const char *oops;
+ size_t n;
+ int af;
+ char *p;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s [-6] addr/mask\n", argv[0]);
+ fprintf(stderr, " or: %s -r\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ af = AF_INET;
+ p = argv[1];
+ if (strcmp(argv[1], "-6") == 0) {
+ af = AF_INET6;
+ p = argv[2];
+ } else if (strchr(argv[1], ':') != NULL)
+ af = AF_INET6;
+
+ oops = ttosubnet(p, 0, af, &s);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = subnettot(&s, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conversion of ", argv[0]);
+ (void) addrtot(&s.addr, 0, buf2, sizeof(buf2));
+ fprintf(stderr, "%s/", buf2);
+ fprintf(stderr, "%d", s.maskbits);
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ int family;
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {4, "1.2.3.0/255.255.255.0", "1.2.3.0/24"},
+ {4, "1.2.3.0/24", "1.2.3.0/24"},
+ {4, "1.2.3.0/24:10", "1.2.3.0/24:10"},
+ {4, "1.2.3.0/24:-1", NULL},
+ {4, "1.2.3.0/24:none", NULL},
+ {4, "1.2.3.0/24:", NULL},
+ {4, "1.2.3.0/24:0x10", "1.2.3.0/24:16"},
+ {4, "1.2.3.0/24:0X10", "1.2.3.0/24:16"},
+ {4, "1.2.3.0/24:010", "1.2.3.0/24:8"},
+ {4, "1.2.3.1/255.255.255.240", "1.2.3.0/28"},
+ {4, "1.2.3.1/32", "1.2.3.1/32"},
+ {4, "1.2.3.1/0", "0.0.0.0/0"},
+/* {4, "1.2.3.1/255.255.127.0", "1.2.3.0/255.255.127.0"}, */
+ {4, "1.2.3.1/255.255.127.0", NULL},
+ {4, "128.009.000.032/32", "128.9.0.32/32"},
+ {4, "128.0x9.0.32/32", NULL},
+ {4, "0x80090020/32", "128.9.0.32/32"},
+ {4, "0x800x0020/32", NULL},
+ {4, "128.9.0.32/0xffFF0000", "128.9.0.0/16"},
+ {4, "128.9.0.32/0xff0000FF", NULL},
+ {4, "128.9.0.32/0x0000ffFF", NULL},
+ {4, "128.9.0.32/0x00ffFF0000", NULL},
+ {4, "128.9.0.32/0xffFF", NULL},
+ {4, "128.9.0.32.27/32", NULL},
+ {4, "128.9.0k32/32", NULL},
+ {4, "328.9.0.32/32", NULL},
+ {4, "128.9..32/32", NULL},
+ {4, "10/8", "10.0.0.0/8"},
+ {4, "10.0/8", "10.0.0.0/8"},
+ {4, "10.0.0/8", "10.0.0.0/8"},
+ {4, "10.0.1/24", "10.0.1.0/24"},
+ {4, "_", NULL},
+ {4, "_/_", NULL},
+ {4, "1.2.3.1", NULL},
+ {4, "1.2.3.1/_", NULL},
+ {4, "1.2.3.1/24._", NULL},
+ {4, "1.2.3.1/99", NULL},
+ {4, "localhost/32", "127.0.0.1/32"},
+ {4, "%default", "0.0.0.0/0"},
+ {6, "3049:1::8007:2040/0", "::/0"},
+ {6, "3049:1::8007:2040/128", "3049:1::8007:2040/128"},
+ {6, "3049:1::192.168.0.1/128", NULL}, /*"3049:1::c0a8:1/128",*/
+ {6, "3049:1::8007::2040/128", NULL},
+ {6, "3049:1::8007:2040/ffff::0", "3049::/16"},
+ {6, "3049:1::8007:2040/64", "3049:1::/64"},
+ {6, "3049:1::8007:2040/ffff::", "3049::/16"},
+ {6, "3049:1::8007:2040/0000:ffff::0", NULL},
+ {6, "3049:1::8007:2040/ff1f::0", NULL},
+ {6, "3049:1::8007:x:2040/128", NULL},
+ {6, "3049:1t::8007:2040/128", NULL},
+ {6, "3049:1::80071:2040/128", NULL},
+ {6, "::/21", "::/21"},
+ {6, "::1/128", "::1/128"},
+ {6, "1::/21", "1::/21"},
+ {6, "1::2/128", "1::2/128"},
+ {6, "1:0:0:0:0:0:0:2/128", "1::2/128"},
+ {6, "1:0:0:0:3:0:0:2/128", "1::3:0:0:2/128"},
+ {6, "1:0:0:3:0:0:0:2/128", "1::3:0:0:0:2/128"},
+ {6, "1:0:3:0:0:0:0:2/128", "1:0:3::2/128"},
+ {6, "abcd:ef01:2345:6789:0:00a:000:20/128", "abcd:ef01:2345:6789:0:a:0:20/128"},
+ {6, "3049:1::8007:2040/ffff:ffff:", NULL},
+ {6, "3049:1::8007:2040/ffff:88::", NULL},
+ {6, "3049:12::9000:3200/ffff:fff0::", "3049:10::/28"},
+ {6, "3049:12::9000:3200/28", "3049:10::/28"},
+ {6, "3049:12::9000:3200/ff00:::", NULL},
+ {6, "3049:12::9000:3200/ffff:::", NULL},
+ {6, "3049:12::9000:3200/128_", NULL},
+ {6, "3049:12::9000:3200/", NULL},
+ {6, "%default", "::/0"},
+ {4, NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ ip_subnet s;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+ int af;
+
+ for (r = rtab; r->input != NULL; r++) {
+ af = (r->family == 4) ? AF_INET : AF_INET6;
+ strcpy(in, r->input);
+ oops = ttosubnet(in, 0, af, &s);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' ttosubnet failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' ttosubnet succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = subnettot(&s, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' subnettot failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* TTOSUBNET_MAIN */
diff --git a/linux/lib/libfreeswan/ttoul.3 b/linux/lib/libfreeswan/ttoul.3
new file mode 100644
index 000000000..67d4bd34f
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoul.3
@@ -0,0 +1,192 @@
+.TH IPSEC_TTOUL 3 "16 Aug 2000"
+.\" RCSID $Id: ttoul.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ttoul, ultot \- convert unsigned-long numbers to and from text
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ttoul(const char *src, size_t srclen,"
+.ti +1c
+.B "int base, unsigned long *n);"
+.br
+.B "size_t ultot(unsigned long n, int format, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+.I Ttoul
+converts a text-string number into a binary
+.B "unsigned long"
+value.
+.I Ultot
+does the reverse conversion, back to a text version.
+.PP
+Numbers are specified in text as
+decimal (e.g.
+.BR 123 ),
+octal with a leading zero (e.g.
+.BR 012 ,
+which has value 10),
+or hexadecimal with a leading
+.B 0x
+(e.g.
+.BR 0x1f ,
+which has value 31)
+in either upper or lower case.
+.PP
+The
+.I srclen
+parameter of
+.I ttoul
+specifies the length of the string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I base
+parameter of
+.I ttoul
+can be
+.BR 8 ,
+.BR 10 ,
+or
+.BR 16 ,
+in which case the number supplied is assumed to be of that form
+(and in the case of
+.BR 16 ,
+to lack any
+.B 0x
+prefix).
+It can also be
+.BR 0 ,
+in which case the number is examined for a leading zero
+or a leading
+.B 0x
+to determine its base.
+.PP
+The
+.I dstlen
+parameter of
+.I ultot
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR ULTOT_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I ultot
+must be one of:
+.RS
+.IP \fB'o'\fR 4
+octal conversion with leading
+.B 0
+.IP \fB\ 8\fR
+octal conversion with no leading
+.B 0
+.IP \fB'd'\fR
+decimal conversion
+.IP \fB10\fR
+same as
+.B d
+.IP \fB'x'\fR
+hexadecimal conversion, including leading
+.B 0x
+.IP \fB16\fR
+hexadecimal conversion with no leading
+.B 0x
+.IP \fB17\fR
+like
+.B 16
+except padded on left with
+.BR 0 s
+to eight digits (full width of a 32-bit number)
+.RE
+.PP
+.I Ttoul
+returns NULL for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Ultot
+returns
+.B 0
+for a failure, and otherwise
+returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL
+(it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred).
+.SH SEE ALSO
+atol(3), strtoul(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I ttoul
+are:
+empty input;
+unknown
+.IR base ;
+non-digit character found;
+number too large for an
+.BR "unsigned long" .
+.PP
+Fatal errors in
+.I ultot
+are:
+unknown
+.IR format .
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+Conversion of
+.B 0
+with format
+.B o
+yields
+.BR 00 .
+.PP
+.I Ultot
+format
+.B 17
+is a bit of a kludge.
+.PP
+The restriction of error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The error-reporting convention lends itself to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = ttoul( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/linux/lib/libfreeswan/ttoul.c b/linux/lib/libfreeswan/ttoul.c
new file mode 100644
index 000000000..9c6193c68
--- /dev/null
+++ b/linux/lib/libfreeswan/ttoul.c
@@ -0,0 +1,91 @@
+/*
+ * convert from text form of unsigned long to binary
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ttoul.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ttoul - convert text substring to unsigned long number
+ */
+const char * /* NULL for success, else string literal */
+ttoul(src, srclen, base, resultp)
+const char *src;
+size_t srclen; /* 0 means strlen(src) */
+int base; /* 0 means figure it out */
+unsigned long *resultp;
+{
+ const char *stop;
+ static char hex[] = "0123456789abcdef";
+ static char uchex[] = "0123456789ABCDEF";
+ int d;
+ char c;
+ char *p;
+ unsigned long r;
+ unsigned long rlimit;
+ int dlimit;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+
+ if (base == 0) {
+ if (srclen > 2 && *src == '0' &&
+ (*(src+1) == 'x' || *(src+1) == 'X'))
+ return ttoul(src+2, srclen-2, 16, resultp);
+ if (srclen > 1 && *src == '0')
+ return ttoul(src+1, srclen-1, 8, resultp);
+ return ttoul(src, srclen, 10, resultp);
+ }
+ if (base != 8 && base != 10 && base != 16)
+ return "unsupported number base";
+
+ r = 0;
+ stop = src + srclen;
+ if (base == 16) {
+ while (src < stop) {
+ c = *src++;
+ p = strchr(hex, c);
+ if (p != NULL)
+ d = p - hex;
+ else {
+ p = strchr(uchex, c);
+ if (p == NULL)
+ return "non-hex digit in hex number";
+ d = p - uchex;
+ }
+ r = (r << 4) | d;
+ }
+ /* defer length check to catch invalid digits first */
+ if (srclen > sizeof(unsigned long) * 2)
+ return "hex number too long";
+ } else {
+ rlimit = ULONG_MAX / base;
+ dlimit = (int)(ULONG_MAX - rlimit*base);
+ while (src < stop) {
+ c = *src++;
+ d = c - '0';
+ if (d < 0 || d >= base)
+ return "non-digit in number";
+ if (r > rlimit || (r == rlimit && d > dlimit))
+ return "unsigned-long overflow";
+ r = r*base + d;
+ }
+ }
+
+ *resultp = r;
+ return NULL;
+}
diff --git a/linux/lib/libfreeswan/ultoa.c b/linux/lib/libfreeswan/ultoa.c
new file mode 100644
index 000000000..2c2644826
--- /dev/null
+++ b/linux/lib/libfreeswan/ultoa.c
@@ -0,0 +1,67 @@
+/*
+ * convert unsigned long to ASCII
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ultoa.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ultoa - convert unsigned long to decimal ASCII
+ */
+size_t /* length required for full conversion */
+ultoa(n, base, dst, dstlen)
+unsigned long n;
+int base;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[3*sizeof(unsigned long) + 1];
+ char *bufend = buf + sizeof(buf);
+ size_t len;
+ char *p;
+ static char hex[] = "0123456789abcdef";
+
+ p = bufend;
+ *--p = '\0';
+ if (base == 10) {
+ do {
+ *--p = n%10 + '0';
+ n /= 10;
+ } while (n != 0);
+ } else if (base == 16) {
+ do {
+ *--p = hex[n&0xf];
+ n >>= 4;
+ } while (n != 0);
+ *--p = 'x';
+ *--p = '0';
+ } else if (base == 8) {
+ do {
+ *--p = (n&07) + '0';
+ n >>= 3;
+ } while (n != 0);
+ *--p = '0';
+ } else
+ *--p = '?';
+
+ len = bufend - p;
+
+ if (dstlen > 0) {
+ if (len > dstlen)
+ *(p + dstlen - 1) = '\0';
+ strcpy(dst, p);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/ultot.c b/linux/lib/libfreeswan/ultot.c
new file mode 100644
index 000000000..edffa4a2d
--- /dev/null
+++ b/linux/lib/libfreeswan/ultot.c
@@ -0,0 +1,83 @@
+/*
+ * convert unsigned long to text
+ * Copyright (C) 2000 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: ultot.c,v 1.1 2004/03/15 20:35:26 as Exp $
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - ultot - convert unsigned long to text
+ */
+size_t /* length required for full conversion */
+ultot(n, base, dst, dstlen)
+unsigned long n;
+int base;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[3*sizeof(unsigned long) + 1];
+ char *bufend = buf + sizeof(buf);
+ size_t len;
+ char *p;
+ static char hex[] = "0123456789abcdef";
+# define HEX32 (32/4)
+
+ p = bufend;
+ *--p = '\0';
+ switch (base) {
+ case 10:
+ case 'd':
+ do {
+ *--p = n%10 + '0';
+ n /= 10;
+ } while (n != 0);
+ break;
+ case 16:
+ case 17:
+ case 'x':
+ do {
+ *--p = hex[n&0xf];
+ n >>= 4;
+ } while (n != 0);
+ if (base == 17)
+ while (bufend - p < HEX32 + 1)
+ *--p = '0';
+ if (base == 'x') {
+ *--p = 'x';
+ *--p = '0';
+ }
+ break;
+ case 8:
+ case 'o':
+ do {
+ *--p = (n&07) + '0';
+ n >>= 3;
+ } while (n != 0);
+ if (base == 'o')
+ *--p = '0';
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ len = bufend - p;
+ if (dstlen > 0) {
+ if (len > dstlen)
+ *(p + dstlen - 1) = '\0';
+ strcpy(dst, p);
+ }
+ return len;
+}
diff --git a/linux/lib/libfreeswan/version.3 b/linux/lib/libfreeswan/version.3
new file mode 100644
index 000000000..06c5f01e3
--- /dev/null
+++ b/linux/lib/libfreeswan/version.3
@@ -0,0 +1,44 @@
+.TH IPSEC_VERSION 3 "21 Nov 2001"
+.\" RCSID $Id: version.3,v 1.1 2004/03/15 20:35:26 as Exp $
+.SH NAME
+ipsec ipsec_version_code \- get IPsec version code
+.br
+ipsec ipsec_version_string \- get full IPsec version string
+.br
+ipsec ipsec_copyright_notice \- get IPsec copyright notice
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *ipsec_version_code(void);"
+.br
+.B "const char *ipsec_version_string(void);"
+.br
+.B "const char **ipsec_copyright_notice(void);"
+.SH DESCRIPTION
+These functions provide information on version numbering and copyright
+of the Linux FreeS/WAN IPsec implementation.
+.PP
+.I Ipsec_version_code
+returns a pointer to a string constant
+containing the current IPsec version code,
+such as ``1.92'' or ``snap2001Nov19b''.
+.PP
+.I Ipsec_version_string
+returns a pointer to a string constant giving a full version identification,
+consisting of the version code preceded by a prefix identifying the software,
+e.g. ``Linux FreeS/WAN 1.92''.
+.PP
+.I Ipsec_copyright_notice
+returns a pointer to a vector of pointers,
+terminated by a
+.BR NULL ,
+which is the text of a suitable copyright notice.
+Each pointer points to a string constant (possibly empty) which is one line
+of the somewhat-verbose copyright notice.
+The strings are NUL-terminated and do not contain a newline;
+supplying suitable line termination for the output device is
+the caller's responsibility.
+.SH SEE ALSO
+ipsec(8)
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/linux/lib/libfreeswan/version.in.c b/linux/lib/libfreeswan/version.in.c
new file mode 100644
index 000000000..b3556f721
--- /dev/null
+++ b/linux/lib/libfreeswan/version.in.c
@@ -0,0 +1,44 @@
+/*
+ * return IPsec version information
+ * Copyright (C) 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ *
+ * RCSID $Id: version.in.c,v 1.2 2004/03/16 12:26:32 as Exp $
+ */
+
+#ifdef __KERNEL__
+#include <linux/netdevice.h>
+#endif
+
+#include "freeswan.h"
+
+#define V "xxx" /* substituted in by Makefile */
+static const char strongswan_number[] = V;
+static const char strongswan_string[] = "Linux strongSwan " V;
+
+/*
+ - ipsec_version_code - return IPsec version number/code, as string
+ */
+const char *
+ipsec_version_code()
+{
+ return strongswan_number;
+}
+
+/*
+ - ipsec_version_string - return full version string
+ */
+const char *
+ipsec_version_string()
+{
+ return strongswan_string;
+}