Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf

Pablo Neira Ayuso says:

====================
The following patchset contains Netfilter/IPVS fixes for 3.10-rc3,
they are:

* fix xt_addrtype with IPv6, from Florian Westphal. This required
a new hook for IPv6 functions in the netfilter core to avoid
hard dependencies with the ipv6 subsystem when this match is
only used for IPv4.

* fix connection reuse case in IPVS. Currently, if an reused
connection are directed to the same server. If that server is
down, those connection would fail. Therefore, clear the
connection and choose a new server among the available ones.

* fix possible non-nul terminated string sent to user-space if
ipt_ULOG is used as the default netfilter logging stub, from
Chen Gang.

* fix mark logging of IPv6 packets in xt_LOG, from Michal Kubecek.
This bug has been there since 2.6.26.

* Fix breakage ip_vs_sh due to incorrect structure layout for
RCU, from Jan Beulich.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+85 -18
+16
include/linux/netfilter_ipv6.h
··· 17 17 18 18 extern int ipv6_netfilter_init(void); 19 19 extern void ipv6_netfilter_fini(void); 20 + 21 + /* 22 + * Hook functions for ipv6 to allow xt_* modules to be built-in even 23 + * if IPv6 is a module. 24 + */ 25 + struct nf_ipv6_ops { 26 + int (*chk_addr)(struct net *net, const struct in6_addr *addr, 27 + const struct net_device *dev, int strict); 28 + }; 29 + 30 + extern const struct nf_ipv6_ops __rcu *nf_ipv6_ops; 31 + static inline const struct nf_ipv6_ops *nf_get_ipv6_ops(void) 32 + { 33 + return rcu_dereference(nf_ipv6_ops); 34 + } 35 + 20 36 #else /* CONFIG_NETFILTER */ 21 37 static inline int ipv6_netfilter_init(void) { return 0; } 22 38 static inline void ipv6_netfilter_fini(void) { return; }
+1 -1
include/net/addrconf.h
··· 65 65 66 66 extern int ipv6_chk_addr(struct net *net, 67 67 const struct in6_addr *addr, 68 - struct net_device *dev, 68 + const struct net_device *dev, 69 69 int strict); 70 70 71 71 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+4 -2
net/ipv4/netfilter/ipt_ULOG.c
··· 231 231 put_unaligned(tv.tv_usec, &pm->timestamp_usec); 232 232 put_unaligned(skb->mark, &pm->mark); 233 233 pm->hook = hooknum; 234 - if (prefix != NULL) 235 - strncpy(pm->prefix, prefix, sizeof(pm->prefix)); 234 + if (prefix != NULL) { 235 + strncpy(pm->prefix, prefix, sizeof(pm->prefix) - 1); 236 + pm->prefix[sizeof(pm->prefix) - 1] = '\0'; 237 + } 236 238 else if (loginfo->prefix[0] != '\0') 237 239 strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix)); 238 240 else
+1 -1
net/ipv6/addrconf.c
··· 1487 1487 } 1488 1488 1489 1489 int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, 1490 - struct net_device *dev, int strict) 1490 + const struct net_device *dev, int strict) 1491 1491 { 1492 1492 struct inet6_ifaddr *ifp; 1493 1493 unsigned int hash = inet6_addr_hash(addr);
+7
net/ipv6/netfilter.c
··· 10 10 #include <linux/netfilter.h> 11 11 #include <linux/netfilter_ipv6.h> 12 12 #include <linux/export.h> 13 + #include <net/addrconf.h> 13 14 #include <net/dst.h> 14 15 #include <net/ipv6.h> 15 16 #include <net/ip6_route.h> ··· 187 186 return csum; 188 187 }; 189 188 189 + static const struct nf_ipv6_ops ipv6ops = { 190 + .chk_addr = ipv6_chk_addr, 191 + }; 192 + 190 193 static const struct nf_afinfo nf_ip6_afinfo = { 191 194 .family = AF_INET6, 192 195 .checksum = nf_ip6_checksum, ··· 203 198 204 199 int __init ipv6_netfilter_init(void) 205 200 { 201 + RCU_INIT_POINTER(nf_ipv6_ops, &ipv6ops); 206 202 return nf_register_afinfo(&nf_ip6_afinfo); 207 203 } 208 204 ··· 212 206 */ 213 207 void ipv6_netfilter_fini(void) 214 208 { 209 + RCU_INIT_POINTER(nf_ipv6_ops, NULL); 215 210 nf_unregister_afinfo(&nf_ip6_afinfo); 216 211 }
+2
net/netfilter/core.c
··· 30 30 31 31 const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO] __read_mostly; 32 32 EXPORT_SYMBOL(nf_afinfo); 33 + const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly; 34 + EXPORT_SYMBOL_GPL(nf_ipv6_ops); 33 35 34 36 int nf_register_afinfo(const struct nf_afinfo *afinfo) 35 37 {
+35
net/netfilter/ipvs/ip_vs_core.c
··· 1001 1001 return th->rst; 1002 1002 } 1003 1003 1004 + static inline bool is_new_conn(const struct sk_buff *skb, 1005 + struct ip_vs_iphdr *iph) 1006 + { 1007 + switch (iph->protocol) { 1008 + case IPPROTO_TCP: { 1009 + struct tcphdr _tcph, *th; 1010 + 1011 + th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph); 1012 + if (th == NULL) 1013 + return false; 1014 + return th->syn; 1015 + } 1016 + case IPPROTO_SCTP: { 1017 + sctp_chunkhdr_t *sch, schunk; 1018 + 1019 + sch = skb_header_pointer(skb, iph->len + sizeof(sctp_sctphdr_t), 1020 + sizeof(schunk), &schunk); 1021 + if (sch == NULL) 1022 + return false; 1023 + return sch->type == SCTP_CID_INIT; 1024 + } 1025 + default: 1026 + return false; 1027 + } 1028 + } 1029 + 1004 1030 /* Handle response packets: rewrite addresses and send away... 1005 1031 */ 1006 1032 static unsigned int ··· 1638 1612 * Check if the packet belongs to an existing connection entry 1639 1613 */ 1640 1614 cp = pp->conn_in_get(af, skb, &iph, 0); 1615 + 1616 + if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp && cp->dest && 1617 + unlikely(!atomic_read(&cp->dest->weight)) && !iph.fragoffs && 1618 + is_new_conn(skb, &iph)) { 1619 + ip_vs_conn_expire_now(cp); 1620 + __ip_vs_conn_put(cp); 1621 + cp = NULL; 1622 + } 1623 + 1641 1624 if (unlikely(!cp) && !iph.fragoffs) { 1642 1625 /* No (second) fragments need to enter here, as nf_defrag_ipv6 1643 1626 * replayed fragment zero will already have created the cp
+1 -1
net/netfilter/ipvs/ip_vs_sh.c
··· 67 67 #define IP_VS_SH_TAB_MASK (IP_VS_SH_TAB_SIZE - 1) 68 68 69 69 struct ip_vs_sh_state { 70 - struct ip_vs_sh_bucket buckets[IP_VS_SH_TAB_SIZE]; 71 70 struct rcu_head rcu_head; 71 + struct ip_vs_sh_bucket buckets[IP_VS_SH_TAB_SIZE]; 72 72 }; 73 73 74 74 /*
+1 -1
net/netfilter/xt_LOG.c
··· 737 737 dump_sk_uid_gid(m, skb->sk); 738 738 739 739 /* Max length: 16 "MARK=0xFFFFFFFF " */ 740 - if (!recurse && skb->mark) 740 + if (recurse && skb->mark) 741 741 sb_add(m, "MARK=0x%x ", skb->mark); 742 742 } 743 743
+17 -12
net/netfilter/xt_addrtype.c
··· 22 22 #include <net/ip6_fib.h> 23 23 #endif 24 24 25 + #include <linux/netfilter_ipv6.h> 25 26 #include <linux/netfilter/xt_addrtype.h> 26 27 #include <linux/netfilter/x_tables.h> 27 28 ··· 34 33 35 34 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) 36 35 static u32 match_lookup_rt6(struct net *net, const struct net_device *dev, 37 - const struct in6_addr *addr) 36 + const struct in6_addr *addr, u16 mask) 38 37 { 39 38 const struct nf_afinfo *afinfo; 40 39 struct flowi6 flow; 41 40 struct rt6_info *rt; 42 - u32 ret; 41 + u32 ret = 0; 43 42 int route_err; 44 43 45 44 memset(&flow, 0, sizeof(flow)); ··· 50 49 rcu_read_lock(); 51 50 52 51 afinfo = nf_get_afinfo(NFPROTO_IPV6); 53 - if (afinfo != NULL) 54 - route_err = afinfo->route(net, (struct dst_entry **)&rt, 55 - flowi6_to_flowi(&flow), !!dev); 56 - else 57 - route_err = 1; 52 + if (afinfo != NULL) { 53 + const struct nf_ipv6_ops *v6ops; 58 54 55 + if (dev && (mask & XT_ADDRTYPE_LOCAL)) { 56 + v6ops = nf_get_ipv6_ops(); 57 + if (v6ops && v6ops->chk_addr(net, addr, dev, true)) 58 + ret = XT_ADDRTYPE_LOCAL; 59 + } 60 + route_err = afinfo->route(net, (struct dst_entry **)&rt, 61 + flowi6_to_flowi(&flow), false); 62 + } else { 63 + route_err = 1; 64 + } 59 65 rcu_read_unlock(); 60 66 61 67 if (route_err) ··· 70 62 71 63 if (rt->rt6i_flags & RTF_REJECT) 72 64 ret = XT_ADDRTYPE_UNREACHABLE; 73 - else 74 - ret = 0; 75 65 76 - if (rt->rt6i_flags & RTF_LOCAL) 66 + if (dev == NULL && rt->rt6i_flags & RTF_LOCAL) 77 67 ret |= XT_ADDRTYPE_LOCAL; 78 68 if (rt->rt6i_flags & RTF_ANYCAST) 79 69 ret |= XT_ADDRTYPE_ANYCAST; 80 - 81 70 82 71 dst_release(&rt->dst); 83 72 return ret; ··· 95 90 96 91 if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST | 97 92 XT_ADDRTYPE_UNREACHABLE) & mask) 98 - return !!(mask & match_lookup_rt6(net, dev, addr)); 93 + return !!(mask & match_lookup_rt6(net, dev, addr, mask)); 99 94 return true; 100 95 } 101 96