Skip to content

Commit

Permalink
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/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>
  • Loading branch information
David S. Miller committed May 30, 2013
2 parents 8e6d91a + a70b964 commit 73ce00d
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 17 deletions.
16 changes: 16 additions & 0 deletions include/linux/netfilter_ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,22 @@ extern __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook,

extern int ipv6_netfilter_init(void);
extern void ipv6_netfilter_fini(void);

/*
* Hook functions for ipv6 to allow xt_* modules to be built-in even
* if IPv6 is a module.
*/
struct nf_ipv6_ops {
int (*chk_addr)(struct net *net, const struct in6_addr *addr,
const struct net_device *dev, int strict);
};

extern const struct nf_ipv6_ops __rcu *nf_ipv6_ops;
static inline const struct nf_ipv6_ops *nf_get_ipv6_ops(void)
{
return rcu_dereference(nf_ipv6_ops);
}

#else /* CONFIG_NETFILTER */
static inline int ipv6_netfilter_init(void) { return 0; }
static inline void ipv6_netfilter_fini(void) { return; }
Expand Down
2 changes: 1 addition & 1 deletion include/net/addrconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ extern int addrconf_set_dstaddr(struct net *net,

extern int ipv6_chk_addr(struct net *net,
const struct in6_addr *addr,
struct net_device *dev,
const struct net_device *dev,
int strict);

#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
Expand Down
6 changes: 4 additions & 2 deletions net/ipv4/netfilter/ipt_ULOG.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,10 @@ static void ipt_ulog_packet(struct net *net,
put_unaligned(tv.tv_usec, &pm->timestamp_usec);
put_unaligned(skb->mark, &pm->mark);
pm->hook = hooknum;
if (prefix != NULL)
strncpy(pm->prefix, prefix, sizeof(pm->prefix));
if (prefix != NULL) {
strncpy(pm->prefix, prefix, sizeof(pm->prefix) - 1);
pm->prefix[sizeof(pm->prefix) - 1] = '\0';
}
else if (loginfo->prefix[0] != '\0')
strncpy(pm->prefix, loginfo->prefix, sizeof(pm->prefix));
else
Expand Down
2 changes: 1 addition & 1 deletion net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1487,7 +1487,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
}

int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
struct net_device *dev, int strict)
const struct net_device *dev, int strict)
{
struct inet6_ifaddr *ifp;
unsigned int hash = inet6_addr_hash(addr);
Expand Down
7 changes: 7 additions & 0 deletions net/ipv6/netfilter.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
#include <linux/export.h>
#include <net/addrconf.h>
#include <net/dst.h>
#include <net/ipv6.h>
#include <net/ip6_route.h>
Expand Down Expand Up @@ -186,6 +187,10 @@ static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook,
return csum;
};

static const struct nf_ipv6_ops ipv6ops = {
.chk_addr = ipv6_chk_addr,
};

static const struct nf_afinfo nf_ip6_afinfo = {
.family = AF_INET6,
.checksum = nf_ip6_checksum,
Expand All @@ -198,6 +203,7 @@ static const struct nf_afinfo nf_ip6_afinfo = {

int __init ipv6_netfilter_init(void)
{
RCU_INIT_POINTER(nf_ipv6_ops, &ipv6ops);
return nf_register_afinfo(&nf_ip6_afinfo);
}

Expand All @@ -206,5 +212,6 @@ int __init ipv6_netfilter_init(void)
*/
void ipv6_netfilter_fini(void)
{
RCU_INIT_POINTER(nf_ipv6_ops, NULL);
nf_unregister_afinfo(&nf_ip6_afinfo);
}
2 changes: 2 additions & 0 deletions net/netfilter/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ static DEFINE_MUTEX(afinfo_mutex);

const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO] __read_mostly;
EXPORT_SYMBOL(nf_afinfo);
const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly;
EXPORT_SYMBOL_GPL(nf_ipv6_ops);

int nf_register_afinfo(const struct nf_afinfo *afinfo)
{
Expand Down
35 changes: 35 additions & 0 deletions net/netfilter/ipvs/ip_vs_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,32 @@ static inline int is_tcp_reset(const struct sk_buff *skb, int nh_len)
return th->rst;
}

static inline bool is_new_conn(const struct sk_buff *skb,
struct ip_vs_iphdr *iph)
{
switch (iph->protocol) {
case IPPROTO_TCP: {
struct tcphdr _tcph, *th;

th = skb_header_pointer(skb, iph->len, sizeof(_tcph), &_tcph);
if (th == NULL)
return false;
return th->syn;
}
case IPPROTO_SCTP: {
sctp_chunkhdr_t *sch, schunk;

sch = skb_header_pointer(skb, iph->len + sizeof(sctp_sctphdr_t),
sizeof(schunk), &schunk);
if (sch == NULL)
return false;
return sch->type == SCTP_CID_INIT;
}
default:
return false;
}
}

/* Handle response packets: rewrite addresses and send away...
*/
static unsigned int
Expand Down Expand Up @@ -1612,6 +1638,15 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af)
* Check if the packet belongs to an existing connection entry
*/
cp = pp->conn_in_get(af, skb, &iph, 0);

if (unlikely(sysctl_expire_nodest_conn(ipvs)) && cp && cp->dest &&
unlikely(!atomic_read(&cp->dest->weight)) && !iph.fragoffs &&
is_new_conn(skb, &iph)) {
ip_vs_conn_expire_now(cp);
__ip_vs_conn_put(cp);
cp = NULL;
}

if (unlikely(!cp) && !iph.fragoffs) {
/* No (second) fragments need to enter here, as nf_defrag_ipv6
* replayed fragment zero will already have created the cp
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/ipvs/ip_vs_sh.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ struct ip_vs_sh_bucket {
#define IP_VS_SH_TAB_MASK (IP_VS_SH_TAB_SIZE - 1)

struct ip_vs_sh_state {
struct ip_vs_sh_bucket buckets[IP_VS_SH_TAB_SIZE];
struct rcu_head rcu_head;
struct ip_vs_sh_bucket buckets[IP_VS_SH_TAB_SIZE];
};

/*
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/xt_LOG.c
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ static void dump_ipv6_packet(struct sbuff *m,
dump_sk_uid_gid(m, skb->sk);

/* Max length: 16 "MARK=0xFFFFFFFF " */
if (!recurse && skb->mark)
if (recurse && skb->mark)
sb_add(m, "MARK=0x%x ", skb->mark);
}

Expand Down
27 changes: 16 additions & 11 deletions net/netfilter/xt_addrtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <net/ip6_fib.h>
#endif

#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/xt_addrtype.h>
#include <linux/netfilter/x_tables.h>

Expand All @@ -33,12 +34,12 @@ MODULE_ALIAS("ip6t_addrtype");

#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
static u32 match_lookup_rt6(struct net *net, const struct net_device *dev,
const struct in6_addr *addr)
const struct in6_addr *addr, u16 mask)
{
const struct nf_afinfo *afinfo;
struct flowi6 flow;
struct rt6_info *rt;
u32 ret;
u32 ret = 0;
int route_err;

memset(&flow, 0, sizeof(flow));
Expand All @@ -49,28 +50,32 @@ static u32 match_lookup_rt6(struct net *net, const struct net_device *dev,
rcu_read_lock();

afinfo = nf_get_afinfo(NFPROTO_IPV6);
if (afinfo != NULL)
if (afinfo != NULL) {
const struct nf_ipv6_ops *v6ops;

if (dev && (mask & XT_ADDRTYPE_LOCAL)) {
v6ops = nf_get_ipv6_ops();
if (v6ops && v6ops->chk_addr(net, addr, dev, true))
ret = XT_ADDRTYPE_LOCAL;
}
route_err = afinfo->route(net, (struct dst_entry **)&rt,
flowi6_to_flowi(&flow), !!dev);
else
flowi6_to_flowi(&flow), false);
} else {
route_err = 1;

}
rcu_read_unlock();

if (route_err)
return XT_ADDRTYPE_UNREACHABLE;

if (rt->rt6i_flags & RTF_REJECT)
ret = XT_ADDRTYPE_UNREACHABLE;
else
ret = 0;

if (rt->rt6i_flags & RTF_LOCAL)
if (dev == NULL && rt->rt6i_flags & RTF_LOCAL)
ret |= XT_ADDRTYPE_LOCAL;
if (rt->rt6i_flags & RTF_ANYCAST)
ret |= XT_ADDRTYPE_ANYCAST;


dst_release(&rt->dst);
return ret;
}
Expand All @@ -90,7 +95,7 @@ static bool match_type6(struct net *net, const struct net_device *dev,

if ((XT_ADDRTYPE_LOCAL | XT_ADDRTYPE_ANYCAST |
XT_ADDRTYPE_UNREACHABLE) & mask)
return !!(mask & match_lookup_rt6(net, dev, addr));
return !!(mask & match_lookup_rt6(net, dev, addr, mask));
return true;
}

Expand Down

0 comments on commit 73ce00d

Please sign in to comment.