Commit 07034aeae152de52c29f032ca995bf9dafbe24e2

Authored by Jozsef Kadlecsik
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);