1/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu> 2 * Patrick Schaaf <bof@bof.de> 3 * Martin Josefsson <gandalf@wlug.westbo.se> 4 * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 11/* Kernel module implementing an IP set type: the bitmap:ip,mac type */ 12 13#include <linux/module.h> 14#include <linux/ip.h> 15#include <linux/etherdevice.h> 16#include <linux/skbuff.h> 17#include <linux/errno.h> 18#include <linux/if_ether.h> 19#include <linux/netlink.h> 20#include <linux/jiffies.h> 21#include <linux/timer.h> 22#include <net/netlink.h> 23 24#include <linux/netfilter/ipset/pfxlen.h> 25#include <linux/netfilter/ipset/ip_set.h> 26#include <linux/netfilter/ipset/ip_set_bitmap.h> 27 28#define REVISION_MIN 0 29#define REVISION_MAX 1 /* Counter support added */ 30 31MODULE_LICENSE("GPL"); 32MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>"); 33IP_SET_MODULE_DESC("bitmap:ip,mac", REVISION_MIN, REVISION_MAX); 34MODULE_ALIAS("ip_set_bitmap:ip,mac"); 35 36#define MTYPE bitmap_ipmac 37#define IP_SET_BITMAP_STORED_TIMEOUT 38 39enum { 40 MAC_UNSET, /* element is set, without MAC */ 41 MAC_FILLED, /* element is set with MAC */ 42}; 43 44/* Type structure */ 45struct bitmap_ipmac { 46 void *members; /* the set members */ 47 void *extensions; /* MAC + data extensions */ 48 u32 first_ip; /* host byte order, included in range */ 49 u32 last_ip; /* host byte order, included in range */ 50 u32 elements; /* number of max elements in the set */ 51 u32 timeout; /* timeout value */ 52 struct timer_list gc; /* garbage collector */ 53 size_t memsize; /* members size */ 54 size_t dsize; /* size of element */ 55 size_t offset[IPSET_OFFSET_MAX]; /* Offsets to extensions */ 56}; 57 58/* ADT structure for generic function args */ 59struct bitmap_ipmac_adt_elem { 60 u16 id; 61 unsigned char *ether; 62}; 63 64struct bitmap_ipmac_elem { 65 unsigned char ether[ETH_ALEN]; 66 unsigned char filled; 67} __attribute__ ((aligned)); 68 69static inline u32 70ip_to_id(const struct bitmap_ipmac *m, u32 ip) 71{ 72 return ip - m->first_ip; 73} 74 75static inline struct bitmap_ipmac_elem * 76get_elem(void *extensions, u16 id, size_t dsize) 77{ 78 return (struct bitmap_ipmac_elem *)(extensions + id * dsize); 79} 80 81/* Common functions */ 82 83static inline int 84bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e, 85 const struct bitmap_ipmac *map) 86{ 87 const struct bitmap_ipmac_elem *elem; 88 89 if (!test_bit(e->id, map->members)) 90 return 0; 91 elem = get_elem(map->extensions, e->id, map->dsize); 92 if (elem->filled == MAC_FILLED) 93 return e->ether == NULL || 94 ether_addr_equal(e->ether, elem->ether); 95 /* Trigger kernel to fill out the ethernet address */ 96 return -EAGAIN; 97} 98 99static inline int 100bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map) 101{ 102 const struct bitmap_ipmac_elem *elem; 103 104 if (!test_bit(id, map->members)) 105 return 0; 106 elem = get_elem(map->extensions, id, map->dsize); 107 /* Timer not started for the incomplete elements */ 108 return elem->filled == MAC_FILLED; 109} 110 111static inline int 112bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem) 113{ 114 return elem->filled == MAC_FILLED; 115} 116 117static inline int 118bitmap_ipmac_add_timeout(unsigned long *timeout, 119 const struct bitmap_ipmac_adt_elem *e, 120 const struct ip_set_ext *ext, 121 struct bitmap_ipmac *map, int mode) 122{ 123 u32 t = ext->timeout; 124 125 if (mode == IPSET_ADD_START_STORED_TIMEOUT) { 126 if (t == map->timeout) 127 /* Timeout was not specified, get stored one */ 128 t = *timeout; 129 ip_set_timeout_set(timeout, t); 130 } else { 131 /* If MAC is unset yet, we store plain timeout value 132 * because the timer is not activated yet 133 * and we can reuse it later when MAC is filled out, 134 * possibly by the kernel */ 135 if (e->ether) 136 ip_set_timeout_set(timeout, t); 137 else 138 *timeout = t; 139 } 140 return 0; 141} 142 143static inline int 144bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e, 145 struct bitmap_ipmac *map, u32 flags) 146{ 147 struct bitmap_ipmac_elem *elem; 148 149 elem = get_elem(map->extensions, e->id, map->dsize); 150 if (test_and_set_bit(e->id, map->members)) { 151 if (elem->filled == MAC_FILLED) { 152 if (e->ether && (flags & IPSET_FLAG_EXIST)) 153 memcpy(elem->ether, e->ether, ETH_ALEN); 154 return IPSET_ADD_FAILED; 155 } else if (!e->ether) 156 /* Already added without ethernet address */ 157 return IPSET_ADD_FAILED; 158 /* Fill the MAC address and trigger the timer activation */ 159 memcpy(elem->ether, e->ether, ETH_ALEN); 160 elem->filled = MAC_FILLED; 161 return IPSET_ADD_START_STORED_TIMEOUT; 162 } else if (e->ether) { 163 /* We can store MAC too */ 164 memcpy(elem->ether, e->ether, ETH_ALEN); 165 elem->filled = MAC_FILLED; 166 return 0; 167 } else { 168 elem->filled = MAC_UNSET; 169 /* MAC is not stored yet, don't start timer */ 170 return IPSET_ADD_STORE_PLAIN_TIMEOUT; 171 } 172} 173 174static inline int 175bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e, 176 struct bitmap_ipmac *map) 177{ 178 return !test_and_clear_bit(e->id, map->members); 179} 180 181static inline unsigned long 182ip_set_timeout_stored(struct bitmap_ipmac *map, u32 id, unsigned long *timeout) 183{ 184 const struct bitmap_ipmac_elem *elem = 185 get_elem(map->extensions, id, map->dsize); 186 187 return elem->filled == MAC_FILLED ? ip_set_timeout_get(timeout) : 188 *timeout; 189} 190 191static inline int 192bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map, 193 u32 id) 194{ 195 const struct bitmap_ipmac_elem *elem = 196 get_elem(map->extensions, id, map->dsize); 197 198 return nla_put_ipaddr4(skb, IPSET_ATTR_IP, 199 htonl(map->first_ip + id)) || 200 (elem->filled == MAC_FILLED && 201 nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether)); 202} 203 204static inline int 205bitmap_ipmac_do_head(struct sk_buff *skb, const struct bitmap_ipmac *map) 206{ 207 return nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) || 208 nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip)); 209} 210 211static int 212bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb, 213 const struct xt_action_param *par, 214 enum ipset_adt adt, struct ip_set_adt_opt *opt) 215{ 216 struct bitmap_ipmac *map = set->data; 217 ipset_adtfn adtfn = set->variant->adt[adt]; 218 struct bitmap_ipmac_adt_elem e = {}; 219 struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, map); 220 u32 ip; 221 222 /* MAC can be src only */ 223 if (!(opt->flags & IPSET_DIM_TWO_SRC)) 224 return 0; 225 226 ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC)); 227 if (ip < map->first_ip || ip > map->last_ip) 228 return -IPSET_ERR_BITMAP_RANGE; 229 230 /* Backward compatibility: we don't check the second flag */ 231 if (skb_mac_header(skb) < skb->head || 232 (skb_mac_header(skb) + ETH_HLEN) > skb->data) 233 return -EINVAL; 234 235 e.id = ip_to_id(map, ip); 236 e.ether = eth_hdr(skb)->h_source; 237 238 return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags); 239} 240 241static int 242bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[], 243 enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) 244{ 245 const struct bitmap_ipmac *map = set->data; 246 ipset_adtfn adtfn = set->variant->adt[adt]; 247 struct bitmap_ipmac_adt_elem e = {}; 248 struct ip_set_ext ext = IP_SET_INIT_UEXT(map); 249 u32 ip; 250 int ret = 0; 251 252 if (unlikely(!tb[IPSET_ATTR_IP] || 253 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 254 !ip_set_optattr_netorder(tb, IPSET_ATTR_PACKETS) || 255 !ip_set_optattr_netorder(tb, IPSET_ATTR_BYTES))) 256 return -IPSET_ERR_PROTOCOL; 257 258 if (tb[IPSET_ATTR_LINENO]) 259 *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); 260 261 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip) || 262 ip_set_get_extensions(set, tb, &ext); 263 if (ret) 264 return ret; 265 266 if (ip < map->first_ip || ip > map->last_ip) 267 return -IPSET_ERR_BITMAP_RANGE; 268 269 e.id = ip_to_id(map, ip); 270 if (tb[IPSET_ATTR_ETHER]) 271 e.ether = nla_data(tb[IPSET_ATTR_ETHER]); 272 else 273 e.ether = NULL; 274 275 ret = adtfn(set, &e, &ext, &ext, flags); 276 277 return ip_set_eexist(ret, flags) ? 0 : ret; 278} 279 280static bool 281bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b) 282{ 283 const struct bitmap_ipmac *x = a->data; 284 const struct bitmap_ipmac *y = b->data; 285 286 return x->first_ip == y->first_ip && 287 x->last_ip == y->last_ip && 288 x->timeout == y->timeout && 289 a->extensions == b->extensions; 290} 291 292/* Plain variant */ 293 294/* Timeout variant */ 295 296struct bitmap_ipmact_elem { 297 struct { 298 unsigned char ether[ETH_ALEN]; 299 unsigned char filled; 300 } __attribute__ ((aligned)); 301 unsigned long timeout; 302}; 303 304/* Plain variant with counter */ 305 306struct bitmap_ipmacc_elem { 307 struct { 308 unsigned char ether[ETH_ALEN]; 309 unsigned char filled; 310 } __attribute__ ((aligned)); 311 struct ip_set_counter counter; 312}; 313 314/* Timeout variant with counter */ 315 316struct bitmap_ipmacct_elem { 317 struct { 318 unsigned char ether[ETH_ALEN]; 319 unsigned char filled; 320 } __attribute__ ((aligned)); 321 unsigned long timeout; 322 struct ip_set_counter counter; 323}; 324 325#include "ip_set_bitmap_gen.h" 326 327/* Create bitmap:ip,mac type of sets */ 328 329static bool 330init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map, 331 u32 first_ip, u32 last_ip, u32 elements) 332{ 333 map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize); 334 if (!map->members) 335 return false; 336 if (map->dsize) { 337 map->extensions = ip_set_alloc(map->dsize * elements); 338 if (!map->extensions) { 339 kfree(map->members); 340 return false; 341 } 342 } 343 map->first_ip = first_ip; 344 map->last_ip = last_ip; 345 map->elements = elements; 346 map->timeout = IPSET_NO_TIMEOUT; 347 348 set->data = map; 349 set->family = NFPROTO_IPV4; 350 351 return true; 352} 353 354static int 355bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[], 356 u32 flags) 357{ 358 u32 first_ip, last_ip, cadt_flags = 0; 359 u64 elements; 360 struct bitmap_ipmac *map; 361 int ret; 362 363 if (unlikely(!tb[IPSET_ATTR_IP] || 364 !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || 365 !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) 366 return -IPSET_ERR_PROTOCOL; 367 368 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip); 369 if (ret) 370 return ret; 371 372 if (tb[IPSET_ATTR_IP_TO]) { 373 ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip); 374 if (ret) 375 return ret; 376 if (first_ip > last_ip) { 377 u32 tmp = first_ip; 378 379 first_ip = last_ip; 380 last_ip = tmp; 381 } 382 } else if (tb[IPSET_ATTR_CIDR]) { 383 u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]); 384 385 if (cidr >= 32) 386 return -IPSET_ERR_INVALID_CIDR; 387 ip_set_mask_from_to(first_ip, last_ip, cidr); 388 } else 389 return -IPSET_ERR_PROTOCOL; 390 391 elements = (u64)last_ip - first_ip + 1; 392 393 if (elements > IPSET_BITMAP_MAX_RANGE + 1) 394 return -IPSET_ERR_BITMAP_RANGE_SIZE; 395 396 map = kzalloc(sizeof(*map), GFP_KERNEL); 397 if (!map) 398 return -ENOMEM; 399 400 map->memsize = bitmap_bytes(0, elements - 1); 401 set->variant = &bitmap_ipmac; 402 if (tb[IPSET_ATTR_CADT_FLAGS]) 403 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); 404 if (cadt_flags & IPSET_FLAG_WITH_COUNTERS) { 405 set->extensions |= IPSET_EXT_COUNTER; 406 if (tb[IPSET_ATTR_TIMEOUT]) { 407 map->dsize = sizeof(struct bitmap_ipmacct_elem); 408 map->offset[IPSET_OFFSET_TIMEOUT] = 409 offsetof(struct bitmap_ipmacct_elem, timeout); 410 map->offset[IPSET_OFFSET_COUNTER] = 411 offsetof(struct bitmap_ipmacct_elem, counter); 412 413 if (!init_map_ipmac(set, map, first_ip, last_ip, 414 elements)) { 415 kfree(map); 416 return -ENOMEM; 417 } 418 map->timeout = ip_set_timeout_uget( 419 tb[IPSET_ATTR_TIMEOUT]); 420 set->extensions |= IPSET_EXT_TIMEOUT; 421 bitmap_ipmac_gc_init(set, bitmap_ipmac_gc); 422 } else { 423 map->dsize = sizeof(struct bitmap_ipmacc_elem); 424 map->offset[IPSET_OFFSET_COUNTER] = 425 offsetof(struct bitmap_ipmacc_elem, counter); 426 427 if (!init_map_ipmac(set, map, first_ip, last_ip, 428 elements)) { 429 kfree(map); 430 return -ENOMEM; 431 } 432 } 433 } else if (tb[IPSET_ATTR_TIMEOUT]) { 434 map->dsize = sizeof(struct bitmap_ipmact_elem); 435 map->offset[IPSET_OFFSET_TIMEOUT] = 436 offsetof(struct bitmap_ipmact_elem, timeout); 437 438 if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { 439 kfree(map); 440 return -ENOMEM; 441 } 442 map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); 443 set->extensions |= IPSET_EXT_TIMEOUT; 444 bitmap_ipmac_gc_init(set, bitmap_ipmac_gc); 445 } else { 446 map->dsize = sizeof(struct bitmap_ipmac_elem); 447 448 if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) { 449 kfree(map); 450 return -ENOMEM; 451 } 452 set->variant = &bitmap_ipmac; 453 } 454 return 0; 455} 456 457static struct ip_set_type bitmap_ipmac_type = { 458 .name = "bitmap:ip,mac", 459 .protocol = IPSET_PROTOCOL, 460 .features = IPSET_TYPE_IP | IPSET_TYPE_MAC, 461 .dimension = IPSET_DIM_TWO, 462 .family = NFPROTO_IPV4, 463 .revision_min = REVISION_MIN, 464 .revision_max = REVISION_MAX, 465 .create = bitmap_ipmac_create, 466 .create_policy = { 467 [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 468 [IPSET_ATTR_IP_TO] = { .type = NLA_NESTED }, 469 [IPSET_ATTR_CIDR] = { .type = NLA_U8 }, 470 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 471 [IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 }, 472 }, 473 .adt_policy = { 474 [IPSET_ATTR_IP] = { .type = NLA_NESTED }, 475 [IPSET_ATTR_ETHER] = { .type = NLA_BINARY, 476 .len = ETH_ALEN }, 477 [IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 }, 478 [IPSET_ATTR_LINENO] = { .type = NLA_U32 }, 479 [IPSET_ATTR_BYTES] = { .type = NLA_U64 }, 480 [IPSET_ATTR_PACKETS] = { .type = NLA_U64 }, 481 }, 482 .me = THIS_MODULE, 483}; 484 485static int __init 486bitmap_ipmac_init(void) 487{ 488 return ip_set_type_register(&bitmap_ipmac_type); 489} 490 491static void __exit 492bitmap_ipmac_fini(void) 493{ 494 ip_set_type_unregister(&bitmap_ipmac_type); 495} 496 497module_init(bitmap_ipmac_init); 498module_exit(bitmap_ipmac_fini); 499