summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--Make_global.am2
-rw-r--r--configure.ac16
-rw-r--r--include/libipset/args.h1
-rw-r--r--include/libipset/data.h6
-rw-r--r--include/libipset/linux_ip_set.h2
-rw-r--r--include/libipset/list_sort.h4
-rw-r--r--include/libipset/parse.h2
-rw-r--r--kernel/ChangeLog21
-rw-r--r--kernel/include/linux/netfilter/ipset/ip_set.h10
-rw-r--r--kernel/include/linux/netfilter/ipset/ip_set_compat.h.in14
-rw-r--r--kernel/include/uapi/linux/netfilter/ipset/ip_set.h6
-rw-r--r--kernel/net/netfilter/ipset/ip_set_core.c11
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_gen.h105
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_ip.c27
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_ipport.c24
-rw-r--r--kernel/net/netfilter/ipset/ip_set_hash_netnet.c26
-rw-r--r--kernel/net/sched/em_ipset.c7
-rw-r--r--lib/args.c8
-rw-r--r--lib/data.c10
-rw-r--r--lib/debug.c1
-rw-r--r--lib/errcode.c2
-rw-r--r--lib/ipset.c32
-rw-r--r--lib/ipset_hash_ip.c86
-rw-r--r--lib/ipset_hash_ipport.c108
-rw-r--r--lib/ipset_hash_netnet.c101
-rw-r--r--lib/libipset.map4
-rw-r--r--lib/parse.c48
-rw-r--r--lib/print.c3
-rw-r--r--lib/session.c8
-rw-r--r--src/ipset.833
-rw-r--r--src/ipset.c3
-rw-r--r--tests/hash:ip,port.t118
-rw-r--r--tests/hash:ip,port.t.list311
-rw-r--r--tests/hash:ip,port.t.list49
-rw-r--r--tests/hash:ip,port.t.list511
-rw-r--r--tests/hash:ip,port.t.list69
-rw-r--r--tests/hash:ip,port.t.list79
-rw-r--r--tests/hash:ip.t76
-rw-r--r--tests/hash:ip.t.list411
-rw-r--r--tests/hash:ip.t.list59
-rw-r--r--tests/hash:ip.t.list69
-rw-r--r--tests/hash:net,iface.t4
-rw-r--r--tests/hash:net,net.t106
-rw-r--r--tests/hash:net,net.t.list311
-rw-r--r--tests/hash:net,net.t.list49
-rw-r--r--tests/hash:net,net.t.list511
-rw-r--r--tests/hash:net,net.t.list69
-rw-r--r--tests/hash:net,net.t.list79
49 files changed, 1073 insertions, 104 deletions
diff --git a/ChangeLog b/ChangeLog
index c5bf19c..8c6ef3c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+7.16
+ - Add new ipset_parse_bitmask() function to the library interface
+ - test: Make sure no more than 64 clashing elements can be added
+ to hash:net,iface sets
+ - netfilter: ipset: add tests for the new bitmask feature (Vishwanath Pai)
+ - netfilter: ipset: Update the man page to include netmask/bitmask options
+ (Vishwanath Pai)
+ - netfilter: ipset: Add bitmask support to hash:netnet (Vishwanath Pai)
+ - netfilter: ipset: Add bitmask support to hash:ipport (Vishwanath Pai)
+ - netfilter: ipset: Add bitmask support to hash:ip (Vishwanath Pai)
+ - netfilter: ipset: Add support for new bitmask parameter (Vishwanath Pai)
+ - ipset-translate: allow invoking with a path name (Quentin Armitage)
+ - Fix IPv6 sets nftables translation (Pablo Neira Ayuso)
+ - Fix typo in ipset-translate man page (Bernhard M. Wiedemann)
+
7.14
- Add missing function to libipset.map and bump library version
(reported by Jan Engelhardt)
diff --git a/Make_global.am b/Make_global.am
index ed92cfe..9ba6adf 100644
--- a/Make_global.am
+++ b/Make_global.am
@@ -69,7 +69,7 @@
# interface.
# curr:rev:age
-LIBVERSION = 16:0:3
+LIBVERSION = 17:0:4
AM_CPPFLAGS = $(kinclude_CFLAGS) $(all_includes) -I$(top_srcdir)/include
diff --git a/configure.ac b/configure.ac
index 1acc976..e94f4db 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
dnl Boilerplate
-AC_INIT([ipset], [7.15], [kadlec@netfilter.org])
+AC_INIT([ipset], [7.16], [kadlec@netfilter.org])
AC_CONFIG_AUX_DIR([build-aux])
AC_CANONICAL_HOST
AC_CONFIG_MACRO_DIR([m4])
@@ -443,6 +443,10 @@ if test -f $ksourcedir/include/linux/mm.h && \
$GREP -q 'kvcalloc' $ksourcedir/include/linux/mm.h; then
AC_MSG_RESULT(yes)
AC_SUBST(HAVE_KVCALLOC, define)
+elif test -f $ksourcedir/include/linux/slab.h && \
+ $GREP -q 'kvcalloc' $ksourcedir/include/linux/slab.h; then
+ AC_MSG_RESULT(yes)
+ AC_SUBST(HAVE_KVCALLOC, define)
else
AC_MSG_RESULT(no)
AC_SUBST(HAVE_KVCALLOC, undef)
@@ -453,6 +457,10 @@ if test -f $ksourcedir/include/linux/mm.h && \
$GREP -q 'kvfree' $ksourcedir/include/linux/mm.h; then
AC_MSG_RESULT(yes)
AC_SUBST(HAVE_KVFREE, define)
+elif test -f $ksourcedir/include/linux/slab.h && \
+ $GREP -q 'kvfree' $ksourcedir/include/linux/slab.h; then
+ AC_MSG_RESULT(yes)
+ AC_SUBST(HAVE_KVFREE, define)
else
AC_MSG_RESULT(no)
AC_SUBST(HAVE_KVFREE, undef)
@@ -837,11 +845,15 @@ else
AC_SUBST(HAVE_NLMSG_UNICAST, undef)
fi
-AC_MSG_CHECKING([kernel source for kvzalloc() in mm.h])
+AC_MSG_CHECKING([kernel source for kvzalloc() in mm.h and slab.h])
if test -f $ksourcedir/include/linux/mm.h && \
$GREP -q 'static inline void \*kvzalloc(' $ksourcedir/include/linux/mm.h; then
AC_MSG_RESULT(yes)
AC_SUBST(HAVE_KVZALLOC, define)
+elif test -f $ksourcedir/include/linux/slab.h && \
+ $GREP -q 'kvzalloc' $ksourcedir/include/linux/slab.h; then
+ AC_MSG_RESULT(yes)
+ AC_SUBST(HAVE_KVZALLOC, define)
else
AC_MSG_RESULT(no)
AC_SUBST(HAVE_KVZALLOC, undef)
diff --git a/include/libipset/args.h b/include/libipset/args.h
index ef861c1..a549e42 100644
--- a/include/libipset/args.h
+++ b/include/libipset/args.h
@@ -58,6 +58,7 @@ enum ipset_keywords {
IPSET_ARG_SKBQUEUE, /* skbqueue */
IPSET_ARG_BUCKETSIZE, /* bucketsize */
IPSET_ARG_INITVAL, /* initval */
+ IPSET_ARG_BITMASK, /* bitmask */
IPSET_ARG_MAX,
};
diff --git a/include/libipset/data.h b/include/libipset/data.h
index 0e33c67..afaf18c 100644
--- a/include/libipset/data.h
+++ b/include/libipset/data.h
@@ -37,6 +37,7 @@ enum ipset_opt {
IPSET_OPT_RESIZE,
IPSET_OPT_SIZE,
IPSET_OPT_FORCEADD,
+ IPSET_OPT_BITMASK,
/* Create-specific options, filled out by the kernel */
IPSET_OPT_ELEMENTS,
IPSET_OPT_REFERENCES,
@@ -70,7 +71,7 @@ enum ipset_opt {
IPSET_OPT_BUCKETSIZE,
IPSET_OPT_INITVAL,
/* Internal options */
- IPSET_OPT_FLAGS = 48, /* IPSET_FLAG_EXIST| */
+ IPSET_OPT_FLAGS = 49, /* IPSET_FLAG_EXIST| */
IPSET_OPT_CADT_FLAGS, /* IPSET_FLAG_BEFORE| */
IPSET_OPT_ELEM,
IPSET_OPT_TYPE,
@@ -105,7 +106,8 @@ enum ipset_opt {
| IPSET_FLAG(IPSET_OPT_COUNTERS)\
| IPSET_FLAG(IPSET_OPT_CREATE_COMMENT)\
| IPSET_FLAG(IPSET_OPT_FORCEADD)\
- | IPSET_FLAG(IPSET_OPT_SKBINFO))
+ | IPSET_FLAG(IPSET_OPT_SKBINFO)\
+ | IPSET_FLAG(IPSET_OPT_BITMASK))
#define IPSET_ADT_FLAGS \
(IPSET_FLAG(IPSET_OPT_IP) \
diff --git a/include/libipset/linux_ip_set.h b/include/libipset/linux_ip_set.h
index 1852636..4e32a50 100644
--- a/include/libipset/linux_ip_set.h
+++ b/include/libipset/linux_ip_set.h
@@ -89,6 +89,7 @@ enum {
IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */
IPSET_ATTR_MARK, /* 10 */
IPSET_ATTR_MARKMASK, /* 11 */
+ IPSET_ATTR_BITMASK, /* 12 */
/* Reserve empty slots */
IPSET_ATTR_CADT_MAX = 16,
/* Create-only specific attributes */
@@ -157,6 +158,7 @@ enum ipset_errno {
IPSET_ERR_COMMENT,
IPSET_ERR_INVALID_MARKMASK,
IPSET_ERR_SKBINFO,
+ IPSET_ERR_BITMASK_NETMASK_EXCL,
/* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 4352,
diff --git a/include/libipset/list_sort.h b/include/libipset/list_sort.h
index 70bb02d..d9d7b36 100644
--- a/include/libipset/list_sort.h
+++ b/include/libipset/list_sort.h
@@ -61,7 +61,7 @@ static inline void list_del(struct list_head *entry)
// entry->prev = (void *) 0;
}
-static inline void __list_splice(const struct list_head *list,
+static inline void __list_splice(struct list_head *list,
struct list_head *prev,
struct list_head *next)
{
@@ -75,7 +75,7 @@ static inline void __list_splice(const struct list_head *list,
next->prev = last;
}
-static inline void list_splice(const struct list_head *list,
+static inline void list_splice(struct list_head *list,
struct list_head *head)
{
if (!list_empty(list))
diff --git a/include/libipset/parse.h b/include/libipset/parse.h
index 3fa9129..0123d4b 100644
--- a/include/libipset/parse.h
+++ b/include/libipset/parse.h
@@ -92,6 +92,8 @@ extern int ipset_parse_uint8(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_netmask(struct ipset_session *session,
enum ipset_opt opt, const char *str);
+extern int ipset_parse_bitmask(struct ipset_session *session,
+ enum ipset_opt opt, const char *str);
extern int ipset_parse_flag(struct ipset_session *session,
enum ipset_opt opt, const char *str);
extern int ipset_parse_typename(struct ipset_session *session,
diff --git a/kernel/ChangeLog b/kernel/ChangeLog
index 0ee716d..b7d2266 100644
--- a/kernel/ChangeLog
+++ b/kernel/ChangeLog
@@ -1,3 +1,24 @@
+7.16
+ - netfilter: ipset: restore allowing 64 clashing elements in hash:net,iface
+ - Fix all debug mode warnings
+ - netfilter: ipset: Add support for new bitmask parameter (Vishwanath Pai)
+ - netfilter: ipset: regression in ip_set_hash_ip.c (Vishwanath Pai)
+ - netfilter: move from strlcpy with unused retval to strscpy
+ (Wolfram Sang)
+ - compatibility: handle unsafe_memcpy()
+ - netlink: Bounds-check struct nlmsgerr creation (Kees Cook)
+ - compatibility: move to skb_protocol in the code from tc_skb_protocol
+ - Compatibility: check kvcalloc, kvfree, kvzalloc in slab.h too
+ - sched: consistently handle layer3 header accesses in the presence
+ of VLANs (Toke Høiland-Jørgensen)
+ - treewide: Replace GPLv2 boilerplate/reference with SPDX
+ - rule 500 (Thomas Gleixner)
+ - headers: Remove some left-over license text in
+ include/uapi/linux/netfilter/ (Christophe JAILLET)
+ - netfilter: ipset: enforce documented limit to prevent allocating
+ huge memory
+ - netfilter: ipset: Fix oversized kvmalloc() calls
+
7.15
- netfilter: ipset: Fix maximal range check in hash_ipportnet4_uadt()
(Nathan Chancellor)
diff --git a/kernel/include/linux/netfilter/ipset/ip_set.h b/kernel/include/linux/netfilter/ipset/ip_set.h
index 3a6963c..efc0e6d 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set.h
+++ b/kernel/include/linux/netfilter/ipset/ip_set.h
@@ -528,6 +528,16 @@ ip_set_init_skbinfo(struct ip_set_skbinfo *skbinfo,
*skbinfo = ext->skbinfo;
}
+static inline void
+nf_inet_addr_mask_inplace(union nf_inet_addr *a1,
+ const union nf_inet_addr *mask)
+{
+ a1->all[0] &= mask->all[0];
+ a1->all[1] &= mask->all[1];
+ a1->all[2] &= mask->all[2];
+ a1->all[3] &= mask->all[3];
+}
+
#define IP_SET_INIT_KEXT(skb, opt, set) \
{ .bytes = (skb)->len, .packets = 1, .target = true,\
.timeout = ip_set_adt_opt_timeout(opt, set) }
diff --git a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
index 4d2c446..7d3f536 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
+++ b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
@@ -406,11 +406,9 @@ static inline int nla_put_in6_addr(struct sk_buff *skb, int attrtype,
#define skb_vlan_tag_present vlan_tx_tag_present
#endif
-static inline __be16 tc_skb_protocol(const struct sk_buff *skb)
+#ifndef HAVE_SKB_PROTOCOL
+static inline __be16 skb_protocol(const struct sk_buff *skb, bool skip_vlan)
{
-#ifdef HAVE_SKB_PROTOCOL
- return skb_protocol(skb, true);
-#else
if (skb_vlan_tag_present(skb))
#ifdef HAVE_VLAN_PROTO_IN_SK_BUFF
return skb->vlan_proto;
@@ -418,9 +416,9 @@ static inline __be16 tc_skb_protocol(const struct sk_buff *skb)
return htons(ETH_P_8021Q);
#endif
return skb->protocol;
-#endif
}
#endif
+#endif
#ifdef HAVE_XT_NET
#define IPSET_DEV_NET(par) xt_net(par)
@@ -607,5 +605,11 @@ static inline void *kvzalloc(size_t size, gfp_t flags)
return members;
}
#endif
+
+#ifndef unsafe_memcpy
+#define unsafe_memcpy(dst, src, bytes, justification) \
+ memcpy(dst, src, bytes)
+#endif
+
#endif /* IP_SET_COMPAT_HEADERS */
#endif /* __IP_SET_COMPAT_H */
diff --git a/kernel/include/uapi/linux/netfilter/ipset/ip_set.h b/kernel/include/uapi/linux/netfilter/ipset/ip_set.h
index 8a495aa..b81f1ae 100644
--- a/kernel/include/uapi/linux/netfilter/ipset/ip_set.h
+++ b/kernel/include/uapi/linux/netfilter/ipset/ip_set.h
@@ -3,10 +3,6 @@
* Patrick Schaaf <bof@bof.de>
* Martin Josefsson <gandalf@wlug.westbo.se>
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@netfilter.org>
- *
- * 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.
*/
#ifndef _UAPI_IP_SET_H
#define _UAPI_IP_SET_H
@@ -89,6 +85,7 @@ enum {
IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */
IPSET_ATTR_MARK, /* 10 */
IPSET_ATTR_MARKMASK, /* 11 */
+ IPSET_ATTR_BITMASK, /* 12 */
/* Reserve empty slots */
IPSET_ATTR_CADT_MAX = 16,
/* Create-only specific attributes */
@@ -157,6 +154,7 @@ enum ipset_errno {
IPSET_ERR_COMMENT,
IPSET_ERR_INVALID_MARKMASK,
IPSET_ERR_SKBINFO,
+ IPSET_ERR_BITMASK_NETMASK_EXCL,
/* Type specific error codes */
IPSET_ERR_TYPE_SPECIFIC = 4352,
diff --git a/kernel/net/netfilter/ipset/ip_set_core.c b/kernel/net/netfilter/ipset/ip_set_core.c
index 0fdafb7..77fb55c 100644
--- a/kernel/net/netfilter/ipset/ip_set_core.c
+++ b/kernel/net/netfilter/ipset/ip_set_core.c
@@ -354,7 +354,7 @@ ip_set_init_comment(struct ip_set *set, struct ip_set_comment *comment,
c = kmalloc(sizeof(*c) + len + 1, GFP_ATOMIC);
if (unlikely(!c))
return;
- strlcpy(c->str, ext->comment, len + 1);
+ strscpy(c->str, ext->comment, len + 1);
set->ext_size += sizeof(*c) + strlen(c->str) + 1;
rcu_assign_pointer(comment->c, c);
}
@@ -1082,7 +1082,7 @@ IPSET_CBFN(ip_set_create, struct net *n, struct sock *ctnl,
if (!set)
return -ENOMEM;
spin_lock_init(&set->lock);
- strlcpy(set->name, name, IPSET_MAXNAMELEN);
+ strscpy(set->name, name, IPSET_MAXNAMELEN);
set->family = family;
set->revision = revision;
@@ -1775,11 +1775,12 @@ CALL_AD(struct net *net, struct sock *ctnl, struct sk_buff *skb,
skb2 = nlmsg_new(payload, GFP_KERNEL);
if (!skb2)
return -ENOMEM;
- rep = __nlmsg_put(skb2, NETLINK_PORTID(skb),
- nlh->nlmsg_seq, NLMSG_ERROR, payload, 0);
+ rep = nlmsg_put(skb2, NETLINK_PORTID(skb),
+ nlh->nlmsg_seq, NLMSG_ERROR, payload, 0);
errmsg = nlmsg_data(rep);
errmsg->error = ret;
- memcpy(&errmsg->msg, nlh, nlh->nlmsg_len);
+ unsafe_memcpy(&errmsg->msg, nlh, nlh->nlmsg_len,
+ /* Bounds checked by the skb layer. */);
cmdattr = (void *)&errmsg->msg + min_len;
ret = NLA_PARSE(cda, IPSET_ATTR_CMD_MAX, cmdattr,
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_gen.h b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
index adf35fd..af38991 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/kernel/net/netfilter/ipset/ip_set_hash_gen.h
@@ -43,31 +43,8 @@
#define AHASH_MAX_SIZE (6 * AHASH_INIT_SIZE)
/* Max muber of elements in the array block when tuned */
#define AHASH_MAX_TUNED 64
-
#define AHASH_MAX(h) ((h)->bucketsize)
-/* Max number of elements can be tuned */
-#ifdef IP_SET_HASH_WITH_MULTI
-static u8
-tune_bucketsize(u8 curr, u32 multi)
-{
- u32 n;
-
- if (multi < curr)
- return curr;
-
- n = curr + AHASH_INIT_SIZE;
- /* Currently, at listing one hash bucket must fit into a message.
- * Therefore we have a hard limit here.
- */
- return n > curr && n <= AHASH_MAX_TUNED ? n : curr;
-}
-#define TUNE_BUCKETSIZE(h, multi) \
- ((h)->bucketsize = tune_bucketsize((h)->bucketsize, multi))
-#else
-#define TUNE_BUCKETSIZE(h, multi)
-#endif
-
/* A hash bucket */
struct hbucket {
struct rcu_head rcu; /* for call_rcu_bh */
@@ -131,11 +108,11 @@ htable_size(u8 hbits)
{
size_t hsize;
- /* We must fit both into u32 in jhash and size_t */
+ /* We must fit both into u32 in jhash and INT_MAX in kvmalloc_node() */
if (hbits > 31)
return 0;
hsize = jhash_size(hbits);
- if ((((size_t)-1) - sizeof(struct htable)) / sizeof(struct hbucket *)
+ if ((INT_MAX - sizeof(struct htable)) / sizeof(struct hbucket *)
< hsize)
return 0;
@@ -183,6 +160,17 @@ htable_size(u8 hbits)
(SET_WITH_TIMEOUT(set) && \
ip_set_timeout_expired(ext_timeout(d, set)))
+#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK)
+static const union nf_inet_addr onesmask = {
+ .all[0] = 0xffffffff,
+ .all[1] = 0xffffffff,
+ .all[2] = 0xffffffff,
+ .all[3] = 0xffffffff
+};
+
+static const union nf_inet_addr zeromask = {};
+#endif
+
#endif /* _IP_SET_HASH_GEN_H */
#ifndef MTYPE
@@ -307,8 +295,9 @@ struct htype {
u32 markmask; /* markmask value for mark mask to store */
#endif
u8 bucketsize; /* max elements in an array block */
-#ifdef IP_SET_HASH_WITH_NETMASK
+#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK)
u8 netmask; /* netmask value for subnets to store */
+ union nf_inet_addr bitmask; /* stores bitmask */
#endif
struct list_head ad; /* Resize add|del backlist */
struct mtype_elem next; /* temporary storage for uadd */
@@ -483,8 +472,8 @@ mtype_same_set(const struct ip_set *a, const struct ip_set *b)
/* Resizing changes htable_bits, so we ignore it */
return x->maxelem == y->maxelem &&
a->timeout == b->timeout &&
-#ifdef IP_SET_HASH_WITH_NETMASK
- x->netmask == y->netmask &&
+#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK)
+ nf_inet_addr_cmp(&x->bitmask, &y->bitmask) &&
#endif
#ifdef IP_SET_HASH_WITH_MARKMASK
x->markmask == y->markmask &&
@@ -937,7 +926,12 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
goto set_full;
/* Create a new slot */
if (n->pos >= n->size) {
- TUNE_BUCKETSIZE(h, multi);
+#ifdef IP_SET_HASH_WITH_MULTI
+ if (h->bucketsize >= AHASH_MAX_TUNED)
+ goto set_full;
+ else if (h->bucketsize <= multi)
+ h->bucketsize += AHASH_INIT_SIZE;
+#endif
if (n->size >= AHASH_MAX(h)) {
/* Trigger rehashing */
mtype_data_next(&h->next, d);
@@ -1283,9 +1277,21 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
htonl(jhash_size(htable_bits))) ||
nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))
goto nla_put_failure;
+#ifdef IP_SET_HASH_WITH_BITMASK
+ /* if netmask is set to anything other than HOST_MASK we know that the user supplied netmask
+ * and not bitmask. These two are mutually exclusive. */
+ if (h->netmask == HOST_MASK && !nf_inet_addr_cmp(&onesmask, &h->bitmask)) {
+ if (set->family == NFPROTO_IPV4) {
+ if (nla_put_ipaddr4(skb, IPSET_ATTR_BITMASK, h->bitmask.ip))
+ goto nla_put_failure;
+ } else if (set->family == NFPROTO_IPV6) {
+ if (nla_put_ipaddr6(skb, IPSET_ATTR_BITMASK, &h->bitmask.in6))
+ goto nla_put_failure;
+ }
+ }
+#endif
#ifdef IP_SET_HASH_WITH_NETMASK
- if (h->netmask != HOST_MASK &&
- nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))
+ if (h->netmask != HOST_MASK && nla_put_u8(skb, IPSET_ATTR_NETMASK, h->netmask))
goto nla_put_failure;
#endif
#ifdef IP_SET_HASH_WITH_MARKMASK
@@ -1448,8 +1454,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
u32 markmask;
#endif
u8 hbits;
-#ifdef IP_SET_HASH_WITH_NETMASK
- u8 netmask;
+#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK)
+ int ret __attribute__((unused)) = 0;
+ u8 netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
+ union nf_inet_addr bitmask = onesmask;
#endif
size_t hsize;
struct htype *h;
@@ -1487,7 +1495,6 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
#endif
#ifdef IP_SET_HASH_WITH_NETMASK
- netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
if (tb[IPSET_ATTR_NETMASK]) {
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
@@ -1495,6 +1502,33 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
(set->family == NFPROTO_IPV6 && netmask > 128) ||
netmask == 0)
return -IPSET_ERR_INVALID_NETMASK;
+
+ /* we convert netmask to bitmask and store it */
+ if (set->family == NFPROTO_IPV4)
+ bitmask.ip = ip_set_netmask(netmask);
+ else
+ ip6_netmask(&bitmask, netmask);
+ }
+#endif
+
+#ifdef IP_SET_HASH_WITH_BITMASK
+ if (tb[IPSET_ATTR_BITMASK]) {
+ /* bitmask and netmask do the same thing, allow only one of these options */
+ if (tb[IPSET_ATTR_NETMASK])
+ return -IPSET_ERR_BITMASK_NETMASK_EXCL;
+
+ if (set->family == NFPROTO_IPV4) {
+ ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_BITMASK], &bitmask.ip);
+ if (ret || !bitmask.ip)
+ return -IPSET_ERR_INVALID_NETMASK;
+ } else if (set->family == NFPROTO_IPV6) {
+ ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_BITMASK], &bitmask);
+ if (ret || ipv6_addr_any(&bitmask.in6))
+ return -IPSET_ERR_INVALID_NETMASK;
+ }
+
+ if (nf_inet_addr_cmp(&bitmask, &zeromask))
+ return -IPSET_ERR_INVALID_NETMASK;
}
#endif
@@ -1537,7 +1571,8 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
for (i = 0; i < ahash_numof_locks(hbits); i++)
spin_lock_init(&t->hregion[i].lock);
h->maxelem = maxelem;
-#ifdef IP_SET_HASH_WITH_NETMASK
+#if defined(IP_SET_HASH_WITH_NETMASK) || defined(IP_SET_HASH_WITH_BITMASK)
+ h->bitmask = bitmask;
h->netmask = netmask;
#endif
#ifdef IP_SET_HASH_WITH_MARKMASK
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ip.c b/kernel/net/netfilter/ipset/ip_set_hash_ip.c
index baa5e14..be11354 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ip.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ip.c
@@ -25,7 +25,8 @@
/* 2 Comments support */
/* 3 Forceadd support */
/* 4 skbinfo support */
-#define IPSET_TYPE_REV_MAX 5 /* bucketsize, initval support */
+/* 5 bucketsize, initval support */
+#define IPSET_TYPE_REV_MAX 6 /* bitmask support */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
@@ -35,6 +36,7 @@ MODULE_ALIAS("ip_set_hash:ip");
/* Type specific function prefix */
#define HTYPE hash_ip
#define IP_SET_HASH_WITH_NETMASK
+#define IP_SET_HASH_WITH_BITMASK
/* IPv4 variant */
@@ -87,7 +89,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
__be32 ip;
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
- ip &= ip_set_netmask(h->netmask);
+ ip &= h->bitmask.ip;
if (ip == 0)
return -EINVAL;
@@ -120,7 +122,7 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (ret)
return ret;
- ip &= ip_set_hostmask(h->netmask);
+ ip &= ntohl(h->bitmask.ip);
e.ip = htonl(ip);
if (e.ip == 0)
return -IPSET_ERR_HASH_ELEM;
@@ -152,18 +154,16 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
if (((u64)ip_to - ip + 1) >> (32 - h->netmask) > IPSET_MAX_RANGE)
return -ERANGE;
- if (retried) {
+ if (retried)
ip = ntohl(h->next.ip);
- e.ip = htonl(ip);
- }
for (; ip <= ip_to;) {
+ e.ip = htonl(ip);
ret = adtfn(set, &e, &ext, &ext, flags);
if (ret && !ip_set_eexist(ret, flags))
return ret;
ip += hosts;
- e.ip = htonl(ip);
- if (e.ip == 0)
+ if (ip == 0)
return 0;
ret = 0;
@@ -188,12 +188,6 @@ hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
return ipv6_addr_equal(&ip1->ip.in6, &ip2->ip.in6);
}
-static void
-hash_ip6_netmask(union nf_inet_addr *ip, u8 prefix)
-{
- ip6_netmask(ip, prefix);
-}
-
static bool
hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *e)
{
@@ -230,7 +224,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
- hash_ip6_netmask(&e.ip, h->netmask);
+ nf_inet_addr_mask_inplace(&e.ip, &h->bitmask);
if (ipv6_addr_any(&e.ip.in6))
return -EINVAL;
@@ -269,7 +263,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
if (ret)
return ret;
- hash_ip6_netmask(&e.ip, h->netmask);
+ nf_inet_addr_mask_inplace(&e.ip, &h->bitmask);
if (ipv6_addr_any(&e.ip.in6))
return -IPSET_ERR_HASH_ELEM;
@@ -296,6 +290,7 @@ static struct ip_set_type hash_ip_type __read_mostly = {
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
+ [IPSET_ATTR_BITMASK] = { .type = NLA_NESTED },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
},
.adt_policy = {
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_ipport.c b/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
index 09837c3..5ca5df9 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_ipport.c
@@ -27,7 +27,8 @@
/* 3 Comments support added */
/* 4 Forceadd support added */
/* 5 skbinfo support added */
-#define IPSET_TYPE_REV_MAX 6 /* bucketsize, initval support added */
+/* 6 bucketsize, initval support added */
+#define IPSET_TYPE_REV_MAX 7 /* bitmask support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
@@ -36,6 +37,8 @@ MODULE_ALIAS("ip_set_hash:ip,port");
/* Type specific function prefix */
#define HTYPE hash_ipport
+#define IP_SET_HASH_WITH_NETMASK
+#define IP_SET_HASH_WITH_BITMASK
/* IPv4 variant */
@@ -93,12 +96,16 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport4_elem e = { .ip = 0 };
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ const struct MTYPE *h = set->data;
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&e.port, &e.proto))
return -EINVAL;
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
+ e.ip &= h->bitmask.ip;
+ if (e.ip == 0)
+ return -EINVAL;
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
@@ -130,6 +137,10 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
if (ret)
return ret;
+ e.ip &= h->bitmask.ip;
+ if (e.ip == 0)
+ return -EINVAL;
+
e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
if (tb[IPSET_ATTR_PROTO]) {
@@ -254,12 +265,17 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_ipport6_elem e = { .ip = { .all = { 0 } } };
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
+ const struct MTYPE *h = set->data;
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
&e.port, &e.proto))
return -EINVAL;
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
+ nf_inet_addr_mask_inplace(&e.ip, &h->bitmask);
+ if (ipv6_addr_any(&e.ip.in6))
+ return -EINVAL;
+
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
@@ -299,6 +315,10 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
if (ret)
return ret;
+ nf_inet_addr_mask_inplace(&e.ip, &h->bitmask);
+ if (ipv6_addr_any(&e.ip.in6))
+ return -EINVAL;
+
e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
if (tb[IPSET_ATTR_PROTO]) {
@@ -357,6 +377,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+ [IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
+ [IPSET_ATTR_BITMASK] = { .type = NLA_NESTED },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
diff --git a/kernel/net/netfilter/ipset/ip_set_hash_netnet.c b/kernel/net/netfilter/ipset/ip_set_hash_netnet.c
index 3d09eef..cdfb78c 100644
--- a/kernel/net/netfilter/ipset/ip_set_hash_netnet.c
+++ b/kernel/net/netfilter/ipset/ip_set_hash_netnet.c
@@ -23,7 +23,8 @@
#define IPSET_TYPE_REV_MIN 0
/* 1 Forceadd support added */
/* 2 skbinfo support added */
-#define IPSET_TYPE_REV_MAX 3 /* bucketsize, initval support added */
+/* 3 bucketsize, initval support added */
+#define IPSET_TYPE_REV_MAX 4 /* bitmask support added */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
@@ -33,6 +34,8 @@ MODULE_ALIAS("ip_set_hash:net,net");
/* Type specific function prefix */
#define HTYPE hash_netnet
#define IP_SET_HASH_WITH_NETS
+#define IP_SET_HASH_WITH_NETMASK
+#define IP_SET_HASH_WITH_BITMASK
#define IPSET_NET_COUNT 2
/* IPv4 variants */
@@ -153,8 +156,8 @@ hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0]);
ip4addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1]);
- e.ip[0] &= ip_set_netmask(e.cidr[0]);
- e.ip[1] &= ip_set_netmask(e.cidr[1]);
+ e.ip[0] &= (ip_set_netmask(e.cidr[0]) & h->bitmask.ip);
+ e.ip[1] &= (ip_set_netmask(e.cidr[1]) & h->bitmask.ip);
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
@@ -213,8 +216,8 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
if (adt == IPSET_TEST || !(tb[IPSET_ATTR_IP_TO] ||
tb[IPSET_ATTR_IP2_TO])) {
- e.ip[0] = htonl(ip & ip_set_hostmask(e.cidr[0]));
- e.ip[1] = htonl(ip2_from & ip_set_hostmask(e.cidr[1]));
+ e.ip[0] = htonl(ip & ntohl(h->bitmask.ip) & ip_set_hostmask(e.cidr[0]));
+ e.ip[1] = htonl(ip2_from & ntohl(h->bitmask.ip) & ip_set_hostmask(e.cidr[1]));
ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_enomatch(ret, flags, adt, set) ? -ret :
ip_set_eexist(ret, flags) ? 0 : ret;
@@ -404,6 +407,11 @@ hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
ip6_netmask(&e.ip[0], e.cidr[0]);
ip6_netmask(&e.ip[1], e.cidr[1]);
+ nf_inet_addr_mask_inplace(&e.ip[0], &h->bitmask);
+ nf_inet_addr_mask_inplace(&e.ip[1], &h->bitmask);
+ if (e.cidr[0] == HOST_MASK && ipv6_addr_any(&e.ip[0].in6))
+ return -EINVAL;
+
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
@@ -414,6 +422,7 @@ hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[],
ipset_adtfn adtfn = set->variant->adt[adt];
struct hash_netnet6_elem e = { };
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
+ const struct hash_netnet6 *h = set->data;
int ret;
if (tb[IPSET_ATTR_LINENO])
@@ -453,6 +462,11 @@ hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[],
ip6_netmask(&e.ip[0], e.cidr[0]);
ip6_netmask(&e.ip[1], e.cidr[1]);
+ nf_inet_addr_mask_inplace(&e.ip[0], &h->bitmask);
+ nf_inet_addr_mask_inplace(&e.ip[1], &h->bitmask);
+ if (e.cidr[0] == HOST_MASK && ipv6_addr_any(&e.ip[0].in6))
+ return -IPSET_ERR_HASH_ELEM;
+
if (tb[IPSET_ATTR_CADT_FLAGS]) {
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
@@ -484,6 +498,8 @@ static struct ip_set_type hash_netnet_type __read_mostly = {
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
+ [IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
+ [IPSET_ATTR_BITMASK] = { .type = NLA_NESTED },
},
.adt_policy = {
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
diff --git a/kernel/net/sched/em_ipset.c b/kernel/net/sched/em_ipset.c
index 96fd4a3..5428f8d 100644
--- a/kernel/net/sched/em_ipset.c
+++ b/kernel/net/sched/em_ipset.c
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* net/sched/em_ipset.c ipset ematch
*
* Copyright (c) 2012 Florian Westphal <fw@strlen.de>
- *
- * 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.
*/
#include <linux/gfp.h>
@@ -87,7 +84,7 @@ static int em_ipset_match(struct sk_buff *skb, struct tcf_ematch *em,
#else
#define ACPAR_FAMILY(f) acpar.family = f
#endif
- switch (tc_skb_protocol(skb)) {
+ switch (skb_protocol(skb, true)) {
case htons(ETH_P_IP):
ACPAR_FAMILY(NFPROTO_IPV4);
if (!pskb_network_may_pull(skb, sizeof(struct iphdr)))
diff --git a/lib/args.c b/lib/args.c
index bab3b13..e47105c 100644
--- a/lib/args.c
+++ b/lib/args.c
@@ -300,6 +300,14 @@ static const struct ipset_arg ipset_args[] = {
.print = ipset_print_hexnumber,
.help = "[initval VALUE]",
},
+ [IPSET_ARG_BITMASK] = {
+ .name = { "bitmask", NULL },
+ .has_arg = IPSET_MANDATORY_ARG,
+ .opt = IPSET_OPT_BITMASK,
+ .parse = ipset_parse_bitmask,
+ .print = ipset_print_ip,
+ .help = "[bitmask bitmask]",
+ },
};
const struct ipset_arg *
diff --git a/lib/data.c b/lib/data.c
index 7720178..72f1330 100644
--- a/lib/data.c
+++ b/lib/data.c
@@ -53,6 +53,7 @@ struct ipset_data {
uint8_t bucketsize;
uint8_t resize;
uint8_t netmask;
+ union nf_inet_addr bitmask;
uint32_t hashsize;
uint32_t maxelem;
uint32_t markmask;
@@ -301,6 +302,12 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
case IPSET_OPT_NETMASK:
data->create.netmask = *(const uint8_t *) value;
break;
+ case IPSET_OPT_BITMASK:
+ if (!(data->family == NFPROTO_IPV4 ||
+ data->family == NFPROTO_IPV6))
+ return -1;
+ copy_addr(data->family, &data->create.bitmask, value);
+ break;
case IPSET_OPT_BUCKETSIZE:
data->create.bucketsize = *(const uint8_t *) value;
break;
@@ -508,6 +515,8 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
return &data->create.markmask;
case IPSET_OPT_NETMASK:
return &data->create.netmask;
+ case IPSET_OPT_BITMASK:
+ return &data->create.bitmask;
case IPSET_OPT_BUCKETSIZE:
return &data->create.bucketsize;
case IPSET_OPT_RESIZE:
@@ -594,6 +603,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
case IPSET_OPT_IP_TO:
case IPSET_OPT_IP2:
case IPSET_OPT_IP2_TO:
+ case IPSET_OPT_BITMASK:
return family == NFPROTO_IPV4 ? sizeof(uint32_t)
: sizeof(struct in6_addr);
case IPSET_OPT_MARK:
diff --git a/lib/debug.c b/lib/debug.c
index bf57a41..dbc5cfb 100644
--- a/lib/debug.c
+++ b/lib/debug.c
@@ -40,6 +40,7 @@ static const struct ipset_attrname createattr2name[] = {
[IPSET_ATTR_MAXELEM] = { .name = "MAXELEM" },
[IPSET_ATTR_MARKMASK] = { .name = "MARKMASK" },
[IPSET_ATTR_NETMASK] = { .name = "NETMASK" },
+ [IPSET_ATTR_BITMASK] = { .name = "BITMASK" },
[IPSET_ATTR_BUCKETSIZE] = { .name = "BUCKETSIZE" },
[IPSET_ATTR_RESIZE] = { .name = "RESIZE" },
[IPSET_ATTR_SIZE] = { .name = "SIZE" },
diff --git a/lib/errcode.c b/lib/errcode.c
index 76bab74..49c97a1 100644
--- a/lib/errcode.c
+++ b/lib/errcode.c
@@ -44,6 +44,8 @@ static const struct ipset_errcode_table core_errcode_table[] = {
"The value of the markmask parameter is invalid" },
{ IPSET_ERR_INVALID_FAMILY, 0,
"Protocol family not supported by the set type" },
+ { IPSET_ERR_BITMASK_NETMASK_EXCL, 0,
+ "netmask and bitmask options are mutually exclusive, provide only one" },
/* DESTROY specific error codes */
{ IPSET_ERR_BUSY, IPSET_CMD_DESTROY,
diff --git a/lib/ipset.c b/lib/ipset.c
index 50f86ae..f57b074 100644
--- a/lib/ipset.c
+++ b/lib/ipset.c
@@ -30,6 +30,7 @@
#include <libipset/ipset.h> /* prototypes */
#include <libipset/ip_set_compiler.h> /* compiler attributes */
#include <libipset/list_sort.h> /* lists */
+#include <libipset/xlate.h> /* ipset_xlate_argv */
static char program_name[] = PACKAGE;
static char program_version[] = PACKAGE_VERSION;
@@ -936,10 +937,10 @@ static const char *cmd_prefix[] = {
[IPSET_TEST] = "test SETNAME",
};
-static const struct ipset_xlate_set *
+static struct ipset_xlate_set *
ipset_xlate_set_get(struct ipset *ipset, const char *name)
{
- const struct ipset_xlate_set *set;
+ struct ipset_xlate_set *set;
list_for_each_entry(set, &ipset->xlate_sets, list) {
if (!strcmp(set->name, name))
@@ -958,7 +959,7 @@ ipset_parser(struct ipset *ipset, int oargc, char *oargv[])
char *arg0 = NULL, *arg1 = NULL;
const struct ipset_envopts *opt;
const struct ipset_commands *command;
- const struct ipset_type *type;
+ const struct ipset_type *type = NULL;
struct ipset_session *session = ipset->session;
void *p = ipset_session_printf_private(session);
int argc = oargc;
@@ -1127,6 +1128,7 @@ ipset_parser(struct ipset *ipset, int oargc, char *oargv[])
if (arg0) {
const struct ipset_arg *arg;
int k;
+ enum ipset_adt c;
/* Type-specific help, without kernel checking */
type = type_find(arg0);
@@ -1136,11 +1138,11 @@ ipset_parser(struct ipset *ipset, int oargc, char *oargv[])
"Unknown settype: `%s'", arg0);
printf("\n%s type specific options:\n\n", type->name);
for (i = 0; cmd_help_order[i] != IPSET_CADT_MAX; i++) {
- cmd = cmd_help_order[i];
+ c = cmd_help_order[i];
printf("%s %s %s\n",
- cmd_prefix[cmd], type->name, type->cmd[cmd].help);
- for (k = 0; type->cmd[cmd].args[k] != IPSET_ARG_NONE; k++) {
- arg = ipset_keyword(type->cmd[cmd].args[k]);
+ cmd_prefix[c], type->name, type->cmd[c].help);
+ for (k = 0; type->cmd[c].args[k] != IPSET_ARG_NONE; k++) {
+ arg = ipset_keyword(type->cmd[c].args[k]);
if (!arg->help || arg->help[0] == '\0')
continue;
printf(" %s\n", arg->help);
@@ -1548,7 +1550,7 @@ ipset_fini(struct ipset *ipset)
}
/* Ignore the set family, use inet. */
-static const char *ipset_xlate_family(uint8_t family)
+static const char *ipset_xlate_family(uint8_t family UNUSED)
{
return "inet";
}
@@ -1705,6 +1707,10 @@ ipset_xlate_type_to_nftables(int family, enum ipset_xlate_set_type type,
else if (family == AF_INET6)
return "ipv6_addr";
break;
+ case IPSET_XLATE_TYPE_UNKNOWN:
+ break;
+ default:
+ break;
}
/* This should not ever happen. */
return "unknown";
@@ -1729,7 +1735,6 @@ static int ipset_xlate(struct ipset *ipset, enum ipset_cmd cmd,
char buf[64];
bool concat;
char *term;
- int i;
session = ipset_session(ipset);
data = ipset_session_data(session);
@@ -1843,7 +1848,7 @@ static int ipset_xlate(struct ipset *ipset, enum ipset_cmd cmd,
return -1;
case IPSET_CMD_LIST:
if (!set) {
- printf("list sets %s\n",
+ printf("list sets %s %s\n",
ipset_xlate_family(family), table);
} else {
printf("list set %s %s %s\n",
@@ -1902,6 +1907,8 @@ static int ipset_xlate(struct ipset *ipset, enum ipset_cmd cmd,
}
if (ipset_data_test(data, IPSET_OPT_ETHER)) {
ipset_print_ether(buf, sizeof(buf), data, IPSET_OPT_ETHER, 0);
+ size_t i;
+
for (i = 0; i < strlen(buf); i++)
buf[i] = tolower(buf[i]);
@@ -1964,7 +1971,6 @@ static int ipset_xlate_restore(struct ipset *ipset)
struct ipset_session *session = ipset_session(ipset);
struct ipset_data *data = ipset_session_data(session);
void *p = ipset_session_printf_private(session);
- const char *filename;
enum ipset_cmd cmd;
FILE *f = stdin;
int ret = 0;
@@ -1973,7 +1979,7 @@ static int ipset_xlate_restore(struct ipset *ipset)
if (ipset->filename) {
f = fopen(ipset->filename, "r");
if (!f) {
- fprintf(stderr, "cannot open file `%s'\n", filename);
+ fprintf(stderr, "cannot open file `%s'\n", ipset->filename);
return -1;
}
}
@@ -2007,7 +2013,7 @@ static int ipset_xlate_restore(struct ipset *ipset)
ipset_data_reset(data);
}
- if (filename)
+ if (ipset->filename)
fclose(f);
return ret;
diff --git a/lib/ipset_hash_ip.c b/lib/ipset_hash_ip.c
index ea85700..4f96ebb 100644
--- a/lib/ipset_hash_ip.c
+++ b/lib/ipset_hash_ip.c
@@ -477,6 +477,91 @@ static struct ipset_type ipset_hash_ip5 = {
.description = "bucketsize, initval support",
};
+/* bitmask support */
+static struct ipset_type ipset_hash_ip6 = {
+ .name = "hash:ip",
+ .alias = { "iphash", NULL },
+ .revision = 6,
+ .family = NFPROTO_IPSET_IPV46,
+ .dimension = IPSET_DIM_ONE,
+ .elem = {
+ [IPSET_DIM_ONE - 1] = {
+ .parse = ipset_parse_ip4_single6,
+ .print = ipset_print_ip,
+ .opt = IPSET_OPT_IP
+ },
+ },
+ .cmd = {
+ [IPSET_CREATE] = {
+ .args = {
+ IPSET_ARG_FAMILY,
+ /* Aliases */
+ IPSET_ARG_INET,
+ IPSET_ARG_INET6,
+ IPSET_ARG_HASHSIZE,
+ IPSET_ARG_MAXELEM,
+ IPSET_ARG_NETMASK,
+ IPSET_ARG_BITMASK,
+ IPSET_ARG_TIMEOUT,
+ IPSET_ARG_COUNTERS,
+ IPSET_ARG_COMMENT,
+ IPSET_ARG_FORCEADD,
+ IPSET_ARG_SKBINFO,
+ IPSET_ARG_BUCKETSIZE,
+ IPSET_ARG_INITVAL,
+ /* Ignored options: backward compatibilty */
+ IPSET_ARG_PROBES,
+ IPSET_ARG_RESIZE,
+ IPSET_ARG_GC,
+ IPSET_ARG_NONE,
+ },
+ .need = 0,
+ .full = 0,
+ .help = "",
+ },
+ [IPSET_ADD] = {
+ .args = {
+ IPSET_ARG_TIMEOUT,
+ IPSET_ARG_PACKETS,
+ IPSET_ARG_BYTES,
+ IPSET_ARG_ADT_COMMENT,
+ IPSET_ARG_SKBMARK,
+ IPSET_ARG_SKBPRIO,
+ IPSET_ARG_SKBQUEUE,
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP_TO),
+ .help = "IP",
+ },
+ [IPSET_DEL] = {
+ .args = {
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP_TO),
+ .help = "IP",
+ },
+ [IPSET_TEST] = {
+ .args = {
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP_TO),
+ .help = "IP",
+ },
+ },
+ .usage = "where depending on the INET family\n"
+ " IP is a valid IPv4 or IPv6 address (or hostname),\n"
+ " CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+ " Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+ " is supported for IPv4.",
+ .description = "bitmask support",
+};
+
void _init(void);
void _init(void)
{
@@ -486,4 +571,5 @@ void _init(void)
ipset_type_add(&ipset_hash_ip3);
ipset_type_add(&ipset_hash_ip4);
ipset_type_add(&ipset_hash_ip5);
+ ipset_type_add(&ipset_hash_ip6);
}
diff --git a/lib/ipset_hash_ipport.c b/lib/ipset_hash_ipport.c
index 288be10..2fa8abd 100644
--- a/lib/ipset_hash_ipport.c
+++ b/lib/ipset_hash_ipport.c
@@ -604,6 +604,113 @@ static struct ipset_type ipset_hash_ipport6 = {
.description = "bucketsize, initval support",
};
+/* bitmask support */
+static struct ipset_type ipset_hash_ipport7 = {
+ .name = "hash:ip,port",
+ .alias = { "ipporthash", NULL },
+ .revision = 7,
+ .family = NFPROTO_IPSET_IPV46,
+ .dimension = IPSET_DIM_TWO,
+ .elem = {
+ [IPSET_DIM_ONE - 1] = {
+ .parse = ipset_parse_ip4_single6,
+ .print = ipset_print_ip,
+ .opt = IPSET_OPT_IP
+ },
+ [IPSET_DIM_TWO - 1] = {
+ .parse = ipset_parse_proto_port,
+ .print = ipset_print_proto_port,
+ .opt = IPSET_OPT_PORT
+ },
+ },
+ .cmd = {
+ [IPSET_CREATE] = {
+ .args = {
+ IPSET_ARG_FAMILY,
+ /* Aliases */
+ IPSET_ARG_INET,
+ IPSET_ARG_INET6,
+ IPSET_ARG_HASHSIZE,
+ IPSET_ARG_MAXELEM,
+ IPSET_ARG_TIMEOUT,
+ IPSET_ARG_COUNTERS,
+ IPSET_ARG_COMMENT,
+ IPSET_ARG_FORCEADD,
+ IPSET_ARG_SKBINFO,
+ IPSET_ARG_BUCKETSIZE,
+ IPSET_ARG_INITVAL,
+ IPSET_ARG_NETMASK,
+ IPSET_ARG_BITMASK,
+ /* Ignored options: backward compatibilty */
+ IPSET_ARG_PROBES,
+ IPSET_ARG_RESIZE,
+ IPSET_ARG_IGNORED_FROM,
+ IPSET_ARG_IGNORED_TO,
+ IPSET_ARG_IGNORED_NETWORK,
+ IPSET_ARG_NONE,
+ },
+ .need = 0,
+ .full = 0,
+ .help = "",
+ },
+ [IPSET_ADD] = {
+ .args = {
+ IPSET_ARG_TIMEOUT,
+ IPSET_ARG_PACKETS,
+ IPSET_ARG_BYTES,
+ IPSET_ARG_ADT_COMMENT,
+ IPSET_ARG_SKBMARK,
+ IPSET_ARG_SKBPRIO,
+ IPSET_ARG_SKBQUEUE,
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
+ | IPSET_FLAG(IPSET_OPT_PORT),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP_TO)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
+ | IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PORT_TO),
+ .help = "IP,[PROTO:]PORT",
+ },
+ [IPSET_DEL] = {
+ .args = {
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
+ | IPSET_FLAG(IPSET_OPT_PORT),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP_TO)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
+ | IPSET_FLAG(IPSET_OPT_PORT)
+ | IPSET_FLAG(IPSET_OPT_PORT_TO),
+ .help = "IP,[PROTO:]PORT",
+ },
+ [IPSET_TEST] = {
+ .args = {
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
+ | IPSET_FLAG(IPSET_OPT_PORT),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_PROTO)
+ | IPSET_FLAG(IPSET_OPT_PORT),
+ .help = "IP,[PROTO:]PORT",
+ },
+ },
+ .usage = "where depending on the INET family\n"
+ " IP is a valid IPv4 or IPv6 address (or hostname).\n"
+ " Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
+ " is supported for IPv4.\n"
+ " Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
+ " port range is supported both for IPv4 and IPv6.",
+ .usagefn = ipset_port_usage,
+ .description = "netmask and bitmask support",
+};
+
void _init(void);
void _init(void)
{
@@ -613,4 +720,5 @@ void _init(void)
ipset_type_add(&ipset_hash_ipport4);
ipset_type_add(&ipset_hash_ipport5);
ipset_type_add(&ipset_hash_ipport6);
+ ipset_type_add(&ipset_hash_ipport7);
}
diff --git a/lib/ipset_hash_netnet.c b/lib/ipset_hash_netnet.c
index df993b8..0e176e3 100644
--- a/lib/ipset_hash_netnet.c
+++ b/lib/ipset_hash_netnet.c
@@ -387,6 +387,106 @@ static struct ipset_type ipset_hash_netnet3 = {
.description = "bucketsize, initval support",
};
+/* bitmask support */
+static struct ipset_type ipset_hash_netnet4 = {
+ .name = "hash:net,net",
+ .alias = { "netnethash", NULL },
+ .revision = 4,
+ .family = NFPROTO_IPSET_IPV46,
+ .dimension = IPSET_DIM_TWO,
+ .elem = {
+ [IPSET_DIM_ONE - 1] = {
+ .parse = ipset_parse_ip4_net6,
+ .print = ipset_print_ip,
+ .opt = IPSET_OPT_IP
+ },
+ [IPSET_DIM_TWO - 1] = {
+ .parse = ipset_parse_ip4_net6,
+ .print = ipset_print_ip,
+ .opt = IPSET_OPT_IP2
+ },
+ },
+ .cmd = {
+ [IPSET_CREATE] = {
+ .args = {
+ IPSET_ARG_FAMILY,
+ /* Aliases */
+ IPSET_ARG_INET,
+ IPSET_ARG_INET6,
+ IPSET_ARG_HASHSIZE,
+ IPSET_ARG_MAXELEM,
+ IPSET_ARG_TIMEOUT,
+ IPSET_ARG_COUNTERS,
+ IPSET_ARG_COMMENT,
+ IPSET_ARG_FORCEADD,
+ IPSET_ARG_SKBINFO,
+ IPSET_ARG_BUCKETSIZE,
+ IPSET_ARG_INITVAL,
+ IPSET_ARG_BITMASK,
+ IPSET_ARG_NETMASK,
+ IPSET_ARG_NONE,
+ },
+ .need = 0,
+ .full = 0,
+ .help = "",
+ },
+ [IPSET_ADD] = {
+ .args = {
+ IPSET_ARG_TIMEOUT,
+ IPSET_ARG_NOMATCH,
+ IPSET_ARG_PACKETS,
+ IPSET_ARG_BYTES,
+ IPSET_ARG_ADT_COMMENT,
+ IPSET_ARG_SKBMARK,
+ IPSET_ARG_SKBPRIO,
+ IPSET_ARG_SKBQUEUE,
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP2),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_CIDR)
+ | IPSET_FLAG(IPSET_OPT_IP_TO)
+ | IPSET_FLAG(IPSET_OPT_IP2)
+ | IPSET_FLAG(IPSET_OPT_CIDR2)
+ | IPSET_FLAG(IPSET_OPT_IP2_TO),
+ .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+ },
+ [IPSET_DEL] = {
+ .args = {
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP2),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_CIDR)
+ | IPSET_FLAG(IPSET_OPT_IP_TO)
+ | IPSET_FLAG(IPSET_OPT_IP2)
+ | IPSET_FLAG(IPSET_OPT_CIDR2)
+ | IPSET_FLAG(IPSET_OPT_IP2_TO),
+ .help = "IP[/CIDR]|FROM-TO,IP[/CIDR]|FROM-TO",
+ },
+ [IPSET_TEST] = {
+ .args = {
+ IPSET_ARG_NOMATCH,
+ IPSET_ARG_NONE,
+ },
+ .need = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_IP2),
+ .full = IPSET_FLAG(IPSET_OPT_IP)
+ | IPSET_FLAG(IPSET_OPT_CIDR)
+ | IPSET_FLAG(IPSET_OPT_IP2)
+ | IPSET_FLAG(IPSET_OPT_CIDR2),
+ .help = "IP[/CIDR],IP[/CIDR]",
+ },
+ },
+ .usage = "where depending on the INET family\n"
+ " IP is an IPv4 or IPv6 address (or hostname),\n"
+ " CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
+ " IP range is not supported with IPv6.",
+ .description = "netmask and bitmask support",
+};
+
void _init(void);
void _init(void)
{
@@ -394,4 +494,5 @@ void _init(void)
ipset_type_add(&ipset_hash_netnet1);
ipset_type_add(&ipset_hash_netnet2);
ipset_type_add(&ipset_hash_netnet3);
+ ipset_type_add(&ipset_hash_netnet4);
}
diff --git a/lib/libipset.map b/lib/libipset.map
index c380f9c..c69b738 100644
--- a/lib/libipset.map
+++ b/lib/libipset.map
@@ -213,3 +213,7 @@ global:
ipset_xlate_argv;
} LIBIPSET_4.10;
+LIBIPSET_4.12 {
+global:
+ ipset_parse_bitmask;
+} LIBIPSET_4.10;
diff --git a/lib/parse.c b/lib/parse.c
index 974eaf8..4d2d8b3 100644
--- a/lib/parse.c
+++ b/lib/parse.c
@@ -280,7 +280,8 @@ static int
parse_portname(struct ipset_session *session, const char *str,
uint16_t *port, const char *proto)
{
- char *saved, *tmp, *protoname;
+ char *saved, *tmp;
+ const char *protoname;
const struct protoent *protoent;
struct servent *service;
uint8_t protonum = 0;
@@ -292,7 +293,7 @@ parse_portname(struct ipset_session *session, const char *str,
if (tmp == NULL)
goto error;
- protoname = (char *)proto;
+ protoname = proto;
if (string_to_u8(session, proto, &protonum, IPSET_WARNING) == 0) {
protoent = getprotobynumber(protonum);
if (protoent == NULL)
@@ -1703,6 +1704,9 @@ ipset_parse_netmask(struct ipset_session *session,
assert(str);
data = ipset_session_data(session);
+ if (ipset_data_test(data, IPSET_OPT_BITMASK))
+ return syntax_err("bitmask and netmask are mutually exclusive, provide only one");
+
family = ipset_data_family(data);
if (family == NFPROTO_UNSPEC) {
family = NFPROTO_IPV4;
@@ -1722,6 +1726,46 @@ ipset_parse_netmask(struct ipset_session *session,
}
/**
+ * ipset_parse_bitmask - parse string as a bitmask
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a bitmask value, depending on family type.
+ * If family is not set yet, INET is assumed.
+ * The value is stored in the data blob of the session.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_bitmask(struct ipset_session *session,
+ enum ipset_opt opt, const char *str)
+{
+ uint8_t family;
+ struct ipset_data *data;
+
+ assert(session);
+ assert(opt == IPSET_OPT_BITMASK);
+ assert(str);
+
+ data = ipset_session_data(session);
+ if (ipset_data_test(data, IPSET_OPT_NETMASK))
+ return syntax_err("bitmask and netmask are mutually exclusive, provide only one");
+
+ family = ipset_data_family(data);
+ if (family == NFPROTO_UNSPEC) {
+ family = NFPROTO_IPV4;
+ ipset_data_set(data, IPSET_OPT_FAMILY, &family);
+ }
+
+ if (parse_ipaddr(session, opt, str, family))
+ return syntax_err("bitmask is not valid for family = %s",
+ family == NFPROTO_IPV4 ? "inet" : "inet6");
+
+ return 0;
+}
+
+/**
* ipset_parse_flag - "parse" option flags
* @session: session structure
* @opt: option kind of the data
diff --git a/lib/print.c b/lib/print.c
index a7ffd81..50f0ad6 100644
--- a/lib/print.c
+++ b/lib/print.c
@@ -265,7 +265,7 @@ ipset_print_ip(char *buf, unsigned int len,
assert(buf);
assert(len > 0);
assert(data);
- assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
+ assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2 || opt == IPSET_OPT_BITMASK);
D("len: %u", len);
family = ipset_data_family(data);
@@ -976,6 +976,7 @@ ipset_print_data(char *buf, unsigned int len,
size = ipset_print_elem(buf, len, data, opt, env);
break;
case IPSET_OPT_IP:
+ case IPSET_OPT_BITMASK:
size = ipset_print_ip(buf, len, data, opt, env);
break;
case IPSET_OPT_PORT:
diff --git a/lib/session.c b/lib/session.c
index 1ca26ff..cdc59e0 100644
--- a/lib/session.c
+++ b/lib/session.c
@@ -462,6 +462,10 @@ static const struct ipset_attr_policy create_attrs[] = {
.type = MNL_TYPE_U32,
.opt = IPSET_OPT_MEMSIZE,
},
+ [IPSET_ATTR_BITMASK] = {
+ .type = MNL_TYPE_NESTED,
+ .opt = IPSET_OPT_BITMASK,
+ },
};
static const struct ipset_attr_policy adt_attrs[] = {
@@ -1721,6 +1725,10 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
if (attr->type == MNL_TYPE_NESTED) {
/* IP addresses */
struct nlattr *nested;
+
+ if (type == IPSET_ATTR_BITMASK)
+ family = ipset_data_family(session->data);
+
int atype = family == NFPROTO_IPV4 ? IPSET_ATTR_IPADDR_IPV4
: IPSET_ATTR_IPADDR_IPV6;
diff --git a/src/ipset.8 b/src/ipset.8
index 269b9b5..f9a880b 100644
--- a/src/ipset.8
+++ b/src/ipset.8
@@ -524,7 +524,7 @@ The \fBhash:ip\fR set type uses a hash to store IP host addresses (default) or
network addresses. Zero valued IP address cannot be stored in a \fBhash:ip\fR
type of set.
.PP
-\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBbucketsize\fR \fIvalue\fR ] [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ] [ \fBcounters\fP ] [ \fBcomment\fP ] [ \fBskbinfo\fP ]
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBbucketsize\fR \fIvalue\fR ] [ \fBnetmask\fP \fIcidr\fP ] [ \fBbitmask\fP \fImask\fP ] [ \fBtimeout\fR \fIvalue\fR ] [ \fBcounters\fP ] [ \fBcomment\fP ] [ \fBskbinfo\fP ]
.PP
\fIADD\-ENTRY\fR := \fIipaddr\fR
.PP
@@ -549,6 +549,9 @@ ipset create foo hash:ip netmask 30
ipset add foo 192.168.1.0/24
.IP
ipset test foo 192.168.1.2
+.TP
+\fBbitmask\fP \fImask\fP
+This works similar to \fBnetmask\fP but it will accept any valid IPv4/v6 address. It does not have to be a valid netmask.
.SS hash:mac
The \fBhash:mac\fR set type uses a hash to store MAC addresses. Zero valued MAC addresses cannot be stored in a \fBhash:mac\fR
type of set. For matches on destination MAC addresses, see COMMENTS below.
@@ -648,7 +651,7 @@ over the second, so a nomatch entry could be potentially be ineffective if a mor
first parameter existed with a suitable second parameter.
Network address with zero prefix size cannot be stored in this type of set.
.PP
-\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBbucketsize\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ] [ \fBcounters\fP ] [ \fBcomment\fP ] [ \fBskbinfo\fP ]
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBbucketsize\fR \fIvalue\fR ] [ \fBnetmask\fP \fIcidr\fP ] [ \fBbitmask\fP \fImask\fP ] [ \fBtimeout\fR \fIvalue\fR ] [ \fBcounters\fP ] [ \fBcomment\fP ] [ \fBskbinfo\fP ]
.PP
\fIADD\-ENTRY\fR := \fInetaddr\fR,\fInetaddr\fR
.PP
@@ -680,6 +683,18 @@ values added to the first parameter of the set. The number of secondary prefixes
further increases this as the list of secondary prefixes is traversed per primary
prefix.
.PP
+Optional \fBcreate\fR options:
+.TP
+\fBnetmask\fP \fIcidr\fP
+When the optional \fBnetmask\fP parameter specified, network addresses will be
+stored in the set instead of IP host addresses. The \fIcidr\fP prefix value must be
+between 1\-32 for IPv4 and between 1\-128 for IPv6. An IP address will be in the set
+if the network address, which is resulted by masking the address with the netmask,
+can be found in the set.
+.TP
+\fBbitmask\fP \fImask\fP
+This works similar to \fBnetmask\fP but it will accept any valid IPv4/v6 address. It does not have to be a valid netmask.
+.PP
Example:
.IP
ipset create foo hash:net,net
@@ -701,7 +716,7 @@ The \fBhash:ip,port\fR set type uses a hash to store IP address and port number
The port number is interpreted together with a protocol (default TCP) and zero
protocol number cannot be used.
.PP
-\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBbucketsize\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ] [ \fBcounters\fP ] [ \fBcomment\fP ] [ \fBskbinfo\fP ]
+\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBbucketsize\fR \fIvalue\fR ] [ \fBnetmask\fP \fIcidr\fP ] [ \fBbitmask\fP \fImask\fP ] [ \fBtimeout\fR \fIvalue\fR ] [ \fBcounters\fP ] [ \fBcomment\fP ] [ \fBskbinfo\fP ]
.PP
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR
.PP
@@ -741,6 +756,18 @@ The \fBhash:ip,port\fR type of sets require
two \fBsrc\fR/\fBdst\fR parameters of the \fBset\fR match and \fBSET\fR
target kernel modules.
.PP
+Optional \fBcreate\fR options:
+.TP
+\fBnetmask\fP \fIcidr\fP
+When the optional \fBnetmask\fP parameter specified, network addresses will be
+stored in the set instead of IP host addresses. The \fIcidr\fP prefix value must be
+between 1\-32 for IPv4 and between 1\-128 for IPv6. An IP address will be in the set
+if the network address, which is resulted by masking the address with the netmask,
+can be found in the set.
+.TP
+\fBbitmask\fP \fImask\fP
+This works similar to \fBnetmask\fP but it will accept any valid IPv4/v6 address. It does not have to be a valid netmask.
+.PP
Examples:
.IP
ipset create foo hash:ip,port
diff --git a/src/ipset.c b/src/ipset.c
index 6d42b60..162f477 100644
--- a/src/ipset.c
+++ b/src/ipset.c
@@ -6,6 +6,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#define _GNU_SOURCE
#include <assert.h> /* assert */
#include <stdio.h> /* fprintf */
#include <stdlib.h> /* exit */
@@ -31,7 +32,7 @@ main(int argc, char *argv[])
exit(1);
}
- if (!strcmp(argv[0], "ipset-translate")) {
+ if (!strcmp(basename(argv[0]), "ipset-translate")) {
ret = ipset_xlate_argv(ipset, argc, argv);
} else {
ret = ipset_parse_argv(ipset, argc, argv);
diff --git a/tests/hash:ip,port.t b/tests/hash:ip,port.t
index 7a0e821..addbe3b 100644
--- a/tests/hash:ip,port.t
+++ b/tests/hash:ip,port.t
@@ -170,4 +170,122 @@
0 ./check_extensions test 2.0.0.20 700 13 12479
# Counters and timeout: destroy set
0 ipset x test
+# Network: Create a set with timeout and netmask
+0 ipset -N test hash:ip,port --hashsize 128 --netmask 24 timeout 4
+# Network: Add zero valued element
+1 ipset -A test 0.0.0.0,80
+# Network: Test zero valued element
+1 ipset -T test 0.0.0.0,80
+# Network: Delete zero valued element
+1 ipset -D test 0.0.0.0,80
+# Network: Add first random network
+0 ipset -A test 2.0.0.1,8080
+# Network: Add second random network
+0 ipset -A test 192.168.68.69,22
+# Network: Test first random value
+0 ipset -T test 2.0.0.255,8080
+# Network: Test second random value
+0 ipset -T test 192.168.68.95,22
+# Network: Test value not added to the set
+1 ipset -T test 2.0.1.0,8080
+# Network: Add third element
+0 ipset -A test 200.100.10.1,22 timeout 0
+# Network: Add third random network
+0 ipset -A test 200.100.0.12,22
+# Network: Delete the same network
+0 ipset -D test 200.100.0.12,22
+# Network: List set
+0 ipset -L test > .foo0 && ./sort.sh .foo0
+# Network: Check listing
+0 ./diff.sh .foo hash:ip,port.t.list3
+# Sleep 5s so that elements can time out
+0 sleep 5
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:ip,port.t.list4
+# Network: Flush test set
+0 ipset -F test
+# Network: add element with 1s timeout
+0 ipset add test 200.100.0.12,80 timeout 1
+# Network: readd element with 3s timeout
+0 ipset add test 200.100.0.12,80 timeout 3 -exist
+# Network: sleep 2s
+0 sleep 2s
+# Network: check readded element
+0 ipset test test 200.100.0.12,80
+# Network: Delete test set
+0 ipset -X test
+# Network: Create a set with timeout and bitmask
+0 ipset -N test hash:ip,port --hashsize 128 --bitmask 255.255.255.0 timeout 4
+# Network: Add zero valued element
+1 ipset -A test 0.0.0.0,80
+# Network: Test zero valued element
+1 ipset -T test 0.0.0.0,80
+# Network: Delete zero valued element
+1 ipset -D test 0.0.0.0,80
+# Network: Add first random network
+0 ipset -A test 2.0.0.1,8080
+# Network: Add second random network
+0 ipset -A test 192.168.68.69,22
+# Network: Test first random value
+0 ipset -T test 2.0.0.255,8080
+# Network: Test second random value
+0 ipset -T test 192.168.68.95,22
+# Network: Test value not added to the set
+1 ipset -T test 2.0.1.0,8080
+# Network: Add third element
+0 ipset -A test 200.100.10.1,22 timeout 0
+# Network: Add third random network
+0 ipset -A test 200.100.0.12,22
+# Network: Delete the same network
+0 ipset -D test 200.100.0.12,22
+# Network: List set
+0 ipset -L test > .foo0 && ./sort.sh .foo0
+# Network: Check listing
+0 ./diff.sh .foo hash:ip,port.t.list5
+# Sleep 5s so that elements can time out
+0 sleep 5
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:ip,port.t.list6
+# Network: Flush test set
+0 ipset -F test
+# Network: add element with 1s timeout
+0 ipset add test 200.100.0.12,80 timeout 1
+# Network: readd element with 3s timeout
+0 ipset add test 200.100.0.12,80 timeout 3 -exist
+# Network: sleep 2s
+0 sleep 2s
+# Network: check readded element
+0 ipset test test 200.100.0.12,80
+# Network: Delete test set
+0 ipset -X test
+# Network: Create a set with bitmask which is not a valid netmask
+0 ipset -N test hash:ip,port --hashsize 128 --bitmask 255.255.0.255
+# Network: Add zero valued element
+1 ipset -A test 0.0.0.0
+# Network: Test zero valued element
+1 ipset -T test 0.0.0.0
+# Network: Delete zero valued element
+1 ipset -D test 0.0.0.0
+# Network: Add first random network
+0 ipset -A test 1.2.3.4,22
+# Network: Add second random network
+0 ipset -A test 1.168.122.124,22
+# Network: Test first random value
+0 ipset -T test 1.2.9.4,22
+# Network: Test second random value
+0 ipset -T test 1.168.68.124,22
+# Network: Test value not added to the set
+1 ipset -T test 2.0.1.0,23
+# Network: Test delete value
+0 ipset -D test 1.168.0.124,22
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:ip,port.t.list7
+# Network: Delete test set
+0 ipset -X test
# eof
diff --git a/tests/hash:ip,port.t.list3 b/tests/hash:ip,port.t.list3
new file mode 100644
index 0000000..b2cdc28
--- /dev/null
+++ b/tests/hash:ip,port.t.list3
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip,port
+Revision: 7
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0xf49ba001 netmask 24
+Size in memory: 408
+References: 0
+Number of entries: 3
+Members:
+192.168.68.0,tcp:22 timeout 3
+2.0.0.0,tcp:8080 timeout 3
+200.100.10.0,tcp:22 timeout 0
diff --git a/tests/hash:ip,port.t.list4 b/tests/hash:ip,port.t.list4
new file mode 100644
index 0000000..c28987a
--- /dev/null
+++ b/tests/hash:ip,port.t.list4
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:ip,port
+Revision: 7
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0x18b2277a netmask 24
+Size in memory: 408
+References: 0
+Number of entries: 1
+Members:
+200.100.10.0,tcp:22 timeout 0
diff --git a/tests/hash:ip,port.t.list5 b/tests/hash:ip,port.t.list5
new file mode 100644
index 0000000..b5fa817
--- /dev/null
+++ b/tests/hash:ip,port.t.list5
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip,port
+Revision: 7
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0x6a0e903a bitmask 255.255.255.0
+Size in memory: 408
+References: 0
+Number of entries: 3
+Members:
+192.168.68.0,tcp:22 timeout 3
+2.0.0.0,tcp:8080 timeout 3
+200.100.10.0,tcp:22 timeout 0
diff --git a/tests/hash:ip,port.t.list6 b/tests/hash:ip,port.t.list6
new file mode 100644
index 0000000..33969cf
--- /dev/null
+++ b/tests/hash:ip,port.t.list6
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:ip,port
+Revision: 7
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0x2fcffdca bitmask 255.255.255.0
+Size in memory: 408
+References: 0
+Number of entries: 1
+Members:
+200.100.10.0,tcp:22 timeout 0
diff --git a/tests/hash:ip,port.t.list7 b/tests/hash:ip,port.t.list7
new file mode 100644
index 0000000..f223657
--- /dev/null
+++ b/tests/hash:ip,port.t.list7
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:ip,port
+Revision: 7
+Header: family inet hashsize 128 maxelem 65536 bucketsize 12 initval 0x98bdfa72 bitmask 255.255.0.255
+Size in memory: 312
+References: 0
+Number of entries: 1
+Members:
+1.2.0.4,tcp:22
diff --git a/tests/hash:ip.t b/tests/hash:ip.t
index 3239701..a1b4de7 100644
--- a/tests/hash:ip.t
+++ b/tests/hash:ip.t
@@ -72,7 +72,7 @@
0 n=`ipset list test|grep '^10.0'|wc -l` && test $n -eq 1024
# IP: Destroy sets
0 ipset -X
-# Network: Create a set with timeout
+# Network: Create a set with timeout and netmask
0 ipset -N test iphash --hashsize 128 --netmask 24 timeout 4
# Network: Add zero valued element
1 ipset -A test 0.0.0.0
@@ -210,4 +210,78 @@ skip which sendip
0 ./check_extensions test 10.255.255.64 600 6 $((6*40))
# Counters and timeout: destroy set
0 ipset x test
+# Network: Create a set with timeout and bitmask
+0 ipset -N test iphash --hashsize 128 --bitmask 255.255.255.0 timeout 4
+# Network: Add zero valued element
+1 ipset -A test 0.0.0.0
+# Network: Test zero valued element
+1 ipset -T test 0.0.0.0
+# Network: Delete zero valued element
+1 ipset -D test 0.0.0.0
+# Network: Add first random network
+0 ipset -A test 2.0.0.1
+# Network: Add second random network
+0 ipset -A test 192.168.68.69
+# Network: Test first random value
+0 ipset -T test 2.0.0.255
+# Network: Test second random value
+0 ipset -T test 192.168.68.95
+# Network: Test value not added to the set
+1 ipset -T test 2.0.1.0
+# Network: Add third element
+0 ipset -A test 200.100.10.1 timeout 0
+# Network: Add third random network
+0 ipset -A test 200.100.0.12
+# Network: Delete the same network
+0 ipset -D test 200.100.0.12
+# Network: List set
+0 ipset -L test > .foo0 && ./sort.sh .foo0
+# Network: Check listing
+0 ./diff.sh .foo hash:ip.t.list4
+# Sleep 5s so that elements can time out
+0 sleep 5
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:ip.t.list5
+# Network: Flush test set
+0 ipset -F test
+# Network: add element with 1s timeout
+0 ipset add test 200.100.0.12 timeout 1
+# Network: readd element with 3s timeout
+0 ipset add test 200.100.0.12 timeout 3 -exist
+# Network: sleep 2s
+0 sleep 2s
+# Network: check readded element
+0 ipset test test 200.100.0.12
+# Network: Delete test set
+0 ipset -X test
+# Network: Create a set with both bitmask and netmask
+1 ipset -N test iphash --hashsize 128 --bitmask 255.255.0.255 --netmask 24
+# Network: Create a set with bitmask which is not a valid netmask
+0 ipset -N test iphash --hashsize 128 --bitmask 255.255.0.255
+# Network: Add zero valued element
+1 ipset -A test 0.0.0.0
+# Network: Test zero valued element
+1 ipset -T test 0.0.0.0
+# Network: Delete zero valued element
+1 ipset -D test 0.0.0.0
+# Network: Add first random network
+0 ipset -A test 1.2.3.4
+# Network: Add second random network
+0 ipset -A test 1.2.4.5
+# Network: Test first random value
+0 ipset -T test 1.2.9.4
+# Network: Test second random value
+0 ipset -T test 1.2.9.5
+# Network: Test value not added to the set
+1 ipset -T test 2.0.1.0
+# Network: Test delete value
+0 ipset -D test 1.2.0.5
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:ip.t.list6
+# Network: Delete test set
+0 ipset -X test
# eof
diff --git a/tests/hash:ip.t.list4 b/tests/hash:ip.t.list4
new file mode 100644
index 0000000..5f92afa
--- /dev/null
+++ b/tests/hash:ip.t.list4
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:ip
+Revision: 5
+Header: family inet hashsize 128 maxelem 65536 bitmask 255.255.255.0 timeout 4 bucketsize 12 initval 0xfe970e91
+Size in memory: 528
+References: 0
+Number of entries: 3
+Members:
+192.168.68.0 timeout 3
+2.0.0.0 timeout 3
+200.100.10.0 timeout 0
diff --git a/tests/hash:ip.t.list5 b/tests/hash:ip.t.list5
new file mode 100644
index 0000000..9a29e75
--- /dev/null
+++ b/tests/hash:ip.t.list5
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:ip
+Revision: 5
+Header: family inet hashsize 128 maxelem 65536 bitmask 255.255.255.0 timeout 4 bucketsize 12 initval 0xbc66e38a
+Size in memory: 528
+References: 0
+Number of entries: 1
+Members:
+200.100.10.0 timeout 0
diff --git a/tests/hash:ip.t.list6 b/tests/hash:ip.t.list6
new file mode 100644
index 0000000..44c5a49
--- /dev/null
+++ b/tests/hash:ip.t.list6
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:ip
+Revision: 6
+Header: family inet hashsize 128 maxelem 65536 bitmask 255.255.0.255 bucketsize 12 initval 0xd7d821e1
+Size in memory: 296
+References: 0
+Number of entries: 1
+Members:
+1.2.0.4
diff --git a/tests/hash:net,iface.t b/tests/hash:net,iface.t
index e594cca..444f230 100644
--- a/tests/hash:net,iface.t
+++ b/tests/hash:net,iface.t
@@ -132,6 +132,10 @@
0 (set -e; for x in `seq 0 63`; do ipset add test 10.0.0.0/16,eth$x; done)
# Check listing
0 n=`ipset list test | grep -v Revision: | wc -l` && test $n -eq 71
+# Flush test set
+0 ipset flush test
+# Try to add more than 64 clashing entries
+1 (set -e; for x in `seq 0 64`; do ipset add test 10.0.0.0/16,eth$x; done)
# Delete test set
0 ipset destroy test
# Check all possible CIDR values
diff --git a/tests/hash:net,net.t b/tests/hash:net,net.t
index feb13d9..41189b7 100644
--- a/tests/hash:net,net.t
+++ b/tests/hash:net,net.t
@@ -166,4 +166,110 @@
0 ./check_extensions test 2.0.0.0/25,2.0.0.0/25 700 13 12479
# Counters and timeout: destroy set
0 ipset x test
+# Network: Create a set with timeout and netmask
+0 ipset -N test hash:net,net --hashsize 128 --netmask 24 timeout 4
+# Network: Add first random network
+0 ipset -A test 2.0.10.1,2.10.10.254
+# Network: Add second random network
+0 ipset -A test 192.168.68.1,192.168.68.254
+# Network: Test first random value
+0 ipset -T test 2.0.10.11,2.10.10.25
+# Network: Test second random value
+0 ipset -T test 192.168.68.11,192.168.68.5
+# Network: Test value not added to the set
+1 ipset -T test 2.10.1.0,21.0.1.0
+# Network: Add third element
+0 ipset -A test 200.100.10.1,200.100.10.100 timeout 0
+# Network: Add third random network
+0 ipset -A test 200.100.0.12,200.100.0.13
+# Network: Delete the same network
+0 ipset -D test 200.100.0.12,200.100.0.13
+# Network: List set
+0 ipset -L test > .foo0 && ./sort.sh .foo0
+# Network: Check listing
+0 ./diff.sh .foo hash:net,net.t.list3
+# Sleep 5s so that elements can time out
+0 sleep 5
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:net,net.t.list4
+# Network: Flush test set
+0 ipset -F test
+# Network: add element with 1s timeout
+0 ipset add test 200.100.0.12,80.20.0.12 timeout 1
+# Network: readd element with 3s timeout
+0 ipset add test 200.100.0.12,80.20.0.12 timeout 3 -exist
+# Network: sleep 2s
+0 sleep 2s
+# Network: check readded element
+0 ipset test test 200.100.0.12,80.20.0.12
+# Network: Delete test set
+0 ipset -X test
+# Network: Create a set with timeout and bitmask
+0 ipset -N test hash:net,net --hashsize 128 --bitmask 255.255.255.0 timeout 4
+# Network: Add first random network
+0 ipset -A test 2.0.10.1,2.10.10.254
+# Network: Add second random network
+0 ipset -A test 192.168.68.1,192.168.68.254
+# Network: Test first random value
+0 ipset -T test 2.0.10.11,2.10.10.25
+# Network: Test second random value
+0 ipset -T test 192.168.68.11,192.168.68.5
+# Network: Test value not added to the set
+1 ipset -T test 2.10.1.0,21.0.1.0
+# Network: Add third element
+0 ipset -A test 200.100.10.1,200.100.10.100 timeout 0
+# Network: Add third random network
+0 ipset -A test 200.100.0.12,200.100.0.13
+# Network: Delete the same network
+0 ipset -D test 200.100.0.12,200.100.0.13
+# Network: List set
+0 ipset -L test > .foo0 && ./sort.sh .foo0
+# Network: Check listing
+0 ./diff.sh .foo hash:net,net.t.list5
+# Sleep 5s so that elements can time out
+0 sleep 5
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:net,net.t.list6
+# Network: Flush test set
+0 ipset -F test
+# Network: add element with 1s timeout
+0 ipset add test 200.100.0.12,80.20.0.12 timeout 1
+# Network: readd element with 3s timeout
+0 ipset add test 200.100.0.12,80.20.0.12 timeout 3 -exist
+# Network: sleep 2s
+0 sleep 2s
+# Network: check readded element
+0 ipset test test 200.100.0.12,80.20.0.12
+# Network: Delete test set
+0 ipset -X test
+# Network: Create a set with bitmask which is not a valid netmask
+0 ipset -N test hash:net,net --hashsize 128 --bitmask 255.255.0.255
+# Network: Add zero valued element
+1 ipset -A test 0.0.0.0
+# Network: Test zero valued element
+1 ipset -T test 0.0.0.0
+# Network: Delete zero valued element
+1 ipset -D test 0.0.0.0
+# Network: Add first random network
+0 ipset -A test 1.2.3.4,22.23.24.25
+# Network: Add second random network
+0 ipset -A test 1.168.122.124,122.23.45.50
+# Network: Test first random value
+0 ipset -T test 1.2.43.4,22.23.2.25
+# Network: Test second random value
+0 ipset -T test 1.168.12.124,122.23.4.50
+# Network: Test value not added to the set
+1 ipset -T test 2.168.122.124,22.23.45.50
+# Network: Test delete value
+0 ipset -D test 1.168.12.124,122.23.0.50
+# Network: List set
+0 ipset -L test > .foo
+# Network: Check listing
+0 ./diff.sh .foo hash:net,net.t.list7
+# Network: Delete test set
+0 ipset -X test
# eof
diff --git a/tests/hash:net,net.t.list3 b/tests/hash:net,net.t.list3
new file mode 100644
index 0000000..fc5b97a
--- /dev/null
+++ b/tests/hash:net,net.t.list3
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:net,net
+Revision: 4
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0xe17e4732 netmask 24
+Size in memory: 848
+References: 0
+Number of entries: 3
+Members:
+192.168.68.0,192.168.68.0 timeout 3
+2.0.10.0,2.10.10.0 timeout 3
+200.100.10.0,200.100.10.0 timeout 0
diff --git a/tests/hash:net,net.t.list4 b/tests/hash:net,net.t.list4
new file mode 100644
index 0000000..908cab6
--- /dev/null
+++ b/tests/hash:net,net.t.list4
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:net,net
+Revision: 4
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0xb69e293e netmask 24
+Size in memory: 848
+References: 0
+Number of entries: 1
+Members:
+200.100.10.0,200.100.10.0 timeout 0
diff --git a/tests/hash:net,net.t.list5 b/tests/hash:net,net.t.list5
new file mode 100644
index 0000000..0ff37fb
--- /dev/null
+++ b/tests/hash:net,net.t.list5
@@ -0,0 +1,11 @@
+Name: test
+Type: hash:net,net
+Revision: 4
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0xe17e4732 bitmask 255.255.255.0
+Size in memory: 848
+References: 0
+Number of entries: 3
+Members:
+192.168.68.0,192.168.68.0 timeout 3
+2.0.10.0,2.10.10.0 timeout 3
+200.100.10.0,200.100.10.0 timeout 0
diff --git a/tests/hash:net,net.t.list6 b/tests/hash:net,net.t.list6
new file mode 100644
index 0000000..84beb5b
--- /dev/null
+++ b/tests/hash:net,net.t.list6
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:net,net
+Revision: 4
+Header: family inet hashsize 128 maxelem 65536 timeout 4 bucketsize 12 initval 0xb69e293e bitmask 255.255.255.0
+Size in memory: 848
+References: 0
+Number of entries: 1
+Members:
+200.100.10.0,200.100.10.0 timeout 0
diff --git a/tests/hash:net,net.t.list7 b/tests/hash:net,net.t.list7
new file mode 100644
index 0000000..6601795
--- /dev/null
+++ b/tests/hash:net,net.t.list7
@@ -0,0 +1,9 @@
+Name: test
+Type: hash:net,net
+Revision: 4
+Header: family inet hashsize 128 maxelem 65536 bucketsize 12 initval 0x6223fef7 bitmask 255.255.0.255
+Size in memory: 736
+References: 0
+Number of entries: 1
+Members:
+1.2.0.4,22.23.0.25