[strongSwan] Issues with HA configuration

Whisker, Peter peter.whisker at cgi.com
Mon Sep 28 16:32:17 CEST 2015


OK, got to the bottom of this. Centos patching woes.

I have had to patch up the HA kernel patch as Centos won't build with warnings and using an unsigned int as a pointer sure generates one! ;-)

Attached is a patch that will go into rpmbuild against the Centos 7.1 kernel as long as you set the fuzz to 2 (patch -F2) in kernel.spec. 

Peter

[whiskerp at irisp-gsgw-1a ha_kernel_patches]$ cat ha-3.10-abicompat.patch
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index de70f7b..098a323 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -37,9 +37,6 @@ static inline void nf_inet_addr_mask(const union nf_inet_addr *a1,

 extern int netfilter_init(void);

-/* Largest hook number + 1 */
-#define NF_MAX_HOOKS 8
-
 struct sk_buff;

 typedef unsigned int nf_hookfn(unsigned int hooknum,
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index e823786..9fe5571 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -279,6 +279,7 @@ struct xfrm_replay {
                           __be32 net_seq);
        void    (*notify)(struct xfrm_state *x, int event);
        int     (*overflow)(struct xfrm_state *x, struct sk_buff *skb);
+       void    (*failover)(struct xfrm_state *x, int ratio);
 };

 struct net_device;
diff --git a/include/uapi/linux/netfilter.h b/include/uapi/linux/netfilter.h
index f7dc0eb..c64d06a 100644
--- a/include/uapi/linux/netfilter.h
+++ b/include/uapi/linux/netfilter.h
@@ -48,7 +48,15 @@ enum nf_inet_hooks {
        NF_INET_FORWARD,
        NF_INET_LOCAL_OUT,
        NF_INET_POST_ROUTING,
-       NF_INET_NUMHOOKS
+       NF_INET_NUMHOOKS,
+
+#ifdef __KERNEL__
+       /* not accessible from userspace, keep iptables ABI. */
+       NF_INET_XFRM_IN = NF_INET_NUMHOOKS,
+       NF_INET_XFRM_OUT,
+
+       NF_MAX_HOOKS
+#endif
 };

 enum {
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 0b732ef..eeb992e 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -21,6 +21,7 @@
 #include <linux/udp.h>
 #include <linux/icmp.h>
 #include <linux/if_arp.h>
+#include <linux/etherdevice.h>
 #include <linux/seq_file.h>
 #include <linux/netfilter_arp.h>
 #include <linux/netfilter/x_tables.h>
@@ -30,8 +31,9 @@
 #include <net/net_namespace.h>
 #include <net/checksum.h>
 #include <net/ip.h>
+#include <net/xfrm.h>

-#define CLUSTERIP_VERSION "0.8"
+#define CLUSTERIP_VERSION "0.9"

 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Harald Welte <laforge at netfilter.org>");
@@ -113,7 +115,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
 }

 static struct clusterip_config *
-__clusterip_config_find(__be32 clusterip)
+clusterip_config_find(__be32 clusterip)
 {
        struct clusterip_config *c;

@@ -125,13 +127,26 @@ __clusterip_config_find(__be32 clusterip)
        return NULL;
 }

+static struct clusterip_config *
+clusterip_config_find_mac(u_int8_t clustermac[])
+{
+       struct clusterip_config *c;
+
+       list_for_each_entry_rcu(c, &clusterip_configs, list) {
+               if (memcmp(c->clustermac, clustermac, ETH_ALEN) == 0)
+                       return c;
+       }
+
+       return NULL;
+}
+
 static inline struct clusterip_config *
 clusterip_config_find_get(__be32 clusterip, int entry)
 {
        struct clusterip_config *c;

        rcu_read_lock_bh();
-       c = __clusterip_config_find(clusterip);
+       c = clusterip_config_find(clusterip);
        if (c) {
                if (unlikely(!atomic_inc_not_zero(&c->refcount)))
                        c = NULL;
@@ -143,6 +158,22 @@ clusterip_config_find_get(__be32 clusterip, int entry)
        return c;
 }

+static inline struct clusterip_config *
+clusterip_config_find_get_mac(u_int8_t clustermac[])
+{
+       struct clusterip_config *c;
+
+       rcu_read_lock_bh();
+       c = clusterip_config_find_mac(clustermac);
+       if (c) {
+               if (unlikely(!atomic_inc_not_zero(&c->refcount)))
+                       c = NULL;
+       }
+       rcu_read_unlock_bh();
+
+       return c;
+}
+
 static void
 clusterip_config_init_nodelist(struct clusterip_config *c,
                               const struct ipt_clusterip_tgt_info *i)
@@ -197,6 +228,33 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip,
 }

 #ifdef CONFIG_PROC_FS
+#ifdef CONFIG_XFRM
+static int
+clusterip_advance_xfrm_seq_one(struct xfrm_state *x, int count, void *data)
+{
+       __be32 clusterip = *(__be32 *)data;
+
+       if (x->repl && x->props.family == AF_INET &&
+           x->props.saddr.a4 == clusterip) {
+               spin_lock(&x->lock);
+               x->repl->failover(x, 16);
+               spin_unlock(&x->lock);
+       }
+       return 0;
+}
+
+static void
+clusterip_advance_xfrm_seq(__be32 clusterip, u8 proto)
+{
+       struct xfrm_state_walk walk;
+
+       xfrm_state_walk_init(&walk, proto);
+       xfrm_state_walk(&init_net, &walk, clusterip_advance_xfrm_seq_one,
+                       &clusterip);
+       xfrm_state_walk_done(&walk);
+}
+#endif /* CONFIG_XFRM */
+
 static int
 clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum)
 {
@@ -212,19 +270,26 @@ clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum)
        return 0;
 }

-static bool
+static int
 clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum)
 {
        if (nodenum == 0 ||
            nodenum > c->num_total_nodes)
-               return true;
+               return 1;
+
+       if (!test_and_clear_bit(nodenum - 1, &c->local_nodes))
+               return 1;

-       if (test_and_clear_bit(nodenum - 1, &c->local_nodes))
-               return false;
+       return 0;
+}
+#endif /* CONFIG_PROC_FS */

-       return true;
+static inline u_int32_t
+clusterip_hash_to_node(const struct clusterip_config *c, u64 hash)
+{
+       /* node numbers are 1..n, not 0..n */
+       return ((hash * c->num_total_nodes) >> 32) + 1;
 }
-#endif

 static inline u_int32_t
 clusterip_hashfn(const struct sk_buff *skb,
@@ -272,8 +337,7 @@ clusterip_hashfn(const struct sk_buff *skb,
                break;
        }

-       /* node numbers are 1..n, not 0..n */
-       return (((u64)hashval * config->num_total_nodes) >> 32) + 1;
+       return clusterip_hash_to_node(config, hashval);
 }

 static inline int
@@ -302,12 +366,34 @@ clusterip_tg(struct sk_buff *skb, const struct xt_action_param *par)
        if (ct == NULL)
                return NF_DROP;

-       /* special case: ICMP error handling. conntrack distinguishes between
-        * error messages (RELATED) and information requests (see below) */
-       if (ip_hdr(skb)->protocol == IPPROTO_ICMP &&
-           (ctinfo == IP_CT_RELATED ||
-            ctinfo == IP_CT_RELATED_REPLY))
+       switch (ip_hdr(skb)->protocol) {
+       case IPPROTO_ICMP:
+               /* ICMP error handling: conntrack distinguishes between error
+                * messages (RELATED) and information requests (see below)
+                */
+               if (ctinfo == IP_CT_RELATED ||
+                   ctinfo == IP_CT_RELATED_REPLY)
+                       return XT_CONTINUE;
+               break;
+#ifdef CONFIG_XFRM
+       case IPPROTO_ESP:
+       case IPPROTO_AH:
+       case IPPROTO_IPIP:
+               /* responsibility for IPsec is handled in xfrm input hook */
                return XT_CONTINUE;
+       case IPPROTO_UDP: {
+               /* UDP 4500 with an SPI is encapsulated ESP */
+               const struct iphdr *iph = ip_hdr(skb);
+               const u_int16_t *halfs = (const void *)iph+iph->ihl*4;
+
+               if (halfs[1] == htons(4500) && (halfs[4] || halfs[5]))
+                       return XT_CONTINUE;
+               break;
+       }
+#endif /* CONFIG_XFRM */
+       default:
+               break;
+       }

        /* ip_conntrack_icmp guarantees us that we only have ICMP_ECHO,
         * TIMESTAMP, INFO_REQUEST or ADDRESS type icmp packets from here
@@ -545,6 +631,158 @@ static struct nf_hook_ops cip_arp_ops __read_mostly = {
 };

 /***********************************************************************
+ * IPSEC FORWARDING HOOKS
+ ***********************************************************************/
+
+#ifdef CONFIG_XFRM
+
+static unsigned int
+cip_pre_routing_hook(const struct nf_hook_ops hook,
+                    struct sk_buff *skb,
+                    const struct net_device *in,
+                    const struct net_device *out,
+                    int (*okfn)(struct sk_buff *))
+{
+       if (skb_mac_header(skb) < skb->head ||
+           skb_mac_header(skb) + ETH_HLEN > skb->data ||
+           !is_multicast_ether_addr(eth_hdr(skb)->h_dest))
+               return NF_ACCEPT;
+
+       /* if we receive a packet for a CLUSTERIP multicast address,
+        * we let it pass through ip_forward.
+        */
+       if (clusterip_config_find_mac(eth_hdr(skb)->h_dest))
+               skb->pkt_type = PACKET_HOST;
+
+       return NF_ACCEPT;
+}
+
+static struct nf_hook_ops cip_pre_routing_ops __read_mostly = {
+       .hook           = cip_pre_routing_hook,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_INET_PRE_ROUTING,
+       .priority       = -1,
+};
+
+static inline u_int32_t
+clusterip_hashfn_xfrm(const struct xfrm_state *x,
+                     const struct clusterip_config *config)
+{
+       unsigned long hashval;
+
+       hashval = jhash_2words(ntohl(x->id.daddr.a4), ntohl(x->id.spi),
+                              config->hash_initval);
+       return clusterip_hash_to_node(config, hashval);
+}
+
+/* interval to process packet not responsible */
+#define SEQ_UPDATE_MASK 0x0F
+
+static unsigned int
+cip_xfrm_in_hook(const struct nf_hook_ops hook,
+                struct sk_buff *skb,
+                const struct net_device *in,
+                const struct net_device *out,
+                int (*okfn)(struct sk_buff *))
+{
+       struct clusterip_config *c;
+       struct xfrm_state *x;
+       u_int32_t hash;
+       __be32 seq;
+       unsigned int res = NF_DROP;
+
+       x = skb->sp->xvec[skb->sp->len - 1];
+
+       switch (x->id.proto) {
+       case IPPROTO_ESP:
+       case IPPROTO_AH:
+               break;
+       case IPPROTO_IPIP:
+       case IPPROTO_COMP:
+               /* FIXME: Accept IPCOMP if packet was encrypted only */
+       default:
+               return NF_ACCEPT;
+       }
+
+       c = clusterip_config_find_get(x->id.daddr.a4, 0);
+       if (!c)
+               return NF_ACCEPT;
+
+       /* process every n-th packet to update sequence counter, but drop it */
+       hash = clusterip_hashfn_xfrm(x, c);
+       seq = XFRM_SKB_CB(skb)->seq.input.low;
+       if (clusterip_responsible(c, hash))
+               res = NF_ACCEPT;
+       else if ((ntohl(seq) & SEQ_UPDATE_MASK) == 0) {
+               if (x->type->input(x, skb) > 0) {
+                       spin_lock(&x->lock);
+
+                       x->repl->advance(x, seq);
+
+                       spin_unlock(&x->lock);
+               }
+       }
+       clusterip_config_put(c);
+       return res;
+}
+
+static struct nf_hook_ops cip_xfrm_in_ops __read_mostly = {
+       .hook           = cip_xfrm_in_hook,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_INET_XFRM_IN,
+       .priority       = -1,
+};
+
+static unsigned int
+cip_xfrm_out_hook(const struct nf_hook_ops hook,
+                 struct sk_buff *skb,
+                 const struct net_device *in,
+                 const struct net_device *out,
+                 int (*okfn)(struct sk_buff *))
+{
+       struct clusterip_config *c;
+       struct xfrm_state *x;
+       u_int32_t hash;
+       unsigned int res = NF_DROP;
+
+       x = skb_dst(skb)->xfrm;
+
+       switch (x->id.proto) {
+       case IPPROTO_ESP:
+       case IPPROTO_AH:
+               break;
+       case IPPROTO_IPIP:
+       case IPPROTO_COMP:
+               /* FIXME: Skip IPCOMP processing if we are not responsible */
+       default:
+               return NF_ACCEPT;
+       }
+
+       c = clusterip_config_find_get(x->props.saddr.a4, 0);
+       if (!c)
+               return NF_ACCEPT;
+
+       hash = clusterip_hashfn_xfrm(x, c);
+       if (clusterip_responsible(c, hash))
+               res = NF_ACCEPT;
+
+       clusterip_config_put(c);
+       return res;
+}
+
+static struct nf_hook_ops cip_xfrm_out_ops __read_mostly = {
+       .hook           = cip_xfrm_out_hook,
+       .owner          = THIS_MODULE,
+       .pf             = PF_INET,
+       .hooknum        = NF_INET_XFRM_OUT,
+       .priority       = -1,
+};
+
+#endif /* CONFIG_XFRM */
+
+/***********************************************************************
  * PROC DIR HANDLING
  ***********************************************************************/

@@ -684,6 +922,11 @@ static ssize_t clusterip_proc_write(struct file *file, const char __user *input,
        } else
                return -EIO;

+#ifdef CONFIG_XFRM
+       clusterip_advance_xfrm_seq(c->clusterip, IPPROTO_ESP);
+       clusterip_advance_xfrm_seq(c->clusterip, IPPROTO_AH);
+#endif /* CONFIG_XFRM */
+
        return size;
 }

@@ -706,10 +949,24 @@ static int __init clusterip_tg_init(void)
        if (ret < 0)
                return ret;

-       ret = nf_register_hook(&cip_arp_ops);
+#ifdef CONFIG_XFRM
+       ret = nf_register_hook(&cip_pre_routing_ops);
        if (ret < 0)
                goto cleanup_target;

+       ret = nf_register_hook(&cip_xfrm_in_ops);
+       if (ret < 0)
+               goto cleanup_pre;
+
+       ret = nf_register_hook(&cip_xfrm_out_ops);
+       if (ret < 0)
+               goto cleanup_xfrm_in;
+#endif /* CONFIG_XFRM */
+
+       ret = nf_register_hook(&cip_arp_ops);
+       if (ret < 0)
+               goto cleanup_xfrm_out;
+
 #ifdef CONFIG_PROC_FS
        clusterip_procdir = proc_mkdir("ipt_CLUSTERIP", init_net.proc_net);
        if (!clusterip_procdir) {
@@ -727,7 +984,15 @@ static int __init clusterip_tg_init(void)
 cleanup_hook:
        nf_unregister_hook(&cip_arp_ops);
 #endif /* CONFIG_PROC_FS */
+cleanup_xfrm_out:
+#ifdef CONFIG_XFRM
+       nf_unregister_hook(&cip_xfrm_out_ops);
+cleanup_xfrm_in:
+       nf_unregister_hook(&cip_xfrm_in_ops);
+cleanup_pre:
+       nf_unregister_hook(&cip_pre_routing_ops);
 cleanup_target:
+#endif /* CONFIG_XFRM */
        xt_unregister_target(&clusterip_tg_reg);
        return ret;
 }
@@ -739,6 +1004,11 @@ static void __exit clusterip_tg_exit(void)
        proc_remove(clusterip_procdir);
 #endif
        nf_unregister_hook(&cip_arp_ops);
+#ifdef CONFIG_XFRM
+       nf_unregister_hook(&cip_pre_routing_ops);
+       nf_unregister_hook(&cip_xfrm_in_ops);
+       nf_unregister_hook(&cip_xfrm_out_ops);
+#endif /* CONFIG_XFRM */
        xt_unregister_target(&clusterip_tg_reg);

        /* Wait for completion of call_rcu_bh()'s (clusterip_config_rcu_free) */
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 8884399..0ef7ddd 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -9,6 +9,7 @@

 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/netfilter.h>
 #include <linux/netdevice.h>
 #include <net/dst.h>
 #include <net/ip.h>
@@ -102,6 +103,14 @@ int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
 }
 EXPORT_SYMBOL(xfrm_prepare_input);

+static int xfrm_type_input(struct sk_buff *skb)
+{
+       struct xfrm_state *x;
+
+       x = skb->sp->xvec[skb->sp->len - 1];
+       return x->type->input(x, skb);
+}
+
 int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
 {
        struct net *net = dev_net(skb->dev);
@@ -197,9 +206,10 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)

                skb_dst_force(skb);

-               nexthdr = x->type->input(x, skb);
+               nexthdr = NF_HOOK(family, NF_INET_XFRM_IN, skb,
+                                 skb->dev, NULL, xfrm_type_input);

-               if (nexthdr == -EINPROGRESS)
+               if (nexthdr == -EINPROGRESS || nexthdr == -EPERM)
                        return 0;

 resume:
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 3bb2cdc..add29a9 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -38,6 +38,13 @@ static int xfrm_skb_check_space(struct sk_buff *skb)
        return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC);
 }

+static int xfrm_type_output(struct sk_buff *skb)
+{
+       struct xfrm_state *x = skb_dst(skb)->xfrm;
+
+       return x->type->output(x, skb);
+}
+
 static int xfrm_output_one(struct sk_buff *skb, int err)
 {
        struct dst_entry *dst = skb_dst(skb);
@@ -87,8 +94,9 @@ static int xfrm_output_one(struct sk_buff *skb, int err)

                skb_dst_force(skb);

-               err = x->type->output(x, skb);
-               if (err == -EINPROGRESS)
+               err = NF_HOOK(dst->ops->family, NF_INET_XFRM_OUT, skb,
+                             NULL, dst->dev, xfrm_type_output);
+               if (err == -EINPROGRESS || err == -EPERM)
                        goto out_exit;

 resume:
diff --git a/net/xfrm/xfrm_replay.c b/net/xfrm/xfrm_replay.c
index 8dafe6d3..013fd42 100644
--- a/net/xfrm/xfrm_replay.c
+++ b/net/xfrm/xfrm_replay.c
@@ -113,6 +115,23 @@ static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb)
        return err;
 }

+static void xfrm_replay_failover(struct xfrm_state *x, int ratio)
+{
+       struct net *net = xs_net(x);
+       u32 incr;
+
+       if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
+
+               incr = x->replay.oseq / ratio;
+               if (U32_MAX - x->replay.oseq > incr) {
+                       x->replay.oseq += incr;
+
+                       if (xfrm_aevent_is_on(net))
+                               x->repl->notify(x, XFRM_REPLAY_UPDATE);
+               }
+       }
+}
+
 static int xfrm_replay_check(struct xfrm_state *x,
                      struct sk_buff *skb, __be32 net_seq)
 {
@@ -192,6 +211,24 @@ static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb)
        return err;
 }

+static void xfrm_replay_failover_bmp(struct xfrm_state *x, int ratio)
+{
+       struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
+       struct net *net = xs_net(x);
+       u32 incr;
+
+       if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
+
+               incr = replay_esn->oseq / ratio;
+               if (U32_MAX - replay_esn->oseq > incr) {
+                       replay_esn->oseq += incr;
+
+                       if (xfrm_aevent_is_on(net))
+                               x->repl->notify(x, XFRM_REPLAY_UPDATE);
+               }
+       }
+}
+
 static int xfrm_replay_check_bmp(struct xfrm_state *x,
                                 struct sk_buff *skb, __be32 net_seq)
 {
@@ -427,6 +464,31 @@ static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb)
        return err;
 }

+static void xfrm_replay_failover_esn(struct xfrm_state *x, int ratio)
+{
+       struct xfrm_replay_state_esn *replay_esn = x->replay_esn;
+       struct net *net = xs_net(x);
+       u32 incr;
+
+       if (x->type->flags & XFRM_TYPE_REPLAY_PROT) {
+
+               if (replay_esn->oseq_hi)
+                       incr = U32_MAX / ratio;
+               else
+                       incr = replay_esn->oseq / ratio;
+               if (U32_MAX - replay_esn->oseq < incr) {
+                       replay_esn->oseq_hi++;
+                       if (replay_esn->oseq_hi == 0) {
+                               replay_esn->oseq_hi--;
+                               incr = 0;
+                       }
+               }
+               replay_esn->oseq += incr;
+               if (xfrm_aevent_is_on(net))
+                       x->repl->notify(x, XFRM_REPLAY_UPDATE);
+       }
+}
+
 static int xfrm_replay_check_esn(struct xfrm_state *x,
                                 struct sk_buff *skb, __be32 net_seq)
 {
@@ -560,6 +622,7 @@ static struct xfrm_replay xfrm_replay_legacy = {
        .recheck        = xfrm_replay_check,
        .notify         = xfrm_replay_notify,
        .overflow       = xfrm_replay_overflow,
+       .failover       = xfrm_replay_failover,
 };

 static struct xfrm_replay xfrm_replay_bmp = {
@@ -568,6 +631,7 @@ static struct xfrm_replay xfrm_replay_bmp = {
        .recheck        = xfrm_replay_check_bmp,
        .notify         = xfrm_replay_notify_bmp,
        .overflow       = xfrm_replay_overflow_bmp,
+       .failover       = xfrm_replay_failover_bmp,
 };

 static struct xfrm_replay xfrm_replay_esn = {
@@ -576,6 +640,7 @@ static struct xfrm_replay xfrm_replay_esn = {
        .recheck        = xfrm_replay_recheck_esn,
        .notify         = xfrm_replay_notify_esn,
        .overflow       = xfrm_replay_overflow_esn,
+       .failover       = xfrm_replay_failover_esn,
 };

 int xfrm_init_replay(struct xfrm_state *x)

-----Original Message-----
From: users-bounces at lists.strongswan.org [mailto:users-bounces at lists.strongswan.org] On Behalf Of Whisker, Peter
Sent: 25 September 2015 15:23
To: users at lists.strongswan.org
Subject: [strongSwan] Issues with HA configuration

Hi

I'm struggling with the HA cluster configuration on Centos 7 (I have what seems to work well running on Debian Jessie). I have now got to a stage where the IPSec side of the HA seems to be working (one node is passive and one is active) but I'm having issues routing to the protected network behind the Strongwan cluster.

I have patched Linux 3.10 (on Centos 7) using the 3.11 CLUSTERIP/XFRM patches in ha-3.11-abicompat.patch.bz2 . One needed to be done manually as there was a minor variable name change between 3.10 and 3.11.

I have set up the two CLUSTERIP rules on the two boxes as:

[root at irisp-gsgw-1a ipv4]# cat /sbin/ifup-local #!/bin/sh

if [ "$1" = "ens224" ]; then
echo "Setting up HA cluster (Air side) address on $1"
/usr/sbin/ip address add 10.0.0.2/24 dev ens224
/usr/sbin/iptables -A INPUT -i ens224 -d 10.0.0.2 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5e:00:64:20    --total-nodes 2 --local-node 0
fi

if [ "$1" == "ens256" ]; then
echo "Setting up HA cluster (Ground side) address on $1"
/usr/sbin/ip address add 10.10.0.200/24 dev ens256
/usr/sbin/iptables -A INPUT -i ens256 -d 10.10.0.200 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5e:00:65:40    --total-nodes 2 --local-node 0
fi

I have enabled forwarding and there are no iptables rules to stop it:

[root at irisp-gsgw-1a ipv4]# cat /etc/sysctl.conf # System default settings live in /usr/lib/sysctl.d/00-system.conf.
# To override those settings, enter new settings here, or in an /etc/sysctl.d/<name>.conf file # # For more information, see sysctl.conf(5) and sysctl.d(5).
net.ipv4.ip_forward=1

[root at irisp-gsgw-1a ipv4]# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
CLUSTERIP  all  --  anywhere             irisp-gsgw-1a        CLUSTERIP hashmode=sourceip clustermac=01:00:5E:00:64:20 total_nodes=2 local_node=0 hash_init=0
CLUSTERIP  all  --  anywhere             irisp-gsgw-1a        CLUSTERIP hashmode=sourceip clustermac=01:00:5E:00:65:40 total_nodes=2 local_node=0 hash_init=0
LOGGING    all  --  anywhere             anywhere
LOG        all  --  anywhere             anywhere             limit: avg 15/min burst 5 LOG level debug prefix "IPTABLES DENIED[INPUT]:  "

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain LOGGING (1 references)
target     prot opt source               destination
[root at irisp-gsgw-1a ipv4]# iptables -L -t nat Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination

The network addresses are there:
[root at irisp-gsgw-1a ipv4]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: ens161: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:7b:03:c9 brd ff:ff:ff:ff:ff:ff
    inet 1xx.xxx.89.92/22 brd 158.234.91.255 scope global dynamic ens161
       valid_lft 8323sec preferred_lft 8323sec
    inet6 fe80::20c:29ff:fe7b:3c9/64 scope link
       valid_lft forever preferred_lft forever
3: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:7b:03:ab brd ff:ff:ff:ff:ff:ff
    inet 172.31.255.201/24 brd 172.31.255.255 scope global ens192
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7b:3ab/64 scope link
       valid_lft forever preferred_lft forever
4: ens224: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:7b:03:b5 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.11/24 brd 10.0.0.255 scope global ens224
       valid_lft forever preferred_lft forever
    inet 10.0.0.2/24 scope global secondary ens224
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7b:3b5/64 scope link
       valid_lft forever preferred_lft forever
5: ens256: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 00:0c:29:7b:03:bf brd ff:ff:ff:ff:ff:ff
    inet 10.10.0.201/24 brd 10.10.0.255 scope global ens256
       valid_lft forever preferred_lft forever
    inet 10.10.0.200/24 scope global secondary ens256
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe7b:3bf/64 scope link
       valid_lft forever preferred_lft forever [root at irisp-gsgw-1a ipv4]#

ens192 is the hearbeat, ens224 is the encrypted link over the public network and ens256 is the link to the protected network.

I have a test server on 10.10.0.203 which has a route to 10.10.0.200 (the VIP) for the remote client which is on 172.26.0.1

[root at irisp-gsgw-1a ipv4]# ipsec status
Security Associations (1 up, 0 connecting):
        asgw[1]: ESTABLISHED 3 hours ago, 10.0.0.2[C=GB, O=Iris Service Provider, OU=airline device sponsor, CN=GSGW28Aug15]...10.126.0.2[ICAO76543210.IMSI543210987654321.CRD123456789abc.00]
        asgw{1}:  INSTALLED, TUNNEL, reqid 1, ESP in UDP SPIs: c86c1ca9_i f5d3d5f9_o
        asgw{1}:   10.10.0.0/24 === 172.26.0.1/32

When I ping 172.26.0.1 from 10.10.0.203 I can see the ICMP requests appearing on both StrongSwan nodes in tcpdump but neither seem to deal with it (ie it gets dropped).
When I ping 10.10.0.203 from 172.26.0.1, the ICMP request gets put onto the 10.10.0.0/24 network and 10.10.0.203 replies however as before with the ICMP request the reply gets dropped.

I believe from dropwatch that the reply is being dropped in ip_forward+1b8 which is the code at the end:

drop:
        kfree_skb(skb);
        return NET_RX_DROP;
}

One question I have is about the 
iptables -A INPUT -i ens224 -d 10.0.0.2 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5e:00:64:20    --total-nodes 2 --local-node 0
iptables -A INPUT -i ens256 -d 10.10.0.200 -j CLUSTERIP --new --hashmode sourceip --clustermac 01:00:5e:00:65:40    --total-nodes 2 --local-node 0

lines looking similar like this (which I have send elsewhere). If the hash is on SOURCE IP then won't it potentially hash to a different segment depending on the direction of the message? Or am I missing something? I would really appreciate some guidance! Could there be one of the settings (perhaps related to multicast ARP or martians or something which I might also need to change?)

Many thanks
Peter
_______________________________________________
Users mailing list
Users at lists.strongswan.org
https://lists.strongswan.org/mailman/listinfo/users


More information about the Users mailing list