diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2014-09-15 11:36:06 -0400 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2014-09-15 16:20:21 -0400 |
commit | 07034aeae152de52c29f032ca995bf9dafbe24e2 (patch) | |
tree | 294de1cc19c3e8d0a73e0d7493d6e63146c5e01d | |
parent | aef96193fe7b2791c4a3b19fe75426b929769471 (diff) |
netfilter: ipset: hash:mac type added to ipset
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
-rw-r--r-- | net/netfilter/ipset/Kconfig | 9 | ||||
-rw-r--r-- | net/netfilter/ipset/Makefile | 1 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_gen.h | 11 | ||||
-rw-r--r-- | net/netfilter/ipset/ip_set_hash_mac.c | 173 |
4 files changed, 193 insertions, 1 deletions
diff --git a/net/netfilter/ipset/Kconfig b/net/netfilter/ipset/Kconfig index 2f7f5c32c6f9..234a8ec82076 100644 --- a/net/netfilter/ipset/Kconfig +++ b/net/netfilter/ipset/Kconfig | |||
@@ -99,6 +99,15 @@ config IP_SET_HASH_IPPORTNET | |||
99 | 99 | ||
100 | To compile it as a module, choose M here. If unsure, say N. | 100 | To compile it as a module, choose M here. If unsure, say N. |
101 | 101 | ||
102 | config IP_SET_HASH_MAC | ||
103 | tristate "hash:mac set support" | ||
104 | depends on IP_SET | ||
105 | help | ||
106 | This option adds the hash:mac set type support, by which | ||
107 | one can store MAC (ethernet address) elements in a set. | ||
108 | |||
109 | To compile it as a module, choose M here. If unsure, say N. | ||
110 | |||
102 | config IP_SET_HASH_NETPORTNET | 111 | config IP_SET_HASH_NETPORTNET |
103 | tristate "hash:net,port,net set support" | 112 | tristate "hash:net,port,net set support" |
104 | depends on IP_SET | 113 | depends on IP_SET |
diff --git a/net/netfilter/ipset/Makefile b/net/netfilter/ipset/Makefile index 231f10196cb9..3dbd5e958489 100644 --- a/net/netfilter/ipset/Makefile +++ b/net/netfilter/ipset/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_IP_SET_HASH_IPMARK) += ip_set_hash_ipmark.o | |||
18 | obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o | 18 | obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o |
19 | obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o | 19 | obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o |
20 | obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o | 20 | obj-$(CONFIG_IP_SET_HASH_IPPORTNET) += ip_set_hash_ipportnet.o |
21 | obj-$(CONFIG_IP_SET_HASH_MAC) += ip_set_hash_mac.o | ||
21 | obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o | 22 | obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o |
22 | obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o | 23 | obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o |
23 | obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o | 24 | obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o |
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index ac3a268287d9..fee7c64e4dd1 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h | |||
@@ -1054,8 +1054,10 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, | |||
1054 | struct HTYPE *h; | 1054 | struct HTYPE *h; |
1055 | struct htable *t; | 1055 | struct htable *t; |
1056 | 1056 | ||
1057 | #ifndef IP_SET_PROTO_UNDEF | ||
1057 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) | 1058 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
1058 | return -IPSET_ERR_INVALID_FAMILY; | 1059 | return -IPSET_ERR_INVALID_FAMILY; |
1060 | #endif | ||
1059 | 1061 | ||
1060 | #ifdef IP_SET_HASH_WITH_MARKMASK | 1062 | #ifdef IP_SET_HASH_WITH_MARKMASK |
1061 | markmask = 0xffffffff; | 1063 | markmask = 0xffffffff; |
@@ -1137,25 +1139,32 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set, | |||
1137 | rcu_assign_pointer(h->table, t); | 1139 | rcu_assign_pointer(h->table, t); |
1138 | 1140 | ||
1139 | set->data = h; | 1141 | set->data = h; |
1142 | #ifndef IP_SET_PROTO_UNDEF | ||
1140 | if (set->family == NFPROTO_IPV4) { | 1143 | if (set->family == NFPROTO_IPV4) { |
1144 | #endif | ||
1141 | set->variant = &IPSET_TOKEN(HTYPE, 4_variant); | 1145 | set->variant = &IPSET_TOKEN(HTYPE, 4_variant); |
1142 | set->dsize = ip_set_elem_len(set, tb, | 1146 | set->dsize = ip_set_elem_len(set, tb, |
1143 | sizeof(struct IPSET_TOKEN(HTYPE, 4_elem))); | 1147 | sizeof(struct IPSET_TOKEN(HTYPE, 4_elem))); |
1148 | #ifndef IP_SET_PROTO_UNDEF | ||
1144 | } else { | 1149 | } else { |
1145 | set->variant = &IPSET_TOKEN(HTYPE, 6_variant); | 1150 | set->variant = &IPSET_TOKEN(HTYPE, 6_variant); |
1146 | set->dsize = ip_set_elem_len(set, tb, | 1151 | set->dsize = ip_set_elem_len(set, tb, |
1147 | sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); | 1152 | sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); |
1148 | } | 1153 | } |
1154 | #endif | ||
1149 | if (tb[IPSET_ATTR_TIMEOUT]) { | 1155 | if (tb[IPSET_ATTR_TIMEOUT]) { |
1150 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); | 1156 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
1157 | #ifndef IP_SET_PROTO_UNDEF | ||
1151 | if (set->family == NFPROTO_IPV4) | 1158 | if (set->family == NFPROTO_IPV4) |
1159 | #endif | ||
1152 | IPSET_TOKEN(HTYPE, 4_gc_init)(set, | 1160 | IPSET_TOKEN(HTYPE, 4_gc_init)(set, |
1153 | IPSET_TOKEN(HTYPE, 4_gc)); | 1161 | IPSET_TOKEN(HTYPE, 4_gc)); |
1162 | #ifndef IP_SET_PROTO_UNDEF | ||
1154 | else | 1163 | else |
1155 | IPSET_TOKEN(HTYPE, 6_gc_init)(set, | 1164 | IPSET_TOKEN(HTYPE, 6_gc_init)(set, |
1156 | IPSET_TOKEN(HTYPE, 6_gc)); | 1165 | IPSET_TOKEN(HTYPE, 6_gc)); |
1166 | #endif | ||
1157 | } | 1167 | } |
1158 | |||
1159 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", | 1168 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", |
1160 | set->name, jhash_size(t->htable_bits), | 1169 | set->name, jhash_size(t->htable_bits), |
1161 | t->htable_bits, h->maxelem, set->data, t); | 1170 | t->htable_bits, h->maxelem, set->data, t); |
diff --git a/net/netfilter/ipset/ip_set_hash_mac.c b/net/netfilter/ipset/ip_set_hash_mac.c new file mode 100644 index 000000000000..65690b52a4d5 --- /dev/null +++ b/net/netfilter/ipset/ip_set_hash_mac.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* Copyright (C) 2014 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or modify | ||
4 | * it under the terms of the GNU General Public License version 2 as | ||
5 | * published by the Free Software Foundation. | ||
6 | */ | ||
7 | |||
8 | /* Kernel module implementing an IP set type: the hash:mac type */ | ||
9 | |||
10 | #include <linux/jhash.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/etherdevice.h> | ||
13 | #include <linux/skbuff.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/if_ether.h> | ||
16 | #include <net/netlink.h> | ||
17 | |||
18 | #include <linux/netfilter.h> | ||
19 | #include <linux/netfilter/ipset/ip_set.h> | ||
20 | #include <linux/netfilter/ipset/ip_set_hash.h> | ||
21 | |||
22 | #define IPSET_TYPE_REV_MIN 0 | ||
23 | #define IPSET_TYPE_REV_MAX 0 | ||
24 | |||
25 | MODULE_LICENSE("GPL"); | ||
26 | MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); | ||
27 | IP_SET_MODULE_DESC("hash:mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX); | ||
28 | MODULE_ALIAS("ip_set_hash:mac"); | ||
29 | |||
30 | /* Type specific function prefix */ | ||
31 | #define HTYPE hash_mac | ||
32 | |||
33 | /* Member elements */ | ||
34 | struct hash_mac4_elem { | ||
35 | /* Zero valued IP addresses cannot be stored */ | ||
36 | union { | ||
37 | unsigned char ether[ETH_ALEN]; | ||
38 | __be32 foo[2]; | ||
39 | }; | ||
40 | }; | ||
41 | |||
42 | /* Common functions */ | ||
43 | |||
44 | static inline bool | ||
45 | hash_mac4_data_equal(const struct hash_mac4_elem *e1, | ||
46 | const struct hash_mac4_elem *e2, | ||
47 | u32 *multi) | ||
48 | { | ||
49 | return ether_addr_equal(e1->ether, e2->ether); | ||
50 | } | ||
51 | |||
52 | static inline bool | ||
53 | hash_mac4_data_list(struct sk_buff *skb, const struct hash_mac4_elem *e) | ||
54 | { | ||
55 | return nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, e->ether); | ||
56 | } | ||
57 | |||
58 | static inline void | ||
59 | hash_mac4_data_next(struct hash_mac4_elem *next, | ||
60 | const struct hash_mac4_elem *e) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | #define MTYPE hash_mac4 | ||
65 | #define PF 4 | ||
66 | #define HOST_MASK 32 | ||
67 | #define IP_SET_EMIT_CREATE | ||
68 | #define IP_SET_PROTO_UNDEF | ||
69 | #include "ip_set_hash_gen.h" | ||
70 | |||
71 | /* Zero valued element is not supported */ | ||
72 | static const unsigned char invalid_ether[ETH_ALEN] = { 0 }; | ||
73 | |||
74 | static int | ||
75 | hash_mac4_kadt(struct ip_set *set, const struct sk_buff *skb, | ||
76 | const struct xt_action_param *par, | ||
77 | enum ipset_adt adt, struct ip_set_adt_opt *opt) | ||
78 | { | ||
79 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
80 | struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; | ||
81 | struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set); | ||
82 | |||
83 | /* MAC can be src only */ | ||
84 | if (!(opt->flags & IPSET_DIM_ONE_SRC)) | ||
85 | return 0; | ||
86 | |||
87 | if (skb_mac_header(skb) < skb->head || | ||
88 | (skb_mac_header(skb) + ETH_HLEN) > skb->data) | ||
89 | return -EINVAL; | ||
90 | |||
91 | memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN); | ||
92 | if (memcmp(e.ether, invalid_ether, ETH_ALEN) == 0) | ||
93 | return -EINVAL; | ||
94 | return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | hash_mac4_uadt(struct ip_set *set, struct nlattr *tb[], | ||
99 | enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) | ||
100 | { | ||
101 | ipset_adtfn adtfn = set->variant->adt[adt]; | ||
102 | struct hash_mac4_elem e = { { .foo[0] = 0, .foo[1] = 0 } }; | ||
103 | struct ip_set_ext ext = IP_SET_INIT_UEXT(set); | ||
104 | int ret; | ||
105 | |||
106 | if (unlikely(!tb[IPSET_ATTR_ETHER] || | ||
107 | !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || | ||
108 | !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || | ||
109 | !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES) || | ||
110 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) || | ||
111 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) || | ||
112 | !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE))) | ||
113 | return -IPSET_ERR_PROTOCOL; | ||
114 | |||
115 | if (tb[IPSET_ATTR_LINENO]) | ||
116 | *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); | ||
117 | |||
118 | ret = ip_set_get_extensions(set, tb, &ext); | ||
119 | if (ret) | ||
120 | return ret; | ||
121 | memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN); | ||
122 | if (memcmp(e.ether, invalid_ether, ETH_ALEN) == 0) | ||
123 | return -IPSET_ERR_HASH_ELEM; | ||
124 | |||
125 | return adtfn(set, &e, &ext, &ext, flags); | ||
126 | } | ||
127 | |||
128 | static struct ip_set_type hash_mac_type __read_mostly = { | ||
129 | .name = "hash:mac", | ||
130 | .protocol = IPSET_PROTOCOL, | ||
131 | .features = IPSET_TYPE_MAC, | ||
132 | .dimension = IPSET_DIM_ONE, | ||
133 | .family = NFPROTO_UNSPEC, | ||
134 | .revision_min = IPSET_TYPE_REV_MIN, | ||
135 | .revision_max = IPSET_TYPE_REV_MAX, | ||
136 | .create = hash_mac_create, | ||
137 | .create_policy = { | ||
138 | [IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 }, | ||
139 | [IPSET_ATTR_MAXELEM] = { .type = NLA_U32 }, | ||
140 | [IPSET_ATTR_PROBES] = { .type = NLA_U8 }, | ||
141 | [IPSET_ATTR_RESIZE] = { .type = NLA_U8 }, | ||
142 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
143 | [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, | ||
144 | }, | ||
145 | .adt_policy = { | ||
146 | [IPSET_ATTR_ETHER] = { .type = NLA_BINARY, | ||
147 | .len = ETH_ALEN }, | ||
148 | [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, | ||
149 | [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, | ||
150 | [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, | ||
151 | [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, | ||
152 | [IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING }, | ||
153 | [IPSET_ATTR_SKBMARK] = { .type = NLA_U64 }, | ||
154 | [IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 }, | ||
155 | [IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 }, | ||
156 | }, | ||
157 | .me = THIS_MODULE, | ||
158 | }; | ||
159 | |||
160 | static int __init | ||
161 | hash_mac_init(void) | ||
162 | { | ||
163 | return ip_set_type_register(&hash_mac_type); | ||
164 | } | ||
165 | |||
166 | static void __exit | ||
167 | hash_mac_fini(void) | ||
168 | { | ||
169 | ip_set_type_unregister(&hash_mac_type); | ||
170 | } | ||
171 | |||
172 | module_init(hash_mac_init); | ||
173 | module_exit(hash_mac_fini); | ||