Commit 07034aeae152de52c29f032ca995bf9dafbe24e2
1 parent
aef96193fe
netfilter: ipset: hash:mac type added to ipset
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Showing 4 changed files with 193 additions and 1 deletions Side-by-side Diff
net/netfilter/ipset/Kconfig
... | ... | @@ -99,6 +99,15 @@ |
99 | 99 | |
100 | 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 | 111 | config IP_SET_HASH_NETPORTNET |
103 | 112 | tristate "hash:net,port,net set support" |
104 | 113 | depends on IP_SET |
net/netfilter/ipset/Makefile
... | ... | @@ -18,6 +18,7 @@ |
18 | 18 | obj-$(CONFIG_IP_SET_HASH_IPPORT) += ip_set_hash_ipport.o |
19 | 19 | obj-$(CONFIG_IP_SET_HASH_IPPORTIP) += ip_set_hash_ipportip.o |
20 | 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 | 22 | obj-$(CONFIG_IP_SET_HASH_NET) += ip_set_hash_net.o |
22 | 23 | obj-$(CONFIG_IP_SET_HASH_NETPORT) += ip_set_hash_netport.o |
23 | 24 | obj-$(CONFIG_IP_SET_HASH_NETIFACE) += ip_set_hash_netiface.o |
net/netfilter/ipset/ip_set_hash_gen.h
... | ... | @@ -1054,8 +1054,10 @@ |
1054 | 1054 | struct HTYPE *h; |
1055 | 1055 | struct htable *t; |
1056 | 1056 | |
1057 | +#ifndef IP_SET_PROTO_UNDEF | |
1057 | 1058 | if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6)) |
1058 | 1059 | return -IPSET_ERR_INVALID_FAMILY; |
1060 | +#endif | |
1059 | 1061 | |
1060 | 1062 | #ifdef IP_SET_HASH_WITH_MARKMASK |
1061 | 1063 | markmask = 0xffffffff; |
1062 | 1064 | |
1063 | 1065 | |
1064 | 1066 | |
1065 | 1067 | |
1066 | 1068 | |
1067 | 1069 | |
1068 | 1070 | |
1069 | 1071 | |
... | ... | @@ -1137,25 +1139,32 @@ |
1137 | 1139 | rcu_assign_pointer(h->table, t); |
1138 | 1140 | |
1139 | 1141 | set->data = h; |
1142 | +#ifndef IP_SET_PROTO_UNDEF | |
1140 | 1143 | if (set->family == NFPROTO_IPV4) { |
1144 | +#endif | |
1141 | 1145 | set->variant = &IPSET_TOKEN(HTYPE, 4_variant); |
1142 | 1146 | set->dsize = ip_set_elem_len(set, tb, |
1143 | 1147 | sizeof(struct IPSET_TOKEN(HTYPE, 4_elem))); |
1148 | +#ifndef IP_SET_PROTO_UNDEF | |
1144 | 1149 | } else { |
1145 | 1150 | set->variant = &IPSET_TOKEN(HTYPE, 6_variant); |
1146 | 1151 | set->dsize = ip_set_elem_len(set, tb, |
1147 | 1152 | sizeof(struct IPSET_TOKEN(HTYPE, 6_elem))); |
1148 | 1153 | } |
1154 | +#endif | |
1149 | 1155 | if (tb[IPSET_ATTR_TIMEOUT]) { |
1150 | 1156 | set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); |
1157 | +#ifndef IP_SET_PROTO_UNDEF | |
1151 | 1158 | if (set->family == NFPROTO_IPV4) |
1159 | +#endif | |
1152 | 1160 | IPSET_TOKEN(HTYPE, 4_gc_init)(set, |
1153 | 1161 | IPSET_TOKEN(HTYPE, 4_gc)); |
1162 | +#ifndef IP_SET_PROTO_UNDEF | |
1154 | 1163 | else |
1155 | 1164 | IPSET_TOKEN(HTYPE, 6_gc_init)(set, |
1156 | 1165 | IPSET_TOKEN(HTYPE, 6_gc)); |
1166 | +#endif | |
1157 | 1167 | } |
1158 | - | |
1159 | 1168 | pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n", |
1160 | 1169 | set->name, jhash_size(t->htable_bits), |
1161 | 1170 | t->htable_bits, h->maxelem, set->data, t); |
net/netfilter/ipset/ip_set_hash_mac.c
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); |