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

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
...@@ -190,6 +190,7 @@ enum ip_set_dim { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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,
...@@ -249,7 +259,7 @@ struct ip_set_type_variant { ...@@ -249,7 +259,7 @@ struct ip_set_type_variant {
* returns negative error code, * returns negative error code,
* zero for no match/success to add/delete * zero for no match/success to add/delete
* positive for matching element */ * positive for matching element */
int (*kadt)(struct ip_set *set, const struct sk_buff * skb, int (*kadt)(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt); enum ipset_adt adt, const struct ip_set_adt_opt *opt);
...@@ -424,7 +434,8 @@ static inline int nla_put_ipaddr4(struct sk_buff *skb, int type, __be32 ipaddr) ...@@ -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;
......
...@@ -137,50 +137,59 @@ htable_bits(u32 hashsize) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
...@@ -690,7 +696,7 @@ type_pf_list(const struct ip_set *set, ...@@ -690,7 +696,7 @@ type_pf_list(const struct ip_set *set,
} }
static int static int
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb, type_pf_kadt(struct ip_set *set, const struct sk_buff *skb,
const struct xt_action_param *par, const struct xt_action_param *par,
enum ipset_adt adt, const struct ip_set_adt_opt *opt); enum ipset_adt adt, const struct ip_set_adt_opt *opt);
static int static int
...@@ -783,7 +789,7 @@ type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -18,13 +18,17 @@ enum nf_ct_ftp_type { ...@@ -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;
......
...@@ -44,6 +44,7 @@ enum nfqnl_attr_type { ...@@ -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
}; };
......
...@@ -17,6 +17,9 @@ enum { ...@@ -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 { ...@@ -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 */
...@@ -172,23 +172,20 @@ config IP_NF_TARGET_MASQUERADE ...@@ -172,23 +172,20 @@ config IP_NF_TARGET_MASQUERADE
config IP_NF_TARGET_NETMAP config IP_NF_TARGET_NETMAP
tristate "NETMAP target support" tristate "NETMAP target support"
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
help select NETFILTER_XT_TARGET_NETMAP
NETMAP is an implementation of static 1:1 NAT mapping of network ---help---
addresses. It maps the network address part, while keeping the host This is a backwards-compat option for the user's convenience
address part intact. (e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_TARGET_NETMAP.
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_TARGET_REDIRECT config IP_NF_TARGET_REDIRECT
tristate "REDIRECT target support" tristate "REDIRECT target support"
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
help select NETFILTER_XT_TARGET_REDIRECT
REDIRECT is a special case of NAT: all incoming connections are ---help---
mapped onto the incoming interface's address, causing the packets to This is a backwards-compat option for the user's convenience
come to the local machine instead of passing through. This is (e.g. when running oldconfig). It selects
useful for transparent proxies. CONFIG_NETFILTER_XT_TARGET_REDIRECT.
To compile it as a module, choose M here. If unsure, say N.
endif endif
......
...@@ -45,8 +45,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o ...@@ -45,8 +45,6 @@ obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
......
...@@ -25,18 +25,6 @@ config NF_CONNTRACK_IPV6 ...@@ -25,18 +25,6 @@ config NF_CONNTRACK_IPV6
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config NF_NAT_IPV6
tristate "IPv6 NAT"
depends on NF_CONNTRACK_IPV6
depends on NETFILTER_ADVANCED
select NF_NAT
help
The IPv6 NAT option allows masquerading, port forwarding and other
forms of full Network Address Port Translation. It is controlled by
the `nat' table in ip6tables, see the man page for ip6tables(8).
To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_IPTABLES config IP6_NF_IPTABLES
tristate "IP6 tables support (required for filtering)" tristate "IP6 tables support (required for filtering)"
depends on INET && IPV6 depends on INET && IPV6
...@@ -144,48 +132,6 @@ config IP6_NF_TARGET_HL ...@@ -144,48 +132,6 @@ config IP6_NF_TARGET_HL
(e.g. when running oldconfig). It selects (e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_TARGET_HL. CONFIG_NETFILTER_XT_TARGET_HL.
config IP6_NF_TARGET_MASQUERADE
tristate "MASQUERADE target support"
depends on NF_NAT_IPV6
help
Masquerading is a special case of NAT: all outgoing connections are
changed to seem to come from a particular interface's address, and
if the interface goes down, those connections are lost. This is
only useful for dialup accounts with dynamic IP address (ie. your IP
address will be different on next dialup).
To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_TARGET_NETMAP
tristate "NETMAP target support"
depends on NF_NAT_IPV6
help
NETMAP is an implementation of static 1:1 NAT mapping of network
addresses. It maps the network address part, while keeping the host
address part intact.
To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_TARGET_REDIRECT
tristate "REDIRECT target support"
depends on NF_NAT_IPV6
help
REDIRECT is a special case of NAT: all incoming connections are
mapped onto the incoming interface's address, causing the packets to
come to the local machine instead of passing through. This is
useful for transparent proxies.
To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_TARGET_NPT
tristate "NPT (Network Prefix translation) target support"
depends on NETFILTER_ADVANCED
help
This option adds the `SNPT' and `DNPT' target, which perform
stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296.
To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_FILTER config IP6_NF_FILTER
tristate "Packet filtering" tristate "Packet filtering"
default m if NETFILTER_ADVANCED=n default m if NETFILTER_ADVANCED=n
...@@ -238,6 +184,41 @@ config IP6_NF_SECURITY ...@@ -238,6 +184,41 @@ config IP6_NF_SECURITY
If unsure, say N. If unsure, say N.
config NF_NAT_IPV6
tristate "IPv6 NAT"
depends on NF_CONNTRACK_IPV6
depends on NETFILTER_ADVANCED
select NF_NAT
help
The IPv6 NAT option allows masquerading, port forwarding and other
forms of full Network Address Port Translation. It is controlled by
the `nat' table in ip6tables, see the man page for ip6tables(8).
To compile it as a module, choose M here. If unsure, say N.
if NF_NAT_IPV6
config IP6_NF_TARGET_MASQUERADE
tristate "MASQUERADE target support"
help
Masquerading is a special case of NAT: all outgoing connections are
changed to seem to come from a particular interface's address, and
if the interface goes down, those connections are lost. This is
only useful for dialup accounts with dynamic IP address (ie. your IP
address will be different on next dialup).
To compile it as a module, choose M here. If unsure, say N.
config IP6_NF_TARGET_NPT
tristate "NPT (Network Prefix translation) target support"
help
This option adds the `SNPT' and `DNPT' target, which perform
stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296.
To compile it as a module, choose M here. If unsure, say N.
endif # NF_NAT_IPV6
endif # IP6_NF_IPTABLES endif # IP6_NF_IPTABLES
endmenu endmenu
......
...@@ -35,7 +35,5 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o ...@@ -35,7 +35,5 @@ obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
# targets # targets
obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
obj-$(CONFIG_IP6_NF_TARGET_NETMAP) += ip6t_NETMAP.o
obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o obj-$(CONFIG_IP6_NF_TARGET_NPT) += ip6t_NPT.o
obj-$(CONFIG_IP6_NF_TARGET_REDIRECT) += ip6t_REDIRECT.o
obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o
/*
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Based on Svenning Soerensen's IPv4 NETMAP target. Development of IPv6
* NAT funded by Astaro.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ipv6.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat.h>
static unsigned int
netmap_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct nf_nat_range *range = par->targinfo;
struct nf_nat_range newrange;
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
union nf_inet_addr new_addr, netmask;
unsigned int i;
ct = nf_ct_get(skb, &ctinfo);
for (i = 0; i < ARRAY_SIZE(range->min_addr.ip6); i++)
netmask.ip6[i] = ~(range->min_addr.ip6[i] ^
range->max_addr.ip6[i]);
if (par->hooknum == NF_INET_PRE_ROUTING ||
par->hooknum == NF_INET_LOCAL_OUT)
new_addr.in6 = ipv6_hdr(skb)->daddr;
else
new_addr.in6 = ipv6_hdr(skb)->saddr;
for (i = 0; i < ARRAY_SIZE(new_addr.ip6); i++) {
new_addr.ip6[i] &= ~netmask.ip6[i];
new_addr.ip6[i] |= range->min_addr.ip6[i] &
netmask.ip6[i];
}
newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
newrange.min_addr = new_addr;
newrange.max_addr = new_addr;
newrange.min_proto = range->min_proto;
newrange.max_proto = range->max_proto;
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
}
static int netmap_tg6_checkentry(const struct xt_tgchk_param *par)
{
const struct nf_nat_range *range = par->targinfo;
if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
return -EINVAL;
return 0;
}
static struct xt_target netmap_tg6_reg __read_mostly = {
.name = "NETMAP",
.family = NFPROTO_IPV6,
.target = netmap_tg6,
.targetsize = sizeof(struct nf_nat_range),
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING) |
(1 << NF_INET_LOCAL_OUT) |
(1 << NF_INET_LOCAL_IN),
.checkentry = netmap_tg6_checkentry,
.me = THIS_MODULE,
};
static int __init netmap_tg6_init(void)
{
return xt_register_target(&netmap_tg6_reg);
}
static void netmap_tg6_exit(void)
{
xt_unregister_target(&netmap_tg6_reg);
}
module_init(netmap_tg6_init);
module_exit(netmap_tg6_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of IPv6 subnets");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
/*
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6
* NAT funded by Astaro.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/x_tables.h>
#include <net/addrconf.h>
#include <net/netfilter/nf_nat.h>
static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
static unsigned int
redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct nf_nat_range *range = par->targinfo;
struct nf_nat_range newrange;
struct in6_addr newdst;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
ct = nf_ct_get(skb, &ctinfo);
if (par->hooknum == NF_INET_LOCAL_OUT)
newdst = loopback_addr;
else {
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
bool addr = false;
rcu_read_lock();
idev = __in6_dev_get(skb->dev);
if (idev != NULL) {
list_for_each_entry(ifa, &idev->addr_list, if_list) {
newdst = ifa->addr;
addr = true;
break;
}
}
rcu_read_unlock();
if (!addr)
return NF_DROP;
}
newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
newrange.min_addr.in6 = newdst;
newrange.max_addr.in6 = newdst;
newrange.min_proto = range->min_proto;
newrange.max_proto = range->max_proto;
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
}
static int redirect_tg6_checkentry(const struct xt_tgchk_param *par)
{
const struct nf_nat_range *range = par->targinfo;
if (range->flags & NF_NAT_RANGE_MAP_IPS)
return -EINVAL;
return 0;
}
static struct xt_target redirect_tg6_reg __read_mostly = {
.name = "REDIRECT",
.family = NFPROTO_IPV6,
.checkentry = redirect_tg6_checkentry,
.target = redirect_tg6,
.targetsize = sizeof(struct nf_nat_range),
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT),
.me = THIS_MODULE,
};
static int __init redirect_tg6_init(void)
{
return xt_register_target(&redirect_tg6_reg);
}
static void __exit redirect_tg6_exit(void)
{
xt_unregister_target(&redirect_tg6_reg);
}
module_init(redirect_tg6_init);
module_exit(redirect_tg6_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("Xtables: Connection redirection to localhost");
...@@ -648,6 +648,16 @@ config NETFILTER_XT_TARGET_MARK ...@@ -648,6 +648,16 @@ config NETFILTER_XT_TARGET_MARK
(e.g. when running oldconfig). It selects (e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_MARK (combined mark/MARK module). CONFIG_NETFILTER_XT_MARK (combined mark/MARK module).
config NETFILTER_XT_TARGET_NETMAP
tristate '"NETMAP" target support'
depends on NF_NAT
---help---
NETMAP is an implementation of static 1:1 NAT mapping of network
addresses. It maps the network address part, while keeping the host
address part intact.
To compile it as a module, choose M here. If unsure, say N.
config NETFILTER_XT_TARGET_NFLOG config NETFILTER_XT_TARGET_NFLOG
tristate '"NFLOG" target support' tristate '"NFLOG" target support'
default m if NETFILTER_ADVANCED=n default m if NETFILTER_ADVANCED=n
...@@ -680,6 +690,17 @@ config NETFILTER_XT_TARGET_RATEEST ...@@ -680,6 +690,17 @@ config NETFILTER_XT_TARGET_RATEEST
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config NETFILTER_XT_TARGET_REDIRECT
tristate "REDIRECT target support"
depends on NF_NAT
---help---
REDIRECT is a special case of NAT: all incoming connections are
mapped onto the incoming interface's address, causing the packets to
come to the local machine instead of passing through. This is
useful for transparent proxies.
To compile it as a module, choose M here. If unsure, say N.
config NETFILTER_XT_TARGET_TEE config NETFILTER_XT_TARGET_TEE
tristate '"TEE" - packet cloning to alternate destination' tristate '"TEE" - packet cloning to alternate destination'
depends on NETFILTER_ADVANCED depends on NETFILTER_ADVANCED
......
...@@ -83,9 +83,11 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o ...@@ -83,9 +83,11 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NETMAP) += xt_NETMAP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o
obj-$(CONFIG_NETFILTER_XT_TARGET_REDIRECT) += xt_REDIRECT.o
obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
......
...@@ -27,9 +27,12 @@ ...@@ -27,9 +27,12 @@
#define IP_SET_BITMAP_TIMEOUT #define IP_SET_BITMAP_TIMEOUT
#include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_timeout.h>
#define REVISION_MIN 0
#define REVISION_MAX 0
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("bitmap:ip type of IP sets"); IP_SET_MODULE_DESC("bitmap:ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:ip"); MODULE_ALIAS("ip_set_bitmap:ip");
/* Type structure */ /* Type structure */
...@@ -284,7 +287,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -284,7 +287,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (cidr > 32) if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr); ip_set_mask_from_to(ip, ip_to, cidr);
} else } else
...@@ -454,7 +457,8 @@ static int ...@@ -454,7 +457,8 @@ static int
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
{ {
struct bitmap_ip *map; struct bitmap_ip *map;
u32 first_ip, last_ip, hosts, elements; u32 first_ip, last_ip, hosts;
u64 elements;
u8 netmask = 32; u8 netmask = 32;
int ret; int ret;
...@@ -497,7 +501,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -497,7 +501,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (netmask == 32) { if (netmask == 32) {
hosts = 1; hosts = 1;
elements = last_ip - first_ip + 1; elements = (u64)last_ip - first_ip + 1;
} else { } else {
u8 mask_bits; u8 mask_bits;
u32 mask; u32 mask;
...@@ -515,7 +519,8 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -515,7 +519,8 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
if (elements > IPSET_BITMAP_MAX_RANGE + 1) if (elements > IPSET_BITMAP_MAX_RANGE + 1)
return -IPSET_ERR_BITMAP_RANGE_SIZE; return -IPSET_ERR_BITMAP_RANGE_SIZE;
pr_debug("hosts %u, elements %u\n", hosts, elements); pr_debug("hosts %u, elements %llu\n",
hosts, (unsigned long long)elements);
map = kzalloc(sizeof(*map), GFP_KERNEL); map = kzalloc(sizeof(*map), GFP_KERNEL);
if (!map) if (!map)
...@@ -554,8 +559,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = { ...@@ -554,8 +559,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 0, .revision_max = REVISION_MAX,
.create = bitmap_ip_create, .create = bitmap_ip_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_IP] = { .type = NLA_NESTED },
......
...@@ -26,9 +26,12 @@ ...@@ -26,9 +26,12 @@
#include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_bitmap.h> #include <linux/netfilter/ipset/ip_set_bitmap.h>
#define REVISION_MIN 0
#define REVISION_MAX 0
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("bitmap:ip,mac type of IP sets"); IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:ip,mac"); MODULE_ALIAS("ip_set_bitmap:ip,mac");
enum { enum {
...@@ -557,7 +560,8 @@ static int ...@@ -557,7 +560,8 @@ static int
bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
u32 flags) u32 flags)
{ {
u32 first_ip, last_ip, elements; u32 first_ip, last_ip;
u64 elements;
struct bitmap_ipmac *map; struct bitmap_ipmac *map;
int ret; int ret;
...@@ -588,7 +592,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], ...@@ -588,7 +592,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
} else } else
return -IPSET_ERR_PROTOCOL; return -IPSET_ERR_PROTOCOL;
elements = last_ip - first_ip + 1; elements = (u64)last_ip - first_ip + 1;
if (elements > IPSET_BITMAP_MAX_RANGE + 1) if (elements > IPSET_BITMAP_MAX_RANGE + 1)
return -IPSET_ERR_BITMAP_RANGE_SIZE; return -IPSET_ERR_BITMAP_RANGE_SIZE;
...@@ -629,8 +633,8 @@ static struct ip_set_type bitmap_ipmac_type = { ...@@ -629,8 +633,8 @@ static struct ip_set_type bitmap_ipmac_type = {
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC, .features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 0, .revision_max = REVISION_MAX,
.create = bitmap_ipmac_create, .create = bitmap_ipmac_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED }, [IPSET_ATTR_IP] = { .type = NLA_NESTED },
......
...@@ -22,9 +22,12 @@ ...@@ -22,9 +22,12 @@
#define IP_SET_BITMAP_TIMEOUT #define IP_SET_BITMAP_TIMEOUT
#include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_timeout.h>
#define REVISION_MIN 0
#define REVISION_MAX 0
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("bitmap:port type of IP sets"); IP_SET_MODULE_DESC("bitmap:port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_bitmap:port"); MODULE_ALIAS("ip_set_bitmap:port");
/* Type structure */ /* Type structure */
...@@ -487,8 +490,8 @@ static struct ip_set_type bitmap_port_type = { ...@@ -487,8 +490,8 @@ static struct ip_set_type bitmap_port_type = {
.features = IPSET_TYPE_PORT, .features = IPSET_TYPE_PORT,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 0, .revision_max = REVISION_MAX,
.create = bitmap_port_create, .create = bitmap_port_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_PORT] = { .type = NLA_U16 }, [IPSET_ATTR_PORT] = { .type = NLA_U16 },
......
...@@ -69,7 +69,8 @@ find_set_type(const char *name, u8 family, u8 revision) ...@@ -69,7 +69,8 @@ find_set_type(const char *name, u8 family, u8 revision)
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) && if (STREQ(type->name, name) &&
(type->family == family || type->family == NFPROTO_UNSPEC) && (type->family == family ||
type->family == NFPROTO_UNSPEC) &&
revision >= type->revision_min && revision >= type->revision_min &&
revision <= type->revision_max) revision <= type->revision_max)
return type; return type;
...@@ -149,7 +150,8 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max, ...@@ -149,7 +150,8 @@ __find_set_type_minmax(const char *name, u8 family, u8 *min, u8 *max,
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(type, &ip_set_type_list, list) list_for_each_entry_rcu(type, &ip_set_type_list, list)
if (STREQ(type->name, name) && if (STREQ(type->name, name) &&
(type->family == family || type->family == NFPROTO_UNSPEC)) { (type->family == family ||
type->family == NFPROTO_UNSPEC)) {
found = true; found = true;
if (type->revision_min < *min) if (type->revision_min < *min)
*min = type->revision_min; *min = type->revision_min;
...@@ -368,6 +370,12 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb, ...@@ -368,6 +370,12 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
set->variant->kadt(set, skb, par, IPSET_ADD, opt); set->variant->kadt(set, skb, par, IPSET_ADD, opt);
write_unlock_bh(&set->lock); write_unlock_bh(&set->lock);
ret = 1; ret = 1;
} else {
/* --return-nomatch: invert matched element */
if ((opt->flags & IPSET_RETURN_NOMATCH) &&
(set->type->features & IPSET_TYPE_NOMATCH) &&
(ret > 0 || ret == -ENOTEMPTY))
ret = -ret;
} }
/* Convert error codes to nomatch */ /* Convert error codes to nomatch */
...@@ -721,7 +729,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb, ...@@ -721,7 +729,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
* by the nfnl mutex. Find the first free index in ip_set_list * by the nfnl mutex. Find the first free index in ip_set_list
* and check clashing. * and check clashing.
*/ */
if ((ret = find_free_id(set->name, &index, &clash)) != 0) { ret = find_free_id(set->name, &index, &clash);
if (ret != 0) {
/* If this is the same set and requested, ignore error */ /* If this is the same set and requested, ignore error */
if (ret == -EEXIST && if (ret == -EEXIST &&
(flags & IPSET_FLAG_EXIST) && (flags & IPSET_FLAG_EXIST) &&
......
...@@ -24,9 +24,12 @@ ...@@ -24,9 +24,12 @@
#include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
#define REVISION_MAX 0
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:ip type of IP sets"); IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip"); MODULE_ALIAS("ip_set_hash:ip");
/* Type specific function prefix */ /* Type specific function prefix */
...@@ -114,7 +117,7 @@ hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data) ...@@ -114,7 +117,7 @@ hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
static inline void static inline void
hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d) hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
{ {
h->next.ip = ntohl(d->ip); h->next.ip = d->ip;
} }
static int static int
...@@ -179,7 +182,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -179,7 +182,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (cidr > 32) if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr); ip_set_mask_from_to(ip, ip_to, cidr);
} else } else
...@@ -188,7 +191,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -188,7 +191,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1); hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
if (retried) if (retried)
ip = h->next.ip; ip = ntohl(h->next.ip);
for (; !before(ip_to, ip); ip += hosts) { for (; !before(ip_to, ip); ip += hosts) {
nip = htonl(ip); nip = htonl(ip);
if (nip == 0) if (nip == 0)
...@@ -452,8 +455,8 @@ static struct ip_set_type hash_ip_type __read_mostly = { ...@@ -452,8 +455,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 0, .revision_max = REVISION_MAX,
.create = hash_ip_create, .create = hash_ip_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -25,9 +25,12 @@ ...@@ -25,9 +25,12 @@
#include <linux/netfilter/ipset/ip_set_getport.h> #include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
#define REVISION_MAX 1 /* SCTP and UDPLITE support added */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:ip,port type of IP sets"); IP_SET_MODULE_DESC("hash:ip,port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port"); MODULE_ALIAS("ip_set_hash:ip,port");
/* Type specific function prefix */ /* Type specific function prefix */
...@@ -130,8 +133,8 @@ static inline void ...@@ -130,8 +133,8 @@ static inline void
hash_ipport4_data_next(struct ip_set_hash *h, hash_ipport4_data_next(struct ip_set_hash *h,
const struct hash_ipport4_elem *d) const struct hash_ipport4_elem *d)
{ {
h->next.ip = ntohl(d->ip); h->next.ip = d->ip;
h->next.port = ntohs(d->port); h->next.port = d->port;
} }
static int static int
...@@ -217,7 +220,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -217,7 +220,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (cidr > 32) if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr); ip_set_mask_from_to(ip, ip_to, cidr);
} else } else
...@@ -231,9 +234,10 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -231,9 +234,10 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (retried) if (retried)
ip = h->next.ip; ip = ntohl(h->next.ip);
for (; !before(ip_to, ip); ip++) { for (; !before(ip_to, ip); ip++) {
p = retried && ip == h->next.ip ? h->next.port : port; p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
data.ip = htonl(ip); data.ip = htonl(ip);
data.port = htons(p); data.port = htons(p);
...@@ -349,7 +353,7 @@ static inline void ...@@ -349,7 +353,7 @@ static inline void
hash_ipport6_data_next(struct ip_set_hash *h, hash_ipport6_data_next(struct ip_set_hash *h,
const struct hash_ipport6_elem *d) const struct hash_ipport6_elem *d)
{ {
h->next.port = ntohs(d->port); h->next.port = d->port;
} }
static int static int
...@@ -431,7 +435,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -431,7 +435,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
if (retried) if (retried)
port = h->next.port; port = ntohs(h->next.port);
for (; port <= port_to; port++) { for (; port <= port_to; port++) {
data.port = htons(port); data.port = htons(port);
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -522,8 +526,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = { ...@@ -522,8 +526,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 1, /* SCTP and UDPLITE support added */ .revision_max = REVISION_MAX,
.create = hash_ipport_create, .create = hash_ipport_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -25,9 +25,12 @@ ...@@ -25,9 +25,12 @@
#include <linux/netfilter/ipset/ip_set_getport.h> #include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
#define REVISION_MAX 1 /* SCTP and UDPLITE support added */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:ip,port,ip type of IP sets"); IP_SET_MODULE_DESC("hash:ip,port,ip", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port,ip"); MODULE_ALIAS("ip_set_hash:ip,port,ip");
/* Type specific function prefix */ /* Type specific function prefix */
...@@ -133,8 +136,8 @@ static inline void ...@@ -133,8 +136,8 @@ static inline void
hash_ipportip4_data_next(struct ip_set_hash *h, hash_ipportip4_data_next(struct ip_set_hash *h,
const struct hash_ipportip4_elem *d) const struct hash_ipportip4_elem *d)
{ {
h->next.ip = ntohl(d->ip); h->next.ip = d->ip;
h->next.port = ntohs(d->port); h->next.port = d->port;
} }
static int static int
...@@ -225,7 +228,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -225,7 +228,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (cidr > 32) if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr); ip_set_mask_from_to(ip, ip_to, cidr);
} else } else
...@@ -239,9 +242,10 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -239,9 +242,10 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (retried) if (retried)
ip = h->next.ip; ip = ntohl(h->next.ip);
for (; !before(ip_to, ip); ip++) { for (; !before(ip_to, ip); ip++) {
p = retried && ip == h->next.ip ? h->next.port : port; p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
data.ip = htonl(ip); data.ip = htonl(ip);
data.port = htons(p); data.port = htons(p);
...@@ -362,7 +366,7 @@ static inline void ...@@ -362,7 +366,7 @@ static inline void
hash_ipportip6_data_next(struct ip_set_hash *h, hash_ipportip6_data_next(struct ip_set_hash *h,
const struct hash_ipportip6_elem *d) const struct hash_ipportip6_elem *d)
{ {
h->next.port = ntohs(d->port); h->next.port = d->port;
} }
static int static int
...@@ -449,7 +453,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -449,7 +453,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
if (retried) if (retried)
port = h->next.port; port = ntohs(h->next.port);
for (; port <= port_to; port++) { for (; port <= port_to; port++) {
data.port = htons(port); data.port = htons(port);
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -540,8 +544,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = { ...@@ -540,8 +544,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
.dimension = IPSET_DIM_THREE, .dimension = IPSET_DIM_THREE,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 1, /* SCTP and UDPLITE support added */ .revision_max = REVISION_MAX,
.create = hash_ipportip_create, .create = hash_ipportip_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -25,9 +25,14 @@ ...@@ -25,9 +25,14 @@
#include <linux/netfilter/ipset/ip_set_getport.h> #include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 SCTP and UDPLITE support added */
/* 2 Range as input support for IPv4 added */
#define REVISION_MAX 3 /* nomatch flag support added */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:ip,port,net type of IP sets"); IP_SET_MODULE_DESC("hash:ip,port,net", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:ip,port,net"); MODULE_ALIAS("ip_set_hash:ip,port,net");
/* Type specific function prefix */ /* Type specific function prefix */
...@@ -99,10 +104,10 @@ hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags) ...@@ -99,10 +104,10 @@ hash_ipportnet4_data_flags(struct hash_ipportnet4_elem *dst, u32 flags)
dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
} }
static inline bool static inline int
hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem) hash_ipportnet4_data_match(const struct hash_ipportnet4_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
...@@ -173,9 +178,9 @@ static inline void ...@@ -173,9 +178,9 @@ static inline void
hash_ipportnet4_data_next(struct ip_set_hash *h, hash_ipportnet4_data_next(struct ip_set_hash *h,
const struct hash_ipportnet4_elem *d) const struct hash_ipportnet4_elem *d)
{ {
h->next.ip = ntohl(d->ip); h->next.ip = d->ip;
h->next.port = ntohs(d->port); h->next.port = d->port;
h->next.ip2 = ntohl(d->ip2); h->next.ip2 = d->ip2;
} }
static int static int
...@@ -290,7 +295,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -290,7 +295,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} else if (tb[IPSET_ATTR_CIDR]) { } else if (tb[IPSET_ATTR_CIDR]) {
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (cidr > 32) if (!cidr || cidr > 32)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip_set_mask_from_to(ip, ip_to, cidr); ip_set_mask_from_to(ip, ip_to, cidr);
} }
...@@ -314,14 +319,17 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -314,14 +319,17 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (retried) if (retried)
ip = h->next.ip; ip = ntohl(h->next.ip);
for (; !before(ip_to, ip); ip++) { for (; !before(ip_to, ip); ip++) {
data.ip = htonl(ip); data.ip = htonl(ip);
p = retried && ip == h->next.ip ? h->next.port : port; p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
data.port = htons(p); data.port = htons(p);
ip2 = retried && ip == h->next.ip && p == h->next.port ip2 = retried
? h->next.ip2 : ip2_from; && ip == ntohl(h->next.ip)
&& p == ntohs(h->next.port)
? ntohl(h->next.ip2) : ip2_from;
while (!after(ip2, ip2_to)) { while (!after(ip2, ip2_to)) {
data.ip2 = htonl(ip2); data.ip2 = htonl(ip2);
ip2_last = ip_set_range_to_cidr(ip2, ip2_to, ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
...@@ -403,10 +411,10 @@ hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags) ...@@ -403,10 +411,10 @@ hash_ipportnet6_data_flags(struct hash_ipportnet6_elem *dst, u32 flags)
dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
} }
static inline bool static inline int
hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem) hash_ipportnet6_data_match(const struct hash_ipportnet6_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
...@@ -486,7 +494,7 @@ static inline void ...@@ -486,7 +494,7 @@ static inline void
hash_ipportnet6_data_next(struct ip_set_hash *h, hash_ipportnet6_data_next(struct ip_set_hash *h,
const struct hash_ipportnet6_elem *d) const struct hash_ipportnet6_elem *d)
{ {
h->next.port = ntohs(d->port); h->next.port = d->port;
} }
static int static int
...@@ -598,7 +606,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -598,7 +606,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
if (retried) if (retried)
port = h->next.port; port = ntohs(h->next.port);
for (; port <= port_to; port++) { for (; port <= port_to; port++) {
data.port = htons(port); data.port = htons(port);
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -689,13 +697,12 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -689,13 +697,12 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
static struct ip_set_type hash_ipportnet_type __read_mostly = { static struct ip_set_type hash_ipportnet_type __read_mostly = {
.name = "hash:ip,port,net", .name = "hash:ip,port,net",
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 |
IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_THREE, .dimension = IPSET_DIM_THREE,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
/* 1 SCTP and UDPLITE support added */ .revision_max = REVISION_MAX,
/* 2 Range as input support for IPv4 added */
.revision_max = 3, /* nomatch flag support added */
.create = hash_ipportnet_create, .create = hash_ipportnet_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -23,9 +23,13 @@ ...@@ -23,9 +23,13 @@
#include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 Range as input support for IPv4 added */
#define REVISION_MAX 2 /* nomatch flag support added */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:net type of IP sets"); IP_SET_MODULE_DESC("hash:net", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net"); MODULE_ALIAS("ip_set_hash:net");
/* Type specific function prefix */ /* Type specific function prefix */
...@@ -86,10 +90,10 @@ hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags) ...@@ -86,10 +90,10 @@ hash_net4_data_flags(struct hash_net4_elem *dst, u32 flags)
dst->nomatch = flags & IPSET_FLAG_NOMATCH; dst->nomatch = flags & IPSET_FLAG_NOMATCH;
} }
static inline bool static inline int
hash_net4_data_match(const struct hash_net4_elem *elem) hash_net4_data_match(const struct hash_net4_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
...@@ -152,7 +156,7 @@ static inline void ...@@ -152,7 +156,7 @@ static inline void
hash_net4_data_next(struct ip_set_hash *h, hash_net4_data_next(struct ip_set_hash *h,
const struct hash_net4_elem *d) const struct hash_net4_elem *d)
{ {
h->next.ip = ntohl(d->ip); h->next.ip = d->ip;
} }
static int static int
...@@ -235,7 +239,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -235,7 +239,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
return -IPSET_ERR_HASH_RANGE; return -IPSET_ERR_HASH_RANGE;
} }
if (retried) if (retried)
ip = h->next.ip; ip = ntohl(h->next.ip);
while (!after(ip, ip_to)) { while (!after(ip, ip_to)) {
data.ip = htonl(ip); data.ip = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr); last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
...@@ -307,10 +311,10 @@ hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags) ...@@ -307,10 +311,10 @@ hash_net6_data_flags(struct hash_net6_elem *dst, u32 flags)
dst->nomatch = flags & IPSET_FLAG_NOMATCH; dst->nomatch = flags & IPSET_FLAG_NOMATCH;
} }
static inline bool static inline int
hash_net6_data_match(const struct hash_net6_elem *elem) hash_net6_data_match(const struct hash_net6_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
...@@ -532,12 +536,11 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -532,12 +536,11 @@ hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
static struct ip_set_type hash_net_type __read_mostly = { static struct ip_set_type hash_net_type __read_mostly = {
.name = "hash:net", .name = "hash:net",
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP, .features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
/* = 1 Range as input support for IPv4 added */ .revision_max = REVISION_MAX,
.revision_max = 2, /* nomatch flag support added */
.create = hash_net_create, .create = hash_net_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -24,9 +24,13 @@ ...@@ -24,9 +24,13 @@
#include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 nomatch flag support added */
#define REVISION_MAX 2 /* /0 support added */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:net,iface type of IP sets"); IP_SET_MODULE_DESC("hash:net,iface", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net,iface"); MODULE_ALIAS("ip_set_hash:net,iface");
/* Interface name rbtree */ /* Interface name rbtree */
...@@ -140,7 +144,7 @@ struct hash_netiface4_elem_hashed { ...@@ -140,7 +144,7 @@ struct hash_netiface4_elem_hashed {
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u8 nomatch; u8 nomatch;
u8 padding; u8 elem;
}; };
#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed) #define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
...@@ -151,7 +155,7 @@ struct hash_netiface4_elem { ...@@ -151,7 +155,7 @@ struct hash_netiface4_elem {
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u8 nomatch; u8 nomatch;
u8 padding; u8 elem;
const char *iface; const char *iface;
}; };
...@@ -161,7 +165,7 @@ struct hash_netiface4_telem { ...@@ -161,7 +165,7 @@ struct hash_netiface4_telem {
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u8 nomatch; u8 nomatch;
u8 padding; u8 elem;
const char *iface; const char *iface;
unsigned long timeout; unsigned long timeout;
}; };
...@@ -181,18 +185,14 @@ hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1, ...@@ -181,18 +185,14 @@ hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
static inline bool static inline bool
hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem) hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
{ {
return elem->cidr == 0; return elem->elem == 0;
} }
static inline void static inline void
hash_netiface4_data_copy(struct hash_netiface4_elem *dst, hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
const struct hash_netiface4_elem *src) const struct hash_netiface4_elem *src)
{ {
dst->ip = src->ip; memcpy(dst, src, sizeof(*dst));
dst->cidr = src->cidr;
dst->physdev = src->physdev;
dst->iface = src->iface;
dst->nomatch = src->nomatch;
} }
static inline void static inline void
...@@ -201,10 +201,10 @@ hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags) ...@@ -201,10 +201,10 @@ hash_netiface4_data_flags(struct hash_netiface4_elem *dst, u32 flags)
dst->nomatch = flags & IPSET_FLAG_NOMATCH; dst->nomatch = flags & IPSET_FLAG_NOMATCH;
} }
static inline bool static inline int
hash_netiface4_data_match(const struct hash_netiface4_elem *elem) hash_netiface4_data_match(const struct hash_netiface4_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
...@@ -217,7 +217,7 @@ hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr) ...@@ -217,7 +217,7 @@ hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
static inline void static inline void
hash_netiface4_data_zero_out(struct hash_netiface4_elem *elem) hash_netiface4_data_zero_out(struct hash_netiface4_elem *elem)
{ {
elem->cidr = 0; elem->elem = 0;
} }
static bool static bool
...@@ -277,7 +277,7 @@ static inline void ...@@ -277,7 +277,7 @@ static inline void
hash_netiface4_data_next(struct ip_set_hash *h, hash_netiface4_data_next(struct ip_set_hash *h,
const struct hash_netiface4_elem *d) const struct hash_netiface4_elem *d)
{ {
h->next.ip = ntohl(d->ip); h->next.ip = d->ip;
} }
static int static int
...@@ -288,7 +288,8 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -288,7 +288,8 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem data = { struct hash_netiface4_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
.elem = 1,
}; };
int ret; int ret;
...@@ -339,7 +340,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -339,7 +340,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
{ {
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface4_elem data = { .cidr = HOST_MASK }; struct hash_netiface4_elem data = { .cidr = HOST_MASK, .elem = 1 };
u32 ip = 0, ip_to, last; u32 ip = 0, ip_to, last;
u32 timeout = h->timeout; u32 timeout = h->timeout;
char iface[IFNAMSIZ]; char iface[IFNAMSIZ];
...@@ -360,7 +361,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -360,7 +361,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CIDR]) { if (tb[IPSET_ATTR_CIDR]) {
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr || data.cidr > HOST_MASK) if (data.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
} }
...@@ -389,7 +390,6 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -389,7 +390,6 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH)) if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
flags |= (cadt_flags << 16); flags |= (cadt_flags << 16);
} }
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) { if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
data.ip = htonl(ip & ip_set_hostmask(data.cidr)); data.ip = htonl(ip & ip_set_hostmask(data.cidr));
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -409,7 +409,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -409,7 +409,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (retried) if (retried)
ip = h->next.ip; ip = ntohl(h->next.ip);
while (!after(ip, ip_to)) { while (!after(ip, ip_to)) {
data.ip = htonl(ip); data.ip = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr); last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
...@@ -442,7 +442,7 @@ struct hash_netiface6_elem_hashed { ...@@ -442,7 +442,7 @@ struct hash_netiface6_elem_hashed {
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u8 nomatch; u8 nomatch;
u8 padding; u8 elem;
}; };
#define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed) #define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
...@@ -452,7 +452,7 @@ struct hash_netiface6_elem { ...@@ -452,7 +452,7 @@ struct hash_netiface6_elem {
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u8 nomatch; u8 nomatch;
u8 padding; u8 elem;
const char *iface; const char *iface;
}; };
...@@ -461,7 +461,7 @@ struct hash_netiface6_telem { ...@@ -461,7 +461,7 @@ struct hash_netiface6_telem {
u8 physdev; u8 physdev;
u8 cidr; u8 cidr;
u8 nomatch; u8 nomatch;
u8 padding; u8 elem;
const char *iface; const char *iface;
unsigned long timeout; unsigned long timeout;
}; };
...@@ -481,7 +481,7 @@ hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1, ...@@ -481,7 +481,7 @@ hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
static inline bool static inline bool
hash_netiface6_data_isnull(const struct hash_netiface6_elem *elem) hash_netiface6_data_isnull(const struct hash_netiface6_elem *elem)
{ {
return elem->cidr == 0; return elem->elem == 0;
} }
static inline void static inline void
...@@ -497,16 +497,16 @@ hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags) ...@@ -497,16 +497,16 @@ hash_netiface6_data_flags(struct hash_netiface6_elem *dst, u32 flags)
dst->nomatch = flags & IPSET_FLAG_NOMATCH; dst->nomatch = flags & IPSET_FLAG_NOMATCH;
} }
static inline bool static inline int
hash_netiface6_data_match(const struct hash_netiface6_elem *elem) hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem) hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
{ {
elem->cidr = 0; elem->elem = 0;
} }
static inline void static inline void
...@@ -590,7 +590,8 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb, ...@@ -590,7 +590,8 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface6_elem data = { struct hash_netiface6_elem data = {
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK .cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
.elem = 1,
}; };
int ret; int ret;
...@@ -637,7 +638,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -637,7 +638,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
{ {
struct ip_set_hash *h = set->data; struct ip_set_hash *h = set->data;
ipset_adtfn adtfn = set->variant->adt[adt]; ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netiface6_elem data = { .cidr = HOST_MASK }; struct hash_netiface6_elem data = { .cidr = HOST_MASK, .elem = 1 };
u32 timeout = h->timeout; u32 timeout = h->timeout;
char iface[IFNAMSIZ]; char iface[IFNAMSIZ];
int ret; int ret;
...@@ -659,7 +660,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -659,7 +660,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
if (tb[IPSET_ATTR_CIDR]) if (tb[IPSET_ATTR_CIDR])
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
if (!data.cidr || data.cidr > HOST_MASK) if (data.cidr > HOST_MASK)
return -IPSET_ERR_INVALID_CIDR; return -IPSET_ERR_INVALID_CIDR;
ip6_netmask(&data.ip, data.cidr); ip6_netmask(&data.ip, data.cidr);
...@@ -773,11 +774,12 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -773,11 +774,12 @@ hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
static struct ip_set_type hash_netiface_type __read_mostly = { static struct ip_set_type hash_netiface_type __read_mostly = {
.name = "hash:net,iface", .name = "hash:net,iface",
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_IFACE, .features = IPSET_TYPE_IP | IPSET_TYPE_IFACE |
IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 1, /* nomatch flag support added */ .revision_max = REVISION_MAX,
.create = hash_netiface_create, .create = hash_netiface_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -24,9 +24,14 @@ ...@@ -24,9 +24,14 @@
#include <linux/netfilter/ipset/ip_set_getport.h> #include <linux/netfilter/ipset/ip_set_getport.h>
#include <linux/netfilter/ipset/ip_set_hash.h> #include <linux/netfilter/ipset/ip_set_hash.h>
#define REVISION_MIN 0
/* 1 SCTP and UDPLITE support added */
/* 2 Range as input support for IPv4 added */
#define REVISION_MAX 3 /* nomatch flag support added */
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("hash:net,port type of IP sets"); IP_SET_MODULE_DESC("hash:net,port", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_hash:net,port"); MODULE_ALIAS("ip_set_hash:net,port");
/* Type specific function prefix */ /* Type specific function prefix */
...@@ -99,10 +104,10 @@ hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags) ...@@ -99,10 +104,10 @@ hash_netport4_data_flags(struct hash_netport4_elem *dst, u32 flags)
dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
} }
static inline bool static inline int
hash_netport4_data_match(const struct hash_netport4_elem *elem) hash_netport4_data_match(const struct hash_netport4_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
...@@ -171,8 +176,8 @@ static inline void ...@@ -171,8 +176,8 @@ static inline void
hash_netport4_data_next(struct ip_set_hash *h, hash_netport4_data_next(struct ip_set_hash *h,
const struct hash_netport4_elem *d) const struct hash_netport4_elem *d)
{ {
h->next.ip = ntohl(d->ip); h->next.ip = d->ip;
h->next.port = ntohs(d->port); h->next.port = d->port;
} }
static int static int
...@@ -289,12 +294,13 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -289,12 +294,13 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
} }
if (retried) if (retried)
ip = h->next.ip; ip = ntohl(h->next.ip);
while (!after(ip, ip_to)) { while (!after(ip, ip_to)) {
data.ip = htonl(ip); data.ip = htonl(ip);
last = ip_set_range_to_cidr(ip, ip_to, &cidr); last = ip_set_range_to_cidr(ip, ip_to, &cidr);
data.cidr = cidr - 1; data.cidr = cidr - 1;
p = retried && ip == h->next.ip ? h->next.port : port; p = retried && ip == ntohl(h->next.ip) ? ntohs(h->next.port)
: port;
for (; p <= port_to; p++) { for (; p <= port_to; p++) {
data.port = htons(p); data.port = htons(p);
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -369,10 +375,10 @@ hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags) ...@@ -369,10 +375,10 @@ hash_netport6_data_flags(struct hash_netport6_elem *dst, u32 flags)
dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH); dst->nomatch = !!(flags & IPSET_FLAG_NOMATCH);
} }
static inline bool static inline int
hash_netport6_data_match(const struct hash_netport6_elem *elem) hash_netport6_data_match(const struct hash_netport6_elem *elem)
{ {
return !elem->nomatch; return elem->nomatch ? -ENOTEMPTY : 1;
} }
static inline void static inline void
...@@ -450,7 +456,7 @@ static inline void ...@@ -450,7 +456,7 @@ static inline void
hash_netport6_data_next(struct ip_set_hash *h, hash_netport6_data_next(struct ip_set_hash *h,
const struct hash_netport6_elem *d) const struct hash_netport6_elem *d)
{ {
h->next.port = ntohs(d->port); h->next.port = d->port;
} }
static int static int
...@@ -554,7 +560,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[], ...@@ -554,7 +560,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
swap(port, port_to); swap(port, port_to);
if (retried) if (retried)
port = h->next.port; port = ntohs(h->next.port);
for (; port <= port_to; port++) { for (; port <= port_to; port++) {
data.port = htons(port); data.port = htons(port);
ret = adtfn(set, &data, timeout, flags); ret = adtfn(set, &data, timeout, flags);
...@@ -644,13 +650,11 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags) ...@@ -644,13 +650,11 @@ hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
static struct ip_set_type hash_netport_type __read_mostly = { static struct ip_set_type hash_netport_type __read_mostly = {
.name = "hash:net,port", .name = "hash:net,port",
.protocol = IPSET_PROTOCOL, .protocol = IPSET_PROTOCOL,
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT, .features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH,
.dimension = IPSET_DIM_TWO, .dimension = IPSET_DIM_TWO,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
/* 1 SCTP and UDPLITE support added */ .revision_max = REVISION_MAX,
/* 2, Range as input support for IPv4 added */
.revision_max = 3, /* nomatch flag support added */
.create = hash_netport_create, .create = hash_netport_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
......
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
#include <linux/netfilter/ipset/ip_set_timeout.h> #include <linux/netfilter/ipset/ip_set_timeout.h>
#include <linux/netfilter/ipset/ip_set_list.h> #include <linux/netfilter/ipset/ip_set_list.h>
#define REVISION_MIN 0
#define REVISION_MAX 0
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
MODULE_DESCRIPTION("list:set type of IP sets"); IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
MODULE_ALIAS("ip_set_list:set"); MODULE_ALIAS("ip_set_list:set");
/* Member elements without and with timeout */ /* Member elements without and with timeout */
...@@ -579,8 +582,8 @@ static struct ip_set_type list_set_type __read_mostly = { ...@@ -579,8 +582,8 @@ static struct ip_set_type list_set_type __read_mostly = {
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST, .features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
.dimension = IPSET_DIM_ONE, .dimension = IPSET_DIM_ONE,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.revision_min = 0, .revision_min = REVISION_MIN,
.revision_max = 0, .revision_max = REVISION_MAX,
.create = list_set_create, .create = list_set_create,
.create_policy = { .create_policy = {
[IPSET_ATTR_SIZE] = { .type = NLA_U32 }, [IPSET_ATTR_SIZE] = { .type = NLA_U32 },
......
...@@ -1224,6 +1224,8 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), ...@@ -1224,6 +1224,8 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data),
spin_lock_bh(&nf_conntrack_lock); spin_lock_bh(&nf_conntrack_lock);
for (; *bucket < net->ct.htable_size; (*bucket)++) { for (; *bucket < net->ct.htable_size; (*bucket)++) {
hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) { hlist_nulls_for_each_entry(h, n, &net->ct.hash[*bucket], hnnode) {
if (NF_CT_DIRECTION(h) != IP_CT_DIR_ORIGINAL)
continue;
ct = nf_ct_tuplehash_to_ctrack(h); ct = nf_ct_tuplehash_to_ctrack(h);
if (iter(ct, data)) if (iter(ct, data))
goto found; goto found;
......
...@@ -396,6 +396,12 @@ static int help(struct sk_buff *skb, ...@@ -396,6 +396,12 @@ static int help(struct sk_buff *skb,
/* Look up to see if we're just after a \n. */ /* Look up to see if we're just after a \n. */
if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) { if (!find_nl_seq(ntohl(th->seq), ct_ftp_info, dir)) {
/* We're picking up this, clear flags and let it continue */
if (unlikely(ct_ftp_info->flags[dir] & NF_CT_FTP_SEQ_PICKUP)) {
ct_ftp_info->flags[dir] ^= NF_CT_FTP_SEQ_PICKUP;
goto skip_nl_seq;
}
/* Now if this ends in \n, update ftp info. */ /* Now if this ends in \n, update ftp info. */
pr_debug("nf_conntrack_ftp: wrong seq pos %s(%u) or %s(%u)\n", pr_debug("nf_conntrack_ftp: wrong seq pos %s(%u) or %s(%u)\n",
ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)", ct_ftp_info->seq_aft_nl_num[dir] > 0 ? "" : "(UNSET)",
...@@ -406,6 +412,7 @@ static int help(struct sk_buff *skb, ...@@ -406,6 +412,7 @@ static int help(struct sk_buff *skb,
goto out_update_nl; goto out_update_nl;
} }
skip_nl_seq:
/* Initialize IP/IPv6 addr to expected address (it's not mentioned /* Initialize IP/IPv6 addr to expected address (it's not mentioned
in EPSV responses) */ in EPSV responses) */
cmd.l3num = nf_ct_l3num(ct); cmd.l3num = nf_ct_l3num(ct);
...@@ -512,6 +519,19 @@ static int help(struct sk_buff *skb, ...@@ -512,6 +519,19 @@ static int help(struct sk_buff *skb,
return ret; return ret;
} }
static int nf_ct_ftp_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
{
struct nf_ct_ftp_master *ftp = nfct_help_data(ct);
/* This conntrack has been injected from user-space, always pick up
* sequence tracking. Otherwise, the first FTP command after the
* failover breaks.
*/
ftp->flags[IP_CT_DIR_ORIGINAL] |= NF_CT_FTP_SEQ_PICKUP;
ftp->flags[IP_CT_DIR_REPLY] |= NF_CT_FTP_SEQ_PICKUP;
return 0;
}
static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly; static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly;
static const struct nf_conntrack_expect_policy ftp_exp_policy = { static const struct nf_conntrack_expect_policy ftp_exp_policy = {
...@@ -561,6 +581,7 @@ static int __init nf_conntrack_ftp_init(void) ...@@ -561,6 +581,7 @@ static int __init nf_conntrack_ftp_init(void)
ftp[i][j].expect_policy = &ftp_exp_policy; ftp[i][j].expect_policy = &ftp_exp_policy;
ftp[i][j].me = THIS_MODULE; ftp[i][j].me = THIS_MODULE;
ftp[i][j].help = help; ftp[i][j].help = help;
ftp[i][j].from_nlattr = nf_ct_ftp_from_nlattr;
if (ports[i] == FTP_PORT) if (ports[i] == FTP_PORT)
sprintf(ftp[i][j].name, "ftp"); sprintf(ftp[i][j].name, "ftp");
else else
......
...@@ -1238,7 +1238,7 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[]) ...@@ -1238,7 +1238,7 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[])
if (help) { if (help) {
if (help->helper == helper) { if (help->helper == helper) {
/* update private helper data if allowed. */ /* update private helper data if allowed. */
if (helper->from_nlattr && helpinfo) if (helper->from_nlattr)
helper->from_nlattr(helpinfo, ct); helper->from_nlattr(helpinfo, ct);
return 0; return 0;
} else } else
...@@ -1467,7 +1467,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone, ...@@ -1467,7 +1467,7 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
goto err2; goto err2;
} }
/* set private helper data if allowed. */ /* set private helper data if allowed. */
if (helper->from_nlattr && helpinfo) if (helper->from_nlattr)
helper->from_nlattr(helpinfo, ct); helper->from_nlattr(helpinfo, ct);
/* not in hash table yet so not strictly necessary */ /* not in hash table yet so not strictly necessary */
......
...@@ -201,12 +201,10 @@ find_appropriate_src(struct net *net, u16 zone, ...@@ -201,12 +201,10 @@ find_appropriate_src(struct net *net, u16 zone,
&ct->tuplehash[IP_CT_DIR_REPLY].tuple); &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
result->dst = tuple->dst; result->dst = tuple->dst;
if (in_range(l3proto, l4proto, result, range)) { if (in_range(l3proto, l4proto, result, range))
rcu_read_unlock();
return 1; return 1;
} }
} }
}
return 0; return 0;
} }
...@@ -481,6 +479,8 @@ static int nf_nat_proto_clean(struct nf_conn *i, void *data) ...@@ -481,6 +479,8 @@ static int nf_nat_proto_clean(struct nf_conn *i, void *data)
if (!nat) if (!nat)
return 0; return 0;
if (!(i->status & IPS_SRC_NAT_DONE))
return 0;
if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) || if ((clean->l3proto && nf_ct_l3num(i) != clean->l3proto) ||
(clean->l4proto && nf_ct_protonum(i) != clean->l4proto)) (clean->l4proto && nf_ct_protonum(i) != clean->l4proto))
return 0; return 0;
......
...@@ -85,6 +85,9 @@ nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct) ...@@ -85,6 +85,9 @@ nfnl_cthelper_from_nlattr(struct nlattr *attr, struct nf_conn *ct)
{ {
const struct nf_conn_help *help = nfct_help(ct); const struct nf_conn_help *help = nfct_help(ct);
if (attr == NULL)
return -EINVAL;
if (help->helper->data_len == 0) if (help->helper->data_len == 0)
return -EINVAL; return -EINVAL;
......
...@@ -225,7 +225,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, ...@@ -225,7 +225,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
{ {
sk_buff_data_t old_tail; sk_buff_data_t old_tail;
size_t size; size_t size;
size_t data_len = 0; size_t data_len = 0, cap_len = 0;
struct sk_buff *skb; struct sk_buff *skb;
struct nlattr *nla; struct nlattr *nla;
struct nfqnl_msg_packet_hdr *pmsg; struct nfqnl_msg_packet_hdr *pmsg;
...@@ -247,7 +247,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, ...@@ -247,7 +247,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
#endif #endif
+ nla_total_size(sizeof(u_int32_t)) /* mark */ + nla_total_size(sizeof(u_int32_t)) /* mark */
+ nla_total_size(sizeof(struct nfqnl_msg_packet_hw)) + nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
+ nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp)); + nla_total_size(sizeof(struct nfqnl_msg_packet_timestamp)
+ nla_total_size(sizeof(u_int32_t))); /* cap_len */
outdev = entry->outdev; outdev = entry->outdev;
...@@ -266,6 +267,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, ...@@ -266,6 +267,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
data_len = entskb->len; data_len = entskb->len;
size += nla_total_size(data_len); size += nla_total_size(data_len);
cap_len = entskb->len;
break; break;
} }
...@@ -402,6 +404,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, ...@@ -402,6 +404,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0) if (ct && nfqnl_ct_put(skb, ct, ctinfo) < 0)
goto nla_put_failure; goto nla_put_failure;
if (cap_len > 0 && nla_put_be32(skb, NFQA_CAP_LEN, htonl(cap_len)))
goto nla_put_failure;
nlh->nlmsg_len = skb->tail - old_tail; nlh->nlmsg_len = skb->tail - old_tail;
return skb; return skb;
...@@ -526,9 +531,13 @@ nfqnl_set_mode(struct nfqnl_instance *queue, ...@@ -526,9 +531,13 @@ nfqnl_set_mode(struct nfqnl_instance *queue,
case NFQNL_COPY_PACKET: case NFQNL_COPY_PACKET:
queue->copy_mode = mode; queue->copy_mode = mode;
/* we're using struct nlattr which has 16bit nla_len */ /* We're using struct nlattr which has 16bit nla_len. Note that
if (range > 0xffff) * nla_len includes the header length. Thus, the maximum packet
queue->copy_range = 0xffff; * length that we support is 65531 bytes. We send truncated
* packets if the specified length is larger than that.
*/
if (range > 0xffff - NLA_HDRLEN)
queue->copy_range = 0xffff - NLA_HDRLEN;
else else
queue->copy_range = range; queue->copy_range = range;
break; break;
......
/* NETMAP - static NAT mapping of IP network addresses (1:1). /*
* The mapping can be applied to source (POSTROUTING), * (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
* destination (PREROUTING), or both (with separate rules). * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
*/
/* (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/ipv6.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat.h>
MODULE_LICENSE("GPL"); static unsigned int
MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>"); netmap_tg6(struct sk_buff *skb, const struct xt_action_param *par)
MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of IPv4 subnets");
static int netmap_tg_check(const struct xt_tgchk_param *par)
{ {
const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; const struct nf_nat_range *range = par->targinfo;
struct nf_nat_range newrange;
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
union nf_inet_addr new_addr, netmask;
unsigned int i;
if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) { ct = nf_ct_get(skb, &ctinfo);
pr_debug("bad MAP_IPS.\n"); for (i = 0; i < ARRAY_SIZE(range->min_addr.ip6); i++)
return -EINVAL; netmask.ip6[i] = ~(range->min_addr.ip6[i] ^
range->max_addr.ip6[i]);
if (par->hooknum == NF_INET_PRE_ROUTING ||
par->hooknum == NF_INET_LOCAL_OUT)
new_addr.in6 = ipv6_hdr(skb)->daddr;
else
new_addr.in6 = ipv6_hdr(skb)->saddr;
for (i = 0; i < ARRAY_SIZE(new_addr.ip6); i++) {
new_addr.ip6[i] &= ~netmask.ip6[i];
new_addr.ip6[i] |= range->min_addr.ip6[i] &
netmask.ip6[i];
} }
if (mr->rangesize != 1) {
pr_debug("bad rangesize %u.\n", mr->rangesize); newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
newrange.min_addr = new_addr;
newrange.max_addr = new_addr;
newrange.min_proto = range->min_proto;
newrange.max_proto = range->max_proto;
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
}
static int netmap_tg6_checkentry(const struct xt_tgchk_param *par)
{
const struct nf_nat_range *range = par->targinfo;
if (!(range->flags & NF_NAT_RANGE_MAP_IPS))
return -EINVAL; return -EINVAL;
}
return 0; return 0;
} }
static unsigned int static unsigned int
netmap_tg(struct sk_buff *skb, const struct xt_action_param *par) netmap_tg4(struct sk_buff *skb, const struct xt_action_param *par)
{ {
struct nf_conn *ct; struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
...@@ -73,29 +99,67 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -73,29 +99,67 @@ netmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum)); return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
} }
static struct xt_target netmap_tg_reg __read_mostly = { static int netmap_tg4_check(const struct xt_tgchk_param *par)
{
const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
if (!(mr->range[0].flags & NF_NAT_RANGE_MAP_IPS)) {
pr_debug("bad MAP_IPS.\n");
return -EINVAL;
}
if (mr->rangesize != 1) {
pr_debug("bad rangesize %u.\n", mr->rangesize);
return -EINVAL;
}
return 0;
}
static struct xt_target netmap_tg_reg[] __read_mostly = {
{
.name = "NETMAP",
.family = NFPROTO_IPV6,
.revision = 0,
.target = netmap_tg6,
.targetsize = sizeof(struct nf_nat_range),
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING) |
(1 << NF_INET_LOCAL_OUT) |
(1 << NF_INET_LOCAL_IN),
.checkentry = netmap_tg6_checkentry,
.me = THIS_MODULE,
},
{
.name = "NETMAP", .name = "NETMAP",
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.target = netmap_tg, .revision = 0,
.target = netmap_tg4,
.targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat), .targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
.table = "nat", .table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) | .hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING) | (1 << NF_INET_POST_ROUTING) |
(1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_OUT) |
(1 << NF_INET_LOCAL_IN), (1 << NF_INET_LOCAL_IN),
.checkentry = netmap_tg_check, .checkentry = netmap_tg4_check,
.me = THIS_MODULE .me = THIS_MODULE,
},
}; };
static int __init netmap_tg_init(void) static int __init netmap_tg_init(void)
{ {
return xt_register_target(&netmap_tg_reg); return xt_register_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg));
} }
static void __exit netmap_tg_exit(void) static void netmap_tg_exit(void)
{ {
xt_unregister_target(&netmap_tg_reg); xt_unregister_targets(netmap_tg_reg, ARRAY_SIZE(netmap_tg_reg));
} }
module_init(netmap_tg_init); module_init(netmap_tg_init);
module_exit(netmap_tg_exit); module_exit(netmap_tg_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Xtables: 1:1 NAT mapping of subnets");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_ALIAS("ip6t_NETMAP");
MODULE_ALIAS("ipt_NETMAP");
/* Redirect. Simple mapping which alters dst to a local IP address. */ /*
/* (C) 1999-2001 Paul `Rusty' Russell * (C) 1999-2001 Paul `Rusty' Russell
* (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org> * (C) 2002-2006 Netfilter Core Team <coreteam@netfilter.org>
* Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*
* Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6
* NAT funded by Astaro.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/types.h> #include <linux/if.h>
#include <linux/inetdevice.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/timer.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if.h> #include <linux/netfilter.h>
#include <linux/inetdevice.h> #include <linux/types.h>
#include <net/protocol.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <net/addrconf.h>
#include <net/checksum.h>
#include <net/protocol.h>
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat.h>
MODULE_LICENSE("GPL"); static const struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
MODULE_DESCRIPTION("Xtables: Connection redirection to localhost"); static unsigned int
redirect_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct nf_nat_range *range = par->targinfo;
struct nf_nat_range newrange;
struct in6_addr newdst;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
ct = nf_ct_get(skb, &ctinfo);
if (par->hooknum == NF_INET_LOCAL_OUT)
newdst = loopback_addr;
else {
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
bool addr = false;
rcu_read_lock();
idev = __in6_dev_get(skb->dev);
if (idev != NULL) {
list_for_each_entry(ifa, &idev->addr_list, if_list) {
newdst = ifa->addr;
addr = true;
break;
}
}
rcu_read_unlock();
if (!addr)
return NF_DROP;
}
newrange.flags = range->flags | NF_NAT_RANGE_MAP_IPS;
newrange.min_addr.in6 = newdst;
newrange.max_addr.in6 = newdst;
newrange.min_proto = range->min_proto;
newrange.max_proto = range->max_proto;
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
}
static int redirect_tg6_checkentry(const struct xt_tgchk_param *par)
{
const struct nf_nat_range *range = par->targinfo;
if (range->flags & NF_NAT_RANGE_MAP_IPS)
return -EINVAL;
return 0;
}
/* FIXME: Take multiple ranges --RR */ /* FIXME: Take multiple ranges --RR */
static int redirect_tg_check(const struct xt_tgchk_param *par) static int redirect_tg4_check(const struct xt_tgchk_param *par)
{ {
const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo; const struct nf_nat_ipv4_multi_range_compat *mr = par->targinfo;
...@@ -42,7 +96,7 @@ static int redirect_tg_check(const struct xt_tgchk_param *par) ...@@ -42,7 +96,7 @@ static int redirect_tg_check(const struct xt_tgchk_param *par)
} }
static unsigned int static unsigned int
redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) redirect_tg4(struct sk_buff *skb, const struct xt_action_param *par)
{ {
struct nf_conn *ct; struct nf_conn *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
...@@ -88,26 +142,49 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -88,26 +142,49 @@ redirect_tg(struct sk_buff *skb, const struct xt_action_param *par)
return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST); return nf_nat_setup_info(ct, &newrange, NF_NAT_MANIP_DST);
} }
static struct xt_target redirect_tg_reg __read_mostly = { static struct xt_target redirect_tg_reg[] __read_mostly = {
{
.name = "REDIRECT",
.family = NFPROTO_IPV6,
.revision = 0,
.table = "nat",
.checkentry = redirect_tg6_checkentry,
.target = redirect_tg6,
.targetsize = sizeof(struct nf_nat_range),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_OUT),
.me = THIS_MODULE,
},
{
.name = "REDIRECT", .name = "REDIRECT",
.family = NFPROTO_IPV4, .family = NFPROTO_IPV4,
.target = redirect_tg, .revision = 0,
.targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
.table = "nat", .table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT), .target = redirect_tg4,
.checkentry = redirect_tg_check, .checkentry = redirect_tg4_check,
.targetsize = sizeof(struct nf_nat_ipv4_multi_range_compat),
.hooks = (1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_LOCAL_OUT),
.me = THIS_MODULE, .me = THIS_MODULE,
},
}; };
static int __init redirect_tg_init(void) static int __init redirect_tg_init(void)
{ {
return xt_register_target(&redirect_tg_reg); return xt_register_targets(redirect_tg_reg,
ARRAY_SIZE(redirect_tg_reg));
} }
static void __exit redirect_tg_exit(void) static void __exit redirect_tg_exit(void)
{ {
xt_unregister_target(&redirect_tg_reg); xt_unregister_targets(redirect_tg_reg, ARRAY_SIZE(redirect_tg_reg));
} }
module_init(redirect_tg_init); module_init(redirect_tg_init);
module_exit(redirect_tg_exit); module_exit(redirect_tg_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("Xtables: Connection redirection to localhost");
MODULE_ALIAS("ip6t_REDIRECT");
MODULE_ALIAS("ipt_REDIRECT");
...@@ -356,6 +356,27 @@ static struct xt_match set_matches[] __read_mostly = { ...@@ -356,6 +356,27 @@ static struct xt_match set_matches[] __read_mostly = {
.destroy = set_match_v1_destroy, .destroy = set_match_v1_destroy,
.me = THIS_MODULE .me = THIS_MODULE
}, },
/* --return-nomatch flag support */
{
.name = "set",
.family = NFPROTO_IPV4,
.revision = 2,
.match = set_match_v1,
.matchsize = sizeof(struct xt_set_info_match_v1),
.checkentry = set_match_v1_checkentry,
.destroy = set_match_v1_destroy,
.me = THIS_MODULE
},
{
.name = "set",
.family = NFPROTO_IPV6,
.revision = 2,
.match = set_match_v1,
.matchsize = sizeof(struct xt_set_info_match_v1),
.checkentry = set_match_v1_checkentry,
.destroy = set_match_v1_destroy,
.me = THIS_MODULE
},
}; };
static struct xt_target set_targets[] __read_mostly = { static struct xt_target set_targets[] __read_mostly = {
...@@ -389,6 +410,7 @@ static struct xt_target set_targets[] __read_mostly = { ...@@ -389,6 +410,7 @@ static struct xt_target set_targets[] __read_mostly = {
.destroy = set_target_v1_destroy, .destroy = set_target_v1_destroy,
.me = THIS_MODULE .me = THIS_MODULE
}, },
/* --timeout and --exist flags support */
{ {
.name = "SET", .name = "SET",
.revision = 2, .revision = 2,
......
...@@ -42,6 +42,7 @@ static const u_int16_t days_since_leapyear[] = { ...@@ -42,6 +42,7 @@ static const u_int16_t days_since_leapyear[] = {
*/ */
enum { enum {
DSE_FIRST = 2039, DSE_FIRST = 2039,
SECONDS_PER_DAY = 86400,
}; };
static const u_int16_t days_since_epoch[] = { static const u_int16_t days_since_epoch[] = {
/* 2039 - 2030 */ /* 2039 - 2030 */
...@@ -78,7 +79,7 @@ static inline unsigned int localtime_1(struct xtm *r, time_t time) ...@@ -78,7 +79,7 @@ static inline unsigned int localtime_1(struct xtm *r, time_t time)
unsigned int v, w; unsigned int v, w;
/* Each day has 86400s, so finding the hour/minute is actually easy. */ /* Each day has 86400s, so finding the hour/minute is actually easy. */
v = time % 86400; v = time % SECONDS_PER_DAY;
r->second = v % 60; r->second = v % 60;
w = v / 60; w = v / 60;
r->minute = w % 60; r->minute = w % 60;
...@@ -199,6 +200,18 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -199,6 +200,18 @@ time_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (packet_time < info->daytime_start && if (packet_time < info->daytime_start &&
packet_time > info->daytime_stop) packet_time > info->daytime_stop)
return false; return false;
/** if user asked to ignore 'next day', then e.g.
* '1 PM Wed, August 1st' should be treated
* like 'Tue 1 PM July 31st'.
*
* This also causes
* 'Monday, "23:00 to 01:00", to match for 2 hours, starting
* Monday 23:00 to Tuesday 01:00.
*/
if ((info->flags & XT_TIME_CONTIGUOUS) &&
packet_time <= info->daytime_stop)
stamp -= SECONDS_PER_DAY;
} }
localtime_2(&current_time, stamp); localtime_2(&current_time, stamp);
...@@ -227,6 +240,15 @@ static int time_mt_check(const struct xt_mtchk_param *par) ...@@ -227,6 +240,15 @@ static int time_mt_check(const struct xt_mtchk_param *par)
return -EDOM; return -EDOM;
} }
if (info->flags & ~XT_TIME_ALL_FLAGS) {
pr_info("unknown flags 0x%x\n", info->flags & ~XT_TIME_ALL_FLAGS);
return -EINVAL;
}
if ((info->flags & XT_TIME_CONTIGUOUS) &&
info->daytime_start < info->daytime_stop)
return -EINVAL;
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment