mirror of https://gitee.com/openkylin/linux.git
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Pablo Neira Ayuso says: ==================== The following patchset contains Netfilter updates for your net-next tree, mostly ipset improvements and enhancements features, they are: * Don't call ip_nest_end needlessly in the error path from me, suggested by Pablo Neira Ayuso, from Jozsef Kadlecsik. * Fixed sparse warnings about shadowed variable and missing rcu annotation and fix of "may be used uninitialized" warnings, also from Jozsef. * Renamed simple macro names to avoid namespace issues, reported by David Laight, again from Jozsef. * Use fix sized type for timeout in the extension part, and cosmetic ordering of matches and targets separatedly in xt_set.c, from Jozsef. * Support package fragments for IPv4 protos without ports from Anders K. Pedersen. For example this allows a hash:ip,port ipset containing the entry 192.168.0.1,gre:0 to match all package fragments for PPTP VPN tunnels to/from the host. Without this patch only the first package fragment (with fragment offset 0) was matched. * Introduced a new operation to get both setname and family, from Jozsef. ip[6]tables set match and SET target need to know the family of the set in order to reject adding rules which refer to a set with a non-mathcing family. Currently such rules are silently accepted and then ignored instead of generating an error message to the user. * Reworked extensions support in ipset types from Jozsef. The approach of defining structures with all variations is not manageable as the number of extensions grows. Therefore a blob for the extensions is introduced, somewhat similar to conntrack. The support of extensions which need a per data destroy function is added as well. * When an element timed out in a list:set type of set, the garbage collector skipped the checking of the next element. So the purging was delayed to the next run of the gc, fixed by Jozsef. * A small Kconfig fix: NETFILTER_NETLINK cannot be selected and ipset requires it. * hash:net,net type from Oliver Smith. The type provides the ability to store pairs of subnets in a set. * Comment for ipset entries from Oliver Smith. This makes possible to annotate entries in a set with comments, for example: ipset n foo hash:net,net comment ipset a foo 10.0.0.0/21,192.168.1.0/24 comment "office nets A and B" * Fix of hash types resizing with comment extension from Jozsef. * Fix of new extensions for list:set type when an element is added into a slot from where another element was pushed away from Jozsef. * Introduction of a common function for the listing of the element extensions from Jozsef. * Net namespace support for ipset from Vitaly Lavrov. * hash:net,port,net type from Oliver Smith, which makes possible to store the triples of two subnets and a protocol, port pair in a set. * Get xt_TCPMSS working with net namespace, by Gao feng. * Use the proper net netnamespace to allocate skbs, also by Gao feng. * A couple of cleanups for the conntrack SIP helper, by Holger Eitzenberger. * Extend cttimeout to allow setting default conntrack timeouts via nfnetlink, so we can get rid of all our sysctl/proc interfaces in the future for timeout tuning, from me. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d639feaaf3
|
@ -49,31 +49,68 @@ enum ip_set_feature {
|
|||
|
||||
/* Set extensions */
|
||||
enum ip_set_extension {
|
||||
IPSET_EXT_NONE = 0,
|
||||
IPSET_EXT_BIT_TIMEOUT = 1,
|
||||
IPSET_EXT_BIT_TIMEOUT = 0,
|
||||
IPSET_EXT_TIMEOUT = (1 << IPSET_EXT_BIT_TIMEOUT),
|
||||
IPSET_EXT_BIT_COUNTER = 2,
|
||||
IPSET_EXT_BIT_COUNTER = 1,
|
||||
IPSET_EXT_COUNTER = (1 << IPSET_EXT_BIT_COUNTER),
|
||||
};
|
||||
|
||||
/* Extension offsets */
|
||||
enum ip_set_offset {
|
||||
IPSET_OFFSET_TIMEOUT = 0,
|
||||
IPSET_OFFSET_COUNTER,
|
||||
IPSET_OFFSET_MAX,
|
||||
IPSET_EXT_BIT_COMMENT = 2,
|
||||
IPSET_EXT_COMMENT = (1 << IPSET_EXT_BIT_COMMENT),
|
||||
/* Mark set with an extension which needs to call destroy */
|
||||
IPSET_EXT_BIT_DESTROY = 7,
|
||||
IPSET_EXT_DESTROY = (1 << IPSET_EXT_BIT_DESTROY),
|
||||
};
|
||||
|
||||
#define SET_WITH_TIMEOUT(s) ((s)->extensions & IPSET_EXT_TIMEOUT)
|
||||
#define SET_WITH_COUNTER(s) ((s)->extensions & IPSET_EXT_COUNTER)
|
||||
#define SET_WITH_COMMENT(s) ((s)->extensions & IPSET_EXT_COMMENT)
|
||||
|
||||
/* Extension id, in size order */
|
||||
enum ip_set_ext_id {
|
||||
IPSET_EXT_ID_COUNTER = 0,
|
||||
IPSET_EXT_ID_TIMEOUT,
|
||||
IPSET_EXT_ID_COMMENT,
|
||||
IPSET_EXT_ID_MAX,
|
||||
};
|
||||
|
||||
/* Extension type */
|
||||
struct ip_set_ext_type {
|
||||
/* Destroy extension private data (can be NULL) */
|
||||
void (*destroy)(void *ext);
|
||||
enum ip_set_extension type;
|
||||
enum ipset_cadt_flags flag;
|
||||
/* Size and minimal alignment */
|
||||
u8 len;
|
||||
u8 align;
|
||||
};
|
||||
|
||||
extern const struct ip_set_ext_type ip_set_extensions[];
|
||||
|
||||
struct ip_set_ext {
|
||||
unsigned long timeout;
|
||||
u64 packets;
|
||||
u64 bytes;
|
||||
u32 timeout;
|
||||
char *comment;
|
||||
};
|
||||
|
||||
struct ip_set_counter {
|
||||
atomic64_t bytes;
|
||||
atomic64_t packets;
|
||||
};
|
||||
|
||||
struct ip_set_comment {
|
||||
char *str;
|
||||
};
|
||||
|
||||
struct ip_set;
|
||||
|
||||
#define ext_timeout(e, s) \
|
||||
(unsigned long *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_TIMEOUT])
|
||||
#define ext_counter(e, s) \
|
||||
(struct ip_set_counter *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COUNTER])
|
||||
#define ext_comment(e, s) \
|
||||
(struct ip_set_comment *)(((void *)(e)) + (s)->offset[IPSET_EXT_ID_COMMENT])
|
||||
|
||||
|
||||
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
|
||||
const struct ip_set_ext *ext,
|
||||
struct ip_set_ext *mext, u32 cmdflags);
|
||||
|
@ -147,7 +184,8 @@ struct ip_set_type {
|
|||
u8 revision_min, revision_max;
|
||||
|
||||
/* Create set */
|
||||
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
|
||||
int (*create)(struct net *net, struct ip_set *set,
|
||||
struct nlattr *tb[], u32 flags);
|
||||
|
||||
/* Attribute policies */
|
||||
const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1];
|
||||
|
@ -179,14 +217,45 @@ struct ip_set {
|
|||
u8 revision;
|
||||
/* Extensions */
|
||||
u8 extensions;
|
||||
/* Default timeout value, if enabled */
|
||||
u32 timeout;
|
||||
/* Element data size */
|
||||
size_t dsize;
|
||||
/* Offsets to extensions in elements */
|
||||
size_t offset[IPSET_EXT_ID_MAX];
|
||||
/* The type specific data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct ip_set_counter {
|
||||
atomic64_t bytes;
|
||||
atomic64_t packets;
|
||||
};
|
||||
static inline void
|
||||
ip_set_ext_destroy(struct ip_set *set, void *data)
|
||||
{
|
||||
/* Check that the extension is enabled for the set and
|
||||
* call it's destroy function for its extension part in data.
|
||||
*/
|
||||
if (SET_WITH_COMMENT(set))
|
||||
ip_set_extensions[IPSET_EXT_ID_COMMENT].destroy(
|
||||
ext_comment(data, set));
|
||||
}
|
||||
|
||||
static inline int
|
||||
ip_set_put_flags(struct sk_buff *skb, struct ip_set *set)
|
||||
{
|
||||
u32 cadt_flags = 0;
|
||||
|
||||
if (SET_WITH_TIMEOUT(set))
|
||||
if (unlikely(nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(set->timeout))))
|
||||
return -EMSGSIZE;
|
||||
if (SET_WITH_COUNTER(set))
|
||||
cadt_flags |= IPSET_FLAG_WITH_COUNTERS;
|
||||
if (SET_WITH_COMMENT(set))
|
||||
cadt_flags |= IPSET_FLAG_WITH_COMMENT;
|
||||
|
||||
if (!cadt_flags)
|
||||
return 0;
|
||||
return nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(cadt_flags));
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip_set_add_bytes(u64 bytes, struct ip_set_counter *counter)
|
||||
|
@ -248,12 +317,13 @@ ip_set_init_counter(struct ip_set_counter *counter,
|
|||
}
|
||||
|
||||
/* register and unregister set references */
|
||||
extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set);
|
||||
extern void ip_set_put_byindex(ip_set_id_t index);
|
||||
extern const char *ip_set_name_byindex(ip_set_id_t index);
|
||||
extern ip_set_id_t ip_set_nfnl_get(const char *name);
|
||||
extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index);
|
||||
extern void ip_set_nfnl_put(ip_set_id_t index);
|
||||
extern ip_set_id_t ip_set_get_byname(struct net *net,
|
||||
const char *name, struct ip_set **set);
|
||||
extern void ip_set_put_byindex(struct net *net, ip_set_id_t index);
|
||||
extern const char *ip_set_name_byindex(struct net *net, ip_set_id_t index);
|
||||
extern ip_set_id_t ip_set_nfnl_get(struct net *net, const char *name);
|
||||
extern ip_set_id_t ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index);
|
||||
extern void ip_set_nfnl_put(struct net *net, ip_set_id_t index);
|
||||
|
||||
/* API for iptables set match, and SET target */
|
||||
|
||||
|
@ -272,6 +342,8 @@ extern void *ip_set_alloc(size_t size);
|
|||
extern void ip_set_free(void *members);
|
||||
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
|
||||
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
|
||||
extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[],
|
||||
size_t len);
|
||||
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
|
||||
struct ip_set_ext *ext);
|
||||
|
||||
|
@ -389,13 +461,40 @@ bitmap_bytes(u32 a, u32 b)
|
|||
}
|
||||
|
||||
#include <linux/netfilter/ipset/ip_set_timeout.h>
|
||||
#include <linux/netfilter/ipset/ip_set_comment.h>
|
||||
|
||||
#define IP_SET_INIT_KEXT(skb, opt, map) \
|
||||
static inline int
|
||||
ip_set_put_extensions(struct sk_buff *skb, const struct ip_set *set,
|
||||
const void *e, bool active)
|
||||
{
|
||||
if (SET_WITH_TIMEOUT(set)) {
|
||||
unsigned long *timeout = ext_timeout(e, set);
|
||||
|
||||
if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(active ? ip_set_timeout_get(timeout)
|
||||
: *timeout)))
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
if (SET_WITH_COUNTER(set) &&
|
||||
ip_set_put_counter(skb, ext_counter(e, set)))
|
||||
return -EMSGSIZE;
|
||||
if (SET_WITH_COMMENT(set) &&
|
||||
ip_set_put_comment(skb, ext_comment(e, set)))
|
||||
return -EMSGSIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define IP_SET_INIT_KEXT(skb, opt, set) \
|
||||
{ .bytes = (skb)->len, .packets = 1, \
|
||||
.timeout = ip_set_adt_opt_timeout(opt, map) }
|
||||
.timeout = ip_set_adt_opt_timeout(opt, set) }
|
||||
|
||||
#define IP_SET_INIT_UEXT(map) \
|
||||
#define IP_SET_INIT_UEXT(set) \
|
||||
{ .bytes = ULLONG_MAX, .packets = ULLONG_MAX, \
|
||||
.timeout = (map)->timeout }
|
||||
.timeout = (set)->timeout }
|
||||
|
||||
#define IP_SET_INIT_CIDR(a, b) ((a) ? (a) : (b))
|
||||
|
||||
#define IPSET_CONCAT(a, b) a##b
|
||||
#define IPSET_TOKEN(a, b) IPSET_CONCAT(a, b)
|
||||
|
||||
#endif /*_IP_SET_H */
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#ifndef _IP_SET_COMMENT_H
|
||||
#define _IP_SET_COMMENT_H
|
||||
|
||||
/* Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
static inline char*
|
||||
ip_set_comment_uget(struct nlattr *tb)
|
||||
{
|
||||
return nla_data(tb);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip_set_init_comment(struct ip_set_comment *comment,
|
||||
const struct ip_set_ext *ext)
|
||||
{
|
||||
size_t len = ext->comment ? strlen(ext->comment) : 0;
|
||||
|
||||
if (unlikely(comment->str)) {
|
||||
kfree(comment->str);
|
||||
comment->str = NULL;
|
||||
}
|
||||
if (!len)
|
||||
return;
|
||||
if (unlikely(len > IPSET_MAX_COMMENT_SIZE))
|
||||
len = IPSET_MAX_COMMENT_SIZE;
|
||||
comment->str = kzalloc(len + 1, GFP_ATOMIC);
|
||||
if (unlikely(!comment->str))
|
||||
return;
|
||||
strlcpy(comment->str, ext->comment, len + 1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ip_set_put_comment(struct sk_buff *skb, struct ip_set_comment *comment)
|
||||
{
|
||||
if (!comment->str)
|
||||
return 0;
|
||||
return nla_put_string(skb, IPSET_ATTR_COMMENT, comment->str);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip_set_comment_free(struct ip_set_comment *comment)
|
||||
{
|
||||
if (unlikely(!comment->str))
|
||||
return;
|
||||
kfree(comment->str);
|
||||
comment->str = NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
|
@ -23,8 +23,8 @@
|
|||
/* Set is defined with timeout support: timeout value may be 0 */
|
||||
#define IPSET_NO_TIMEOUT UINT_MAX
|
||||
|
||||
#define ip_set_adt_opt_timeout(opt, map) \
|
||||
((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (map)->timeout)
|
||||
#define ip_set_adt_opt_timeout(opt, set) \
|
||||
((opt)->ext.timeout != IPSET_NO_TIMEOUT ? (opt)->ext.timeout : (set)->timeout)
|
||||
|
||||
static inline unsigned int
|
||||
ip_set_timeout_uget(struct nlattr *tb)
|
||||
|
|
|
@ -107,14 +107,17 @@ enum sdp_header_types {
|
|||
SDP_HDR_MEDIA,
|
||||
};
|
||||
|
||||
extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
|
||||
struct nf_nat_sip_hooks {
|
||||
unsigned int (*msg)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
unsigned int *datalen);
|
||||
extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb,
|
||||
|
||||
void (*seq_adjust)(struct sk_buff *skb,
|
||||
unsigned int protoff, s16 off);
|
||||
extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
|
||||
|
||||
unsigned int (*expect)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
|
@ -122,7 +125,8 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
|
|||
struct nf_conntrack_expect *exp,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen);
|
||||
extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
|
||||
|
||||
unsigned int (*sdp_addr)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
|
@ -131,7 +135,8 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
|
|||
enum sdp_header_types type,
|
||||
enum sdp_header_types term,
|
||||
const union nf_inet_addr *addr);
|
||||
extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
|
||||
|
||||
unsigned int (*sdp_port)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
|
@ -139,14 +144,16 @@ extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
|
|||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
u_int16_t port);
|
||||
extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
|
||||
|
||||
unsigned int (*sdp_session)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
unsigned int *datalen,
|
||||
unsigned int sdpoff,
|
||||
const union nf_inet_addr *addr);
|
||||
extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
|
||||
|
||||
unsigned int (*sdp_media)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
|
@ -156,6 +163,8 @@ extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
|
|||
unsigned int mediaoff,
|
||||
unsigned int medialen,
|
||||
union nf_inet_addr *rtp_addr);
|
||||
};
|
||||
extern const struct nf_nat_sip_hooks *nf_nat_sip_hooks;
|
||||
|
||||
int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr,
|
||||
unsigned int datalen, unsigned int *matchoff,
|
||||
|
|
|
@ -10,12 +10,14 @@
|
|||
#ifndef _UAPI_IP_SET_H
|
||||
#define _UAPI_IP_SET_H
|
||||
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 6
|
||||
|
||||
/* The maximum permissible comment length we will accept over netlink */
|
||||
#define IPSET_MAX_COMMENT_SIZE 255
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
|
||||
|
@ -110,6 +112,7 @@ enum {
|
|||
IPSET_ATTR_IFACE,
|
||||
IPSET_ATTR_BYTES,
|
||||
IPSET_ATTR_PACKETS,
|
||||
IPSET_ATTR_COMMENT,
|
||||
__IPSET_ATTR_ADT_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
|
||||
|
@ -140,6 +143,7 @@ enum ipset_errno {
|
|||
IPSET_ERR_IPADDR_IPV4,
|
||||
IPSET_ERR_IPADDR_IPV6,
|
||||
IPSET_ERR_COUNTER,
|
||||
IPSET_ERR_COMMENT,
|
||||
|
||||
/* Type specific error codes */
|
||||
IPSET_ERR_TYPE_SPECIFIC = 4352,
|
||||
|
@ -176,6 +180,8 @@ enum ipset_cadt_flags {
|
|||
IPSET_FLAG_NOMATCH = (1 << IPSET_FLAG_BIT_NOMATCH),
|
||||
IPSET_FLAG_BIT_WITH_COUNTERS = 3,
|
||||
IPSET_FLAG_WITH_COUNTERS = (1 << IPSET_FLAG_BIT_WITH_COUNTERS),
|
||||
IPSET_FLAG_BIT_WITH_COMMENT = 4,
|
||||
IPSET_FLAG_WITH_COMMENT = (1 << IPSET_FLAG_BIT_WITH_COMMENT),
|
||||
IPSET_FLAG_CADT_MAX = 15,
|
||||
};
|
||||
|
||||
|
@ -250,6 +256,14 @@ struct ip_set_req_get_set {
|
|||
#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
|
||||
/* Uses ip_set_req_get_set */
|
||||
|
||||
#define IP_SET_OP_GET_FNAME 0x00000008 /* Get set index and family */
|
||||
struct ip_set_req_get_set_family {
|
||||
unsigned int op;
|
||||
unsigned int version;
|
||||
unsigned int family;
|
||||
union ip_set_name_index set;
|
||||
};
|
||||
|
||||
#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
|
||||
struct ip_set_req_version {
|
||||
unsigned int op;
|
||||
|
|
|
@ -6,6 +6,8 @@ enum ctnl_timeout_msg_types {
|
|||
IPCTNL_MSG_TIMEOUT_NEW,
|
||||
IPCTNL_MSG_TIMEOUT_GET,
|
||||
IPCTNL_MSG_TIMEOUT_DELETE,
|
||||
IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
|
||||
IPCTNL_MSG_TIMEOUT_DEFAULT_GET,
|
||||
|
||||
IPCTNL_MSG_TIMEOUT_MAX
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
menuconfig IP_SET
|
||||
tristate "IP set support"
|
||||
depends on INET && NETFILTER
|
||||
depends on NETFILTER_NETLINK
|
||||
select NETFILTER_NETLINK
|
||||
help
|
||||
This option adds IP set support to the kernel.
|
||||
In order to define and use the sets, you need the userspace utility
|
||||
|
@ -90,6 +90,15 @@ config IP_SET_HASH_IPPORTNET
|
|||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_SET_HASH_NETPORTNET
|
||||
tristate "hash:net,port,net set support"
|
||||
depends on IP_SET
|
||||
help
|
||||
This option adds the hash:net,port,net set type support, by which
|
||||
one can store two IPv4/IPv6 subnets, and a protocol/port in a set.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_SET_HASH_NET
|
||||
tristate "hash:net set support"
|
||||
depends on IP_SET
|
||||
|
@ -99,6 +108,15 @@ config IP_SET_HASH_NET
|
|||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_SET_HASH_NETNET
|
||||
tristate "hash:net,net set support"
|
||||
depends on IP_SET
|
||||
help
|
||||
This option adds the hash:net,net set type support, by which
|
||||
one can store IPv4/IPv6 network address/prefix pairs in a set.
|
||||
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
|
||||
config IP_SET_HASH_NETPORT
|
||||
tristate "hash:net,port set support"
|
||||
depends on IP_SET
|
||||
|
|
|
@ -20,6 +20,8 @@ obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o
|
|||
obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o
|
||||
obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o
|
||||
obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o
|
||||
obj-$(CONFIG_IP_SET_HASH_NETNET) += ip_set_hash_netnet.o
|
||||
obj-$(CONFIG_IP_SET_HASH_NETPORTNET) += ip_set_hash_netportnet.o
|
||||
|
||||
# list types
|
||||
obj-$(CONFIG_IP_SET_LIST_SET) += ip_set_list_set.o
|
||||
|
|
|
@ -8,38 +8,32 @@
|
|||
#ifndef __IP_SET_BITMAP_IP_GEN_H
|
||||
#define __IP_SET_BITMAP_IP_GEN_H
|
||||
|
||||
#define CONCAT(a, b) a##b
|
||||
#define TOKEN(a,b) CONCAT(a, b)
|
||||
|
||||
#define mtype_do_test TOKEN(MTYPE, _do_test)
|
||||
#define mtype_gc_test TOKEN(MTYPE, _gc_test)
|
||||
#define mtype_is_filled TOKEN(MTYPE, _is_filled)
|
||||
#define mtype_do_add TOKEN(MTYPE, _do_add)
|
||||
#define mtype_do_del TOKEN(MTYPE, _do_del)
|
||||
#define mtype_do_list TOKEN(MTYPE, _do_list)
|
||||
#define mtype_do_head TOKEN(MTYPE, _do_head)
|
||||
#define mtype_adt_elem TOKEN(MTYPE, _adt_elem)
|
||||
#define mtype_add_timeout TOKEN(MTYPE, _add_timeout)
|
||||
#define mtype_gc_init TOKEN(MTYPE, _gc_init)
|
||||
#define mtype_kadt TOKEN(MTYPE, _kadt)
|
||||
#define mtype_uadt TOKEN(MTYPE, _uadt)
|
||||
#define mtype_destroy TOKEN(MTYPE, _destroy)
|
||||
#define mtype_flush TOKEN(MTYPE, _flush)
|
||||
#define mtype_head TOKEN(MTYPE, _head)
|
||||
#define mtype_same_set TOKEN(MTYPE, _same_set)
|
||||
#define mtype_elem TOKEN(MTYPE, _elem)
|
||||
#define mtype_test TOKEN(MTYPE, _test)
|
||||
#define mtype_add TOKEN(MTYPE, _add)
|
||||
#define mtype_del TOKEN(MTYPE, _del)
|
||||
#define mtype_list TOKEN(MTYPE, _list)
|
||||
#define mtype_gc TOKEN(MTYPE, _gc)
|
||||
#define mtype_do_test IPSET_TOKEN(MTYPE, _do_test)
|
||||
#define mtype_gc_test IPSET_TOKEN(MTYPE, _gc_test)
|
||||
#define mtype_is_filled IPSET_TOKEN(MTYPE, _is_filled)
|
||||
#define mtype_do_add IPSET_TOKEN(MTYPE, _do_add)
|
||||
#define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup)
|
||||
#define mtype_do_del IPSET_TOKEN(MTYPE, _do_del)
|
||||
#define mtype_do_list IPSET_TOKEN(MTYPE, _do_list)
|
||||
#define mtype_do_head IPSET_TOKEN(MTYPE, _do_head)
|
||||
#define mtype_adt_elem IPSET_TOKEN(MTYPE, _adt_elem)
|
||||
#define mtype_add_timeout IPSET_TOKEN(MTYPE, _add_timeout)
|
||||
#define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init)
|
||||
#define mtype_kadt IPSET_TOKEN(MTYPE, _kadt)
|
||||
#define mtype_uadt IPSET_TOKEN(MTYPE, _uadt)
|
||||
#define mtype_destroy IPSET_TOKEN(MTYPE, _destroy)
|
||||
#define mtype_flush IPSET_TOKEN(MTYPE, _flush)
|
||||
#define mtype_head IPSET_TOKEN(MTYPE, _head)
|
||||
#define mtype_same_set IPSET_TOKEN(MTYPE, _same_set)
|
||||
#define mtype_elem IPSET_TOKEN(MTYPE, _elem)
|
||||
#define mtype_test IPSET_TOKEN(MTYPE, _test)
|
||||
#define mtype_add IPSET_TOKEN(MTYPE, _add)
|
||||
#define mtype_del IPSET_TOKEN(MTYPE, _del)
|
||||
#define mtype_list IPSET_TOKEN(MTYPE, _list)
|
||||
#define mtype_gc IPSET_TOKEN(MTYPE, _gc)
|
||||
#define mtype MTYPE
|
||||
|
||||
#define ext_timeout(e, m) \
|
||||
(unsigned long *)((e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
|
||||
#define ext_counter(e, m) \
|
||||
(struct ip_set_counter *)((e) + (m)->offset[IPSET_OFFSET_COUNTER])
|
||||
#define get_ext(map, id) ((map)->extensions + (map)->dsize * (id))
|
||||
#define get_ext(set, map, id) ((map)->extensions + (set)->dsize * (id))
|
||||
|
||||
static void
|
||||
mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
|
||||
|
@ -49,10 +43,21 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
|
|||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = gc;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static void
|
||||
mtype_ext_cleanup(struct ip_set *set)
|
||||
{
|
||||
struct mtype *map = set->data;
|
||||
u32 id;
|
||||
|
||||
for (id = 0; id < map->elements; id++)
|
||||
if (test_bit(id, map->members))
|
||||
ip_set_ext_destroy(set, get_ext(set, map, id));
|
||||
}
|
||||
|
||||
static void
|
||||
mtype_destroy(struct ip_set *set)
|
||||
{
|
||||
|
@ -62,8 +67,11 @@ mtype_destroy(struct ip_set *set)
|
|||
del_timer_sync(&map->gc);
|
||||
|
||||
ip_set_free(map->members);
|
||||
if (map->dsize)
|
||||
if (set->dsize) {
|
||||
if (set->extensions & IPSET_EXT_DESTROY)
|
||||
mtype_ext_cleanup(set);
|
||||
ip_set_free(map->extensions);
|
||||
}
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
|
@ -74,6 +82,8 @@ mtype_flush(struct ip_set *set)
|
|||
{
|
||||
struct mtype *map = set->data;
|
||||
|
||||
if (set->extensions & IPSET_EXT_DESTROY)
|
||||
mtype_ext_cleanup(set);
|
||||
memset(map->members, 0, map->memsize);
|
||||
}
|
||||
|
||||
|
@ -91,12 +101,9 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
|
|||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) +
|
||||
map->memsize +
|
||||
map->dsize * map->elements)) ||
|
||||
(SET_WITH_TIMEOUT(set) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
|
||||
(SET_WITH_COUNTER(set) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
|
||||
htonl(IPSET_FLAG_WITH_COUNTERS))))
|
||||
set->dsize * map->elements)))
|
||||
goto nla_put_failure;
|
||||
if (unlikely(ip_set_put_flags(skb, set)))
|
||||
goto nla_put_failure;
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
|
@ -111,16 +118,16 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
{
|
||||
struct mtype *map = set->data;
|
||||
const struct mtype_adt_elem *e = value;
|
||||
void *x = get_ext(map, e->id);
|
||||
int ret = mtype_do_test(e, map);
|
||||
void *x = get_ext(set, map, e->id);
|
||||
int ret = mtype_do_test(e, map, set->dsize);
|
||||
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(x, map)))
|
||||
ip_set_timeout_expired(ext_timeout(x, set)))
|
||||
return 0;
|
||||
if (SET_WITH_COUNTER(set))
|
||||
ip_set_update_counter(ext_counter(x, map), ext, mext, flags);
|
||||
ip_set_update_counter(ext_counter(x, set), ext, mext, flags);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -130,26 +137,30 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
{
|
||||
struct mtype *map = set->data;
|
||||
const struct mtype_adt_elem *e = value;
|
||||
void *x = get_ext(map, e->id);
|
||||
int ret = mtype_do_add(e, map, flags);
|
||||
void *x = get_ext(set, map, e->id);
|
||||
int ret = mtype_do_add(e, map, flags, set->dsize);
|
||||
|
||||
if (ret == IPSET_ADD_FAILED) {
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(x, map)))
|
||||
ip_set_timeout_expired(ext_timeout(x, set)))
|
||||
ret = 0;
|
||||
else if (!(flags & IPSET_FLAG_EXIST))
|
||||
return -IPSET_ERR_EXIST;
|
||||
/* Element is re-added, cleanup extensions */
|
||||
ip_set_ext_destroy(set, x);
|
||||
}
|
||||
|
||||
if (SET_WITH_TIMEOUT(set))
|
||||
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
|
||||
mtype_add_timeout(ext_timeout(x, map), e, ext, map, ret);
|
||||
mtype_add_timeout(ext_timeout(x, set), e, ext, set, map, ret);
|
||||
#else
|
||||
ip_set_timeout_set(ext_timeout(x, map), ext->timeout);
|
||||
ip_set_timeout_set(ext_timeout(x, set), ext->timeout);
|
||||
#endif
|
||||
|
||||
if (SET_WITH_COUNTER(set))
|
||||
ip_set_init_counter(ext_counter(x, map), ext);
|
||||
ip_set_init_counter(ext_counter(x, set), ext);
|
||||
if (SET_WITH_COMMENT(set))
|
||||
ip_set_init_comment(ext_comment(x, set), ext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -159,16 +170,27 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
{
|
||||
struct mtype *map = set->data;
|
||||
const struct mtype_adt_elem *e = value;
|
||||
const void *x = get_ext(map, e->id);
|
||||
void *x = get_ext(set, map, e->id);
|
||||
|
||||
if (mtype_do_del(e, map) ||
|
||||
(SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(x, map))))
|
||||
if (mtype_do_del(e, map))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
ip_set_ext_destroy(set, x);
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(x, set)))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef IP_SET_BITMAP_STORED_TIMEOUT
|
||||
static inline bool
|
||||
mtype_is_filled(const struct mtype_elem *x)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
mtype_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
|
@ -183,13 +205,13 @@ mtype_list(const struct ip_set *set,
|
|||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->elements; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
x = get_ext(map, id);
|
||||
x = get_ext(set, map, id);
|
||||
if (!test_bit(id, map->members) ||
|
||||
(SET_WITH_TIMEOUT(set) &&
|
||||
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
|
||||
mtype_is_filled((const struct mtype_elem *) x) &&
|
||||
#endif
|
||||
ip_set_timeout_expired(ext_timeout(x, map))))
|
||||
ip_set_timeout_expired(ext_timeout(x, set))))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
|
@ -199,23 +221,10 @@ mtype_list(const struct ip_set *set,
|
|||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
if (mtype_do_list(skb, map, id))
|
||||
if (mtype_do_list(skb, map, id, set->dsize))
|
||||
goto nla_put_failure;
|
||||
if (SET_WITH_TIMEOUT(set)) {
|
||||
#ifdef IP_SET_BITMAP_STORED_TIMEOUT
|
||||
if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_stored(map, id,
|
||||
ext_timeout(x, map)))))
|
||||
goto nla_put_failure;
|
||||
#else
|
||||
if (nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(
|
||||
ext_timeout(x, map)))))
|
||||
goto nla_put_failure;
|
||||
#endif
|
||||
}
|
||||
if (SET_WITH_COUNTER(set) &&
|
||||
ip_set_put_counter(skb, ext_counter(x, map)))
|
||||
if (ip_set_put_extensions(skb, set, x,
|
||||
mtype_is_filled((const struct mtype_elem *) x)))
|
||||
goto nla_put_failure;
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
|
@ -228,11 +237,11 @@ mtype_list(const struct ip_set *set,
|
|||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, adt);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
ipset_nest_end(skb, adt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -241,21 +250,23 @@ mtype_gc(unsigned long ul_set)
|
|||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct mtype *map = set->data;
|
||||
const void *x;
|
||||
void *x;
|
||||
u32 id;
|
||||
|
||||
/* We run parallel with other readers (test element)
|
||||
* but adding/deleting new entries is locked out */
|
||||
read_lock_bh(&set->lock);
|
||||
for (id = 0; id < map->elements; id++)
|
||||
if (mtype_gc_test(id, map)) {
|
||||
x = get_ext(map, id);
|
||||
if (ip_set_timeout_expired(ext_timeout(x, map)))
|
||||
if (mtype_gc_test(id, map, set->dsize)) {
|
||||
x = get_ext(set, map, id);
|
||||
if (ip_set_timeout_expired(ext_timeout(x, set))) {
|
||||
clear_bit(id, map->members);
|
||||
ip_set_ext_destroy(set, x);
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_bitmap.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define REVISION_MAX 1 /* Counter support added */
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 Counter support added */
|
||||
#define IPSET_TYPE_REV_MAX 2 /* Comment support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("bitmap:ip", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("bitmap:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_bitmap:ip");
|
||||
|
||||
#define MTYPE bitmap_ip
|
||||
|
@ -44,10 +45,7 @@ struct bitmap_ip {
|
|||
u32 elements; /* number of max elements in the set */
|
||||
u32 hosts; /* number of hosts in a subnet */
|
||||
size_t memsize; /* members size */
|
||||
size_t dsize; /* extensions struct size */
|
||||
size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
|
||||
u8 netmask; /* subnet netmask */
|
||||
u32 timeout; /* timeout parameter */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
};
|
||||
|
||||
|
@ -65,20 +63,21 @@ ip_to_id(const struct bitmap_ip *m, u32 ip)
|
|||
/* Common functions */
|
||||
|
||||
static inline int
|
||||
bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map)
|
||||
bitmap_ip_do_test(const struct bitmap_ip_adt_elem *e,
|
||||
struct bitmap_ip *map, size_t dsize)
|
||||
{
|
||||
return !!test_bit(e->id, map->members);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map)
|
||||
bitmap_ip_gc_test(u16 id, const struct bitmap_ip *map, size_t dsize)
|
||||
{
|
||||
return !!test_bit(id, map->members);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_do_add(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map,
|
||||
u32 flags)
|
||||
u32 flags, size_t dsize)
|
||||
{
|
||||
return !!test_and_set_bit(e->id, map->members);
|
||||
}
|
||||
|
@ -90,7 +89,8 @@ bitmap_ip_do_del(const struct bitmap_ip_adt_elem *e, struct bitmap_ip *map)
|
|||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id)
|
||||
bitmap_ip_do_list(struct sk_buff *skb, const struct bitmap_ip *map, u32 id,
|
||||
size_t dsize)
|
||||
{
|
||||
return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id * map->hosts));
|
||||
|
@ -113,7 +113,7 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct bitmap_ip_adt_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
u32 ip;
|
||||
|
||||
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
|
||||
|
@ -131,9 +131,9 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 ip, ip_to;
|
||||
u32 ip = 0, ip_to = 0;
|
||||
struct bitmap_ip_adt_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
|
@ -200,7 +200,7 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
|
|||
return x->first_ip == y->first_ip &&
|
||||
x->last_ip == y->last_ip &&
|
||||
x->netmask == y->netmask &&
|
||||
x->timeout == y->timeout &&
|
||||
a->timeout == b->timeout &&
|
||||
a->extensions == b->extensions;
|
||||
}
|
||||
|
||||
|
@ -209,25 +209,6 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
|
|||
struct bitmap_ip_elem {
|
||||
};
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
struct bitmap_ipt_elem {
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Plain variant with counter */
|
||||
|
||||
struct bitmap_ipc_elem {
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
/* Timeout variant with counter */
|
||||
|
||||
struct bitmap_ipct_elem {
|
||||
unsigned long timeout;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
#include "ip_set_bitmap_gen.h"
|
||||
|
||||
/* Create bitmap:ip type of sets */
|
||||
|
@ -240,8 +221,8 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
|||
map->members = ip_set_alloc(map->memsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
if (map->dsize) {
|
||||
map->extensions = ip_set_alloc(map->dsize * elements);
|
||||
if (set->dsize) {
|
||||
map->extensions = ip_set_alloc(set->dsize * elements);
|
||||
if (!map->extensions) {
|
||||
kfree(map->members);
|
||||
return false;
|
||||
|
@ -252,7 +233,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
|||
map->elements = elements;
|
||||
map->hosts = hosts;
|
||||
map->netmask = netmask;
|
||||
map->timeout = IPSET_NO_TIMEOUT;
|
||||
set->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
set->data = map;
|
||||
set->family = NFPROTO_IPV4;
|
||||
|
@ -261,10 +242,11 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
|||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
|
||||
u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map;
|
||||
u32 first_ip, last_ip, hosts, cadt_flags = 0;
|
||||
u32 first_ip = 0, last_ip = 0, hosts;
|
||||
u64 elements;
|
||||
u8 netmask = 32;
|
||||
int ret;
|
||||
|
@ -336,61 +318,15 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
|
||||
map->memsize = bitmap_bytes(0, elements - 1);
|
||||
set->variant = &bitmap_ip;
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS])
|
||||
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
|
||||
set->extensions |= IPSET_EXT_COUNTER;
|
||||
set->dsize = ip_set_elem_len(set, tb, 0);
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->dsize = sizeof(struct bitmap_ipct_elem);
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct bitmap_ipct_elem, timeout);
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct bitmap_ipct_elem, counter);
|
||||
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(
|
||||
tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
|
||||
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
bitmap_ip_gc_init(set, bitmap_ip_gc);
|
||||
} else {
|
||||
map->dsize = sizeof(struct bitmap_ipc_elem);
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct bitmap_ipc_elem, counter);
|
||||
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->dsize = sizeof(struct bitmap_ipt_elem);
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct bitmap_ipt_elem, timeout);
|
||||
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
|
||||
bitmap_ip_gc_init(set, bitmap_ip_gc);
|
||||
} else {
|
||||
map->dsize = 0;
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -401,8 +337,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
|
|||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = bitmap_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
|
@ -420,6 +356,7 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -25,12 +25,13 @@
|
|||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_bitmap.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define REVISION_MAX 1 /* Counter support added */
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 Counter support added */
|
||||
#define IPSET_TYPE_REV_MAX 2 /* Comment support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_bitmap:ip,mac");
|
||||
|
||||
#define MTYPE bitmap_ipmac
|
||||
|
@ -48,11 +49,8 @@ struct bitmap_ipmac {
|
|||
u32 first_ip; /* host byte order, included in range */
|
||||
u32 last_ip; /* host byte order, included in range */
|
||||
u32 elements; /* number of max elements in the set */
|
||||
u32 timeout; /* timeout value */
|
||||
struct timer_list gc; /* garbage collector */
|
||||
size_t memsize; /* members size */
|
||||
size_t dsize; /* size of element */
|
||||
size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
|
||||
struct timer_list gc; /* garbage collector */
|
||||
};
|
||||
|
||||
/* ADT structure for generic function args */
|
||||
|
@ -82,13 +80,13 @@ get_elem(void *extensions, u16 id, size_t dsize)
|
|||
|
||||
static inline int
|
||||
bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
|
||||
const struct bitmap_ipmac *map)
|
||||
const struct bitmap_ipmac *map, size_t dsize)
|
||||
{
|
||||
const struct bitmap_ipmac_elem *elem;
|
||||
|
||||
if (!test_bit(e->id, map->members))
|
||||
return 0;
|
||||
elem = get_elem(map->extensions, e->id, map->dsize);
|
||||
elem = get_elem(map->extensions, e->id, dsize);
|
||||
if (elem->filled == MAC_FILLED)
|
||||
return e->ether == NULL ||
|
||||
ether_addr_equal(e->ether, elem->ether);
|
||||
|
@ -97,13 +95,13 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
|
|||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map)
|
||||
bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
|
||||
{
|
||||
const struct bitmap_ipmac_elem *elem;
|
||||
|
||||
if (!test_bit(id, map->members))
|
||||
return 0;
|
||||
elem = get_elem(map->extensions, id, map->dsize);
|
||||
elem = get_elem(map->extensions, id, dsize);
|
||||
/* Timer not started for the incomplete elements */
|
||||
return elem->filled == MAC_FILLED;
|
||||
}
|
||||
|
@ -117,13 +115,13 @@ bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)
|
|||
static inline int
|
||||
bitmap_ipmac_add_timeout(unsigned long *timeout,
|
||||
const struct bitmap_ipmac_adt_elem *e,
|
||||
const struct ip_set_ext *ext,
|
||||
const struct ip_set_ext *ext, struct ip_set *set,
|
||||
struct bitmap_ipmac *map, int mode)
|
||||
{
|
||||
u32 t = ext->timeout;
|
||||
|
||||
if (mode == IPSET_ADD_START_STORED_TIMEOUT) {
|
||||
if (t == map->timeout)
|
||||
if (t == set->timeout)
|
||||
/* Timeout was not specified, get stored one */
|
||||
t = *timeout;
|
||||
ip_set_timeout_set(timeout, t);
|
||||
|
@ -142,11 +140,11 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
|
|||
|
||||
static inline int
|
||||
bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
|
||||
struct bitmap_ipmac *map, u32 flags)
|
||||
struct bitmap_ipmac *map, u32 flags, size_t dsize)
|
||||
{
|
||||
struct bitmap_ipmac_elem *elem;
|
||||
|
||||
elem = get_elem(map->extensions, e->id, map->dsize);
|
||||
elem = get_elem(map->extensions, e->id, dsize);
|
||||
if (test_and_set_bit(e->id, map->members)) {
|
||||
if (elem->filled == MAC_FILLED) {
|
||||
if (e->ether && (flags & IPSET_FLAG_EXIST))
|
||||
|
@ -178,22 +176,12 @@ bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,
|
|||
return !test_and_clear_bit(e->id, map->members);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
ip_set_timeout_stored(struct bitmap_ipmac *map, u32 id, unsigned long *timeout)
|
||||
{
|
||||
const struct bitmap_ipmac_elem *elem =
|
||||
get_elem(map->extensions, id, map->dsize);
|
||||
|
||||
return elem->filled == MAC_FILLED ? ip_set_timeout_get(timeout) :
|
||||
*timeout;
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
|
||||
u32 id)
|
||||
u32 id, size_t dsize)
|
||||
{
|
||||
const struct bitmap_ipmac_elem *elem =
|
||||
get_elem(map->extensions, id, map->dsize);
|
||||
get_elem(map->extensions, id, dsize);
|
||||
|
||||
return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id)) ||
|
||||
|
@ -216,7 +204,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
struct bitmap_ipmac *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct bitmap_ipmac_adt_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
u32 ip;
|
||||
|
||||
/* MAC can be src only */
|
||||
|
@ -245,8 +233,8 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct bitmap_ipmac *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct bitmap_ipmac_adt_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
|
||||
u32 ip;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
|
@ -285,43 +273,12 @@ bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
|
|||
|
||||
return x->first_ip == y->first_ip &&
|
||||
x->last_ip == y->last_ip &&
|
||||
x->timeout == y->timeout &&
|
||||
a->timeout == b->timeout &&
|
||||
a->extensions == b->extensions;
|
||||
}
|
||||
|
||||
/* Plain variant */
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
struct bitmap_ipmact_elem {
|
||||
struct {
|
||||
unsigned char ether[ETH_ALEN];
|
||||
unsigned char filled;
|
||||
} __attribute__ ((aligned));
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Plain variant with counter */
|
||||
|
||||
struct bitmap_ipmacc_elem {
|
||||
struct {
|
||||
unsigned char ether[ETH_ALEN];
|
||||
unsigned char filled;
|
||||
} __attribute__ ((aligned));
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
/* Timeout variant with counter */
|
||||
|
||||
struct bitmap_ipmacct_elem {
|
||||
struct {
|
||||
unsigned char ether[ETH_ALEN];
|
||||
unsigned char filled;
|
||||
} __attribute__ ((aligned));
|
||||
unsigned long timeout;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
#include "ip_set_bitmap_gen.h"
|
||||
|
||||
/* Create bitmap:ip,mac type of sets */
|
||||
|
@ -330,11 +287,11 @@ static bool
|
|||
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
||||
u32 first_ip, u32 last_ip, u32 elements)
|
||||
{
|
||||
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
|
||||
map->members = ip_set_alloc(map->memsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
if (map->dsize) {
|
||||
map->extensions = ip_set_alloc(map->dsize * elements);
|
||||
if (set->dsize) {
|
||||
map->extensions = ip_set_alloc(set->dsize * elements);
|
||||
if (!map->extensions) {
|
||||
kfree(map->members);
|
||||
return false;
|
||||
|
@ -343,7 +300,7 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
|||
map->first_ip = first_ip;
|
||||
map->last_ip = last_ip;
|
||||
map->elements = elements;
|
||||
map->timeout = IPSET_NO_TIMEOUT;
|
||||
set->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
set->data = map;
|
||||
set->family = NFPROTO_IPV4;
|
||||
|
@ -352,10 +309,10 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
|||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
|
||||
bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
|
||||
u32 flags)
|
||||
{
|
||||
u32 first_ip, last_ip, cadt_flags = 0;
|
||||
u32 first_ip = 0, last_ip = 0;
|
||||
u64 elements;
|
||||
struct bitmap_ipmac *map;
|
||||
int ret;
|
||||
|
@ -399,57 +356,15 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
|
|||
|
||||
map->memsize = bitmap_bytes(0, elements - 1);
|
||||
set->variant = &bitmap_ipmac;
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS])
|
||||
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
|
||||
set->extensions |= IPSET_EXT_COUNTER;
|
||||
set->dsize = ip_set_elem_len(set, tb,
|
||||
sizeof(struct bitmap_ipmac_elem));
|
||||
if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->dsize = sizeof(struct bitmap_ipmacct_elem);
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct bitmap_ipmacct_elem, timeout);
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct bitmap_ipmacct_elem, counter);
|
||||
|
||||
if (!init_map_ipmac(set, map, first_ip, last_ip,
|
||||
elements)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
map->timeout = ip_set_timeout_uget(
|
||||
tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
|
||||
} else {
|
||||
map->dsize = sizeof(struct bitmap_ipmacc_elem);
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct bitmap_ipmacc_elem, counter);
|
||||
|
||||
if (!init_map_ipmac(set, map, first_ip, last_ip,
|
||||
elements)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->dsize = sizeof(struct bitmap_ipmact_elem);
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct bitmap_ipmact_elem, timeout);
|
||||
|
||||
if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
|
||||
} else {
|
||||
map->dsize = sizeof(struct bitmap_ipmac_elem);
|
||||
|
||||
if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
set->variant = &bitmap_ipmac;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -460,8 +375,8 @@ static struct ip_set_type bitmap_ipmac_type = {
|
|||
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = bitmap_ipmac_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
|
@ -478,6 +393,7 @@ static struct ip_set_type bitmap_ipmac_type = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -20,12 +20,13 @@
|
|||
#include <linux/netfilter/ipset/ip_set_bitmap.h>
|
||||
#include <linux/netfilter/ipset/ip_set_getport.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define REVISION_MAX 1 /* Counter support added */
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 Counter support added */
|
||||
#define IPSET_TYPE_REV_MAX 2 /* Comment support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("bitmap:port", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("bitmap:port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_bitmap:port");
|
||||
|
||||
#define MTYPE bitmap_port
|
||||
|
@ -38,9 +39,6 @@ struct bitmap_port {
|
|||
u16 last_port; /* host byte order, included in range */
|
||||
u32 elements; /* number of max elements in the set */
|
||||
size_t memsize; /* members size */
|
||||
size_t dsize; /* extensions struct size */
|
||||
size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
|
||||
u32 timeout; /* timeout parameter */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
};
|
||||
|
||||
|
@ -59,20 +57,20 @@ port_to_id(const struct bitmap_port *m, u16 port)
|
|||
|
||||
static inline int
|
||||
bitmap_port_do_test(const struct bitmap_port_adt_elem *e,
|
||||
const struct bitmap_port *map)
|
||||
const struct bitmap_port *map, size_t dsize)
|
||||
{
|
||||
return !!test_bit(e->id, map->members);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_port_gc_test(u16 id, const struct bitmap_port *map)
|
||||
bitmap_port_gc_test(u16 id, const struct bitmap_port *map, size_t dsize)
|
||||
{
|
||||
return !!test_bit(id, map->members);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_port_do_add(const struct bitmap_port_adt_elem *e,
|
||||
struct bitmap_port *map, u32 flags)
|
||||
struct bitmap_port *map, u32 flags, size_t dsize)
|
||||
{
|
||||
return !!test_and_set_bit(e->id, map->members);
|
||||
}
|
||||
|
@ -85,7 +83,8 @@ bitmap_port_do_del(const struct bitmap_port_adt_elem *e,
|
|||
}
|
||||
|
||||
static inline int
|
||||
bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id)
|
||||
bitmap_port_do_list(struct sk_buff *skb, const struct bitmap_port *map, u32 id,
|
||||
size_t dsize)
|
||||
{
|
||||
return nla_put_net16(skb, IPSET_ATTR_PORT,
|
||||
htons(map->first_port + id));
|
||||
|
@ -106,7 +105,7 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
struct bitmap_port *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct bitmap_port_adt_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
__be16 __port;
|
||||
u16 port = 0;
|
||||
|
||||
|
@ -131,7 +130,7 @@ bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
struct bitmap_port *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct bitmap_port_adt_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 port; /* wraparound */
|
||||
u16 port_to;
|
||||
int ret = 0;
|
||||
|
@ -191,7 +190,7 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
|
|||
|
||||
return x->first_port == y->first_port &&
|
||||
x->last_port == y->last_port &&
|
||||
x->timeout == y->timeout &&
|
||||
a->timeout == b->timeout &&
|
||||
a->extensions == b->extensions;
|
||||
}
|
||||
|
||||
|
@ -200,25 +199,6 @@ bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
|
|||
struct bitmap_port_elem {
|
||||
};
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
struct bitmap_portt_elem {
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Plain variant with counter */
|
||||
|
||||
struct bitmap_portc_elem {
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
/* Timeout variant with counter */
|
||||
|
||||
struct bitmap_portct_elem {
|
||||
unsigned long timeout;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
#include "ip_set_bitmap_gen.h"
|
||||
|
||||
/* Create bitmap:ip type of sets */
|
||||
|
@ -230,8 +210,8 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
|
|||
map->members = ip_set_alloc(map->memsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
if (map->dsize) {
|
||||
map->extensions = ip_set_alloc(map->dsize * map->elements);
|
||||
if (set->dsize) {
|
||||
map->extensions = ip_set_alloc(set->dsize * map->elements);
|
||||
if (!map->extensions) {
|
||||
kfree(map->members);
|
||||
return false;
|
||||
|
@ -239,7 +219,7 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
|
|||
}
|
||||
map->first_port = first_port;
|
||||
map->last_port = last_port;
|
||||
map->timeout = IPSET_NO_TIMEOUT;
|
||||
set->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
set->data = map;
|
||||
set->family = NFPROTO_UNSPEC;
|
||||
|
@ -248,11 +228,11 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
|
|||
}
|
||||
|
||||
static int
|
||||
bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
|
||||
u32 flags)
|
||||
{
|
||||
struct bitmap_port *map;
|
||||
u16 first_port, last_port;
|
||||
u32 cadt_flags = 0;
|
||||
|
||||
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
|
@ -276,53 +256,14 @@ bitmap_port_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
map->elements = last_port - first_port + 1;
|
||||
map->memsize = map->elements * sizeof(unsigned long);
|
||||
set->variant = &bitmap_port;
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS])
|
||||
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
|
||||
set->extensions |= IPSET_EXT_COUNTER;
|
||||
set->dsize = ip_set_elem_len(set, tb, 0);
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->dsize = sizeof(struct bitmap_portct_elem);
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct bitmap_portct_elem, timeout);
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct bitmap_portct_elem, counter);
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout =
|
||||
ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
bitmap_port_gc_init(set, bitmap_port_gc);
|
||||
} else {
|
||||
map->dsize = sizeof(struct bitmap_portc_elem);
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct bitmap_portc_elem, counter);
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->dsize = sizeof(struct bitmap_portt_elem);
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct bitmap_portt_elem, timeout);
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
bitmap_port_gc_init(set, bitmap_port_gc);
|
||||
} else {
|
||||
map->dsize = 0;
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -333,8 +274,8 @@ static struct ip_set_type bitmap_port_type = {
|
|||
.features = IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = bitmap_port_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
|
@ -349,6 +290,7 @@ static struct ip_set_type bitmap_port_type = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/netns/generic.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
@ -27,8 +29,17 @@ static LIST_HEAD(ip_set_type_list); /* all registered set types */
|
|||
static DEFINE_MUTEX(ip_set_type_mutex); /* protects ip_set_type_list */
|
||||
static DEFINE_RWLOCK(ip_set_ref_lock); /* protects the set refs */
|
||||
|
||||
static struct ip_set * __rcu *ip_set_list; /* all individual sets */
|
||||
static ip_set_id_t ip_set_max = CONFIG_IP_SET_MAX; /* max number of sets */
|
||||
struct ip_set_net {
|
||||
struct ip_set * __rcu *ip_set_list; /* all individual sets */
|
||||
ip_set_id_t ip_set_max; /* max number of sets */
|
||||
int is_deleted; /* deleted by ip_set_net_exit */
|
||||
};
|
||||
static int ip_set_net_id __read_mostly;
|
||||
|
||||
static inline struct ip_set_net *ip_set_pernet(struct net *net)
|
||||
{
|
||||
return net_generic(net, ip_set_net_id);
|
||||
}
|
||||
|
||||
#define IP_SET_INC 64
|
||||
#define STREQ(a, b) (strncmp(a, b, IPSET_MAXNAMELEN) == 0)
|
||||
|
@ -45,8 +56,8 @@ MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_IPSET);
|
|||
/* When the nfnl mutex is held: */
|
||||
#define nfnl_dereference(p) \
|
||||
rcu_dereference_protected(p, 1)
|
||||
#define nfnl_set(id) \
|
||||
nfnl_dereference(ip_set_list)[id]
|
||||
#define nfnl_set(inst, id) \
|
||||
nfnl_dereference((inst)->ip_set_list)[id]
|
||||
|
||||
/*
|
||||
* The set types are implemented in modules and registered set types
|
||||
|
@ -315,6 +326,60 @@ ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_ipaddr6);
|
||||
|
||||
typedef void (*destroyer)(void *);
|
||||
/* ipset data extension types, in size order */
|
||||
|
||||
const struct ip_set_ext_type ip_set_extensions[] = {
|
||||
[IPSET_EXT_ID_COUNTER] = {
|
||||
.type = IPSET_EXT_COUNTER,
|
||||
.flag = IPSET_FLAG_WITH_COUNTERS,
|
||||
.len = sizeof(struct ip_set_counter),
|
||||
.align = __alignof__(struct ip_set_counter),
|
||||
},
|
||||
[IPSET_EXT_ID_TIMEOUT] = {
|
||||
.type = IPSET_EXT_TIMEOUT,
|
||||
.len = sizeof(unsigned long),
|
||||
.align = __alignof__(unsigned long),
|
||||
},
|
||||
[IPSET_EXT_ID_COMMENT] = {
|
||||
.type = IPSET_EXT_COMMENT | IPSET_EXT_DESTROY,
|
||||
.flag = IPSET_FLAG_WITH_COMMENT,
|
||||
.len = sizeof(struct ip_set_comment),
|
||||
.align = __alignof__(struct ip_set_comment),
|
||||
.destroy = (destroyer) ip_set_comment_free,
|
||||
},
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ip_set_extensions);
|
||||
|
||||
static inline bool
|
||||
add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
|
||||
{
|
||||
return ip_set_extensions[id].flag ?
|
||||
(flags & ip_set_extensions[id].flag) :
|
||||
!!tb[IPSET_ATTR_TIMEOUT];
|
||||
}
|
||||
|
||||
size_t
|
||||
ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
|
||||
{
|
||||
enum ip_set_ext_id id;
|
||||
size_t offset = 0;
|
||||
u32 cadt_flags = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS])
|
||||
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
|
||||
if (!add_extension(id, cadt_flags, tb))
|
||||
continue;
|
||||
offset += ALIGN(len + offset, ip_set_extensions[id].align);
|
||||
set->offset[id] = offset;
|
||||
set->extensions |= ip_set_extensions[id].type;
|
||||
offset += ip_set_extensions[id].len;
|
||||
}
|
||||
return len + offset;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_elem_len);
|
||||
|
||||
int
|
||||
ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
|
||||
struct ip_set_ext *ext)
|
||||
|
@ -334,6 +399,12 @@ ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
|
|||
ext->packets = be64_to_cpu(nla_get_be64(
|
||||
tb[IPSET_ATTR_PACKETS]));
|
||||
}
|
||||
if (tb[IPSET_ATTR_COMMENT]) {
|
||||
if (!(set->extensions & IPSET_EXT_COMMENT))
|
||||
return -IPSET_ERR_COMMENT;
|
||||
ext->comment = ip_set_comment_uget(tb[IPSET_ATTR_COMMENT]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_extensions);
|
||||
|
@ -374,13 +445,14 @@ __ip_set_put(struct ip_set *set)
|
|||
*/
|
||||
|
||||
static inline struct ip_set *
|
||||
ip_set_rcu_get(ip_set_id_t index)
|
||||
ip_set_rcu_get(struct net *net, ip_set_id_t index)
|
||||
{
|
||||
struct ip_set *set;
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
rcu_read_lock();
|
||||
/* ip_set_list itself needs to be protected */
|
||||
set = rcu_dereference(ip_set_list)[index];
|
||||
set = rcu_dereference(inst->ip_set_list)[index];
|
||||
rcu_read_unlock();
|
||||
|
||||
return set;
|
||||
|
@ -390,7 +462,8 @@ int
|
|||
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_rcu_get(index);
|
||||
struct ip_set *set = ip_set_rcu_get(
|
||||
dev_net(par->in ? par->in : par->out), index);
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(set == NULL);
|
||||
|
@ -428,7 +501,8 @@ int
|
|||
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_rcu_get(index);
|
||||
struct ip_set *set = ip_set_rcu_get(
|
||||
dev_net(par->in ? par->in : par->out), index);
|
||||
int ret;
|
||||
|
||||
BUG_ON(set == NULL);
|
||||
|
@ -450,7 +524,8 @@ int
|
|||
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_rcu_get(index);
|
||||
struct ip_set *set = ip_set_rcu_get(
|
||||
dev_net(par->in ? par->in : par->out), index);
|
||||
int ret = 0;
|
||||
|
||||
BUG_ON(set == NULL);
|
||||
|
@ -474,14 +549,15 @@ EXPORT_SYMBOL_GPL(ip_set_del);
|
|||
*
|
||||
*/
|
||||
ip_set_id_t
|
||||
ip_set_get_byname(const char *name, struct ip_set **set)
|
||||
ip_set_get_byname(struct net *net, const char *name, struct ip_set **set)
|
||||
{
|
||||
ip_set_id_t i, index = IPSET_INVALID_ID;
|
||||
struct ip_set *s;
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
s = rcu_dereference(ip_set_list)[i];
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
s = rcu_dereference(inst->ip_set_list)[i];
|
||||
if (s != NULL && STREQ(s->name, name)) {
|
||||
__ip_set_get(s);
|
||||
index = i;
|
||||
|
@ -501,17 +577,26 @@ EXPORT_SYMBOL_GPL(ip_set_get_byname);
|
|||
* to be valid, after calling this function.
|
||||
*
|
||||
*/
|
||||
void
|
||||
ip_set_put_byindex(ip_set_id_t index)
|
||||
|
||||
static inline void
|
||||
__ip_set_put_byindex(struct ip_set_net *inst, ip_set_id_t index)
|
||||
{
|
||||
struct ip_set *set;
|
||||
|
||||
rcu_read_lock();
|
||||
set = rcu_dereference(ip_set_list)[index];
|
||||
set = rcu_dereference(inst->ip_set_list)[index];
|
||||
if (set != NULL)
|
||||
__ip_set_put(set);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void
|
||||
ip_set_put_byindex(struct net *net, ip_set_id_t index)
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
__ip_set_put_byindex(inst, index);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_put_byindex);
|
||||
|
||||
/*
|
||||
|
@ -522,9 +607,9 @@ EXPORT_SYMBOL_GPL(ip_set_put_byindex);
|
|||
*
|
||||
*/
|
||||
const char *
|
||||
ip_set_name_byindex(ip_set_id_t index)
|
||||
ip_set_name_byindex(struct net *net, ip_set_id_t index)
|
||||
{
|
||||
const struct ip_set *set = ip_set_rcu_get(index);
|
||||
const struct ip_set *set = ip_set_rcu_get(net, index);
|
||||
|
||||
BUG_ON(set == NULL);
|
||||
BUG_ON(set->ref == 0);
|
||||
|
@ -546,14 +631,15 @@ EXPORT_SYMBOL_GPL(ip_set_name_byindex);
|
|||
* The nfnl mutex is used in the function.
|
||||
*/
|
||||
ip_set_id_t
|
||||
ip_set_nfnl_get(const char *name)
|
||||
ip_set_nfnl_get(struct net *net, const char *name)
|
||||
{
|
||||
ip_set_id_t i, index = IPSET_INVALID_ID;
|
||||
struct ip_set *s;
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
s = nfnl_set(i);
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
s = nfnl_set(inst, i);
|
||||
if (s != NULL && STREQ(s->name, name)) {
|
||||
__ip_set_get(s);
|
||||
index = i;
|
||||
|
@ -573,15 +659,16 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get);
|
|||
* The nfnl mutex is used in the function.
|
||||
*/
|
||||
ip_set_id_t
|
||||
ip_set_nfnl_get_byindex(ip_set_id_t index)
|
||||
ip_set_nfnl_get_byindex(struct net *net, ip_set_id_t index)
|
||||
{
|
||||
struct ip_set *set;
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
if (index > ip_set_max)
|
||||
if (index > inst->ip_set_max)
|
||||
return IPSET_INVALID_ID;
|
||||
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
set = nfnl_set(index);
|
||||
set = nfnl_set(inst, index);
|
||||
if (set)
|
||||
__ip_set_get(set);
|
||||
else
|
||||
|
@ -600,13 +687,17 @@ EXPORT_SYMBOL_GPL(ip_set_nfnl_get_byindex);
|
|||
* The nfnl mutex is used in the function.
|
||||
*/
|
||||
void
|
||||
ip_set_nfnl_put(ip_set_id_t index)
|
||||
ip_set_nfnl_put(struct net *net, ip_set_id_t index)
|
||||
{
|
||||
struct ip_set *set;
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
set = nfnl_set(index);
|
||||
if (!inst->is_deleted) { /* already deleted from ip_set_net_exit() */
|
||||
set = nfnl_set(inst, index);
|
||||
if (set != NULL)
|
||||
__ip_set_put(set);
|
||||
}
|
||||
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_nfnl_put);
|
||||
|
@ -664,14 +755,14 @@ static const struct nla_policy ip_set_create_policy[IPSET_ATTR_CMD_MAX + 1] = {
|
|||
};
|
||||
|
||||
static struct ip_set *
|
||||
find_set_and_id(const char *name, ip_set_id_t *id)
|
||||
find_set_and_id(struct ip_set_net *inst, const char *name, ip_set_id_t *id)
|
||||
{
|
||||
struct ip_set *set = NULL;
|
||||
ip_set_id_t i;
|
||||
|
||||
*id = IPSET_INVALID_ID;
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
set = nfnl_set(i);
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
set = nfnl_set(inst, i);
|
||||
if (set != NULL && STREQ(set->name, name)) {
|
||||
*id = i;
|
||||
break;
|
||||
|
@ -681,22 +772,23 @@ find_set_and_id(const char *name, ip_set_id_t *id)
|
|||
}
|
||||
|
||||
static inline struct ip_set *
|
||||
find_set(const char *name)
|
||||
find_set(struct ip_set_net *inst, const char *name)
|
||||
{
|
||||
ip_set_id_t id;
|
||||
|
||||
return find_set_and_id(name, &id);
|
||||
return find_set_and_id(inst, name, &id);
|
||||
}
|
||||
|
||||
static int
|
||||
find_free_id(const char *name, ip_set_id_t *index, struct ip_set **set)
|
||||
find_free_id(struct ip_set_net *inst, const char *name, ip_set_id_t *index,
|
||||
struct ip_set **set)
|
||||
{
|
||||
struct ip_set *s;
|
||||
ip_set_id_t i;
|
||||
|
||||
*index = IPSET_INVALID_ID;
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
s = nfnl_set(i);
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
s = nfnl_set(inst, i);
|
||||
if (s == NULL) {
|
||||
if (*index == IPSET_INVALID_ID)
|
||||
*index = i;
|
||||
|
@ -725,6 +817,8 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct net *net = sock_net(ctnl);
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
struct ip_set *set, *clash = NULL;
|
||||
ip_set_id_t index = IPSET_INVALID_ID;
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
|
@ -783,7 +877,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
|||
goto put_out;
|
||||
}
|
||||
|
||||
ret = set->type->create(set, tb, flags);
|
||||
ret = set->type->create(net, set, tb, flags);
|
||||
if (ret != 0)
|
||||
goto put_out;
|
||||
|
||||
|
@ -794,7 +888,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
|||
* by the nfnl mutex. Find the first free index in ip_set_list
|
||||
* and check clashing.
|
||||
*/
|
||||
ret = find_free_id(set->name, &index, &clash);
|
||||
ret = find_free_id(inst, set->name, &index, &clash);
|
||||
if (ret == -EEXIST) {
|
||||
/* If this is the same set and requested, ignore error */
|
||||
if ((flags & IPSET_FLAG_EXIST) &&
|
||||
|
@ -807,9 +901,9 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
|||
goto cleanup;
|
||||
} else if (ret == -IPSET_ERR_MAX_SETS) {
|
||||
struct ip_set **list, **tmp;
|
||||
ip_set_id_t i = ip_set_max + IP_SET_INC;
|
||||
ip_set_id_t i = inst->ip_set_max + IP_SET_INC;
|
||||
|
||||
if (i < ip_set_max || i == IPSET_INVALID_ID)
|
||||
if (i < inst->ip_set_max || i == IPSET_INVALID_ID)
|
||||
/* Wraparound */
|
||||
goto cleanup;
|
||||
|
||||
|
@ -817,14 +911,14 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
|||
if (!list)
|
||||
goto cleanup;
|
||||
/* nfnl mutex is held, both lists are valid */
|
||||
tmp = nfnl_dereference(ip_set_list);
|
||||
memcpy(list, tmp, sizeof(struct ip_set *) * ip_set_max);
|
||||
rcu_assign_pointer(ip_set_list, list);
|
||||
tmp = nfnl_dereference(inst->ip_set_list);
|
||||
memcpy(list, tmp, sizeof(struct ip_set *) * inst->ip_set_max);
|
||||
rcu_assign_pointer(inst->ip_set_list, list);
|
||||
/* Make sure all current packets have passed through */
|
||||
synchronize_net();
|
||||
/* Use new list */
|
||||
index = ip_set_max;
|
||||
ip_set_max = i;
|
||||
index = inst->ip_set_max;
|
||||
inst->ip_set_max = i;
|
||||
kfree(tmp);
|
||||
ret = 0;
|
||||
} else if (ret)
|
||||
|
@ -834,7 +928,7 @@ ip_set_create(struct sock *ctnl, struct sk_buff *skb,
|
|||
* Finally! Add our shiny new set to the list, and be done.
|
||||
*/
|
||||
pr_debug("create: '%s' created with index %u!\n", set->name, index);
|
||||
nfnl_set(index) = set;
|
||||
nfnl_set(inst, index) = set;
|
||||
|
||||
return ret;
|
||||
|
||||
|
@ -857,12 +951,12 @@ ip_set_setname_policy[IPSET_ATTR_CMD_MAX + 1] = {
|
|||
};
|
||||
|
||||
static void
|
||||
ip_set_destroy_set(ip_set_id_t index)
|
||||
ip_set_destroy_set(struct ip_set_net *inst, ip_set_id_t index)
|
||||
{
|
||||
struct ip_set *set = nfnl_set(index);
|
||||
struct ip_set *set = nfnl_set(inst, index);
|
||||
|
||||
pr_debug("set: %s\n", set->name);
|
||||
nfnl_set(index) = NULL;
|
||||
nfnl_set(inst, index) = NULL;
|
||||
|
||||
/* Must call it without holding any lock */
|
||||
set->variant->destroy(set);
|
||||
|
@ -875,6 +969,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
struct ip_set *s;
|
||||
ip_set_id_t i;
|
||||
int ret = 0;
|
||||
|
@ -894,21 +989,22 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
|
|||
*/
|
||||
read_lock_bh(&ip_set_ref_lock);
|
||||
if (!attr[IPSET_ATTR_SETNAME]) {
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
s = nfnl_set(i);
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
s = nfnl_set(inst, i);
|
||||
if (s != NULL && s->ref) {
|
||||
ret = -IPSET_ERR_BUSY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
read_unlock_bh(&ip_set_ref_lock);
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
s = nfnl_set(i);
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
s = nfnl_set(inst, i);
|
||||
if (s != NULL)
|
||||
ip_set_destroy_set(i);
|
||||
ip_set_destroy_set(inst, i);
|
||||
}
|
||||
} else {
|
||||
s = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &i);
|
||||
s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
|
||||
&i);
|
||||
if (s == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
|
@ -918,7 +1014,7 @@ ip_set_destroy(struct sock *ctnl, struct sk_buff *skb,
|
|||
}
|
||||
read_unlock_bh(&ip_set_ref_lock);
|
||||
|
||||
ip_set_destroy_set(i);
|
||||
ip_set_destroy_set(inst, i);
|
||||
}
|
||||
return 0;
|
||||
out:
|
||||
|
@ -943,6 +1039,7 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
struct ip_set *s;
|
||||
ip_set_id_t i;
|
||||
|
||||
|
@ -950,13 +1047,13 @@ ip_set_flush(struct sock *ctnl, struct sk_buff *skb,
|
|||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (!attr[IPSET_ATTR_SETNAME]) {
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
s = nfnl_set(i);
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
s = nfnl_set(inst, i);
|
||||
if (s != NULL)
|
||||
ip_set_flush_set(s);
|
||||
}
|
||||
} else {
|
||||
s = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
s = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (s == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -982,6 +1079,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
struct ip_set *set, *s;
|
||||
const char *name2;
|
||||
ip_set_id_t i;
|
||||
|
@ -992,7 +1090,7 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
|
|||
attr[IPSET_ATTR_SETNAME2] == NULL))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (set == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -1003,8 +1101,8 @@ ip_set_rename(struct sock *ctnl, struct sk_buff *skb,
|
|||
}
|
||||
|
||||
name2 = nla_data(attr[IPSET_ATTR_SETNAME2]);
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
s = nfnl_set(i);
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
s = nfnl_set(inst, i);
|
||||
if (s != NULL && STREQ(s->name, name2)) {
|
||||
ret = -IPSET_ERR_EXIST_SETNAME2;
|
||||
goto out;
|
||||
|
@ -1031,6 +1129,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
struct ip_set *from, *to;
|
||||
ip_set_id_t from_id, to_id;
|
||||
char from_name[IPSET_MAXNAMELEN];
|
||||
|
@ -1040,11 +1139,13 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
|
|||
attr[IPSET_ATTR_SETNAME2] == NULL))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
from = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME]), &from_id);
|
||||
from = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
|
||||
&from_id);
|
||||
if (from == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
to = find_set_and_id(nla_data(attr[IPSET_ATTR_SETNAME2]), &to_id);
|
||||
to = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME2]),
|
||||
&to_id);
|
||||
if (to == NULL)
|
||||
return -IPSET_ERR_EXIST_SETNAME2;
|
||||
|
||||
|
@ -1061,8 +1162,8 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
|
|||
|
||||
write_lock_bh(&ip_set_ref_lock);
|
||||
swap(from->ref, to->ref);
|
||||
nfnl_set(from_id) = to;
|
||||
nfnl_set(to_id) = from;
|
||||
nfnl_set(inst, from_id) = to;
|
||||
nfnl_set(inst, to_id) = from;
|
||||
write_unlock_bh(&ip_set_ref_lock);
|
||||
|
||||
return 0;
|
||||
|
@ -1081,9 +1182,10 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
|
|||
static int
|
||||
ip_set_dump_done(struct netlink_callback *cb)
|
||||
{
|
||||
struct ip_set_net *inst = (struct ip_set_net *)cb->data;
|
||||
if (cb->args[2]) {
|
||||
pr_debug("release set %s\n", nfnl_set(cb->args[1])->name);
|
||||
ip_set_put_byindex((ip_set_id_t) cb->args[1]);
|
||||
pr_debug("release set %s\n", nfnl_set(inst, cb->args[1])->name);
|
||||
__ip_set_put_byindex(inst, (ip_set_id_t) cb->args[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1109,6 +1211,7 @@ dump_init(struct netlink_callback *cb)
|
|||
struct nlattr *attr = (void *)nlh + min_len;
|
||||
u32 dump_type;
|
||||
ip_set_id_t index;
|
||||
struct ip_set_net *inst = (struct ip_set_net *)cb->data;
|
||||
|
||||
/* Second pass, so parser can't fail */
|
||||
nla_parse(cda, IPSET_ATTR_CMD_MAX,
|
||||
|
@ -1122,7 +1225,7 @@ dump_init(struct netlink_callback *cb)
|
|||
if (cda[IPSET_ATTR_SETNAME]) {
|
||||
struct ip_set *set;
|
||||
|
||||
set = find_set_and_id(nla_data(cda[IPSET_ATTR_SETNAME]),
|
||||
set = find_set_and_id(inst, nla_data(cda[IPSET_ATTR_SETNAME]),
|
||||
&index);
|
||||
if (set == NULL)
|
||||
return -ENOENT;
|
||||
|
@ -1150,6 +1253,7 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
unsigned int flags = NETLINK_CB(cb->skb).portid ? NLM_F_MULTI : 0;
|
||||
u32 dump_type, dump_flags;
|
||||
int ret = 0;
|
||||
struct ip_set_net *inst = (struct ip_set_net *)cb->data;
|
||||
|
||||
if (!cb->args[0]) {
|
||||
ret = dump_init(cb);
|
||||
|
@ -1163,18 +1267,18 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
}
|
||||
}
|
||||
|
||||
if (cb->args[1] >= ip_set_max)
|
||||
if (cb->args[1] >= inst->ip_set_max)
|
||||
goto out;
|
||||
|
||||
dump_type = DUMP_TYPE(cb->args[0]);
|
||||
dump_flags = DUMP_FLAGS(cb->args[0]);
|
||||
max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
|
||||
max = dump_type == DUMP_ONE ? cb->args[1] + 1 : inst->ip_set_max;
|
||||
dump_last:
|
||||
pr_debug("args[0]: %u %u args[1]: %ld\n",
|
||||
dump_type, dump_flags, cb->args[1]);
|
||||
for (; cb->args[1] < max; cb->args[1]++) {
|
||||
index = (ip_set_id_t) cb->args[1];
|
||||
set = nfnl_set(index);
|
||||
set = nfnl_set(inst, index);
|
||||
if (set == NULL) {
|
||||
if (dump_type == DUMP_ONE) {
|
||||
ret = -ENOENT;
|
||||
|
@ -1252,8 +1356,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
release_refcount:
|
||||
/* If there was an error or set is done, release set */
|
||||
if (ret || !cb->args[2]) {
|
||||
pr_debug("release set %s\n", nfnl_set(index)->name);
|
||||
ip_set_put_byindex(index);
|
||||
pr_debug("release set %s\n", nfnl_set(inst, index)->name);
|
||||
__ip_set_put_byindex(inst, index);
|
||||
cb->args[2] = 0;
|
||||
}
|
||||
out:
|
||||
|
@ -1271,6 +1375,8 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
|
||||
if (unlikely(protocol_failed(attr)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
|
@ -1278,6 +1384,7 @@ ip_set_dump(struct sock *ctnl, struct sk_buff *skb,
|
|||
struct netlink_dump_control c = {
|
||||
.dump = ip_set_dump_start,
|
||||
.done = ip_set_dump_done,
|
||||
.data = (void *)inst
|
||||
};
|
||||
return netlink_dump_start(ctnl, skb, nlh, &c);
|
||||
}
|
||||
|
@ -1356,6 +1463,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
struct ip_set *set;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
|
||||
const struct nlattr *nla;
|
||||
|
@ -1374,7 +1482,7 @@ ip_set_uadd(struct sock *ctnl, struct sk_buff *skb,
|
|||
attr[IPSET_ATTR_LINENO] == NULL))))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (set == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -1410,6 +1518,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
struct ip_set *set;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
|
||||
const struct nlattr *nla;
|
||||
|
@ -1428,7 +1537,7 @@ ip_set_udel(struct sock *ctnl, struct sk_buff *skb,
|
|||
attr[IPSET_ATTR_LINENO] == NULL))))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (set == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -1464,6 +1573,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
struct ip_set *set;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1] = {};
|
||||
int ret = 0;
|
||||
|
@ -1474,7 +1584,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
|
|||
!flag_nested(attr[IPSET_ATTR_DATA])))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (set == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -1499,6 +1609,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
|
|||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const attr[])
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(sock_net(ctnl));
|
||||
const struct ip_set *set;
|
||||
struct sk_buff *skb2;
|
||||
struct nlmsghdr *nlh2;
|
||||
|
@ -1508,7 +1619,7 @@ ip_set_header(struct sock *ctnl, struct sk_buff *skb,
|
|||
attr[IPSET_ATTR_SETNAME] == NULL))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
set = find_set(nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
set = find_set(inst, nla_data(attr[IPSET_ATTR_SETNAME]));
|
||||
if (set == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -1733,8 +1844,10 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
|
|||
unsigned int *op;
|
||||
void *data;
|
||||
int copylen = *len, ret = 0;
|
||||
struct net *net = sock_net(sk);
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
|
||||
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
if (optval != SO_IP_SET)
|
||||
return -EBADF;
|
||||
|
@ -1783,22 +1896,39 @@ ip_set_sockfn_get(struct sock *sk, int optval, void __user *user, int *len)
|
|||
}
|
||||
req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
find_set_and_id(req_get->set.name, &id);
|
||||
find_set_and_id(inst, req_get->set.name, &id);
|
||||
req_get->set.index = id;
|
||||
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||
goto copy;
|
||||
}
|
||||
case IP_SET_OP_GET_FNAME: {
|
||||
struct ip_set_req_get_set_family *req_get = data;
|
||||
ip_set_id_t id;
|
||||
|
||||
if (*len != sizeof(struct ip_set_req_get_set_family)) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
req_get->set.name[IPSET_MAXNAMELEN - 1] = '\0';
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
find_set_and_id(inst, req_get->set.name, &id);
|
||||
req_get->set.index = id;
|
||||
if (id != IPSET_INVALID_ID)
|
||||
req_get->family = nfnl_set(inst, id)->family;
|
||||
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||
goto copy;
|
||||
}
|
||||
case IP_SET_OP_GET_BYINDEX: {
|
||||
struct ip_set_req_get_set *req_get = data;
|
||||
struct ip_set *set;
|
||||
|
||||
if (*len != sizeof(struct ip_set_req_get_set) ||
|
||||
req_get->set.index >= ip_set_max) {
|
||||
req_get->set.index >= inst->ip_set_max) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
nfnl_lock(NFNL_SUBSYS_IPSET);
|
||||
set = nfnl_set(req_get->set.index);
|
||||
set = nfnl_set(inst, req_get->set.index);
|
||||
strncpy(req_get->set.name, set ? set->name : "",
|
||||
IPSET_MAXNAMELEN);
|
||||
nfnl_unlock(NFNL_SUBSYS_IPSET);
|
||||
|
@ -1827,49 +1957,82 @@ static struct nf_sockopt_ops so_set __read_mostly = {
|
|||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __net_init
|
||||
ip_set_net_init(struct net *net)
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
struct ip_set **list;
|
||||
|
||||
inst->ip_set_max = max_sets ? max_sets : CONFIG_IP_SET_MAX;
|
||||
if (inst->ip_set_max >= IPSET_INVALID_ID)
|
||||
inst->ip_set_max = IPSET_INVALID_ID - 1;
|
||||
|
||||
list = kzalloc(sizeof(struct ip_set *) * inst->ip_set_max, GFP_KERNEL);
|
||||
if (!list)
|
||||
return -ENOMEM;
|
||||
inst->is_deleted = 0;
|
||||
rcu_assign_pointer(inst->ip_set_list, list);
|
||||
pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __net_exit
|
||||
ip_set_net_exit(struct net *net)
|
||||
{
|
||||
struct ip_set_net *inst = ip_set_pernet(net);
|
||||
|
||||
struct ip_set *set = NULL;
|
||||
ip_set_id_t i;
|
||||
|
||||
inst->is_deleted = 1; /* flag for ip_set_nfnl_put */
|
||||
|
||||
for (i = 0; i < inst->ip_set_max; i++) {
|
||||
set = nfnl_set(inst, i);
|
||||
if (set != NULL)
|
||||
ip_set_destroy_set(inst, i);
|
||||
}
|
||||
kfree(rcu_dereference_protected(inst->ip_set_list, 1));
|
||||
}
|
||||
|
||||
static struct pernet_operations ip_set_net_ops = {
|
||||
.init = ip_set_net_init,
|
||||
.exit = ip_set_net_exit,
|
||||
.id = &ip_set_net_id,
|
||||
.size = sizeof(struct ip_set_net)
|
||||
};
|
||||
|
||||
|
||||
static int __init
|
||||
ip_set_init(void)
|
||||
{
|
||||
struct ip_set **list;
|
||||
int ret;
|
||||
|
||||
if (max_sets)
|
||||
ip_set_max = max_sets;
|
||||
if (ip_set_max >= IPSET_INVALID_ID)
|
||||
ip_set_max = IPSET_INVALID_ID - 1;
|
||||
|
||||
list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL);
|
||||
if (!list)
|
||||
return -ENOMEM;
|
||||
|
||||
rcu_assign_pointer(ip_set_list, list);
|
||||
ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);
|
||||
int ret = nfnetlink_subsys_register(&ip_set_netlink_subsys);
|
||||
if (ret != 0) {
|
||||
pr_err("ip_set: cannot register with nfnetlink.\n");
|
||||
kfree(list);
|
||||
return ret;
|
||||
}
|
||||
ret = nf_register_sockopt(&so_set);
|
||||
if (ret != 0) {
|
||||
pr_err("SO_SET registry failed: %d\n", ret);
|
||||
nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
|
||||
kfree(list);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_notice("ip_set: protocol %u\n", IPSET_PROTOCOL);
|
||||
ret = register_pernet_subsys(&ip_set_net_ops);
|
||||
if (ret) {
|
||||
pr_err("ip_set: cannot register pernet_subsys.\n");
|
||||
nf_unregister_sockopt(&so_set);
|
||||
nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit
|
||||
ip_set_fini(void)
|
||||
{
|
||||
struct ip_set **list = rcu_dereference_protected(ip_set_list, 1);
|
||||
|
||||
/* There can't be any existing set */
|
||||
unregister_pernet_subsys(&ip_set_net_ops);
|
||||
nf_unregister_sockopt(&so_set);
|
||||
nfnetlink_subsys_unregister(&ip_set_netlink_subsys);
|
||||
kfree(list);
|
||||
pr_debug("these are the famous last words\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -102,9 +102,25 @@ ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
|
|||
int protocol = iph->protocol;
|
||||
|
||||
/* See comments at tcp_match in ip_tables.c */
|
||||
if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET))
|
||||
if (protocol <= 0)
|
||||
return false;
|
||||
|
||||
if (ntohs(iph->frag_off) & IP_OFFSET)
|
||||
switch (protocol) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_SCTP:
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
case IPPROTO_ICMP:
|
||||
/* Port info not available for fragment offset > 0 */
|
||||
return false;
|
||||
default:
|
||||
/* Other protocols doesn't have ports,
|
||||
so we can match fragments */
|
||||
*proto = protocol;
|
||||
return true;
|
||||
}
|
||||
|
||||
return get_port(skb, protocol, protooff, src, port, proto);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_ip4_port);
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
#define rcu_dereference_bh(p) rcu_dereference(p)
|
||||
#endif
|
||||
|
||||
#define CONCAT(a, b) a##b
|
||||
#define TOKEN(a, b) CONCAT(a, b)
|
||||
#define rcu_dereference_bh_nfnl(p) rcu_dereference_bh_check(p, 1)
|
||||
|
||||
/* Hashing which uses arrays to resolve clashing. The hash table is resized
|
||||
* (doubled) when searching becomes too long.
|
||||
|
@ -78,10 +77,14 @@ struct htable {
|
|||
|
||||
#define hbucket(h, i) (&((h)->bucket[i]))
|
||||
|
||||
#ifndef IPSET_NET_COUNT
|
||||
#define IPSET_NET_COUNT 1
|
||||
#endif
|
||||
|
||||
/* Book-keeping of the prefixes added to the set */
|
||||
struct net_prefixes {
|
||||
u8 cidr; /* the different cidr values in the set */
|
||||
u32 nets; /* number of elements per cidr */
|
||||
u32 nets[IPSET_NET_COUNT]; /* number of elements per cidr */
|
||||
u8 cidr[IPSET_NET_COUNT]; /* the different cidr values in the set */
|
||||
};
|
||||
|
||||
/* Compute the hash table size */
|
||||
|
@ -114,23 +117,6 @@ htable_bits(u32 hashsize)
|
|||
return bits;
|
||||
}
|
||||
|
||||
/* Destroy the hashtable part of the set */
|
||||
static void
|
||||
ahash_destroy(struct htable *t)
|
||||
{
|
||||
struct hbucket *n;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < jhash_size(t->htable_bits); i++) {
|
||||
n = hbucket(t, i);
|
||||
if (n->size)
|
||||
/* FIXME: use slab cache */
|
||||
kfree(n->value);
|
||||
}
|
||||
|
||||
ip_set_free(t);
|
||||
}
|
||||
|
||||
static int
|
||||
hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
|
||||
{
|
||||
|
@ -156,30 +142,30 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
|
|||
}
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
#if IPSET_NET_COUNT > 1
|
||||
#define __CIDR(cidr, i) (cidr[i])
|
||||
#else
|
||||
#define __CIDR(cidr, i) (cidr)
|
||||
#endif
|
||||
#ifdef IP_SET_HASH_WITH_NETS_PACKED
|
||||
/* When cidr is packed with nomatch, cidr - 1 is stored in the entry */
|
||||
#define CIDR(cidr) (cidr + 1)
|
||||
#define CIDR(cidr, i) (__CIDR(cidr, i) + 1)
|
||||
#else
|
||||
#define CIDR(cidr) (cidr)
|
||||
#define CIDR(cidr, i) (__CIDR(cidr, i))
|
||||
#endif
|
||||
|
||||
#define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128)
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_MULTI
|
||||
#define NETS_LENGTH(family) (SET_HOST_MASK(family) + 1)
|
||||
#define NLEN(family) (SET_HOST_MASK(family) + 1)
|
||||
#else
|
||||
#define NETS_LENGTH(family) SET_HOST_MASK(family)
|
||||
#define NLEN(family) SET_HOST_MASK(family)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define NETS_LENGTH(family) 0
|
||||
#define NLEN(family) 0
|
||||
#endif /* IP_SET_HASH_WITH_NETS */
|
||||
|
||||
#define ext_timeout(e, h) \
|
||||
(unsigned long *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_TIMEOUT])
|
||||
#define ext_counter(e, h) \
|
||||
(struct ip_set_counter *)(((void *)(e)) + (h)->offset[IPSET_OFFSET_COUNTER])
|
||||
|
||||
#endif /* _IP_SET_HASH_GEN_H */
|
||||
|
||||
/* Family dependent templates */
|
||||
|
@ -194,6 +180,8 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
|
|||
#undef mtype_data_next
|
||||
#undef mtype_elem
|
||||
|
||||
#undef mtype_ahash_destroy
|
||||
#undef mtype_ext_cleanup
|
||||
#undef mtype_add_cidr
|
||||
#undef mtype_del_cidr
|
||||
#undef mtype_ahash_memsize
|
||||
|
@ -220,41 +208,44 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
|
|||
|
||||
#undef HKEY
|
||||
|
||||
#define mtype_data_equal TOKEN(MTYPE, _data_equal)
|
||||
#define mtype_data_equal IPSET_TOKEN(MTYPE, _data_equal)
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
#define mtype_do_data_match TOKEN(MTYPE, _do_data_match)
|
||||
#define mtype_do_data_match IPSET_TOKEN(MTYPE, _do_data_match)
|
||||
#else
|
||||
#define mtype_do_data_match(d) 1
|
||||
#endif
|
||||
#define mtype_data_set_flags TOKEN(MTYPE, _data_set_flags)
|
||||
#define mtype_data_reset_flags TOKEN(MTYPE, _data_reset_flags)
|
||||
#define mtype_data_netmask TOKEN(MTYPE, _data_netmask)
|
||||
#define mtype_data_list TOKEN(MTYPE, _data_list)
|
||||
#define mtype_data_next TOKEN(MTYPE, _data_next)
|
||||
#define mtype_elem TOKEN(MTYPE, _elem)
|
||||
#define mtype_add_cidr TOKEN(MTYPE, _add_cidr)
|
||||
#define mtype_del_cidr TOKEN(MTYPE, _del_cidr)
|
||||
#define mtype_ahash_memsize TOKEN(MTYPE, _ahash_memsize)
|
||||
#define mtype_flush TOKEN(MTYPE, _flush)
|
||||
#define mtype_destroy TOKEN(MTYPE, _destroy)
|
||||
#define mtype_gc_init TOKEN(MTYPE, _gc_init)
|
||||
#define mtype_same_set TOKEN(MTYPE, _same_set)
|
||||
#define mtype_kadt TOKEN(MTYPE, _kadt)
|
||||
#define mtype_uadt TOKEN(MTYPE, _uadt)
|
||||
#define mtype_data_set_flags IPSET_TOKEN(MTYPE, _data_set_flags)
|
||||
#define mtype_data_reset_elem IPSET_TOKEN(MTYPE, _data_reset_elem)
|
||||
#define mtype_data_reset_flags IPSET_TOKEN(MTYPE, _data_reset_flags)
|
||||
#define mtype_data_netmask IPSET_TOKEN(MTYPE, _data_netmask)
|
||||
#define mtype_data_list IPSET_TOKEN(MTYPE, _data_list)
|
||||
#define mtype_data_next IPSET_TOKEN(MTYPE, _data_next)
|
||||
#define mtype_elem IPSET_TOKEN(MTYPE, _elem)
|
||||
#define mtype_ahash_destroy IPSET_TOKEN(MTYPE, _ahash_destroy)
|
||||
#define mtype_ext_cleanup IPSET_TOKEN(MTYPE, _ext_cleanup)
|
||||
#define mtype_add_cidr IPSET_TOKEN(MTYPE, _add_cidr)
|
||||
#define mtype_del_cidr IPSET_TOKEN(MTYPE, _del_cidr)
|
||||
#define mtype_ahash_memsize IPSET_TOKEN(MTYPE, _ahash_memsize)
|
||||
#define mtype_flush IPSET_TOKEN(MTYPE, _flush)
|
||||
#define mtype_destroy IPSET_TOKEN(MTYPE, _destroy)
|
||||
#define mtype_gc_init IPSET_TOKEN(MTYPE, _gc_init)
|
||||
#define mtype_same_set IPSET_TOKEN(MTYPE, _same_set)
|
||||
#define mtype_kadt IPSET_TOKEN(MTYPE, _kadt)
|
||||
#define mtype_uadt IPSET_TOKEN(MTYPE, _uadt)
|
||||
#define mtype MTYPE
|
||||
|
||||
#define mtype_elem TOKEN(MTYPE, _elem)
|
||||
#define mtype_add TOKEN(MTYPE, _add)
|
||||
#define mtype_del TOKEN(MTYPE, _del)
|
||||
#define mtype_test_cidrs TOKEN(MTYPE, _test_cidrs)
|
||||
#define mtype_test TOKEN(MTYPE, _test)
|
||||
#define mtype_expire TOKEN(MTYPE, _expire)
|
||||
#define mtype_resize TOKEN(MTYPE, _resize)
|
||||
#define mtype_head TOKEN(MTYPE, _head)
|
||||
#define mtype_list TOKEN(MTYPE, _list)
|
||||
#define mtype_gc TOKEN(MTYPE, _gc)
|
||||
#define mtype_variant TOKEN(MTYPE, _variant)
|
||||
#define mtype_data_match TOKEN(MTYPE, _data_match)
|
||||
#define mtype_elem IPSET_TOKEN(MTYPE, _elem)
|
||||
#define mtype_add IPSET_TOKEN(MTYPE, _add)
|
||||
#define mtype_del IPSET_TOKEN(MTYPE, _del)
|
||||
#define mtype_test_cidrs IPSET_TOKEN(MTYPE, _test_cidrs)
|
||||
#define mtype_test IPSET_TOKEN(MTYPE, _test)
|
||||
#define mtype_expire IPSET_TOKEN(MTYPE, _expire)
|
||||
#define mtype_resize IPSET_TOKEN(MTYPE, _resize)
|
||||
#define mtype_head IPSET_TOKEN(MTYPE, _head)
|
||||
#define mtype_list IPSET_TOKEN(MTYPE, _list)
|
||||
#define mtype_gc IPSET_TOKEN(MTYPE, _gc)
|
||||
#define mtype_variant IPSET_TOKEN(MTYPE, _variant)
|
||||
#define mtype_data_match IPSET_TOKEN(MTYPE, _data_match)
|
||||
|
||||
#ifndef HKEY_DATALEN
|
||||
#define HKEY_DATALEN sizeof(struct mtype_elem)
|
||||
|
@ -269,13 +260,10 @@ hbucket_elem_add(struct hbucket *n, u8 ahash_max, size_t dsize)
|
|||
|
||||
/* The generic hash structure */
|
||||
struct htype {
|
||||
struct htable *table; /* the hash table */
|
||||
struct htable __rcu *table; /* the hash table */
|
||||
u32 maxelem; /* max elements in the hash */
|
||||
u32 elements; /* current element (vs timeout) */
|
||||
u32 initval; /* random jhash init value */
|
||||
u32 timeout; /* timeout value, if enabled */
|
||||
size_t dsize; /* data struct size */
|
||||
size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
|
||||
struct timer_list gc; /* garbage collection when timeout enabled */
|
||||
struct mtype_elem next; /* temporary storage for uadd */
|
||||
#ifdef IP_SET_HASH_WITH_MULTI
|
||||
|
@ -297,49 +285,49 @@ struct htype {
|
|||
/* Network cidr size book keeping when the hash stores different
|
||||
* sized networks */
|
||||
static void
|
||||
mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
|
||||
mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
/* Add in increasing prefix order, so larger cidr first */
|
||||
for (i = 0, j = -1; i < nets_length && h->nets[i].nets; i++) {
|
||||
for (i = 0, j = -1; i < nets_length && h->nets[i].nets[n]; i++) {
|
||||
if (j != -1)
|
||||
continue;
|
||||
else if (h->nets[i].cidr < cidr)
|
||||
else if (h->nets[i].cidr[n] < cidr)
|
||||
j = i;
|
||||
else if (h->nets[i].cidr == cidr) {
|
||||
h->nets[i].nets++;
|
||||
else if (h->nets[i].cidr[n] == cidr) {
|
||||
h->nets[i].nets[n]++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (j != -1) {
|
||||
for (; i > j; i--) {
|
||||
h->nets[i].cidr = h->nets[i - 1].cidr;
|
||||
h->nets[i].nets = h->nets[i - 1].nets;
|
||||
h->nets[i].cidr[n] = h->nets[i - 1].cidr[n];
|
||||
h->nets[i].nets[n] = h->nets[i - 1].nets[n];
|
||||
}
|
||||
}
|
||||
h->nets[i].cidr = cidr;
|
||||
h->nets[i].nets = 1;
|
||||
h->nets[i].cidr[n] = cidr;
|
||||
h->nets[i].nets[n] = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
|
||||
mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n)
|
||||
{
|
||||
u8 i, j, net_end = nets_length - 1;
|
||||
|
||||
for (i = 0; i < nets_length; i++) {
|
||||
if (h->nets[i].cidr != cidr)
|
||||
if (h->nets[i].cidr[n] != cidr)
|
||||
continue;
|
||||
if (h->nets[i].nets > 1 || i == net_end ||
|
||||
h->nets[i + 1].nets == 0) {
|
||||
h->nets[i].nets--;
|
||||
if (h->nets[i].nets[n] > 1 || i == net_end ||
|
||||
h->nets[i + 1].nets[n] == 0) {
|
||||
h->nets[i].nets[n]--;
|
||||
return;
|
||||
}
|
||||
for (j = i; j < net_end && h->nets[j].nets; j++) {
|
||||
h->nets[j].cidr = h->nets[j + 1].cidr;
|
||||
h->nets[j].nets = h->nets[j + 1].nets;
|
||||
for (j = i; j < net_end && h->nets[j].nets[n]; j++) {
|
||||
h->nets[j].cidr[n] = h->nets[j + 1].cidr[n];
|
||||
h->nets[j].nets[n] = h->nets[j + 1].nets[n];
|
||||
}
|
||||
h->nets[j].nets = 0;
|
||||
h->nets[j].nets[n] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -347,10 +335,10 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
|
|||
|
||||
/* Calculate the actual memory size of the set data */
|
||||
static size_t
|
||||
mtype_ahash_memsize(const struct htype *h, u8 nets_length)
|
||||
mtype_ahash_memsize(const struct htype *h, const struct htable *t,
|
||||
u8 nets_length, size_t dsize)
|
||||
{
|
||||
u32 i;
|
||||
struct htable *t = h->table;
|
||||
size_t memsize = sizeof(*h)
|
||||
+ sizeof(*t)
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
|
@ -359,35 +347,70 @@ mtype_ahash_memsize(const struct htype *h, u8 nets_length)
|
|||
+ jhash_size(t->htable_bits) * sizeof(struct hbucket);
|
||||
|
||||
for (i = 0; i < jhash_size(t->htable_bits); i++)
|
||||
memsize += t->bucket[i].size * h->dsize;
|
||||
memsize += t->bucket[i].size * dsize;
|
||||
|
||||
return memsize;
|
||||
}
|
||||
|
||||
/* Get the ith element from the array block n */
|
||||
#define ahash_data(n, i, dsize) \
|
||||
((struct mtype_elem *)((n)->value + ((i) * (dsize))))
|
||||
|
||||
static void
|
||||
mtype_ext_cleanup(struct ip_set *set, struct hbucket *n)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n->pos; i++)
|
||||
ip_set_ext_destroy(set, ahash_data(n, i, set->dsize));
|
||||
}
|
||||
|
||||
/* Flush a hash type of set: destroy all elements */
|
||||
static void
|
||||
mtype_flush(struct ip_set *set)
|
||||
{
|
||||
struct htype *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
struct htable *t;
|
||||
struct hbucket *n;
|
||||
u32 i;
|
||||
|
||||
t = rcu_dereference_bh_nfnl(h->table);
|
||||
for (i = 0; i < jhash_size(t->htable_bits); i++) {
|
||||
n = hbucket(t, i);
|
||||
if (n->size) {
|
||||
if (set->extensions & IPSET_EXT_DESTROY)
|
||||
mtype_ext_cleanup(set, n);
|
||||
n->size = n->pos = 0;
|
||||
/* FIXME: use slab cache */
|
||||
kfree(n->value);
|
||||
}
|
||||
}
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
memset(h->nets, 0, sizeof(struct net_prefixes)
|
||||
* NETS_LENGTH(set->family));
|
||||
memset(h->nets, 0, sizeof(struct net_prefixes) * NLEN(set->family));
|
||||
#endif
|
||||
h->elements = 0;
|
||||
}
|
||||
|
||||
/* Destroy the hashtable part of the set */
|
||||
static void
|
||||
mtype_ahash_destroy(struct ip_set *set, struct htable *t, bool ext_destroy)
|
||||
{
|
||||
struct hbucket *n;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < jhash_size(t->htable_bits); i++) {
|
||||
n = hbucket(t, i);
|
||||
if (n->size) {
|
||||
if (set->extensions & IPSET_EXT_DESTROY && ext_destroy)
|
||||
mtype_ext_cleanup(set, n);
|
||||
/* FIXME: use slab cache */
|
||||
kfree(n->value);
|
||||
}
|
||||
}
|
||||
|
||||
ip_set_free(t);
|
||||
}
|
||||
|
||||
/* Destroy a hash type of set */
|
||||
static void
|
||||
mtype_destroy(struct ip_set *set)
|
||||
|
@ -397,7 +420,7 @@ mtype_destroy(struct ip_set *set)
|
|||
if (set->extensions & IPSET_EXT_TIMEOUT)
|
||||
del_timer_sync(&h->gc);
|
||||
|
||||
ahash_destroy(h->table);
|
||||
mtype_ahash_destroy(set, rcu_dereference_bh_nfnl(h->table), true);
|
||||
#ifdef IP_SET_HASH_WITH_RBTREE
|
||||
rbtree_destroy(&h->rbtree);
|
||||
#endif
|
||||
|
@ -414,10 +437,10 @@ mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
|
|||
init_timer(&h->gc);
|
||||
h->gc.data = (unsigned long) set;
|
||||
h->gc.function = gc;
|
||||
h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
|
||||
h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
|
||||
add_timer(&h->gc);
|
||||
pr_debug("gc initialized, run in every %u\n",
|
||||
IPSET_GC_PERIOD(h->timeout));
|
||||
IPSET_GC_PERIOD(set->timeout));
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -428,37 +451,40 @@ 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 &&
|
||||
x->timeout == y->timeout &&
|
||||
a->timeout == b->timeout &&
|
||||
#ifdef IP_SET_HASH_WITH_NETMASK
|
||||
x->netmask == y->netmask &&
|
||||
#endif
|
||||
a->extensions == b->extensions;
|
||||
}
|
||||
|
||||
/* Get the ith element from the array block n */
|
||||
#define ahash_data(n, i, dsize) \
|
||||
((struct mtype_elem *)((n)->value + ((i) * (dsize))))
|
||||
|
||||
/* Delete expired elements from the hashtable */
|
||||
static void
|
||||
mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
|
||||
mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
|
||||
{
|
||||
struct htable *t = h->table;
|
||||
struct htable *t;
|
||||
struct hbucket *n;
|
||||
struct mtype_elem *data;
|
||||
u32 i;
|
||||
int j;
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
u8 k;
|
||||
#endif
|
||||
|
||||
rcu_read_lock_bh();
|
||||
t = rcu_dereference_bh(h->table);
|
||||
for (i = 0; i < jhash_size(t->htable_bits); i++) {
|
||||
n = hbucket(t, i);
|
||||
for (j = 0; j < n->pos; j++) {
|
||||
data = ahash_data(n, j, dsize);
|
||||
if (ip_set_timeout_expired(ext_timeout(data, h))) {
|
||||
if (ip_set_timeout_expired(ext_timeout(data, set))) {
|
||||
pr_debug("expired %u/%u\n", i, j);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
mtype_del_cidr(h, CIDR(data->cidr),
|
||||
nets_length);
|
||||
for (k = 0; k < IPSET_NET_COUNT; k++)
|
||||
mtype_del_cidr(h, CIDR(data->cidr, k),
|
||||
nets_length, k);
|
||||
#endif
|
||||
ip_set_ext_destroy(set, data);
|
||||
if (j != n->pos - 1)
|
||||
/* Not last one */
|
||||
memcpy(data,
|
||||
|
@ -481,6 +507,7 @@ mtype_expire(struct htype *h, u8 nets_length, size_t dsize)
|
|||
n->value = tmp;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock_bh();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -491,10 +518,10 @@ mtype_gc(unsigned long ul_set)
|
|||
|
||||
pr_debug("called\n");
|
||||
write_lock_bh(&set->lock);
|
||||
mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
|
||||
mtype_expire(set, h, NLEN(set->family), set->dsize);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
|
||||
h->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
|
||||
add_timer(&h->gc);
|
||||
}
|
||||
|
||||
|
@ -505,7 +532,7 @@ static int
|
|||
mtype_resize(struct ip_set *set, bool retried)
|
||||
{
|
||||
struct htype *h = set->data;
|
||||
struct htable *t, *orig = h->table;
|
||||
struct htable *t, *orig = rcu_dereference_bh_nfnl(h->table);
|
||||
u8 htable_bits = orig->htable_bits;
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
u8 flags;
|
||||
|
@ -520,8 +547,7 @@ mtype_resize(struct ip_set *set, bool retried)
|
|||
if (SET_WITH_TIMEOUT(set) && !retried) {
|
||||
i = h->elements;
|
||||
write_lock_bh(&set->lock);
|
||||
mtype_expire(set->data, NETS_LENGTH(set->family),
|
||||
h->dsize);
|
||||
mtype_expire(set, set->data, NLEN(set->family), set->dsize);
|
||||
write_unlock_bh(&set->lock);
|
||||
if (h->elements < i)
|
||||
return 0;
|
||||
|
@ -548,25 +574,25 @@ mtype_resize(struct ip_set *set, bool retried)
|
|||
for (i = 0; i < jhash_size(orig->htable_bits); i++) {
|
||||
n = hbucket(orig, i);
|
||||
for (j = 0; j < n->pos; j++) {
|
||||
data = ahash_data(n, j, h->dsize);
|
||||
data = ahash_data(n, j, set->dsize);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
flags = 0;
|
||||
mtype_data_reset_flags(data, &flags);
|
||||
#endif
|
||||
m = hbucket(t, HKEY(data, h->initval, htable_bits));
|
||||
ret = hbucket_elem_add(m, AHASH_MAX(h), h->dsize);
|
||||
ret = hbucket_elem_add(m, AHASH_MAX(h), set->dsize);
|
||||
if (ret < 0) {
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
mtype_data_reset_flags(data, &flags);
|
||||
#endif
|
||||
read_unlock_bh(&set->lock);
|
||||
ahash_destroy(t);
|
||||
mtype_ahash_destroy(set, t, false);
|
||||
if (ret == -EAGAIN)
|
||||
goto retry;
|
||||
return ret;
|
||||
}
|
||||
d = ahash_data(m, m->pos++, h->dsize);
|
||||
memcpy(d, data, h->dsize);
|
||||
d = ahash_data(m, m->pos++, set->dsize);
|
||||
memcpy(d, data, set->dsize);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
mtype_data_reset_flags(d, &flags);
|
||||
#endif
|
||||
|
@ -581,7 +607,7 @@ mtype_resize(struct ip_set *set, bool retried)
|
|||
|
||||
pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
|
||||
orig->htable_bits, orig, t->htable_bits, t);
|
||||
ahash_destroy(orig);
|
||||
mtype_ahash_destroy(set, orig, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -604,7 +630,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
|
||||
if (SET_WITH_TIMEOUT(set) && h->elements >= h->maxelem)
|
||||
/* FIXME: when set is full, we slow down here */
|
||||
mtype_expire(h, NETS_LENGTH(set->family), h->dsize);
|
||||
mtype_expire(set, h, NLEN(set->family), set->dsize);
|
||||
|
||||
if (h->elements >= h->maxelem) {
|
||||
if (net_ratelimit())
|
||||
|
@ -618,11 +644,11 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
key = HKEY(value, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i, h->dsize);
|
||||
data = ahash_data(n, i, set->dsize);
|
||||
if (mtype_data_equal(data, d, &multi)) {
|
||||
if (flag_exist ||
|
||||
(SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(data, h)))) {
|
||||
ip_set_timeout_expired(ext_timeout(data, set)))) {
|
||||
/* Just the extensions could be overwritten */
|
||||
j = i;
|
||||
goto reuse_slot;
|
||||
|
@ -633,30 +659,37 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
}
|
||||
/* Reuse first timed out entry */
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(data, h)) &&
|
||||
ip_set_timeout_expired(ext_timeout(data, set)) &&
|
||||
j != AHASH_MAX(h) + 1)
|
||||
j = i;
|
||||
}
|
||||
reuse_slot:
|
||||
if (j != AHASH_MAX(h) + 1) {
|
||||
/* Fill out reused slot */
|
||||
data = ahash_data(n, j, h->dsize);
|
||||
data = ahash_data(n, j, set->dsize);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
mtype_del_cidr(h, CIDR(data->cidr), NETS_LENGTH(set->family));
|
||||
mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
|
||||
for (i = 0; i < IPSET_NET_COUNT; i++) {
|
||||
mtype_del_cidr(h, CIDR(data->cidr, i),
|
||||
NLEN(set->family), i);
|
||||
mtype_add_cidr(h, CIDR(d->cidr, i),
|
||||
NLEN(set->family), i);
|
||||
}
|
||||
#endif
|
||||
ip_set_ext_destroy(set, data);
|
||||
} else {
|
||||
/* Use/create a new slot */
|
||||
TUNE_AHASH_MAX(h, multi);
|
||||
ret = hbucket_elem_add(n, AHASH_MAX(h), h->dsize);
|
||||
ret = hbucket_elem_add(n, AHASH_MAX(h), set->dsize);
|
||||
if (ret != 0) {
|
||||
if (ret == -EAGAIN)
|
||||
mtype_data_next(&h->next, d);
|
||||
goto out;
|
||||
}
|
||||
data = ahash_data(n, n->pos++, h->dsize);
|
||||
data = ahash_data(n, n->pos++, set->dsize);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
mtype_add_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
|
||||
for (i = 0; i < IPSET_NET_COUNT; i++)
|
||||
mtype_add_cidr(h, CIDR(d->cidr, i), NLEN(set->family),
|
||||
i);
|
||||
#endif
|
||||
h->elements++;
|
||||
}
|
||||
|
@ -665,9 +698,11 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
mtype_data_set_flags(data, flags);
|
||||
#endif
|
||||
if (SET_WITH_TIMEOUT(set))
|
||||
ip_set_timeout_set(ext_timeout(data, h), ext->timeout);
|
||||
ip_set_timeout_set(ext_timeout(data, set), ext->timeout);
|
||||
if (SET_WITH_COUNTER(set))
|
||||
ip_set_init_counter(ext_counter(data, h), ext);
|
||||
ip_set_init_counter(ext_counter(data, set), ext);
|
||||
if (SET_WITH_COMMENT(set))
|
||||
ip_set_init_comment(ext_comment(data, set), ext);
|
||||
|
||||
out:
|
||||
rcu_read_unlock_bh();
|
||||
|
@ -682,47 +717,60 @@ mtype_del(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
struct ip_set_ext *mext, u32 flags)
|
||||
{
|
||||
struct htype *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
struct htable *t;
|
||||
const struct mtype_elem *d = value;
|
||||
struct mtype_elem *data;
|
||||
struct hbucket *n;
|
||||
int i;
|
||||
int i, ret = -IPSET_ERR_EXIST;
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
u8 j;
|
||||
#endif
|
||||
u32 key, multi = 0;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
t = rcu_dereference_bh(h->table);
|
||||
key = HKEY(value, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i, h->dsize);
|
||||
data = ahash_data(n, i, set->dsize);
|
||||
if (!mtype_data_equal(data, d, &multi))
|
||||
continue;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(data, h)))
|
||||
return -IPSET_ERR_EXIST;
|
||||
ip_set_timeout_expired(ext_timeout(data, set)))
|
||||
goto out;
|
||||
if (i != n->pos - 1)
|
||||
/* Not last one */
|
||||
memcpy(data, ahash_data(n, n->pos - 1, h->dsize),
|
||||
h->dsize);
|
||||
memcpy(data, ahash_data(n, n->pos - 1, set->dsize),
|
||||
set->dsize);
|
||||
|
||||
n->pos--;
|
||||
h->elements--;
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
mtype_del_cidr(h, CIDR(d->cidr), NETS_LENGTH(set->family));
|
||||
for (j = 0; j < IPSET_NET_COUNT; j++)
|
||||
mtype_del_cidr(h, CIDR(d->cidr, j), NLEN(set->family),
|
||||
j);
|
||||
#endif
|
||||
ip_set_ext_destroy(set, data);
|
||||
if (n->pos + AHASH_INIT_SIZE < n->size) {
|
||||
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
|
||||
* h->dsize,
|
||||
* set->dsize,
|
||||
GFP_ATOMIC);
|
||||
if (!tmp)
|
||||
return 0;
|
||||
if (!tmp) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
n->size -= AHASH_INIT_SIZE;
|
||||
memcpy(tmp, n->value, n->size * h->dsize);
|
||||
memcpy(tmp, n->value, n->size * set->dsize);
|
||||
kfree(n->value);
|
||||
n->value = tmp;
|
||||
}
|
||||
return 0;
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return -IPSET_ERR_EXIST;
|
||||
out:
|
||||
rcu_read_unlock_bh();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
@ -730,8 +778,7 @@ mtype_data_match(struct mtype_elem *data, const struct ip_set_ext *ext,
|
|||
struct ip_set_ext *mext, struct ip_set *set, u32 flags)
|
||||
{
|
||||
if (SET_WITH_COUNTER(set))
|
||||
ip_set_update_counter(ext_counter(data,
|
||||
(struct htype *)(set->data)),
|
||||
ip_set_update_counter(ext_counter(data, set),
|
||||
ext, mext, flags);
|
||||
return mtype_do_data_match(data);
|
||||
}
|
||||
|
@ -745,25 +792,38 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
|
|||
struct ip_set_ext *mext, u32 flags)
|
||||
{
|
||||
struct htype *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
struct htable *t = rcu_dereference_bh(h->table);
|
||||
struct hbucket *n;
|
||||
struct mtype_elem *data;
|
||||
#if IPSET_NET_COUNT == 2
|
||||
struct mtype_elem orig = *d;
|
||||
int i, j = 0, k;
|
||||
#else
|
||||
int i, j = 0;
|
||||
#endif
|
||||
u32 key, multi = 0;
|
||||
u8 nets_length = NETS_LENGTH(set->family);
|
||||
u8 nets_length = NLEN(set->family);
|
||||
|
||||
pr_debug("test by nets\n");
|
||||
for (; j < nets_length && h->nets[j].nets && !multi; j++) {
|
||||
mtype_data_netmask(d, h->nets[j].cidr);
|
||||
for (; j < nets_length && h->nets[j].nets[0] && !multi; j++) {
|
||||
#if IPSET_NET_COUNT == 2
|
||||
mtype_data_reset_elem(d, &orig);
|
||||
mtype_data_netmask(d, h->nets[j].cidr[0], false);
|
||||
for (k = 0; k < nets_length && h->nets[k].nets[1] && !multi;
|
||||
k++) {
|
||||
mtype_data_netmask(d, h->nets[k].cidr[1], true);
|
||||
#else
|
||||
mtype_data_netmask(d, h->nets[j].cidr[0]);
|
||||
#endif
|
||||
key = HKEY(d, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i, h->dsize);
|
||||
data = ahash_data(n, i, set->dsize);
|
||||
if (!mtype_data_equal(data, d, &multi))
|
||||
continue;
|
||||
if (SET_WITH_TIMEOUT(set)) {
|
||||
if (!ip_set_timeout_expired(
|
||||
ext_timeout(data, h)))
|
||||
ext_timeout(data, set)))
|
||||
return mtype_data_match(data, ext,
|
||||
mext, set,
|
||||
flags);
|
||||
|
@ -774,6 +834,9 @@ mtype_test_cidrs(struct ip_set *set, struct mtype_elem *d,
|
|||
return mtype_data_match(data, ext,
|
||||
mext, set, flags);
|
||||
}
|
||||
#if IPSET_NET_COUNT == 2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -785,30 +848,41 @@ mtype_test(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
struct ip_set_ext *mext, u32 flags)
|
||||
{
|
||||
struct htype *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
struct htable *t;
|
||||
struct mtype_elem *d = value;
|
||||
struct hbucket *n;
|
||||
struct mtype_elem *data;
|
||||
int i;
|
||||
int i, ret = 0;
|
||||
u32 key, multi = 0;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
t = rcu_dereference_bh(h->table);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
/* If we test an IP address and not a network address,
|
||||
* try all possible network sizes */
|
||||
if (CIDR(d->cidr) == SET_HOST_MASK(set->family))
|
||||
return mtype_test_cidrs(set, d, ext, mext, flags);
|
||||
for (i = 0; i < IPSET_NET_COUNT; i++)
|
||||
if (CIDR(d->cidr, i) != SET_HOST_MASK(set->family))
|
||||
break;
|
||||
if (i == IPSET_NET_COUNT) {
|
||||
ret = mtype_test_cidrs(set, d, ext, mext, flags);
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
key = HKEY(d, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i, h->dsize);
|
||||
data = ahash_data(n, i, set->dsize);
|
||||
if (mtype_data_equal(data, d, &multi) &&
|
||||
!(SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(data, h))))
|
||||
return mtype_data_match(data, ext, mext, set, flags);
|
||||
ip_set_timeout_expired(ext_timeout(data, set)))) {
|
||||
ret = mtype_data_match(data, ext, mext, set, flags);
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
out:
|
||||
rcu_read_unlock_bh();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reply a HEADER request: fill out the header part of the set */
|
||||
|
@ -816,18 +890,18 @@ static int
|
|||
mtype_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct htype *h = set->data;
|
||||
const struct htable *t;
|
||||
struct nlattr *nested;
|
||||
size_t memsize;
|
||||
|
||||
read_lock_bh(&set->lock);
|
||||
memsize = mtype_ahash_memsize(h, NETS_LENGTH(set->family));
|
||||
read_unlock_bh(&set->lock);
|
||||
t = rcu_dereference_bh_nfnl(h->table);
|
||||
memsize = mtype_ahash_memsize(h, t, NLEN(set->family), set->dsize);
|
||||
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
if (nla_put_net32(skb, IPSET_ATTR_HASHSIZE,
|
||||
htonl(jhash_size(h->table->htable_bits))) ||
|
||||
htonl(jhash_size(t->htable_bits))) ||
|
||||
nla_put_net32(skb, IPSET_ATTR_MAXELEM, htonl(h->maxelem)))
|
||||
goto nla_put_failure;
|
||||
#ifdef IP_SET_HASH_WITH_NETMASK
|
||||
|
@ -836,12 +910,9 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
|
|||
goto nla_put_failure;
|
||||
#endif
|
||||
if (nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
|
||||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)) ||
|
||||
((set->extensions & IPSET_EXT_TIMEOUT) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout))) ||
|
||||
((set->extensions & IPSET_EXT_COUNTER) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
|
||||
htonl(IPSET_FLAG_WITH_COUNTERS))))
|
||||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
|
||||
goto nla_put_failure;
|
||||
if (unlikely(ip_set_put_flags(skb, set)))
|
||||
goto nla_put_failure;
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
|
@ -856,7 +927,7 @@ mtype_list(const struct ip_set *set,
|
|||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct htype *h = set->data;
|
||||
const struct htable *t = h->table;
|
||||
const struct htable *t = rcu_dereference_bh_nfnl(h->table);
|
||||
struct nlattr *atd, *nested;
|
||||
const struct hbucket *n;
|
||||
const struct mtype_elem *e;
|
||||
|
@ -874,9 +945,9 @@ mtype_list(const struct ip_set *set,
|
|||
n = hbucket(t, cb->args[2]);
|
||||
pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
e = ahash_data(n, i, h->dsize);
|
||||
e = ahash_data(n, i, set->dsize);
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, h)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
continue;
|
||||
pr_debug("list hash %lu hbucket %p i %u, data %p\n",
|
||||
cb->args[2], n, i, e);
|
||||
|
@ -890,13 +961,7 @@ mtype_list(const struct ip_set *set,
|
|||
}
|
||||
if (mtype_data_list(skb, e))
|
||||
goto nla_put_failure;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(
|
||||
ext_timeout(e, h)))))
|
||||
goto nla_put_failure;
|
||||
if (SET_WITH_COUNTER(set) &&
|
||||
ip_set_put_counter(skb, ext_counter(e, h)))
|
||||
if (ip_set_put_extensions(skb, set, e, true))
|
||||
goto nla_put_failure;
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
|
@ -909,23 +974,23 @@ mtype_list(const struct ip_set *set,
|
|||
|
||||
nla_put_failure:
|
||||
nlmsg_trim(skb, incomplete);
|
||||
ipset_nest_end(skb, atd);
|
||||
if (unlikely(first == cb->args[2])) {
|
||||
pr_warning("Can't list set %s: one bucket does not fit into "
|
||||
"a message. Please report it!\n", set->name);
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
ipset_nest_end(skb, atd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb,
|
||||
IPSET_TOKEN(MTYPE, _kadt)(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt);
|
||||
|
||||
static int
|
||||
TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[],
|
||||
IPSET_TOKEN(MTYPE, _uadt)(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
|
||||
|
||||
static const struct ip_set_type_variant mtype_variant = {
|
||||
|
@ -946,16 +1011,17 @@ static const struct ip_set_type_variant mtype_variant = {
|
|||
|
||||
#ifdef IP_SET_EMIT_CREATE
|
||||
static int
|
||||
TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
|
||||
struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u32 cadt_flags = 0;
|
||||
u8 hbits;
|
||||
#ifdef IP_SET_HASH_WITH_NETMASK
|
||||
u8 netmask;
|
||||
#endif
|
||||
size_t hsize;
|
||||
struct HTYPE *h;
|
||||
struct htable *t;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
@ -1005,7 +1071,7 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
h->netmask = netmask;
|
||||
#endif
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
set->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
hsize = htable_size(hbits);
|
||||
|
@ -1013,91 +1079,37 @@ TOKEN(HTYPE, _create)(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table = ip_set_alloc(hsize);
|
||||
if (!h->table) {
|
||||
t = ip_set_alloc(hsize);
|
||||
if (!t) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
t->htable_bits = hbits;
|
||||
rcu_assign_pointer(h->table, t);
|
||||
|
||||
set->data = h;
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
set->variant = &TOKEN(HTYPE, 4_variant);
|
||||
else
|
||||
set->variant = &TOKEN(HTYPE, 6_variant);
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS])
|
||||
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
|
||||
set->extensions |= IPSET_EXT_COUNTER;
|
||||
if (set->family == NFPROTO_IPV4) {
|
||||
set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
|
||||
set->dsize = ip_set_elem_len(set, tb,
|
||||
sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)));
|
||||
} else {
|
||||
set->variant = &IPSET_TOKEN(HTYPE, 6_variant);
|
||||
set->dsize = ip_set_elem_len(set, tb,
|
||||
sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)));
|
||||
}
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout =
|
||||
ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
if (set->family == NFPROTO_IPV4) {
|
||||
h->dsize =
|
||||
sizeof(struct TOKEN(HTYPE, 4ct_elem));
|
||||
h->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct TOKEN(HTYPE, 4ct_elem),
|
||||
timeout);
|
||||
h->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct TOKEN(HTYPE, 4ct_elem),
|
||||
counter);
|
||||
TOKEN(HTYPE, 4_gc_init)(set,
|
||||
TOKEN(HTYPE, 4_gc));
|
||||
} else {
|
||||
h->dsize =
|
||||
sizeof(struct TOKEN(HTYPE, 6ct_elem));
|
||||
h->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct TOKEN(HTYPE, 6ct_elem),
|
||||
timeout);
|
||||
h->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct TOKEN(HTYPE, 6ct_elem),
|
||||
counter);
|
||||
TOKEN(HTYPE, 6_gc_init)(set,
|
||||
TOKEN(HTYPE, 6_gc));
|
||||
}
|
||||
} else {
|
||||
if (set->family == NFPROTO_IPV4) {
|
||||
h->dsize =
|
||||
sizeof(struct TOKEN(HTYPE, 4c_elem));
|
||||
h->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct TOKEN(HTYPE, 4c_elem),
|
||||
counter);
|
||||
} else {
|
||||
h->dsize =
|
||||
sizeof(struct TOKEN(HTYPE, 6c_elem));
|
||||
h->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct TOKEN(HTYPE, 6c_elem),
|
||||
counter);
|
||||
}
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
if (set->family == NFPROTO_IPV4) {
|
||||
h->dsize = sizeof(struct TOKEN(HTYPE, 4t_elem));
|
||||
h->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct TOKEN(HTYPE, 4t_elem),
|
||||
timeout);
|
||||
TOKEN(HTYPE, 4_gc_init)(set, TOKEN(HTYPE, 4_gc));
|
||||
} else {
|
||||
h->dsize = sizeof(struct TOKEN(HTYPE, 6t_elem));
|
||||
h->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct TOKEN(HTYPE, 6t_elem),
|
||||
timeout);
|
||||
TOKEN(HTYPE, 6_gc_init)(set, TOKEN(HTYPE, 6_gc));
|
||||
}
|
||||
} else {
|
||||
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
h->dsize = sizeof(struct TOKEN(HTYPE, 4_elem));
|
||||
IPSET_TOKEN(HTYPE, 4_gc_init)(set,
|
||||
IPSET_TOKEN(HTYPE, 4_gc));
|
||||
else
|
||||
h->dsize = sizeof(struct TOKEN(HTYPE, 6_elem));
|
||||
IPSET_TOKEN(HTYPE, 6_gc_init)(set,
|
||||
IPSET_TOKEN(HTYPE, 6_gc));
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
set->name, jhash_size(t->htable_bits),
|
||||
t->htable_bits, h->maxelem, set->data, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,19 +23,20 @@
|
|||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define REVISION_MAX 1 /* Counters support */
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 Counters support */
|
||||
#define IPSET_TYPE_REV_MAX 2 /* Comments support */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("hash:ip", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("hash:ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:ip");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define HTYPE hash_ip
|
||||
#define IP_SET_HASH_WITH_NETMASK
|
||||
|
||||
/* IPv4 variants */
|
||||
/* IPv4 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_ip4_elem {
|
||||
|
@ -43,22 +44,6 @@ struct hash_ip4_elem {
|
|||
__be32 ip;
|
||||
};
|
||||
|
||||
struct hash_ip4t_elem {
|
||||
__be32 ip;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ip4c_elem {
|
||||
__be32 ip;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ip4ct_elem {
|
||||
__be32 ip;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -99,7 +84,7 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_ip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ip4_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
__be32 ip;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
|
||||
|
@ -118,8 +103,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ip4_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
u32 ip, ip_to, hosts;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip = 0, ip_to = 0, hosts;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
|
@ -178,29 +163,13 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
/* IPv6 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_ip6_elem {
|
||||
union nf_inet_addr ip;
|
||||
};
|
||||
|
||||
struct hash_ip6t_elem {
|
||||
union nf_inet_addr ip;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ip6c_elem {
|
||||
union nf_inet_addr ip;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ip6ct_elem {
|
||||
union nf_inet_addr ip;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -253,7 +222,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_ip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ip6_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
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);
|
||||
|
@ -270,7 +239,7 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ip6_elem e = {};
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
|
@ -304,8 +273,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
|
|||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@ -324,6 +293,7 @@ static struct ip_set_type hash_ip_type __read_mostly = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -24,19 +24,20 @@
|
|||
#include <linux/netfilter/ipset/ip_set_getport.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
#define REVISION_MAX 2 /* Counters support added */
|
||||
/* 2 Counters support added */
|
||||
#define IPSET_TYPE_REV_MAX 3 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("hash:ip,port", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("hash:ip,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:ip,port");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define HTYPE hash_ipport
|
||||
|
||||
/* IPv4 variants */
|
||||
/* IPv4 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_ipport4_elem {
|
||||
|
@ -46,31 +47,6 @@ struct hash_ipport4_elem {
|
|||
u8 padding;
|
||||
};
|
||||
|
||||
struct hash_ipport4t_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ipport4c_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ipport4ct_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -116,10 +92,9 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_ipport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&e.port, &e.proto))
|
||||
|
@ -136,8 +111,8 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ipport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip, ip_to = 0, p = 0, port, port_to;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
|
@ -222,7 +197,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
/* IPv6 variant */
|
||||
|
||||
struct hash_ipport6_elem {
|
||||
union nf_inet_addr ip;
|
||||
|
@ -231,31 +206,6 @@ struct hash_ipport6_elem {
|
|||
u8 padding;
|
||||
};
|
||||
|
||||
struct hash_ipport6t_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ipport6c_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ipport6ct_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -306,10 +256,9 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_ipport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport6_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&e.port, &e.proto))
|
||||
|
@ -326,7 +275,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ipport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport6_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 port, port_to;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
@ -396,8 +345,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
|
|||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_ipport_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@ -419,6 +368,7 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -24,19 +24,20 @@
|
|||
#include <linux/netfilter/ipset/ip_set_getport.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
#define REVISION_MAX 2 /* Counters support added */
|
||||
/* 2 Counters support added */
|
||||
#define IPSET_TYPE_REV_MAX 3 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("hash:ip,port,ip", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("hash:ip,port,ip", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:ip,port,ip");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define HTYPE hash_ipportip
|
||||
|
||||
/* IPv4 variants */
|
||||
/* IPv4 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_ipportip4_elem {
|
||||
|
@ -47,34 +48,6 @@ struct hash_ipportip4_elem {
|
|||
u8 padding;
|
||||
};
|
||||
|
||||
struct hash_ipportip4t_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ipportip4c_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ipportip4ct_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
|
||||
const struct hash_ipportip4_elem *ip2,
|
||||
|
@ -120,10 +93,9 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_ipportip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&e.port, &e.proto))
|
||||
|
@ -141,8 +113,8 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ipportip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip, ip_to = 0, p = 0, port, port_to;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
|
@ -231,7 +203,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
/* IPv6 variant */
|
||||
|
||||
struct hash_ipportip6_elem {
|
||||
union nf_inet_addr ip;
|
||||
|
@ -241,34 +213,6 @@ struct hash_ipportip6_elem {
|
|||
u8 padding;
|
||||
};
|
||||
|
||||
struct hash_ipportip6t_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ipportip6c_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ipportip6ct_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -319,10 +263,9 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_ipportip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip6_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&e.port, &e.proto))
|
||||
|
@ -340,7 +283,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ipportip *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip6_elem e = { };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 port, port_to;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
@ -414,8 +357,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
|
|||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_ipportip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@ -437,6 +380,7 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -24,15 +24,16 @@
|
|||
#include <linux/netfilter/ipset/ip_set_getport.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
/* 2 Range as input support for IPv4 added */
|
||||
/* 3 nomatch flag support added */
|
||||
#define REVISION_MAX 4 /* Counters support added */
|
||||
/* 4 Counters support added */
|
||||
#define IPSET_TYPE_REV_MAX 5 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("hash:ip,port,net", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("hash:ip,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:ip,port,net");
|
||||
|
||||
/* Type specific function prefix */
|
||||
|
@ -46,7 +47,7 @@ MODULE_ALIAS("ip_set_hash:ip,port,net");
|
|||
#define IP_SET_HASH_WITH_PROTO
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
|
||||
/* IPv4 variants */
|
||||
/* IPv4 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_ipportnet4_elem {
|
||||
|
@ -58,37 +59,6 @@ struct hash_ipportnet4_elem {
|
|||
u8 proto;
|
||||
};
|
||||
|
||||
struct hash_ipportnet4t_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ipportnet4c_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ipportnet4ct_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -170,9 +140,9 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_ipportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet4_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.cidr = HOST_MASK - 1;
|
||||
|
@ -195,9 +165,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ipportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet4_elem e = { .cidr = HOST_MASK - 1 };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
u32 ip2_from, ip2_to, ip2_last, ip2;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip = 0, ip_to = 0, p = 0, port, port_to;
|
||||
u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
|
||||
bool with_ports = false;
|
||||
u8 cidr;
|
||||
int ret;
|
||||
|
@ -272,7 +242,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (!cidr || cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
@ -306,9 +276,9 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
: port;
|
||||
for (; p <= port_to; p++) {
|
||||
e.port = htons(p);
|
||||
ip2 = retried
|
||||
&& ip == ntohl(h->next.ip)
|
||||
&& p == ntohs(h->next.port)
|
||||
ip2 = retried &&
|
||||
ip == ntohl(h->next.ip) &&
|
||||
p == ntohs(h->next.port)
|
||||
? ntohl(h->next.ip2) : ip2_from;
|
||||
while (!after(ip2, ip2_to)) {
|
||||
e.ip2 = htonl(ip2);
|
||||
|
@ -328,7 +298,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
/* IPv6 variant */
|
||||
|
||||
struct hash_ipportnet6_elem {
|
||||
union nf_inet_addr ip;
|
||||
|
@ -339,37 +309,6 @@ struct hash_ipportnet6_elem {
|
|||
u8 proto;
|
||||
};
|
||||
|
||||
struct hash_ipportnet6t_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_ipportnet6c_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_ipportnet6ct_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -454,9 +393,9 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_ipportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet6_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.cidr = HOST_MASK - 1;
|
||||
|
@ -479,7 +418,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_ipportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet6_elem e = { .cidr = HOST_MASK - 1 };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 port, port_to;
|
||||
bool with_ports = false;
|
||||
u8 cidr;
|
||||
|
@ -574,8 +513,8 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
|||
IPSET_TYPE_NOMATCH,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_ipportnet_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@ -600,6 +539,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -22,21 +22,22 @@
|
|||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 Range as input support for IPv4 added */
|
||||
/* 2 nomatch flag support added */
|
||||
#define REVISION_MAX 3 /* Counters support added */
|
||||
/* 3 Counters support added */
|
||||
#define IPSET_TYPE_REV_MAX 4 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("hash:net", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("hash:net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:net");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define HTYPE hash_net
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
|
||||
/* IPv4 variants */
|
||||
/* IPv4 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_net4_elem {
|
||||
|
@ -46,31 +47,6 @@ struct hash_net4_elem {
|
|||
u8 cidr;
|
||||
};
|
||||
|
||||
struct hash_net4t_elem {
|
||||
__be32 ip;
|
||||
u16 padding0;
|
||||
u8 nomatch;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_net4c_elem {
|
||||
__be32 ip;
|
||||
u16 padding0;
|
||||
u8 nomatch;
|
||||
u8 cidr;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_net4ct_elem {
|
||||
__be32 ip;
|
||||
u16 padding0;
|
||||
u8 nomatch;
|
||||
u8 cidr;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -143,9 +119,9 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_net *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net4_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (e.cidr == 0)
|
||||
return -EINVAL;
|
||||
|
@ -165,8 +141,8 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_net *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net4_elem e = { .cidr = HOST_MASK };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
u32 ip = 0, ip_to, last;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip = 0, ip_to = 0, last;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
|
@ -228,7 +204,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
/* IPv6 variant */
|
||||
|
||||
struct hash_net6_elem {
|
||||
union nf_inet_addr ip;
|
||||
|
@ -237,31 +213,6 @@ struct hash_net6_elem {
|
|||
u8 cidr;
|
||||
};
|
||||
|
||||
struct hash_net6t_elem {
|
||||
union nf_inet_addr ip;
|
||||
u16 padding0;
|
||||
u8 nomatch;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_net6c_elem {
|
||||
union nf_inet_addr ip;
|
||||
u16 padding0;
|
||||
u8 nomatch;
|
||||
u8 cidr;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_net6ct_elem {
|
||||
union nf_inet_addr ip;
|
||||
u16 padding0;
|
||||
u8 nomatch;
|
||||
u8 cidr;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -338,9 +289,9 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_net *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net6_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (e.cidr == 0)
|
||||
return -EINVAL;
|
||||
|
@ -357,10 +308,9 @@ static int
|
|||
hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct hash_net *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net6_elem e = { .cidr = HOST_MASK };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
|
@ -406,8 +356,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
|
|||
.features = IPSET_TYPE_IP | IPSET_TYPE_NOMATCH,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_net_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@ -425,6 +375,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
|
|||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -23,14 +23,15 @@
|
|||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 nomatch flag support added */
|
||||
/* 2 /0 support added */
|
||||
#define REVISION_MAX 3 /* Counters support added */
|
||||
/* 3 Counters support added */
|
||||
#define IPSET_TYPE_REV_MAX 4 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("hash:net,iface", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("hash:net,iface", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:net,iface");
|
||||
|
||||
/* Interface name rbtree */
|
||||
|
@ -134,7 +135,7 @@ iface_add(struct rb_root *root, const char **iface)
|
|||
|
||||
#define STREQ(a, b) (strcmp(a, b) == 0)
|
||||
|
||||
/* IPv4 variants */
|
||||
/* IPv4 variant */
|
||||
|
||||
struct hash_netiface4_elem_hashed {
|
||||
__be32 ip;
|
||||
|
@ -144,7 +145,7 @@ struct hash_netiface4_elem_hashed {
|
|||
u8 elem;
|
||||
};
|
||||
|
||||
/* Member elements without timeout */
|
||||
/* Member elements */
|
||||
struct hash_netiface4_elem {
|
||||
__be32 ip;
|
||||
u8 physdev;
|
||||
|
@ -154,37 +155,6 @@ struct hash_netiface4_elem {
|
|||
const char *iface;
|
||||
};
|
||||
|
||||
struct hash_netiface4t_elem {
|
||||
__be32 ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u8 nomatch;
|
||||
u8 elem;
|
||||
const char *iface;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_netiface4c_elem {
|
||||
__be32 ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u8 nomatch;
|
||||
u8 elem;
|
||||
const char *iface;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_netiface4ct_elem {
|
||||
__be32 ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u8 nomatch;
|
||||
u8 elem;
|
||||
const char *iface;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -265,10 +235,10 @@ hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
struct hash_netiface *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface4_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
|
||||
.elem = 1,
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
int ret;
|
||||
|
||||
if (e.cidr == 0)
|
||||
|
@ -319,8 +289,8 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
struct hash_netiface *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface4_elem e = { .cidr = HOST_MASK, .elem = 1 };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
u32 ip = 0, ip_to, last;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip = 0, ip_to = 0, last;
|
||||
char iface[IFNAMSIZ];
|
||||
int ret;
|
||||
|
||||
|
@ -399,7 +369,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
/* IPv6 variant */
|
||||
|
||||
struct hash_netiface6_elem_hashed {
|
||||
union nf_inet_addr ip;
|
||||
|
@ -418,37 +388,6 @@ struct hash_netiface6_elem {
|
|||
const char *iface;
|
||||
};
|
||||
|
||||
struct hash_netiface6t_elem {
|
||||
union nf_inet_addr ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u8 nomatch;
|
||||
u8 elem;
|
||||
const char *iface;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_netiface6c_elem {
|
||||
union nf_inet_addr ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u8 nomatch;
|
||||
u8 elem;
|
||||
const char *iface;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_netiface6ct_elem {
|
||||
union nf_inet_addr ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u8 nomatch;
|
||||
u8 elem;
|
||||
const char *iface;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -534,10 +473,10 @@ hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
struct hash_netiface *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface6_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK,
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
|
||||
.elem = 1,
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
int ret;
|
||||
|
||||
if (e.cidr == 0)
|
||||
|
@ -584,7 +523,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
struct hash_netiface *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface6_elem e = { .cidr = HOST_MASK, .elem = 1 };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
char iface[IFNAMSIZ];
|
||||
int ret;
|
||||
|
||||
|
@ -645,8 +584,8 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
|
|||
IPSET_TYPE_NOMATCH,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_netiface_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@ -668,6 +607,7 @@ static struct ip_set_type hash_netiface_type __read_mostly = {
|
|||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,483 @@
|
|||
/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2013 Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:net type */
|
||||
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/ipset/pfxlen.h>
|
||||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
#define IPSET_TYPE_REV_MAX 0
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
|
||||
IP_SET_MODULE_DESC("hash:net,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:net,net");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define HTYPE hash_netnet
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
#define IPSET_NET_COUNT 2
|
||||
|
||||
/* IPv4 variants */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_netnet4_elem {
|
||||
union {
|
||||
__be32 ip[2];
|
||||
__be64 ipcmp;
|
||||
};
|
||||
u8 nomatch;
|
||||
union {
|
||||
u8 cidr[2];
|
||||
u16 ccmp;
|
||||
};
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
hash_netnet4_data_equal(const struct hash_netnet4_elem *ip1,
|
||||
const struct hash_netnet4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ipcmp == ip2->ipcmp &&
|
||||
ip2->ccmp == ip2->ccmp;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hash_netnet4_do_data_match(const struct hash_netnet4_elem *elem)
|
||||
{
|
||||
return elem->nomatch ? -ENOTEMPTY : 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet4_data_set_flags(struct hash_netnet4_elem *elem, u32 flags)
|
||||
{
|
||||
elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet4_data_reset_flags(struct hash_netnet4_elem *elem, u8 *flags)
|
||||
{
|
||||
swap(*flags, elem->nomatch);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet4_data_reset_elem(struct hash_netnet4_elem *elem,
|
||||
struct hash_netnet4_elem *orig)
|
||||
{
|
||||
elem->ip[1] = orig->ip[1];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet4_data_netmask(struct hash_netnet4_elem *elem, u8 cidr, bool inner)
|
||||
{
|
||||
if (inner) {
|
||||
elem->ip[1] &= ip_set_netmask(cidr);
|
||||
elem->cidr[1] = cidr;
|
||||
} else {
|
||||
elem->ip[0] &= ip_set_netmask(cidr);
|
||||
elem->cidr[0] = cidr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netnet4_data_list(struct sk_buff *skb,
|
||||
const struct hash_netnet4_elem *data)
|
||||
{
|
||||
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
|
||||
|
||||
if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
|
||||
nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
|
||||
(flags &&
|
||||
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet4_data_next(struct hash_netnet4_elem *next,
|
||||
const struct hash_netnet4_elem *d)
|
||||
{
|
||||
next->ipcmp = d->ipcmp;
|
||||
}
|
||||
|
||||
#define MTYPE hash_netnet4
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_hash_gen.h"
|
||||
|
||||
static int
|
||||
hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_netnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netnet4_elem e = {
|
||||
.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
|
||||
.cidr[1] = h->nets[0].cidr[1] ? h->nets[0].cidr[1] : HOST_MASK,
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK;
|
||||
|
||||
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]);
|
||||
|
||||
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct hash_netnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netnet4_elem e = { .cidr[0] = HOST_MASK,
|
||||
.cidr[1] = HOST_MASK };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip = 0, ip_to = 0, last;
|
||||
u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2;
|
||||
u8 cidr, cidr2;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
|
||||
ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) ||
|
||||
ip_set_get_extensions(set, tb, &ext);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!cidr || cidr > HOST_MASK)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
e.cidr[0] = cidr;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2]) {
|
||||
cidr2 = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
if (!cidr2 || cidr2 > HOST_MASK)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
e.cidr[1] = cidr2;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_NOMATCH)
|
||||
flags |= (IPSET_FLAG_NOMATCH << 16);
|
||||
}
|
||||
|
||||
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]));
|
||||
ret = adtfn(set, &e, &ext, &ext, flags);
|
||||
return ip_set_enomatch(ret, flags, adt, set) ? -ret :
|
||||
ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip_to = ip;
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip_to < ip)
|
||||
swap(ip, ip_to);
|
||||
if (ip + UINT_MAX == ip_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
}
|
||||
|
||||
ip2_to = ip2_from;
|
||||
if (tb[IPSET_ATTR_IP2_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip2_to < ip2_from)
|
||||
swap(ip2_from, ip2_to);
|
||||
if (ip2_from + UINT_MAX == ip2_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = ntohl(h->next.ip[0]);
|
||||
|
||||
while (!after(ip, ip_to)) {
|
||||
e.ip[0] = htonl(ip);
|
||||
last = ip_set_range_to_cidr(ip, ip_to, &cidr);
|
||||
e.cidr[0] = cidr;
|
||||
ip2 = (retried &&
|
||||
ip == ntohl(h->next.ip[0])) ? ntohl(h->next.ip[1])
|
||||
: ip2_from;
|
||||
while (!after(ip2, ip2_to)) {
|
||||
e.ip[1] = htonl(ip2);
|
||||
last2 = ip_set_range_to_cidr(ip2, ip2_to, &cidr2);
|
||||
e.cidr[1] = cidr2;
|
||||
ret = adtfn(set, &e, &ext, &ext, flags);
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip2 = last2 + 1;
|
||||
}
|
||||
ip = last + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
|
||||
struct hash_netnet6_elem {
|
||||
union nf_inet_addr ip[2];
|
||||
u8 nomatch;
|
||||
union {
|
||||
u8 cidr[2];
|
||||
u16 ccmp;
|
||||
};
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
hash_netnet6_data_equal(const struct hash_netnet6_elem *ip1,
|
||||
const struct hash_netnet6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
|
||||
ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
|
||||
ip1->ccmp == ip2->ccmp;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hash_netnet6_do_data_match(const struct hash_netnet6_elem *elem)
|
||||
{
|
||||
return elem->nomatch ? -ENOTEMPTY : 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet6_data_set_flags(struct hash_netnet6_elem *elem, u32 flags)
|
||||
{
|
||||
elem->nomatch = (flags >> 16) & IPSET_FLAG_NOMATCH;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet6_data_reset_flags(struct hash_netnet6_elem *elem, u8 *flags)
|
||||
{
|
||||
swap(*flags, elem->nomatch);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet6_data_reset_elem(struct hash_netnet6_elem *elem,
|
||||
struct hash_netnet6_elem *orig)
|
||||
{
|
||||
elem->ip[1] = orig->ip[1];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet6_data_netmask(struct hash_netnet6_elem *elem, u8 cidr, bool inner)
|
||||
{
|
||||
if (inner) {
|
||||
ip6_netmask(&elem->ip[1], cidr);
|
||||
elem->cidr[1] = cidr;
|
||||
} else {
|
||||
ip6_netmask(&elem->ip[0], cidr);
|
||||
elem->cidr[0] = cidr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netnet6_data_list(struct sk_buff *skb,
|
||||
const struct hash_netnet6_elem *data)
|
||||
{
|
||||
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
|
||||
|
||||
if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
|
||||
nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
|
||||
(flags &&
|
||||
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netnet6_data_next(struct hash_netnet4_elem *next,
|
||||
const struct hash_netnet6_elem *d)
|
||||
{
|
||||
}
|
||||
|
||||
#undef MTYPE
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define MTYPE hash_netnet6
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#define IP_SET_EMIT_CREATE
|
||||
#include "ip_set_hash_gen.h"
|
||||
|
||||
static int
|
||||
hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_netnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netnet6_elem e = {
|
||||
.cidr[0] = h->nets[0].cidr[0] ? h->nets[0].cidr[0] : HOST_MASK,
|
||||
.cidr[1] = h->nets[0].cidr[1] ? h->nets[0].cidr[1] : HOST_MASK
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.ccmp = (HOST_MASK << (sizeof(u8)*8)) | HOST_MASK;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip[0].in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_TWO_SRC, &e.ip[1].in6);
|
||||
ip6_netmask(&e.ip[0], e.cidr[0]);
|
||||
ip6_netmask(&e.ip[1], e.cidr[1]);
|
||||
|
||||
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netnet6_elem e = { .cidr[0] = HOST_MASK,
|
||||
.cidr[1] = HOST_MASK };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
|
||||
ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) ||
|
||||
ip_set_get_extensions(set, tb, &ext);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2])
|
||||
e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
|
||||
if (!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] ||
|
||||
e.cidr[1] > HOST_MASK)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
ip6_netmask(&e.ip[0], e.cidr[0]);
|
||||
ip6_netmask(&e.ip[1], e.cidr[1]);
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_NOMATCH)
|
||||
flags |= (IPSET_FLAG_NOMATCH << 16);
|
||||
}
|
||||
|
||||
ret = adtfn(set, &e, &ext, &ext, flags);
|
||||
|
||||
return ip_set_enomatch(ret, flags, adt, set) ? -ret :
|
||||
ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_netnet_type __read_mostly = {
|
||||
.name = "hash:net,net",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_IP2 | IPSET_TYPE_NOMATCH,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_netnet_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_netnet_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_netnet_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_netnet_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_netnet_type);
|
||||
}
|
||||
|
||||
module_init(hash_netnet_init);
|
||||
module_exit(hash_netnet_fini);
|
|
@ -23,15 +23,16 @@
|
|||
#include <linux/netfilter/ipset/ip_set_getport.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
/* 2 Range as input support for IPv4 added */
|
||||
/* 3 nomatch flag support added */
|
||||
#define REVISION_MAX 4 /* Counters support added */
|
||||
/* 4 Counters support added */
|
||||
#define IPSET_TYPE_REV_MAX 5 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("hash:net,port", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("hash:net,port", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:net,port");
|
||||
|
||||
/* Type specific function prefix */
|
||||
|
@ -45,7 +46,7 @@ MODULE_ALIAS("ip_set_hash:net,port");
|
|||
*/
|
||||
#define IP_SET_HASH_WITH_NETS_PACKED
|
||||
|
||||
/* IPv4 variants */
|
||||
/* IPv4 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_netport4_elem {
|
||||
|
@ -56,34 +57,6 @@ struct hash_netport4_elem {
|
|||
u8 nomatch:1;
|
||||
};
|
||||
|
||||
struct hash_netport4t_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_netport4c_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_netport4ct_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -162,9 +135,9 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_netport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport4_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.cidr = HOST_MASK - 1;
|
||||
|
@ -186,8 +159,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_netport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport4_elem e = { .cidr = HOST_MASK - 1 };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
u32 port, port_to, p = 0, ip = 0, ip_to, last;
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 port, port_to, p = 0, ip = 0, ip_to = 0, last;
|
||||
bool with_ports = false;
|
||||
u8 cidr;
|
||||
int ret;
|
||||
|
@ -287,7 +260,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variants */
|
||||
/* IPv6 variant */
|
||||
|
||||
struct hash_netport6_elem {
|
||||
union nf_inet_addr ip;
|
||||
|
@ -297,34 +270,6 @@ struct hash_netport6_elem {
|
|||
u8 nomatch:1;
|
||||
};
|
||||
|
||||
struct hash_netport6t_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct hash_netport6c_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct hash_netport6ct_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr:7;
|
||||
u8 nomatch:1;
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
|
@ -407,9 +352,9 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct hash_netport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport6_elem e = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr - 1 : HOST_MASK - 1,
|
||||
.cidr = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK) - 1,
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.cidr = HOST_MASK - 1;
|
||||
|
@ -431,7 +376,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
const struct hash_netport *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport6_elem e = { .cidr = HOST_MASK - 1 };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(h);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 port, port_to;
|
||||
bool with_ports = false;
|
||||
u8 cidr;
|
||||
|
@ -518,8 +463,8 @@ static struct ip_set_type hash_netport_type __read_mostly = {
|
|||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_NOMATCH,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_netport_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@ -542,6 +487,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
|
|||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,588 @@
|
|||
/* Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:ip,port,net type */
|
||||
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/ipset/pfxlen.h>
|
||||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_getport.h>
|
||||
#include <linux/netfilter/ipset/ip_set_hash.h>
|
||||
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
#define IPSET_TYPE_REV_MAX 0 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Oliver Smith <oliver@8.c.9.b.0.7.4.0.1.0.0.2.ip6.arpa>");
|
||||
IP_SET_MODULE_DESC("hash:net,port,net", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_hash:net,port,net");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define HTYPE hash_netportnet
|
||||
#define IP_SET_HASH_WITH_PROTO
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
#define IPSET_NET_COUNT 2
|
||||
|
||||
/* IPv4 variant */
|
||||
|
||||
/* Member elements */
|
||||
struct hash_netportnet4_elem {
|
||||
union {
|
||||
__be32 ip[2];
|
||||
__be64 ipcmp;
|
||||
};
|
||||
__be16 port;
|
||||
union {
|
||||
u8 cidr[2];
|
||||
u16 ccmp;
|
||||
};
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
hash_netportnet4_data_equal(const struct hash_netportnet4_elem *ip1,
|
||||
const struct hash_netportnet4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ipcmp == ip2->ipcmp &&
|
||||
ip1->ccmp == ip2->ccmp &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hash_netportnet4_do_data_match(const struct hash_netportnet4_elem *elem)
|
||||
{
|
||||
return elem->nomatch ? -ENOTEMPTY : 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet4_data_set_flags(struct hash_netportnet4_elem *elem, u32 flags)
|
||||
{
|
||||
elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet4_data_reset_flags(struct hash_netportnet4_elem *elem, u8 *flags)
|
||||
{
|
||||
swap(*flags, elem->nomatch);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet4_data_reset_elem(struct hash_netportnet4_elem *elem,
|
||||
struct hash_netportnet4_elem *orig)
|
||||
{
|
||||
elem->ip[1] = orig->ip[1];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet4_data_netmask(struct hash_netportnet4_elem *elem,
|
||||
u8 cidr, bool inner)
|
||||
{
|
||||
if (inner) {
|
||||
elem->ip[1] &= ip_set_netmask(cidr);
|
||||
elem->cidr[1] = cidr;
|
||||
} else {
|
||||
elem->ip[0] &= ip_set_netmask(cidr);
|
||||
elem->cidr[0] = cidr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netportnet4_data_list(struct sk_buff *skb,
|
||||
const struct hash_netportnet4_elem *data)
|
||||
{
|
||||
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
|
||||
|
||||
if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, data->ip[0]) ||
|
||||
nla_put_ipaddr4(skb, IPSET_ATTR_IP2, data->ip[1]) ||
|
||||
nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
|
||||
(flags &&
|
||||
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet4_data_next(struct hash_netportnet4_elem *next,
|
||||
const struct hash_netportnet4_elem *d)
|
||||
{
|
||||
next->ipcmp = d->ipcmp;
|
||||
next->port = d->port;
|
||||
}
|
||||
|
||||
#define MTYPE hash_netportnet4
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_hash_gen.h"
|
||||
|
||||
static int
|
||||
hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_netportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netportnet4_elem e = {
|
||||
.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
|
||||
.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK),
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.ccmp = (HOST_MASK << (sizeof(e.cidr[0]) * 8)) | HOST_MASK;
|
||||
|
||||
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[0]);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1]);
|
||||
e.ip[0] &= ip_set_netmask(e.cidr[0]);
|
||||
e.ip[1] &= ip_set_netmask(e.cidr[1]);
|
||||
|
||||
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct hash_netportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netportnet4_elem e = { .cidr[0] = HOST_MASK,
|
||||
.cidr[1] = HOST_MASK };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to;
|
||||
u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2;
|
||||
bool with_ports = false;
|
||||
u8 cidr, cidr2;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) ||
|
||||
ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from) ||
|
||||
ip_set_get_extensions(set, tb, &ext);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!cidr || cidr > HOST_MASK)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
e.cidr[0] = cidr;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2]) {
|
||||
cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
if (!cidr || cidr > HOST_MASK)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
e.cidr[1] = cidr;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(e.proto);
|
||||
|
||||
if (e.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || e.proto == IPPROTO_ICMP))
|
||||
e.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_NOMATCH)
|
||||
flags |= (IPSET_FLAG_NOMATCH << 16);
|
||||
}
|
||||
|
||||
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_IP_TO] || with_ports || 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]));
|
||||
ret = adtfn(set, &e, &ext, &ext, flags);
|
||||
return ip_set_enomatch(ret, flags, adt, set) ? -ret :
|
||||
ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip_to = ip;
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
if (unlikely(ip + UINT_MAX == ip_to))
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
}
|
||||
|
||||
port_to = port = ntohs(e.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);
|
||||
}
|
||||
|
||||
ip2_to = ip2_from;
|
||||
if (tb[IPSET_ATTR_IP2_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip2_from > ip2_to)
|
||||
swap(ip2_from, ip2_to);
|
||||
if (unlikely(ip2_from + UINT_MAX == ip2_to))
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = ntohl(h->next.ip[0]);
|
||||
|
||||
while (!after(ip, ip_to)) {
|
||||
e.ip[0] = htonl(ip);
|
||||
ip_last = ip_set_range_to_cidr(ip, ip_to, &cidr);
|
||||
e.cidr[0] = cidr;
|
||||
p = retried && ip == ntohl(h->next.ip[0]) ? ntohs(h->next.port)
|
||||
: port;
|
||||
for (; p <= port_to; p++) {
|
||||
e.port = htons(p);
|
||||
ip2 = (retried && ip == ntohl(h->next.ip[0]) &&
|
||||
p == ntohs(h->next.port)) ? ntohl(h->next.ip[1])
|
||||
: ip2_from;
|
||||
while (!after(ip2, ip2_to)) {
|
||||
e.ip[1] = htonl(ip2);
|
||||
ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
|
||||
&cidr2);
|
||||
e.cidr[1] = cidr2;
|
||||
ret = adtfn(set, &e, &ext, &ext, flags);
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip2 = ip2_last + 1;
|
||||
}
|
||||
}
|
||||
ip = ip_last + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* IPv6 variant */
|
||||
|
||||
struct hash_netportnet6_elem {
|
||||
union nf_inet_addr ip[2];
|
||||
__be16 port;
|
||||
union {
|
||||
u8 cidr[2];
|
||||
u16 ccmp;
|
||||
};
|
||||
u8 nomatch:1;
|
||||
u8 proto;
|
||||
};
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline bool
|
||||
hash_netportnet6_data_equal(const struct hash_netportnet6_elem *ip1,
|
||||
const struct hash_netportnet6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_equal(&ip1->ip[0].in6, &ip2->ip[0].in6) &&
|
||||
ipv6_addr_equal(&ip1->ip[1].in6, &ip2->ip[1].in6) &&
|
||||
ip1->ccmp == ip2->ccmp &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hash_netportnet6_do_data_match(const struct hash_netportnet6_elem *elem)
|
||||
{
|
||||
return elem->nomatch ? -ENOTEMPTY : 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet6_data_set_flags(struct hash_netportnet6_elem *elem, u32 flags)
|
||||
{
|
||||
elem->nomatch = !!((flags >> 16) & IPSET_FLAG_NOMATCH);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet6_data_reset_flags(struct hash_netportnet6_elem *elem, u8 *flags)
|
||||
{
|
||||
swap(*flags, elem->nomatch);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet6_data_reset_elem(struct hash_netportnet6_elem *elem,
|
||||
struct hash_netportnet6_elem *orig)
|
||||
{
|
||||
elem->ip[1] = orig->ip[1];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet6_data_netmask(struct hash_netportnet6_elem *elem,
|
||||
u8 cidr, bool inner)
|
||||
{
|
||||
if (inner) {
|
||||
ip6_netmask(&elem->ip[1], cidr);
|
||||
elem->cidr[1] = cidr;
|
||||
} else {
|
||||
ip6_netmask(&elem->ip[0], cidr);
|
||||
elem->cidr[0] = cidr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netportnet6_data_list(struct sk_buff *skb,
|
||||
const struct hash_netportnet6_elem *data)
|
||||
{
|
||||
u32 flags = data->nomatch ? IPSET_FLAG_NOMATCH : 0;
|
||||
|
||||
if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &data->ip[0].in6) ||
|
||||
nla_put_ipaddr6(skb, IPSET_ATTR_IP2, &data->ip[1].in6) ||
|
||||
nla_put_net16(skb, IPSET_ATTR_PORT, data->port) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR, data->cidr[0]) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_CIDR2, data->cidr[1]) ||
|
||||
nla_put_u8(skb, IPSET_ATTR_PROTO, data->proto) ||
|
||||
(flags &&
|
||||
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS, htonl(flags))))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netportnet6_data_next(struct hash_netportnet4_elem *next,
|
||||
const struct hash_netportnet6_elem *d)
|
||||
{
|
||||
next->port = d->port;
|
||||
}
|
||||
|
||||
#undef MTYPE
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define MTYPE hash_netportnet6
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#define IP_SET_EMIT_CREATE
|
||||
#include "ip_set_hash_gen.h"
|
||||
|
||||
static int
|
||||
hash_netportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct hash_netportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netportnet6_elem e = {
|
||||
.cidr[0] = IP_SET_INIT_CIDR(h->nets[0].cidr[0], HOST_MASK),
|
||||
.cidr[1] = IP_SET_INIT_CIDR(h->nets[0].cidr[1], HOST_MASK),
|
||||
};
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
e.ccmp = (HOST_MASK << (sizeof(u8) * 8)) | HOST_MASK;
|
||||
|
||||
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[0].in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &e.ip[1].in6);
|
||||
ip6_netmask(&e.ip[0], e.cidr[0]);
|
||||
ip6_netmask(&e.ip[1], e.cidr[1]);
|
||||
|
||||
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct hash_netportnet *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netportnet6_elem e = { .cidr[0] = HOST_MASK,
|
||||
.cidr[1] = HOST_MASK };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
u32 port, port_to;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_IP2_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip[0]) ||
|
||||
ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &e.ip[1]) ||
|
||||
ip_set_get_extensions(set, tb, &ext);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
e.cidr[0] = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2])
|
||||
e.cidr[1] = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
|
||||
if (unlikely(!e.cidr[0] || e.cidr[0] > HOST_MASK || !e.cidr[1] ||
|
||||
e.cidr[1] > HOST_MASK))
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
ip6_netmask(&e.ip[0], e.cidr[0]);
|
||||
ip6_netmask(&e.ip[1], e.cidr[1]);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
e.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
e.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(e.proto);
|
||||
|
||||
if (e.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || e.proto == IPPROTO_ICMPV6))
|
||||
e.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_NOMATCH)
|
||||
flags |= (IPSET_FLAG_NOMATCH << 16);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &e, &ext, &ext, flags);
|
||||
return ip_set_enomatch(ret, flags, adt, set) ? -ret :
|
||||
ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
port = ntohs(e.port);
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = ntohs(h->next.port);
|
||||
for (; port <= port_to; port++) {
|
||||
e.port = htons(port);
|
||||
ret = adtfn(set, &e, &ext, &ext, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_netportnet_type __read_mostly = {
|
||||
.name = "hash:net,port,net",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2 |
|
||||
IPSET_TYPE_NOMATCH,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = hash_netportnet_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2_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_CIDR2] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_netportnet_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_netportnet_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_netportnet_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_netportnet_type);
|
||||
}
|
||||
|
||||
module_init(hash_netportnet_init);
|
||||
module_exit(hash_netportnet_fini);
|
|
@ -15,12 +15,13 @@
|
|||
#include <linux/netfilter/ipset/ip_set.h>
|
||||
#include <linux/netfilter/ipset/ip_set_list.h>
|
||||
|
||||
#define REVISION_MIN 0
|
||||
#define REVISION_MAX 1 /* Counters support added */
|
||||
#define IPSET_TYPE_REV_MIN 0
|
||||
/* 1 Counters support added */
|
||||
#define IPSET_TYPE_REV_MAX 2 /* Comments support added */
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
IP_SET_MODULE_DESC("list:set", REVISION_MIN, REVISION_MAX);
|
||||
IP_SET_MODULE_DESC("list:set", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
||||
MODULE_ALIAS("ip_set_list:set");
|
||||
|
||||
/* Member elements */
|
||||
|
@ -28,28 +29,6 @@ struct set_elem {
|
|||
ip_set_id_t id;
|
||||
};
|
||||
|
||||
struct sett_elem {
|
||||
struct {
|
||||
ip_set_id_t id;
|
||||
} __attribute__ ((aligned));
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct setc_elem {
|
||||
struct {
|
||||
ip_set_id_t id;
|
||||
} __attribute__ ((aligned));
|
||||
struct ip_set_counter counter;
|
||||
};
|
||||
|
||||
struct setct_elem {
|
||||
struct {
|
||||
ip_set_id_t id;
|
||||
} __attribute__ ((aligned));
|
||||
struct ip_set_counter counter;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
struct set_adt_elem {
|
||||
ip_set_id_t id;
|
||||
ip_set_id_t refid;
|
||||
|
@ -58,24 +37,14 @@ struct set_adt_elem {
|
|||
|
||||
/* Type structure */
|
||||
struct list_set {
|
||||
size_t dsize; /* element size */
|
||||
size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */
|
||||
u32 size; /* size of set list array */
|
||||
u32 timeout; /* timeout value */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
struct net *net; /* namespace */
|
||||
struct set_elem members[0]; /* the set members */
|
||||
};
|
||||
|
||||
static inline struct set_elem *
|
||||
list_set_elem(const struct list_set *map, u32 id)
|
||||
{
|
||||
return (struct set_elem *)((void *)map->members + id * map->dsize);
|
||||
}
|
||||
|
||||
#define ext_timeout(e, m) \
|
||||
(unsigned long *)((void *)(e) + (m)->offset[IPSET_OFFSET_TIMEOUT])
|
||||
#define ext_counter(e, m) \
|
||||
(struct ip_set_counter *)((void *)(e) + (m)->offset[IPSET_OFFSET_COUNTER])
|
||||
#define list_set_elem(set, map, id) \
|
||||
(struct set_elem *)((void *)(map)->members + (id) * (set)->dsize)
|
||||
|
||||
static int
|
||||
list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
|
||||
|
@ -92,16 +61,16 @@ list_set_ktest(struct ip_set *set, const struct sk_buff *skb,
|
|||
if (opt->cmdflags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)
|
||||
opt->cmdflags &= ~IPSET_FLAG_SKIP_COUNTER_UPDATE;
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
return 0;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
continue;
|
||||
ret = ip_set_test(e->id, skb, par, opt);
|
||||
if (ret > 0) {
|
||||
if (SET_WITH_COUNTER(set))
|
||||
ip_set_update_counter(ext_counter(e, map),
|
||||
ip_set_update_counter(ext_counter(e, set),
|
||||
ext, &opt->ext,
|
||||
cmdflags);
|
||||
return ret;
|
||||
|
@ -121,11 +90,11 @@ list_set_kadd(struct ip_set *set, const struct sk_buff *skb,
|
|||
int ret;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
return 0;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
continue;
|
||||
ret = ip_set_add(e->id, skb, par, opt);
|
||||
if (ret == 0)
|
||||
|
@ -145,11 +114,11 @@ list_set_kdel(struct ip_set *set, const struct sk_buff *skb,
|
|||
int ret;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
return 0;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
continue;
|
||||
ret = ip_set_del(e->id, skb, par, opt);
|
||||
if (ret == 0)
|
||||
|
@ -163,8 +132,7 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map);
|
||||
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
||||
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
|
@ -188,10 +156,10 @@ id_eq(const struct ip_set *set, u32 i, ip_set_id_t id)
|
|||
if (i >= map->size)
|
||||
return 0;
|
||||
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
return !!(e->id == id &&
|
||||
!(SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map))));
|
||||
ip_set_timeout_expired(ext_timeout(e, set))));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -199,28 +167,36 @@ list_set_add(struct ip_set *set, u32 i, struct set_adt_elem *d,
|
|||
const struct ip_set_ext *ext)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
struct set_elem *e = list_set_elem(map, i);
|
||||
struct set_elem *e = list_set_elem(set, map, i);
|
||||
|
||||
if (e->id != IPSET_INVALID_ID) {
|
||||
if (i == map->size - 1)
|
||||
if (i == map->size - 1) {
|
||||
/* Last element replaced: e.g. add new,before,last */
|
||||
ip_set_put_byindex(e->id);
|
||||
else {
|
||||
struct set_elem *x = list_set_elem(map, map->size - 1);
|
||||
ip_set_put_byindex(map->net, e->id);
|
||||
ip_set_ext_destroy(set, e);
|
||||
} else {
|
||||
struct set_elem *x = list_set_elem(set, map,
|
||||
map->size - 1);
|
||||
|
||||
/* Last element pushed off */
|
||||
if (x->id != IPSET_INVALID_ID)
|
||||
ip_set_put_byindex(x->id);
|
||||
memmove(list_set_elem(map, i + 1), e,
|
||||
map->dsize * (map->size - (i + 1)));
|
||||
if (x->id != IPSET_INVALID_ID) {
|
||||
ip_set_put_byindex(map->net, x->id);
|
||||
ip_set_ext_destroy(set, x);
|
||||
}
|
||||
memmove(list_set_elem(set, map, i + 1), e,
|
||||
set->dsize * (map->size - (i + 1)));
|
||||
/* Extensions must be initialized to zero */
|
||||
memset(e, 0, set->dsize);
|
||||
}
|
||||
}
|
||||
|
||||
e->id = d->id;
|
||||
if (SET_WITH_TIMEOUT(set))
|
||||
ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
|
||||
ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
|
||||
if (SET_WITH_COUNTER(set))
|
||||
ip_set_init_counter(ext_counter(e, map), ext);
|
||||
ip_set_init_counter(ext_counter(e, set), ext);
|
||||
if (SET_WITH_COMMENT(set))
|
||||
ip_set_init_comment(ext_comment(e, set), ext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -228,16 +204,17 @@ static int
|
|||
list_set_del(struct ip_set *set, u32 i)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
struct set_elem *e = list_set_elem(map, i);
|
||||
struct set_elem *e = list_set_elem(set, map, i);
|
||||
|
||||
ip_set_put_byindex(e->id);
|
||||
ip_set_put_byindex(map->net, e->id);
|
||||
ip_set_ext_destroy(set, e);
|
||||
|
||||
if (i < map->size - 1)
|
||||
memmove(e, list_set_elem(map, i + 1),
|
||||
map->dsize * (map->size - (i + 1)));
|
||||
memmove(e, list_set_elem(set, map, i + 1),
|
||||
set->dsize * (map->size - (i + 1)));
|
||||
|
||||
/* Last element */
|
||||
e = list_set_elem(map, map->size - 1);
|
||||
e = list_set_elem(set, map, map->size - 1);
|
||||
e->id = IPSET_INVALID_ID;
|
||||
return 0;
|
||||
}
|
||||
|
@ -247,13 +224,16 @@ set_cleanup_entries(struct ip_set *set)
|
|||
{
|
||||
struct list_set *map = set->data;
|
||||
struct set_elem *e;
|
||||
u32 i;
|
||||
u32 i = 0;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
while (i < map->size) {
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id != IPSET_INVALID_ID &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
list_set_del(set, i);
|
||||
/* Check element moved to position i in next loop */
|
||||
else
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,11 +248,11 @@ list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
int ret;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
return 0;
|
||||
else if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
continue;
|
||||
else if (e->id != d->id)
|
||||
continue;
|
||||
|
@ -299,14 +279,14 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
u32 i, ret = 0;
|
||||
|
||||
if (SET_WITH_TIMEOUT(set))
|
||||
set_cleanup_entries(set);
|
||||
|
||||
/* Check already added element */
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
goto insert;
|
||||
else if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
continue;
|
||||
else if (e->id != d->id)
|
||||
continue;
|
||||
|
||||
|
@ -319,18 +299,22 @@ list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
/* Can't re-add */
|
||||
return -IPSET_ERR_EXIST;
|
||||
/* Update extensions */
|
||||
ip_set_ext_destroy(set, e);
|
||||
|
||||
if (SET_WITH_TIMEOUT(set))
|
||||
ip_set_timeout_set(ext_timeout(e, map), ext->timeout);
|
||||
ip_set_timeout_set(ext_timeout(e, set), ext->timeout);
|
||||
if (SET_WITH_COUNTER(set))
|
||||
ip_set_init_counter(ext_counter(e, map), ext);
|
||||
ip_set_init_counter(ext_counter(e, set), ext);
|
||||
if (SET_WITH_COMMENT(set))
|
||||
ip_set_init_comment(ext_comment(e, set), ext);
|
||||
/* Set is already added to the list */
|
||||
ip_set_put_byindex(d->id);
|
||||
ip_set_put_byindex(map->net, d->id);
|
||||
return 0;
|
||||
}
|
||||
insert:
|
||||
ret = -IPSET_ERR_LIST_FULL;
|
||||
for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
ret = d->before != 0 ? -IPSET_ERR_REF_EXIST
|
||||
: list_set_add(set, i, d, ext);
|
||||
|
@ -355,12 +339,12 @@ list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext,
|
|||
u32 i;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
return d->before != 0 ? -IPSET_ERR_REF_EXIST
|
||||
: -IPSET_ERR_EXIST;
|
||||
else if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
continue;
|
||||
else if (e->id != d->id)
|
||||
continue;
|
||||
|
@ -386,7 +370,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
struct list_set *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct set_adt_elem e = { .refid = IPSET_INVALID_ID };
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(map);
|
||||
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
||||
struct ip_set *s;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -403,7 +387,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
ret = ip_set_get_extensions(set, tb, &ext);
|
||||
if (ret)
|
||||
return ret;
|
||||
e.id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
|
||||
e.id = ip_set_get_byname(map->net, nla_data(tb[IPSET_ATTR_NAME]), &s);
|
||||
if (e.id == IPSET_INVALID_ID)
|
||||
return -IPSET_ERR_NAME;
|
||||
/* "Loop detection" */
|
||||
|
@ -423,7 +407,8 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
}
|
||||
|
||||
if (tb[IPSET_ATTR_NAMEREF]) {
|
||||
e.refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
|
||||
e.refid = ip_set_get_byname(map->net,
|
||||
nla_data(tb[IPSET_ATTR_NAMEREF]),
|
||||
&s);
|
||||
if (e.refid == IPSET_INVALID_ID) {
|
||||
ret = -IPSET_ERR_NAMEREF;
|
||||
|
@ -439,9 +424,9 @@ list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
|||
|
||||
finish:
|
||||
if (e.refid != IPSET_INVALID_ID)
|
||||
ip_set_put_byindex(e.refid);
|
||||
ip_set_put_byindex(map->net, e.refid);
|
||||
if (adt != IPSET_ADD || ret)
|
||||
ip_set_put_byindex(e.id);
|
||||
ip_set_put_byindex(map->net, e.id);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
@ -454,9 +439,10 @@ list_set_flush(struct ip_set *set)
|
|||
u32 i;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id != IPSET_INVALID_ID) {
|
||||
ip_set_put_byindex(e->id);
|
||||
ip_set_put_byindex(map->net, e->id);
|
||||
ip_set_ext_destroy(set, e);
|
||||
e->id = IPSET_INVALID_ID;
|
||||
}
|
||||
}
|
||||
|
@ -485,14 +471,11 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
|
|||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
if (nla_put_net32(skb, IPSET_ATTR_SIZE, htonl(map->size)) ||
|
||||
(SET_WITH_TIMEOUT(set) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout))) ||
|
||||
(SET_WITH_COUNTER(set) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_CADT_FLAGS,
|
||||
htonl(IPSET_FLAG_WITH_COUNTERS))) ||
|
||||
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
|
||||
nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->size * map->dsize)))
|
||||
htonl(sizeof(*map) + map->size * set->dsize)))
|
||||
goto nla_put_failure;
|
||||
if (unlikely(ip_set_put_flags(skb, set)))
|
||||
goto nla_put_failure;
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
|
@ -515,11 +498,11 @@ list_set_list(const struct ip_set *set,
|
|||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->size; cb->args[2]++) {
|
||||
i = cb->args[2];
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
goto finish;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
ip_set_timeout_expired(ext_timeout(e, map)))
|
||||
ip_set_timeout_expired(ext_timeout(e, set)))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
|
@ -530,15 +513,9 @@ list_set_list(const struct ip_set *set,
|
|||
goto nla_put_failure;
|
||||
}
|
||||
if (nla_put_string(skb, IPSET_ATTR_NAME,
|
||||
ip_set_name_byindex(e->id)))
|
||||
ip_set_name_byindex(map->net, e->id)))
|
||||
goto nla_put_failure;
|
||||
if (SET_WITH_TIMEOUT(set) &&
|
||||
nla_put_net32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(
|
||||
ext_timeout(e, map)))))
|
||||
goto nla_put_failure;
|
||||
if (SET_WITH_COUNTER(set) &&
|
||||
ip_set_put_counter(skb, ext_counter(e, map)))
|
||||
if (ip_set_put_extensions(skb, set, e, true))
|
||||
goto nla_put_failure;
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
|
@ -550,11 +527,11 @@ list_set_list(const struct ip_set *set,
|
|||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
if (unlikely(i == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
ipset_nest_end(skb, atd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -565,7 +542,7 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)
|
|||
const struct list_set *y = b->data;
|
||||
|
||||
return x->size == y->size &&
|
||||
x->timeout == y->timeout &&
|
||||
a->timeout == b->timeout &&
|
||||
a->extensions == b->extensions;
|
||||
}
|
||||
|
||||
|
@ -594,7 +571,7 @@ list_set_gc(unsigned long ul_set)
|
|||
set_cleanup_entries(set);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
|
@ -606,43 +583,40 @@ list_set_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
|
|||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = gc;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(set->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
/* Create list:set type of sets */
|
||||
|
||||
static struct list_set *
|
||||
init_list_set(struct ip_set *set, u32 size, size_t dsize,
|
||||
unsigned long timeout)
|
||||
static bool
|
||||
init_list_set(struct net *net, struct ip_set *set, u32 size)
|
||||
{
|
||||
struct list_set *map;
|
||||
struct set_elem *e;
|
||||
u32 i;
|
||||
|
||||
map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
|
||||
map = kzalloc(sizeof(*map) + size * set->dsize, GFP_KERNEL);
|
||||
if (!map)
|
||||
return NULL;
|
||||
return false;
|
||||
|
||||
map->size = size;
|
||||
map->dsize = dsize;
|
||||
map->timeout = timeout;
|
||||
map->net = net;
|
||||
set->data = map;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e = list_set_elem(set, map, i);
|
||||
e->id = IPSET_INVALID_ID;
|
||||
}
|
||||
|
||||
return map;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
|
||||
u32 flags)
|
||||
{
|
||||
struct list_set *map;
|
||||
u32 size = IP_SET_LIST_DEFAULT_SIZE, cadt_flags = 0;
|
||||
unsigned long timeout = 0;
|
||||
u32 size = IP_SET_LIST_DEFAULT_SIZE;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
|
@ -654,45 +628,13 @@ list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
|||
if (size < IP_SET_LIST_MIN_SIZE)
|
||||
size = IP_SET_LIST_MIN_SIZE;
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS])
|
||||
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (tb[IPSET_ATTR_TIMEOUT])
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->variant = &set_variant;
|
||||
if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) {
|
||||
set->extensions |= IPSET_EXT_COUNTER;
|
||||
set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
|
||||
if (!init_list_set(net, set, size))
|
||||
return -ENOMEM;
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map = init_list_set(set, size,
|
||||
sizeof(struct setct_elem), timeout);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct setct_elem, timeout);
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct setct_elem, counter);
|
||||
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
list_set_gc_init(set, list_set_gc);
|
||||
} else {
|
||||
map = init_list_set(set, size,
|
||||
sizeof(struct setc_elem), 0);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
map->offset[IPSET_OFFSET_COUNTER] =
|
||||
offsetof(struct setc_elem, counter);
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map = init_list_set(set, size,
|
||||
sizeof(struct sett_elem), timeout);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
set->extensions |= IPSET_EXT_TIMEOUT;
|
||||
map->offset[IPSET_OFFSET_TIMEOUT] =
|
||||
offsetof(struct sett_elem, timeout);
|
||||
list_set_gc_init(set, list_set_gc);
|
||||
} else {
|
||||
map = init_list_set(set, size, sizeof(struct set_elem), 0);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -703,8 +645,8 @@ static struct ip_set_type list_set_type __read_mostly = {
|
|||
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = REVISION_MIN,
|
||||
.revision_max = REVISION_MAX,
|
||||
.revision_min = IPSET_TYPE_REV_MIN,
|
||||
.revision_max = IPSET_TYPE_REV_MAX,
|
||||
.create = list_set_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
|
||||
|
@ -721,6 +663,7 @@ static struct ip_set_type list_set_type __read_mostly = {
|
|||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
||||
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
|
|
@ -52,66 +52,8 @@ module_param(sip_direct_media, int, 0600);
|
|||
MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling "
|
||||
"endpoints only (default 1)");
|
||||
|
||||
unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int protoff,
|
||||
unsigned int dataoff, const char **dptr,
|
||||
unsigned int *datalen) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sip_hook);
|
||||
|
||||
void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, unsigned int protoff,
|
||||
s16 off) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook);
|
||||
|
||||
unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
unsigned int *datalen,
|
||||
struct nf_conntrack_expect *exp,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook);
|
||||
|
||||
unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
unsigned int *datalen,
|
||||
unsigned int sdpoff,
|
||||
enum sdp_header_types type,
|
||||
enum sdp_header_types term,
|
||||
const union nf_inet_addr *addr)
|
||||
__read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook);
|
||||
|
||||
unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
unsigned int *datalen,
|
||||
unsigned int matchoff,
|
||||
unsigned int matchlen,
|
||||
u_int16_t port) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook);
|
||||
|
||||
unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
|
||||
unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
unsigned int *datalen,
|
||||
unsigned int sdpoff,
|
||||
const union nf_inet_addr *addr)
|
||||
__read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook);
|
||||
|
||||
unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, unsigned int protoff,
|
||||
unsigned int dataoff,
|
||||
const char **dptr,
|
||||
unsigned int *datalen,
|
||||
struct nf_conntrack_expect *rtp_exp,
|
||||
struct nf_conntrack_expect *rtcp_exp,
|
||||
unsigned int mediaoff,
|
||||
unsigned int medialen,
|
||||
union nf_inet_addr *rtp_addr)
|
||||
__read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook);
|
||||
const struct nf_nat_sip_hooks *nf_nat_sip_hooks;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_sip_hooks);
|
||||
|
||||
static int string_len(const struct nf_conn *ct, const char *dptr,
|
||||
const char *limit, int *shift)
|
||||
|
@ -914,8 +856,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
|
|||
int direct_rtp = 0, skip_expect = 0, ret = NF_DROP;
|
||||
u_int16_t base_port;
|
||||
__be16 rtp_port, rtcp_port;
|
||||
typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port;
|
||||
typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media;
|
||||
const struct nf_nat_sip_hooks *hooks;
|
||||
|
||||
saddr = NULL;
|
||||
if (sip_direct_media) {
|
||||
|
@ -966,22 +907,23 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
|
|||
#endif
|
||||
skip_expect = 1;
|
||||
} while (!skip_expect);
|
||||
rcu_read_unlock();
|
||||
|
||||
base_port = ntohs(tuple.dst.u.udp.port) & ~1;
|
||||
rtp_port = htons(base_port);
|
||||
rtcp_port = htons(base_port + 1);
|
||||
|
||||
if (direct_rtp) {
|
||||
nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook);
|
||||
if (nf_nat_sdp_port &&
|
||||
!nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
|
||||
hooks = rcu_dereference(nf_nat_sip_hooks);
|
||||
if (hooks &&
|
||||
!hooks->sdp_port(skb, protoff, dataoff, dptr, datalen,
|
||||
mediaoff, medialen, ntohs(rtp_port)))
|
||||
goto err1;
|
||||
}
|
||||
|
||||
if (skip_expect)
|
||||
if (skip_expect) {
|
||||
rcu_read_unlock();
|
||||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
rtp_exp = nf_ct_expect_alloc(ct);
|
||||
if (rtp_exp == NULL)
|
||||
|
@ -995,10 +937,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
|
|||
nf_ct_expect_init(rtcp_exp, class, nf_ct_l3num(ct), saddr, daddr,
|
||||
IPPROTO_UDP, NULL, &rtcp_port);
|
||||
|
||||
nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook);
|
||||
if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp)
|
||||
ret = nf_nat_sdp_media(skb, protoff, dataoff, dptr, datalen,
|
||||
rtp_exp, rtcp_exp,
|
||||
hooks = rcu_dereference(nf_nat_sip_hooks);
|
||||
if (hooks && ct->status & IPS_NAT_MASK && !direct_rtp)
|
||||
ret = hooks->sdp_media(skb, protoff, dataoff, dptr,
|
||||
datalen, rtp_exp, rtcp_exp,
|
||||
mediaoff, medialen, daddr);
|
||||
else {
|
||||
if (nf_ct_expect_related(rtp_exp) == 0) {
|
||||
|
@ -1012,6 +954,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
|
|||
err2:
|
||||
nf_ct_expect_put(rtp_exp);
|
||||
err1:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1051,13 +994,12 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
|
|||
unsigned int caddr_len, maddr_len;
|
||||
unsigned int i;
|
||||
union nf_inet_addr caddr, maddr, rtp_addr;
|
||||
const struct nf_nat_sip_hooks *hooks;
|
||||
unsigned int port;
|
||||
const struct sdp_media_type *t;
|
||||
int ret = NF_ACCEPT;
|
||||
typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr;
|
||||
typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session;
|
||||
|
||||
nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook);
|
||||
hooks = rcu_dereference(nf_nat_sip_hooks);
|
||||
|
||||
/* Find beginning of session description */
|
||||
if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
|
||||
|
@ -1125,10 +1067,11 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
|
|||
}
|
||||
|
||||
/* Update media connection address if present */
|
||||
if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) {
|
||||
ret = nf_nat_sdp_addr(skb, protoff, dataoff,
|
||||
if (maddr_len && hooks && ct->status & IPS_NAT_MASK) {
|
||||
ret = hooks->sdp_addr(skb, protoff, dataoff,
|
||||
dptr, datalen, mediaoff,
|
||||
SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
|
||||
SDP_HDR_CONNECTION,
|
||||
SDP_HDR_MEDIA,
|
||||
&rtp_addr);
|
||||
if (ret != NF_ACCEPT) {
|
||||
nf_ct_helper_log(skb, ct, "cannot mangle SDP");
|
||||
|
@ -1139,10 +1082,11 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff,
|
|||
}
|
||||
|
||||
/* Update session connection and owner addresses */
|
||||
nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook);
|
||||
if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK)
|
||||
ret = nf_nat_sdp_session(skb, protoff, dataoff,
|
||||
dptr, datalen, sdpoff, &rtp_addr);
|
||||
hooks = rcu_dereference(nf_nat_sip_hooks);
|
||||
if (hooks && ct->status & IPS_NAT_MASK)
|
||||
ret = hooks->sdp_session(skb, protoff, dataoff,
|
||||
dptr, datalen, sdpoff,
|
||||
&rtp_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1242,11 +1186,11 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
|
|||
unsigned int matchoff, matchlen;
|
||||
struct nf_conntrack_expect *exp;
|
||||
union nf_inet_addr *saddr, daddr;
|
||||
const struct nf_nat_sip_hooks *hooks;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
unsigned int expires = 0;
|
||||
int ret;
|
||||
typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect;
|
||||
|
||||
/* Expected connections can not register again. */
|
||||
if (ct->status & IPS_EXPECTED)
|
||||
|
@ -1309,9 +1253,9 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,
|
|||
exp->helper = nfct_help(ct)->helper;
|
||||
exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE;
|
||||
|
||||
nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook);
|
||||
if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK)
|
||||
ret = nf_nat_sip_expect(skb, protoff, dataoff, dptr, datalen,
|
||||
hooks = rcu_dereference(nf_nat_sip_hooks);
|
||||
if (hooks && ct->status & IPS_NAT_MASK)
|
||||
ret = hooks->expect(skb, protoff, dataoff, dptr, datalen,
|
||||
exp, matchoff, matchlen);
|
||||
else {
|
||||
if (nf_ct_expect_related(exp) != 0) {
|
||||
|
@ -1515,7 +1459,7 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
|
|||
unsigned int protoff, unsigned int dataoff,
|
||||
const char **dptr, unsigned int *datalen)
|
||||
{
|
||||
typeof(nf_nat_sip_hook) nf_nat_sip;
|
||||
const struct nf_nat_sip_hooks *hooks;
|
||||
int ret;
|
||||
|
||||
if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0)
|
||||
|
@ -1524,8 +1468,8 @@ static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct,
|
|||
ret = process_sip_response(skb, protoff, dataoff, dptr, datalen);
|
||||
|
||||
if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
|
||||
nf_nat_sip = rcu_dereference(nf_nat_sip_hook);
|
||||
if (nf_nat_sip && !nf_nat_sip(skb, protoff, dataoff,
|
||||
hooks = rcu_dereference(nf_nat_sip_hooks);
|
||||
if (hooks && !hooks->msg(skb, protoff, dataoff,
|
||||
dptr, datalen)) {
|
||||
nf_ct_helper_log(skb, ct, "cannot NAT SIP message");
|
||||
ret = NF_DROP;
|
||||
|
@ -1546,7 +1490,6 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
|
|||
s16 diff, tdiff = 0;
|
||||
int ret = NF_ACCEPT;
|
||||
bool term;
|
||||
typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust;
|
||||
|
||||
if (ctinfo != IP_CT_ESTABLISHED &&
|
||||
ctinfo != IP_CT_ESTABLISHED_REPLY)
|
||||
|
@ -1610,9 +1553,11 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff,
|
|||
}
|
||||
|
||||
if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) {
|
||||
nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook);
|
||||
if (nf_nat_sip_seq_adjust)
|
||||
nf_nat_sip_seq_adjust(skb, protoff, tdiff);
|
||||
const struct nf_nat_sip_hooks *hooks;
|
||||
|
||||
hooks = rcu_dereference(nf_nat_sip_hooks);
|
||||
if (hooks)
|
||||
hooks->seq_adjust(skb, protoff, tdiff);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -625,33 +625,26 @@ static struct nf_ct_helper_expectfn sip_nat = {
|
|||
|
||||
static void __exit nf_nat_sip_fini(void)
|
||||
{
|
||||
RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sip_hooks, NULL);
|
||||
|
||||
nf_ct_helper_expectfn_unregister(&sip_nat);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
static const struct nf_nat_sip_hooks sip_hooks = {
|
||||
.msg = nf_nat_sip,
|
||||
.seq_adjust = nf_nat_sip_seq_adjust,
|
||||
.expect = nf_nat_sip_expect,
|
||||
.sdp_addr = nf_nat_sdp_addr,
|
||||
.sdp_port = nf_nat_sdp_port,
|
||||
.sdp_session = nf_nat_sdp_session,
|
||||
.sdp_media = nf_nat_sdp_media,
|
||||
};
|
||||
|
||||
static int __init nf_nat_sip_init(void)
|
||||
{
|
||||
BUG_ON(nf_nat_sip_hook != NULL);
|
||||
BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
|
||||
BUG_ON(nf_nat_sip_expect_hook != NULL);
|
||||
BUG_ON(nf_nat_sdp_addr_hook != NULL);
|
||||
BUG_ON(nf_nat_sdp_port_hook != NULL);
|
||||
BUG_ON(nf_nat_sdp_session_hook != NULL);
|
||||
BUG_ON(nf_nat_sdp_media_hook != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip);
|
||||
RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust);
|
||||
RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session);
|
||||
RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media);
|
||||
BUG_ON(nf_nat_sip_hooks != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_sip_hooks, &sip_hooks);
|
||||
nf_ct_helper_expectfn_register(&sip_nat);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -49,10 +49,8 @@ static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
|
|||
};
|
||||
|
||||
static int
|
||||
ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
|
||||
struct nf_conntrack_l4proto *l4proto,
|
||||
struct net *net,
|
||||
const struct nlattr *attr)
|
||||
ctnl_timeout_parse_policy(void *timeouts, struct nf_conntrack_l4proto *l4proto,
|
||||
struct net *net, const struct nlattr *attr)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
|
@ -64,8 +62,7 @@ ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net,
|
||||
&timeout->data);
|
||||
ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net, timeouts);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -123,7 +120,8 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
|
|||
goto err_proto_put;
|
||||
}
|
||||
|
||||
ret = ctnl_timeout_parse_policy(matching, l4proto, net,
|
||||
ret = ctnl_timeout_parse_policy(&matching->data,
|
||||
l4proto, net,
|
||||
cda[CTA_TIMEOUT_DATA]);
|
||||
return ret;
|
||||
}
|
||||
|
@ -138,7 +136,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
|
|||
goto err_proto_put;
|
||||
}
|
||||
|
||||
ret = ctnl_timeout_parse_policy(timeout, l4proto, net,
|
||||
ret = ctnl_timeout_parse_policy(&timeout->data, l4proto, net,
|
||||
cda[CTA_TIMEOUT_DATA]);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
@ -342,6 +340,147 @@ cttimeout_del_timeout(struct sock *ctnl, struct sk_buff *skb,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
cttimeout_default_set(struct sock *ctnl, struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
__u16 l3num;
|
||||
__u8 l4num;
|
||||
struct nf_conntrack_l4proto *l4proto;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
unsigned int *timeouts;
|
||||
int ret;
|
||||
|
||||
if (!cda[CTA_TIMEOUT_L3PROTO] ||
|
||||
!cda[CTA_TIMEOUT_L4PROTO] ||
|
||||
!cda[CTA_TIMEOUT_DATA])
|
||||
return -EINVAL;
|
||||
|
||||
l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
|
||||
l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
|
||||
l4proto = nf_ct_l4proto_find_get(l3num, l4num);
|
||||
|
||||
/* This protocol is not supported, skip. */
|
||||
if (l4proto->l4proto != l4num) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto err;
|
||||
}
|
||||
|
||||
timeouts = l4proto->get_timeouts(net);
|
||||
|
||||
ret = ctnl_timeout_parse_policy(timeouts, l4proto, net,
|
||||
cda[CTA_TIMEOUT_DATA]);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
nf_ct_l4proto_put(l4proto);
|
||||
return 0;
|
||||
err:
|
||||
nf_ct_l4proto_put(l4proto);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
cttimeout_default_fill_info(struct net *net, struct sk_buff *skb, u32 portid,
|
||||
u32 seq, u32 type, int event,
|
||||
struct nf_conntrack_l4proto *l4proto)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfmsg;
|
||||
unsigned int flags = portid ? NLM_F_MULTI : 0;
|
||||
|
||||
event |= NFNL_SUBSYS_CTNETLINK_TIMEOUT << 8;
|
||||
nlh = nlmsg_put(skb, portid, seq, event, sizeof(*nfmsg), flags);
|
||||
if (nlh == NULL)
|
||||
goto nlmsg_failure;
|
||||
|
||||
nfmsg = nlmsg_data(nlh);
|
||||
nfmsg->nfgen_family = AF_UNSPEC;
|
||||
nfmsg->version = NFNETLINK_V0;
|
||||
nfmsg->res_id = 0;
|
||||
|
||||
if (nla_put_be16(skb, CTA_TIMEOUT_L3PROTO, htons(l4proto->l3proto)) ||
|
||||
nla_put_u8(skb, CTA_TIMEOUT_L4PROTO, l4proto->l4proto))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (likely(l4proto->ctnl_timeout.obj_to_nlattr)) {
|
||||
struct nlattr *nest_parms;
|
||||
unsigned int *timeouts = l4proto->get_timeouts(net);
|
||||
int ret;
|
||||
|
||||
nest_parms = nla_nest_start(skb,
|
||||
CTA_TIMEOUT_DATA | NLA_F_NESTED);
|
||||
if (!nest_parms)
|
||||
goto nla_put_failure;
|
||||
|
||||
ret = l4proto->ctnl_timeout.obj_to_nlattr(skb, timeouts);
|
||||
if (ret < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
nla_nest_end(skb, nest_parms);
|
||||
}
|
||||
|
||||
nlmsg_end(skb, nlh);
|
||||
return skb->len;
|
||||
|
||||
nlmsg_failure:
|
||||
nla_put_failure:
|
||||
nlmsg_cancel(skb, nlh);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int cttimeout_default_get(struct sock *ctnl, struct sk_buff *skb,
|
||||
const struct nlmsghdr *nlh,
|
||||
const struct nlattr * const cda[])
|
||||
{
|
||||
__u16 l3num;
|
||||
__u8 l4num;
|
||||
struct nf_conntrack_l4proto *l4proto;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
struct sk_buff *skb2;
|
||||
int ret, err;
|
||||
|
||||
if (!cda[CTA_TIMEOUT_L3PROTO] || !cda[CTA_TIMEOUT_L4PROTO])
|
||||
return -EINVAL;
|
||||
|
||||
l3num = ntohs(nla_get_be16(cda[CTA_TIMEOUT_L3PROTO]));
|
||||
l4num = nla_get_u8(cda[CTA_TIMEOUT_L4PROTO]);
|
||||
l4proto = nf_ct_l4proto_find_get(l3num, l4num);
|
||||
|
||||
/* This protocol is not supported, skip. */
|
||||
if (l4proto->l4proto != l4num) {
|
||||
err = -EOPNOTSUPP;
|
||||
goto err;
|
||||
}
|
||||
|
||||
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (skb2 == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = cttimeout_default_fill_info(net, skb2, NETLINK_CB(skb).portid,
|
||||
nlh->nlmsg_seq,
|
||||
NFNL_MSG_TYPE(nlh->nlmsg_type),
|
||||
IPCTNL_MSG_TIMEOUT_DEFAULT_SET,
|
||||
l4proto);
|
||||
if (ret <= 0) {
|
||||
kfree_skb(skb2);
|
||||
err = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
ret = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).portid, MSG_DONTWAIT);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
|
||||
/* this avoids a loop in nfnetlink. */
|
||||
return ret == -EAGAIN ? -ENOBUFS : ret;
|
||||
err:
|
||||
nf_ct_l4proto_put(l4proto);
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||
static struct ctnl_timeout *ctnl_timeout_find_get(const char *name)
|
||||
{
|
||||
|
@ -384,6 +523,12 @@ static const struct nfnl_callback cttimeout_cb[IPCTNL_MSG_TIMEOUT_MAX] = {
|
|||
[IPCTNL_MSG_TIMEOUT_DELETE] = { .call = cttimeout_del_timeout,
|
||||
.attr_count = CTA_TIMEOUT_MAX,
|
||||
.policy = cttimeout_nla_policy },
|
||||
[IPCTNL_MSG_TIMEOUT_DEFAULT_SET]= { .call = cttimeout_default_set,
|
||||
.attr_count = CTA_TIMEOUT_MAX,
|
||||
.policy = cttimeout_nla_policy },
|
||||
[IPCTNL_MSG_TIMEOUT_DEFAULT_GET]= { .call = cttimeout_default_get,
|
||||
.attr_count = CTA_TIMEOUT_MAX,
|
||||
.policy = cttimeout_nla_policy },
|
||||
};
|
||||
|
||||
static const struct nfnetlink_subsystem cttimeout_subsys = {
|
||||
|
|
|
@ -319,7 +319,8 @@ nfulnl_set_flags(struct nfulnl_instance *inst, u_int16_t flags)
|
|||
}
|
||||
|
||||
static struct sk_buff *
|
||||
nfulnl_alloc_skb(u32 peer_portid, unsigned int inst_size, unsigned int pkt_size)
|
||||
nfulnl_alloc_skb(struct net *net, u32 peer_portid, unsigned int inst_size,
|
||||
unsigned int pkt_size)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
unsigned int n;
|
||||
|
@ -328,13 +329,13 @@ nfulnl_alloc_skb(u32 peer_portid, unsigned int inst_size, unsigned int pkt_size)
|
|||
* message. WARNING: has to be <= 128k due to slab restrictions */
|
||||
|
||||
n = max(inst_size, pkt_size);
|
||||
skb = nfnetlink_alloc_skb(&init_net, n, peer_portid, GFP_ATOMIC);
|
||||
skb = nfnetlink_alloc_skb(net, n, peer_portid, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
if (n > pkt_size) {
|
||||
/* try to allocate only as much as we need for current
|
||||
* packet */
|
||||
|
||||
skb = nfnetlink_alloc_skb(&init_net, pkt_size,
|
||||
skb = nfnetlink_alloc_skb(net, pkt_size,
|
||||
peer_portid, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
pr_err("nfnetlink_log: can't even alloc %u bytes\n",
|
||||
|
@ -702,8 +703,8 @@ nfulnl_log_packet(struct net *net,
|
|||
}
|
||||
|
||||
if (!inst->skb) {
|
||||
inst->skb = nfulnl_alloc_skb(inst->peer_portid, inst->nlbufsiz,
|
||||
size);
|
||||
inst->skb = nfulnl_alloc_skb(net, inst->peer_portid,
|
||||
inst->nlbufsiz, size);
|
||||
if (!inst->skb)
|
||||
goto alloc_failure;
|
||||
}
|
||||
|
|
|
@ -298,7 +298,7 @@ nfqnl_put_packet_info(struct sk_buff *nlskb, struct sk_buff *packet,
|
|||
}
|
||||
|
||||
static struct sk_buff *
|
||||
nfqnl_build_packet_message(struct nfqnl_instance *queue,
|
||||
nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
||||
struct nf_queue_entry *entry,
|
||||
__be32 **packet_id_ptr)
|
||||
{
|
||||
|
@ -372,7 +372,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue,
|
|||
if (queue->flags & NFQA_CFG_F_CONNTRACK)
|
||||
ct = nfqnl_ct_get(entskb, &size, &ctinfo);
|
||||
|
||||
skb = nfnetlink_alloc_skb(&init_net, size, queue->peer_portid,
|
||||
skb = nfnetlink_alloc_skb(net, size, queue->peer_portid,
|
||||
GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
@ -525,7 +525,7 @@ __nfqnl_enqueue_packet(struct net *net, struct nfqnl_instance *queue,
|
|||
__be32 *packet_id_ptr;
|
||||
int failopen = 0;
|
||||
|
||||
nskb = nfqnl_build_packet_message(queue, entry, &packet_id_ptr);
|
||||
nskb = nfqnl_build_packet_message(net, queue, entry, &packet_id_ptr);
|
||||
if (nskb == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto err_out;
|
||||
|
|
|
@ -43,10 +43,42 @@ optlen(const u_int8_t *opt, unsigned int offset)
|
|||
return opt[offset+1];
|
||||
}
|
||||
|
||||
static u_int32_t tcpmss_reverse_mtu(struct net *net,
|
||||
const struct sk_buff *skb,
|
||||
unsigned int family)
|
||||
{
|
||||
struct flowi fl;
|
||||
const struct nf_afinfo *ai;
|
||||
struct rtable *rt = NULL;
|
||||
u_int32_t mtu = ~0U;
|
||||
|
||||
if (family == PF_INET) {
|
||||
struct flowi4 *fl4 = &fl.u.ip4;
|
||||
memset(fl4, 0, sizeof(*fl4));
|
||||
fl4->daddr = ip_hdr(skb)->saddr;
|
||||
} else {
|
||||
struct flowi6 *fl6 = &fl.u.ip6;
|
||||
|
||||
memset(fl6, 0, sizeof(*fl6));
|
||||
fl6->daddr = ipv6_hdr(skb)->saddr;
|
||||
}
|
||||
rcu_read_lock();
|
||||
ai = nf_get_afinfo(family);
|
||||
if (ai != NULL)
|
||||
ai->route(net, (struct dst_entry **)&rt, &fl, false);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (rt != NULL) {
|
||||
mtu = dst_mtu(&rt->dst);
|
||||
dst_release(&rt->dst);
|
||||
}
|
||||
return mtu;
|
||||
}
|
||||
|
||||
static int
|
||||
tcpmss_mangle_packet(struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
unsigned int in_mtu,
|
||||
unsigned int family,
|
||||
unsigned int tcphoff,
|
||||
unsigned int minlen)
|
||||
{
|
||||
|
@ -76,6 +108,9 @@ tcpmss_mangle_packet(struct sk_buff *skb,
|
|||
return -1;
|
||||
|
||||
if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
|
||||
struct net *net = dev_net(par->in ? par->in : par->out);
|
||||
unsigned int in_mtu = tcpmss_reverse_mtu(net, skb, family);
|
||||
|
||||
if (dst_mtu(skb_dst(skb)) <= minlen) {
|
||||
net_err_ratelimited("unknown or invalid path-MTU (%u)\n",
|
||||
dst_mtu(skb_dst(skb)));
|
||||
|
@ -165,37 +200,6 @@ tcpmss_mangle_packet(struct sk_buff *skb,
|
|||
return TCPOLEN_MSS;
|
||||
}
|
||||
|
||||
static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
|
||||
unsigned int family)
|
||||
{
|
||||
struct flowi fl;
|
||||
const struct nf_afinfo *ai;
|
||||
struct rtable *rt = NULL;
|
||||
u_int32_t mtu = ~0U;
|
||||
|
||||
if (family == PF_INET) {
|
||||
struct flowi4 *fl4 = &fl.u.ip4;
|
||||
memset(fl4, 0, sizeof(*fl4));
|
||||
fl4->daddr = ip_hdr(skb)->saddr;
|
||||
} else {
|
||||
struct flowi6 *fl6 = &fl.u.ip6;
|
||||
|
||||
memset(fl6, 0, sizeof(*fl6));
|
||||
fl6->daddr = ipv6_hdr(skb)->saddr;
|
||||
}
|
||||
rcu_read_lock();
|
||||
ai = nf_get_afinfo(family);
|
||||
if (ai != NULL)
|
||||
ai->route(&init_net, (struct dst_entry **)&rt, &fl, false);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (rt != NULL) {
|
||||
mtu = dst_mtu(&rt->dst);
|
||||
dst_release(&rt->dst);
|
||||
}
|
||||
return mtu;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
|
@ -204,7 +208,7 @@ tcpmss_tg4(struct sk_buff *skb, const struct xt_action_param *par)
|
|||
int ret;
|
||||
|
||||
ret = tcpmss_mangle_packet(skb, par,
|
||||
tcpmss_reverse_mtu(skb, PF_INET),
|
||||
PF_INET,
|
||||
iph->ihl * 4,
|
||||
sizeof(*iph) + sizeof(struct tcphdr));
|
||||
if (ret < 0)
|
||||
|
@ -233,7 +237,7 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)
|
|||
if (tcphoff < 0)
|
||||
return NF_DROP;
|
||||
ret = tcpmss_mangle_packet(skb, par,
|
||||
tcpmss_reverse_mtu(skb, PF_INET6),
|
||||
PF_INET6,
|
||||
tcphoff,
|
||||
sizeof(*ipv6h) + sizeof(struct tcphdr));
|
||||
if (ret < 0)
|
||||
|
|
|
@ -81,7 +81,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
|||
struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
|
||||
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
|
@ -91,7 +91,7 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
|||
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
ip_set_nfnl_put(par->net, info->match_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
|
@ -106,81 +106,10 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par)
|
|||
{
|
||||
struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
ip_set_nfnl_put(par->net, info->match_set.index);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
|
||||
info->add_set.u.compat.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
|
||||
info->del_set.u.compat.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|
||||
info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->add_set);
|
||||
compat_flags(&info->del_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_v0_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
}
|
||||
|
||||
/* Revision 1 match and target */
|
||||
/* Revision 1 match */
|
||||
|
||||
static bool
|
||||
set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
|
@ -202,7 +131,7 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par)
|
|||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
|
||||
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
|
@ -212,7 +141,7 @@ set_match_v1_checkentry(const struct xt_mtchk_param *par)
|
|||
if (info->match_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
ip_set_nfnl_put(par->net, info->match_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
|
@ -224,102 +153,9 @@ set_match_v1_destroy(const struct xt_mtdtor_param *par)
|
|||
{
|
||||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
ip_set_nfnl_put(par->net, info->match_set.index);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_target_v1_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.dim > IPSET_DIM_MAX ||
|
||||
info->del_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_v1_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
}
|
||||
|
||||
/* Revision 2 target */
|
||||
|
||||
static unsigned int
|
||||
set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v2 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, info->flags, info->timeout);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
/* Normalize to fit into jiffies */
|
||||
if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
|
||||
add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
|
||||
add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#define set_target_v2_checkentry set_target_v1_checkentry
|
||||
#define set_target_v2_destroy set_target_v1_destroy
|
||||
|
||||
/* Revision 3 match */
|
||||
|
||||
static bool
|
||||
|
@ -366,6 +202,174 @@ set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
|
|||
#define set_match_v3_checkentry set_match_v1_checkentry
|
||||
#define set_match_v3_destroy set_match_v1_destroy
|
||||
|
||||
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
||||
|
||||
static unsigned int
|
||||
set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
|
||||
info->add_set.u.compat.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
|
||||
info->del_set.u.compat.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|
||||
info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->del_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->add_set);
|
||||
compat_flags(&info->del_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_v0_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->del_set.index);
|
||||
}
|
||||
|
||||
/* Revision 1 target */
|
||||
|
||||
static unsigned int
|
||||
set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_target_v1_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.dim > IPSET_DIM_MAX ||
|
||||
info->del_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->del_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_v1_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(par->net, info->del_set.index);
|
||||
}
|
||||
|
||||
/* Revision 2 target */
|
||||
|
||||
static unsigned int
|
||||
set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v2 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, info->flags, info->timeout);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
/* Normalize to fit into jiffies */
|
||||
if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
|
||||
add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
|
||||
add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#define set_target_v2_checkentry set_target_v1_checkentry
|
||||
#define set_target_v2_destroy set_target_v1_destroy
|
||||
|
||||
static struct xt_match set_matches[] __read_mostly = {
|
||||
{
|
||||
.name = "set",
|
||||
|
|
|
@ -24,11 +24,12 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len,
|
|||
{
|
||||
struct xt_set_info *set = data;
|
||||
ip_set_id_t index;
|
||||
struct net *net = qdisc_dev(tp->q)->nd_net;
|
||||
|
||||
if (data_len != sizeof(*set))
|
||||
return -EINVAL;
|
||||
|
||||
index = ip_set_nfnl_get_byindex(set->index);
|
||||
index = ip_set_nfnl_get_byindex(net, set->index);
|
||||
if (index == IPSET_INVALID_ID)
|
||||
return -ENOENT;
|
||||
|
||||
|
@ -37,7 +38,7 @@ static int em_ipset_change(struct tcf_proto *tp, void *data, int data_len,
|
|||
if (em->data)
|
||||
return 0;
|
||||
|
||||
ip_set_nfnl_put(index);
|
||||
ip_set_nfnl_put(net, index);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -45,7 +46,7 @@ static void em_ipset_destroy(struct tcf_proto *p, struct tcf_ematch *em)
|
|||
{
|
||||
const struct xt_set_info *set = (const void *) em->data;
|
||||
if (set) {
|
||||
ip_set_nfnl_put(set->index);
|
||||
ip_set_nfnl_put(qdisc_dev(p->q)->nd_net, set->index);
|
||||
kfree((void *) em->data);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue