When using the FAST_IPSEC option in the kernel build, the sysctl variable net.key.prefered_oldsa seems to make no difference. The kernel always chooses an old SA. This problem can be easily reproduced. Just wait till the soft limit of the SA is expired and do a setkey -F on the remote and then ping through the tunnel. Because the old SA's are preferred and the remote no longer has the old SA's the server and the remote cannot talk through the tunnel. Looking at the source code in netipsec/key.c and comparing it with netkey/key.c I see the there is some differences that didn't make it into netipsec/key.c. Here is a context diff applied to 1.3.2.2 of the changes I made to fix the problem. *** /tmp/ipsec.key.c Thu Sep 11 14:26:07 2003 --- /usr/src/sys/netipsec/key.c Thu Sep 11 14:27:42 2003 *************** *** 1,4 **** ! /* $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/key.c,v 1.3.2.2 2003/07/01 01:38:13 sam Exp $ */ /* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */ /* --- 1,4 ---- ! /* $FreeBSD: src/sys/netipsec/key.c,v 1.3.2.2 2003/07/01 01:38:13 sam Exp $*/ /* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */ /* *************** *** 133,138 **** --- 133,139 ---- #endif static LIST_HEAD(_spacqtree, secspacq) spacqtree; /* SP acquiring list */ + #if 0 /* search order for SAs */ static u_int saorder_state_valid[] = { SADB_SASTATE_DYING, SADB_SASTATE_MATURE, *************** *** 141,146 **** --- 142,155 ---- * for outbound processing. For inbound, This is not important. */ }; + #endif + static const u_int saorder_state_valid_prefer_old[] = { + SADB_SASTATE_DYING, SADB_SASTATE_MATURE, + }; + static const u_int saorder_state_valid_prefer_new[] = { + SADB_SASTATE_MATURE, SADB_SASTATE_DYING, + }; + static u_int saorder_state_alive[] = { /* except DEAD */ SADB_SASTATE_MATURE, SADB_SASTATE_DYING, SADB_SASTATE_LARVAL *************** *** 816,821 **** --- 825,832 ---- struct secashead *sah; struct secasvar *sav; u_int stateidx, state; + const u_int *saorder_state_valid; + int arraysize; LIST_FOREACH(sah, &sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) *************** *** 828,836 **** found: /* search valid state */ for (stateidx = 0; ! stateidx < _ARRAYLEN(saorder_state_valid); stateidx++) { state = saorder_state_valid[stateidx]; --- 839,859 ---- found: + /* + * search a valid state list for outbound packet. + * This search order is important. + */ + if (key_prefered_oldsa) { + saorder_state_valid = saorder_state_valid_prefer_old; + arraysize = _ARRAYLEN(saorder_state_valid_prefer_old); + } else { + saorder_state_valid = saorder_state_valid_prefer_new; + arraysize = _ARRAYLEN(saorder_state_valid_prefer_new); + } + /* search valid state */ for (stateidx = 0; ! stateidx < arraysize; stateidx++) { state = saorder_state_valid[stateidx]; *************** *** 997,1008 **** --- 1020,1045 ---- struct secasvar *sav; u_int stateidx, state; int s; + const u_int *saorder_state_valid; + int arraysize; KASSERT(dst != NULL, ("key_allocsa: null dst address")); KEYDEBUG(KEYDEBUG_IPSEC_STAMP, printf("DP key_allocsa from %s:%u\n", where, tag)); + /* + * when both systems employ similar strategy to use a SA. + * the search order is important even in the inbound case. + */ + if (key_prefered_oldsa) { + saorder_state_valid = saorder_state_valid_prefer_old; + arraysize = _ARRAYLEN(saorder_state_valid_prefer_old); + } else { + saorder_state_valid = saorder_state_valid_prefer_new; + arraysize = _ARRAYLEN(saorder_state_valid_prefer_new); + } + /* * searching SAD. * XXX: to be checked internal IP header somewhere. Also when *************** *** 1013,1019 **** LIST_FOREACH(sah, &sahtree, chain) { /* search valid state */ for (stateidx = 0; ! stateidx < _ARRAYLEN(saorder_state_valid); stateidx++) { state = saorder_state_valid[stateidx]; LIST_FOREACH(sav, &sah->savtree[state], chain) { --- 1050,1056 ---- LIST_FOREACH(sah, &sahtree, chain) { /* search valid state */ for (stateidx = 0; ! stateidx < arraysize; stateidx++) { state = saorder_state_valid[stateidx]; LIST_FOREACH(sav, &sah->savtree[state], chain) {
Oldach, Helge
2003-Sep-11 12:18 UTC
FAST_IPSEC doesn't seem to honor net.key.prefered_oldsa=0
Gabor, thank you, this is exactly what I observe as well. I wish to add that commercial IPSec equipment appears to prefer net.key.prefered_oldsa=0 which makes FAST_IPSEC (defaulting to "1") slightly incompatible. This applies to Cisco IPSec gear in particular. Regards, Helge> -----Original Message----- > From: Gabor [mailto:gabor@vmunix.com] > Sent: Thursday, 11. September 2003 20:32 > To: freebsd-stable@freebsd.org > Cc: Sam Leffler > Subject: FAST_IPSEC doesn't seem to honor net.key.prefered_oldsa=0 > > > When using the FAST_IPSEC option in the kernel build, the sysctl > variable net.key.prefered_oldsa seems to make no difference. The > kernel always chooses an old SA. This problem can be easily > reproduced. Just wait till the soft limit of the SA is expired and do > a setkey -F on the remote and then ping through the tunnel. Because > the old SA's are preferred and the remote no longer has the old SA's > the server and the remote cannot talk through the tunnel. Looking > at the source code in netipsec/key.c and comparing it with > netkey/key.c I see the there is some differences that didn't make it > into netipsec/key.c. > > Here is a context diff applied to 1.3.2.2 of the changes I made to fix > the problem. > > *** /tmp/ipsec.key.c Thu Sep 11 14:26:07 2003 > --- /usr/src/sys/netipsec/key.c Thu Sep 11 14:27:42 2003 > *************** > *** 1,4 **** > ! /* $FreeBSD: /repoman/r/ncvs/src/sys/netipsec/key.c,v > 1.3.2.2 2003/07/01 01:38:13 sam Exp $ */ > /* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */ > > /* > --- 1,4 ---- > ! /* $FreeBSD: src/sys/netipsec/key.c,v 1.3.2.2 2003/07/01 > 01:38:13 sam Exp $*/ > /* $KAME: key.c,v 1.191 2001/06/27 10:46:49 sakane Exp $ */ > > /* > *************** > *** 133,138 **** > --- 133,139 ---- > #endif > static LIST_HEAD(_spacqtree, secspacq) spacqtree; /* SP > acquiring list */ > > + #if 0 > /* search order for SAs */ > static u_int saorder_state_valid[] = { > SADB_SASTATE_DYING, SADB_SASTATE_MATURE, > *************** > *** 141,146 **** > --- 142,155 ---- > * for outbound processing. For inbound, This is not > important. > */ > }; > + #endif > + static const u_int saorder_state_valid_prefer_old[] = { > + SADB_SASTATE_DYING, SADB_SASTATE_MATURE, > + }; > + static const u_int saorder_state_valid_prefer_new[] = { > + SADB_SASTATE_MATURE, SADB_SASTATE_DYING, > + }; > + > static u_int saorder_state_alive[] = { > /* except DEAD */ > SADB_SASTATE_MATURE, SADB_SASTATE_DYING, SADB_SASTATE_LARVAL > *************** > *** 816,821 **** > --- 825,832 ---- > struct secashead *sah; > struct secasvar *sav; > u_int stateidx, state; > + const u_int *saorder_state_valid; > + int arraysize; > > LIST_FOREACH(sah, &sahtree, chain) { > if (sah->state == SADB_SASTATE_DEAD) > *************** > *** 828,836 **** > > found: > > /* search valid state */ > for (stateidx = 0; > ! stateidx < _ARRAYLEN(saorder_state_valid); > stateidx++) { > > state = saorder_state_valid[stateidx]; > --- 839,859 ---- > > found: > > + /* > + * search a valid state list for outbound packet. > + * This search order is important. > + */ > + if (key_prefered_oldsa) { > + saorder_state_valid = > saorder_state_valid_prefer_old; > + arraysize = > _ARRAYLEN(saorder_state_valid_prefer_old); > + } else { > + saorder_state_valid = > saorder_state_valid_prefer_new; > + arraysize = > _ARRAYLEN(saorder_state_valid_prefer_new); > + } > + > /* search valid state */ > for (stateidx = 0; > ! stateidx < arraysize; > stateidx++) { > > state = saorder_state_valid[stateidx]; > *************** > *** 997,1008 **** > --- 1020,1045 ---- > struct secasvar *sav; > u_int stateidx, state; > int s; > + const u_int *saorder_state_valid; > + int arraysize; > > KASSERT(dst != NULL, ("key_allocsa: null dst address")); > > KEYDEBUG(KEYDEBUG_IPSEC_STAMP, > printf("DP key_allocsa from %s:%u\n", where, tag)); > > + /* > + * when both systems employ similar strategy to use a SA. > + * the search order is important even in the inbound case. > + */ > + if (key_prefered_oldsa) { > + saorder_state_valid = > saorder_state_valid_prefer_old; > + arraysize = > _ARRAYLEN(saorder_state_valid_prefer_old); > + } else { > + saorder_state_valid = > saorder_state_valid_prefer_new; > + arraysize = > _ARRAYLEN(saorder_state_valid_prefer_new); > + } > + > /* > * searching SAD. > * XXX: to be checked internal IP header somewhere. Also when > *************** > *** 1013,1019 **** > LIST_FOREACH(sah, &sahtree, chain) { > /* search valid state */ > for (stateidx = 0; > ! stateidx < _ARRAYLEN(saorder_state_valid); > stateidx++) { > state = saorder_state_valid[stateidx]; > LIST_FOREACH(sav, > &sah->savtree[state], chain) { > --- 1050,1056 ---- > LIST_FOREACH(sah, &sahtree, chain) { > /* search valid state */ > for (stateidx = 0; > ! stateidx < arraysize; > stateidx++) { > state = saorder_state_valid[stateidx]; > LIST_FOREACH(sav, > &sah->savtree[state], chain) { > > _______________________________________________ > freebsd-stable@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-stable > To unsubscribe, send any mail to > "freebsd-stable-unsubscribe@freebsd.org" >