mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-07 13:15:12 +02:00
180 lines
4.8 KiB
C
180 lines
4.8 KiB
C
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
|
* Patrick Schaaf <bof@bof.de>
|
|
* Martin Josefsson <gandalf@wlug.westbo.se>
|
|
* Copyright (C) 2003-2008 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
|
|
/* Kernel module implementing an IP set type: the macipmap type */
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/ip.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/errno.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/bitops.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/if_ether.h>
|
|
|
|
#include "ip_set_macipmap.h"
|
|
|
|
static int
|
|
macipmap_utest(struct ip_set *set, const void *data, u_int32_t size)
|
|
{
|
|
const struct ip_set_macipmap *map = set->data;
|
|
const struct ip_set_macip *table = map->members;
|
|
const struct ip_set_req_macipmap *req = data;
|
|
|
|
if (req->ip < map->first_ip || req->ip > map->last_ip)
|
|
return -ERANGE;
|
|
|
|
DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(req->ip));
|
|
if (table[req->ip - map->first_ip].match) {
|
|
return (memcmp(req->ethernet,
|
|
&table[req->ip - map->first_ip].ethernet,
|
|
ETH_ALEN) == 0);
|
|
} else {
|
|
return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
static int
|
|
macipmap_ktest(struct ip_set *set,
|
|
const struct sk_buff *skb,
|
|
const u_int32_t *flags)
|
|
{
|
|
const struct ip_set_macipmap *map = set->data;
|
|
const struct ip_set_macip *table = map->members;
|
|
ip_set_ip_t ip;
|
|
|
|
ip = ipaddr(skb, flags);
|
|
|
|
if (ip < map->first_ip || ip > map->last_ip)
|
|
return 0;
|
|
|
|
DP("set: %s, ip:%u.%u.%u.%u", set->name, HIPQUAD(ip));
|
|
if (table[ip - map->first_ip].match) {
|
|
/* Is mac pointer valid?
|
|
* If so, compare... */
|
|
return (skb_mac_header(skb) >= skb->head
|
|
&& (skb_mac_header(skb) + ETH_HLEN) <= skb->data
|
|
&& (memcmp(eth_hdr(skb)->h_source,
|
|
&table[ip - map->first_ip].ethernet,
|
|
ETH_ALEN) == 0));
|
|
} else {
|
|
return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
|
|
}
|
|
}
|
|
|
|
/* returns 0 on success */
|
|
static inline int
|
|
macipmap_add(struct ip_set *set,
|
|
ip_set_ip_t ip, const unsigned char *ethernet)
|
|
{
|
|
struct ip_set_macipmap *map = set->data;
|
|
struct ip_set_macip *table = map->members;
|
|
|
|
if (ip < map->first_ip || ip > map->last_ip)
|
|
return -ERANGE;
|
|
if (table[ip - map->first_ip].match)
|
|
return -EEXIST;
|
|
|
|
DP("set: %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
|
|
memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
|
|
table[ip - map->first_ip].match = IPSET_MACIP_ISSET;
|
|
return 0;
|
|
}
|
|
|
|
#define KADT_CONDITION \
|
|
if (!(skb_mac_header(skb) >= skb->head \
|
|
&& (skb_mac_header(skb) + ETH_HLEN) <= skb->data))\
|
|
return -EINVAL;
|
|
|
|
UADT(macipmap, add, req->ethernet)
|
|
KADT(macipmap, add, ipaddr, eth_hdr(skb)->h_source)
|
|
|
|
static inline int
|
|
macipmap_del(struct ip_set *set, ip_set_ip_t ip)
|
|
{
|
|
struct ip_set_macipmap *map = set->data;
|
|
struct ip_set_macip *table = map->members;
|
|
|
|
if (ip < map->first_ip || ip > map->last_ip)
|
|
return -ERANGE;
|
|
if (!table[ip - map->first_ip].match)
|
|
return -EEXIST;
|
|
|
|
table[ip - map->first_ip].match = 0;
|
|
DP("set: %s, ip: %u.%u.%u.%u", set->name, HIPQUAD(ip));
|
|
return 0;
|
|
}
|
|
|
|
#undef KADT_CONDITION
|
|
#define KADT_CONDITION
|
|
|
|
UADT(macipmap, del)
|
|
KADT(macipmap, del, ipaddr)
|
|
|
|
static inline int
|
|
__macipmap_create(const struct ip_set_req_macipmap_create *req,
|
|
struct ip_set_macipmap *map)
|
|
{
|
|
if (req->to - req->from > MAX_RANGE) {
|
|
ip_set_printk("range too big, %d elements (max %d)",
|
|
req->to - req->from + 1, MAX_RANGE+1);
|
|
return -ENOEXEC;
|
|
}
|
|
map->flags = req->flags;
|
|
return (req->to - req->from + 1) * sizeof(struct ip_set_macip);
|
|
}
|
|
|
|
BITMAP_CREATE(macipmap)
|
|
BITMAP_DESTROY(macipmap)
|
|
BITMAP_FLUSH(macipmap)
|
|
|
|
static inline void
|
|
__macipmap_list_header(const struct ip_set_macipmap *map,
|
|
struct ip_set_req_macipmap_create *header)
|
|
{
|
|
header->flags = map->flags;
|
|
}
|
|
|
|
BITMAP_LIST_HEADER(macipmap)
|
|
BITMAP_LIST_MEMBERS_SIZE(macipmap, struct ip_set_req_macipmap,
|
|
(map->last_ip - map->first_ip + 1),
|
|
((const struct ip_set_macip *)map->members)[i].match)
|
|
|
|
|
|
static void
|
|
macipmap_list_members(const struct ip_set *set, void *data, char dont_align)
|
|
{
|
|
const struct ip_set_macipmap *map = set->data;
|
|
const struct ip_set_macip *table = map->members;
|
|
uint32_t i, n = 0;
|
|
struct ip_set_req_macipmap *d;
|
|
|
|
if (dont_align) {
|
|
memcpy(data, map->members, map->size);
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < map->last_ip - map->first_ip + 1; i++)
|
|
if (table[i].match) {
|
|
d = data + n * IPSET_ALIGN(sizeof(struct ip_set_req_macipmap));
|
|
d->ip = map->first_ip + i;
|
|
memcpy(d->ethernet, &table[i].ethernet, ETH_ALEN);
|
|
n++;
|
|
}
|
|
}
|
|
|
|
IP_SET_TYPE(macipmap, IPSET_TYPE_IP | IPSET_DATA_SINGLE)
|
|
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
|
MODULE_DESCRIPTION("macipmap type of IP sets");
|
|
|
|
REGISTER_MODULE(macipmap)
|