root/net/netfilter/ipset/ip_set_hash_ipmac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hash_ipmac4_data_equal
  2. hash_ipmac4_data_list
  3. hash_ipmac4_data_next
  4. hash_ipmac4_kadt
  5. hash_ipmac4_uadt
  6. hash_ipmac6_data_equal
  7. hash_ipmac6_data_list
  8. hash_ipmac6_data_next
  9. hash_ipmac6_kadt
  10. hash_ipmac6_uadt
  11. hash_ipmac_init
  12. hash_ipmac_fini

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* Copyright (C) 2016 Tomasz Chilinski <tomasz.chilinski@chilan.com>
   3  */
   4 
   5 /* Kernel module implementing an IP set type: the hash:ip,mac type */
   6 
   7 #include <linux/jhash.h>
   8 #include <linux/module.h>
   9 #include <linux/ip.h>
  10 #include <linux/etherdevice.h>
  11 #include <linux/skbuff.h>
  12 #include <linux/errno.h>
  13 #include <linux/random.h>
  14 #include <linux/if_ether.h>
  15 #include <net/ip.h>
  16 #include <net/ipv6.h>
  17 #include <net/netlink.h>
  18 #include <net/tcp.h>
  19 
  20 #include <linux/netfilter.h>
  21 #include <linux/netfilter/ipset/pfxlen.h>
  22 #include <linux/netfilter/ipset/ip_set.h>
  23 #include <linux/netfilter/ipset/ip_set_hash.h>
  24 
  25 #define IPSET_TYPE_REV_MIN      0
  26 #define IPSET_TYPE_REV_MAX      0
  27 
  28 MODULE_LICENSE("GPL");
  29 MODULE_AUTHOR("Tomasz Chilinski <tomasz.chilinski@chilan.com>");
  30 IP_SET_MODULE_DESC("hash:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
  31 MODULE_ALIAS("ip_set_hash:ip,mac");
  32 
  33 /* Type specific function prefix */
  34 #define HTYPE           hash_ipmac
  35 
  36 /* IPv4 variant */
  37 
  38 /* Member elements */
  39 struct hash_ipmac4_elem {
  40         /* Zero valued IP addresses cannot be stored */
  41         __be32 ip;
  42         union {
  43                 unsigned char ether[ETH_ALEN];
  44                 __be32 foo[2];
  45         };
  46 };
  47 
  48 /* Common functions */
  49 
  50 static inline bool
  51 hash_ipmac4_data_equal(const struct hash_ipmac4_elem *e1,
  52                        const struct hash_ipmac4_elem *e2,
  53                        u32 *multi)
  54 {
  55         return e1->ip == e2->ip && ether_addr_equal(e1->ether, e2->ether);
  56 }
  57 
  58 static bool
  59 hash_ipmac4_data_list(struct sk_buff *skb, const struct hash_ipmac4_elem *e)
  60 {
  61         if (nla_put_ipaddr4(skb, IPSET_ATTR_IP, e->ip) ||
  62             nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, e->ether))
  63                 goto nla_put_failure;
  64         return false;
  65 
  66 nla_put_failure:
  67         return true;
  68 }
  69 
  70 static inline void
  71 hash_ipmac4_data_next(struct hash_ipmac4_elem *next,
  72                       const struct hash_ipmac4_elem *e)
  73 {
  74         next->ip = e->ip;
  75 }
  76 
  77 #define MTYPE           hash_ipmac4
  78 #define PF              4
  79 #define HOST_MASK       32
  80 #define HKEY_DATALEN    sizeof(struct hash_ipmac4_elem)
  81 #include "ip_set_hash_gen.h"
  82 
  83 static int
  84 hash_ipmac4_kadt(struct ip_set *set, const struct sk_buff *skb,
  85                  const struct xt_action_param *par,
  86                  enum ipset_adt adt, struct ip_set_adt_opt *opt)
  87 {
  88         ipset_adtfn adtfn = set->variant->adt[adt];
  89         struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } };
  90         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
  91 
  92         if (skb_mac_header(skb) < skb->head ||
  93             (skb_mac_header(skb) + ETH_HLEN) > skb->data)
  94                 return -EINVAL;
  95 
  96         if (opt->flags & IPSET_DIM_TWO_SRC)
  97                 ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
  98         else
  99                 ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
 100 
 101         if (is_zero_ether_addr(e.ether))
 102                 return -EINVAL;
 103 
 104         ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip);
 105 
 106         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 107 }
 108 
 109 static int
 110 hash_ipmac4_uadt(struct ip_set *set, struct nlattr *tb[],
 111                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 112 {
 113         ipset_adtfn adtfn = set->variant->adt[adt];
 114         struct hash_ipmac4_elem e = { .ip = 0, { .foo[0] = 0, .foo[1] = 0 } };
 115         struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 116         int ret;
 117 
 118         if (unlikely(!tb[IPSET_ATTR_IP] ||
 119                      !tb[IPSET_ATTR_ETHER] ||
 120                      nla_len(tb[IPSET_ATTR_ETHER]) != ETH_ALEN ||
 121                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 122                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
 123                      !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)   ||
 124                      !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
 125                      !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
 126                      !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
 127                 return -IPSET_ERR_PROTOCOL;
 128 
 129         if (tb[IPSET_ATTR_LINENO])
 130                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 131 
 132         ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &e.ip) ||
 133                 ip_set_get_extensions(set, tb, &ext);
 134         if (ret)
 135                 return ret;
 136         memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
 137         if (is_zero_ether_addr(e.ether))
 138                 return -IPSET_ERR_HASH_ELEM;
 139 
 140         return adtfn(set, &e, &ext, &ext, flags);
 141 }
 142 
 143 /* IPv6 variant */
 144 
 145 /* Member elements */
 146 struct hash_ipmac6_elem {
 147         /* Zero valued IP addresses cannot be stored */
 148         union nf_inet_addr ip;
 149         union {
 150                 unsigned char ether[ETH_ALEN];
 151                 __be32 foo[2];
 152         };
 153 };
 154 
 155 /* Common functions */
 156 
 157 static inline bool
 158 hash_ipmac6_data_equal(const struct hash_ipmac6_elem *e1,
 159                        const struct hash_ipmac6_elem *e2,
 160                        u32 *multi)
 161 {
 162         return ipv6_addr_equal(&e1->ip.in6, &e2->ip.in6) &&
 163                 ether_addr_equal(e1->ether, e2->ether);
 164 }
 165 
 166 static bool
 167 hash_ipmac6_data_list(struct sk_buff *skb, const struct hash_ipmac6_elem *e)
 168 {
 169         if (nla_put_ipaddr6(skb, IPSET_ATTR_IP, &e->ip.in6) ||
 170             nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, e->ether))
 171                 goto nla_put_failure;
 172         return false;
 173 
 174 nla_put_failure:
 175         return true;
 176 }
 177 
 178 static inline void
 179 hash_ipmac6_data_next(struct hash_ipmac6_elem *next,
 180                       const struct hash_ipmac6_elem *e)
 181 {
 182 }
 183 
 184 #undef MTYPE
 185 #undef PF
 186 #undef HOST_MASK
 187 #undef HKEY_DATALEN
 188 
 189 #define MTYPE           hash_ipmac6
 190 #define PF              6
 191 #define HOST_MASK       128
 192 #define HKEY_DATALEN    sizeof(struct hash_ipmac6_elem)
 193 #define IP_SET_EMIT_CREATE
 194 #include "ip_set_hash_gen.h"
 195 
 196 static int
 197 hash_ipmac6_kadt(struct ip_set *set, const struct sk_buff *skb,
 198                  const struct xt_action_param *par,
 199                  enum ipset_adt adt, struct ip_set_adt_opt *opt)
 200 {
 201         ipset_adtfn adtfn = set->variant->adt[adt];
 202         struct hash_ipmac6_elem e = {
 203                 { .all = { 0 } },
 204                 { .foo[0] = 0, .foo[1] = 0 }
 205         };
 206         struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
 207 
 208         if (skb_mac_header(skb) < skb->head ||
 209             (skb_mac_header(skb) + ETH_HLEN) > skb->data)
 210                 return -EINVAL;
 211 
 212         if (opt->flags & IPSET_DIM_TWO_SRC)
 213                 ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
 214         else
 215                 ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
 216 
 217         if (is_zero_ether_addr(e.ether))
 218                 return -EINVAL;
 219 
 220         ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &e.ip.in6);
 221 
 222         return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
 223 }
 224 
 225 static int
 226 hash_ipmac6_uadt(struct ip_set *set, struct nlattr *tb[],
 227                  enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
 228 {
 229         ipset_adtfn adtfn = set->variant->adt[adt];
 230         struct hash_ipmac6_elem e = {
 231                 { .all = { 0 } },
 232                 { .foo[0] = 0, .foo[1] = 0 }
 233         };
 234         struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
 235         int ret;
 236 
 237         if (unlikely(!tb[IPSET_ATTR_IP] ||
 238                      !tb[IPSET_ATTR_ETHER] ||
 239                      nla_len(tb[IPSET_ATTR_ETHER]) != ETH_ALEN ||
 240                      !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
 241                      !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) ||
 242                      !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES)   ||
 243                      !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBMARK) ||
 244                      !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBPRIO) ||
 245                      !ip_set_optattr_netorder(tb, IPSET_ATTR_SKBQUEUE)))
 246                 return -IPSET_ERR_PROTOCOL;
 247 
 248         if (tb[IPSET_ATTR_LINENO])
 249                 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
 250 
 251         ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &e.ip) ||
 252                 ip_set_get_extensions(set, tb, &ext);
 253         if (ret)
 254                 return ret;
 255 
 256         memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
 257         if (is_zero_ether_addr(e.ether))
 258                 return -IPSET_ERR_HASH_ELEM;
 259 
 260         return adtfn(set, &e, &ext, &ext, flags);
 261 }
 262 
 263 static struct ip_set_type hash_ipmac_type __read_mostly = {
 264         .name           = "hash:ip,mac",
 265         .protocol       = IPSET_PROTOCOL,
 266         .features       = IPSET_TYPE_IP | IPSET_TYPE_MAC,
 267         .dimension      = IPSET_DIM_TWO,
 268         .family         = NFPROTO_UNSPEC,
 269         .revision_min   = IPSET_TYPE_REV_MIN,
 270         .revision_max   = IPSET_TYPE_REV_MAX,
 271         .create         = hash_ipmac_create,
 272         .create_policy  = {
 273                 [IPSET_ATTR_HASHSIZE]   = { .type = NLA_U32 },
 274                 [IPSET_ATTR_MAXELEM]    = { .type = NLA_U32 },
 275                 [IPSET_ATTR_PROBES]     = { .type = NLA_U8 },
 276                 [IPSET_ATTR_RESIZE]     = { .type = NLA_U8  },
 277                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 278                 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
 279         },
 280         .adt_policy     = {
 281                 [IPSET_ATTR_IP]         = { .type = NLA_NESTED },
 282                 [IPSET_ATTR_ETHER]      = { .type = NLA_BINARY,
 283                                 .len  = ETH_ALEN },
 284                 [IPSET_ATTR_TIMEOUT]    = { .type = NLA_U32 },
 285                 [IPSET_ATTR_LINENO]     = { .type = NLA_U32 },
 286                 [IPSET_ATTR_BYTES]      = { .type = NLA_U64 },
 287                 [IPSET_ATTR_PACKETS]    = { .type = NLA_U64 },
 288                 [IPSET_ATTR_COMMENT]    = { .type = NLA_NUL_STRING },
 289                 [IPSET_ATTR_SKBMARK]    = { .type = NLA_U64 },
 290                 [IPSET_ATTR_SKBPRIO]    = { .type = NLA_U32 },
 291                 [IPSET_ATTR_SKBQUEUE]   = { .type = NLA_U16 },
 292         },
 293         .me             = THIS_MODULE,
 294 };
 295 
 296 static int __init
 297 hash_ipmac_init(void)
 298 {
 299         return ip_set_type_register(&hash_ipmac_type);
 300 }
 301 
 302 static void __exit
 303 hash_ipmac_fini(void)
 304 {
 305         ip_set_type_unregister(&hash_ipmac_type);
 306 }
 307 
 308 module_init(hash_ipmac_init);
 309 module_exit(hash_ipmac_fini);

/* [<][>][^][v][top][bottom][index][help] */