]> granicus.if.org Git - ipset/commitdiff
Support adding/deleting multiple entries, kernel part.
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 17 Dec 2010 20:28:18 +0000 (21:28 +0100)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 17 Dec 2010 20:28:18 +0000 (21:28 +0100)
Support adding/deleting multiple entries in the kernel side
of the hash:ip,port, hash:ip,port,ip, hash:ip,port,net and
hash:net,port types.

kernel/ip_set_hash_ipport.c
kernel/ip_set_hash_ipportip.c
kernel/ip_set_hash_ipportnet.c
kernel/ip_set_hash_netport.c

index d201adf0eb293160d61833408d781e9e9147009b..d9ee214ddef4bdf4b81a4738dd7385fc9c4b4311 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/netlink.h>
+#include <net/tcp.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter/ipset/ip_set.h>
@@ -155,7 +156,10 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
 static const struct nla_policy
 hash_ipport_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
        [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
        [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
        [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
        [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
        [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
@@ -169,6 +173,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport4_elem data = { };
+       u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -212,9 +217,52 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
+                || tb[IPSET_ATTR_PORT_TO])) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       ip = ntohl(data.ip);
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
+               if (ret)
+                       return ret;
+               ip_to = ntohl(ip_to);
+               if (ip > ip_to)
+                       swap(ip, ip_to);
+       } else if (tb[IPSET_ATTR_CIDR]) {
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+
+               if (cidr > 32)
+                       return -IPSET_ERR_INVALID_CIDR;
+               ip &= HOSTMASK(cidr);
+               ip_to = ip | ~HOSTMASK(cidr);
+       } else
+               ip_to = ip;
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+       port = ntohs(data.port);
+       if (tb[IPSET_ATTR_PORT_TO]) {
+               port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+               if (port > port_to)
+                       swap(port, port_to);
+       } else
+               port_to = port;
+
+       for (; !before(ip_to, ip); ip++)
+               for (p = port; p <= port_to; p++) {
+                       data.ip = htonl(ip);
+                       data.port = htons(p);
+                       ret = adtfn(set, &data, timeout);
+
+                       if (ret && !ip_set_eexist(ret, flags))
+                               return ret;
+                       else
+                               ret = 0;
+               }
+       return ret;
 }
 
 static bool
@@ -347,6 +395,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipport6_elem data = { };
+       u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -390,9 +439,28 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !tb[IPSET_ATTR_PORT_TO]) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+       port = ntohs(data.port);
+       port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+       if (port > port_to)
+               swap(port, port_to);
+
+       for (; port <= port_to; port++) {
+               data.port = htons(port);
+               ret = adtfn(set, &data, timeout);
+
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+       }
+       return ret;
 }
 
 /* Create hash:ip type of sets */
index 53c9e7aa99bb08ccbbcda17e40185fcd58c1a175..b0aaf08c786c24f65f11337fa59f0393707c5da8 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/netlink.h>
+#include <net/tcp.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter/ipset/ip_set.h>
@@ -161,8 +162,11 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
 static const struct nla_policy
 hash_ipportip_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
        [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
        [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
        [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
        [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
        [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
        [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
@@ -176,6 +180,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportip4_elem data = { };
+       u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -223,9 +228,52 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
+                || tb[IPSET_ATTR_PORT_TO])) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       ip = ntohl(data.ip);
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
+               if (ret)
+                       return ret;
+               ip_to = ntohl(ip_to);
+               if (ip > ip_to)
+                       swap(ip, ip_to);
+       } else if (tb[IPSET_ATTR_CIDR]) {
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+
+               if (cidr > 32)
+                       return -IPSET_ERR_INVALID_CIDR;
+               ip &= HOSTMASK(cidr);
+               ip_to = ip | ~HOSTMASK(cidr);
+       } else
+               ip_to = ip;
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+       port = ntohs(data.port);
+       if (tb[IPSET_ATTR_PORT_TO]) {
+               port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+               if (port > port_to)
+                       swap(port, port_to);
+       } else
+               port_to = port;
+
+       for (; !before(ip_to, ip); ip++)
+               for (p = port; p <= port_to; p++) {
+                       data.ip = htonl(ip);
+                       data.port = htons(p);
+                       ret = adtfn(set, &data, timeout);
+
+                       if (ret && !ip_set_eexist(ret, flags))
+                               return ret;
+                       else
+                               ret = 0;
+               }
+       return ret;
 }
 
 static bool
@@ -364,6 +412,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportip6_elem data = { };
+       u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -411,9 +460,28 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !tb[IPSET_ATTR_PORT_TO]) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+       port = ntohs(data.port);
+       port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+       if (port > port_to)
+               swap(port, port_to);
+
+       for (; port <= port_to; port++) {
+               data.port = htons(port);
+               ret = adtfn(set, &data, timeout);
+
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+       }
+       return ret;
 }
 
 /* Create hash:ip type of sets */
index 293fc31fd2b34cb4a963a2c4a604d8c790bc4315..6886aa8964b0d63b0780d2293a4a5a3fde84ffff 100644 (file)
@@ -20,6 +20,7 @@
 #include <net/ip.h>
 #include <net/ipv6.h>
 #include <net/netlink.h>
+#include <net/tcp.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter/ipset/ip_set.h>
@@ -181,8 +182,11 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
 static const struct nla_policy
 hash_ipportnet_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
        [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
+       [IPSET_ATTR_IP_TO]      = { .type = NLA_NESTED },
        [IPSET_ATTR_IP2]        = { .type = NLA_NESTED },
        [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
+       [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
        [IPSET_ATTR_CIDR2]      = { .type = NLA_U8 },
        [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
        [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
@@ -197,6 +201,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
+       u32 ip, ip_to, p, port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -252,9 +257,52 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
+                || tb[IPSET_ATTR_PORT_TO])) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       ip = ntohl(data.ip);
+       if (tb[IPSET_ATTR_IP_TO]) {
+               ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
+               if (ret)
+                       return ret;
+               ip_to = ntohl(ip_to);
+               if (ip > ip_to)
+                       swap(ip, ip_to);
+       } else if (tb[IPSET_ATTR_CIDR]) {
+               u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
+
+               if (cidr > 32)
+                       return -IPSET_ERR_INVALID_CIDR;
+               ip &= HOSTMASK(cidr);
+               ip_to = ip | ~HOSTMASK(cidr);
+       } else
+               ip_to = ip;
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+       port = ntohs(data.port);
+       if (tb[IPSET_ATTR_PORT_TO]) {
+               port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+               if (port > port_to)
+                       swap(port, port_to);
+       } else
+               port_to = port;
+
+       for (; !before(ip_to, ip); ip++)
+               for (p = port; p <= port_to; p++) {
+                       data.ip = htonl(ip);
+                       data.port = htons(p);
+                       ret = adtfn(set, &data, timeout);
+
+                       if (ret && !ip_set_eexist(ret, flags))
+                               return ret;
+                       else
+                               ret = 0;
+               }
+       return ret;
 }
 
 static bool
@@ -419,6 +467,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
+       u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -474,9 +523,28 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !tb[IPSET_ATTR_PORT_TO]) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+       port = ntohs(data.port);
+       port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+       if (port > port_to)
+               swap(port, port_to);
+
+       for (; port <= port_to; port++) {
+               data.port = htons(port);
+               ret = adtfn(set, &data, timeout);
+
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+       }
+       return ret;
 }
 
 /* Create hash:ip type of sets */
index 71539d4dcf813bb9352f949bac0fd8d4ef2af5dc..2c42c5b32eada91e0ae15587cef4a7f5af207aed 100644 (file)
@@ -178,6 +178,7 @@ static const struct nla_policy
 hash_netport_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = {
        [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
        [IPSET_ATTR_PORT]       = { .type = NLA_U16 },
+       [IPSET_ATTR_PORT_TO]    = { .type = NLA_U16 },
        [IPSET_ATTR_PROTO]      = { .type = NLA_U8 },
        [IPSET_ATTR_CIDR]       = { .type = NLA_U8 },
        [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
@@ -192,6 +193,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport4_elem data = { .cidr = HOST_MASK };
+       u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -241,9 +243,28 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !tb[IPSET_ATTR_PORT_TO]) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       port = ntohs(data.port);
+       port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+       if (port > port_to)
+               swap(port, port_to);
+
+       for (; port <= port_to; port++) {
+               data.port = htons(port);
+               ret = adtfn(set, &data, timeout);
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+       }
+       return ret;
 }
 
 static bool
@@ -402,6 +423,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
        struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
        ipset_adtfn adtfn = set->variant->adt[adt];
        struct hash_netport6_elem data = { .cidr = HOST_MASK };
+       u32 port, port_to;
        u32 timeout = h->timeout;
        int ret;
 
@@ -451,9 +473,28 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
                timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
        }
 
-       ret = adtfn(set, &data, timeout);
+       if (adt == IPSET_TEST
+           || !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
+           || !tb[IPSET_ATTR_PORT_TO]) {
+               ret = adtfn(set, &data, timeout);
+               return ip_set_eexist(ret, flags) ? 0 : ret;
+       }
+
+       port = ntohs(data.port);
+       port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
+       if (port > port_to)
+               swap(port, port_to);
+
+       for (; port <= port_to; port++) {
+               data.port = htons(port);
+               ret = adtfn(set, &data, timeout);
 
-       return ip_set_eexist(ret, flags) ? 0 : ret;
+               if (ret && !ip_set_eexist(ret, flags))
+                       return ret;
+               else
+                       ret = 0;
+       }
+       return ret;
 }
 
 /* Create hash:ip type of sets */