From: Zheng Zhong <[email protected]>

Make replay window configurable per connection.

A new ipsec.conf option is available in the conn section:
    replay_window 32

If unset, then the default value from strongswan.conf is used
(charon.replay_window).

The replay window size is now available to all kernel interface
implementations.

Signed-off-by: Zheng Zhong <[email protected]>
Signed-off-by: Christophe Gouault <[email protected]>
---
v1 -> v2:

- child_cfg.replay_window is now the actual window size, the magic
  value -1 is only used by stroke.
- update add_sa method of formerly missed kernel interface
  implementations (tkm, libandroidbridge, libipsec, load_tester)
- make replay_window size available to all kernel interface
  implementations.
- cleanup kernel_netlink_ipsec code
---
 src/charon-tkm/src/tkm/tkm_kernel_ipsec.c          |  1 +
 .../jni/libandroidbridge/kernel/android_ipsec.c    |  5 +-
 src/libcharon/config/child_cfg.c                   | 24 ++++++++++
 src/libcharon/config/child_cfg.h                   | 14 ++++++
 .../plugins/load_tester/load_tester_ipsec.c        |  1 +
 src/libcharon/plugins/stroke/stroke_config.c       |  2 +
 src/libcharon/sa/child_sa.c                        |  6 ++-
 src/libhydra/kernel/kernel_interface.c             | 10 ++--
 src/libhydra/kernel/kernel_interface.h             |  4 +-
 src/libhydra/kernel/kernel_ipsec.h                 |  4 +-
 .../plugins/kernel_klips/kernel_klips_ipsec.c      |  6 ++-
 .../plugins/kernel_netlink/kernel_netlink_ipsec.c  | 56 +++++++++-------------
 .../plugins/kernel_pfkey/kernel_pfkey_ipsec.c      |  7 +--
 src/libipsec/ipsec_sa_mgr.c                        |  1 +
 src/libipsec/ipsec_sa_mgr.h                        |  1 +
 src/starter/args.c                                 |  1 +
 src/starter/confread.c                             |  2 +
 src/starter/confread.h                             |  1 +
 src/starter/keywords.h                             |  1 +
 src/starter/keywords.txt                           |  1 +
 src/starter/starterstroke.c                        |  1 +
 src/stroke/stroke_msg.h                            |  1 +
 22 files changed, 101 insertions(+), 49 deletions(-)

diff --git a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c 
b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c
index 72c247d..3e3d139 100644
--- a/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c
+++ b/src/charon-tkm/src/tkm/tkm_kernel_ipsec.c
@@ -92,6 +92,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
        u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t 
enc_key,
        u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+       u_int32_t replay_window,
        u_int16_t cpi, bool _initiator, bool encap, bool esn, bool inbound,
        traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
 {
diff --git a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c 
b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c
index 48f1487..9885da4 100644
--- a/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c
+++ b/src/frontends/android/jni/libandroidbridge/kernel/android_ipsec.c
@@ -65,13 +65,14 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
        u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t 
enc_key,
        u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+       u_int32_t replay_window,
        u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
 {
        return ipsec->sas->add_sa(ipsec->sas, src, dst, spi, protocol, reqid, 
mark,
                                                          tfc, lifetime, 
enc_alg, enc_key, int_alg, int_key,
-                                                         mode, ipcomp, cpi, 
initiator, encap, esn, inbound,
-                                                         src_ts, dst_ts);
+                                                         mode, ipcomp, 
replay_window, cpi, initiator,
+                                                         encap, esn, inbound, 
src_ts, dst_ts);
 }
 
 METHOD(kernel_ipsec_t, update_sa, status_t,
diff --git a/src/libcharon/config/child_cfg.c b/src/libcharon/config/child_cfg.c
index 3f07b58..7e4a143 100644
--- a/src/libcharon/config/child_cfg.c
+++ b/src/libcharon/config/child_cfg.c
@@ -27,6 +27,9 @@ ENUM(action_names, ACTION_NONE, ACTION_RESTART,
        "restart",
 );
 
+/** Default replay window size, if not set using charon.replay_window */
+#define DEFAULT_REPLAY_WINDOW 32
+
 typedef struct private_child_cfg_t private_child_cfg_t;
 
 /**
@@ -138,6 +141,11 @@ struct private_child_cfg_t {
         * enable installation and removal of kernel IPsec policies
         */
        bool install_policy;
+
+       /**
+        * anti-replay window size
+        */
+       u_int32_t replay_window;
 };
 
 METHOD(child_cfg_t, get_name, char*,
@@ -481,6 +489,18 @@ METHOD(child_cfg_t, get_tfc, u_int32_t,
        return this->tfc;
 }
 
+METHOD(child_cfg_t, get_replay_window, u_int32_t,
+       private_child_cfg_t *this)
+{
+       return this->replay_window;
+}
+
+METHOD(child_cfg_t, set_replay_window, void,
+       private_child_cfg_t *this, u_int32_t replay_window)
+{
+       this->replay_window = replay_window;
+}
+
 METHOD(child_cfg_t, set_mipv6_options, void,
        private_child_cfg_t *this, bool proxy_mode, bool install_policy)
 {
@@ -558,6 +578,8 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t 
*lifetime,
                        .get_reqid = _get_reqid,
                        .get_mark = _get_mark,
                        .get_tfc = _get_tfc,
+                       .get_replay_window = _get_replay_window,
+                       .set_replay_window = _set_replay_window,
                        .use_proxy_mode = _use_proxy_mode,
                        .install_policy = _install_policy,
                        .get_ref = _get_ref,
@@ -580,6 +602,8 @@ child_cfg_t *child_cfg_create(char *name, lifetime_cfg_t 
*lifetime,
                .my_ts = linked_list_create(),
                .other_ts = linked_list_create(),
                .tfc = tfc,
+               .replay_window = lib->settings->get_int(lib->settings,
+                               "%s.replay_window", DEFAULT_REPLAY_WINDOW, 
lib->ns),
        );
 
        if (mark_in)
diff --git a/src/libcharon/config/child_cfg.h b/src/libcharon/config/child_cfg.h
index 43ad1c5..9f7a92b 100644
--- a/src/libcharon/config/child_cfg.h
+++ b/src/libcharon/config/child_cfg.h
@@ -235,6 +235,20 @@ struct child_cfg_t {
        u_int32_t (*get_tfc)(child_cfg_t *this);
 
        /**
+        * Get anti-replay window size
+        *
+        * @return                              anti-replay window size
+        */
+       u_int32_t (*get_replay_window)(child_cfg_t *this);
+
+       /**
+        * Set anti-replay window size
+        *
+        * @param window                anti-replay window size
+        */
+       void (*set_replay_window)(child_cfg_t *this, u_int32_t window);
+
+       /**
         * Sets two options needed for Mobile IPv6 interoperability.
         *
         * @param proxy_mode    use IPsec transport proxy mode (default FALSE)
diff --git a/src/libcharon/plugins/load_tester/load_tester_ipsec.c 
b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
index 5edd3b8..980c854 100644
--- a/src/libcharon/plugins/load_tester/load_tester_ipsec.c
+++ b/src/libcharon/plugins/load_tester/load_tester_ipsec.c
@@ -54,6 +54,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
        u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t 
enc_key,
        u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+       u_int32_t replay_window,
        u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
 {
diff --git a/src/libcharon/plugins/stroke/stroke_config.c 
b/src/libcharon/plugins/stroke/stroke_config.c
index df15a16..d22c37f 100644
--- a/src/libcharon/plugins/stroke/stroke_config.c
+++ b/src/libcharon/plugins/stroke/stroke_config.c
@@ -1151,6 +1151,8 @@ static child_cfg_t 
*build_child_cfg(private_stroke_config_t *this,
                                map_action(msg->add_conn.close_action), 
msg->add_conn.ipcomp,
                                msg->add_conn.inactivity, msg->add_conn.reqid,
                                &mark_in, &mark_out, msg->add_conn.tfc);
+       if (msg->add_conn.replay_window != -1)
+               child_cfg->set_replay_window(child_cfg, 
msg->add_conn.replay_window);
        child_cfg->set_mipv6_options(child_cfg, msg->add_conn.proxy_mode,
                                                                                
        msg->add_conn.install_policy);
        add_ts(this, &msg->add_conn.me, child_cfg, TRUE);
diff --git a/src/libcharon/sa/child_sa.c b/src/libcharon/sa/child_sa.c
index 847cfc7..5a010fc 100644
--- a/src/libcharon/sa/child_sa.c
+++ b/src/libcharon/sa/child_sa.c
@@ -639,6 +639,7 @@ METHOD(child_sa_t, install, status_t,
        host_t *src, *dst;
        status_t status;
        bool update = FALSE;
+       u_int32_t replay_window = 0;
 
        /* now we have to decide which spi to use. Use self allocated, if "in",
         * or the one in the proposal, if not "in" (others). Additionally,
@@ -653,6 +654,7 @@ METHOD(child_sa_t, install, status_t,
                }
                this->my_spi = spi;
                this->my_cpi = cpi;
+               replay_window = this->config->get_replay_window(this->config);
        }
        else
        {
@@ -722,8 +724,8 @@ METHOD(child_sa_t, install, status_t,
                                src, dst, spi, proto_ike2ip(this->protocol), 
this->reqid,
                                inbound ? this->mark_in : this->mark_out, tfc,
                                lifetime, enc_alg, encr, int_alg, integ, 
this->mode,
-                               this->ipcomp, cpi, initiator, this->encap, esn, 
update,
-                               src_ts, dst_ts);
+                               this->ipcomp, replay_window, cpi, initiator, 
this->encap,
+                               esn, update, src_ts, dst_ts);
 
        free(lifetime);
 
diff --git a/src/libhydra/kernel/kernel_interface.c 
b/src/libhydra/kernel/kernel_interface.c
index 3e34d20..6e10394 100644
--- a/src/libhydra/kernel/kernel_interface.c
+++ b/src/libhydra/kernel/kernel_interface.c
@@ -179,9 +179,10 @@ METHOD(kernel_interface_t, add_sa, status_t,
        private_kernel_interface_t *this, host_t *src, host_t *dst,
        u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
        u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t 
enc_key,
-       u_int16_t int_alg, chunk_t int_key,     ipsec_mode_t mode, u_int16_t 
ipcomp,
-       u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
-       traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
+       u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+       u_int32_t replay_window,
+       u_int16_t cpi, bool initiator, bool encap, bool esn,
+       bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
 {
        if (!this->ipsec)
        {
@@ -189,7 +190,8 @@ METHOD(kernel_interface_t, add_sa, status_t,
        }
        return this->ipsec->add_sa(this->ipsec, src, dst, spi, protocol, reqid,
                        mark, tfc, lifetime, enc_alg, enc_key, int_alg, 
int_key, mode,
-                       ipcomp, cpi, initiator, encap, esn, inbound, src_ts, 
dst_ts);
+                       ipcomp, replay_window, cpi, initiator, encap, esn, 
inbound,
+                       src_ts, dst_ts);
 }
 
 METHOD(kernel_interface_t, update_sa, status_t,
diff --git a/src/libhydra/kernel/kernel_interface.h 
b/src/libhydra/kernel/kernel_interface.h
index cc47d3c..ad13f6e 100644
--- a/src/libhydra/kernel/kernel_interface.h
+++ b/src/libhydra/kernel/kernel_interface.h
@@ -144,6 +144,7 @@ struct kernel_interface_t {
         * @param int_key               key to use for integrity protection
         * @param mode                  mode of the SA (tunnel, transport)
         * @param ipcomp                IPComp transform to use
+        * @param replay_window anti-replay window size
         * @param cpi                   CPI for IPComp
         * @param initiator             TRUE if initiator of the exchange 
creating this SA
         * @param encap                 enable UDP encapsulation for NAT 
traversal
@@ -159,7 +160,8 @@ struct kernel_interface_t {
                                                u_int32_t tfc, lifetime_cfg_t 
*lifetime,
                                                u_int16_t enc_alg, chunk_t 
enc_key,
                                                u_int16_t int_alg, chunk_t 
int_key,
-                                               ipsec_mode_t mode, u_int16_t 
ipcomp, u_int16_t cpi,
+                                               ipsec_mode_t mode, u_int16_t 
ipcomp,
+                                               u_int32_t replay_window, 
u_int16_t cpi,
                                                bool initiator, bool encap, 
bool esn, bool inbound,
                                                traffic_selector_t *src_ts, 
traffic_selector_t *dst_ts);
 
diff --git a/src/libhydra/kernel/kernel_ipsec.h 
b/src/libhydra/kernel/kernel_ipsec.h
index 25f5b38..43f5f3d 100644
--- a/src/libhydra/kernel/kernel_ipsec.h
+++ b/src/libhydra/kernel/kernel_ipsec.h
@@ -100,6 +100,7 @@ struct kernel_ipsec_t {
         * @param int_key               key to use for integrity protection
         * @param mode                  mode of the SA (tunnel, transport)
         * @param ipcomp                IPComp transform to use
+        * @param replay_window anti-replay window size
         * @param cpi                   CPI for IPComp
         * @param initiator             TRUE if initiator of the exchange 
creating this SA
         * @param encap                 enable UDP encapsulation for NAT 
traversal
@@ -115,7 +116,8 @@ struct kernel_ipsec_t {
                                                mark_t mark, u_int32_t tfc, 
lifetime_cfg_t *lifetime,
                                                u_int16_t enc_alg, chunk_t 
enc_key,
                                                u_int16_t int_alg, chunk_t 
int_key,
-                                               ipsec_mode_t mode, u_int16_t 
ipcomp, u_int16_t cpi,
+                                               ipsec_mode_t mode, u_int16_t 
ipcomp,
+                                               u_int32_t replay_window, 
u_int16_t cpi,
                                                bool initiator, bool encap, 
bool esn, bool inbound,
                                                traffic_selector_t *src_ts, 
traffic_selector_t *dst_ts);
 
diff --git a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c 
b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
index 0b66b4d..5600410 100644
--- a/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
+++ b/src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
@@ -1682,7 +1682,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
        lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
        u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
-       u_int16_t ipcomp, u_int16_t cpi, bool initiator, bool encap, bool esn,
+       u_int16_t ipcomp, u_int32_t replay_window, u_int16_t cpi,
+       bool initiator, bool encap, bool esn,
        bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
@@ -1728,7 +1729,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        sa->sadb_sa_len = PFKEY_LEN(sizeof(struct sadb_sa));
        sa->sadb_sa_spi = spi;
        sa->sadb_sa_state = SADB_SASTATE_MATURE;
-       sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0 : 32;
+       sa->sadb_sa_replay = (protocol == IPPROTO_COMP) ? 0
+                                                 : min(replay_window, 64);
        sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, int_alg);
        sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, enc_alg);
        PFKEY_EXT_ADD(msg, sa);
diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c 
b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
index c864a92..cc425a9 100644
--- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
+++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
@@ -73,9 +73,6 @@
 /** Default priority of installed policies */
 #define PRIO_BASE 512
 
-/** Default replay window size, if not set using charon.replay_window */
-#define DEFAULT_REPLAY_WINDOW 32
-
 /** Default lifetime of an acquire XFRM state (in seconds) */
 #define DEFAULT_ACQUIRE_LIFETIME 165
 
@@ -316,16 +313,6 @@ struct private_kernel_netlink_ipsec_t {
         * Whether to track the history of a policy
         */
        bool policy_history;
-
-       /**
-        * Size of the replay window, in packets (= bits)
-        */
-       u_int32_t replay_window;
-
-       /**
-        * Size of the replay window bitmap, in number of __u32 blocks
-        */
-       u_int32_t replay_bmp;
 };
 
 typedef struct route_entry_t route_entry_t;
@@ -631,11 +618,12 @@ static inline u_int32_t get_priority(policy_entry_t 
*policy,
 }
 
 /**
- * Return the length of the ESN bitmap
+ * Return the length of the replay bitmap in number of __u32 blocks
  */
-static inline size_t esn_bmp_len(private_kernel_netlink_ipsec_t *this)
+static inline u_int32_t replay_bmp_len(u_int32_t replay_window)
 {
-       return this->replay_bmp * sizeof(u_int32_t);
+       return (replay_window + sizeof(u_int32_t) * 8 - 1) /
+                  (sizeof(u_int32_t) * 8);
 }
 
 /**
@@ -1195,6 +1183,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        u_int32_t spi, u_int8_t protocol, u_int32_t reqid, mark_t mark,
        u_int32_t tfc, lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t 
enc_key,
        u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+       u_int32_t replay_window,
        u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
        traffic_selector_t* src_ts, traffic_selector_t* dst_ts)
 {
@@ -1213,8 +1202,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
                add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, 
mark,
                           tfc, &lft, ENCR_UNDEFINED, chunk_empty, 
AUTH_UNDEFINED,
-                          chunk_empty, mode, ipcomp, 0, initiator, FALSE, 
FALSE, inbound,
-                          src_ts, dst_ts);
+                          chunk_empty, mode, ipcomp, 0, 0, initiator, FALSE, 
FALSE,
+                          inbound, src_ts, dst_ts);
                ipcomp = IPCOMP_NONE;
                /* use transport mode ESP SA, IPComp uses tunnel mode */
                mode = MODE_TRANSPORT;
@@ -1480,23 +1469,24 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
 
        if (protocol != IPPROTO_COMP)
        {
-               if (esn || this->replay_window > DEFAULT_REPLAY_WINDOW)
+               if (esn || replay_window > 32)
                {
                        /* for ESN or larger replay windows we need the new
                         * XFRMA_REPLAY_ESN_VAL attribute to configure a bitmap 
*/
                        struct xfrm_replay_state_esn *replay;
+                       u_int32_t replay_bmp = replay_bmp_len(replay_window);
 
                        replay = netlink_reserve(hdr, sizeof(request), 
XFRMA_REPLAY_ESN_VAL,
-                                                                        
sizeof(*replay) + esn_bmp_len(this));
+                                                                        
sizeof(*replay) + replay_bmp * sizeof(u_int32_t));
                        if (!replay)
                        {
                                goto failed;
                        }
                        /* bmp_len contains number uf __u32's */
-                       replay->bmp_len = this->replay_bmp;
-                       replay->replay_window = this->replay_window;
+                       replay->bmp_len = replay_bmp;
+                       replay->replay_window = replay_window;
                        DBG2(DBG_KNL, "  using replay window of %u packets",
-                                this->replay_window);
+                                replay_window);
 
                        if (esn)
                        {
@@ -1507,8 +1497,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                else
                {
                        DBG2(DBG_KNL, "  using replay window of %u packets",
-                                this->replay_window);
-                       sa->replay_window = this->replay_window;
+                                replay_window);
+                       sa->replay_window = replay_window;
                }
        }
 
@@ -1542,6 +1532,7 @@ static void 
get_replay_state(private_kernel_netlink_ipsec_t *this,
                                                         u_int32_t spi, 
u_int8_t protocol,
                                                         host_t *dst, mark_t 
mark,
                                                         struct 
xfrm_replay_state_esn **replay_esn,
+                                                        u_int32_t 
*replay_esn_len,
                                                         struct 
xfrm_replay_state **replay)
 {
        netlink_buf_t request;
@@ -1618,9 +1609,10 @@ static void 
get_replay_state(private_kernel_netlink_ipsec_t *this,
                                break;
                        }
                        if (rta->rta_type == XFRMA_REPLAY_ESN_VAL &&
-                               RTA_PAYLOAD(rta) >= sizeof(**replay_esn) + 
esn_bmp_len(this))
+                               RTA_PAYLOAD(rta) >= sizeof(**replay_esn))
                        {
                                *replay_esn = malloc(RTA_PAYLOAD(rta));
+                               *replay_esn_len = RTA_PAYLOAD(rta);
                                memcpy(*replay_esn, RTA_DATA(rta), 
RTA_PAYLOAD(rta));
                                break;
                        }
@@ -1804,6 +1796,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
        struct xfrm_encap_tmpl* tmpl = NULL;
        struct xfrm_replay_state *replay = NULL;
        struct xfrm_replay_state_esn *replay_esn = NULL;
+       u_int32_t replay_esn_len;
        status_t status = FAILED;
 
        /* if IPComp is used, we first update the IPComp SA */
@@ -1868,7 +1861,7 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
                goto failed;
        }
 
-       get_replay_state(this, spi, protocol, dst, mark, &replay_esn, &replay);
+       get_replay_state(this, spi, protocol, dst, mark, &replay_esn, 
&replay_esn_len, &replay);
 
        /* delete the old SA (without affecting the IPComp SA) */
        if (del_sa(this, src, dst, spi, protocol, 0, mark) != SUCCESS)
@@ -1936,12 +1929,12 @@ METHOD(kernel_ipsec_t, update_sa, status_t,
                struct xfrm_replay_state_esn *state;
 
                state = netlink_reserve(hdr, sizeof(request), 
XFRMA_REPLAY_ESN_VAL,
-                                                               sizeof(*state) 
+ esn_bmp_len(this));
+                                                               replay_esn_len);
                if (!state)
                {
                        goto failed;
                }
-               memcpy(state, replay_esn, sizeof(*state) + esn_bmp_len(this));
+               memcpy(state, replay_esn, replay_esn_len);
        }
        else if (replay)
        {
@@ -2686,13 +2679,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
                .policy_history = TRUE,
                .install_routes = lib->settings->get_bool(lib->settings,
                                                        "%s.install_routes", 
TRUE, lib->ns),
-               .replay_window = lib->settings->get_int(lib->settings,
-                                                       "%s.replay_window", 
DEFAULT_REPLAY_WINDOW, lib->ns),
        );
 
-       this->replay_bmp = (this->replay_window + sizeof(u_int32_t) * 8 - 1) /
-                                                                               
                        (sizeof(u_int32_t) * 8);
-
        if (streq(lib->ns, "starter"))
        {       /* starter has no threads, so we do not register for kernel 
events */
                register_for_events = FALSE;
diff --git a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c 
b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
index c865917..95054c2 100644
--- a/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
+++ b/src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
@@ -1615,7 +1615,8 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        u_int8_t protocol, u_int32_t reqid, mark_t mark, u_int32_t tfc,
        lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
        u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode,
-       u_int16_t ipcomp, u_int16_t cpi, bool initiator, bool encap, bool esn,
+       u_int16_t ipcomp, u_int32_t replay_window, u_int16_t cpi,
+       bool initiator, bool encap, bool esn,
        bool inbound, traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
@@ -1633,7 +1634,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
                lifetime_cfg_t lft = {{0,0,0},{0,0,0},{0,0,0}};
                add_sa(this, src, dst, htonl(ntohs(cpi)), IPPROTO_COMP, reqid, 
mark,
                           tfc, &lft, ENCR_UNDEFINED, chunk_empty, 
AUTH_UNDEFINED,
-                          chunk_empty, mode, ipcomp, 0, FALSE, FALSE, FALSE, 
inbound,
+                          chunk_empty, mode, ipcomp, 0, 0, FALSE, FALSE, 
FALSE, inbound,
                           NULL, NULL);
                ipcomp = IPCOMP_NONE;
                /* use transport mode ESP SA, IPComp uses tunnel mode */
@@ -1676,7 +1677,7 @@ METHOD(kernel_ipsec_t, add_sa, status_t,
        }
        else
        {
-               sa->sadb_sa_replay = 32;
+               sa->sadb_sa_replay = min(replay_window, 32);
                sa->sadb_sa_auth = lookup_algorithm(INTEGRITY_ALGORITHM, 
int_alg);
                sa->sadb_sa_encrypt = lookup_algorithm(ENCRYPTION_ALGORITHM, 
enc_alg);
        }
diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c
index 1db1776..ba342bd 100644
--- a/src/libipsec/ipsec_sa_mgr.c
+++ b/src/libipsec/ipsec_sa_mgr.c
@@ -441,6 +441,7 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
        u_int8_t protocol, u_int32_t reqid,     mark_t mark, u_int32_t tfc,
        lifetime_cfg_t *lifetime, u_int16_t enc_alg, chunk_t enc_key,
        u_int16_t int_alg, chunk_t int_key, ipsec_mode_t mode, u_int16_t ipcomp,
+       u_int32_t replay_window,
        u_int16_t cpi, bool initiator, bool encap, bool esn, bool inbound,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts)
 {
diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h
index 8c234ce..9ae0701 100644
--- a/src/libipsec/ipsec_sa_mgr.h
+++ b/src/libipsec/ipsec_sa_mgr.h
@@ -83,6 +83,7 @@ struct ipsec_sa_mgr_t {
                                           mark_t mark, u_int32_t tfc,  
lifetime_cfg_t *lifetime,
                                           u_int16_t enc_alg, chunk_t enc_key, 
u_int16_t int_alg,
                                           chunk_t int_key, ipsec_mode_t mode, 
u_int16_t ipcomp,
+                                          uint32_t replay_window,
                                           u_int16_t cpi, bool initiator, bool 
encap, bool esn,
                                           bool inbound, traffic_selector_t 
*src_ts,
                                           traffic_selector_t *dst_ts);
diff --git a/src/starter/args.c b/src/starter/args.c
index f5a617e..0d662f4 100644
--- a/src/starter/args.c
+++ b/src/starter/args.c
@@ -173,6 +173,7 @@ static const token_info_t token_info[] =
        { ARG_STR,  offsetof(starter_conn_t, me_mediated_by), NULL              
       },
        { ARG_STR,  offsetof(starter_conn_t, me_peerid), NULL                   
       },
        { ARG_UINT, offsetof(starter_conn_t, reqid), NULL                       
       },
+       { ARG_UINT, offsetof(starter_conn_t, replay_window), NULL               
       },
        { ARG_MISC, 0, NULL  /* KW_MARK */                                      
       },
        { ARG_MISC, 0, NULL  /* KW_MARK_IN */                                   
       },
        { ARG_MISC, 0, NULL  /* KW_MARK_OUT */                                  
       },
diff --git a/src/starter/confread.c b/src/starter/confread.c
index 19178a2..0fac895 100644
--- a/src/starter/confread.c
+++ b/src/starter/confread.c
@@ -34,6 +34,7 @@
 #define SA_REPLACEMENT_MARGIN_DEFAULT  540 /* 9 minutes */
 #define SA_REPLACEMENT_FUZZ_DEFAULT    100 /* 100% of margin */
 #define SA_REPLACEMENT_RETRIES_DEFAULT   3
+#define SA_REPLAY_WINDOW_DEFAULT        -1 /* use charon.replay_window */
 
 static const char ike_defaults[] = "aes128-sha1-modp2048,3des-sha1-modp1536";
 static const char esp_defaults[] = "aes128-sha1,3des-sha1";
@@ -132,6 +133,7 @@ static void default_values(starter_config_t *cfg)
        cfg->conn_default.install_policy        = TRUE;
        cfg->conn_default.dpd_delay             =  30; /* seconds */
        cfg->conn_default.dpd_timeout           = 150; /* seconds */
+       cfg->conn_default.replay_window         = SA_REPLAY_WINDOW_DEFAULT;
 
        cfg->conn_default.left.seen  = SEEN_NONE;
        cfg->conn_default.right.seen = SEEN_NONE;
diff --git a/src/starter/confread.h b/src/starter/confread.h
index d55a17e..a32f8cb 100644
--- a/src/starter/confread.h
+++ b/src/starter/confread.h
@@ -162,6 +162,7 @@ struct starter_conn {
                u_int32_t       reqid;
                mark_t          mark_in;
                mark_t          mark_out;
+               u_int32_t       replay_window;
                u_int32_t       tfc;
                bool            install_policy;
                bool            aggressive;
diff --git a/src/starter/keywords.h b/src/starter/keywords.h
index 705a7c1..5b6b28b 100644
--- a/src/starter/keywords.h
+++ b/src/starter/keywords.h
@@ -69,6 +69,7 @@ typedef enum {
        KW_MEDIATED_BY,
        KW_ME_PEERID,
        KW_REQID,
+       KW_REPLAY_WINDOW,
        KW_MARK,
        KW_MARK_IN,
        KW_MARK_OUT,
diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt
index ad915bf..ee0bd31 100644
--- a/src/starter/keywords.txt
+++ b/src/starter/keywords.txt
@@ -69,6 +69,7 @@ mediation,         KW_MEDIATION
 mediated_by,       KW_MEDIATED_BY
 me_peerid,         KW_ME_PEERID
 reqid,             KW_REQID
+replay_window,     KW_REPLAY_WINDOW
 mark,              KW_MARK
 mark_in,           KW_MARK_IN
 mark_out,          KW_MARK_OUT
diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c
index fca4b1e..839e66e 100644
--- a/src/starter/starterstroke.c
+++ b/src/starter/starterstroke.c
@@ -202,6 +202,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, 
starter_conn_t *conn)
        msg.add_conn.ikeme.mediated_by = push_string(&msg, 
conn->me_mediated_by);
        msg.add_conn.ikeme.peerid = push_string(&msg, conn->me_peerid);
        msg.add_conn.reqid = conn->reqid;
+       msg.add_conn.replay_window = conn->replay_window;
        msg.add_conn.mark_in.value = conn->mark_in.value;
        msg.add_conn.mark_in.mask = conn->mark_in.mask;
        msg.add_conn.mark_out.value = conn->mark_out.value;
diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h
index 5ece724..60886cf 100644
--- a/src/stroke/stroke_msg.h
+++ b/src/stroke/stroke_msg.h
@@ -304,6 +304,7 @@ struct stroke_msg_t {
                                u_int32_t mask;
                        } mark_in, mark_out;
                        stroke_end_t me, other;
+                       u_int32_t replay_window;
                } add_conn;
 
                /* data for STR_ADD_CA */
-- 
1.8.3.2

_______________________________________________
Dev mailing list
[email protected]
https://lists.strongswan.org/mailman/listinfo/dev

Reply via email to