2019-06-04 08:11:33 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2011-02-01 14:35:12 +00:00
|
|
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
|
|
|
* Patrick Schaaf <bof@bof.de>
|
|
|
|
* Martin Josefsson <gandalf@wlug.westbo.se>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Kernel module implementing an IP set type: the bitmap:ip,mac type */
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/ip.h>
|
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
#include <linux/skbuff.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/if_ether.h>
|
|
|
|
#include <linux/netlink.h>
|
|
|
|
#include <linux/jiffies.h>
|
|
|
|
#include <linux/timer.h>
|
|
|
|
#include <net/netlink.h>
|
|
|
|
|
|
|
|
#include <linux/netfilter/ipset/pfxlen.h>
|
|
|
|
#include <linux/netfilter/ipset/ip_set.h>
|
|
|
|
#include <linux/netfilter/ipset/ip_set_bitmap.h>
|
|
|
|
|
2013-04-30 21:02:43 +00:00
|
|
|
#define IPSET_TYPE_REV_MIN 0
|
2013-09-22 18:56:32 +00:00
|
|
|
/* 1 Counter support added */
|
2014-08-28 06:11:28 +00:00
|
|
|
/* 2 Comment support added */
|
|
|
|
#define IPSET_TYPE_REV_MAX 3 /* skbinfo support added */
|
2012-09-21 19:59:32 +00:00
|
|
|
|
2011-02-01 14:35:12 +00:00
|
|
|
MODULE_LICENSE("GPL");
|
2019-06-10 11:00:24 +00:00
|
|
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@netfilter.org>");
|
2013-04-30 21:02:43 +00:00
|
|
|
IP_SET_MODULE_DESC("bitmap:ip,mac", IPSET_TYPE_REV_MIN, IPSET_TYPE_REV_MAX);
|
2011-02-01 14:35:12 +00:00
|
|
|
MODULE_ALIAS("ip_set_bitmap:ip,mac");
|
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
#define MTYPE bitmap_ipmac
|
2015-05-02 17:28:11 +00:00
|
|
|
#define HOST_MASK 32
|
2013-04-27 12:37:01 +00:00
|
|
|
#define IP_SET_BITMAP_STORED_TIMEOUT
|
|
|
|
|
2011-02-01 14:35:12 +00:00
|
|
|
enum {
|
|
|
|
MAC_UNSET, /* element is set, without MAC */
|
2013-04-27 12:37:01 +00:00
|
|
|
MAC_FILLED, /* element is set with MAC */
|
2011-02-01 14:35:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* Type structure */
|
|
|
|
struct bitmap_ipmac {
|
2020-01-19 21:06:49 +00:00
|
|
|
unsigned long *members; /* the set members */
|
2011-02-01 14:35:12 +00:00
|
|
|
u32 first_ip; /* host byte order, included in range */
|
|
|
|
u32 last_ip; /* host byte order, included in range */
|
2013-04-27 12:37:01 +00:00
|
|
|
u32 elements; /* number of max elements in the set */
|
|
|
|
size_t memsize; /* members size */
|
2013-09-06 22:10:07 +00:00
|
|
|
struct timer_list gc; /* garbage collector */
|
2017-10-17 00:29:18 +00:00
|
|
|
struct ip_set *set; /* attached to this ip_set */
|
2020-02-20 13:59:14 +00:00
|
|
|
unsigned char extensions[] /* MAC + data extensions */
|
2015-11-07 10:21:47 +00:00
|
|
|
__aligned(__alignof__(u64));
|
2011-02-01 14:35:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/* ADT structure for generic function args */
|
2013-04-27 12:37:01 +00:00
|
|
|
struct bitmap_ipmac_adt_elem {
|
2015-11-07 10:21:47 +00:00
|
|
|
unsigned char ether[ETH_ALEN] __aligned(2);
|
2013-04-27 12:37:01 +00:00
|
|
|
u16 id;
|
2015-11-07 10:21:47 +00:00
|
|
|
u16 add_mac;
|
2011-02-01 14:35:12 +00:00
|
|
|
};
|
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
struct bitmap_ipmac_elem {
|
2011-02-01 14:35:12 +00:00
|
|
|
unsigned char ether[ETH_ALEN];
|
2013-04-27 12:37:01 +00:00
|
|
|
unsigned char filled;
|
2015-11-07 10:21:47 +00:00
|
|
|
} __aligned(__alignof__(u64));
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static u32
|
2013-04-27 12:37:01 +00:00
|
|
|
ip_to_id(const struct bitmap_ipmac *m, u32 ip)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2013-04-27 12:37:01 +00:00
|
|
|
return ip - m->first_ip;
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
|
2015-11-07 10:21:47 +00:00
|
|
|
#define get_elem(extensions, id, dsize) \
|
|
|
|
(struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
|
|
|
|
|
|
|
|
#define get_const_elem(extensions, id, dsize) \
|
|
|
|
(const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
/* Common functions */
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
|
2013-09-06 22:10:07 +00:00
|
|
|
const struct bitmap_ipmac *map, size_t dsize)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2013-04-27 12:37:01 +00:00
|
|
|
const struct bitmap_ipmac_elem *elem;
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
if (!test_bit(e->id, map->members))
|
|
|
|
return 0;
|
2015-11-07 10:21:47 +00:00
|
|
|
elem = get_const_elem(map->extensions, e->id, dsize);
|
|
|
|
if (e->add_mac && elem->filled == MAC_FILLED)
|
|
|
|
return ether_addr_equal(e->ether, elem->ether);
|
2013-04-27 12:37:01 +00:00
|
|
|
/* Trigger kernel to fill out the ethernet address */
|
|
|
|
return -EAGAIN;
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-09-06 22:10:07 +00:00
|
|
|
bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2013-04-27 12:37:01 +00:00
|
|
|
const struct bitmap_ipmac_elem *elem;
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
if (!test_bit(id, map->members))
|
|
|
|
return 0;
|
2015-11-07 10:21:47 +00:00
|
|
|
elem = get_const_elem(map->extensions, id, dsize);
|
2013-04-27 12:37:01 +00:00
|
|
|
/* Timer not started for the incomplete elements */
|
|
|
|
return elem->filled == MAC_FILLED;
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_is_filled(const struct bitmap_ipmac_elem *elem)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2013-04-27 12:37:01 +00:00
|
|
|
return elem->filled == MAC_FILLED;
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_add_timeout(unsigned long *timeout,
|
|
|
|
const struct bitmap_ipmac_adt_elem *e,
|
2013-09-06 22:10:07 +00:00
|
|
|
const struct ip_set_ext *ext, struct ip_set *set,
|
2013-04-27 12:37:01 +00:00
|
|
|
struct bitmap_ipmac *map, int mode)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2013-04-27 12:37:01 +00:00
|
|
|
u32 t = ext->timeout;
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
if (mode == IPSET_ADD_START_STORED_TIMEOUT) {
|
2013-09-06 22:10:07 +00:00
|
|
|
if (t == set->timeout)
|
2011-02-01 14:35:12 +00:00
|
|
|
/* Timeout was not specified, get stored one */
|
2013-04-27 12:37:01 +00:00
|
|
|
t = *timeout;
|
|
|
|
ip_set_timeout_set(timeout, t);
|
|
|
|
} else {
|
2011-02-01 14:35:12 +00:00
|
|
|
/* If MAC is unset yet, we store plain timeout value
|
|
|
|
* because the timer is not activated yet
|
|
|
|
* and we can reuse it later when MAC is filled out,
|
2015-06-13 17:45:33 +00:00
|
|
|
* possibly by the kernel
|
|
|
|
*/
|
2015-11-07 10:21:47 +00:00
|
|
|
if (e->add_mac)
|
2013-04-27 12:37:01 +00:00
|
|
|
ip_set_timeout_set(timeout, t);
|
|
|
|
else
|
|
|
|
*timeout = t;
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
|
2013-09-06 22:10:07 +00:00
|
|
|
struct bitmap_ipmac *map, u32 flags, size_t dsize)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2013-04-27 12:37:01 +00:00
|
|
|
struct bitmap_ipmac_elem *elem;
|
|
|
|
|
2013-09-06 22:10:07 +00:00
|
|
|
elem = get_elem(map->extensions, e->id, dsize);
|
2015-06-13 12:39:59 +00:00
|
|
|
if (test_bit(e->id, map->members)) {
|
2013-04-27 12:37:01 +00:00
|
|
|
if (elem->filled == MAC_FILLED) {
|
2015-11-07 10:21:47 +00:00
|
|
|
if (e->add_mac &&
|
2015-06-13 12:39:59 +00:00
|
|
|
(flags & IPSET_FLAG_EXIST) &&
|
|
|
|
!ether_addr_equal(e->ether, elem->ether)) {
|
|
|
|
/* memcpy isn't atomic */
|
|
|
|
clear_bit(e->id, map->members);
|
|
|
|
smp_mb__after_atomic();
|
2015-06-13 17:45:33 +00:00
|
|
|
ether_addr_copy(elem->ether, e->ether);
|
2015-06-13 12:39:59 +00:00
|
|
|
}
|
2013-04-27 12:37:01 +00:00
|
|
|
return IPSET_ADD_FAILED;
|
2015-11-07 10:21:47 +00:00
|
|
|
} else if (!e->add_mac)
|
2013-04-27 12:37:01 +00:00
|
|
|
/* Already added without ethernet address */
|
|
|
|
return IPSET_ADD_FAILED;
|
|
|
|
/* Fill the MAC address and trigger the timer activation */
|
2015-06-13 12:39:59 +00:00
|
|
|
clear_bit(e->id, map->members);
|
|
|
|
smp_mb__after_atomic();
|
2015-06-13 17:45:33 +00:00
|
|
|
ether_addr_copy(elem->ether, e->ether);
|
2013-04-27 12:37:01 +00:00
|
|
|
elem->filled = MAC_FILLED;
|
|
|
|
return IPSET_ADD_START_STORED_TIMEOUT;
|
2015-11-07 10:21:47 +00:00
|
|
|
} else if (e->add_mac) {
|
2013-04-27 12:37:01 +00:00
|
|
|
/* We can store MAC too */
|
2015-06-13 17:45:33 +00:00
|
|
|
ether_addr_copy(elem->ether, e->ether);
|
2013-04-27 12:37:01 +00:00
|
|
|
elem->filled = MAC_FILLED;
|
|
|
|
return 0;
|
|
|
|
}
|
2015-06-13 17:45:33 +00:00
|
|
|
elem->filled = MAC_UNSET;
|
|
|
|
/* MAC is not stored yet, don't start timer */
|
|
|
|
return IPSET_ADD_STORE_PLAIN_TIMEOUT;
|
2013-04-27 12:37:01 +00:00
|
|
|
}
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_do_del(const struct bitmap_ipmac_adt_elem *e,
|
|
|
|
struct bitmap_ipmac *map)
|
|
|
|
{
|
|
|
|
return !test_and_clear_bit(e->id, map->members);
|
|
|
|
}
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
|
2013-09-06 22:10:07 +00:00
|
|
|
u32 id, size_t dsize)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2013-04-27 12:37:01 +00:00
|
|
|
const struct bitmap_ipmac_elem *elem =
|
2015-11-07 10:21:47 +00:00
|
|
|
get_const_elem(map->extensions, id, dsize);
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
|
|
|
|
htonl(map->first_ip + id)) ||
|
|
|
|
(elem->filled == MAC_FILLED &&
|
|
|
|
nla_put(skb, IPSET_ATTR_ETHER, ETH_ALEN, elem->ether));
|
|
|
|
}
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2019-10-03 19:56:02 +00:00
|
|
|
static int
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_do_head(struct sk_buff *skb, const struct bitmap_ipmac *map)
|
|
|
|
{
|
|
|
|
return nla_put_ipaddr4(skb, IPSET_ATTR_IP, htonl(map->first_ip)) ||
|
|
|
|
nla_put_ipaddr4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
2011-06-16 16:56:47 +00:00
|
|
|
const struct xt_action_param *par,
|
2013-04-27 12:37:01 +00:00
|
|
|
enum ipset_adt adt, struct ip_set_adt_opt *opt)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
|
|
|
struct bitmap_ipmac *map = set->data;
|
|
|
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
2015-11-07 10:21:47 +00:00
|
|
|
struct bitmap_ipmac_adt_elem e = { .id = 0, .add_mac = 1 };
|
2013-09-06 22:10:07 +00:00
|
|
|
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
|
2013-04-27 12:37:01 +00:00
|
|
|
u32 ip;
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
|
|
|
|
if (ip < map->first_ip || ip > map->last_ip)
|
2011-02-01 14:35:12 +00:00
|
|
|
return -IPSET_ERR_BITMAP_RANGE;
|
|
|
|
|
|
|
|
/* Backward compatibility: we don't check the second flag */
|
|
|
|
if (skb_mac_header(skb) < skb->head ||
|
|
|
|
(skb_mac_header(skb) + ETH_HLEN) > skb->data)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
e.id = ip_to_id(map, ip);
|
2018-08-17 19:09:47 +00:00
|
|
|
|
netfilter: ipset: Copy the right MAC address in bitmap:ip,mac and hash:ip,mac sets
In commit 8cc4ccf58379 ("ipset: Allow matching on destination MAC address
for mac and ipmac sets"), ipset.git commit 1543514c46a7, I added to the
KADT functions for sets matching on MAC addreses the copy of source or
destination MAC address depending on the configured match.
This was done correctly for hash:mac, but for hash:ip,mac and
bitmap:ip,mac, copying and pasting the same code block presents an
obvious problem: in these two set types, the MAC address is the second
dimension, not the first one, and we are actually selecting the MAC
address depending on whether the first dimension (IP address) specifies
source or destination.
Fix this by checking for the IPSET_DIM_TWO_SRC flag in option flags.
This way, mixing source and destination matches for the two dimensions
of ip,mac set types works as expected. With this setup:
ip netns add A
ip link add veth1 type veth peer name veth2 netns A
ip addr add 192.0.2.1/24 dev veth1
ip -net A addr add 192.0.2.2/24 dev veth2
ip link set veth1 up
ip -net A link set veth2 up
dst=$(ip netns exec A cat /sys/class/net/veth2/address)
ip netns exec A ipset create test_bitmap bitmap:ip,mac range 192.0.0.0/16
ip netns exec A ipset add test_bitmap 192.0.2.1,${dst}
ip netns exec A iptables -A INPUT -m set ! --match-set test_bitmap src,dst -j DROP
ip netns exec A ipset create test_hash hash:ip,mac
ip netns exec A ipset add test_hash 192.0.2.1,${dst}
ip netns exec A iptables -A INPUT -m set ! --match-set test_hash src,dst -j DROP
ipset correctly matches a test packet:
# ping -c1 192.0.2.2 >/dev/null
# echo $?
0
Reported-by: Chen Yi <yiche@redhat.com>
Fixes: 8cc4ccf58379 ("ipset: Allow matching on destination MAC address for mac and ipmac sets")
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
2019-06-24 13:20:12 +00:00
|
|
|
if (opt->flags & IPSET_DIM_TWO_SRC)
|
2018-08-17 19:09:47 +00:00
|
|
|
ether_addr_copy(e.ether, eth_hdr(skb)->h_source);
|
|
|
|
else
|
|
|
|
ether_addr_copy(e.ether, eth_hdr(skb)->h_dest);
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2018-08-17 19:09:48 +00:00
|
|
|
if (is_zero_ether_addr(e.ether))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
|
2011-06-16 16:49:17 +00:00
|
|
|
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
|
|
|
const struct bitmap_ipmac *map = set->data;
|
|
|
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
2014-08-05 11:56:21 +00:00
|
|
|
struct bitmap_ipmac_adt_elem e = { .id = 0 };
|
2013-09-06 22:10:07 +00:00
|
|
|
struct ip_set_ext ext = IP_SET_INIT_UEXT(set);
|
2013-05-01 16:47:32 +00:00
|
|
|
u32 ip = 0;
|
2011-02-01 14:35:12 +00:00
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (tb[IPSET_ATTR_LINENO])
|
|
|
|
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
|
|
|
|
2015-06-12 19:26:43 +00:00
|
|
|
if (unlikely(!tb[IPSET_ATTR_IP]))
|
|
|
|
return -IPSET_ERR_PROTOCOL;
|
|
|
|
|
2015-05-02 17:28:07 +00:00
|
|
|
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = ip_set_get_extensions(set, tb, &ext);
|
2011-02-01 14:35:12 +00:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
if (ip < map->first_ip || ip > map->last_ip)
|
2011-02-01 14:35:12 +00:00
|
|
|
return -IPSET_ERR_BITMAP_RANGE;
|
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
e.id = ip_to_id(map, ip);
|
2015-11-07 10:21:47 +00:00
|
|
|
if (tb[IPSET_ATTR_ETHER]) {
|
2016-03-08 19:29:10 +00:00
|
|
|
if (nla_len(tb[IPSET_ATTR_ETHER]) != ETH_ALEN)
|
|
|
|
return -IPSET_ERR_PROTOCOL;
|
2015-11-07 10:21:47 +00:00
|
|
|
memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
|
|
|
|
e.add_mac = 1;
|
|
|
|
}
|
2013-04-27 12:37:01 +00:00
|
|
|
ret = adtfn(set, &e, &ext, &ext, flags);
|
2011-02-01 14:35:12 +00:00
|
|
|
|
|
|
|
return ip_set_eexist(ret, flags) ? 0 : ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
bitmap_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
|
|
|
|
{
|
|
|
|
const struct bitmap_ipmac *x = a->data;
|
|
|
|
const struct bitmap_ipmac *y = b->data;
|
|
|
|
|
|
|
|
return x->first_ip == y->first_ip &&
|
|
|
|
x->last_ip == y->last_ip &&
|
2013-09-06 22:10:07 +00:00
|
|
|
a->timeout == b->timeout &&
|
2013-04-27 12:37:01 +00:00
|
|
|
a->extensions == b->extensions;
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
/* Plain variant */
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2013-04-27 12:37:01 +00:00
|
|
|
#include "ip_set_bitmap_gen.h"
|
2011-02-01 14:35:12 +00:00
|
|
|
|
|
|
|
/* Create bitmap:ip,mac type of sets */
|
|
|
|
|
|
|
|
static bool
|
|
|
|
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
2013-04-27 12:37:01 +00:00
|
|
|
u32 first_ip, u32 last_ip, u32 elements)
|
2011-02-01 14:35:12 +00:00
|
|
|
{
|
2020-01-19 21:06:49 +00:00
|
|
|
map->members = bitmap_zalloc(elements, GFP_KERNEL | __GFP_NOWARN);
|
2011-02-01 14:35:12 +00:00
|
|
|
if (!map->members)
|
|
|
|
return false;
|
|
|
|
map->first_ip = first_ip;
|
|
|
|
map->last_ip = last_ip;
|
2013-04-27 12:37:01 +00:00
|
|
|
map->elements = elements;
|
2013-09-06 22:10:07 +00:00
|
|
|
set->timeout = IPSET_NO_TIMEOUT;
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2017-10-17 00:29:18 +00:00
|
|
|
map->set = set;
|
2011-02-01 14:35:12 +00:00
|
|
|
set->data = map;
|
2012-02-13 23:24:10 +00:00
|
|
|
set->family = NFPROTO_IPV4;
|
2011-02-01 14:35:12 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2013-09-30 15:07:02 +00:00
|
|
|
bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
|
2011-02-01 14:35:12 +00:00
|
|
|
u32 flags)
|
|
|
|
{
|
2013-09-06 22:43:52 +00:00
|
|
|
u32 first_ip = 0, last_ip = 0;
|
2012-09-04 15:45:59 +00:00
|
|
|
u64 elements;
|
2011-02-01 14:35:12 +00:00
|
|
|
struct bitmap_ipmac *map;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
2013-04-08 21:10:22 +00:00
|
|
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
|
|
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
|
2011-02-01 14:35:12 +00:00
|
|
|
return -IPSET_ERR_PROTOCOL;
|
|
|
|
|
|
|
|
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
if (tb[IPSET_ATTR_IP_TO]) {
|
|
|
|
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
2017-10-30 22:19:25 +00:00
|
|
|
if (first_ip > last_ip)
|
|
|
|
swap(first_ip, last_ip);
|
2011-02-01 14:35:12 +00:00
|
|
|
} else if (tb[IPSET_ATTR_CIDR]) {
|
|
|
|
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
|
|
|
|
2015-05-02 17:28:11 +00:00
|
|
|
if (cidr >= HOST_MASK)
|
2011-02-01 14:35:12 +00:00
|
|
|
return -IPSET_ERR_INVALID_CIDR;
|
2011-06-16 16:55:58 +00:00
|
|
|
ip_set_mask_from_to(first_ip, last_ip, cidr);
|
2015-06-13 17:45:33 +00:00
|
|
|
} else {
|
2011-02-01 14:35:12 +00:00
|
|
|
return -IPSET_ERR_PROTOCOL;
|
2015-06-13 17:45:33 +00:00
|
|
|
}
|
2011-02-01 14:35:12 +00:00
|
|
|
|
2012-09-04 15:45:59 +00:00
|
|
|
elements = (u64)last_ip - first_ip + 1;
|
2011-02-01 14:35:12 +00:00
|
|
|
|
|
|
|
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
|
|
|
|
return -IPSET_ERR_BITMAP_RANGE_SIZE;
|
|
|
|
|
2015-11-07 10:21:47 +00:00
|
|
|
set->dsize = ip_set_elem_len(set, tb,
|
|
|
|
sizeof(struct bitmap_ipmac_elem),
|
|
|
|
__alignof__(struct bitmap_ipmac_elem));
|
|
|
|
map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
|
2011-02-01 14:35:12 +00:00
|
|
|
if (!map)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2020-01-19 21:06:49 +00:00
|
|
|
map->memsize = BITS_TO_LONGS(elements) * sizeof(unsigned long);
|
2013-04-27 12:37:01 +00:00
|
|
|
set->variant = &bitmap_ipmac;
|
2013-09-06 22:43:52 +00:00
|
|
|
if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
|
2020-06-30 00:04:17 +00:00
|
|
|
ip_set_free(map);
|
2013-09-06 22:43:52 +00:00
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
2013-09-06 22:10:07 +00:00
|
|
|
set->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
2013-04-27 12:37:01 +00:00
|
|
|
bitmap_ipmac_gc_init(set, bitmap_ipmac_gc);
|
2011-02-01 14:35:12 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct ip_set_type bitmap_ipmac_type = {
|
|
|
|
.name = "bitmap:ip,mac",
|
|
|
|
.protocol = IPSET_PROTOCOL,
|
|
|
|
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
|
|
|
.dimension = IPSET_DIM_TWO,
|
2012-02-13 23:24:10 +00:00
|
|
|
.family = NFPROTO_IPV4,
|
2013-04-30 21:02:43 +00:00
|
|
|
.revision_min = IPSET_TYPE_REV_MIN,
|
|
|
|
.revision_max = IPSET_TYPE_REV_MAX,
|
2011-02-01 14:35:12 +00:00
|
|
|
.create = bitmap_ipmac_create,
|
|
|
|
.create_policy = {
|
|
|
|
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
|
|
|
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
|
|
|
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
|
|
|
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
2013-04-08 21:10:22 +00:00
|
|
|
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
2011-02-01 14:35:12 +00:00
|
|
|
},
|
|
|
|
.adt_policy = {
|
|
|
|
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
2011-06-16 17:01:26 +00:00
|
|
|
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY,
|
|
|
|
.len = ETH_ALEN },
|
2011-02-01 14:35:12 +00:00
|
|
|
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
|
|
|
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
2013-04-08 21:10:22 +00:00
|
|
|
[IPSET_ATTR_BYTES] = { .type = NLA_U64 },
|
|
|
|
[IPSET_ATTR_PACKETS] = { .type = NLA_U64 },
|
2015-05-02 17:28:16 +00:00
|
|
|
[IPSET_ATTR_COMMENT] = { .type = NLA_NUL_STRING,
|
|
|
|
.len = IPSET_MAX_COMMENT_SIZE },
|
2014-08-28 06:11:28 +00:00
|
|
|
[IPSET_ATTR_SKBMARK] = { .type = NLA_U64 },
|
|
|
|
[IPSET_ATTR_SKBPRIO] = { .type = NLA_U32 },
|
|
|
|
[IPSET_ATTR_SKBQUEUE] = { .type = NLA_U16 },
|
2011-02-01 14:35:12 +00:00
|
|
|
},
|
|
|
|
.me = THIS_MODULE,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int __init
|
|
|
|
bitmap_ipmac_init(void)
|
|
|
|
{
|
|
|
|
return ip_set_type_register(&bitmap_ipmac_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit
|
|
|
|
bitmap_ipmac_fini(void)
|
|
|
|
{
|
2015-06-13 12:39:59 +00:00
|
|
|
rcu_barrier();
|
2011-02-01 14:35:12 +00:00
|
|
|
ip_set_type_unregister(&bitmap_ipmac_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(bitmap_ipmac_init);
|
|
|
|
module_exit(bitmap_ipmac_fini);
|