]> granicus.if.org Git - ipset/commitdiff
Add /0 network support to hash:net,iface type
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 10 Sep 2012 19:22:23 +0000 (21:22 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Mon, 10 Sep 2012 19:22:23 +0000 (21:22 +0200)
Now it is possible to setup a single hash:net,iface type of set and
a single ip6?tables match which covers all egress/ingress filtering.

kernel/net/netfilter/ipset/ip_set_hash_netiface.c
lib/ipset_hash_netiface.c
src/ipset.8
tests/hash:net,iface.t

index 632693f0beeb7fb60cf467fcd5cf383ae33c6c40..e7c671dd3cce8de5a31ba9b954e81d2088455a7f 100644 (file)
@@ -140,7 +140,7 @@ struct hash_netiface4_elem_hashed {
        u8 physdev;
        u8 cidr;
        u8 nomatch;
-       u8 padding;
+       u8 elem;
 };
 
 #define HKEY_DATALEN   sizeof(struct hash_netiface4_elem_hashed)
@@ -151,7 +151,7 @@ struct hash_netiface4_elem {
        u8 physdev;
        u8 cidr;
        u8 nomatch;
-       u8 padding;
+       u8 elem;
        const char *iface;
 };
 
@@ -161,7 +161,7 @@ struct hash_netiface4_telem {
        u8 physdev;
        u8 cidr;
        u8 nomatch;
-       u8 padding;
+       u8 elem;
        const char *iface;
        unsigned long timeout;
 };
@@ -181,18 +181,14 @@ hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
 static inline bool
 hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
 {
-       return elem->cidr == 0;
+       return elem->elem == 0;
 }
 
 static inline void
 hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
                         const struct hash_netiface4_elem *src)
 {
-       dst->ip = src->ip;
-       dst->cidr = src->cidr;
-       dst->physdev = src->physdev;
-       dst->iface = src->iface;
-       dst->nomatch = src->nomatch;
+       memcpy(dst, src, sizeof(*dst));
 }
 
 static inline void
@@ -217,7 +213,7 @@ hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
 static inline void
 hash_netiface4_data_zero_out(struct hash_netiface4_elem *elem)
 {
-       elem->cidr = 0;
+       elem->elem = 0;
 }
 
 static bool
@@ -288,7 +284,8 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
        struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        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;
 
@@ -339,7 +336,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 {
        struct ip_set_hash *h = set->data;
        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 timeout = h->timeout;
        char iface[IFNAMSIZ];
@@ -360,7 +357,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (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;
        }
 
@@ -389,7 +386,6 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
                if (adt == IPSET_ADD && (cadt_flags & IPSET_FLAG_NOMATCH))
                        flags |= (cadt_flags << 16);
        }
-
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
                data.ip = htonl(ip & ip_set_hostmask(data.cidr));
                ret = adtfn(set, &data, timeout, flags);
@@ -442,7 +438,7 @@ struct hash_netiface6_elem_hashed {
        u8 physdev;
        u8 cidr;
        u8 nomatch;
-       u8 padding;
+       u8 elem;
 };
 
 #define HKEY_DATALEN   sizeof(struct hash_netiface6_elem_hashed)
@@ -452,7 +448,7 @@ struct hash_netiface6_elem {
        u8 physdev;
        u8 cidr;
        u8 nomatch;
-       u8 padding;
+       u8 elem;
        const char *iface;
 };
 
@@ -461,7 +457,7 @@ struct hash_netiface6_telem {
        u8 physdev;
        u8 cidr;
        u8 nomatch;
-       u8 padding;
+       u8 elem;
        const char *iface;
        unsigned long timeout;
 };
@@ -481,7 +477,7 @@ hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
 static inline bool
 hash_netiface6_data_isnull(const struct hash_netiface6_elem *elem)
 {
-       return elem->cidr == 0;
+       return elem->elem == 0;
 }
 
 static inline void
@@ -506,7 +502,7 @@ hash_netiface6_data_match(const struct hash_netiface6_elem *elem)
 static inline void
 hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
 {
-       elem->cidr = 0;
+       elem->elem = 0;
 }
 
 static inline void
@@ -590,7 +586,8 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
        struct ip_set_hash *h = set->data;
        ipset_adtfn adtfn = set->variant->adt[adt];
        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;
 
@@ -637,7 +634,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 {
        struct ip_set_hash *h = set->data;
        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;
        char iface[IFNAMSIZ];
        int ret;
@@ -659,7 +656,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (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;
        ip6_netmask(&data.ip, data.cidr);
 
@@ -777,7 +774,8 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
        .dimension      = IPSET_DIM_TWO,
        .family         = NFPROTO_UNSPEC,
        .revision_min   = 0,
-       .revision_max   = 1,    /* nomatch flag support added */
+       /*              = 1,       nomatch flag support added */
+       .revision_max   = 2,    /* /0 support added */
        .create         = hash_netiface_create,
        .create_policy  = {
                [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
index bc6aa3ddd629a78096b8cd24af2105f24e2c3b19..298ce2a30413d27dcdaa3ef3551c2cfc26a4c25a 100644 (file)
@@ -200,9 +200,67 @@ static struct ipset_type ipset_hash_netiface1 = {
        .usage = hash_netiface1_usage,
 };
 
+static struct ipset_type ipset_hash_netiface2 = {
+       .name = "hash:net,iface",
+       .alias = { "netifacehash", NULL },
+       .revision = 2,
+       .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_iface,
+                       .print = ipset_print_iface,
+                       .opt = IPSET_OPT_IFACE
+               },
+       },
+       .args = {
+               [IPSET_CREATE] = hash_netiface_create_args,
+               [IPSET_ADD] = hash_netiface1_add_args,
+       },
+       .mandatory = {
+               [IPSET_CREATE] = 0,
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_IFACE),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_IFACE),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_IFACE),
+       },
+       .full = {
+               [IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
+                       | IPSET_FLAG(IPSET_OPT_MAXELEM)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT),
+               [IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_IFACE)
+                       | IPSET_FLAG(IPSET_OPT_PHYSDEV)
+                       | IPSET_FLAG(IPSET_OPT_TIMEOUT)
+                       | IPSET_FLAG(IPSET_OPT_NOMATCH),
+               [IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_IFACE)
+                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+               [IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
+                       | IPSET_FLAG(IPSET_OPT_CIDR)
+                       | IPSET_FLAG(IPSET_OPT_IP_TO)
+                       | IPSET_FLAG(IPSET_OPT_IFACE)
+                       | IPSET_FLAG(IPSET_OPT_PHYSDEV),
+       },
+
+       .usage = hash_netiface1_usage,
+};
+
 void _init(void);
 void _init(void)
 {
        ipset_type_add(&ipset_hash_netiface0);
        ipset_type_add(&ipset_hash_netiface1);
+       ipset_type_add(&ipset_hash_netiface2);
 }
index bbad680e5888df12f73243808df87166e580606b..3a5a5db7dba2c317fd9e4202f2c1a38621a45ae7 100644 (file)
@@ -751,8 +751,7 @@ ipset add foo 192.168.2,25,10.1.0.0/16
 ipset test foo 192.168.1,80.10.0.0/24
 .SS hash:net,iface
 The \fBhash:net,iface\fR set type uses a hash to store different sized IP network
-address and interface name pairs. Network address with zero prefix size is not
-accepted.
+address and interface name pairs.
 .PP 
 \fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
 .PP 
index 0ae4d4e2ac2aa05a314436db0588947d03452ce9..779d77f001d10847336bbe479b1dff0fdb14ba69 100644 (file)
@@ -1,13 +1,17 @@
 # Create a set
 0 ipset create test hash:net,iface hashsize 128
 # Add zero valued element
-1 ipset add test 0.0.0.0/0,eth0
+0 ipset add test 0.0.0.0/0,eth0
 # Test zero valued element
-1 ipset test test 0.0.0.0/0,eth0
+0 ipset test test 0.0.0.0/0,eth0
 # Delete zero valued element
-1 ipset del test 0.0.0.0/0,eth0
-# Try to add /0
-1 ipset add test 1.1.1.1/0,eth0
+0 ipset del test 0.0.0.0/0,eth0
+# Add 1.1.1.1/0
+0 ipset add test 1.1.1.1/0,eth0
+# Test 1.1.1.1/0
+0 ipset test test 1.1.1.1/0,eth0
+# Delete 1.1.1.1/0
+0 ipset del test 1.1.1.1/0,eth0
 # Try to add /32
 0 ipset add test 1.1.1.1/32,eth0
 # Add almost zero valued element
 0 ipset -L test 2>/dev/null > .foo0 && ./sort.sh .foo0
 # Check listing
 0 diff -u -I 'Size in memory.*' .foo hash:net,iface.t.list2
+# Flush test set
+0 ipset flush test
+# Add 0/0,eth0
+0 ipset add test 0/0,eth0
+# Add 10.0.0.0/16,eth1
+0 ipset add test 10.0.0.0/16,eth1
+# Add 10.0.0.0/24,eth0
+0 ipset add test 10.0.0.0/24,eth0
+# Add 10.0.0.0/16,eth2
+0 ipset add test 10.0.0.0/16,eth2
+# Check 10.0.1.1 with eth1
+0 ipset test test 10.0.1.1,eth1
+# Check 10.0.1.1 with eth2
+0 ipset test test 10.0.1.1,eth2
+# Check 10.0.1.1 with eth0
+1 ipset test test 10.0.1.1,eth0
+# Check 10.0.0.1 with eth1
+1 ipset test test 10.0.0.1,eth1
+# Check 10.0.0.1 with eth2
+1 ipset test test 10.0.0.1,eth2
+# Check 10.0.0.1 with eth0
+0 ipset test test 10.0.0.1,eth0
+# Check 1.0.1.1 with eth1
+1 ipset test test 1.0.1.1,eth1
+# Check 1.0.1.1 with eth2
+1 ipset test test 1.0.1.1,eth2
+# Check 1.0.1.1 with eth0
+0 ipset test test 1.0.1.1,eth0
 # Delete test set
 0 ipset destroy test
 # Create test set