Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ae473516 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'master' of git://1984.lsi.us.es/nf-next



Pablo Neira Ayuso says:

====================
This patchset contains updates for your net-next tree, they are:

* Mostly fixes for the recently pushed IPv6 NAT support:

- Fix crash while removing nf_nat modules from Patrick McHardy.
- Fix unbalanced rcu_read_unlock from Ulrich Weber.
- Merge NETMAP and REDIRECT into one single xt_target module, from
  Jan Engelhardt.
- Fix Kconfig for IPv6 NAT, which allows inconsistent configurations,
  from myself.

* Updates for ipset, all of the from Jozsef Kadlecsik:

- Add the new "nomatch" option to obtain reverse set matching.
- Support for /0 CIDR in hash:net,iface set type.
- One non-critical fix for a rare crash due to pass really
  wrong configuration parameters.
- Coding style cleanups.
- Sparse fixes.
- Add set revision supported via modinfo.i

* One extension for the xt_time match, to support matching during
  the transition between two days with one single rule, from
  Florian Westphal.

* Fix maximum packet length supported by nfnetlink_queue and add
  NFQA_CAP_LEN attribute, from myself.

You can notice that this batch contains a couple of fixes that may
go to 3.6-rc but I don't consider them critical to push them:

* The ipset fix for the /0 cidr case, which is triggered with one
  inconsistent command line invocation of ipset.

* The nfnetlink_queue maximum packet length supported since it requires
  the new NFQA_CAP_LEN attribute to provide a full workaround for the
  described problem.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2ddc7fe1 6ee584be
Loading
Loading
Loading
Loading
+13 −2
Original line number Original line Diff line number Diff line
@@ -190,6 +190,7 @@ enum ip_set_dim {
	 * If changed, new revision of iptables match/target is required.
	 * If changed, new revision of iptables match/target is required.
	 */
	 */
	IPSET_DIM_MAX = 6,
	IPSET_DIM_MAX = 6,
	IPSET_BIT_RETURN_NOMATCH = 7,
};
};


/* Option flags for kernel operations */
/* Option flags for kernel operations */
@@ -198,6 +199,7 @@ enum ip_set_kopt {
	IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
	IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
	IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
	IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
	IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
	IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
	IPSET_RETURN_NOMATCH = (1 << IPSET_BIT_RETURN_NOMATCH),
};
};


#ifdef __KERNEL__
#ifdef __KERNEL__
@@ -206,9 +208,15 @@ enum ip_set_kopt {
#include <linux/netlink.h>
#include <linux/netlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/stringify.h>
#include <linux/vmalloc.h>
#include <linux/vmalloc.h>
#include <net/netlink.h>
#include <net/netlink.h>


#define _IP_SET_MODULE_DESC(a, b, c)		\
	MODULE_DESCRIPTION(a " type of IP sets, revisions " b "-" c)
#define IP_SET_MODULE_DESC(a, b, c)		\
	_IP_SET_MODULE_DESC(a, __stringify(b), __stringify(c))

/* Set features */
/* Set features */
enum ip_set_feature {
enum ip_set_feature {
	IPSET_TYPE_IP_FLAG = 0,
	IPSET_TYPE_IP_FLAG = 0,
@@ -223,6 +231,8 @@ enum ip_set_feature {
	IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
	IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
	IPSET_TYPE_IFACE_FLAG = 5,
	IPSET_TYPE_IFACE_FLAG = 5,
	IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
	IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
	IPSET_TYPE_NOMATCH_FLAG = 6,
	IPSET_TYPE_NOMATCH = (1 << IPSET_TYPE_NOMATCH_FLAG),
	/* Strictly speaking not a feature, but a flag for dumping:
	/* Strictly speaking not a feature, but a flag for dumping:
	 * this settype must be dumped last */
	 * this settype must be dumped last */
	IPSET_DUMP_LAST_FLAG = 7,
	IPSET_DUMP_LAST_FLAG = 7,
@@ -424,7 +434,8 @@ static inline int nla_put_ipaddr4(struct sk_buff *skb, int type, __be32 ipaddr)
	return ret;
	return ret;
}
}


static inline int nla_put_ipaddr6(struct sk_buff *skb, int type, const struct in6_addr *ipaddrptr)
static inline int nla_put_ipaddr6(struct sk_buff *skb, int type,
				  const struct in6_addr *ipaddrptr)
{
{
	struct nlattr *__nested = ipset_nest_start(skb, type);
	struct nlattr *__nested = ipset_nest_start(skb, type);
	int ret;
	int ret;
+56 −50
Original line number Original line Diff line number Diff line
@@ -137,50 +137,59 @@ htable_bits(u32 hashsize)
#endif
#endif


#define SET_HOST_MASK(family)	(family == AF_INET ? 32 : 128)
#define SET_HOST_MASK(family)	(family == AF_INET ? 32 : 128)
#ifdef IP_SET_HASH_WITH_MULTI
#define NETS_LENGTH(family)	(SET_HOST_MASK(family) + 1)
#else
#define NETS_LENGTH(family)	SET_HOST_MASK(family)
#endif


/* Network cidr size book keeping when the hash stores different
/* Network cidr size book keeping when the hash stores different
 * sized networks */
 * sized networks */
static void
static void
add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
add_cidr(struct ip_set_hash *h, u8 cidr, u8 nets_length)
{
{
	u8 i;
	int i, j;

	++h->nets[cidr-1].nets;

	pr_debug("add_cidr added %u: %u\n", cidr, h->nets[cidr-1].nets);


	if (h->nets[cidr-1].nets > 1)
		return;

	/* New cidr size */
	for (i = 0; i < host_mask && h->nets[i].cidr; i++) {
	/* Add in increasing prefix order, so larger cidr first */
	/* Add in increasing prefix order, so larger cidr first */
		if (h->nets[i].cidr < cidr)
	for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
			swap(h->nets[i].cidr, cidr);
		if (j != -1)
			continue;
		else if (h->nets[i].cidr < cidr)
			j = i;
		else if (h->nets[i].cidr == cidr) {
			h->nets[i].nets++;
			return;
		}
	}
	if (j != -1) {
		for (; i > j; i--) {
			h->nets[i].cidr = h->nets[i - 1].cidr;
			h->nets[i].nets = h->nets[i - 1].nets;
		}
	}
	}
	if (i < host_mask)
	h->nets[i].cidr = cidr;
	h->nets[i].cidr = cidr;
	h->nets[i].nets = 1;
}
}


static void
static void
del_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
del_cidr(struct ip_set_hash *h, u8 cidr, u8 nets_length)
{
{
	u8 i;
	u8 i, j;

	--h->nets[cidr-1].nets;


	pr_debug("del_cidr deleted %u: %u\n", cidr, h->nets[cidr-1].nets);
	for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
		;
	h->nets[i].nets--;


	if (h->nets[cidr-1].nets != 0)
	if (h->nets[i].nets != 0)
		return;
		return;


	/* All entries with this cidr size deleted, so cleanup h->cidr[] */
	for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
	for (i = 0; i < host_mask - 1 && h->nets[i].cidr; i++) {
		h->nets[j].cidr = h->nets[j + 1].cidr;
		if (h->nets[i].cidr == cidr)
		h->nets[j].nets = h->nets[j + 1].nets;
			h->nets[i].cidr = cidr = h->nets[i+1].cidr;
	}
	}
	h->nets[i - 1].cidr = 0;
}
}
#else
#define NETS_LENGTH(family)		0
#endif
#endif


/* Destroy the hashtable part of the set */
/* Destroy the hashtable part of the set */
@@ -202,14 +211,14 @@ ahash_destroy(struct htable *t)


/* Calculate the actual memory size of the set data */
/* Calculate the actual memory size of the set data */
static size_t
static size_t
ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 host_mask)
ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 nets_length)
{
{
	u32 i;
	u32 i;
	struct htable *t = h->table;
	struct htable *t = h->table;
	size_t memsize = sizeof(*h)
	size_t memsize = sizeof(*h)
			 + sizeof(*t)
			 + sizeof(*t)
#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
			 + sizeof(struct ip_set_hash_nets) * host_mask
			 + sizeof(struct ip_set_hash_nets) * nets_length
#endif
#endif
			 + jhash_size(t->htable_bits) * sizeof(struct hbucket);
			 + jhash_size(t->htable_bits) * sizeof(struct hbucket);


@@ -238,7 +247,7 @@ ip_set_hash_flush(struct ip_set *set)
	}
	}
#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
	memset(h->nets, 0, sizeof(struct ip_set_hash_nets)
	memset(h->nets, 0, sizeof(struct ip_set_hash_nets)
			   * SET_HOST_MASK(set->family));
			   * NETS_LENGTH(set->family));
#endif
#endif
	h->elements = 0;
	h->elements = 0;
}
}
@@ -271,9 +280,6 @@ ip_set_hash_destroy(struct ip_set *set)
(jhash2((u32 *)(data), HKEY_DATALEN/sizeof(u32), initval)	\
(jhash2((u32 *)(data), HKEY_DATALEN/sizeof(u32), initval)	\
	& jhash_mask(htable_bits))
	& jhash_mask(htable_bits))


#define CONCAT(a, b, c)		a##b##c
#define TOKEN(a, b, c)		CONCAT(a, b, c)

/* Type/family dependent function prototypes */
/* Type/family dependent function prototypes */


#define type_pf_data_equal	TOKEN(TYPE, PF, _data_equal)
#define type_pf_data_equal	TOKEN(TYPE, PF, _data_equal)
@@ -478,7 +484,7 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
	}
	}


#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
	add_cidr(h, CIDR(d->cidr), HOST_MASK);
	add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
#endif
	h->elements++;
	h->elements++;
out:
out:
@@ -513,7 +519,7 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
		n->pos--;
		n->pos--;
		h->elements--;
		h->elements--;
#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
		del_cidr(h, CIDR(d->cidr), HOST_MASK);
		del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
#endif
		if (n->pos + AHASH_INIT_SIZE < n->size) {
		if (n->pos + AHASH_INIT_SIZE < n->size) {
			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
@@ -546,10 +552,10 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
	const struct type_pf_elem *data;
	const struct type_pf_elem *data;
	int i, j = 0;
	int i, j = 0;
	u32 key, multi = 0;
	u32 key, multi = 0;
	u8 host_mask = SET_HOST_MASK(set->family);
	u8 nets_length = NETS_LENGTH(set->family);


	pr_debug("test by nets\n");
	pr_debug("test by nets\n");
	for (; j < host_mask && h->nets[j].cidr && !multi; j++) {
	for (; j < nets_length && h->nets[j].nets && !multi; j++) {
		type_pf_data_netmask(d, h->nets[j].cidr);
		type_pf_data_netmask(d, h->nets[j].cidr);
		key = HKEY(d, h->initval, t->htable_bits);
		key = HKEY(d, h->initval, t->htable_bits);
		n = hbucket(t, key);
		n = hbucket(t, key);
@@ -604,7 +610,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb)
	memsize = ahash_memsize(h, with_timeout(h->timeout)
	memsize = ahash_memsize(h, with_timeout(h->timeout)
					? sizeof(struct type_pf_telem)
					? sizeof(struct type_pf_telem)
					: sizeof(struct type_pf_elem),
					: sizeof(struct type_pf_elem),
				set->family == AF_INET ? 32 : 128);
				NETS_LENGTH(set->family));
	read_unlock_bh(&set->lock);
	read_unlock_bh(&set->lock);


	nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
	nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
@@ -783,7 +789,7 @@ type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value,


/* Delete expired elements from the hashtable */
/* Delete expired elements from the hashtable */
static void
static void
type_pf_expire(struct ip_set_hash *h)
type_pf_expire(struct ip_set_hash *h, u8 nets_length)
{
{
	struct htable *t = h->table;
	struct htable *t = h->table;
	struct hbucket *n;
	struct hbucket *n;
@@ -798,7 +804,7 @@ type_pf_expire(struct ip_set_hash *h)
			if (type_pf_data_expired(data)) {
			if (type_pf_data_expired(data)) {
				pr_debug("expired %u/%u\n", i, j);
				pr_debug("expired %u/%u\n", i, j);
#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
				del_cidr(h, CIDR(data->cidr), HOST_MASK);
				del_cidr(h, CIDR(data->cidr), nets_length);
#endif
#endif
				if (j != n->pos - 1)
				if (j != n->pos - 1)
					/* Not last one */
					/* Not last one */
@@ -839,7 +845,7 @@ type_pf_tresize(struct ip_set *set, bool retried)
	if (!retried) {
	if (!retried) {
		i = h->elements;
		i = h->elements;
		write_lock_bh(&set->lock);
		write_lock_bh(&set->lock);
		type_pf_expire(set->data);
		type_pf_expire(set->data, NETS_LENGTH(set->family));
		write_unlock_bh(&set->lock);
		write_unlock_bh(&set->lock);
		if (h->elements <  i)
		if (h->elements <  i)
			return 0;
			return 0;
@@ -904,7 +910,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)


	if (h->elements >= h->maxelem)
	if (h->elements >= h->maxelem)
		/* FIXME: when set is full, we slow down here */
		/* FIXME: when set is full, we slow down here */
		type_pf_expire(h);
		type_pf_expire(h, NETS_LENGTH(set->family));
	if (h->elements >= h->maxelem) {
	if (h->elements >= h->maxelem) {
		if (net_ratelimit())
		if (net_ratelimit())
			pr_warning("Set %s is full, maxelem %u reached\n",
			pr_warning("Set %s is full, maxelem %u reached\n",
@@ -933,8 +939,8 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
	if (j != AHASH_MAX(h) + 1) {
	if (j != AHASH_MAX(h) + 1) {
		data = ahash_tdata(n, j);
		data = ahash_tdata(n, j);
#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
		del_cidr(h, CIDR(data->cidr), HOST_MASK);
		del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
		add_cidr(h, CIDR(d->cidr), HOST_MASK);
		add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
#endif
		type_pf_data_copy(data, d);
		type_pf_data_copy(data, d);
		type_pf_data_timeout_set(data, timeout);
		type_pf_data_timeout_set(data, timeout);
@@ -952,7 +958,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
	}
	}


#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
	add_cidr(h, CIDR(d->cidr), HOST_MASK);
	add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
#endif
	h->elements++;
	h->elements++;
out:
out:
@@ -986,7 +992,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
		n->pos--;
		n->pos--;
		h->elements--;
		h->elements--;
#ifdef IP_SET_HASH_WITH_NETS
#ifdef IP_SET_HASH_WITH_NETS
		del_cidr(h, CIDR(d->cidr), HOST_MASK);
		del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
#endif
#endif
		if (n->pos + AHASH_INIT_SIZE < n->size) {
		if (n->pos + AHASH_INIT_SIZE < n->size) {
			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
			void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
@@ -1016,9 +1022,9 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
	struct hbucket *n;
	struct hbucket *n;
	int i, j = 0;
	int i, j = 0;
	u32 key, multi = 0;
	u32 key, multi = 0;
	u8 host_mask = SET_HOST_MASK(set->family);
	u8 nets_length = NETS_LENGTH(set->family);


	for (; j < host_mask && h->nets[j].cidr && !multi; j++) {
	for (; j < nets_length && h->nets[j].nets && !multi; j++) {
		type_pf_data_netmask(d, h->nets[j].cidr);
		type_pf_data_netmask(d, h->nets[j].cidr);
		key = HKEY(d, h->initval, t->htable_bits);
		key = HKEY(d, h->initval, t->htable_bits);
		n = hbucket(t, key);
		n = hbucket(t, key);
@@ -1147,7 +1153,7 @@ type_pf_gc(unsigned long ul_set)


	pr_debug("called\n");
	pr_debug("called\n");
	write_lock_bh(&set->lock);
	write_lock_bh(&set->lock);
	type_pf_expire(h);
	type_pf_expire(h, NETS_LENGTH(set->family));
	write_unlock_bh(&set->lock);
	write_unlock_bh(&set->lock);


	h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
	h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
+5 −1
Original line number Original line Diff line number Diff line
@@ -18,13 +18,17 @@ enum nf_ct_ftp_type {


#define FTP_PORT	21
#define FTP_PORT	21


#define NF_CT_FTP_SEQ_PICKUP	(1 << 0)

#define NUM_SEQ_TO_REMEMBER 2
#define NUM_SEQ_TO_REMEMBER 2
/* This structure exists only once per master */
/* This structure exists only once per master */
struct nf_ct_ftp_master {
struct nf_ct_ftp_master {
	/* Valid seq positions for cmd matching after newline */
	/* Valid seq positions for cmd matching after newline */
	u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
	u_int32_t seq_aft_nl[IP_CT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
	/* 0 means seq_match_aft_nl not set */
	/* 0 means seq_match_aft_nl not set */
	int seq_aft_nl_num[IP_CT_DIR_MAX];
	u_int16_t seq_aft_nl_num[IP_CT_DIR_MAX];
	/* pickup sequence tracking, useful for conntrackd */
	u_int16_t flags[IP_CT_DIR_MAX];
};
};


struct nf_conntrack_expect;
struct nf_conntrack_expect;
+1 −0
Original line number Original line Diff line number Diff line
@@ -44,6 +44,7 @@ enum nfqnl_attr_type {
	NFQA_PAYLOAD,			/* opaque data payload */
	NFQA_PAYLOAD,			/* opaque data payload */
	NFQA_CT,			/* nf_conntrack_netlink.h */
	NFQA_CT,			/* nf_conntrack_netlink.h */
	NFQA_CT_INFO,			/* enum ip_conntrack_info */
	NFQA_CT_INFO,			/* enum ip_conntrack_info */
	NFQA_CAP_LEN,			/* __u32 length of captured packet */


	__NFQA_MAX
	__NFQA_MAX
};
};
+5 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,9 @@ enum {
	/* Match against local time (instead of UTC) */
	/* Match against local time (instead of UTC) */
	XT_TIME_LOCAL_TZ = 1 << 0,
	XT_TIME_LOCAL_TZ = 1 << 0,


	/* treat timestart > timestop (e.g. 23:00-01:00) as single period */
	XT_TIME_CONTIGUOUS = 1 << 1,

	/* Shortcuts */
	/* Shortcuts */
	XT_TIME_ALL_MONTHDAYS = 0xFFFFFFFE,
	XT_TIME_ALL_MONTHDAYS = 0xFFFFFFFE,
	XT_TIME_ALL_WEEKDAYS  = 0xFE,
	XT_TIME_ALL_WEEKDAYS  = 0xFE,
@@ -24,4 +27,6 @@ enum {
	XT_TIME_MAX_DAYTIME   = 24 * 60 * 60 - 1,
	XT_TIME_MAX_DAYTIME   = 24 * 60 * 60 - 1,
};
};


#define XT_TIME_ALL_FLAGS (XT_TIME_LOCAL_TZ|XT_TIME_CONTIGUOUS)

#endif /* _XT_TIME_H */
#endif /* _XT_TIME_H */
Loading