On Wed, Jan 30, 2013 at 14:59 +0100, Bartosz Brzozowski wrote:
> Hi Misc.
> 
> I have two location A i B in my lab.
> In the location A there is isakmpd + carp + pfsync + sasync cluster
> on which there is installed OpenBSD 5.2 GENERIC.MP#339 i386
> In the location B there is single OpenBSD 5.2 GENERIC#278 i386 installation.
> 
> I have successfully established IPsec site-to-site connection
> between those two location and everything works fine until failover
> occurs in the cluster in location A ( I am  using ifconfig -g carp
> carpdemote 128 command on the MASTER node to force the failover).
> When failover occurs pfsync increase sequence number on the new
> MASTER node by 16384 and cluster continues sending ESP packets with
> the new, increased value (for example if the last seq number on the
> old MASTER was sent with the value equal to 100 the new MASTER will
> send his first packet with seq number equal to 16484).
> On the OpenBSD 5.2 in location B, using tcpdump I am able to see ESP
> packets, with the new increased seq number, on the phisical
> interface, but I do not see any transmition on enc0 interface. The
> ESP packets are continuously going out of the cluster A and are
> continuously, silently dropped on OpenBSD in location B. All IPsec
> transmition is broken until new SA are established and seq number is
> reset to 0.
> 
> I noted that starting from version OpenBSD 5.2 there is added
> support for Extended Sequence Numbers in the IPsec stack, so I go
> back with the version of OpenBSD on the server located in B from 5.2
> to 5.1 GENERIC#160 i386, copied all configuration files to it,
> established once again IPsec beetwen A and B and from that point
> everything started to work perfectly. Now I am able to switch nodes
> in cluster A (ofcourse seq number, everytime I switch nodes is
> increased by 16384) and OpenBSD 5.1 in location B successfully
> decrypt and encrypt connection. I am able to see packets, going in
> both directions, on interface enc0 as well I am able to see ESP
> packet on phisical interface on OpenBSD 5.1.
> 
> Is there bug in inplementation ESN in new IPsec stack on OpenBSD 5.2
> or do I need additional configuration to make above setup to started
> to work properly.
> Please let me know if You need any additional information.
> 
> Thanks for advise regards,
> Bartosz Brzozowski
> 


hi,

your observations are correct.  the problem should be resolved by
this commit:
http://www.openbsd.org/cgi-bin/cvsweb/src/sys/net/if_pfsync.c.diff?r1=1.189;r2=1.190

trying 5.3 beta might be a good idea as well to make sure it doesn't
have the aforementioned problem.  i'm also waiting for a review of a
change that will improve the anti-replay window handing and merge in
a diff from markus@ to increase the anti-replay window to 2100 packets.
i'll update this thread once the change will be in.  but in case you
have some time to play with it, you could try the diff below.

diff --git sys/netinet/ip_ah.c sys/netinet/ip_ah.c
index 243c82a..9ea6534 100644
--- sys/netinet/ip_ah.c
+++ sys/netinet/ip_ah.c
@@ -149,7 +149,6 @@ ah_init(struct tdb *tdbp, struct xformsw *xsp, struct 
ipsecinit *ii)
 
        tdbp->tdb_xform = xsp;
        tdbp->tdb_authalgxform = thash;
-       tdbp->tdb_bitmap = 0;
        tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL;
 
        DPRINTF(("ah_init(): initialized TDB with hash algorithm %s\n",
diff --git sys/netinet/ip_esp.c sys/netinet/ip_esp.c
index 40553c9..77e16ae 100644
--- sys/netinet/ip_esp.c
+++ sys/netinet/ip_esp.c
@@ -242,7 +242,6 @@ esp_init(struct tdb *tdbp, struct xformsw *xsp, struct 
ipsecinit *ii)
        }
 
        tdbp->tdb_xform = xsp;
-       tdbp->tdb_bitmap = 0;
        tdbp->tdb_rpl = AH_HMAC_INITIAL_RPL;
 
        /* Initialize crypto session */
@@ -1114,33 +1113,7 @@ esp_output_cb(void *op)
        return error;
 }
 
-static __inline int
-checkreplay(u_int64_t *bitmap, u_int32_t diff)
-{
-       if (*bitmap & (1ULL << diff))
-               return (1);
-       return (0);
-}
-
-static __inline void
-setreplay(u_int64_t *bitmap, u_int32_t diff, u_int32_t window, int wupdate)
-{
-       if (wupdate) {
-               if (diff < window)
-                       *bitmap = ((*bitmap) << diff) | 1;
-               else
-                       *bitmap = 1;
-       } else
-               *bitmap |= 1ULL << diff;
-}
-
-/*
- * To prevent ESN desynchronization replay distance specifies maximum
- * valid difference between the received SN and the last authenticated
- * one.  It's arbitrary chosen to be 1000 packets, meaning that only
- * up to 999 packets can be lost.
- */
-#define REPLAY_DISTANCE (1000)
+#define SEEN_SIZE      howmany(TDB_REPLAYMAX, 32)
 
 /*
  * return 0 on success
@@ -1153,21 +1126,26 @@ checkreplaywindow(struct tdb *tdb, u_int32_t seq, 
u_int32_t *seqhigh,
     int commit)
 {
        u_int32_t       tl, th, wl;
-       u_int32_t       seqh, diff;
-       u_int32_t       window = tdb->tdb_wnd;
-       u_int64_t       *bitmap = &tdb->tdb_bitmap;
-       int             esn = tdb->tdb_flags & TDBF_ESN;
+       u_int32_t       seqh, packet;
+       u_int32_t       window = TDB_REPLAYMAX - TDB_REPLAYWASTE;
+       int             idx, esn = tdb->tdb_flags & TDBF_ESN;
 
        tl = (u_int32_t)tdb->tdb_rpl;
        th = (u_int32_t)(tdb->tdb_rpl >> 32);
 
        /* Zero SN is not allowed */
-       if (seq == 0 && tl == 0 && th == 0)
+       if ((esn && seq == 0 && tl <= AH_HMAC_INITIAL_RPL && th == 0) ||
+           (!esn && seq == 0))
                return (1);
 
+       if (th == 0 && tl < window)
+               window = tl;
        /* Current replay window starts here */
        wl = tl - window + 1;
 
+       idx = (seq % TDB_REPLAYMAX) / 32;
+       packet = 1 << (31 - (seq & 31));
+
        /*
         * We keep the high part intact when:
         * 1) the SN is within [wl, 0xffffffff] and the whole window is
@@ -1178,24 +1156,35 @@ checkreplaywindow(struct tdb *tdb, u_int32_t seq, 
u_int32_t *seqhigh,
            (tl <  window - 1 && seq <  wl)) {
                seqh = *seqhigh = th;
                if (seq > tl) {
-                       if (seq - tl >= REPLAY_DISTANCE)
-                               return (2);
                        if (commit) {
-                               setreplay(bitmap, seq - tl, window, 1);
+                               if (seq - tl > window)
+                                       bzero(tdb->tdb_seen,
+                                           sizeof(tdb->tdb_seen));
+                               else {
+                                       int i = (tl % TDB_REPLAYMAX) / 32;
+
+                                       while (i != idx) {
+                                               i = (i + 1) % SEEN_SIZE;
+                                               tdb->tdb_seen[i] = 0;
+                                       }
+                               }
+                               tdb->tdb_seen[idx] |= packet;
                                tdb->tdb_rpl = ((u_int64_t)seqh << 32) | seq;
                        }
                } else {
-                       if (checkreplay(bitmap, tl - seq))
+                       if (tl - seq >= window)
+                               return (2);
+                       if (tdb->tdb_seen[idx] & packet)
                                return (3);
                        if (commit)
-                               setreplay(bitmap, tl - seq, window, 0);
+                               tdb->tdb_seen[idx] |= packet;
                }
                return (0);
        }
 
        /* Can't wrap if not doing ESN */
        if (!esn)
-               return (1);
+               return (2);
 
        /*
         * SN is within [wl, 0xffffffff] and wl is within
@@ -1204,13 +1193,11 @@ checkreplaywindow(struct tdb *tdb, u_int32_t seq, 
u_int32_t *seqhigh,
         * subspace.
         */
        if (tl < window - 1 && seq >= wl) {
-               seqh = *seqhigh = th - 1;
-               diff = (u_int32_t)((((u_int64_t)th << 32) | tl) -
-                   (((u_int64_t)seqh << 32) | seq));
-               if (checkreplay(bitmap, diff))
+               if (tdb->tdb_seen[idx] & packet)
                        return (3);
+               seqh = *seqhigh = th - 1;
                if (commit)
-                       setreplay(bitmap, diff, window, 0);
+                       tdb->tdb_seen[idx] |= packet;
                return (0);
        }
 
@@ -1218,17 +1205,21 @@ checkreplaywindow(struct tdb *tdb, u_int32_t seq, 
u_int32_t *seqhigh,
         * SN has wrapped and the last authenticated SN is in the old
         * subspace.
         */
-
-       if (seq - tl >= REPLAY_DISTANCE)
-               return (2);
-
        seqh = *seqhigh = th + 1;
        if (seqh == 0)          /* Don't let high bit to wrap */
                return (1);
        if (commit) {
-               diff = (u_int32_t)((((u_int64_t)seqh << 32) | seq) -
-                   (((u_int64_t)th << 32) | tl));
-               setreplay(bitmap, diff, window, 1);
+               if (seq - tl > window)
+                       bzero(tdb->tdb_seen, sizeof(tdb->tdb_seen));
+               else {
+                       int i = (tl % TDB_REPLAYMAX) / 32;
+
+                       while (i != idx) {
+                               i = (i + 1) % SEEN_SIZE;
+                               tdb->tdb_seen[i] = 0;
+                       }
+               }
+               tdb->tdb_seen[idx] |= packet;
                tdb->tdb_rpl = ((u_int64_t)seqh << 32) | seq;
        }
 
diff --git sys/netinet/ip_ipcomp.c sys/netinet/ip_ipcomp.c
index c40ce2a..5776694 100644
--- sys/netinet/ip_ipcomp.c
+++ sys/netinet/ip_ipcomp.c
@@ -113,7 +113,6 @@ ipcomp_init(tdbp, xsp, ii)
            tcomp->name));
 
        tdbp->tdb_xform = xsp;
-       tdbp->tdb_bitmap = 0;
 
        /* Initialize crypto session */
        bzero(&cric, sizeof(cric));
diff --git sys/netinet/ip_ipsp.h sys/netinet/ip_ipsp.h
index 2e6afe7..475849f 100644
--- sys/netinet/ip_ipsp.h
+++ sys/netinet/ip_ipsp.h
@@ -355,8 +355,11 @@ struct tdb {                               /* tunnel 
descriptor block */
        u_int8_t        *tdb_amxkey;    /* Raw authentication key */
        u_int8_t        *tdb_emxkey;    /* Raw encryption key */
 
+#define TDB_REPLAYWASTE        32
+#define TDB_REPLAYMAX  (2100+TDB_REPLAYWASTE)
+
        u_int64_t       tdb_rpl;        /* Replay counter */
-       u_int64_t       tdb_bitmap;     /* Used for replay sliding window */
+       u_int32_t       tdb_seen[howmany(TDB_REPLAYMAX, 32)]; /* Anti-replay 
window */
 
        u_int8_t        tdb_iv[4];      /* Used for HALF-IV ESP */

Reply via email to