From e3372d2f8f7971a8d6b0edc84710d34838c59cd6 Mon Sep 17 00:00:00 2001 From: tteras Date: Fri, 6 Mar 2009 11:45:03 +0000 Subject: [PATCH] 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 --- crypto/dist/ipsec-tools/src/setkey/extern.h | 5 +- crypto/dist/ipsec-tools/src/setkey/parse.y | 26 ++- crypto/dist/ipsec-tools/src/setkey/setkey.c | 165 +++++++++++++++++++- 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 93eea4369085..6f439fafb3fd 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 2f7e8566e46c..4b211a2b43e4 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 317dce102138..6c40250d51c8 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)