summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortteras <tteras@NetBSD.org>2009-03-06 11:45:03 +0000
committertteras <tteras@NetBSD.org>2009-03-06 11:45:03 +0000
commite3372d2f8f7971a8d6b0edc84710d34838c59cd6 (patch)
treecbf45ed94ecf3f78ffacd8c2ee6a18d4316e1bae
parent61b1fbae0d39e80bffb534617bded468a7ca36be (diff)
setkey: fix deleteall in Linux
Linux requires SADB_DELETE message to have SPI. So send a SADB_DELETE message for each matching SA. Trac #284. From: Gabriel Somlo <somlo@cmu.edu>
-rw-r--r--crypto/dist/ipsec-tools/src/setkey/extern.h5
-rw-r--r--crypto/dist/ipsec-tools/src/setkey/parse.y26
-rw-r--r--crypto/dist/ipsec-tools/src/setkey/setkey.c165
3 files changed, 188 insertions, 8 deletions
diff --git a/crypto/dist/ipsec-tools/src/setkey/extern.h b/crypto/dist/ipsec-tools/src/setkey/extern.h
index 93eea436908..6f439fafb3f 100644
--- a/crypto/dist/ipsec-tools/src/setkey/extern.h
+++ b/crypto/dist/ipsec-tools/src/setkey/extern.h
@@ -1,4 +1,4 @@
-/* $NetBSD: extern.h,v 1.4 2006/09/09 16:22:37 manu Exp $ */
+/* $NetBSD: extern.h,v 1.5 2009/03/06 11:45:03 tteras Exp $ */
@@ -14,6 +14,9 @@ int yyparse __P((void));
void yyfatal __P((const char *));
void yyerror __P((const char *));
+u_int32_t *sendkeymsg_spigrep __P((unsigned int, struct addrinfo *,
+ struct addrinfo *, int *));
+
extern int f_rfcmode;
extern int lineno;
extern int last_msg_type;
diff --git a/crypto/dist/ipsec-tools/src/setkey/parse.y b/crypto/dist/ipsec-tools/src/setkey/parse.y
index 2f7e8566e46..4b211a2b43e 100644
--- a/crypto/dist/ipsec-tools/src/setkey/parse.y
+++ b/crypto/dist/ipsec-tools/src/setkey/parse.y
@@ -1,4 +1,4 @@
-/* $NetBSD: parse.y,v 1.11 2008/12/29 12:54:33 mlelstv Exp $ */
+/* $NetBSD: parse.y,v 1.12 2009/03/06 11:45:03 tteras Exp $ */
/* $KAME: parse.y,v 1.81 2003/07/01 04:01:48 itojun Exp $ */
@@ -211,11 +211,27 @@ delete_command
deleteall_command
: DELETEALL ipaddropts ipaddr ipaddr protocol_spec EOT
{
- int status;
-
- status = setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1);
- if (status < 0)
+#ifndef __linux__
+ if (setkeymsg_addr(SADB_DELETE, $5, $3, $4, 1) < 0)
return -1;
+#else /* __linux__ */
+ /* linux strictly adheres to RFC2367, and returns
+ * an error if we send an SADB_DELETE request without
+ * an SPI. Therefore, we must first retrieve a list
+ * of SPIs for all matching SADB entries, and then
+ * delete each one separately. */
+ u_int32_t *spi;
+ int i, n;
+
+ spi = sendkeymsg_spigrep($5, $3, $4, &n);
+ for (i = 0; i < n; i++) {
+ p_spi = spi[i];
+ if (setkeymsg_addr(SADB_DELETE,
+ $5, $3, $4, 0) < 0)
+ return -1;
+ }
+ free(spi);
+#endif /* __linux__ */
}
;
diff --git a/crypto/dist/ipsec-tools/src/setkey/setkey.c b/crypto/dist/ipsec-tools/src/setkey/setkey.c
index 317dce10213..6c40250d51c 100644
--- a/crypto/dist/ipsec-tools/src/setkey/setkey.c
+++ b/crypto/dist/ipsec-tools/src/setkey/setkey.c
@@ -1,4 +1,4 @@
-/* $NetBSD: setkey.c,v 1.12 2007/07/18 12:07:52 vanhu Exp $ */
+/* $NetBSD: setkey.c,v 1.13 2009/03/06 11:45:03 tteras Exp $ */
/* $KAME: setkey.c,v 1.36 2003/09/24 23:52:51 itojun Exp $ */
@@ -445,6 +445,167 @@ promisc()
}
}
+/* Generate 'spi' array with SPIs matching 'satype', 'srcs', and 'dsts'
+ * Return value is dynamically generated array of SPIs, also number of
+ * SPIs through num_spi pointer.
+ * On any error, set *num_spi to 0 and return NULL.
+ */
+u_int32_t *
+sendkeymsg_spigrep(satype, srcs, dsts, num_spi)
+ unsigned int satype;
+ struct addrinfo *srcs;
+ struct addrinfo *dsts;
+ int *num_spi;
+{
+ struct sadb_msg msg, *m;
+ char *buf;
+ size_t len;
+ ssize_t l;
+ u_char rbuf[1024 * 32];
+ caddr_t mhp[SADB_EXT_MAX + 1];
+ struct sadb_address *saddr;
+ struct sockaddr *s;
+ struct addrinfo *a;
+ struct sadb_sa *sa;
+ u_int32_t *spi = NULL;
+ int max_spi = 0, fail = 0;
+
+ *num_spi = 0;
+
+ if (f_notreally) {
+ return NULL;
+ }
+
+ {
+ struct timeval tv;
+ tv.tv_sec = 1;
+ tv.tv_usec = 0;
+ if (setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
+ perror("setsockopt");
+ return NULL;
+ }
+ }
+
+ msg.sadb_msg_version = PF_KEY_V2;
+ msg.sadb_msg_type = SADB_DUMP;
+ msg.sadb_msg_errno = 0;
+ msg.sadb_msg_satype = satype;
+ msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg));
+ msg.sadb_msg_reserved = 0;
+ msg.sadb_msg_seq = 0;
+ msg.sadb_msg_pid = getpid();
+ buf = (char *)&msg;
+ len = sizeof(msg);
+
+ if (f_verbose) {
+ kdebug_sadb(&msg);
+ printf("\n");
+ }
+ if (f_hexdump) {
+ int i;
+ for (i = 0; i < len; i++) {
+ if (i % 16 == 0)
+ printf("%08x: ", i);
+ printf("%02x ", buf[i] & 0xff);
+ if (i % 16 == 15)
+ printf("\n");
+ }
+ if (len % 16)
+ printf("\n");
+ }
+
+ if ((l = send(so, buf, len, 0)) < 0) {
+ perror("send");
+ return NULL;
+ }
+
+ m = (struct sadb_msg *)rbuf;
+ do {
+ if ((l = recv(so, rbuf, sizeof(rbuf), 0)) < 0) {
+ perror("recv");
+ fail = 1;
+ break;
+ }
+
+ if (PFKEY_UNUNIT64(m->sadb_msg_len) != l) {
+ warnx("invalid keymsg length");
+ fail = 1;
+ break;
+ }
+
+ if (f_verbose) {
+ kdebug_sadb(m);
+ printf("\n");
+ }
+
+ if (m->sadb_msg_type != SADB_DUMP) {
+ warnx("unexpected message type");
+ fail = 1;
+ break;
+ }
+
+ if (m->sadb_msg_errno != 0) {
+ warnx("error encountered");
+ fail = 1;
+ break;
+ }
+
+ /* match satype */
+ if (m->sadb_msg_satype != satype)
+ continue;
+
+ pfkey_align(m, mhp);
+ pfkey_check(mhp);
+
+ /* match src */
+ saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_SRC];
+ if (saddr == NULL)
+ continue;
+ s = (struct sockaddr *)(saddr + 1);
+ for (a = srcs; a; a = a->ai_next)
+ if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
+ break;
+ if (a == NULL)
+ continue;
+
+ /* match dst */
+ saddr = (struct sadb_address *)mhp[SADB_EXT_ADDRESS_DST];
+ if (saddr == NULL)
+ continue;
+ s = (struct sockaddr *)(saddr + 1);
+ for (a = dsts; a; a = a->ai_next)
+ if (memcmp(a->ai_addr, s, a->ai_addrlen) == 0)
+ break;
+ if (a == NULL)
+ continue;
+
+ if (*num_spi >= max_spi) {
+ max_spi += 512;
+ spi = realloc(spi, max_spi * sizeof(u_int32_t));
+ }
+
+ sa = (struct sadb_sa *)mhp[SADB_EXT_SA];
+ if (sa != NULL)
+ spi[(*num_spi)++] = (u_int32_t)ntohl(sa->sadb_sa_spi);
+
+ m = (struct sadb_msg *)((caddr_t)m + PFKEY_UNUNIT64(m->sadb_msg_len));
+
+ if (f_verbose) {
+ kdebug_sadb(m);
+ printf("\n");
+ }
+
+ } while (m->sadb_msg_seq);
+
+ if (fail) {
+ free(spi);
+ *num_spi = 0;
+ return NULL;
+ }
+
+ return spi;
+}
+
int
sendkeymsg(buf, len)
char *buf;
@@ -506,7 +667,7 @@ again:
}
if (f_verbose) {
- kdebug_sadb((struct sadb_msg *)rbuf);
+ kdebug_sadb(msg);
printf("\n");
}
if (postproc(msg, l) < 0)