ipvs: Supply destination address family to ip_vs_conn_new
authorAlex Gartrell <agartrell@fb.com>
Tue, 9 Sep 2014 23:40:23 +0000 (16:40 -0700)
committerSimon Horman <horms@verge.net.au>
Tue, 16 Sep 2014 00:03:34 +0000 (09:03 +0900)
The assumption that dest af is equal to service af is now unreliable, so we
must specify it manually so as not to copy just the first 4 bytes of a v6
address or doing an illegal read of 16 butes on a v6 address.

We "lie" in two places: for synchronization (which we will explicitly
disallow from happening when we have heterogeneous pools) and for black
hole addresses where there's no real dest.

Signed-off-by: Alex Gartrell <agartrell@fb.com>
Acked-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Simon Horman <horms@verge.net.au>
include/net/ip_vs.h
net/netfilter/ipvs/ip_vs_conn.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/ipvs/ip_vs_ftp.c
net/netfilter/ipvs/ip_vs_sync.c

index 2fa1155b24f75ea27644b8885cda5930e4343737..7600dbe5780e22c5e959f913498d1b6595a79ee4 100644 (file)
@@ -535,6 +535,7 @@ struct ip_vs_conn {
        union nf_inet_addr      daddr;          /* destination address */
        volatile __u32          flags;          /* status flags */
        __u16                   protocol;       /* Which protocol (TCP/UDP) */
+       __u16                   daf;            /* Address family of the dest */
 #ifdef CONFIG_NET_NS
        struct net              *net;           /* Name space */
 #endif
@@ -1213,7 +1214,7 @@ static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
 void ip_vs_conn_put(struct ip_vs_conn *cp);
 void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
 
-struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p,
+struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
                                  const union nf_inet_addr *daddr,
                                  __be16 dport, unsigned int flags,
                                  struct ip_vs_dest *dest, __u32 fwmark);
index 8f4c602bb34bfb4d7f9ad82cd0ac7fb08526a589..fdb4880a3a794a781b462516c38221f46aa4a285 100644 (file)
@@ -854,7 +854,7 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
  *     Create a new connection entry and hash it into the ip_vs_conn_tab
  */
 struct ip_vs_conn *
-ip_vs_conn_new(const struct ip_vs_conn_param *p,
+ip_vs_conn_new(const struct ip_vs_conn_param *p, int dest_af,
               const union nf_inet_addr *daddr, __be16 dport, unsigned int flags,
               struct ip_vs_dest *dest, __u32 fwmark)
 {
@@ -873,6 +873,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
        setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
        ip_vs_conn_net_set(cp, p->net);
        cp->af             = p->af;
+       cp->daf            = dest_af;
        cp->protocol       = p->protocol;
        ip_vs_addr_set(p->af, &cp->caddr, p->caddr);
        cp->cport          = p->cport;
@@ -880,7 +881,7 @@ ip_vs_conn_new(const struct ip_vs_conn_param *p,
        ip_vs_addr_set(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
                       &cp->vaddr, p->vaddr);
        cp->vport          = p->vport;
-       ip_vs_addr_set(p->af, &cp->daddr, daddr);
+       ip_vs_addr_set(cp->daf, &cp->daddr, daddr);
        cp->dport          = dport;
        cp->flags          = flags;
        cp->fwmark         = fwmark;
index 5c34e8d42e0190a14ec31c1238bde5929fdf0539..1f6ecb74821fded5ed47ab11f565a95698eefc54 100644 (file)
@@ -328,7 +328,7 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
                 * This adds param.pe_data to the template,
                 * and thus param.pe_data will be destroyed
                 * when the template expires */
-               ct = ip_vs_conn_new(&param, &dest->addr, dport,
+               ct = ip_vs_conn_new(&param, dest->af, &dest->addr, dport,
                                    IP_VS_CONN_F_TEMPLATE, dest, skb->mark);
                if (ct == NULL) {
                        kfree(param.pe_data);
@@ -357,7 +357,8 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
        ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol, &iph->saddr,
                              src_port, &iph->daddr, dst_port, &param);
 
-       cp = ip_vs_conn_new(&param, &dest->addr, dport, flags, dest, skb->mark);
+       cp = ip_vs_conn_new(&param, dest->af, &dest->addr, dport, flags, dest,
+                           skb->mark);
        if (cp == NULL) {
                ip_vs_conn_put(ct);
                *ignored = -1;
@@ -479,7 +480,7 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb,
                ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol,
                                      &iph->saddr, pptr[0], &iph->daddr,
                                      pptr[1], &p);
-               cp = ip_vs_conn_new(&p, &dest->addr,
+               cp = ip_vs_conn_new(&p, dest->af, &dest->addr,
                                    dest->port ? dest->port : pptr[1],
                                    flags, dest, skb->mark);
                if (!cp) {
@@ -550,7 +551,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
                        ip_vs_conn_fill_param(svc->net, svc->af, iph->protocol,
                                              &iph->saddr, pptr[0],
                                              &iph->daddr, pptr[1], &p);
-                       cp = ip_vs_conn_new(&p, &daddr, 0,
+                       cp = ip_vs_conn_new(&p, svc->af, &daddr, 0,
                                            IP_VS_CONN_F_BYPASS | flags,
                                            NULL, skb->mark);
                        if (!cp)
index 77c173282f388ce81bbd54ea6e41761656d95045..a64fa15790e53f8ad0eda7c53b73be8bd849f2aa 100644 (file)
@@ -233,7 +233,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
                        ip_vs_conn_fill_param(ip_vs_conn_net(cp),
                                              AF_INET, IPPROTO_TCP, &cp->caddr,
                                              0, &cp->vaddr, port, &p);
-                       n_cp = ip_vs_conn_new(&p, &from, port,
+                       /* As above, this is ipv4 only */
+                       n_cp = ip_vs_conn_new(&p, AF_INET, &from, port,
                                              IP_VS_CONN_F_NO_CPORT |
                                              IP_VS_CONN_F_NFCT,
                                              cp->dest, skb->mark);
@@ -396,7 +397,8 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
                                      htons(ntohs(cp->vport)-1), &p);
                n_cp = ip_vs_conn_in_get(&p);
                if (!n_cp) {
-                       n_cp = ip_vs_conn_new(&p, &cp->daddr,
+                       /* This is ipv4 only */
+                       n_cp = ip_vs_conn_new(&p, AF_INET, &cp->daddr,
                                              htons(ntohs(cp->dport)-1),
                                              IP_VS_CONN_F_NFCT, cp->dest,
                                              skb->mark);
index edd266414b7d6128e1255f7afbc54540d7176d46..7162c86fd50dca443c0e7c3aa008cdb93038b7e3 100644 (file)
@@ -889,7 +889,8 @@ static void ip_vs_proc_conn(struct net *net, struct ip_vs_conn_param *param,
                                       param->vaddr, param->vport, protocol,
                                       fwmark, flags);
 
-               cp = ip_vs_conn_new(param, daddr, dport, flags, dest, fwmark);
+               cp = ip_vs_conn_new(param, type, daddr, dport, flags, dest,
+                                   fwmark);
                rcu_read_unlock();
                if (!cp) {
                        kfree(param->pe_data);