summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2010-12-17 21:28:18 +0100
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2010-12-17 21:28:18 +0100
commit62a05ab5fe3e5b60057fef9e669137cacab6b614 (patch)
treee2e80b13d4c1a672ca38b3a52672edd75eca2f5c
parent0aec3af45d839beb5054c6f0ed7ff9b115b8d907 (diff)
Support adding/deleting multiple entries, kernel part.
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.
-rw-r--r--kernel/ip_set_hash_ipport.c76
-rw-r--r--kernel/ip_set_hash_ipportip.c76
-rw-r--r--kernel/ip_set_hash_ipportnet.c76
-rw-r--r--kernel/ip_set_hash_netport.c49
4 files changed, 261 insertions, 16 deletions
diff --git a/kernel/ip_set_hash_ipport.c b/kernel/ip_set_hash_ipport.c
index d201adf..d9ee214 100644
--- a/kernel/ip_set_hash_ipport.c
+++ b/kernel/ip_set_hash_ipport.c
@@ -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 */
diff --git a/kernel/ip_set_hash_ipportip.c b/kernel/ip_set_hash_ipportip.c
index 53c9e7a..b0aaf08 100644
--- a/kernel/ip_set_hash_ipportip.c
+++ b/kernel/ip_set_hash_ipportip.c
@@ -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 */
diff --git a/kernel/ip_set_hash_ipportnet.c b/kernel/ip_set_hash_ipportnet.c
index 293fc31..6886aa8 100644
--- a/kernel/ip_set_hash_ipportnet.c
+++ b/kernel/ip_set_hash_ipportnet.c
@@ -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 */
diff --git a/kernel/ip_set_hash_netport.c b/kernel/ip_set_hash_netport.c
index 71539d4..2c42c5b 100644
--- a/kernel/ip_set_hash_netport.c
+++ b/kernel/ip_set_hash_netport.c
@@ -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 */