From 0d32c5c070f817229110f92d7b31df9a3e4eeec5 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Sun, 24 Oct 2010 21:42:48 +0200 Subject: Fixes, cleanups, comments - More comments added to the code - ICMP and ICMPv6 support added to the hash:ip,port, hash:ip,port,ip and hash:ip,port,net types - hash:net and hash:ip,port,net types are reworked - hash:net,port type added - Wrong direction parameters fixed in hash:ip,port - Helps and manpage are updated - More tests added - Ugly macros are rewritten to functions in parse.c (Holger Eitzenberger) - resize related bug in hash types fixed (Holger Eitzenberger) - autoreconf patches by Jan Engelhardt applied - netlink patch minimalized: dumping can be initialized by a second parsing of the message (thanks to David and Patrick for the suggestion) - IPv4/IPv6 address attributes are introduced in order to fix the context (suggested by David) --- kernel/ip_set_hash_ipportnet.c | 128 +++++++++++++++-------------------------- 1 file changed, 47 insertions(+), 81 deletions(-) (limited to 'kernel/ip_set_hash_ipportnet.c') diff --git a/kernel/ip_set_hash_ipportnet.c b/kernel/ip_set_hash_ipportnet.c index f2c0d07..3904168 100644 --- a/kernel/ip_set_hash_ipportnet.c +++ b/kernel/ip_set_hash_ipportnet.c @@ -115,12 +115,11 @@ static inline bool hash_ipportnet4_data_list(struct sk_buff *skb, const struct hash_ipportnet4_elem *data) { - NLA_PUT_NET32(skb, IPSET_ATTR_IP, data->ip); - NLA_PUT_NET32(skb, IPSET_ATTR_IP2, data->ip2); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -134,12 +133,11 @@ hash_ipportnet4_data_tlist(struct sk_buff *skb, const struct hash_ipportnet4_telem *tdata = (const struct hash_ipportnet4_telem *)data; - NLA_PUT_NET32(skb, IPSET_ATTR_IP, tdata->ip); - NLA_PUT_NET32(skb, IPSET_ATTR_IP2, tdata->ip2); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip); + NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(tdata->timeout))); @@ -163,8 +161,7 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet4_elem data = - { .cidr = h->nets[0].cidr || HOST_MASK, - .proto = h->proto }; + { .cidr = h->nets[0].cidr || HOST_MASK }; if (data.cidr == 0) return -EINVAL; @@ -183,9 +180,9 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, } static const struct nla_policy -hash_ipportnet4_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_U32 }, - [IPSET_ATTR_IP2] = { .type = NLA_U32 }, +hash_ipportnet_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { + [IPSET_ATTR_IP] = { .type = NLA_NESTED }, + [IPSET_ATTR_IP2] = { .type = NLA_NESTED }, [IPSET_ATTR_PORT] = { .type = NLA_U16 }, [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, @@ -200,27 +197,24 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportnet4_elem data = { .cidr = HOST_MASK, - .proto = h->proto }; + struct hash_ipportnet4_elem data = { .cidr = HOST_MASK }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportnet4_adt_policy)) + hash_ipportnet_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - data.ip = ip_set_get_n32(tb[IPSET_ATTR_IP]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; - if (tb[IPSET_ATTR_IP2]) - data.ip2 = ip_set_get_n32(tb[IPSET_ATTR_IP2]); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2); + if (ret) + return ret; if (tb[IPSET_ATTR_CIDR2]) data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); @@ -238,15 +232,15 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMP: break; default: data.port = 0; @@ -259,7 +253,7 @@ 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, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -273,7 +267,6 @@ hash_ipportnet_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 && x->timeout == y->timeout - && x->proto == y->proto && x->array_size == y->array_size && x->chain_limit == y->chain_limit; } @@ -358,12 +351,11 @@ static inline bool hash_ipportnet6_data_list(struct sk_buff *skb, const struct hash_ipportnet6_elem *data) { - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &data->ip); - NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); return 0; nla_put_failure: @@ -377,12 +369,11 @@ hash_ipportnet6_data_tlist(struct sk_buff *skb, const struct hash_ipportnet6_telem *e = (const struct hash_ipportnet6_telem *)data; - NLA_PUT(skb, IPSET_ATTR_IP, sizeof(struct in6_addr), &e->ip); - NLA_PUT(skb, IPSET_ATTR_IP2, sizeof(struct in6_addr), &data->ip2); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip); + NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2); NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port); NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr); - if (data->proto != IPSET_IPPROTO_TCPUDP) - NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); + NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto); NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(ip_set_timeout_get(e->timeout))); return 0; @@ -405,8 +396,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, struct chash *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; struct hash_ipportnet6_elem data = - { .cidr = h->nets[0].cidr || HOST_MASK, - .proto = h->proto }; + { .cidr = h->nets[0].cidr || HOST_MASK }; if (data.cidr == 0) return -EINVAL; @@ -424,19 +414,6 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, return adtfn(set, &data, GFP_ATOMIC, h->timeout); } -static const struct nla_policy -hash_ipportnet6_adt_policy[IPSET_ATTR_ADT_MAX + 1] __read_mostly = { - [IPSET_ATTR_IP] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_IP2] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr) }, - [IPSET_ATTR_PORT] = { .type = NLA_U16 }, - [IPSET_ATTR_CIDR2] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, - [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, - [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, -}; - static int hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, enum ipset_adt adt, u32 *lineno, u32 flags) @@ -444,29 +421,24 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, struct chash *h = set->data; struct nlattr *tb[IPSET_ATTR_ADT_MAX+1]; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_ipportnet6_elem data = { .cidr = HOST_MASK, - .proto = h->proto }; + struct hash_ipportnet6_elem data = { .cidr = HOST_MASK }; u32 timeout = h->timeout; int ret; if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len, - hash_ipportnet6_adt_policy)) + hash_ipportnet_adt_policy)) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); - if (tb[IPSET_ATTR_IP]) - memcpy(&data.ip, nla_data(tb[IPSET_ATTR_IP]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip); + if (ret) + return ret; - if (tb[IPSET_ATTR_IP2]) - memcpy(&data.ip2, nla_data(tb[IPSET_ATTR_IP2]), - sizeof(struct in6_addr)); - else - return -IPSET_ERR_PROTOCOL; + ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2); + if (ret) + return ret; if (tb[IPSET_ATTR_CIDR2]) data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]); @@ -484,15 +456,15 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len, if (tb[IPSET_ATTR_PROTO]) { data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (data.proto == 0 || data.proto >= IPSET_IPPROTO_TCPUDP) + if (data.proto == 0) return -IPSET_ERR_INVALID_PROTO; - } else if (data.proto == IPSET_IPPROTO_ANY) + } else return -IPSET_ERR_MISSING_PROTO; switch (data.proto) { case IPPROTO_UDP: case IPPROTO_TCP: - case IPSET_IPPROTO_TCPUDP: + case IPPROTO_ICMPV6: break; default: data.port = 0; @@ -505,7 +477,7 @@ 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, GFP_KERNEL, timeout); + ret = adtfn(set, &data, GFP_ATOMIC, timeout); return ip_set_eexist(ret, flags) ? 0 : ret; } @@ -518,7 +490,6 @@ hash_ipportnet_create_policy[IPSET_ATTR_CREATE_MAX+1] __read_mostly = { [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, - [IPSET_ATTR_PROTO] = { .type = NLA_U8 }, [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, }; @@ -529,7 +500,6 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1]; struct chash *h; u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM; - u8 proto = IPSET_IPPROTO_TCPUDP; /* Backward compatibility */ if (!(set->family == AF_INET || set->family == AF_INET6)) return -IPSET_ERR_INVALID_FAMILY; @@ -547,14 +517,9 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, if (tb[IPSET_ATTR_MAXELEM]) maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]); - if (tb[IPSET_ATTR_PROTO]) { - proto = nla_get_u8(tb[IPSET_ATTR_PROTO]); - if (!proto) - return -IPSET_ERR_INVALID_PROTO; - } h = kzalloc(sizeof(*h) + sizeof(struct chash_nets) - * (set->family == AF_INET ? 31 : 127), GFP_KERNEL); + * (set->family == AF_INET ? 32 : 128), GFP_KERNEL); h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) return -ENOMEM; @@ -563,11 +528,11 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, h->array_size = CHASH_DEFAULT_ARRAY_SIZE; h->chain_limit = CHASH_DEFAULT_CHAIN_LIMIT; get_random_bytes(&h->initval, sizeof(h->initval)); - h->proto = proto; h->timeout = IPSET_NO_TIMEOUT; - h->htable = ip_set_alloc(jhash_size(h->htable_bits) * sizeof(struct slist), - GFP_KERNEL); + h->htable = ip_set_alloc( + jhash_size(h->htable_bits) * sizeof(struct slist), + GFP_KERNEL); if (!h->htable) { kfree(h); return -ENOMEM; @@ -579,7 +544,8 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head, h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); set->variant = set->family == AF_INET - ? &hash_ipportnet4_tvariant : &hash_ipportnet6_tvariant; + ? &hash_ipportnet4_tvariant + : &hash_ipportnet6_tvariant; if (set->family == AF_INET) hash_ipportnet4_gc_init(set); -- cgit v1.2.3