mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-21 12:04:56 +02:00
Compare commits
61 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
757bf0e993 | ||
![]() |
cea4817a46 | ||
![]() |
2dc79fe008 | ||
![]() |
b60f8f1de2 | ||
![]() |
499c6db75e | ||
![]() |
509953daec | ||
![]() |
c53a86874d | ||
![]() |
309b960012 | ||
![]() |
f4882ca029 | ||
![]() |
8fd3eb56eb | ||
![]() |
94574fb829 | ||
![]() |
32871bad39 | ||
![]() |
0ba44bd461 | ||
![]() |
d4e6e3d155 | ||
![]() |
18043f3e3a | ||
![]() |
ff27f61477 | ||
![]() |
9f59f21614 | ||
![]() |
7a8bfed52c | ||
![]() |
1edc9b943b | ||
![]() |
ebfa77795a | ||
![]() |
4a8aa505c4 | ||
![]() |
4654ee127f | ||
![]() |
a7a77d7146 | ||
![]() |
2a61ca7d4b | ||
![]() |
39de351a91 | ||
![]() |
07bf41a294 | ||
![]() |
07cd29d9ce | ||
![]() |
eb9634aee6 | ||
![]() |
19f241a09c | ||
![]() |
0a29c1d32f | ||
![]() |
93a17fdde0 | ||
![]() |
80444b0d31 | ||
![]() |
f180c0e5c6 | ||
![]() |
ca8ebe4467 | ||
![]() |
e82410735a | ||
![]() |
89e72bb0f4 | ||
![]() |
77b9f2024c | ||
![]() |
0edb572f6e | ||
![]() |
8b1ff64b8b | ||
![]() |
ebb61aa3c9 | ||
![]() |
bd2e6108f3 | ||
![]() |
288492c820 | ||
![]() |
e425c8f277 | ||
![]() |
e3e88827fb | ||
![]() |
6c709fd682 | ||
![]() |
1b53724a61 | ||
![]() |
983b28fe8e | ||
![]() |
3141b2ff86 | ||
![]() |
980a53348f | ||
![]() |
8ea781e257 | ||
![]() |
7e39ee66e0 | ||
![]() |
65e97a66e6 | ||
![]() |
d82b20ead7 | ||
![]() |
c5d4dd0bcf | ||
![]() |
0168f8e8a2 | ||
![]() |
dc22ec7bd1 | ||
![]() |
25bf680ead | ||
![]() |
4d547c2bfc | ||
![]() |
f7c7264a65 | ||
![]() |
0f42828fd6 | ||
![]() |
e2da87230a |
23
INSTALL
23
INSTALL
@@ -4,7 +4,7 @@ Installation instructions for Xtables-addons
|
||||
Xtables-addons uses the well-known configure(autotools) infrastructure
|
||||
in combination with the kernel's Kbuild system.
|
||||
|
||||
$ ./configure --with-xtlibdir=SEE_BELOW
|
||||
$ ./configure
|
||||
$ make
|
||||
# make install
|
||||
|
||||
@@ -14,7 +14,7 @@ Supported configurations for this release
|
||||
|
||||
* iptables >= 1.4.3
|
||||
|
||||
* kernel-source >= 2.6.17, no upper bound known
|
||||
* kernel-source >= 2.6.29
|
||||
with prepared build/output directory
|
||||
- CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK
|
||||
- CONFIG_NF_CONNTRACK_MARK or CONFIG_IP_NF_CONNTRACK_MARK
|
||||
@@ -22,13 +22,7 @@ Supported configurations for this release
|
||||
- CONFIG_CONNECTOR y/m if you wish to receive userspace
|
||||
notifications from pknock through netlink/connector
|
||||
|
||||
Extra notes:
|
||||
|
||||
* in the kernel 2.6.18.x series, >= 2.6.18.5 is required
|
||||
|
||||
* requires that no vendor backports interfere
|
||||
|
||||
For ipset-5 you need:
|
||||
For ipset-6 you need:
|
||||
|
||||
* libmnl
|
||||
|
||||
@@ -60,11 +54,12 @@ Configuring and compiling
|
||||
--with-xtlibdir=
|
||||
|
||||
Specifies the path to where the newly built extensions should
|
||||
be installed when `make install` is run. It uses the same
|
||||
default as the Xtables/iptables package, ${libexecdir}/xtables,
|
||||
but you may need to specify this nevertheless, as autotools
|
||||
defaults to using /usr/local as prefix, and distributions put
|
||||
the files in differing locations.
|
||||
be installed when `make install` is run. The default is to
|
||||
use the same path that Xtables/iptables modules use, as
|
||||
determined by `pkg-config xtables --variable xtlibdir`.
|
||||
Thus, this option normally does NOT need to be specified
|
||||
anymore, even if your distribution put modules in a strange
|
||||
location.
|
||||
|
||||
If you want to enable debugging, use
|
||||
|
||||
|
7
README
7
README
@@ -16,6 +16,13 @@ sanity checks and incorrect endianess handling have been fixed,
|
||||
simplified, and sped up.
|
||||
|
||||
|
||||
Included in this package
|
||||
========================
|
||||
- ipset 4.5
|
||||
- ipset 5.4.1
|
||||
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
|
||||
|
||||
|
||||
Inclusion into a kernel tree
|
||||
============================
|
||||
|
||||
|
61
configure.ac
61
configure.ac
@@ -1,9 +1,9 @@
|
||||
|
||||
AC_INIT([xtables-addons], [1.32])
|
||||
AC_INIT([xtables-addons], [1.35])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_PROG_INSTALL
|
||||
AM_INIT_AUTOMAKE([1.10.2 -Wall foreign subdir-objects])
|
||||
AM_INIT_AUTOMAKE([1.10b -Wall foreign subdir-objects])
|
||||
AC_PROG_CC
|
||||
AM_PROG_CC_C_O
|
||||
AC_DISABLE_STATIC
|
||||
@@ -40,44 +40,41 @@ regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
|
||||
-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
|
||||
-Winline -pipe";
|
||||
|
||||
#
|
||||
# check kernel version
|
||||
#
|
||||
if grep -q "CentOS release 5\." /etc/redhat-release 2>/dev/null ||
|
||||
grep -q "Red Hat Enterprise Linux Server release 5" /etc/redhat-release 2>/dev/null; then
|
||||
# しまった!
|
||||
# Well, just a warning. Maybe the admin updated the kernel.
|
||||
echo "WARNING: This distribution's shipped kernel is not supported.";
|
||||
fi;
|
||||
AC_MSG_CHECKING([kernel version that we will build against])
|
||||
krel="$(make -sC "$kbuilddir" M=. kernelrelease)";
|
||||
kmajor="${krel%%[[^0-9]]*}";
|
||||
kmajor="$(($kmajor+0))";
|
||||
krel="${krel:${#kmajor}}";
|
||||
krel="${krel#.}";
|
||||
kminor="${krel%%[[^0-9]]*}";
|
||||
kminor="$(($kminor+0))";
|
||||
krel="${krel:${#kminor}}";
|
||||
krel="${krel#.}";
|
||||
kmicro="${krel%%[[^0-9]]*}";
|
||||
kmicro="$(($kmicro+0))";
|
||||
krel="${krel:${#kmicro}}";
|
||||
krel="${krel#.}";
|
||||
kstable="${krel%%[[^0-9]]*}";
|
||||
kstable="$(($kstable+0))";
|
||||
if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then
|
||||
if test -n "$kbuilddir"; then
|
||||
AC_MSG_CHECKING([kernel version that we will build against])
|
||||
krel="$(make -sC "$kbuilddir" M=. kernelrelease)";
|
||||
kmajor="${krel%%[[^0-9]]*}";
|
||||
kmajor="$(($kmajor+0))";
|
||||
krel="${krel:${#kmajor}}";
|
||||
krel="${krel#.}";
|
||||
kminor="${krel%%[[^0-9]]*}";
|
||||
kminor="$(($kminor+0))";
|
||||
krel="${krel:${#kminor}}";
|
||||
krel="${krel#.}";
|
||||
kmicro="${krel%%[[^0-9]]*}";
|
||||
kmicro="$(($kmicro+0))";
|
||||
krel="${krel:${#kmicro}}";
|
||||
krel="${krel#.}";
|
||||
kstable="${krel%%[[^0-9]]*}";
|
||||
kstable="$(($kstable+0))";
|
||||
if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then
|
||||
echo "WARNING: Version detection did not succeed. Continue at own luck.";
|
||||
else
|
||||
else
|
||||
echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
|
||||
if test "$kmajor" -gt 2 -o "$kminor" -gt 6 -o "$kmicro" -gt 36; then
|
||||
if test "$kmajor" -gt 2 -o "$kminor" -gt 6 -o "$kmicro" -gt 38; then
|
||||
echo "WARNING: You are trying a newer kernel. Results may vary. :-)";
|
||||
elif test "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -ge 29; then
|
||||
:; # everything ok
|
||||
elif test \( "$kmajor" -lt 2 -o \
|
||||
\( "$kmajor" -eq 2 -a "$kminor" -lt 6 \) -o \
|
||||
\( "$kmajor" -eq 2 -a "$kminor" -eq 0 -a "$kmicro" -lt 17 \) -o \
|
||||
\( "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -eq 18 -a \
|
||||
"$kstable" -lt 5 \) \); then
|
||||
echo "ERROR: That kernel version is not supported. Please see INSTALL for minimum configuration.";
|
||||
echo "ERROR: That kernel version is not supported at all. Please see INSTALL for minimum configuration.";
|
||||
exit 1;
|
||||
else
|
||||
echo "WARNING: That kernel version has been recently deprecated for use with Xtables-addons). Compilation may fail.";
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
|
||||
@@ -87,6 +84,6 @@ AC_SUBST([kbuilddir])
|
||||
AC_SUBST([xtlibdir])
|
||||
AC_CONFIG_FILES([Makefile Makefile.iptrules Makefile.mans geoip/Makefile
|
||||
extensions/Makefile extensions/ACCOUNT/Makefile
|
||||
extensions/ipset-4/Makefile extensions/ipset-5/Makefile
|
||||
extensions/ipset-4/Makefile extensions/ipset-6/Makefile
|
||||
extensions/pknock/Makefile])
|
||||
AC_OUTPUT
|
||||
|
@@ -3,6 +3,53 @@ HEAD
|
||||
====
|
||||
|
||||
|
||||
v1.35 (2011-04-11)
|
||||
==================
|
||||
Enhancements:
|
||||
- update to ipset 6.3
|
||||
* allow "new" as a commad alias to "create"
|
||||
* resolving IP addresses did not work at listing/saving sets, fixed
|
||||
* check ICMP and ICMPv6 with the set match and target in the testsuite
|
||||
* avoid possible syntax clashing at saving hostnames
|
||||
* fix linking with CONFIG_IPV6=n
|
||||
* sctp, udplite support for the hash:*port* types
|
||||
- ipset-genl: handle EAGAIN return value emitted from autoloader
|
||||
- ipset-genl: resolve nfgenmsg remains and fix spurious protocol abort
|
||||
|
||||
|
||||
v1.34 (2011-04-07)
|
||||
==================
|
||||
Fixes:
|
||||
- xt_pknock: avoid crash when hash TFM could not be allocated
|
||||
- xt_pknock: avoid inversion of rule lookup that led to warnings
|
||||
- xt_DNETMAP: add missing module alias
|
||||
- xt_DNETMAP: support for kernels below 2.6.34
|
||||
Changes:
|
||||
- Linux kernel versions below 2.6.29 are no longer officially
|
||||
supported, and will not be part of compilation testing.
|
||||
Expect that compat code will be removed shortly.
|
||||
|
||||
|
||||
v1.33 (2011-02-02)
|
||||
==================
|
||||
Fixes:
|
||||
- build: restore functionality of `configure --without-kbuild`
|
||||
- build: fix objdir builds for ipset-5 (xt-a specific)
|
||||
- build: fix missing inclusion of dependency rules
|
||||
- xt_LOGMARK: fix detection of untracked connection for Linux >= 2.6.36
|
||||
Enhancements:
|
||||
- IPv6 support for xt_geoip
|
||||
- Update to ipset 5.3
|
||||
* make IPv4 and IPv6 address handling similar
|
||||
* show correct line numbers in restore output for parser errors
|
||||
- Update to ipset 5.4
|
||||
* fixed ICMP and ICMPv6 handling
|
||||
* fixed trailing whitespaces and pr_* messages
|
||||
* fixed module loading at create/header commands
|
||||
- build: support for Linux up to 2.6.38
|
||||
- build: preliminary support for iptables 1.4.11
|
||||
|
||||
|
||||
v1.32 (2011-01-04)
|
||||
==================
|
||||
Fixes:
|
||||
|
@@ -1,5 +1,8 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${abs_top_srcdir}/extensions
|
||||
AM_CFLAGS = ${regular_CFLAGS}
|
||||
|
||||
include ../../Makefile.extra
|
||||
|
||||
sbin_PROGRAMS = iptaccount
|
||||
|
1
extensions/ACCOUNT/VERSION.txt
Normal file
1
extensions/ACCOUNT/VERSION.txt
Normal file
@@ -0,0 +1 @@
|
||||
1.16
|
@@ -105,11 +105,11 @@ static void account_tg_print_it(const void *ip,
|
||||
struct in_addr a;
|
||||
|
||||
if (!do_prefix)
|
||||
printf("ACCOUNT ");
|
||||
printf(" ACCOUNT ");
|
||||
|
||||
// Network information
|
||||
if (do_prefix)
|
||||
printf("--");
|
||||
printf(" --");
|
||||
printf("%s ", account_tg_opts[0].name);
|
||||
|
||||
a.s_addr = accountinfo->net_ip;
|
||||
@@ -119,7 +119,7 @@ static void account_tg_print_it(const void *ip,
|
||||
|
||||
printf(" ");
|
||||
if (do_prefix)
|
||||
printf("--");
|
||||
printf(" --");
|
||||
|
||||
printf("%s %s", account_tg_opts[1].name, accountinfo->table_name);
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* See http://www.intra2net.com/opensource/ipt_account *
|
||||
* for further information *
|
||||
* *
|
||||
* Copyright (C) 2004-2008 by Intra2net AG *
|
||||
* Copyright (C) 2004-2011 by Intra2net AG *
|
||||
* opensource@intra2net.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
|
@@ -10,6 +10,7 @@ obj-${build_CHAOS} += xt_CHAOS.o
|
||||
obj-${build_CHECKSUM} += xt_CHECKSUM.o
|
||||
obj-${build_DELUDE} += xt_DELUDE.o
|
||||
obj-${build_DHCPMAC} += xt_DHCPMAC.o
|
||||
obj-${build_DNETMAP} += xt_DNETMAP.o
|
||||
obj-${build_ECHO} += xt_ECHO.o
|
||||
obj-${build_IPMARK} += xt_IPMARK.o
|
||||
obj-${build_LOGMARK} += xt_LOGMARK.o
|
||||
@@ -27,7 +28,7 @@ obj-${build_geoip} += xt_geoip.o
|
||||
obj-${build_iface} += xt_iface.o
|
||||
obj-${build_ipp2p} += xt_ipp2p.o
|
||||
obj-${build_ipset4} += ipset-4/
|
||||
obj-${build_ipset5} += ipset-5/
|
||||
obj-${build_ipset6} += ipset-6/
|
||||
obj-${build_ipv4options} += xt_ipv4options.o
|
||||
obj-${build_length2} += xt_length2.o
|
||||
obj-${build_lscan} += xt_lscan.o
|
||||
|
@@ -5,6 +5,7 @@ obj-${build_CHAOS} += libxt_CHAOS.so
|
||||
obj-${build_CHECKSUM} += libxt_CHECKSUM.so
|
||||
obj-${build_DELUDE} += libxt_DELUDE.so
|
||||
obj-${build_DHCPMAC} += libxt_DHCPMAC.so libxt_dhcpmac.so
|
||||
obj-${build_DNETMAP} += libxt_DNETMAP.so
|
||||
obj-${build_ECHO} += libxt_ECHO.so
|
||||
obj-${build_IPMARK} += libxt_IPMARK.so
|
||||
obj-${build_LOGMARK} += libxt_LOGMARK.so
|
||||
@@ -19,7 +20,7 @@ obj-${build_geoip} += libxt_geoip.so
|
||||
obj-${build_iface} += libxt_iface.so
|
||||
obj-${build_ipp2p} += libxt_ipp2p.so
|
||||
obj-${build_ipset4} += ipset-4/
|
||||
obj-${build_ipset5} += ipset-5/
|
||||
obj-${build_ipset6} += ipset-6/
|
||||
obj-${build_ipv4options} += libxt_ipv4options.so
|
||||
obj-${build_length2} += libxt_length2.so
|
||||
obj-${build_lscan} += libxt_lscan.so
|
||||
|
1
extensions/ipset-4/VERSION.txt
Normal file
1
extensions/ipset-4/VERSION.txt
Normal file
@@ -0,0 +1 @@
|
||||
4.5
|
@@ -1,649 +0,0 @@
|
||||
/* Copyright (C) 2003-2010 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 bitmap:port type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/timer.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_bitmap.h"
|
||||
#include "ip_set_getport.h"
|
||||
#define IP_SET_BITMAP_TIMEOUT
|
||||
#include "ip_set_timeout.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("bitmap:port type of IP sets");
|
||||
MODULE_ALIAS("ip_set_bitmap:port");
|
||||
|
||||
/* Base variant */
|
||||
|
||||
struct bitmap_port {
|
||||
void *members; /* the set members */
|
||||
u16 first_port; /* host byte order, included in range */
|
||||
u16 last_port; /* host byte order, included in range */
|
||||
size_t memsize; /* members size */
|
||||
};
|
||||
|
||||
static inline int
|
||||
bitmap_port_test(const struct bitmap_port *map, u16 id)
|
||||
{
|
||||
return !!test_bit(id, map->members);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_port_add(struct bitmap_port *map, u16 id)
|
||||
{
|
||||
if (test_and_set_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_del(struct bitmap_port *map, u16 id)
|
||||
{
|
||||
if (!test_and_clear_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
u16 port = 0;
|
||||
|
||||
if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &port))
|
||||
return -EINVAL;
|
||||
|
||||
port = ntohs(port);
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
port -= map->first_port;
|
||||
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
return bitmap_port_test(map, port);
|
||||
case IPSET_ADD:
|
||||
return bitmap_port_add(map, port);
|
||||
case IPSET_DEL:
|
||||
return bitmap_port_del(map, port);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct nla_policy bitmap_port_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
bitmap_port_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
u32 port; /* wraparound */
|
||||
u16 id, port_to;
|
||||
int ret = 0;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
bitmap_port_adt_policy))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT])
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
return bitmap_port_test(map, port - map->first_port);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to) {
|
||||
swap(port, port_to);
|
||||
if (port < map->first_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
}
|
||||
} else
|
||||
port_to = port;
|
||||
|
||||
if (port_to > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
id = port - map->first_port;
|
||||
ret = adt == IPSET_ADD ? bitmap_port_add(map, id)
|
||||
: bitmap_port_del(map, id);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_port_destroy(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
|
||||
ip_set_free(map->members);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_port_flush(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
|
||||
memset(map->members, 0, map->memsize);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct bitmap_port *map = set->data;
|
||||
struct nlattr *nested;
|
||||
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
||||
htonl(atomic_read(&set->ref) - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->memsize));
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_port *map = set->data;
|
||||
struct nlattr *atd, *nested;
|
||||
u16 id, first = cb->args[2];
|
||||
u16 last = map->last_port - map->first_port;
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EFAULT;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!test_bit(id, map->members))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EFAULT;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
|
||||
htons(map->first_port + id));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, atd);
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
{
|
||||
const struct bitmap_port *x = a->data;
|
||||
const struct bitmap_port *y = b->data;
|
||||
|
||||
return x->first_port == y->first_port
|
||||
&& x->last_port == y->last_port;
|
||||
}
|
||||
|
||||
const struct ip_set_type_variant bitmap_port = {
|
||||
.kadt = bitmap_port_kadt,
|
||||
.uadt = bitmap_port_uadt,
|
||||
.destroy = bitmap_port_destroy,
|
||||
.flush = bitmap_port_flush,
|
||||
.head = bitmap_port_head,
|
||||
.list = bitmap_port_list,
|
||||
.same_set = bitmap_port_same_set,
|
||||
};
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
struct bitmap_port_timeout {
|
||||
unsigned long *members; /* the set members */
|
||||
u16 first_port; /* host byte order, included in range */
|
||||
u16 last_port; /* host byte order, included in range */
|
||||
size_t memsize; /* members size */
|
||||
|
||||
u32 timeout; /* timeout parameter */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
};
|
||||
|
||||
static inline bool
|
||||
bitmap_port_timeout_test(const struct bitmap_port_timeout *map, u16 id)
|
||||
{
|
||||
return ip_set_timeout_test(map->members[id]);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_timeout_add(const struct bitmap_port_timeout *map,
|
||||
u16 id, u32 timeout)
|
||||
{
|
||||
if (bitmap_port_timeout_test(map, id))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
map->members[id] = ip_set_timeout_set(timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_timeout_del(const struct bitmap_port_timeout *map,
|
||||
u16 id)
|
||||
{
|
||||
int ret = -IPSET_ERR_EXIST;
|
||||
|
||||
if (bitmap_port_timeout_test(map, id))
|
||||
ret = 0;
|
||||
|
||||
map->members[id] = IPSET_ELEM_UNSET;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
{
|
||||
struct bitmap_port_timeout *map = set->data;
|
||||
u16 port = 0;
|
||||
|
||||
if (!get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &port))
|
||||
return -EINVAL;
|
||||
|
||||
port = ntohs(port);
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
port -= map->first_port;
|
||||
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
return bitmap_port_timeout_test(map, port);
|
||||
case IPSET_ADD:
|
||||
return bitmap_port_timeout_add(map, port, map->timeout);
|
||||
case IPSET_DEL:
|
||||
return bitmap_port_timeout_del(map, port);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct bitmap_port_timeout *map = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
u16 id, port_to;
|
||||
u32 port, timeout = map->timeout; /* wraparound */
|
||||
int ret = 0;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
bitmap_port_adt_policy))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
return bitmap_port_timeout_test(map, port - map->first_port);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to) {
|
||||
swap(port, port_to);
|
||||
if (port < map->first_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
}
|
||||
} else
|
||||
port_to = port;
|
||||
|
||||
if (port_to > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT])
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
id = port - map->first_port;
|
||||
ret = adt == IPSET_ADD
|
||||
? bitmap_port_timeout_add(map, id, timeout)
|
||||
: bitmap_port_timeout_del(map, id);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_port_timeout_destroy(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port_timeout *map = set->data;
|
||||
|
||||
del_timer_sync(&map->gc);
|
||||
ip_set_free(map->members);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_port_timeout_flush(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port_timeout *map = set->data;
|
||||
|
||||
memset(map->members, 0, map->memsize);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_timeout_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct bitmap_port_timeout *map = set->data;
|
||||
struct nlattr *nested;
|
||||
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT , htonl(map->timeout));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
||||
htonl(atomic_read(&set->ref) - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->memsize));
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_timeout_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_port_timeout *map = set->data;
|
||||
struct nlattr *adt, *nested;
|
||||
u16 id, first = cb->args[2];
|
||||
u16 last = map->last_port - map->first_port;
|
||||
const unsigned long *table = map->members;
|
||||
|
||||
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!adt)
|
||||
return -EFAULT;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!bitmap_port_timeout_test(map, id))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, adt);
|
||||
return -EFAULT;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
|
||||
htons(map->first_port + id));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(table[id])));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, adt);
|
||||
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, adt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
bitmap_port_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
{
|
||||
const struct bitmap_port_timeout *x = a->data;
|
||||
const struct bitmap_port_timeout *y = b->data;
|
||||
|
||||
return x->first_port == y->first_port
|
||||
&& x->last_port == y->last_port
|
||||
&& x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
const struct ip_set_type_variant bitmap_port_timeout = {
|
||||
.kadt = bitmap_port_timeout_kadt,
|
||||
.uadt = bitmap_port_timeout_uadt,
|
||||
.destroy = bitmap_port_timeout_destroy,
|
||||
.flush = bitmap_port_timeout_flush,
|
||||
.head = bitmap_port_timeout_head,
|
||||
.list = bitmap_port_timeout_list,
|
||||
.same_set = bitmap_port_timeout_same_set,
|
||||
};
|
||||
|
||||
static void
|
||||
bitmap_port_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct bitmap_port_timeout *map = set->data;
|
||||
unsigned long *table = map->members;
|
||||
u32 id; /* wraparound */
|
||||
u16 last = map->last_port - map->first_port;
|
||||
|
||||
/* We run parallel with other readers (test element)
|
||||
* but adding/deleting new entries is locked out */
|
||||
read_lock_bh(&set->lock);
|
||||
for (id = 0; id <= last; id++)
|
||||
if (ip_set_timeout_expired(table[id]))
|
||||
table[id] = IPSET_ELEM_UNSET;
|
||||
read_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
bitmap_port_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port_timeout *map = set->data;
|
||||
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = bitmap_port_gc;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
/* Create bitmap:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
bitmap_port_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static bool
|
||||
init_map_port(struct ip_set *set, struct bitmap_port *map,
|
||||
u16 first_port, u16 last_port)
|
||||
{
|
||||
map->members = ip_set_alloc(map->memsize, GFP_KERNEL);
|
||||
if (!map->members)
|
||||
return false;
|
||||
map->first_port = first_port;
|
||||
map->last_port = last_port;
|
||||
|
||||
set->data = map;
|
||||
set->family = AF_UNSPEC;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
u16 first_port, last_port;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
bitmap_port_create_policy))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (first_port > last_port) {
|
||||
u16 tmp = first_port;
|
||||
|
||||
first_port = last_port;
|
||||
last_port = tmp;
|
||||
}
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
struct bitmap_port_timeout *map;
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
map->memsize = (last_port - first_port + 1)
|
||||
* sizeof(unsigned long);
|
||||
|
||||
if (!init_map_port(set, (struct bitmap_port *) map,
|
||||
first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->variant = &bitmap_port_timeout;
|
||||
|
||||
bitmap_port_gc_init(set);
|
||||
} else {
|
||||
struct bitmap_port *map;
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
map->memsize = bitmap_bytes(0, last_port - first_port);
|
||||
pr_debug("memsize: %zu", map->memsize);
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
set->variant = &bitmap_port;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ip_set_type bitmap_port_type = {
|
||||
.name = "bitmap:port",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.create = bitmap_port_create,
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
bitmap_port_init(void)
|
||||
{
|
||||
return ip_set_type_register(&bitmap_port_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
bitmap_port_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&bitmap_port_type);
|
||||
}
|
||||
|
||||
module_init(bitmap_port_init);
|
||||
module_exit(bitmap_port_fini);
|
@@ -1,126 +0,0 @@
|
||||
#ifndef _IP_SET_GETPORT_H
|
||||
#define _IP_SET_GETPORT_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
#include <net/ip.h>
|
||||
|
||||
#define IPSET_INVALID_PORT 65536
|
||||
|
||||
/* We must handle non-linear skbs */
|
||||
static inline bool
|
||||
get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
|
||||
bool src, u16 *port, u8 *proto)
|
||||
{
|
||||
switch (protocol) {
|
||||
case IPPROTO_TCP: {
|
||||
struct tcphdr _tcph;
|
||||
const struct tcphdr *th;
|
||||
|
||||
th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
/* No choice either */
|
||||
return false;
|
||||
|
||||
*port = src ? th->source : th->dest;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_UDP: {
|
||||
struct udphdr _udph;
|
||||
const struct udphdr *uh;
|
||||
|
||||
uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph);
|
||||
if (uh == NULL)
|
||||
/* No choice either */
|
||||
return false;
|
||||
|
||||
*port = src ? uh->source : uh->dest;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_ICMP: {
|
||||
struct icmphdr _icmph;
|
||||
const struct icmphdr *ic;
|
||||
|
||||
ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph);
|
||||
if (ic == NULL)
|
||||
return false;
|
||||
|
||||
*port = (ic->type << 8) & ic->code;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_ICMPV6: {
|
||||
struct icmp6hdr _icmph;
|
||||
const struct icmp6hdr *ic;
|
||||
|
||||
ic = skb_header_pointer(skb, protooff, sizeof(_icmph), &_icmph);
|
||||
if (ic == NULL)
|
||||
return false;
|
||||
|
||||
*port = (ic->icmp6_type << 8) & ic->icmp6_code;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*proto = protocol;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
get_ip4_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
|
||||
{
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
unsigned int protooff = ip_hdrlen(skb);
|
||||
int protocol = iph->protocol;
|
||||
|
||||
/* See comments at tcp_match in ip_tables.c */
|
||||
if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET))
|
||||
return false;
|
||||
|
||||
return get_port(skb, protocol, protooff, src, port, proto);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
get_ip6_port(const struct sk_buff *skb, bool src, u16 *port, u8 *proto)
|
||||
{
|
||||
unsigned int protooff = 0;
|
||||
int protocol;
|
||||
unsigned short fragoff;
|
||||
|
||||
protocol = ipv6_find_hdr(skb, &protooff, -1, &fragoff);
|
||||
if (protocol <= 0 || fragoff)
|
||||
return false;
|
||||
|
||||
return get_port(skb, protocol, protooff, src, port, proto);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
get_ip_port(const struct sk_buff *skb, u8 pf, bool src, u16 *port)
|
||||
{
|
||||
bool ret;
|
||||
u8 proto;
|
||||
|
||||
switch (pf) {
|
||||
case AF_INET:
|
||||
ret = get_ip4_port(skb, src, port, &proto);
|
||||
case AF_INET6:
|
||||
ret = get_ip6_port(skb, src, port, &proto);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (!ret)
|
||||
return ret;
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_UDP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /*_IP_SET_GETPORT_H*/
|
@@ -1,15 +0,0 @@
|
||||
#ifndef _IP_SET_KERNEL_H
|
||||
#define _IP_SET_KERNEL_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#ifdef CONFIG_DEBUG_KERNEL
|
||||
/* Complete debug messages */
|
||||
#define pr_fmt(fmt) "%s %s[%i]: " fmt "\n", __FILE__, __func__, __LINE__
|
||||
#endif
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /*_IP_SET_H */
|
@@ -5,3 +5,7 @@ obj-m += ip_set.o ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o
|
||||
obj-m += ip_set_bitmap_port.o ip_set_hash_ip.o ip_set_hash_ipport.o
|
||||
obj-m += ip_set_hash_ipportip.o ip_set_hash_ipportnet.o ip_set_hash_net.o
|
||||
obj-m += ip_set_hash_netport.o ip_set_list_set.o
|
||||
|
||||
ip_set-y := ip_set_core.o ip_set_getport.o pfxlen.o
|
||||
|
||||
EXTRA_CFLAGS += -DLCONFIG_IP_SET_MAX=256
|
@@ -1,6 +1,7 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
AM_CFLAGS = ${regular_CFLAGS} ${libmnl_CFLAGS} -Iinclude
|
||||
AM_CPPFLAGS = -I${srcdir}/include -DNDEBUG
|
||||
AM_CFLAGS = ${regular_CFLAGS} ${libmnl_CFLAGS}
|
||||
|
||||
include ../../Makefile.extra
|
||||
|
88
extensions/ipset-6/README
Normal file
88
extensions/ipset-6/README
Normal file
@@ -0,0 +1,88 @@
|
||||
This is the ipset source tree. Follow the next steps to install ipset.
|
||||
If you upgrade from an earlier 5.x release, please read the UPGRADE
|
||||
instructions too.
|
||||
|
||||
0. You need the source tree of your kernel (version >= 2.6.34)
|
||||
and it have to be configured with ip6tables support enabled,
|
||||
modules compiled. Please apply the netlink.patch against your kernel
|
||||
tree, which adds the new subsystem identifier for ipset.
|
||||
|
||||
Recompile and install the patched kernel and its modules. Please note,
|
||||
you have to run the patched kernel for ipset to work.
|
||||
|
||||
The ipset source code depends on the libmnl library so the library
|
||||
must be installed. You can download the libmnl library from
|
||||
|
||||
git://git.netfilter.org/libmnl.git
|
||||
|
||||
1. Initialize the compiling environment for ipset. The packages automake,
|
||||
autoconf and libtool are required.
|
||||
|
||||
% ./autogen.sh
|
||||
|
||||
2. Run `./configure` and then compile the ipset binary and the kernel
|
||||
modules.
|
||||
|
||||
Configure parameters can be used to to override the default path
|
||||
to the kernel source tree (/lib/modules/`uname -r`/build),
|
||||
the maximum number of sets (256), the default hash sizes (1024).
|
||||
See `./configure --help`.
|
||||
|
||||
% ./configure
|
||||
% make
|
||||
% make modules
|
||||
|
||||
3. Install the binary and the kernel modules
|
||||
|
||||
# make install
|
||||
# make modules_install
|
||||
|
||||
After installing the modules, you can run the testsuite as well.
|
||||
Please note, several assumptions must be met for the testsuite:
|
||||
|
||||
- no sets defined
|
||||
- iptables/ip6tables rules are not set up
|
||||
- the destination for kernel logs is /var/log/kern.log
|
||||
- the networks 10.255.255.0/24 and 1002:1002:1002:1002::/64
|
||||
are not in use
|
||||
- sendip utility is installed
|
||||
|
||||
# make tests
|
||||
|
||||
4. Cleanup the source tree
|
||||
|
||||
% make clean
|
||||
% make modules_clean
|
||||
|
||||
That's it!
|
||||
|
||||
Read the ipset(8) and iptables(8), ip6tables(8) manpages on how to use
|
||||
ipset and its match and target from iptables.
|
||||
|
||||
Compatibilities and incompatibilities:
|
||||
|
||||
- The ipset 6.x userspace utility contains a backward compatibility
|
||||
interface to support the commandline syntax of ipset 4.x.
|
||||
The commandline syntax of ipset 6.x is fully compatible with 5.x.
|
||||
- The ipset 6.x userspace utility can't talk to the kernel part of ipset 5.x
|
||||
or 4.x.
|
||||
- The ipset 6.x kernel part can't talk to the userspace utility from
|
||||
ipset 5.x or 4.x.
|
||||
- The ipset 6.x kernel part can work together with the set match and SET
|
||||
target from iptables 1.4.7 and below, however if you need the IPv6 support
|
||||
from ipset 6.x, then you have to use iptables 1.4.8 or above.
|
||||
|
||||
The ipset 6.x can interpret the commandline syntax of ipset 4.x, however
|
||||
some internal changes mean different behaviour:
|
||||
|
||||
- The "--matchunset" flag for the macipmap type is ignored and not used
|
||||
anymore.
|
||||
- The "--probes" and "--resize" parameters of the hash types are ignored
|
||||
and not used anymore.
|
||||
- The "--from", "--to" and "--network" parameters of the ipporthash,
|
||||
ipportiphash and ipportnethash types are ignored and not used anymore.
|
||||
- The hash types are not resized when new entries are added by the SET
|
||||
target. If you use a set together with the SET target, create it with
|
||||
the proper size because it won't be resized automatically.
|
||||
- The iptree, iptreemap types are not implemented in ipset 6.x. The types
|
||||
are automatically substituted with the hash:ip type.
|
1
extensions/ipset-6/VERSION.txt
Normal file
1
extensions/ipset-6/VERSION.txt
Normal file
@@ -0,0 +1 @@
|
||||
5.4.1-genl
|
@@ -4,7 +4,7 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2011 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
|
||||
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 5
|
||||
#define IPSET_PROTOCOL 6
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
@@ -118,7 +118,7 @@ enum {
|
||||
|
||||
/* Error codes */
|
||||
enum ipset_errno {
|
||||
IPSET_ERR_PRIVATE = 128,
|
||||
IPSET_ERR_PRIVATE = 4096,
|
||||
IPSET_ERR_PROTOCOL,
|
||||
IPSET_ERR_FIND_TYPE,
|
||||
IPSET_ERR_MAX_SETS,
|
||||
@@ -135,7 +135,7 @@ enum ipset_errno {
|
||||
IPSET_ERR_IPADDR_IPV6,
|
||||
|
||||
/* Type specific error codes */
|
||||
IPSET_ERR_TYPE_SPECIFIC = 160,
|
||||
IPSET_ERR_TYPE_SPECIFIC = 4352,
|
||||
};
|
||||
|
||||
/* Flags at command level */
|
@@ -17,6 +17,7 @@
|
||||
#define IPSET_PROTO_SEPARATOR ":"
|
||||
|
||||
struct ipset_session;
|
||||
struct ipset_arg;
|
||||
|
||||
typedef int (*ipset_parsefn)(struct ipset_session *s,
|
||||
enum ipset_opt opt, const char *str);
|
||||
@@ -84,8 +85,8 @@ extern int ipset_parse_ignored(struct ipset_session *session,
|
||||
extern int ipset_parse_elem(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_call_parser(struct ipset_session *session,
|
||||
ipset_parsefn parse, const char *optstr,
|
||||
enum ipset_opt optional, const char *str);
|
||||
const struct ipset_arg *arg,
|
||||
const char *str);
|
||||
|
||||
/* Compatibility parser functions */
|
||||
extern int ipset_parse_iptimeout(struct ipset_session *session,
|
@@ -24,6 +24,7 @@ struct ipset_handle;
|
||||
extern struct ipset_data * ipset_session_data(const struct ipset_session *session);
|
||||
extern struct ipset_handle * ipset_session_handle(const struct ipset_session *session);
|
||||
extern const struct ipset_type * ipset_saved_type(const struct ipset_session *session);
|
||||
extern void ipset_session_lineno(struct ipset_session *session, uint32_t lineno);
|
||||
|
||||
enum ipset_err_type {
|
||||
IPSET_ERROR,
|
@@ -70,7 +70,7 @@ struct ipset_elem {
|
||||
* but for the readability the full list is supported.
|
||||
*/
|
||||
struct ipset_type {
|
||||
char name[IPSET_MAXNAMELEN]; /* type name */
|
||||
const char *name;
|
||||
uint8_t revision; /* revision number */
|
||||
uint8_t family; /* supported family */
|
||||
uint8_t dimension; /* elem dimension */
|
@@ -25,6 +25,11 @@
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
|
||||
#define UNUSED __attribute__ ((unused))
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT_UNUSED UNUSED
|
||||
#else
|
||||
#define ASSERT_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
@@ -4,15 +4,17 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2011 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.
|
||||
*/
|
||||
|
||||
#include <linux/netlink.h>
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 5
|
||||
#define IPSET_PROTOCOL 6
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
@@ -118,7 +120,7 @@ enum {
|
||||
|
||||
/* Error codes */
|
||||
enum ipset_errno {
|
||||
IPSET_ERR_PRIVATE = 128,
|
||||
IPSET_ERR_PRIVATE = 4096,
|
||||
IPSET_ERR_PROTOCOL,
|
||||
IPSET_ERR_FIND_TYPE,
|
||||
IPSET_ERR_MAX_SETS,
|
||||
@@ -135,7 +137,7 @@ enum ipset_errno {
|
||||
IPSET_ERR_IPADDR_IPV6,
|
||||
|
||||
/* Type specific error codes */
|
||||
IPSET_ERR_TYPE_SPECIFIC = 160,
|
||||
IPSET_ERR_TYPE_SPECIFIC = 4352,
|
||||
};
|
||||
|
||||
/* Flags at command level */
|
||||
@@ -214,7 +216,8 @@ enum ip_set_feature {
|
||||
|
||||
struct ip_set;
|
||||
|
||||
typedef int (*ipset_adtfn)(struct ip_set *set, void *value, u32 timeout);
|
||||
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
|
||||
u32 timeout, u32 flags);
|
||||
|
||||
/* Set type, variant-specific part */
|
||||
struct ip_set_type_variant {
|
||||
@@ -229,7 +232,7 @@ struct ip_set_type_variant {
|
||||
* returns negative error code,
|
||||
* zero for no match/success to add/delete
|
||||
* positive for matching element */
|
||||
int (*uadt)(struct ip_set *set, struct nlattr *head, int len,
|
||||
int (*uadt)(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags);
|
||||
|
||||
/* Low level add/del/test functions */
|
||||
@@ -272,13 +275,17 @@ struct ip_set_type {
|
||||
u8 revision;
|
||||
|
||||
/* Create set */
|
||||
int (*create)(struct ip_set *set,
|
||||
struct nlattr *head, int len, u32 flags);
|
||||
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
|
||||
|
||||
/* Attribute policies */
|
||||
const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1];
|
||||
const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1];
|
||||
|
||||
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
|
||||
struct module *me;
|
||||
};
|
||||
|
||||
/* register and unregister set type */
|
||||
extern int ip_set_type_register(struct ip_set_type *set_type);
|
||||
extern void ip_set_type_unregister(struct ip_set_type *set_type);
|
||||
|
||||
@@ -289,9 +296,9 @@ struct ip_set {
|
||||
/* Lock protecting the set data */
|
||||
rwlock_t lock;
|
||||
/* References to the set */
|
||||
atomic_t ref;
|
||||
u32 ref;
|
||||
/* The core set type */
|
||||
const struct ip_set_type *type;
|
||||
struct ip_set_type *type;
|
||||
/* The type variant doing the real job */
|
||||
const struct ip_set_type_variant *variant;
|
||||
/* The actual INET family of the set */
|
||||
@@ -316,37 +323,22 @@ extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
|
||||
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags);
|
||||
|
||||
/* Allocate members */
|
||||
static inline void *
|
||||
ip_set_alloc(size_t size, gfp_t gfp_mask)
|
||||
/* Utility functions */
|
||||
extern void * ip_set_alloc(size_t size);
|
||||
extern void ip_set_free(void *members);
|
||||
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
|
||||
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
|
||||
|
||||
static inline int
|
||||
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
|
||||
{
|
||||
void *members = NULL;
|
||||
__be32 ip;
|
||||
int ret = ip_set_get_ipaddr4(nla, &ip);
|
||||
|
||||
if (size < KMALLOC_MAX_SIZE)
|
||||
members = kzalloc(size, gfp_mask | __GFP_NOWARN);
|
||||
|
||||
if (members) {
|
||||
pr_debug("%p: allocated with kmalloc", members);
|
||||
return members;
|
||||
}
|
||||
|
||||
members = __vmalloc(size, gfp_mask | __GFP_ZERO, PAGE_KERNEL);
|
||||
if (!members)
|
||||
return NULL;
|
||||
pr_debug("%p: allocated with vmalloc", members);
|
||||
|
||||
return members;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip_set_free(void *members)
|
||||
{
|
||||
pr_debug("%p: free with %s", members,
|
||||
is_vmalloc_addr(members) ? "vfree" : "kfree");
|
||||
if (is_vmalloc_addr(members))
|
||||
vfree(members);
|
||||
else
|
||||
kfree(members);
|
||||
if (ret)
|
||||
return ret;
|
||||
*ipaddr = ntohl(ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ignore IPSET_ERR_EXIST errors if asked to do so? */
|
||||
@@ -356,92 +348,47 @@ ip_set_eexist(int ret, u32 flags)
|
||||
return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST);
|
||||
}
|
||||
|
||||
/* Check the NLA_F_NET_BYTEORDER flag */
|
||||
static inline bool
|
||||
ip_set_attr_netorder(struct nlattr *tb[], int type)
|
||||
{
|
||||
return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_optattr_netorder(struct nlattr *tb[], int type)
|
||||
{
|
||||
return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER);
|
||||
}
|
||||
|
||||
/* Useful converters */
|
||||
static inline u32
|
||||
ip_set_get_h32(const struct nlattr *attr)
|
||||
{
|
||||
u32 value = nla_get_u32(attr);
|
||||
|
||||
return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohl(value) : value;
|
||||
return ntohl(nla_get_be32(attr));
|
||||
}
|
||||
|
||||
static inline u16
|
||||
ip_set_get_h16(const struct nlattr *attr)
|
||||
{
|
||||
u16 value = nla_get_u16(attr);
|
||||
|
||||
return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohs(value) : value;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
ip_set_get_n32(const struct nlattr *attr)
|
||||
{
|
||||
u32 value = nla_get_u32(attr);
|
||||
|
||||
return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htonl(value);
|
||||
}
|
||||
|
||||
static inline u16
|
||||
ip_set_get_n16(const struct nlattr *attr)
|
||||
{
|
||||
u16 value = nla_get_u16(attr);
|
||||
|
||||
return attr->nla_type & NLA_F_NET_BYTEORDER ? value : htons(value);
|
||||
}
|
||||
|
||||
static const struct nla_policy ipaddr_policy[IPSET_ATTR_IPADDR_MAX + 1] = {
|
||||
[IPSET_ATTR_IPADDR_IPV4] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_IPADDR_IPV6] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct in6_addr) },
|
||||
};
|
||||
|
||||
static inline int
|
||||
ip_set_get_ipaddr4(struct nlattr *attr[], int type, u32 *ipaddr)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {};
|
||||
|
||||
if (!attr[type])
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX,
|
||||
nla_data(attr[type]), nla_len(attr[type]),
|
||||
ipaddr_policy))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (!tb[IPSET_ATTR_IPADDR_IPV4])
|
||||
return -IPSET_ERR_IPADDR_IPV4;
|
||||
|
||||
*ipaddr = ip_set_get_n32(tb[IPSET_ATTR_IPADDR_IPV4]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
ip_set_get_ipaddr6(struct nlattr *attr[], int type, union nf_inet_addr *ipaddr)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_IPADDR_MAX+1] = {};
|
||||
|
||||
if (!attr[type])
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_IPADDR_MAX,
|
||||
nla_data(attr[type]), nla_len(attr[type]),
|
||||
ipaddr_policy))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (!tb[IPSET_ATTR_IPADDR_IPV6])
|
||||
return -IPSET_ERR_IPADDR_IPV6;
|
||||
|
||||
memcpy(ipaddr, nla_data(tb[IPSET_ATTR_IPADDR_IPV6]),
|
||||
sizeof(struct in6_addr));
|
||||
return 0;
|
||||
return ntohs(nla_get_be16(attr));
|
||||
}
|
||||
|
||||
#define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED)
|
||||
#define ipset_nest_end(skb, start) nla_nest_end(skb, start)
|
||||
|
||||
#define NLA_PUT_NET32(skb, type, value) \
|
||||
NLA_PUT_BE32(skb, type | NLA_F_NET_BYTEORDER, value)
|
||||
|
||||
#define NLA_PUT_NET16(skb, type, value) \
|
||||
NLA_PUT_BE16(skb, type | NLA_F_NET_BYTEORDER, value)
|
||||
#ifndef NLA_PUT_NET16
|
||||
#define NLA_PUT_NET16(skb, attrtype, value) \
|
||||
NLA_PUT_BE16(skb, attrtype | NLA_F_NET_BYTEORDER, value)
|
||||
#endif
|
||||
#ifndef NLA_PUT_NET32
|
||||
#define NLA_PUT_NET32(skb, attrtype, value) \
|
||||
NLA_PUT_BE32(skb, attrtype | NLA_F_NET_BYTEORDER, value)
|
||||
#endif
|
||||
#ifndef NLA_PUT_NET64
|
||||
#define NLA_PUT_NET64(skb, attrtype, value) \
|
||||
NLA_PUT_BE64(skb, attrtype | NLA_F_NET_BYTEORDER, value)
|
||||
#endif
|
||||
|
||||
#define NLA_PUT_IPADDR4(skb, type, ipaddr) \
|
||||
do { \
|
||||
@@ -465,14 +412,14 @@ do { \
|
||||
} while (0)
|
||||
|
||||
/* Get address from skbuff */
|
||||
static inline u32
|
||||
static inline __be32
|
||||
ip4addr(const struct sk_buff *skb, bool src)
|
||||
{
|
||||
return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip4addrptr(const struct sk_buff *skb, bool src, u32 *addr)
|
||||
ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr)
|
||||
{
|
||||
*addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
|
||||
}
|
||||
@@ -491,15 +438,6 @@ bitmap_bytes(u32 a, u32 b)
|
||||
return 4 * ((((b - a + 8) / 8) + 3) / 4);
|
||||
}
|
||||
|
||||
/* Prefixlen maps */
|
||||
extern const union nf_inet_addr prefixlen_netmask_map[];
|
||||
extern const union nf_inet_addr prefixlen_hostmask_map[];
|
||||
|
||||
#define NETMASK(n) prefixlen_netmask_map[n].ip
|
||||
#define NETMASK6(n) prefixlen_netmask_map[n].ip6
|
||||
#define HOSTMASK(n) prefixlen_hostmask_map[n].ip
|
||||
#define HOSTMASK6(n) prefixlen_hostmask_map[n].ip6
|
||||
|
||||
/* Interface to iptables/ip6tables */
|
||||
|
||||
#define SO_IP_SET 83
|
@@ -63,7 +63,7 @@ struct ip_set_hash {
|
||||
};
|
||||
|
||||
/* Compute htable_bits from the user input parameter hashsize */
|
||||
static inline u8
|
||||
static u8
|
||||
htable_bits(u32 hashsize)
|
||||
{
|
||||
/* Assume that hashsize == 2^htable_bits */
|
||||
@@ -81,14 +81,14 @@ htable_bits(u32 hashsize)
|
||||
|
||||
/* Network cidr size book keeping when the hash stores different
|
||||
* sized networks */
|
||||
static inline void
|
||||
static void
|
||||
add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
++h->nets[cidr-1].nets;
|
||||
|
||||
pr_debug("add_cidr added %u: %u", cidr, h->nets[cidr-1].nets);
|
||||
pr_debug("add_cidr added %u: %u\n", cidr, h->nets[cidr-1].nets);
|
||||
|
||||
if (h->nets[cidr-1].nets > 1)
|
||||
return;
|
||||
@@ -103,14 +103,14 @@ add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
||||
h->nets[i].cidr = cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
static void
|
||||
del_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
||||
{
|
||||
u8 i;
|
||||
|
||||
--h->nets[cidr-1].nets;
|
||||
|
||||
pr_debug("del_cidr deleted %u: %u", cidr, h->nets[cidr-1].nets);
|
||||
pr_debug("del_cidr deleted %u: %u\n", cidr, h->nets[cidr-1].nets);
|
||||
|
||||
if (h->nets[cidr-1].nets != 0)
|
||||
return;
|
||||
@@ -142,7 +142,7 @@ ahash_destroy(struct htable *t)
|
||||
}
|
||||
|
||||
/* Calculate the actual memory size of the set data */
|
||||
static inline size_t
|
||||
static size_t
|
||||
ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 host_mask)
|
||||
{
|
||||
u32 i;
|
||||
@@ -311,8 +311,7 @@ retry:
|
||||
/* In case we have plenty of memory :-) */
|
||||
return -IPSET_ERR_HASH_FULL;
|
||||
t = ip_set_alloc(sizeof(*t)
|
||||
+ jhash_size(htable_bits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(htable_bits) * sizeof(struct hbucket));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
t->htable_bits = htable_bits;
|
||||
@@ -340,7 +339,7 @@ retry:
|
||||
/* Give time to other readers of the set */
|
||||
synchronize_rcu_bh();
|
||||
|
||||
pr_debug("set %s resized from %u (%p) to %u (%p)", set->name,
|
||||
pr_debug("set %s resized from %u (%p) to %u (%p)\n", set->name,
|
||||
orig->htable_bits, orig, t->htable_bits, t);
|
||||
ahash_destroy(orig);
|
||||
|
||||
@@ -350,7 +349,7 @@ retry:
|
||||
/* Add an element to a hash and update the internal counters when succeeded,
|
||||
* otherwise report the proper error code. */
|
||||
static int
|
||||
type_pf_add(struct ip_set *set, void *value, u32 timeout)
|
||||
type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
struct htable *t;
|
||||
@@ -389,7 +388,7 @@ out:
|
||||
* and free up space if possible.
|
||||
*/
|
||||
static int
|
||||
type_pf_del(struct ip_set *set, void *value, u32 timeout)
|
||||
type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
@@ -436,7 +435,7 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout)
|
||||
|
||||
/* Special test function which takes into account the different network
|
||||
* sizes added to the set */
|
||||
static inline int
|
||||
static int
|
||||
type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
@@ -447,7 +446,7 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||
u32 key;
|
||||
u8 host_mask = SET_HOST_MASK(set->family);
|
||||
|
||||
pr_debug("test by nets");
|
||||
pr_debug("test by nets\n");
|
||||
for (; j < host_mask && h->nets[j].cidr; j++) {
|
||||
type_pf_data_netmask(d, h->nets[j].cidr);
|
||||
key = HKEY(d, h->initval, t->htable_bits);
|
||||
@@ -464,7 +463,7 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||
|
||||
/* Test whether the element is added to the set */
|
||||
static int
|
||||
type_pf_test(struct ip_set *set, void *value, u32 timeout)
|
||||
type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
@@ -516,8 +515,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb)
|
||||
if (h->netmask != HOST_MASK)
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask);
|
||||
#endif
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
||||
htonl(atomic_read(&set->ref) - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize));
|
||||
if (with_timeout(h->timeout))
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(h->timeout));
|
||||
@@ -525,7 +523,7 @@ type_pf_head(struct ip_set *set, struct sk_buff *skb)
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
/* Reply a LIST/SAVE request: dump the elements of the specified set */
|
||||
@@ -545,21 +543,21 @@ type_pf_list(const struct ip_set *set,
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EFAULT;
|
||||
pr_debug("list hash set %s", set->name);
|
||||
return -EMSGSIZE;
|
||||
pr_debug("list hash set %s\n", set->name);
|
||||
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
|
||||
incomplete = skb_tail_pointer(skb);
|
||||
n = hbucket(t, cb->args[2]);
|
||||
pr_debug("cb->args[2]: %lu, t %p n %p", cb->args[2], t, n);
|
||||
pr_debug("cb->args[2]: %lu, t %p n %p\n", cb->args[2], t, n);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i);
|
||||
pr_debug("list hash %lu hbucket %p i %u, data %p",
|
||||
pr_debug("list hash %lu hbucket %p i %u, data %p\n",
|
||||
cb->args[2], n, i, data);
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (cb->args[2] == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
@@ -581,6 +579,7 @@ nla_put_failure:
|
||||
pr_warning("Can't list set %s: one bucket does not fit into "
|
||||
"a message. Please report it!\n", set->name);
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -589,7 +588,7 @@ static int
|
||||
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
|
||||
static int
|
||||
type_pf_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags);
|
||||
|
||||
static const struct ip_set_type_variant type_pf_variant = {
|
||||
@@ -686,7 +685,7 @@ type_pf_expire(struct ip_set_hash *h)
|
||||
for (j = 0; j < n->pos; j++) {
|
||||
data = ahash_tdata(n, j);
|
||||
if (type_pf_data_expired(data)) {
|
||||
pr_debug("expired %u/%u", i, j);
|
||||
pr_debug("expired %u/%u\n", i, j);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
del_cidr(h, data->cidr, HOST_MASK);
|
||||
#endif
|
||||
@@ -701,7 +700,7 @@ type_pf_expire(struct ip_set_hash *h)
|
||||
if (n->pos + AHASH_INIT_SIZE < n->size) {
|
||||
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
|
||||
* sizeof(struct type_pf_telem),
|
||||
GFP_KERNEL);
|
||||
GFP_ATOMIC);
|
||||
if (!tmp)
|
||||
/* Still try to delete expired elements */
|
||||
continue;
|
||||
@@ -742,8 +741,7 @@ retry:
|
||||
/* In case we have plenty of memory :-) */
|
||||
return -IPSET_ERR_HASH_FULL;
|
||||
t = ip_set_alloc(sizeof(*t)
|
||||
+ jhash_size(htable_bits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(htable_bits) * sizeof(struct hbucket));
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
t->htable_bits = htable_bits;
|
||||
@@ -778,7 +776,7 @@ retry:
|
||||
}
|
||||
|
||||
static int
|
||||
type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
|
||||
type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
@@ -786,6 +784,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
|
||||
struct hbucket *n;
|
||||
struct type_pf_elem *data;
|
||||
int ret = 0, i, j = AHASH_MAX_SIZE + 1;
|
||||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
u32 key;
|
||||
|
||||
if (h->elements >= h->maxelem)
|
||||
@@ -801,14 +800,14 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_tdata(n, i);
|
||||
if (type_pf_data_equal(data, d)) {
|
||||
if (type_pf_data_expired(data))
|
||||
if (type_pf_data_expired(data) || flag_exist)
|
||||
j = i;
|
||||
else {
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
goto out;
|
||||
}
|
||||
} else if (j == AHASH_MAX_SIZE + 1
|
||||
&& type_pf_data_expired(data))
|
||||
} else if (j == AHASH_MAX_SIZE + 1 &&
|
||||
type_pf_data_expired(data))
|
||||
j = i;
|
||||
}
|
||||
if (j != AHASH_MAX_SIZE + 1) {
|
||||
@@ -835,7 +834,7 @@ out:
|
||||
}
|
||||
|
||||
static int
|
||||
type_pf_tdel(struct ip_set *set, void *value, u32 timeout)
|
||||
type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
@@ -881,7 +880,7 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout)
|
||||
}
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
static inline int
|
||||
static int
|
||||
type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
@@ -907,7 +906,7 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||
#endif
|
||||
|
||||
static int
|
||||
type_pf_ttest(struct ip_set *set, void *value, u32 timeout)
|
||||
type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
struct htable *t = h->table;
|
||||
@@ -946,21 +945,21 @@ type_pf_tlist(const struct ip_set *set,
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
|
||||
incomplete = skb_tail_pointer(skb);
|
||||
n = hbucket(t, cb->args[2]);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_tdata(n, i);
|
||||
pr_debug("list %p %u", n, i);
|
||||
pr_debug("list %p %u\n", n, i);
|
||||
if (type_pf_data_expired(data))
|
||||
continue;
|
||||
pr_debug("do list %p %u", n, i);
|
||||
pr_debug("do list %p %u\n", n, i);
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (cb->args[2] == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
@@ -982,6 +981,7 @@ nla_put_failure:
|
||||
pr_warning("Can't list set %s: one bucket does not fit into "
|
||||
"a message. Please report it!\n", set->name);
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1008,7 +1008,7 @@ type_pf_gc(unsigned long ul_set)
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct ip_set_hash *h = set->data;
|
||||
|
||||
pr_debug("called");
|
||||
pr_debug("called\n");
|
||||
write_lock_bh(&set->lock);
|
||||
type_pf_expire(h);
|
||||
write_unlock_bh(&set->lock);
|
||||
@@ -1017,7 +1017,7 @@ type_pf_gc(unsigned long ul_set)
|
||||
add_timer(&h->gc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
static void
|
||||
type_pf_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
@@ -1027,7 +1027,7 @@ type_pf_gc_init(struct ip_set *set)
|
||||
h->gc.function = type_pf_gc;
|
||||
h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
|
||||
add_timer(&h->gc);
|
||||
pr_debug("gc initialized, run in every %u",
|
||||
pr_debug("gc initialized, run in every %u\n",
|
||||
IPSET_GC_PERIOD(h->timeout));
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2011 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
|
||||
@@ -9,12 +9,10 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the bitmap:ip type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/netlink.h>
|
||||
@@ -23,6 +21,7 @@
|
||||
#include <net/netlink.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_bitmap.h"
|
||||
#define IP_SET_BITMAP_TIMEOUT
|
||||
@@ -33,8 +32,7 @@ MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("bitmap:ip type of IP sets");
|
||||
MODULE_ALIAS("ip_set_bitmap:ip");
|
||||
|
||||
/* Base variant */
|
||||
|
||||
/* Type structure */
|
||||
struct bitmap_ip {
|
||||
void *members; /* the set members */
|
||||
u32 first_ip; /* host byte order, included in range */
|
||||
@@ -43,43 +41,188 @@ struct bitmap_ip {
|
||||
u32 hosts; /* number of hosts in a subnet */
|
||||
size_t memsize; /* members size */
|
||||
u8 netmask; /* subnet netmask */
|
||||
u32 timeout; /* timeout parameter */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
};
|
||||
|
||||
/* Base variant */
|
||||
|
||||
static inline u32
|
||||
ip_to_id(const struct bitmap_ip *map, u32 ip)
|
||||
ip_to_id(const struct bitmap_ip *m, u32 ip)
|
||||
{
|
||||
return ((ip & HOSTMASK(map->netmask)) - map->first_ip)/map->hosts;
|
||||
return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts;
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_test(const struct bitmap_ip *map, u32 id)
|
||||
static int
|
||||
bitmap_ip_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
return !!test_bit(id, map->members);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_add(struct bitmap_ip *map, u32 id)
|
||||
static int
|
||||
bitmap_ip_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (test_and_set_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_del(struct bitmap_ip *map, u32 id)
|
||||
static int
|
||||
bitmap_ip_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (!test_and_clear_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
struct nlattr *atd, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->elements; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!test_bit(id, map->members))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id * map->hosts));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, atd);
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
static int
|
||||
bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
const unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
return ip_set_timeout_test(members[id]);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
members[id] = ip_set_timeout_set(timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
int ret = -IPSET_ERR_EXIST;
|
||||
|
||||
if (ip_set_timeout_test(members[id]))
|
||||
ret = 0;
|
||||
|
||||
members[id] = IPSET_ELEM_UNSET;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_tlist(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
struct nlattr *adt, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
const unsigned long *members = map->members;
|
||||
|
||||
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!adt)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->elements; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!ip_set_timeout_test(members[id]))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, adt);
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id * map->hosts));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(members[id])));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, adt);
|
||||
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, adt);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 ip;
|
||||
|
||||
ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
||||
@@ -88,63 +231,48 @@ bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
|
||||
ip = ip_to_id(map, ip);
|
||||
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
return bitmap_ip_test(map, ip);
|
||||
case IPSET_ADD:
|
||||
return bitmap_ip_add(map, ip);
|
||||
case IPSET_DEL:
|
||||
return bitmap_ip_del(map, ip);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return adtfn(set, &ip, map->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy bitmap_ip_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
|
||||
[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 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 timeout = map->timeout;
|
||||
u32 ip, ip_to, id;
|
||||
int ret = 0;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
bitmap_ip_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip = ntohl(ip);
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
/* Set was defined without timeout support:
|
||||
* don't ignore the attribute silently */
|
||||
if (tb[IPSET_ATTR_TIMEOUT])
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(map->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
return bitmap_ip_test(map, ip_to_id(map, ip));
|
||||
if (adt == IPSET_TEST) {
|
||||
id = ip_to_id(map, ip);
|
||||
return adtfn(set, &id, timeout, flags);
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip_to = ntohl(ip_to);
|
||||
if (ip > ip_to) {
|
||||
swap(ip, ip_to);
|
||||
if (ip < map->first_ip)
|
||||
@@ -155,8 +283,8 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= HOSTMASK(cidr);
|
||||
ip_to = ip | ~HOSTMASK(cidr);
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -165,8 +293,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
for (; !before(ip_to, ip); ip += map->hosts) {
|
||||
id = ip_to_id(map, ip);
|
||||
ret = adt == IPSET_ADD ? bitmap_ip_add(map, id)
|
||||
: bitmap_ip_del(map, id);
|
||||
ret = adtfn(set, &id, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -181,6 +308,9 @@ bitmap_ip_destroy(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
|
||||
if (with_timeout(map->timeout))
|
||||
del_timer_sync(&map->gc);
|
||||
|
||||
ip_set_free(map->members);
|
||||
kfree(map);
|
||||
|
||||
@@ -208,53 +338,16 @@ bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
|
||||
if (map->netmask != 32)
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
||||
htonl(atomic_read(&set->ref) - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->memsize));
|
||||
if (with_timeout(map->timeout))
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
struct nlattr *atd, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EFAULT;
|
||||
for (; cb->args[2] < map->elements; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!bitmap_ip_test(map, id))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EFAULT;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id * map->hosts));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, atd);
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
return 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -263,14 +356,20 @@ bitmap_ip_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct bitmap_ip *x = a->data;
|
||||
const struct bitmap_ip *y = b->data;
|
||||
|
||||
return x->first_ip == y->first_ip
|
||||
&& x->last_ip == y->last_ip
|
||||
&& x->netmask == y->netmask;
|
||||
return x->first_ip == y->first_ip &&
|
||||
x->last_ip == y->last_ip &&
|
||||
x->netmask == y->netmask &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
static const struct ip_set_type_variant bitmap_ip = {
|
||||
.kadt = bitmap_ip_kadt,
|
||||
.uadt = bitmap_ip_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_ip_add,
|
||||
[IPSET_DEL] = bitmap_ip_del,
|
||||
[IPSET_TEST] = bitmap_ip_test,
|
||||
},
|
||||
.destroy = bitmap_ip_destroy,
|
||||
.flush = bitmap_ip_flush,
|
||||
.head = bitmap_ip_head,
|
||||
@@ -278,259 +377,26 @@ static const struct ip_set_type_variant bitmap_ip = {
|
||||
.same_set = bitmap_ip_same_set,
|
||||
};
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
struct bitmap_ip_timeout {
|
||||
unsigned long *members; /* the set members */
|
||||
u32 first_ip; /* host byte order, included in range */
|
||||
u32 last_ip; /* host byte order, included in range */
|
||||
u32 elements; /* number of max elements in the set */
|
||||
u32 hosts; /* number of hosts in a subnet */
|
||||
size_t memsize; /* members size */
|
||||
u8 netmask; /* subnet netmask */
|
||||
|
||||
u32 timeout; /* timeout parameter */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
};
|
||||
|
||||
static inline bool
|
||||
bitmap_ip_timeout_test(const struct bitmap_ip_timeout *map, u32 id)
|
||||
{
|
||||
return ip_set_timeout_test(map->members[id]);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_timeout_add(struct bitmap_ip_timeout *map,
|
||||
u32 id, u32 timeout)
|
||||
{
|
||||
if (bitmap_ip_timeout_test(map, id))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
map->members[id] = ip_set_timeout_set(timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ip_timeout_del(struct bitmap_ip_timeout *map, u32 id)
|
||||
{
|
||||
int ret = -IPSET_ERR_EXIST;
|
||||
|
||||
if (bitmap_ip_timeout_test(map, id))
|
||||
ret = 0;
|
||||
|
||||
map->members[id] = IPSET_ELEM_UNSET;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_timeout_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
{
|
||||
struct bitmap_ip_timeout *map = set->data;
|
||||
u32 ip;
|
||||
|
||||
ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
ip = ip_to_id((const struct bitmap_ip *)map, ip);
|
||||
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
return bitmap_ip_timeout_test(map, ip);
|
||||
case IPSET_ADD:
|
||||
return bitmap_ip_timeout_add(map, ip, map->timeout);
|
||||
case IPSET_DEL:
|
||||
return bitmap_ip_timeout_del(map, ip);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_timeout_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
struct bitmap_ip_timeout *map = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
u32 ip, ip_to, id, timeout = map->timeout;
|
||||
int ret = 0;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
bitmap_ip_adt_policy))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip = ntohl(ip);
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
return bitmap_ip_timeout_test(map,
|
||||
ip_to_id((const struct bitmap_ip *)map, ip));
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip_to = ntohl(ip_to);
|
||||
if (ip > ip_to) {
|
||||
swap(ip, ip_to);
|
||||
if (ip < map->first_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= HOSTMASK(cidr);
|
||||
ip_to = ip | ~HOSTMASK(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
if (ip_to > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT])
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
for (; !before(ip_to, ip); ip += map->hosts) {
|
||||
id = ip_to_id((const struct bitmap_ip *)map, ip);
|
||||
ret = adt == IPSET_ADD
|
||||
? bitmap_ip_timeout_add(map, id, timeout)
|
||||
: bitmap_ip_timeout_del(map, id);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_ip_timeout_destroy(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ip_timeout *map = set->data;
|
||||
|
||||
del_timer_sync(&map->gc);
|
||||
ip_set_free(map->members);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_ip_timeout_flush(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ip_timeout *map = set->data;
|
||||
|
||||
memset(map->members, IPSET_ELEM_UNSET, map->memsize);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_timeout_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct bitmap_ip_timeout *map = set->data;
|
||||
struct nlattr *nested;
|
||||
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
|
||||
if (map->netmask != 32)
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
||||
htonl(atomic_read(&set->ref) - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->memsize));
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_timeout_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ip_timeout *map = set->data;
|
||||
struct nlattr *adt, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
const unsigned long *table = map->members;
|
||||
|
||||
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!adt)
|
||||
return -EFAULT;
|
||||
for (; cb->args[2] < map->elements; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!bitmap_ip_timeout_test(map, id))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, adt);
|
||||
return -EFAULT;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id * map->hosts));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(table[id])));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, adt);
|
||||
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, adt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
bitmap_ip_timeout_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
{
|
||||
const struct bitmap_ip_timeout *x = a->data;
|
||||
const struct bitmap_ip_timeout *y = b->data;
|
||||
|
||||
return x->first_ip == y->first_ip
|
||||
&& x->last_ip == y->last_ip
|
||||
&& x->netmask == y->netmask
|
||||
&& x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
static const struct ip_set_type_variant bitmap_ip_timeout = {
|
||||
.kadt = bitmap_ip_timeout_kadt,
|
||||
.uadt = bitmap_ip_timeout_uadt,
|
||||
.destroy = bitmap_ip_timeout_destroy,
|
||||
.flush = bitmap_ip_timeout_flush,
|
||||
.head = bitmap_ip_timeout_head,
|
||||
.list = bitmap_ip_timeout_list,
|
||||
.same_set = bitmap_ip_timeout_same_set,
|
||||
static const struct ip_set_type_variant bitmap_tip = {
|
||||
.kadt = bitmap_ip_kadt,
|
||||
.uadt = bitmap_ip_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_ip_tadd,
|
||||
[IPSET_DEL] = bitmap_ip_tdel,
|
||||
[IPSET_TEST] = bitmap_ip_ttest,
|
||||
},
|
||||
.destroy = bitmap_ip_destroy,
|
||||
.flush = bitmap_ip_flush,
|
||||
.head = bitmap_ip_head,
|
||||
.list = bitmap_ip_tlist,
|
||||
.same_set = bitmap_ip_same_set,
|
||||
};
|
||||
|
||||
static void
|
||||
bitmap_ip_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct bitmap_ip_timeout *map = set->data;
|
||||
struct bitmap_ip *map = set->data;
|
||||
unsigned long *table = map->members;
|
||||
u32 id;
|
||||
|
||||
@@ -546,10 +412,10 @@ bitmap_ip_gc(unsigned long ul_set)
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
static void
|
||||
bitmap_ip_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ip_timeout *map = set->data;
|
||||
struct bitmap_ip *map = set->data;
|
||||
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
@@ -560,21 +426,12 @@ bitmap_ip_gc_init(struct ip_set *set)
|
||||
|
||||
/* Create bitmap:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
bitmap_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static bool
|
||||
init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
||||
u32 first_ip, u32 last_ip,
|
||||
u32 elements, u32 hosts, u8 netmask)
|
||||
{
|
||||
map->members = ip_set_alloc(map->memsize, GFP_KERNEL);
|
||||
map->members = ip_set_alloc(map->memsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
map->first_ip = first_ip;
|
||||
@@ -582,6 +439,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
||||
map->elements = elements;
|
||||
map->hosts = hosts;
|
||||
map->netmask = netmask;
|
||||
map->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
set->data = map;
|
||||
set->family = AF_INET;
|
||||
@@ -590,28 +448,25 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
u32 flags)
|
||||
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
struct bitmap_ip *map;
|
||||
u32 first_ip, last_ip, hosts, elements;
|
||||
u8 netmask = 32;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
bitmap_ip_create_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
first_ip = ntohl(first_ip);
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
last_ip = htonl(last_ip);
|
||||
if (first_ip > last_ip) {
|
||||
u32 tmp = first_ip;
|
||||
|
||||
@@ -623,7 +478,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
last_ip = first_ip | ~HOSTMASK(cidr);
|
||||
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
@@ -633,8 +488,8 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
if (netmask > 32)
|
||||
return -IPSET_ERR_INVALID_NETMASK;
|
||||
|
||||
first_ip &= HOSTMASK(netmask);
|
||||
last_ip |= ~HOSTMASK(netmask);
|
||||
first_ip &= ip_set_hostmask(netmask);
|
||||
last_ip |= ~ip_set_hostmask(netmask);
|
||||
}
|
||||
|
||||
if (netmask == 32) {
|
||||
@@ -646,50 +501,40 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
mask = range_to_mask(first_ip, last_ip, &mask_bits);
|
||||
|
||||
if ((!mask && (first_ip || last_ip != 0xFFFFFFFF))
|
||||
|| netmask <= mask_bits)
|
||||
if ((!mask && (first_ip || last_ip != 0xFFFFFFFF)) ||
|
||||
netmask <= mask_bits)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
pr_debug("mask_bits %u, netmask %u", mask_bits, netmask);
|
||||
pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask);
|
||||
hosts = 2 << (32 - netmask - 1);
|
||||
elements = 2 << (netmask - mask_bits - 1);
|
||||
}
|
||||
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
|
||||
return -IPSET_ERR_BITMAP_RANGE_SIZE;
|
||||
|
||||
pr_debug("hosts %u, elements %u", hosts, elements);
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
struct bitmap_ip_timeout *map;
|
||||
pr_debug("hosts %u, elements %u\n", hosts, elements);
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->memsize = elements * sizeof(unsigned long);
|
||||
|
||||
if (!init_map_ip(set, (struct bitmap_ip *)map,
|
||||
first_ip, last_ip,
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->variant = &bitmap_ip_timeout;
|
||||
set->variant = &bitmap_tip;
|
||||
|
||||
bitmap_ip_gc_init(set);
|
||||
} else {
|
||||
struct bitmap_ip *map;
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
map->memsize = bitmap_bytes(0, elements - 1);
|
||||
|
||||
if (!init_map_ip(set, map,
|
||||
first_ip, last_ip,
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
@@ -708,6 +553,20 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
|
||||
.family = AF_INET,
|
||||
.revision = 0,
|
||||
.create = bitmap_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_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 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2011 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
|
||||
@@ -10,21 +10,18 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the bitmap:ip,mac type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/timer.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_bitmap.h"
|
||||
@@ -94,15 +91,15 @@ bitmap_expired(const struct bitmap_ipmac *map, u32 id)
|
||||
static inline int
|
||||
bitmap_ipmac_exist(const struct ipmac_telem *elem)
|
||||
{
|
||||
return elem->match == MAC_UNSET
|
||||
|| (elem->match == MAC_FILLED
|
||||
&& !ip_set_timeout_expired(elem->timeout));
|
||||
return elem->match == MAC_UNSET ||
|
||||
(elem->match == MAC_FILLED &&
|
||||
!ip_set_timeout_expired(elem->timeout));
|
||||
}
|
||||
|
||||
/* Base variant */
|
||||
|
||||
static int
|
||||
bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout)
|
||||
bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
@@ -113,14 +110,14 @@ bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout)
|
||||
/* Trigger kernel to fill out the ethernet address */
|
||||
return -EAGAIN;
|
||||
case MAC_FILLED:
|
||||
return data->ether == NULL
|
||||
|| compare_ether_addr(data->ether, elem->ether) == 0;
|
||||
return data->ether == NULL ||
|
||||
compare_ether_addr(data->ether, elem->ether) == 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout)
|
||||
bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
@@ -149,7 +146,7 @@ bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout)
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout)
|
||||
bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
@@ -175,7 +172,7 @@ bitmap_ipmac_list(const struct ip_set *set,
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
elem = bitmap_ipmac_elem(map, id);
|
||||
@@ -185,7 +182,7 @@ bitmap_ipmac_list(const struct ip_set *set,
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
@@ -205,13 +202,17 @@ bitmap_ipmac_list(const struct ip_set *set,
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
static int
|
||||
bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout)
|
||||
bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
@@ -222,23 +223,24 @@ bitmap_ipmac_ttest(struct ip_set *set, void *value, u32 timeout)
|
||||
/* Trigger kernel to fill out the ethernet address */
|
||||
return -EAGAIN;
|
||||
case MAC_FILLED:
|
||||
return (data->ether == NULL
|
||||
|| compare_ether_addr(data->ether, elem->ether) == 0)
|
||||
&& !bitmap_expired(map, data->id);
|
||||
return (data->ether == NULL ||
|
||||
compare_ether_addr(data->ether, elem->ether) == 0) &&
|
||||
!bitmap_expired(map, data->id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
|
||||
bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
|
||||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
|
||||
switch (elem->match) {
|
||||
case MAC_UNSET:
|
||||
if (!data->ether)
|
||||
if (!(data->ether || flag_exist))
|
||||
/* Already added without ethernet address */
|
||||
return -IPSET_ERR_EXIST;
|
||||
/* Fill the MAC address and activate the timer */
|
||||
@@ -250,7 +252,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
|
||||
elem->timeout = ip_set_timeout_set(timeout);
|
||||
break;
|
||||
case MAC_FILLED:
|
||||
if (!bitmap_expired(map, data->id))
|
||||
if (!(bitmap_expired(map, data->id) || flag_exist))
|
||||
return -IPSET_ERR_EXIST;
|
||||
/* Fall through */
|
||||
case MAC_EMPTY:
|
||||
@@ -272,7 +274,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout)
|
||||
bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
@@ -298,7 +300,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
elem = bitmap_ipmac_elem(map, id);
|
||||
@@ -308,7 +310,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
@@ -331,7 +333,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
return 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -342,51 +344,45 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct ipmac data;
|
||||
|
||||
/* MAC can be src only */
|
||||
if (!(flags & IPSET_DIM_TWO_SRC))
|
||||
return 0;
|
||||
|
||||
data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
||||
if (data.id < map->first_ip || data.id > map->last_ip)
|
||||
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)
|
||||
if (skb_mac_header(skb) < skb->head ||
|
||||
(skb_mac_header(skb) + ETH_HLEN) > skb->data)
|
||||
return -EINVAL;
|
||||
|
||||
data.id -= map->first_ip;
|
||||
data.ether = eth_hdr(skb)->h_source;
|
||||
|
||||
return adtfn(set, &data, map->timeout);
|
||||
return adtfn(set, &data, map->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy
|
||||
bitmap_ipmac_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct ipmac data;
|
||||
u32 timeout = map->timeout;
|
||||
int ret = 0;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
bitmap_ipmac_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.id);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &data.id);
|
||||
if (ret)
|
||||
return ret;
|
||||
data.id = ntohl(data.id);
|
||||
|
||||
if (data.id < map->first_ip || data.id > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
@@ -404,7 +400,7 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
data.id -= map->first_ip;
|
||||
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
@@ -443,8 +439,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
|
||||
goto nla_put_failure;
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
||||
htonl(atomic_read(&set->ref) - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map)
|
||||
+ (map->last_ip - map->first_ip + 1) * map->dsize));
|
||||
@@ -454,7 +449,7 @@ bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -463,12 +458,12 @@ 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
|
||||
&& x->timeout == y->timeout;
|
||||
return x->first_ip == y->first_ip &&
|
||||
x->last_ip == y->last_ip &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
const struct ip_set_type_variant bitmap_ipmac = {
|
||||
static const struct ip_set_type_variant bitmap_ipmac = {
|
||||
.kadt = bitmap_ipmac_kadt,
|
||||
.uadt = bitmap_ipmac_uadt,
|
||||
.adt = {
|
||||
@@ -483,7 +478,7 @@ const struct ip_set_type_variant bitmap_ipmac = {
|
||||
.same_set = bitmap_ipmac_same_set,
|
||||
};
|
||||
|
||||
const struct ip_set_type_variant bitmap_tipmac = {
|
||||
static const struct ip_set_type_variant bitmap_tipmac = {
|
||||
.kadt = bitmap_ipmac_kadt,
|
||||
.uadt = bitmap_ipmac_uadt,
|
||||
.adt = {
|
||||
@@ -511,8 +506,8 @@ bitmap_ipmac_gc(unsigned long ul_set)
|
||||
read_lock_bh(&set->lock);
|
||||
for (id = 0; id <= last; id++) {
|
||||
elem = bitmap_ipmac_elem(map, id);
|
||||
if (elem->match == MAC_FILLED
|
||||
&& ip_set_timeout_expired(elem->timeout))
|
||||
if (elem->match == MAC_FILLED &&
|
||||
ip_set_timeout_expired(elem->timeout))
|
||||
elem->match = MAC_EMPTY;
|
||||
}
|
||||
read_unlock_bh(&set->lock);
|
||||
@@ -521,7 +516,7 @@ bitmap_ipmac_gc(unsigned long ul_set)
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
static void
|
||||
bitmap_ipmac_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
@@ -535,19 +530,11 @@ bitmap_ipmac_gc_init(struct ip_set *set)
|
||||
|
||||
/* Create bitmap:ip,mac type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
bitmap_ipmac_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static bool
|
||||
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
||||
u32 first_ip, u32 last_ip)
|
||||
{
|
||||
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize,
|
||||
GFP_KERNEL);
|
||||
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
map->first_ip = first_ip;
|
||||
@@ -561,28 +548,25 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
|
||||
u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
u32 first_ip, last_ip, elements;
|
||||
struct bitmap_ipmac *map;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
bitmap_ipmac_create_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &first_ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
first_ip = ntohl(first_ip);
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &last_ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
last_ip = ntohl(last_ip);
|
||||
if (first_ip > last_ip) {
|
||||
u32 tmp = first_ip;
|
||||
|
||||
@@ -594,7 +578,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
last_ip = first_ip | ~HOSTMASK(cidr);
|
||||
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
@@ -633,7 +617,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ip_set_type bitmap_ipmac_type = {
|
||||
static struct ip_set_type bitmap_ipmac_type = {
|
||||
.name = "bitmap:ip,mac",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
||||
@@ -641,6 +625,18 @@ struct ip_set_type bitmap_ipmac_type = {
|
||||
.family = AF_INET,
|
||||
.revision = 0,
|
||||
.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 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
514
extensions/ipset-6/ip_set_bitmap_port.c
Normal file
514
extensions/ipset-6/ip_set_bitmap_port.c
Normal file
@@ -0,0 +1,514 @@
|
||||
/* Copyright (C) 2003-2011 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 bitmap:port type */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/timer.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_bitmap.h"
|
||||
#include "ip_set_getport.h"
|
||||
#define IP_SET_BITMAP_TIMEOUT
|
||||
#include "ip_set_timeout.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("bitmap:port type of IP sets");
|
||||
MODULE_ALIAS("ip_set_bitmap:port");
|
||||
|
||||
/* Type structure */
|
||||
struct bitmap_port {
|
||||
void *members; /* the set members */
|
||||
u16 first_port; /* host byte order, included in range */
|
||||
u16 last_port; /* host byte order, included in range */
|
||||
size_t memsize; /* members size */
|
||||
u32 timeout; /* timeout parameter */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
};
|
||||
|
||||
/* Base variant */
|
||||
|
||||
static int
|
||||
bitmap_port_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_port *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
return !!test_bit(id, map->members);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (test_and_set_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (!test_and_clear_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_port *map = set->data;
|
||||
struct nlattr *atd, *nested;
|
||||
u16 id, first = cb->args[2];
|
||||
u16 last = map->last_port - map->first_port;
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!test_bit(id, map->members))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
|
||||
htons(map->first_port + id));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, atd);
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
static int
|
||||
bitmap_port_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_port *map = set->data;
|
||||
const unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
return ip_set_timeout_test(members[id]);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
members[id] = ip_set_timeout_set(timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
int ret = -IPSET_ERR_EXIST;
|
||||
|
||||
if (ip_set_timeout_test(members[id]))
|
||||
ret = 0;
|
||||
|
||||
members[id] = IPSET_ELEM_UNSET;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_tlist(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_port *map = set->data;
|
||||
struct nlattr *adt, *nested;
|
||||
u16 id, first = cb->args[2];
|
||||
u16 last = map->last_port - map->first_port;
|
||||
const unsigned long *members = map->members;
|
||||
|
||||
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!adt)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!ip_set_timeout_test(members[id]))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, adt);
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT,
|
||||
htons(map->first_port + id));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(members[id])));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, adt);
|
||||
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, adt);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
__be16 __port;
|
||||
u16 port = 0;
|
||||
|
||||
if (!ip_set_get_ip_port(skb, pf, flags & IPSET_DIM_ONE_SRC, &__port))
|
||||
return -EINVAL;
|
||||
|
||||
port = ntohs(__port);
|
||||
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
port -= map->first_port;
|
||||
|
||||
return adtfn(set, &port, map->timeout, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 timeout = map->timeout;
|
||||
u32 port; /* wraparound */
|
||||
u16 id, port_to;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
|
||||
if (port < map->first_port || port > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(map->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST) {
|
||||
id = port - map->first_port;
|
||||
return adtfn(set, &id, timeout, flags);
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to) {
|
||||
swap(port, port_to);
|
||||
if (port < map->first_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
}
|
||||
} else
|
||||
port_to = port;
|
||||
|
||||
if (port_to > map->last_port)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
id = port - map->first_port;
|
||||
ret = adtfn(set, &id, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_port_destroy(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
|
||||
if (with_timeout(map->timeout))
|
||||
del_timer_sync(&map->gc);
|
||||
|
||||
ip_set_free(map->members);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_port_flush(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
|
||||
memset(map->members, 0, map->memsize);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct bitmap_port *map = set->data;
|
||||
struct nlattr *nested;
|
||||
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, htons(map->first_port));
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT_TO, htons(map->last_port));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->memsize));
|
||||
if (with_timeout(map->timeout))
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static bool
|
||||
bitmap_port_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
{
|
||||
const struct bitmap_port *x = a->data;
|
||||
const struct bitmap_port *y = b->data;
|
||||
|
||||
return x->first_port == y->first_port &&
|
||||
x->last_port == y->last_port &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
static const struct ip_set_type_variant bitmap_port = {
|
||||
.kadt = bitmap_port_kadt,
|
||||
.uadt = bitmap_port_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_port_add,
|
||||
[IPSET_DEL] = bitmap_port_del,
|
||||
[IPSET_TEST] = bitmap_port_test,
|
||||
},
|
||||
.destroy = bitmap_port_destroy,
|
||||
.flush = bitmap_port_flush,
|
||||
.head = bitmap_port_head,
|
||||
.list = bitmap_port_list,
|
||||
.same_set = bitmap_port_same_set,
|
||||
};
|
||||
|
||||
static const struct ip_set_type_variant bitmap_tport = {
|
||||
.kadt = bitmap_port_kadt,
|
||||
.uadt = bitmap_port_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_port_tadd,
|
||||
[IPSET_DEL] = bitmap_port_tdel,
|
||||
[IPSET_TEST] = bitmap_port_ttest,
|
||||
},
|
||||
.destroy = bitmap_port_destroy,
|
||||
.flush = bitmap_port_flush,
|
||||
.head = bitmap_port_head,
|
||||
.list = bitmap_port_tlist,
|
||||
.same_set = bitmap_port_same_set,
|
||||
};
|
||||
|
||||
static void
|
||||
bitmap_port_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct bitmap_port *map = set->data;
|
||||
unsigned long *table = map->members;
|
||||
u32 id; /* wraparound */
|
||||
u16 last = map->last_port - map->first_port;
|
||||
|
||||
/* We run parallel with other readers (test element)
|
||||
* but adding/deleting new entries is locked out */
|
||||
read_lock_bh(&set->lock);
|
||||
for (id = 0; id <= last; id++)
|
||||
if (ip_set_timeout_expired(table[id]))
|
||||
table[id] = IPSET_ELEM_UNSET;
|
||||
read_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_port_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = bitmap_port_gc;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
/* Create bitmap:ip type of sets */
|
||||
|
||||
static bool
|
||||
init_map_port(struct ip_set *set, struct bitmap_port *map,
|
||||
u16 first_port, u16 last_port)
|
||||
{
|
||||
map->members = ip_set_alloc(map->memsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
map->first_port = first_port;
|
||||
map->last_port = last_port;
|
||||
map->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
set->data = map;
|
||||
set->family = AF_UNSPEC;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_create(struct ip_set *set, struct nlattr *tb[],
|
||||
u32 flags)
|
||||
{
|
||||
struct bitmap_port *map;
|
||||
u16 first_port, last_port;
|
||||
|
||||
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
first_port = ip_set_get_h16(tb[IPSET_ATTR_PORT]);
|
||||
last_port = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (first_port > last_port) {
|
||||
u16 tmp = first_port;
|
||||
|
||||
first_port = last_port;
|
||||
last_port = tmp;
|
||||
}
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->memsize = (last_port - first_port + 1)
|
||||
* sizeof(unsigned long);
|
||||
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->variant = &bitmap_tport;
|
||||
|
||||
bitmap_port_gc_init(set);
|
||||
} else {
|
||||
map->memsize = bitmap_bytes(0, last_port - first_port);
|
||||
pr_debug("memsize: %zu\n", map->memsize);
|
||||
if (!init_map_port(set, map, first_port, last_port)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
set->variant = &bitmap_port;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type bitmap_port_type = {
|
||||
.name = "bitmap:port",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.create = bitmap_port_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
bitmap_port_init(void)
|
||||
{
|
||||
return ip_set_type_register(&bitmap_port_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
bitmap_port_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&bitmap_port_type);
|
||||
}
|
||||
|
||||
module_init(bitmap_port_init);
|
||||
module_exit(bitmap_port_fini);
|
File diff suppressed because it is too large
Load Diff
155
extensions/ipset-6/ip_set_getport.c
Normal file
155
extensions/ipset-6/ip_set_getport.c
Normal file
@@ -0,0 +1,155 @@
|
||||
/* Copyright (C) 2003-2011 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.
|
||||
*/
|
||||
|
||||
/* Get Layer-4 data from the packets */
|
||||
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/icmp.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/sctp.h>
|
||||
#include <linux/netfilter_ipv6/ip6_tables.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
|
||||
#include "ip_set_getport.h"
|
||||
|
||||
/* We must handle non-linear skbs */
|
||||
static bool
|
||||
get_port(const struct sk_buff *skb, int protocol, unsigned int protooff,
|
||||
bool src, __be16 *port, u8 *proto)
|
||||
{
|
||||
switch (protocol) {
|
||||
case IPPROTO_TCP: {
|
||||
struct tcphdr _tcph;
|
||||
const struct tcphdr *th;
|
||||
|
||||
th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph);
|
||||
if (th == NULL)
|
||||
/* No choice either */
|
||||
return false;
|
||||
|
||||
*port = src ? th->source : th->dest;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_SCTP: {
|
||||
sctp_sctphdr_t _sh;
|
||||
const sctp_sctphdr_t *sh;
|
||||
|
||||
sh = skb_header_pointer(skb, protooff, sizeof(_sh), &_sh);
|
||||
if (sh == NULL)
|
||||
/* No choice either */
|
||||
return false;
|
||||
|
||||
*port = src ? sh->source : sh->dest;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE: {
|
||||
struct udphdr _udph;
|
||||
const struct udphdr *uh;
|
||||
|
||||
uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph);
|
||||
if (uh == NULL)
|
||||
/* No choice either */
|
||||
return false;
|
||||
|
||||
*port = src ? uh->source : uh->dest;
|
||||
break;
|
||||
}
|
||||
case IPPROTO_ICMP: {
|
||||
struct icmphdr _ich;
|
||||
const struct icmphdr *ic;
|
||||
|
||||
ic = skb_header_pointer(skb, protooff, sizeof(_ich), &_ich);
|
||||
if (ic == NULL)
|
||||
return false;
|
||||
|
||||
*port = (__force __be16)htons((ic->type << 8) | ic->code);
|
||||
break;
|
||||
}
|
||||
case IPPROTO_ICMPV6: {
|
||||
struct icmp6hdr _ich;
|
||||
const struct icmp6hdr *ic;
|
||||
|
||||
ic = skb_header_pointer(skb, protooff, sizeof(_ich), &_ich);
|
||||
if (ic == NULL)
|
||||
return false;
|
||||
|
||||
*port = (__force __be16)
|
||||
htons((ic->icmp6_type << 8) | ic->icmp6_code);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*proto = protocol;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
|
||||
__be16 *port, u8 *proto)
|
||||
{
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
unsigned int protooff = ip_hdrlen(skb);
|
||||
int protocol = iph->protocol;
|
||||
|
||||
/* See comments at tcp_match in ip_tables.c */
|
||||
if (protocol <= 0 || (ntohs(iph->frag_off) & IP_OFFSET))
|
||||
return false;
|
||||
|
||||
return get_port(skb, protocol, protooff, src, port, proto);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_ip4_port);
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
bool
|
||||
ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
|
||||
__be16 *port, u8 *proto)
|
||||
{
|
||||
int protoff;
|
||||
u8 nexthdr;
|
||||
|
||||
nexthdr = ipv6_hdr(skb)->nexthdr;
|
||||
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr);
|
||||
if (protoff < 0)
|
||||
return false;
|
||||
|
||||
return get_port(skb, nexthdr, protoff, src, port, proto);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_ip6_port);
|
||||
#endif
|
||||
|
||||
bool
|
||||
ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src, __be16 *port)
|
||||
{
|
||||
bool ret;
|
||||
u8 proto;
|
||||
|
||||
switch (pf) {
|
||||
case AF_INET:
|
||||
ret = ip_set_get_ip4_port(skb, src, port, &proto);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ret = ip_set_get_ip6_port(skb, src, port, &proto);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (!ret)
|
||||
return ret;
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_UDP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_get_ip_port);
|
33
extensions/ipset-6/ip_set_getport.h
Normal file
33
extensions/ipset-6/ip_set_getport.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef _IP_SET_GETPORT_H
|
||||
#define _IP_SET_GETPORT_H
|
||||
|
||||
extern bool ip_set_get_ip4_port(const struct sk_buff *skb, bool src,
|
||||
__be16 *port, u8 *proto);
|
||||
|
||||
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
|
||||
extern bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
|
||||
__be16 *port, u8 *proto);
|
||||
#else
|
||||
static inline bool ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
|
||||
__be16 *port, u8 *proto)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern bool ip_set_get_ip_port(const struct sk_buff *skb, u8 pf, bool src,
|
||||
__be16 *port);
|
||||
|
||||
static inline bool ip_set_proto_with_ports(u8 proto)
|
||||
{
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_SCTP:
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /*_IP_SET_GETPORT_H*/
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2011 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
|
||||
@@ -7,15 +7,11 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:ip type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
@@ -23,6 +19,7 @@
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_hash.h"
|
||||
@@ -45,12 +42,12 @@ hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ip4_elem {
|
||||
u32 ip;
|
||||
__be32 ip;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ip4_telem {
|
||||
u32 ip;
|
||||
__be32 ip;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
@@ -73,12 +70,6 @@ hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
|
||||
dst->ip = src->ip;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ip4_data_swap(struct hash_ip4_elem *dst, struct hash_ip4_elem *src)
|
||||
{
|
||||
swap(dst->ip, src->ip);
|
||||
}
|
||||
|
||||
/* Zero valued IP addresses cannot be stored */
|
||||
static inline void
|
||||
hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
|
||||
@@ -96,7 +87,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
|
||||
{
|
||||
const struct hash_ip4_telem *tdata =
|
||||
@@ -123,48 +114,38 @@ hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 ip;
|
||||
__be32 ip;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
|
||||
ip &= NETMASK(h->netmask);
|
||||
ip &= ip_set_netmask(h->netmask);
|
||||
if (ip == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return adtfn(set, &ip, h->timeout);
|
||||
return adtfn(set, &ip, h->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy hash_ip4_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[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 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 ip, nip, ip_to, hosts, timeout = h->timeout;
|
||||
u32 ip, ip_to, hosts, timeout = h->timeout;
|
||||
__be32 nip;
|
||||
int ret = 0;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ip4_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ip &= NETMASK(h->netmask);
|
||||
if (ip == 0)
|
||||
return -IPSET_ERR_HASH_ELEM;
|
||||
ip &= ip_set_hostmask(h->netmask);
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -172,15 +153,17 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST)
|
||||
return adtfn(set, &ip, timeout);
|
||||
if (adt == IPSET_TEST) {
|
||||
nip = htonl(ip);
|
||||
if (nip == 0)
|
||||
return -IPSET_ERR_HASH_ELEM;
|
||||
return adtfn(set, &nip, timeout, flags);
|
||||
}
|
||||
|
||||
ip = ntohl(ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip_to = ntohl(ip_to);
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
@@ -188,8 +171,8 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= HOSTMASK(cidr);
|
||||
ip_to = ip | ~HOSTMASK(cidr);
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -197,7 +180,9 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
for (; !before(ip_to, ip); ip += hosts) {
|
||||
nip = htonl(ip);
|
||||
ret = adtfn(set, &nip, timeout);
|
||||
if (nip == 0)
|
||||
return -IPSET_ERR_HASH_ELEM;
|
||||
ret = adtfn(set, &nip, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -214,9 +199,9 @@ hash_ip_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct ip_set_hash *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem
|
||||
&& x->timeout == y->timeout
|
||||
&& x->netmask == y->netmask;
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout &&
|
||||
x->netmask == y->netmask;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
@@ -249,16 +234,6 @@ hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
|
||||
ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ip6_data_swap(struct hash_ip6_elem *dst, struct hash_ip6_elem *src)
|
||||
{
|
||||
struct in6_addr tmp;
|
||||
|
||||
ipv6_addr_copy(&tmp, &dst->ip.in6);
|
||||
ipv6_addr_copy(&dst->ip.in6, &src->ip.in6);
|
||||
ipv6_addr_copy(&src->ip.in6, &tmp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
|
||||
{
|
||||
@@ -268,13 +243,13 @@ hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
@@ -284,7 +259,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
|
||||
{
|
||||
const struct hash_ip6_telem *e =
|
||||
@@ -319,7 +294,7 @@ hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
if (ipv6_addr_any(&ip.in6))
|
||||
return -EINVAL;
|
||||
|
||||
return adtfn(set, &ip, h->timeout);
|
||||
return adtfn(set, &ip, h->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
@@ -329,24 +304,25 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
union nf_inet_addr ip;
|
||||
u32 timeout = h->timeout;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ip6_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &ip);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -360,27 +336,16 @@ hash_ip6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
ret = adtfn(set, &ip, timeout);
|
||||
ret = adtfn(set, &ip, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
hash_ip_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 netmask, hbits;
|
||||
struct ip_set_hash *h;
|
||||
@@ -388,11 +353,12 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
netmask = set->family == AF_INET ? 32 : 128;
|
||||
pr_debug("Create set %s with family %s",
|
||||
pr_debug("Create set %s with family %s\n",
|
||||
set->name, set->family == AF_INET ? "inet" : "inet6");
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
hash_ip_create_policy))
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
@@ -407,9 +373,9 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
if (tb[IPSET_ATTR_NETMASK]) {
|
||||
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
|
||||
|
||||
if ((set->family == AF_INET && netmask > 32)
|
||||
|| (set->family == AF_INET6 && netmask > 128)
|
||||
|| netmask == 0)
|
||||
if ((set->family == AF_INET && netmask > 32) ||
|
||||
(set->family == AF_INET6 && netmask > 128) ||
|
||||
netmask == 0)
|
||||
return -IPSET_ERR_INVALID_NETMASK;
|
||||
}
|
||||
|
||||
@@ -425,8 +391,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
@@ -450,7 +415,7 @@ hash_ip_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
? &hash_ip4_variant : &hash_ip6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
@@ -465,6 +430,21 @@ static struct ip_set_type hash_ip_type __read_mostly = {
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.create = hash_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
|
||||
},
|
||||
.adt_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 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2011 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
|
||||
@@ -7,15 +7,11 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:ip,port type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
@@ -23,6 +19,7 @@
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
@@ -46,16 +43,16 @@ hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ipport4_elem {
|
||||
u32 ip;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ipport4_telem {
|
||||
u32 ip;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
@@ -65,9 +62,9 @@ static inline bool
|
||||
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
|
||||
const struct hash_ipport4_elem *ip2)
|
||||
{
|
||||
return ip1->ip == ip2->ip
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto;
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -85,22 +82,13 @@ hash_ipport4_data_copy(struct hash_ipport4_elem *dst,
|
||||
dst->proto = src->proto;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport4_data_swap(struct hash_ipport4_elem *dst,
|
||||
struct hash_ipport4_elem *src)
|
||||
{
|
||||
swap(dst->ip, src->ip);
|
||||
swap(dst->port, src->port);
|
||||
swap(dst->proto, src->proto);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipport4_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipport4_elem *data)
|
||||
{
|
||||
@@ -113,7 +101,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipport4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipport4_elem *data)
|
||||
{
|
||||
@@ -144,72 +132,56 @@ hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem data = { };
|
||||
|
||||
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy
|
||||
hash_ipport_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem data = { };
|
||||
u32 ip, ip_to, p, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ipport_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMP:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -217,20 +189,18 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
|
||||
|| tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||
tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip = ntohl(data.ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip_to = ntohl(ip_to);
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
@@ -238,24 +208,23 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= HOSTMASK(cidr);
|
||||
ip_to = ip | ~HOSTMASK(cidr);
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
port = ntohs(data.port);
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = port = ntohs(data.port);
|
||||
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
} else
|
||||
port_to = port;
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -272,22 +241,22 @@ hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct ip_set_hash *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem
|
||||
&& x->timeout == y->timeout;
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_ipport6_elem {
|
||||
union nf_inet_addr ip;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
struct hash_ipport6_telem {
|
||||
union nf_inet_addr ip;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
@@ -297,9 +266,9 @@ static inline bool
|
||||
hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
|
||||
const struct hash_ipport6_elem *ip2)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto;
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -315,24 +284,13 @@ hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport6_data_swap(struct hash_ipport6_elem *dst,
|
||||
struct hash_ipport6_elem *src)
|
||||
{
|
||||
struct hash_ipport6_elem tmp;
|
||||
|
||||
memcpy(&tmp, dst, sizeof(tmp));
|
||||
memcpy(dst, src, sizeof(tmp));
|
||||
memcpy(src, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipport6_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipport6_elem *data)
|
||||
{
|
||||
@@ -345,7 +303,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipport6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipport6_elem *data)
|
||||
{
|
||||
@@ -378,60 +336,58 @@ hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport6_elem data = { };
|
||||
|
||||
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport6_elem data = { };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ipport_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMPV6:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -439,10 +395,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
@@ -453,7 +407,7 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -465,20 +419,9 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
hash_ipport_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
@@ -486,8 +429,9 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
hash_ipport_create_policy))
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
@@ -510,8 +454,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
@@ -535,7 +478,7 @@ hash_ipport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
? &hash_ipport4_variant : &hash_ipport6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
@@ -548,8 +491,26 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.create = hash_ipport_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2011 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
|
||||
@@ -7,15 +7,11 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:ip,port,ip type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
@@ -23,6 +19,7 @@
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
@@ -46,18 +43,18 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ipportip4_elem {
|
||||
u32 ip;
|
||||
u32 ip2;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ipportip4_telem {
|
||||
u32 ip;
|
||||
u32 ip2;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
@@ -67,10 +64,10 @@ static inline bool
|
||||
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
|
||||
const struct hash_ipportip4_elem *ip2)
|
||||
{
|
||||
return ip1->ip == ip2->ip
|
||||
&& ip1->ip2 == ip2->ip2
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto;
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->ip2 == ip2->ip2 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -86,24 +83,13 @@ hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip4_data_swap(struct hash_ipportip4_elem *dst,
|
||||
struct hash_ipportip4_elem *src)
|
||||
{
|
||||
struct hash_ipportip4_elem tmp;
|
||||
|
||||
memcpy(&tmp, dst, sizeof(tmp));
|
||||
memcpy(dst, src, sizeof(tmp));
|
||||
memcpy(src, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportip4_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportip4_elem *data)
|
||||
{
|
||||
@@ -117,7 +103,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportip4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportip4_elem *data)
|
||||
{
|
||||
@@ -149,78 +135,61 @@ hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem data = { };
|
||||
|
||||
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy
|
||||
hash_ipportip_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem data = { };
|
||||
u32 ip, ip_to, p, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ipportip_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2);
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMP:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -228,20 +197,18 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
|
||||
|| tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||
tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip = ntohl(data.ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip_to = ntohl(ip_to);
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
@@ -249,24 +216,23 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= HOSTMASK(cidr);
|
||||
ip_to = ip | ~HOSTMASK(cidr);
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
port = ntohs(data.port);
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = port = ntohs(data.port);
|
||||
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
} else
|
||||
port_to = port;
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -283,8 +249,8 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct ip_set_hash *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem
|
||||
&& x->timeout == y->timeout;
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
@@ -292,7 +258,7 @@ hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
struct hash_ipportip6_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
@@ -300,7 +266,7 @@ struct hash_ipportip6_elem {
|
||||
struct hash_ipportip6_telem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
@@ -310,10 +276,10 @@ static inline bool
|
||||
hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
|
||||
const struct hash_ipportip6_elem *ip2)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
||||
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto;
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -329,24 +295,13 @@ hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip6_data_swap(struct hash_ipportip6_elem *dst,
|
||||
struct hash_ipportip6_elem *src)
|
||||
{
|
||||
struct hash_ipportip6_elem tmp;
|
||||
|
||||
memcpy(&tmp, dst, sizeof(tmp));
|
||||
memcpy(dst, src, sizeof(tmp));
|
||||
memcpy(src, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportip6_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportip6_elem *data)
|
||||
{
|
||||
@@ -360,7 +315,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportip6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportip6_elem *data)
|
||||
{
|
||||
@@ -394,65 +349,63 @@ hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip6_elem data = { };
|
||||
|
||||
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip6_elem data = { };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ipportip_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMPV6:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -460,10 +413,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
@@ -474,7 +425,7 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -486,20 +437,9 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
hash_ipportip_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ipportip_create(struct ip_set *set, struct nlattr *head,
|
||||
int len, u32 flags)
|
||||
hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
@@ -507,8 +447,9 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
|
||||
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
hash_ipportip_create_policy))
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
@@ -531,8 +472,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
@@ -556,7 +496,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
|
||||
? &hash_ipportip4_variant : &hash_ipportip6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
@@ -569,8 +509,26 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.create = hash_ipportip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2011 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
|
||||
@@ -7,15 +7,11 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:ip,port,net type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include "jhash.h"
|
||||
#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/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
@@ -23,6 +19,7 @@
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
@@ -46,18 +43,18 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ipportnet4_elem {
|
||||
u32 ip;
|
||||
u32 ip2;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ipportnet4_telem {
|
||||
u32 ip;
|
||||
u32 ip2;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
unsigned long timeout;
|
||||
@@ -67,11 +64,11 @@ static inline bool
|
||||
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
|
||||
const struct hash_ipportnet4_elem *ip2)
|
||||
{
|
||||
return ip1->ip == ip2->ip
|
||||
&& ip1->ip2 == ip2->ip2
|
||||
&& ip1->cidr == ip2->cidr
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto;
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->ip2 == ip2->ip2 &&
|
||||
ip1->cidr == ip2->cidr &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -87,21 +84,10 @@ hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet4_data_swap(struct hash_ipportnet4_elem *dst,
|
||||
struct hash_ipportnet4_elem *src)
|
||||
{
|
||||
struct hash_ipportnet4_elem tmp;
|
||||
|
||||
memcpy(&tmp, dst, sizeof(tmp));
|
||||
memcpy(dst, src, sizeof(tmp));
|
||||
memcpy(src, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
|
||||
{
|
||||
elem->ip2 &= NETMASK(cidr);
|
||||
elem->ip2 &= ip_set_netmask(cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
@@ -111,7 +97,7 @@ hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportnet4_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportnet4_elem *data)
|
||||
{
|
||||
@@ -126,7 +112,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportnet4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportnet4_elem *data)
|
||||
{
|
||||
@@ -168,55 +154,43 @@ hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
data.ip2 &= NETMASK(data.cidr);
|
||||
data.ip2 &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy
|
||||
hash_ipportnet_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
|
||||
u32 ip, ip_to, p, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ipportnet_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP2, &data.ip2);
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -226,30 +200,24 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
data.ip2 &= NETMASK(data.cidr);
|
||||
data.ip2 &= ip_set_netmask(data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMP:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -257,20 +225,18 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
|
||||
|| tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||
tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip = ntohl(data.ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP_TO, &ip_to);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
ip_to = ntohl(ip_to);
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
@@ -278,24 +244,23 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= HOSTMASK(cidr);
|
||||
ip_to = ip | ~HOSTMASK(cidr);
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
port = ntohs(data.port);
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = port = ntohs(data.port);
|
||||
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
} else
|
||||
port_to = port;
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -312,8 +277,8 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct ip_set_hash *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem
|
||||
&& x->timeout == y->timeout;
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
@@ -321,7 +286,7 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
struct hash_ipportnet6_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
};
|
||||
@@ -329,7 +294,7 @@ struct hash_ipportnet6_elem {
|
||||
struct hash_ipportnet6_telem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
unsigned long timeout;
|
||||
@@ -339,11 +304,11 @@ static inline bool
|
||||
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
|
||||
const struct hash_ipportnet6_elem *ip2)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
||||
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
|
||||
&& ip1->cidr == ip2->cidr
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto;
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
|
||||
ip1->cidr == ip2->cidr &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -359,17 +324,6 @@ hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet6_data_swap(struct hash_ipportnet6_elem *dst,
|
||||
struct hash_ipportnet6_elem *src)
|
||||
{
|
||||
struct hash_ipportnet6_elem tmp;
|
||||
|
||||
memcpy(&tmp, dst, sizeof(tmp));
|
||||
memcpy(dst, src, sizeof(tmp));
|
||||
memcpy(src, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
|
||||
{
|
||||
@@ -379,10 +333,10 @@ hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -392,7 +346,7 @@ hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportnet6_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportnet6_elem *data)
|
||||
{
|
||||
@@ -407,7 +361,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_ipportnet6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportnet6_elem *data)
|
||||
{
|
||||
@@ -448,7 +402,7 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
@@ -456,33 +410,37 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
ip6_netmask(&data.ip2, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_ipportnet_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP2, &data.ip2);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -495,27 +453,21 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
ip6_netmask(&data.ip2, data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMPV6:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -523,10 +475,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
@@ -537,7 +487,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -549,20 +499,9 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
hash_ipportnet_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
||||
int len, u32 flags)
|
||||
hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
@@ -570,8 +509,9 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
||||
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
hash_ipportnet_create_policy))
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
@@ -596,8 +536,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
@@ -622,7 +561,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
||||
? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
@@ -635,8 +574,27 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.create = hash_ipportnet_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP2] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_CIDR2] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2011 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
|
||||
@@ -7,21 +7,18 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:net type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_hash.h"
|
||||
@@ -44,7 +41,7 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_net4_elem {
|
||||
u32 ip;
|
||||
__be32 ip;
|
||||
u16 padding0;
|
||||
u8 padding1;
|
||||
u8 cidr;
|
||||
@@ -52,7 +49,7 @@ struct hash_net4_elem {
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_net4_telem {
|
||||
u32 ip;
|
||||
__be32 ip;
|
||||
u16 padding0;
|
||||
u8 padding1;
|
||||
u8 cidr;
|
||||
@@ -80,18 +77,10 @@ hash_net4_data_copy(struct hash_net4_elem *dst,
|
||||
dst->cidr = src->cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net4_data_swap(struct hash_net4_elem *dst,
|
||||
struct hash_net4_elem *src)
|
||||
{
|
||||
swap(dst->ip, src->ip);
|
||||
swap(dst->cidr, src->cidr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
|
||||
{
|
||||
elem->ip &= NETMASK(cidr);
|
||||
elem->ip &= ip_set_netmask(cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
@@ -102,7 +91,7 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem)
|
||||
elem->cidr = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
@@ -113,7 +102,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
|
||||
{
|
||||
const struct hash_net4_telem *tdata =
|
||||
@@ -150,36 +139,29 @@ hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= NETMASK(data.cidr);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy hash_net_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net4_elem data = { .cidr = HOST_MASK };
|
||||
u32 timeout = h->timeout;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_net_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -189,7 +171,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
data.ip &= NETMASK(data.cidr);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -197,7 +179,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
@@ -209,8 +191,8 @@ hash_net_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct ip_set_hash *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem
|
||||
&& x->timeout == y->timeout;
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
@@ -234,8 +216,8 @@ static inline bool
|
||||
hash_net6_data_equal(const struct hash_net6_elem *ip1,
|
||||
const struct hash_net6_elem *ip2)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
||||
&& ip1->cidr == ip2->cidr;
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->cidr == ip2->cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -252,16 +234,6 @@ hash_net6_data_copy(struct hash_net6_elem *dst,
|
||||
dst->cidr = src->cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net6_data_swap(struct hash_net6_elem *dst, struct hash_net6_elem *src)
|
||||
{
|
||||
struct hash_net6_elem tmp;
|
||||
|
||||
memcpy(&tmp, dst, sizeof(tmp));
|
||||
memcpy(dst, src, sizeof(tmp));
|
||||
memcpy(src, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net6_data_zero_out(struct hash_net6_elem *elem)
|
||||
{
|
||||
@@ -271,10 +243,10 @@ hash_net6_data_zero_out(struct hash_net6_elem *elem)
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -284,7 +256,7 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
@@ -295,7 +267,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
|
||||
{
|
||||
const struct hash_net6_telem *e =
|
||||
@@ -334,28 +306,27 @@ hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net6_elem data = { .cidr = HOST_MASK };
|
||||
u32 timeout = h->timeout;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_net_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -373,26 +344,16 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
hash_net_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
struct ip_set_hash *h;
|
||||
u8 hbits;
|
||||
@@ -400,8 +361,9 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
hash_net_create_policy))
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
@@ -426,8 +388,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
@@ -451,7 +412,7 @@ hash_net_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
? &hash_net4_variant : &hash_net6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
@@ -466,6 +427,18 @@ static struct ip_set_type hash_net_type __read_mostly = {
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.create = hash_net_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2011 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
|
||||
@@ -7,21 +7,18 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the hash:net,port type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
@@ -45,16 +42,16 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_netport4_elem {
|
||||
u32 ip;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_netport4_telem {
|
||||
u32 ip;
|
||||
u16 port;
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
@@ -64,10 +61,10 @@ static inline bool
|
||||
hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
|
||||
const struct hash_netport4_elem *ip2)
|
||||
{
|
||||
return ip1->ip == ip2->ip
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto
|
||||
&& ip1->cidr == ip2->cidr;
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto &&
|
||||
ip1->cidr == ip2->cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -86,20 +83,10 @@ hash_netport4_data_copy(struct hash_netport4_elem *dst,
|
||||
dst->cidr = src->cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport4_data_swap(struct hash_netport4_elem *dst,
|
||||
struct hash_netport4_elem *src)
|
||||
{
|
||||
swap(dst->ip, src->ip);
|
||||
swap(dst->port, src->port);
|
||||
swap(dst->proto, src->proto);
|
||||
swap(dst->cidr, src->cidr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
|
||||
{
|
||||
elem->ip &= NETMASK(cidr);
|
||||
elem->ip &= ip_set_netmask(cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
@@ -109,7 +96,7 @@ hash_netport4_data_zero_out(struct hash_netport4_elem *elem)
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_netport4_data_list(struct sk_buff *skb,
|
||||
const struct hash_netport4_elem *data)
|
||||
{
|
||||
@@ -123,7 +110,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_netport4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_netport4_elem *data)
|
||||
{
|
||||
@@ -164,47 +151,38 @@ hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= NETMASK(data.cidr);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static const struct nla_policy
|
||||
hash_netport_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport4_elem data = { .cidr = HOST_MASK };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_netport_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -212,30 +190,24 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
data.ip &= NETMASK(data.cidr);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMP:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -243,10 +215,8 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
@@ -257,7 +227,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -274,22 +244,22 @@ hash_netport_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct ip_set_hash *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem
|
||||
&& x->timeout == y->timeout;
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_netport6_elem {
|
||||
union nf_inet_addr ip;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
};
|
||||
|
||||
struct hash_netport6_telem {
|
||||
union nf_inet_addr ip;
|
||||
u16 port;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
@@ -299,10 +269,10 @@ static inline bool
|
||||
hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
|
||||
const struct hash_netport6_elem *ip2)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
||||
&& ip1->port == ip2->port
|
||||
&& ip1->proto == ip2->proto
|
||||
&& ip1->cidr == ip2->cidr;
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto &&
|
||||
ip1->cidr == ip2->cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -318,17 +288,6 @@ hash_netport6_data_copy(struct hash_netport6_elem *dst,
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport6_data_swap(struct hash_netport6_elem *dst,
|
||||
struct hash_netport6_elem *src)
|
||||
{
|
||||
struct hash_netport6_elem tmp;
|
||||
|
||||
memcpy(&tmp, dst, sizeof(tmp));
|
||||
memcpy(dst, src, sizeof(tmp));
|
||||
memcpy(src, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
|
||||
{
|
||||
@@ -338,10 +297,10 @@ hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -351,7 +310,7 @@ hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_netport6_data_list(struct sk_buff *skb,
|
||||
const struct hash_netport6_elem *data)
|
||||
{
|
||||
@@ -365,7 +324,7 @@ nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
hash_netport6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_netport6_elem *data)
|
||||
{
|
||||
@@ -405,36 +364,38 @@ hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout);
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport6_elem data = { .cidr = HOST_MASK };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
hash_netport_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb, IPSET_ATTR_IP, &data.ip);
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -445,27 +406,21 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = ip_set_get_n16(tb[IPSET_ATTR_PORT]);
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
switch (data.proto) {
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_ICMPV6:
|
||||
break;
|
||||
default:
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -473,10 +428,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST
|
||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout);
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
@@ -487,7 +440,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
@@ -499,20 +452,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
hash_netport_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
@@ -520,8 +462,9 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
hash_netport_create_policy))
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
@@ -546,8 +489,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
||||
GFP_KERNEL);
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
@@ -571,7 +513,7 @@ hash_netport_create(struct ip_set *set, struct nlattr *head, int len, u32 flags)
|
||||
? &hash_netport4_variant : &hash_netport6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)",
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
@@ -584,8 +526,25 @@ static struct ip_set_type hash_netport_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.create = hash_netport_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PORT_TO] = { .type = NLA_U16 },
|
||||
[IPSET_ATTR_PROTO] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2008-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2008-2011 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
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
/* Kernel module implementing an IP set type: the list:set type */
|
||||
|
||||
#include "ip_set_kernel.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
@@ -44,14 +43,19 @@ struct list_set {
|
||||
static inline struct set_elem *
|
||||
list_set_elem(const struct list_set *map, u32 id)
|
||||
{
|
||||
return (struct set_elem *)((char *)map->members + id * map->dsize);
|
||||
return (struct set_elem *)((void *)map->members + id * map->dsize);
|
||||
}
|
||||
|
||||
static inline struct set_telem *
|
||||
list_set_telem(const struct list_set *map, u32 id)
|
||||
{
|
||||
return (struct set_telem *)((void *)map->members + id * map->dsize);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
list_set_timeout(const struct list_set *map, u32 id)
|
||||
{
|
||||
const struct set_telem *elem =
|
||||
(const struct set_telem *) list_set_elem(map, id);
|
||||
const struct set_telem *elem = list_set_telem(map, id);
|
||||
|
||||
return ip_set_timeout_test(elem->timeout);
|
||||
}
|
||||
@@ -59,19 +63,11 @@ list_set_timeout(const struct list_set *map, u32 id)
|
||||
static inline bool
|
||||
list_set_expired(const struct list_set *map, u32 id)
|
||||
{
|
||||
const struct set_telem *elem =
|
||||
(const struct set_telem *) list_set_elem(map, id);
|
||||
const struct set_telem *elem = list_set_telem(map, id);
|
||||
|
||||
return ip_set_timeout_expired(elem->timeout);
|
||||
}
|
||||
|
||||
static inline int
|
||||
list_set_exist(const struct set_telem *elem)
|
||||
{
|
||||
return elem->id != IPSET_INVALID_ID
|
||||
&& !ip_set_timeout_expired(elem->timeout);
|
||||
}
|
||||
|
||||
/* Set list without and with timeout */
|
||||
|
||||
static int
|
||||
@@ -112,32 +108,35 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct nla_policy list_set_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
|
||||
[IPSET_ATTR_NAME] = { .type = NLA_STRING,
|
||||
.len = IPSET_MAXNAMELEN },
|
||||
[IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
|
||||
.len = IPSET_MAXNAMELEN },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static inline bool
|
||||
next_id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
|
||||
static bool
|
||||
id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
|
||||
{
|
||||
const struct set_elem *elem;
|
||||
|
||||
if (i + 1 < map->size) {
|
||||
elem = list_set_elem(map, i + 1);
|
||||
return !!(elem->id == id
|
||||
&& !(with_timeout(map->timeout)
|
||||
&& list_set_expired(map, i + 1)));
|
||||
if (i < map->size) {
|
||||
elem = list_set_elem(map, i);
|
||||
return elem->id == id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
static bool
|
||||
id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id)
|
||||
{
|
||||
const struct set_elem *elem;
|
||||
|
||||
if (i < map->size) {
|
||||
elem = list_set_elem(map, i);
|
||||
return !!(elem->id == id &&
|
||||
!(with_timeout(map->timeout) &&
|
||||
list_set_expired(map, i)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
|
||||
{
|
||||
struct set_elem *e;
|
||||
@@ -150,18 +149,18 @@ list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
static void
|
||||
list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
|
||||
unsigned long timeout)
|
||||
{
|
||||
struct set_telem *e;
|
||||
|
||||
for (; i < map->size; i++) {
|
||||
e = (struct set_telem *)list_set_elem(map, i);
|
||||
e = list_set_telem(map, i);
|
||||
swap(e->id, id);
|
||||
swap(e->timeout, timeout);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
break;
|
||||
swap(e->timeout, timeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +174,7 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
|
||||
/* Last element replaced: e.g. add new,before,last */
|
||||
ip_set_put_byindex(e->id);
|
||||
if (with_timeout(map->timeout))
|
||||
list_elem_tadd(map, i, id, timeout);
|
||||
list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
|
||||
else
|
||||
list_elem_add(map, i, id);
|
||||
|
||||
@@ -183,11 +182,11 @@ list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_del(struct list_set *map, ip_set_id_t id, u32 i)
|
||||
list_set_del(struct list_set *map, u32 i)
|
||||
{
|
||||
struct set_elem *a = list_set_elem(map, i), *b;
|
||||
|
||||
ip_set_put_byindex(id);
|
||||
ip_set_put_byindex(a->id);
|
||||
|
||||
for (; i < map->size - 1; i++) {
|
||||
b = list_set_elem(map, i + 1);
|
||||
@@ -204,13 +203,26 @@ list_set_del(struct list_set *map, ip_set_id_t id, u32 i)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_entries(struct list_set *map)
|
||||
{
|
||||
struct set_telem *e;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_telem(map, i);
|
||||
if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
|
||||
list_set_del(map, i);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
||||
bool with_timeout = with_timeout(map->timeout);
|
||||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
int before = 0;
|
||||
u32 timeout = map->timeout;
|
||||
ip_set_id_t id, refid = IPSET_INVALID_ID;
|
||||
@@ -219,14 +231,14 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
u32 i;
|
||||
int ret = 0;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
||||
list_set_adt_policy))
|
||||
if (unlikely(!tb[IPSET_ATTR_NAME] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
if (tb[IPSET_ATTR_NAME]) {
|
||||
id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
|
||||
if (id == IPSET_INVALID_ID)
|
||||
return -IPSET_ERR_NAME;
|
||||
@@ -235,8 +247,6 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
ret = -IPSET_ERR_LOOP;
|
||||
goto finish;
|
||||
}
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
@@ -265,33 +275,50 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
}
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
if (with_timeout && adt != IPSET_TEST)
|
||||
cleanup_entries(map);
|
||||
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
for (i = 0; i < map->size && !ret; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id == IPSET_INVALID_ID
|
||||
|| (before != 0 && i + 1 >= map->size))
|
||||
if (elem->id == IPSET_INVALID_ID ||
|
||||
(before != 0 && i + 1 >= map->size))
|
||||
break;
|
||||
else if (with_timeout && list_set_expired(map, i))
|
||||
continue;
|
||||
else if (before > 0 && elem->id == id)
|
||||
ret = next_id_eq(map, i, refid);
|
||||
ret = id_eq_timeout(map, i + 1, refid);
|
||||
else if (before < 0 && elem->id == refid)
|
||||
ret = next_id_eq(map, i, id);
|
||||
ret = id_eq_timeout(map, i + 1, id);
|
||||
else if (before == 0 && elem->id == id)
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
case IPSET_ADD:
|
||||
for (i = 0; i < map->size && !ret; i++) {
|
||||
for (i = 0; i < map->size; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id == id
|
||||
&& !(with_timeout && list_set_expired(map, i)))
|
||||
if (elem->id != id)
|
||||
continue;
|
||||
if (!(with_timeout && flag_exist)) {
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
goto finish;
|
||||
} else {
|
||||
struct set_telem *e = list_set_telem(map, i);
|
||||
|
||||
if ((before > 1 &&
|
||||
!id_eq(map, i + 1, refid)) ||
|
||||
(before < 0 &&
|
||||
(i == 0 || !id_eq(map, i - 1, refid)))) {
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
goto finish;
|
||||
}
|
||||
e->timeout = ip_set_timeout_set(timeout);
|
||||
ip_set_put_byindex(id);
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
if (ret == -IPSET_ERR_EXIST)
|
||||
break;
|
||||
ret = -IPSET_ERR_LIST_FULL;
|
||||
for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
@@ -300,9 +327,7 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
: list_set_add(map, i, id, timeout);
|
||||
else if (elem->id != refid)
|
||||
continue;
|
||||
else if (with_timeout && list_set_expired(map, i))
|
||||
ret = -IPSET_ERR_REF_EXIST;
|
||||
else if (before)
|
||||
else if (before > 0)
|
||||
ret = list_set_add(map, i, id, timeout);
|
||||
else if (i + 1 < map->size)
|
||||
ret = list_set_add(map, i + 1, id, timeout);
|
||||
@@ -316,17 +341,13 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
|
||||
ret = before != 0 ? -IPSET_ERR_REF_EXIST
|
||||
: -IPSET_ERR_EXIST;
|
||||
break;
|
||||
} else if (with_timeout && list_set_expired(map, i))
|
||||
continue;
|
||||
else if (elem->id == id
|
||||
&& (before == 0
|
||||
|| (before > 0
|
||||
&& next_id_eq(map, i, refid))))
|
||||
ret = list_set_del(map, id, i);
|
||||
else if (before < 0
|
||||
&& elem->id == refid
|
||||
&& next_id_eq(map, i, id))
|
||||
ret = list_set_del(map, id, i + 1);
|
||||
} else if (elem->id == id &&
|
||||
(before == 0 ||
|
||||
(before > 0 && id_eq(map, i + 1, refid))))
|
||||
ret = list_set_del(map, i);
|
||||
else if (elem->id == refid &&
|
||||
before < 0 && id_eq(map, i + 1, id))
|
||||
ret = list_set_del(map, i + 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -383,15 +404,14 @@ list_set_head(struct ip_set *set, struct sk_buff *skb)
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size));
|
||||
if (with_timeout(map->timeout))
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
||||
htonl(atomic_read(&set->ref) - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->size * map->dsize));
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -405,7 +425,7 @@ list_set_list(const struct ip_set *set,
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->size; cb->args[2]++) {
|
||||
i = cb->args[2];
|
||||
e = list_set_elem(map, i);
|
||||
@@ -417,7 +437,7 @@ list_set_list(const struct ip_set *set,
|
||||
if (!nested) {
|
||||
if (i == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EFAULT;
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
@@ -440,6 +460,10 @@ finish:
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
if (unlikely(i == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -449,8 +473,8 @@ list_set_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
const struct list_set *x = a->data;
|
||||
const struct list_set *y = b->data;
|
||||
|
||||
return x->size == y->size
|
||||
&& x->timeout == y->timeout;
|
||||
return x->size == y->size &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
static const struct ip_set_type_variant list_set = {
|
||||
@@ -468,25 +492,16 @@ list_set_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct list_set *map = set->data;
|
||||
struct set_telem *e;
|
||||
u32 i;
|
||||
|
||||
/* We run parallel with other readers (test element)
|
||||
* but adding/deleting new entries is locked out */
|
||||
read_lock_bh(&set->lock);
|
||||
for (i = map->size - 1; i >= 0; i--) {
|
||||
e = (struct set_telem *) list_set_elem(map, i);
|
||||
if (e->id != IPSET_INVALID_ID
|
||||
&& list_set_expired(map, i))
|
||||
list_set_del(map, e->id, i);
|
||||
}
|
||||
read_unlock_bh(&set->lock);
|
||||
write_lock_bh(&set->lock);
|
||||
cleanup_entries(map);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static inline void
|
||||
static void
|
||||
list_set_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
@@ -500,13 +515,7 @@ list_set_gc_init(struct ip_set *set)
|
||||
|
||||
/* Create list:set type of sets */
|
||||
|
||||
static const struct nla_policy
|
||||
list_set_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
||||
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static inline bool
|
||||
static bool
|
||||
init_list_set(struct ip_set *set, u32 size, size_t dsize,
|
||||
unsigned long timeout)
|
||||
{
|
||||
@@ -532,14 +541,12 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_create(struct ip_set *set, struct nlattr *head, int len,
|
||||
u32 flags)
|
||||
list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
||||
u32 size = IP_SET_LIST_DEFAULT_SIZE;
|
||||
|
||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
||||
list_set_create_policy))
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_SIZE])
|
||||
@@ -570,6 +577,19 @@ static struct ip_set_type list_set_type __read_mostly = {
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.create = list_set_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_NAME] = { .type = NLA_STRING,
|
||||
.len = IPSET_MAXNAMELEN },
|
||||
[IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
|
||||
.len = IPSET_MAXNAMELEN },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#ifndef _IP_SET_TIMEOUT_H
|
||||
#define _IP_SET_TIMEOUT_H
|
||||
|
||||
/* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
/* Copyright (C) 2003-2011 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
|
||||
@@ -43,17 +43,17 @@ ip_set_timeout_uget(struct nlattr *tb)
|
||||
static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET
|
||||
&& (timeout == IPSET_ELEM_PERMANENT
|
||||
|| time_after(timeout, jiffies));
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
(timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_after(timeout, jiffies));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET
|
||||
&& timeout != IPSET_ELEM_PERMANENT
|
||||
&& time_before(timeout, jiffies);
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_before(timeout, jiffies);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
@@ -88,15 +88,15 @@ ip_set_timeout_get(unsigned long timeout)
|
||||
static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT
|
||||
|| time_after(timeout, jiffies);
|
||||
return timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_after(timeout, jiffies);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_PERMANENT
|
||||
&& time_before(timeout, jiffies);
|
||||
return timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_before(timeout, jiffies);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
@@ -231,6 +231,8 @@ parameter for the \fBcreate\fR command means the default timeout value (in secon
|
||||
for new entries. If a set is created with timeout support, then the same
|
||||
\fBtimeout\fR option can be used to specify non\-default timeout values
|
||||
when adding entries. Zero timeout value means the entry is added permanent to the set.
|
||||
The timeout value of already added elements can be changed by readding the element
|
||||
using the \fB\-exist\fR option.
|
||||
.SS bitmap:ip
|
||||
The \fBbitmap:ip\fR set type uses a memory range to store either IPv4 host
|
||||
(default) or IPv4 network addresses. A \fBbitmap:ip\fR type of set can store up
|
||||
@@ -300,9 +302,10 @@ matched by the kernel, it will automatically fill out the missing MAC address wi
|
||||
source MAC address from the packet. If the entry was specified with a timeout value,
|
||||
the timer starts off when the IP and MAC address pair is complete.
|
||||
.PP
|
||||
Please note, the \fBset\fR match and \fBSET\fR target netfilter kernel modules
|
||||
\fBalways\fR use the source MAC address from the packet to match, add or delete
|
||||
entries from a \fBbitmap:ip,mac\fR type of set.
|
||||
The \fBbitmap:ip,mac\fR type of sets require two \fBsrc/dst\fR parameters of
|
||||
the \fBset\fR match and \fBSET\fR target netfilter kernel modules and the second
|
||||
one must be \fBsrc\fR to match, add or delete entries because the \fBset\fR match
|
||||
and \fBSET\fR target have access to the source MAC address only.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
@@ -330,6 +333,9 @@ Mandatory options to use when creating a \fBbitmap:port\fR type of set:
|
||||
\fBrange\fP \fIfromport\fP\-\fItoport\fR
|
||||
Create the set from the specified inclusive port range.
|
||||
.PP
|
||||
The \fBset\fR match and \fBSET\fR target netfilter kernel modules interpret
|
||||
the stored numbers as TCP or UDP port numbers.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo bitmap:port range 0\-1024
|
||||
@@ -380,9 +386,9 @@ a range or a network:
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:ip netmask 24
|
||||
ipset create foo hash:ip netmask 30
|
||||
.IP
|
||||
ipset add foo 192.168.1.1\-192.168.1.2
|
||||
ipset add foo 192.168.1.0/24
|
||||
.IP
|
||||
ipset test foo 192.168.1.2
|
||||
.SS hash:net
|
||||
@@ -414,8 +420,10 @@ correct value.
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
||||
then the host prefix value is assumed. When adding/deleting entries, overlapping
|
||||
elements are not checked.
|
||||
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||
element is added/deleted and overlapping elements are not checked by the kernel.
|
||||
When testing entries, if a host address is tested, then the kernel tries to match
|
||||
the host address in the networks added to the set and reports the result accordingly.
|
||||
.PP
|
||||
From the \fBset\fR netfilter match point of view the searching for a match
|
||||
always starts from the smallest size of netblock (most specific
|
||||
@@ -431,7 +439,7 @@ Examples:
|
||||
.IP
|
||||
ipset create foo hash:net
|
||||
.IP
|
||||
ipset add foo 192.168.0/24
|
||||
ipset add foo 192.168.0.0/24
|
||||
.IP
|
||||
ipset add foo 10.1.0.0/16
|
||||
.IP
|
||||
@@ -481,8 +489,8 @@ TCP port or range of ports expressed in TCP portname identifiers from /etc/servi
|
||||
\fIportnumber[\-portnumber]\fR
|
||||
TCP port or range of ports expressed in TCP port numbers
|
||||
.TP
|
||||
\fBtcp\fR|\fBudp\fR:\fIportname\fR|\fIportnumber\fR[\-\fIportname\fR|\fIportnumber\fR]
|
||||
TCP or UDP port or port range expressed in port name(s) or port number(s)
|
||||
\fBtcp\fR|\fBsctp\fR|\fBudp\fR|\fBudplite\fR:\fIportname\fR|\fIportnumber\fR[\-\fIportname\fR|\fIportnumber\fR]
|
||||
TCP, SCTP, UDP or UDPLITE port or port range expressed in port name(s) or port number(s)
|
||||
.TP
|
||||
\fBicmp\fR:\fIcodename\fR|\fItype\fR/\fIcode\fR
|
||||
ICMP codename or type/code. The supported ICMP codename identifiers can always
|
||||
@@ -508,7 +516,7 @@ ipset add foo 192.168.1.0/24,80\-82
|
||||
.IP
|
||||
ipset add foo 192.168.1.1,udp:53
|
||||
.IP
|
||||
ipset add foo 192.168.1.1,ospf:0
|
||||
ipset add foo 192.168.1.1,vrrp:0
|
||||
.IP
|
||||
ipset test foo 192.168.1.1,80
|
||||
.SS hash:net,port
|
||||
@@ -547,8 +555,10 @@ part of the elements see the description at the
|
||||
\fBhash:ip,port\fR set type.
|
||||
.PP
|
||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
||||
then the host prefix value is assumed. When adding/deleting entries, overlapping
|
||||
elements are not checked.
|
||||
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||
element is added/deleted and overlapping elements are not checked by the kernel.
|
||||
When testing entries, if a host address is tested, then the kernel tries to match
|
||||
the host address in the networks added to the set and reports the result accordingly.
|
||||
.PP
|
||||
From the \fBset\fR netfilter match point of view the searching for a match
|
||||
always starts from the smallest size of netblock (most specific
|
@@ -43,8 +43,8 @@ static const uint16_t cmdflags[] = {
|
||||
[IPSET_CMD_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_RENAME-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_SWAP-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_LIST-1] = NLM_F_REQUEST,
|
||||
[IPSET_CMD_SAVE-1] = NLM_F_REQUEST,
|
||||
[IPSET_CMD_LIST-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_SAVE-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_ADD-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
|
||||
[IPSET_CMD_DEL-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
|
||||
[IPSET_CMD_TEST-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
@@ -83,7 +83,7 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
if (cmdflags[cmd-1] & NLM_F_ACK)
|
||||
nlh->nlmsg_flags |= NLM_F_ACK;
|
||||
nlh->nlmsg_seq = handle->seq = time(NULL);
|
||||
nlh->nlmsg_seq = ++handle->seq;
|
||||
|
||||
ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||
ghdr->cmd = cmd;
|
||||
@@ -225,6 +225,7 @@ ipset_mnl_init(mnl_cb_t *cb_ctl, void *data)
|
||||
handle->portid = mnl_socket_get_portid(handle->h);
|
||||
handle->cb_ctl = cb_ctl;
|
||||
handle->data = data;
|
||||
handle->seq = time(NULL);
|
||||
|
||||
if (ipset_mnl_getid(handle, false) < 0)
|
||||
goto close_nl;
|
@@ -500,10 +500,9 @@ ipset_parse_proto_port(struct ipset_session *session,
|
||||
p = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
|
||||
switch (p) {
|
||||
case IPPROTO_TCP:
|
||||
proto = tmp;
|
||||
tmp = a;
|
||||
goto parse_port;
|
||||
case IPPROTO_SCTP:
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
proto = tmp;
|
||||
tmp = a;
|
||||
goto parse_port;
|
||||
@@ -711,6 +710,14 @@ enum ipaddr_type {
|
||||
IPADDR_RANGE,
|
||||
};
|
||||
|
||||
static inline bool
|
||||
cidr_hostaddr(const char *str, uint8_t family)
|
||||
{
|
||||
char *a = cidr_separator(str);
|
||||
|
||||
return family == AF_INET ? STREQ(a, "/32") : STREQ(a, "/128");
|
||||
}
|
||||
|
||||
static int
|
||||
parse_ip(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str, enum ipaddr_type addrtype)
|
||||
@@ -725,7 +732,8 @@ parse_ip(struct ipset_session *session,
|
||||
|
||||
switch (addrtype) {
|
||||
case IPADDR_PLAIN:
|
||||
if (range_separator(str) || cidr_separator(str))
|
||||
if (range_separator(str)
|
||||
|| (cidr_separator(str) && !cidr_hostaddr(str, family)))
|
||||
return syntax_err("plain IP address must be supplied: %s",
|
||||
str);
|
||||
break;
|
||||
@@ -836,7 +844,7 @@ ipset_parse_net(struct ipset_session *session,
|
||||
*/
|
||||
int
|
||||
ipset_parse_range(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
enum ipset_opt opt ASSERT_UNUSED, const char *str)
|
||||
{
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
||||
@@ -1313,7 +1321,7 @@ ipset_parse_flag(struct ipset_session *session,
|
||||
*/
|
||||
int
|
||||
ipset_parse_typename(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
enum ipset_opt opt ASSERT_UNUSED, const char *str)
|
||||
{
|
||||
const struct ipset_type *type;
|
||||
const char *typename;
|
||||
@@ -1407,15 +1415,14 @@ ipset_parse_ignored(struct ipset_session *session,
|
||||
*/
|
||||
int
|
||||
ipset_call_parser(struct ipset_session *session,
|
||||
ipset_parsefn parse, const char *optstr,
|
||||
enum ipset_opt opt, const char *str)
|
||||
const struct ipset_arg *arg,
|
||||
const char *str)
|
||||
{
|
||||
if (ipset_data_flags_test(ipset_session_data(session),
|
||||
IPSET_FLAG(opt)))
|
||||
syntax_err("%s already specified", optstr);
|
||||
IPSET_FLAG(arg->opt)))
|
||||
syntax_err("%s already specified", arg->name[0]);
|
||||
|
||||
return parse(session, opt, parse == ipset_parse_ignored
|
||||
? optstr : str);
|
||||
return arg->parse(session, arg->opt, str);
|
||||
}
|
||||
|
||||
#define parse_elem(s, t, d, str) \
|
@@ -89,7 +89,8 @@ ipset_print_ether(char *buf, unsigned int len,
|
||||
*/
|
||||
int
|
||||
ipset_print_family(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
uint8_t family;
|
||||
@@ -157,7 +158,8 @@ __getnameinfo##f(char *buf, unsigned int len, \
|
||||
sizeof(saddr), \
|
||||
buf, len, NULL, 0, flags); \
|
||||
\
|
||||
if (err == EAI_AGAIN && !(flags & NI_NUMERICHOST)) \
|
||||
if (!(flags & NI_NUMERICHOST) && \
|
||||
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL))) \
|
||||
err = getnameinfo((const struct sockaddr *)&saddr, \
|
||||
sizeof(saddr), \
|
||||
buf, len, NULL, 0, \
|
||||
@@ -228,7 +230,7 @@ ipset_print_ip(char *buf, unsigned int len,
|
||||
D("CIDR: %u", cidr);
|
||||
} else
|
||||
cidr = family == AF_INET6 ? 128 : 32;
|
||||
flags = env & (1 << IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
|
||||
ip = ipset_data_get(data, opt);
|
||||
assert(ip);
|
||||
@@ -295,7 +297,7 @@ ipset_print_ipaddr(char *buf, unsigned int len,
|
||||
cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
|
||||
else
|
||||
cidr = family == AF_INET6 ? 128 : 32;
|
||||
flags = env & (1 << IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
|
||||
ip = ipset_data_get(data, opt);
|
||||
assert(ip);
|
||||
@@ -410,7 +412,8 @@ ipset_print_name(char *buf, unsigned int len,
|
||||
*/
|
||||
int
|
||||
ipset_print_port(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const uint16_t *port;
|
||||
@@ -454,7 +457,8 @@ ipset_print_port(char *buf, unsigned int len,
|
||||
*/
|
||||
int
|
||||
ipset_print_proto(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const struct protoent *protoent;
|
||||
@@ -490,7 +494,8 @@ ipset_print_proto(char *buf, unsigned int len,
|
||||
*/
|
||||
int
|
||||
ipset_print_icmp(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const char *name;
|
||||
@@ -523,7 +528,8 @@ ipset_print_icmp(char *buf, unsigned int len,
|
||||
*/
|
||||
int
|
||||
ipset_print_icmpv6(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const char *name;
|
||||
@@ -556,7 +562,8 @@ ipset_print_icmpv6(char *buf, unsigned int len,
|
||||
*/
|
||||
int
|
||||
ipset_print_proto_port(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
int size, offset = 0;
|
||||
@@ -578,7 +585,9 @@ ipset_print_proto_port(char *buf, unsigned int len,
|
||||
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_SCTP:
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
break;
|
||||
case IPPROTO_ICMP:
|
||||
return ipset_print_icmp(buf + offset, len, data,
|
@@ -100,6 +100,19 @@ ipset_saved_type(const struct ipset_session *session)
|
||||
return session->saved_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_session_lineno - set session lineno
|
||||
* @session: session structure
|
||||
*
|
||||
* Set session lineno to report parser errors correctly.
|
||||
*/
|
||||
void
|
||||
ipset_session_lineno(struct ipset_session *session, uint32_t lineno)
|
||||
{
|
||||
assert(session);
|
||||
session->lineno = lineno;
|
||||
}
|
||||
|
||||
/*
|
||||
* Environment options
|
||||
*/
|
@@ -198,7 +198,7 @@ create_type_get(struct ipset_session *session)
|
||||
struct ipset_data *data;
|
||||
const char *typename;
|
||||
uint8_t family, tmin = 0, tmax = 0;
|
||||
const uint8_t *kmin, *kmax;
|
||||
uint8_t kmin, kmax;
|
||||
int ret;
|
||||
|
||||
data = ipset_session_data(session);
|
||||
@@ -216,7 +216,7 @@ create_type_get(struct ipset_session *session)
|
||||
&& MATCH_FAMILY(t, family)) {
|
||||
if (match == NULL) {
|
||||
match = t;
|
||||
tmax = t->revision;
|
||||
tmin = tmax = t->revision;
|
||||
} else if (t->family == match->family)
|
||||
tmin = t->revision;
|
||||
}
|
||||
@@ -240,32 +240,31 @@ create_type_get(struct ipset_session *session)
|
||||
if (ret != 0)
|
||||
return NULL;
|
||||
|
||||
kmax = ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
kmin = kmax = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
if (ipset_data_test(data, IPSET_OPT_REVISION_MIN))
|
||||
kmin = ipset_data_get(data, IPSET_OPT_REVISION_MIN);
|
||||
else
|
||||
kmin = kmax;
|
||||
if (MAX(tmin, *kmin) > MIN(tmax, *kmax)) {
|
||||
if (*kmin > tmax)
|
||||
kmin = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION_MIN);
|
||||
|
||||
if (MAX(tmin, kmin) > MIN(tmax, kmax)) {
|
||||
if (kmin > tmax)
|
||||
return ipset_errptr(session,
|
||||
"Kernel supports %s type with family %s "
|
||||
"in minimal revision %u while ipset library "
|
||||
"in maximal revision %u. "
|
||||
"You need to upgrade your ipset library.",
|
||||
"Kernel supports %s type, family %s "
|
||||
"with minimal revision %u while ipset program "
|
||||
"with maximal revision %u.\n"
|
||||
"You need to upgrade your ipset program.",
|
||||
typename,
|
||||
family == AF_INET ? "INET" :
|
||||
family == AF_INET6 ? "INET6" : "UNSPEC",
|
||||
*kmin, tmax);
|
||||
kmin, tmax);
|
||||
else
|
||||
return ipset_errptr(session,
|
||||
"Kernel supports %s type with family %s "
|
||||
"in maximal revision %u while ipset library "
|
||||
"in minimal revision %u. "
|
||||
"Kernel supports %s type, family %s "
|
||||
"with maximal revision %u while ipset program "
|
||||
"with minimal revision %u.\n"
|
||||
"You need to upgrade your kernel.",
|
||||
typename,
|
||||
family == AF_INET ? "INET" :
|
||||
family == AF_INET6 ? "INET6" : "UNSPEC",
|
||||
*kmax, tmin);
|
||||
kmax, tmin);
|
||||
}
|
||||
|
||||
match->kernel_check = IPSET_KERNEL_OK;
|
||||
@@ -441,13 +440,15 @@ ipset_type_add(struct ipset_type *type)
|
||||
|
||||
assert(type);
|
||||
|
||||
if (strlen(type->name) > IPSET_MAXNAMELEN - 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Add to the list: higher revision numbers first */
|
||||
for (t = typelist, prev = NULL; t != NULL; t = t->next) {
|
||||
if (STREQ(t->name, type->name)) {
|
||||
if (t->revision == type->revision) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
} else if (t->revision < type->revision) {
|
||||
if (t->revision == type->revision)
|
||||
return -EEXIST;
|
||||
else if (t->revision < type->revision) {
|
||||
type->next = t;
|
||||
if (prev)
|
||||
prev->next = type;
|
||||
@@ -457,10 +458,9 @@ ipset_type_add(struct ipset_type *type)
|
||||
}
|
||||
}
|
||||
if (t->next != NULL && STREQ(t->next->name, type->name)) {
|
||||
if (t->next->revision == type->revision) {
|
||||
errno = EEXIST;
|
||||
return -1;
|
||||
} else if (t->next->revision < type->revision) {
|
||||
if (t->next->revision == type->revision)
|
||||
return -EEXIST;
|
||||
else if (t->next->revision < type->revision) {
|
||||
type->next = t->next;
|
||||
t->next = type;
|
||||
return 0;
|
291
extensions/ipset-6/pfxlen.c
Normal file
291
extensions/ipset-6/pfxlen.c
Normal file
@@ -0,0 +1,291 @@
|
||||
#include "pfxlen.h"
|
||||
|
||||
/*
|
||||
* Prefixlen maps for fast conversions, by Jan Engelhardt.
|
||||
*/
|
||||
|
||||
#define E(a, b, c, d) \
|
||||
{.ip6 = { \
|
||||
__constant_htonl(a), __constant_htonl(b), \
|
||||
__constant_htonl(c), __constant_htonl(d), \
|
||||
} }
|
||||
|
||||
/*
|
||||
* This table works for both IPv4 and IPv6;
|
||||
* just use prefixlen_netmask_map[prefixlength].ip.
|
||||
*/
|
||||
const union nf_inet_addr ip_set_netmask_map[] = {
|
||||
E(0x00000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0x80000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xC0000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xE0000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xF0000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xF8000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFC000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFE000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFF000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFF800000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFC00000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFE00000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFF00000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFF80000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFC0000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFE0000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFF8000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFC000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFE000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFF000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFF800, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFC00, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFE00, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFF00, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFF80, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFC0, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFE0, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFF0, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFF8, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFC, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFE, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0x80000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xC0000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xE0000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xF0000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xF8000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFC000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFE000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFF800000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFC00000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFE00000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFF00000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFF80000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFC0000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFE0000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFF0000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFF8000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFC000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFE000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFF000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFF800, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFC00, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFE00, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFF00, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFF80, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFC0, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFE0, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFF0, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFF8, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFC, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFE, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0x80000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xC0000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xE0000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xF0000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xF8000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFC000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFE000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFF800000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFC00000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFE00000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFF00000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFF80000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFC0000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFE0000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF0000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF8000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFC000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF800, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFC00, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFE00, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF00, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF80, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFC0, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFE0, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF0, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF8, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFC, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x80000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xC0000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xE0000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xF0000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xF8000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFC000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFE000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF800000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFC00000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE00000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFF00000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFF80000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFC0000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFE0000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF0000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF8000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFC000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF800),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFC00),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFE00),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF00),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF80),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFC0),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFE0),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF0),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF8),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFC),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ip_set_netmask_map);
|
||||
|
||||
#undef E
|
||||
#define E(a, b, c, d) \
|
||||
{.ip6 = { (__force __be32) a, (__force __be32) b, \
|
||||
(__force __be32) c, (__force __be32) d, \
|
||||
} }
|
||||
|
||||
/*
|
||||
* This table works for both IPv4 and IPv6;
|
||||
* just use prefixlen_hostmask_map[prefixlength].ip.
|
||||
*/
|
||||
const union nf_inet_addr ip_set_hostmask_map[] = {
|
||||
E(0x00000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0x80000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xC0000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xE0000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xF0000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xF8000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFC000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFE000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFF000000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFF800000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFC00000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFE00000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFF00000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFF80000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFC0000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFE0000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFF0000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFF8000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFC000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFE000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFF000, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFF800, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFC00, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFE00, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFF00, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFF80, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFC0, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFE0, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFF0, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFF8, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFC, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFE, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0x80000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xC0000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xE0000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xF0000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xF8000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFC000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFE000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFF800000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFC00000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFE00000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFF00000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFF80000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFC0000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFE0000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFF0000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFF8000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFC000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFE000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFF000, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFF800, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFC00, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFE00, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFF00, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFF80, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFC0, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFE0, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFF0, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFF8, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFC, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFE, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0x80000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xC0000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xE0000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xF0000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xF8000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFC000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFE000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFF800000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFC00000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFE00000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFF00000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFF80000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFC0000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFE0000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF0000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF8000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFC000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF000, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF800, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFC00, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFE00, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF00, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF80, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFC0, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFE0, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF0, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF8, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFC, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x80000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xC0000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xE0000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xF0000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xF8000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFC000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFE000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF800000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFC00000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFE00000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFF00000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFF80000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFC0000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFE0000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF0000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFF8000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFC000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF000),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF800),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFC00),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFE00),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF00),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFF80),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFC0),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFE0),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF0),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFF8),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFC),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE),
|
||||
E(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF),
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ip_set_hostmask_map);
|
35
extensions/ipset-6/pfxlen.h
Normal file
35
extensions/ipset-6/pfxlen.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef _PFXLEN_H
|
||||
#define _PFXLEN_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/netfilter.h>
|
||||
|
||||
/* Prefixlen maps, by Jan Engelhardt */
|
||||
extern const union nf_inet_addr ip_set_netmask_map[];
|
||||
extern const union nf_inet_addr ip_set_hostmask_map[];
|
||||
|
||||
static inline __be32
|
||||
ip_set_netmask(u8 pfxlen)
|
||||
{
|
||||
return ip_set_netmask_map[pfxlen].ip;
|
||||
}
|
||||
|
||||
static inline const __be32 *
|
||||
ip_set_netmask6(u8 pfxlen)
|
||||
{
|
||||
return &ip_set_netmask_map[pfxlen].ip6[0];
|
||||
}
|
||||
|
||||
static inline u32
|
||||
ip_set_hostmask(u8 pfxlen)
|
||||
{
|
||||
return (__force u32) ip_set_hostmask_map[pfxlen].ip;
|
||||
}
|
||||
|
||||
static inline const __be32 *
|
||||
ip_set_hostmask6(u8 pfxlen)
|
||||
{
|
||||
return &ip_set_hostmask_map[pfxlen].ip6[0];
|
||||
}
|
||||
|
||||
#endif /*_PFXLEN_H */
|
@@ -21,8 +21,10 @@
|
||||
/* Core kernel error codes */
|
||||
static const struct ipset_errcode_table core_errcode_table[] = {
|
||||
/* Generic error codes */
|
||||
{ EEXIST, 0,
|
||||
{ ENOENT, 0,
|
||||
"The set with the given name does not exist" },
|
||||
{ EMSGSIZE, 0,
|
||||
"Kernel error received: message could not be created" },
|
||||
{ IPSET_ERR_PROTOCOL, 0,
|
||||
"Kernel error received: ipset protocol error" },
|
||||
|
||||
@@ -30,14 +32,14 @@ static const struct ipset_errcode_table core_errcode_table[] = {
|
||||
{ EEXIST, IPSET_CMD_CREATE,
|
||||
"Set cannot be created: set with the same name already exists" },
|
||||
{ IPSET_ERR_FIND_TYPE, 0,
|
||||
"Kernel error received: set type does not supported" },
|
||||
"Kernel error received: set type not supported" },
|
||||
{ IPSET_ERR_MAX_SETS, 0,
|
||||
"Kernel error received: maximal number of sets reached, "
|
||||
"cannot create more." },
|
||||
{ IPSET_ERR_INVALID_NETMASK, 0,
|
||||
"The value of the netmask parameter is invalid" },
|
||||
{ IPSET_ERR_INVALID_FAMILY, 0,
|
||||
"The protocol family not supported by the set type" },
|
||||
"Protocol family not supported by the set type" },
|
||||
|
||||
/* DESTROY specific error codes */
|
||||
{ IPSET_ERR_BUSY, IPSET_CMD_DESTROY,
|
@@ -206,62 +206,54 @@ restore(char *argv0)
|
||||
static int
|
||||
call_parser(int *argc, char *argv[], const struct ipset_arg *args)
|
||||
{
|
||||
int i = 1, ret = 0;
|
||||
int ret = 0;
|
||||
const struct ipset_arg *arg;
|
||||
const char *optstr;
|
||||
|
||||
/* Currently CREATE and ADT may have got additional arguments */
|
||||
if (!args)
|
||||
goto done;
|
||||
if (!args && *argc > 1)
|
||||
goto err_unknown;
|
||||
while (*argc > 1) {
|
||||
for (arg = args; arg->opt; arg++) {
|
||||
for (i = 1; i < *argc; ) {
|
||||
D("argc: %u, i: %u: %s vs %s",
|
||||
*argc, i, argv[i], arg->name[0]);
|
||||
if (!(ipset_match_option(argv[i], arg->name))) {
|
||||
i++;
|
||||
D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]);
|
||||
if (!(ipset_match_option(argv[1], arg->name)))
|
||||
continue;
|
||||
}
|
||||
optstr = argv[i];
|
||||
|
||||
optstr = argv[1];
|
||||
/* Shift off matched option */
|
||||
D("match %s", arg->name[0]);
|
||||
ipset_shift_argv(argc, argv, i);
|
||||
D("argc: %u, i: %u", *argc, i);
|
||||
ipset_shift_argv(argc, argv, 1);
|
||||
switch (arg->has_arg) {
|
||||
case IPSET_MANDATORY_ARG:
|
||||
if (i + 1 > *argc)
|
||||
if (*argc < 2)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Missing mandatory argument "
|
||||
"of option `%s'",
|
||||
arg->name[0]);
|
||||
/* Fall through */
|
||||
case IPSET_OPTIONAL_ARG:
|
||||
if (i + 1 <= *argc) {
|
||||
ret = ipset_call_parser(session,
|
||||
arg->parse,
|
||||
optstr, arg->opt,
|
||||
argv[i]);
|
||||
if (*argc >= 2) {
|
||||
ret = ipset_call_parser(session, arg, argv[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipset_shift_argv(argc, argv, i);
|
||||
ipset_shift_argv(argc, argv, 1);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
ret = ipset_call_parser(session,
|
||||
arg->parse,
|
||||
optstr, arg->opt,
|
||||
optstr);
|
||||
ret = ipset_call_parser(session, arg, optstr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!arg->opt)
|
||||
goto err_unknown;
|
||||
}
|
||||
done:
|
||||
if (i < *argc)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Unknown argument: `%s'",
|
||||
argv[i]);
|
||||
return ret;
|
||||
|
||||
err_unknown:
|
||||
return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]);
|
||||
}
|
||||
|
||||
static enum ipset_adt
|
||||
@@ -431,13 +423,8 @@ parse_commandline(int argc, char *argv[])
|
||||
const struct ipset_commands *command;
|
||||
const struct ipset_type *type;
|
||||
|
||||
/* Initialize session */
|
||||
if (session == NULL) {
|
||||
session = ipset_session_init(printf);
|
||||
if (session == NULL)
|
||||
return exit_error(OTHER_PROBLEM,
|
||||
"Cannot initialize ipset session, aborting.");
|
||||
}
|
||||
/* Set session lineno to report parser errors correctly */
|
||||
ipset_session_lineno(session, restore_line);
|
||||
|
||||
/* Commandline parsing, somewhat similar to that of 'ip' */
|
||||
|
||||
@@ -481,13 +468,11 @@ parse_commandline(int argc, char *argv[])
|
||||
|
||||
/* Second: parse command */
|
||||
for (command = ipset_commands;
|
||||
command->cmd && cmd == IPSET_CMD_NONE;
|
||||
argc > 1 && command->cmd && cmd == IPSET_CMD_NONE;
|
||||
command++) {
|
||||
for (i = 1; i < argc; ) {
|
||||
if (!ipset_match_cmd(argv[1], command->name)) {
|
||||
i++;
|
||||
if (!ipset_match_cmd(argv[1], command->name))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (restore_line != 0
|
||||
&& (command->cmd == IPSET_CMD_RESTORE
|
||||
|| command->cmd == IPSET_CMD_VERSION
|
||||
@@ -496,47 +481,45 @@ parse_commandline(int argc, char *argv[])
|
||||
"Command `%s' is invalid "
|
||||
"in restore mode.",
|
||||
command->name[0]);
|
||||
if (interactive
|
||||
&& command->cmd == IPSET_CMD_RESTORE) {
|
||||
if (interactive && command->cmd == IPSET_CMD_RESTORE) {
|
||||
printf("Restore command ignored "
|
||||
"in interactive mode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Shift off matched command arg */
|
||||
ipset_shift_argv(&argc, argv, i);
|
||||
ipset_shift_argv(&argc, argv, 1);
|
||||
cmd = command->cmd;
|
||||
switch (command->has_arg) {
|
||||
case IPSET_MANDATORY_ARG:
|
||||
case IPSET_MANDATORY_ARG2:
|
||||
if (i + 1 > argc)
|
||||
if (argc < 2)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Missing mandatory argument "
|
||||
"to command %s",
|
||||
command->name[0]);
|
||||
/* Fall through */
|
||||
case IPSET_OPTIONAL_ARG:
|
||||
arg0 = argv[i];
|
||||
if (i + 1 <= argc)
|
||||
arg0 = argv[1];
|
||||
if (argc >= 2)
|
||||
/* Shift off first arg */
|
||||
ipset_shift_argv(&argc, argv, i);
|
||||
ipset_shift_argv(&argc, argv, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (command->has_arg == IPSET_MANDATORY_ARG2) {
|
||||
if (i + 1 > argc)
|
||||
if (argc < 2)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Missing second mandatory "
|
||||
"argument to command %s",
|
||||
command->name[0]);
|
||||
arg1 = argv[i];
|
||||
arg1 = argv[1];
|
||||
/* Shift off second arg */
|
||||
ipset_shift_argv(&argc, argv, i);
|
||||
ipset_shift_argv(&argc, argv, 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Third: catch interactive mode, handle help, version */
|
||||
switch (cmd) {
|
||||
@@ -570,7 +553,8 @@ parse_commandline(int argc, char *argv[])
|
||||
argv[1]);
|
||||
return exit_error(PARAMETER_PROBLEM, "No command specified.");
|
||||
case IPSET_CMD_VERSION:
|
||||
printf("%s v%s.\n", program_name, program_version);
|
||||
printf("%s v%s, protocol version: %u\n",
|
||||
program_name, program_version, IPSET_PROTOCOL);
|
||||
if (interactive)
|
||||
return 0;
|
||||
return exit_error(NO_PROBLEM, NULL);
|
||||
@@ -743,5 +727,11 @@ main(int argc, char *argv[])
|
||||
ipset_type_add(&ipset_hash_ipportnet0);
|
||||
ipset_type_add(&ipset_list_set0);
|
||||
|
||||
/* Initialize session */
|
||||
session = ipset_session_init(printf);
|
||||
if (session == NULL)
|
||||
return exit_error(OTHER_PROBLEM,
|
||||
"Cannot initialize ipset session, aborting.");
|
||||
|
||||
return parse_commandline(argc, argv);
|
||||
}
|
@@ -82,13 +82,13 @@ static const char hash_ipport_usage[] =
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname).\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" is supported for IPv4.\n"
|
||||
" Adding/deleting multiple elements with TCP/UDP port range\n"
|
||||
" is supported both for IPv4 and IPv6.\n";
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipport0 = {
|
||||
.name = "hash:ip,port",
|
||||
.alias = { "ipporthash", NULL },
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
@@ -82,13 +82,13 @@ static const char hash_ipportip_usage[] =
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname).\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" in the first IP component is supported for IPv4.\n"
|
||||
" Adding/deleting multiple elements with TCP/UDP port range\n"
|
||||
" is supported both for IPv4 and IPv6.\n";
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportip0 = {
|
||||
.name = "hash:ip,port,ip",
|
||||
.alias = { "ipportiphash", NULL },
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
@@ -83,13 +83,13 @@ static const char hash_ipportnet_usage[] =
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" in the first IP component is supported for IPv4.\n"
|
||||
" Adding/deleting multiple elements with TCP/UDP port range\n"
|
||||
" is supported both for IPv4 and IPv6.\n";
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportnet0 = {
|
||||
.name = "hash:ip,port,net",
|
||||
.alias = { "ipportnethash", NULL },
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
@@ -60,12 +60,13 @@ static const char hash_netport_usage[] =
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements with TCP/UDP port range supported.\n";
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_netport0 = {
|
||||
.name = "hash:net,port",
|
||||
.alias = { "netporthash", NULL },
|
||||
.revision = 0,
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
@@ -23,9 +23,9 @@
|
||||
const struct ipset_commands ipset_commands[] = {
|
||||
/* Order is important */
|
||||
|
||||
{ /* c[reate], --create, n, -N */
|
||||
{ /* c[reate], --create, n[ew], -N */
|
||||
.cmd = IPSET_CMD_CREATE,
|
||||
.name = { "create", "n" },
|
||||
.name = { "create", "new" },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "SETNAME TYPENAME [type-specific-options]\n"
|
||||
" Create a new set",
|
||||
@@ -143,14 +143,14 @@ ipset_match_cmd(const char *arg, const char * const name[])
|
||||
|
||||
if (len > strlen(name[0]) || !len)
|
||||
return false;
|
||||
else if (strncmp(arg, name[0], len) == 0)
|
||||
else if (len > 1 &&
|
||||
((strncmp(arg, name[0], len) == 0) ||
|
||||
(name[1] != NULL && (strncmp(arg, name[1], len) == 0))))
|
||||
return true;
|
||||
else if (len != 1)
|
||||
return false;
|
||||
else if (name[1] == NULL)
|
||||
return tolower(arg[0]) == name[0][0];
|
||||
else
|
||||
return tolower(arg[0]) == name[1][0];
|
||||
else return tolower(arg[0]) == name[0][0] ||
|
||||
(name[1] != NULL && tolower(arg[0]) == name[1][0]);
|
||||
}
|
||||
|
||||
const struct ipset_envopts ipset_envopts[] = {
|
@@ -1,7 +1,7 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2010 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
* Copyright (C) 2003-2011 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
|
||||
@@ -56,10 +56,10 @@ match_set(ip_set_id_t index, const struct sk_buff *skb,
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
#define CHECK_OK 1
|
||||
#define CHECK_FAIL 0
|
||||
#define CHECK_FAIL(err) 0
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
#define CHECK_OK 0
|
||||
#define CHECK_FAIL (-EINVAL)
|
||||
#define CHECK_FAIL(err) (err)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
@@ -108,13 +108,15 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match",
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return CHECK_FAIL; /* error */
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
}
|
||||
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("That's nasty!");
|
||||
return CHECK_FAIL; /* error */
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
@@ -167,24 +169,31 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("cannot find add_set index %u as target",
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return CHECK_FAIL; /* error */
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("cannot find del_set index %u as target",
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
return CHECK_FAIL; /* error */
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
}
|
||||
}
|
||||
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0
|
||||
|| info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("That's nasty!");
|
||||
return CHECK_FAIL; /* error */
|
||||
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|
||||
info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
@@ -237,13 +246,15 @@ set_match_checkentry(const struct xt_mtchk_param *par)
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match",
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return CHECK_FAIL; /* error */
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
}
|
||||
if (info->match_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("That's nasty!");
|
||||
return CHECK_FAIL; /* error */
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
}
|
||||
|
||||
return CHECK_OK;
|
||||
@@ -275,7 +286,7 @@ set_target(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index,
|
||||
skb, par->family,
|
||||
info->add_set.dim,
|
||||
info->del_set.dim,
|
||||
info->del_set.flags);
|
||||
|
||||
return XT_CONTINUE;
|
||||
@@ -295,24 +306,31 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("cannot find add_set index %u as target",
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return CHECK_FAIL; /* error */
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("cannot find del_set index %u as target",
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
return CHECK_FAIL; /* error */
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
}
|
||||
}
|
||||
if (info->add_set.dim > IPSET_DIM_MAX
|
||||
|| info->del_set.flags > IPSET_DIM_MAX) {
|
||||
pr_warning("That's nasty!");
|
||||
return CHECK_FAIL; /* error */
|
||||
if (info->add_set.dim > IPSET_DIM_MAX ||
|
||||
info->del_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
}
|
||||
|
||||
return CHECK_OK;
|
@@ -1,6 +1,7 @@
|
||||
#ifndef _XT_SET_H
|
||||
#define _XT_SET_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "ip_set.h"
|
||||
|
||||
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
@@ -71,10 +71,10 @@ static void chaos_tg_print(const void *ip,
|
||||
|
||||
switch (info->variant) {
|
||||
case XTCHAOS_DELUDE:
|
||||
printf("DELUDE ");
|
||||
printf(" DELUDE ");
|
||||
break;
|
||||
case XTCHAOS_TARPIT:
|
||||
printf("TARPIT ");
|
||||
printf(" TARPIT ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -85,10 +85,10 @@ static void chaos_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
|
||||
switch (info->variant) {
|
||||
case XTCHAOS_DELUDE:
|
||||
printf("--delude ");
|
||||
printf(" --delude ");
|
||||
break;
|
||||
case XTCHAOS_TARPIT:
|
||||
printf("--tarpit ");
|
||||
printf(" --tarpit ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -62,7 +62,7 @@ static void CHECKSUM_print(const void *ip, const struct xt_entry_target *target,
|
||||
printf("CHECKSUM ");
|
||||
|
||||
if (einfo->operation & XT_CHECKSUM_OP_FILL)
|
||||
printf("fill ");
|
||||
printf(" fill ");
|
||||
}
|
||||
|
||||
static void CHECKSUM_save(const void *ip, const struct xt_entry_target *target)
|
||||
@@ -71,7 +71,7 @@ static void CHECKSUM_save(const void *ip, const struct xt_entry_target *target)
|
||||
(const struct xt_CHECKSUM_info *)target->data;
|
||||
|
||||
if (einfo->operation & XT_CHECKSUM_OP_FILL)
|
||||
printf("--checksum-fill ");
|
||||
printf(" --checksum-fill ");
|
||||
}
|
||||
|
||||
static struct xtables_target checksum_tg_reg = {
|
||||
|
@@ -66,7 +66,7 @@ static void dhcpmac_tg_print(const void *ip,
|
||||
{
|
||||
const struct dhcpmac_info *info = (void *)target->data;
|
||||
|
||||
printf("DHCPMAC %s" DH_MAC_FMT "/%u ",
|
||||
printf(" DHCPMAC %s" DH_MAC_FMT "/%u ",
|
||||
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ static void dhcpmac_tg_save(const void *ip,
|
||||
const struct dhcpmac_info *info = (const void *)target->data;
|
||||
|
||||
if (info->invert)
|
||||
printf("! ");
|
||||
printf("--set-mac " DH_MAC_FMT "/%u ",
|
||||
printf(" !");
|
||||
printf(" --set-mac " DH_MAC_FMT "/%u ",
|
||||
DH_MAC_HEX(info->addr), info->mask);
|
||||
}
|
||||
|
||||
|
241
extensions/libxt_DNETMAP.c
Normal file
241
extensions/libxt_DNETMAP.c
Normal file
@@ -0,0 +1,241 @@
|
||||
/* Shared library add-on to iptables to add DNETMAP support.
|
||||
* (C) 2010 Marek Kierdelewicz <marek@koba.pl>
|
||||
*
|
||||
* uses some code from libipt_NETMAP by:
|
||||
* Svenning Soerensen <svenning@post5.tele.dk>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <xtables.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include "xt_DNETMAP.h"
|
||||
|
||||
#define MODULENAME "DNETMAP"
|
||||
|
||||
static const struct option DNETMAP_opts[] = {
|
||||
{"prefix", 1, NULL, 'p'},
|
||||
{"reuse", 0, NULL, 'r'},
|
||||
{"ttl", 1, NULL, 't'},
|
||||
{.name = NULL}
|
||||
};
|
||||
|
||||
static void DNETMAP_help(void)
|
||||
{
|
||||
printf(MODULENAME " target options:\n"
|
||||
" --%s address[/mask]\n"
|
||||
" Network subnet to map to. If not specified, all existing prefixes are used.\n"
|
||||
" --%s\n"
|
||||
" Reuse entry for given prenat-ip from any prefix despite bindings ttl < 0.\n"
|
||||
" --%s seconds\n"
|
||||
" Regenerate bindings ttl value to seconds. If negative value is specified,\n"
|
||||
" bindings ttl is kept unchanged. If not specified then default ttl value (600s)\n"
|
||||
" is used.\n\n",
|
||||
DNETMAP_opts[0].name, DNETMAP_opts[1].name,
|
||||
DNETMAP_opts[2].name);
|
||||
}
|
||||
|
||||
static u_int32_t bits2netmask(int bits)
|
||||
{
|
||||
u_int32_t netmask, bm;
|
||||
|
||||
if (bits >= 32 || bits < 0)
|
||||
return ~0;
|
||||
for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1)
|
||||
netmask |= bm;
|
||||
return htonl(netmask);
|
||||
}
|
||||
|
||||
static int netmask2bits(u_int32_t netmask)
|
||||
{
|
||||
u_int32_t bm;
|
||||
int bits;
|
||||
|
||||
netmask = ntohl(netmask);
|
||||
for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
|
||||
bits++;
|
||||
if (netmask)
|
||||
return -1; /* holes in netmask */
|
||||
return bits;
|
||||
}
|
||||
|
||||
static void DNETMAP_init(struct xt_entry_target *t)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)&t->data;
|
||||
struct nf_nat_multi_range *mr = &tginfo->prefix;
|
||||
|
||||
/* Actually, it's 0, but it's ignored at the moment. */
|
||||
mr->rangesize = 1;
|
||||
tginfo->ttl = 0;
|
||||
tginfo->flags = 0;
|
||||
}
|
||||
|
||||
/* Parses network address */
|
||||
static void parse_prefix(char *arg, struct nf_nat_range *range)
|
||||
{
|
||||
char *slash;
|
||||
const struct in_addr *ip;
|
||||
u_int32_t netmask;
|
||||
unsigned int bits;
|
||||
|
||||
range->flags |= IP_NAT_RANGE_MAP_IPS;
|
||||
slash = strchr(arg, '/');
|
||||
if (slash)
|
||||
*slash = '\0';
|
||||
|
||||
ip = xtables_numeric_to_ipaddr(arg);
|
||||
if (ip == NULL)
|
||||
xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
|
||||
arg);
|
||||
range->min_ip = ip->s_addr;
|
||||
if (slash) {
|
||||
if (strchr(slash + 1, '.')) {
|
||||
ip = xtables_numeric_to_ipmask(slash + 1);
|
||||
if (ip == NULL)
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Bad netmask \"%s\"\n",
|
||||
slash + 1);
|
||||
netmask = ip->s_addr;
|
||||
} else {
|
||||
if (!xtables_strtoui(slash + 1, NULL, &bits, 0, 32))
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Bad netmask \"%s\"\n",
|
||||
slash + 1);
|
||||
netmask = bits2netmask(bits);
|
||||
}
|
||||
/* Don't allow /0 (/1 is probably insane, too) */
|
||||
if (netmask == 0)
|
||||
xtables_error(PARAMETER_PROBLEM, "Netmask needed\n");
|
||||
/* Mask should be <= then /16 */
|
||||
if (bits < 16)
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"Max netmask size is /16\n");
|
||||
} else
|
||||
netmask = ~0;
|
||||
|
||||
if (range->min_ip & ~netmask) {
|
||||
if (slash)
|
||||
*slash = '/';
|
||||
xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n",
|
||||
arg);
|
||||
}
|
||||
range->max_ip = range->min_ip | ~netmask;
|
||||
}
|
||||
|
||||
static int DNETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_target **target)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)(*target)->data;
|
||||
struct nf_nat_multi_range *mr = &tginfo->prefix;
|
||||
char *end;
|
||||
|
||||
switch (c) {
|
||||
case 'p':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--prefix",
|
||||
*flags & XT_DNETMAP_PREFIX);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--prefix",
|
||||
invert);
|
||||
|
||||
/* TO-DO use xtables_ipparse_any instead? */
|
||||
parse_prefix(optarg, &mr->range[0]);
|
||||
*flags |= XT_DNETMAP_PREFIX;
|
||||
tginfo->flags |= XT_DNETMAP_PREFIX;
|
||||
return 1;
|
||||
case 'r':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--reuse",
|
||||
*flags & XT_DNETMAP_REUSE);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--reuse", invert);
|
||||
*flags |= XT_DNETMAP_REUSE;
|
||||
tginfo->flags |= XT_DNETMAP_REUSE;
|
||||
return 1;
|
||||
case 't':
|
||||
xtables_param_act(XTF_ONLY_ONCE, MODULENAME, "--ttl",
|
||||
*flags & XT_DNETMAP_TTL);
|
||||
xtables_param_act(XTF_NO_INVERT, MODULENAME, "--ttl", invert);
|
||||
*flags |= XT_DNETMAP_TTL;
|
||||
tginfo->flags |= XT_DNETMAP_TTL;
|
||||
tginfo->ttl = strtol(optarg, &end, 10);
|
||||
if (*end != '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void DNETMAP_print_addr(const void *ip,
|
||||
const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
|
||||
const struct nf_nat_multi_range *mr = &tginfo->prefix;
|
||||
const struct nf_nat_range *r = &mr->range[0];
|
||||
struct in_addr a;
|
||||
int bits;
|
||||
|
||||
a.s_addr = r->min_ip;
|
||||
printf("%s", xtables_ipaddr_to_numeric(&a));
|
||||
a.s_addr = ~(r->min_ip ^ r->max_ip);
|
||||
bits = netmask2bits(a.s_addr);
|
||||
if (bits < 0)
|
||||
printf("/%s", xtables_ipaddr_to_numeric(&a));
|
||||
else
|
||||
printf("/%d", bits);
|
||||
}
|
||||
|
||||
static void DNETMAP_print(const void *ip, const struct xt_entry_target *target,
|
||||
int numeric)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
|
||||
const __u8 *flags = &tginfo->flags;
|
||||
|
||||
printf(" prefix ");
|
||||
if (*flags & XT_DNETMAP_PREFIX)
|
||||
DNETMAP_print_addr(ip, target, numeric);
|
||||
else
|
||||
printf("any");
|
||||
|
||||
printf(" reuse %i", (*flags & XT_DNETMAP_REUSE) > 0);
|
||||
if (*flags & XT_DNETMAP_TTL)
|
||||
printf(" ttl %i", tginfo->ttl);
|
||||
else
|
||||
printf(" ttl default");
|
||||
}
|
||||
|
||||
static void DNETMAP_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
struct xt_DNETMAP_tginfo *tginfo = (void *)&target->data;
|
||||
const __u8 *flags = &tginfo->flags;
|
||||
|
||||
if (*flags & XT_DNETMAP_PREFIX) {
|
||||
printf(" --%s ", DNETMAP_opts[0].name);
|
||||
DNETMAP_print_addr(ip, target, 0);
|
||||
}
|
||||
printf(" --reuse %i ", *flags & XT_DNETMAP_REUSE);
|
||||
|
||||
/* ommited because default value can change as kernel mod param */
|
||||
if (*flags & XT_DNETMAP_TTL)
|
||||
printf(" --ttl %i ", tginfo->ttl);
|
||||
}
|
||||
|
||||
static struct xtables_target dnetmap_tg_reg = {
|
||||
.name = MODULENAME,
|
||||
.version = XTABLES_VERSION,
|
||||
.family = NFPROTO_IPV4,
|
||||
.size = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_DNETMAP_tginfo)),
|
||||
.help = DNETMAP_help,
|
||||
.init = DNETMAP_init,
|
||||
.parse = DNETMAP_parse,
|
||||
.print = DNETMAP_print,
|
||||
.save = DNETMAP_save,
|
||||
.extra_opts = DNETMAP_opts,
|
||||
};
|
||||
|
||||
static void _init(void)
|
||||
{
|
||||
xtables_register_target(&dnetmap_tg_reg);
|
||||
}
|
91
extensions/libxt_DNETMAP.man
Normal file
91
extensions/libxt_DNETMAP.man
Normal file
@@ -0,0 +1,91 @@
|
||||
The \fBDNETMAP\fR target allows dynamic two-way 1:1 mapping of IPv4 subnets.
|
||||
Single rule can map private subnet to shorter public subnet creating and
|
||||
maintaining unambigeous private-public ip bindings. Second rule can be used to
|
||||
map new flows to private subnet according to maintained bindings. Target allows
|
||||
efficient public IPv4 space usage and unambigeous NAT at the same time.
|
||||
|
||||
Target can be used only in \fBnat\fR table in \fBPOSTROUTING\fR or \fBOUTPUT\fR
|
||||
chains for SNAT and in \fBPREROUTING\fR for DNAT. Only flows directed to bound
|
||||
IPs will be DNATed. Packet continues chain traversal if there is no free
|
||||
postnat-ip to be assigned to prenat-ip. Default binding \fBttl\fR is \fI10
|
||||
minutes\fR and can be changed using \fBdefault_ttl\fR module option. Default ip
|
||||
hash size is 256 and can be changed using \fBhash_size\fR module option.
|
||||
|
||||
.TP
|
||||
\fB\-\-prefix\fR \fIaddr\fR\fB/\fR\fImask\fR
|
||||
Network subnet to map to. If not specified, all existing prefixes are used.
|
||||
.TP
|
||||
\fB\-\-reuse\fR
|
||||
Reuse entry for given prenat-ip from any prefix despite bindings ttl < 0.
|
||||
.TP
|
||||
\fB\-\-ttl\fR \fIseconds\fR
|
||||
Regenerate bindings ttl value to \fIseconds\fR. If negative value is specified,
|
||||
bindings ttl is kept unchanged. If not specified then default ttl value (600s)
|
||||
is used.
|
||||
.PP
|
||||
\fB* /proc interface\fR
|
||||
|
||||
Module creates following entries for each new specified subnet:
|
||||
.TP
|
||||
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR
|
||||
Contains binding table for subnet/mask. Each line contains \fBprenat-ip\fR,
|
||||
\fBpostnat-ip\fR,\fBttl\fR (seconds till entry times out), \fBlasthit\fR (last
|
||||
entry hit in seconds relative to system boot time).
|
||||
.TP
|
||||
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR
|
||||
Contains statistics for given subnet/mask. Line contains contains three
|
||||
numerical values separated by spaces. First one is number of currently used
|
||||
addresses (bindings with negative ttl excluded), second one is number of all
|
||||
usable addresses in subnet and third one is mean \fBttl\fR value for all active
|
||||
entries.
|
||||
.PP
|
||||
Entries are removed if the last iptables rule for a specific subnet is deleted.
|
||||
|
||||
\fB* Logging\fR
|
||||
|
||||
Module logs binding add/timeout events to klog. This behaviour can be disabled
|
||||
using \fBdisable_log\fR module parameter.
|
||||
|
||||
\fB* Examples\fR
|
||||
|
||||
\fB1.\fR Map subnet 192.168.0.0/24 to subnets 20.0.0.0/26. SNAT only:
|
||||
|
||||
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
|
||||
|
||||
Active hosts from 192.168.0.0/24 subnet are mapped to 20.0.0.0/26. If packet
|
||||
from not yet bound prenat-ip hits the rule and there are no free or timed-out
|
||||
(ttl<0) entries in prefix 20.0.0.0/28, then notice is logged to klog and chain
|
||||
traversal continues. If packet from already bound prenat-ip hits the rule,
|
||||
bindings ttl value is regenerated to default_ttl and SNAT is performed.
|
||||
|
||||
\fB2.\fR Use of \fB\-\-reuse\fR and \fB\-\-ttl\fR switches, multiple rule
|
||||
interaction:
|
||||
|
||||
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix
|
||||
20.0.0.0/26 --reuse --ttl 200
|
||||
|
||||
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 30.0.0.0/26
|
||||
|
||||
Active hosts from 192.168.0.0/24 subnet are mapped to 20.0.0.0/26 with ttl =
|
||||
200 seconds. If there are no free addresses in first prefix the next one
|
||||
(30.0.0.0/26) is used with default ttl. It's important to note that the first
|
||||
rule SNATs all flows whose source IP is already actively (ttl>0) bound to ANY
|
||||
prefix. Parameter \fB\-\-reuse\fR makes this functionality work even for
|
||||
inactive (ttl<0) entries.
|
||||
|
||||
If both subnets are exhaused, then chain traversal continues.
|
||||
|
||||
\fB3.\fR Map 192.168.0.0/24 to subnets 20.0.0.0/26 bidirectional way:
|
||||
|
||||
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -j DNETMAP --prefix 20.0.0.0/26
|
||||
|
||||
iptables -t nat -A PREROUTING -j DNETMAP
|
||||
|
||||
If host 192.168.0.10 generates some traffic, it gets bound to first free IP in
|
||||
subnet - 20.0.0.0. Now any traffic directed to 20.0.0.0 gets DNATed to
|
||||
192.168.0.10 as long as there's an active (ttl>0) binding. There's no need to
|
||||
specify \fB\-\-prefix\fR parameter in PREROUTING rule, because this way it DNATs
|
||||
traffic to all active prefixes. You could specify prefix it you'd like to make
|
||||
DNAT work for specific prefix only.
|
||||
|
||||
.
|
@@ -119,16 +119,16 @@ ipmark_tg_print(const void *entry, const struct xt_entry_target *target,
|
||||
const struct xt_ipmark_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (info->selector == XT_IPMARK_SRC)
|
||||
printf("IPMARK src ip ");
|
||||
printf(" IPMARK src ip ");
|
||||
else
|
||||
printf("IPMARK dst ip ");
|
||||
printf(" IPMARK dst ip ");
|
||||
|
||||
if (info->shift != 0)
|
||||
printf("shift %u ", (unsigned int)info->shift);
|
||||
printf(" shift %u ", (unsigned int)info->shift);
|
||||
if (info->andmask != ~0U)
|
||||
printf("and 0x%x ", (unsigned int)info->andmask);
|
||||
printf(" and 0x%x ", (unsigned int)info->andmask);
|
||||
if (info->ormask != 0)
|
||||
printf("or 0x%x ", (unsigned int)info->ormask);
|
||||
printf(" or 0x%x ", (unsigned int)info->ormask);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -137,16 +137,16 @@ ipmark_tg_save(const void *entry, const struct xt_entry_target *target)
|
||||
const struct xt_ipmark_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (info->selector == XT_IPMARK_SRC)
|
||||
printf("--addr src ");
|
||||
printf(" --addr src ");
|
||||
else
|
||||
printf("--addr dst ");
|
||||
printf(" --addr dst ");
|
||||
|
||||
if (info->shift != 0)
|
||||
printf("--shift %u ", (unsigned int)info->shift);
|
||||
printf(" --shift %u ", (unsigned int)info->shift);
|
||||
if (info->andmask != ~0U)
|
||||
printf("--and-mask 0x%x ", (unsigned int)info->andmask);
|
||||
printf(" --and-mask 0x%x ", (unsigned int)info->andmask);
|
||||
if (info->ormask != 0)
|
||||
printf("--or-mask 0x%x ", (unsigned int)info->ormask);
|
||||
printf(" --or-mask 0x%x ", (unsigned int)info->ormask);
|
||||
}
|
||||
|
||||
static struct xtables_target ipmark_tg_reg = {
|
||||
|
@@ -83,7 +83,7 @@ logmark_tg_print(const void *ip, const struct xt_entry_target *target,
|
||||
{
|
||||
const struct xt_logmark_tginfo *info = (void *)target->data;
|
||||
|
||||
printf("LOGMARK level %u prefix \"%s\" ", info->level, info->prefix);
|
||||
printf(" LOGMARK level %u prefix \"%s\" ", info->level, info->prefix);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -92,9 +92,9 @@ logmark_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
const struct xt_logmark_tginfo *info = (void *)target->data;
|
||||
|
||||
if (info->level != 4)
|
||||
printf("--log-level %u ", info->level);
|
||||
printf(" --log-level %u ", info->level);
|
||||
if (*info->prefix != '\0')
|
||||
printf("--log-prefix \"%s\" ", info->prefix);
|
||||
printf(" --log-prefix \"%s\" ", info->prefix);
|
||||
}
|
||||
|
||||
static struct xtables_target logmark_tg_reg = {
|
||||
|
@@ -110,10 +110,10 @@ rawdnat_tg4_print(const void *entry, const struct xt_entry_target *target,
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (!numeric && info->mask == 32)
|
||||
printf("to-destination %s ",
|
||||
printf(" to-destination %s ",
|
||||
xtables_ipaddr_to_anyname(&info->addr.in));
|
||||
else
|
||||
printf("to-destination %s/%u ",
|
||||
printf(" to-destination %s/%u ",
|
||||
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
|
||||
}
|
||||
|
||||
@@ -124,10 +124,10 @@ rawdnat_tg6_print(const void *entry, const struct xt_entry_target *target,
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (!numeric && info->mask == 128)
|
||||
printf("to-destination %s ",
|
||||
printf(" to-destination %s ",
|
||||
xtables_ip6addr_to_anyname(&info->addr.in6));
|
||||
else
|
||||
printf("to-destination %s/%u ",
|
||||
printf(" to-destination %s/%u ",
|
||||
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ rawdnat_tg4_save(const void *entry, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
printf("--to-destination %s/%u ",
|
||||
printf(" --to-destination %s/%u ",
|
||||
xtables_ipaddr_to_numeric(&info->addr.in),
|
||||
info->mask);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ rawdnat_tg6_save(const void *entry, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
printf("--to-destination %s/%u ",
|
||||
printf(" --to-destination %s/%u ",
|
||||
xtables_ip6addr_to_numeric(&info->addr.in6),
|
||||
info->mask);
|
||||
}
|
||||
|
@@ -110,10 +110,10 @@ rawsnat_tg4_print(const void *entry, const struct xt_entry_target *target,
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (!numeric && info->mask == 32)
|
||||
printf("to-source %s ",
|
||||
printf(" to-source %s ",
|
||||
xtables_ipaddr_to_anyname(&info->addr.in));
|
||||
else
|
||||
printf("to-source %s/%u ",
|
||||
printf(" to-source %s/%u ",
|
||||
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
|
||||
}
|
||||
|
||||
@@ -124,10 +124,10 @@ rawsnat_tg6_print(const void *entry, const struct xt_entry_target *target,
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (!numeric && info->mask == 128)
|
||||
printf("to-source %s ",
|
||||
printf(" to-source %s ",
|
||||
xtables_ip6addr_to_anyname(&info->addr.in6));
|
||||
else
|
||||
printf("to-source %s/%u ",
|
||||
printf(" to-source %s/%u ",
|
||||
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ rawsnat_tg4_save(const void *entry, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
printf("--to-source %s/%u ",
|
||||
printf(" --to-source %s/%u ",
|
||||
xtables_ipaddr_to_numeric(&info->addr.in),
|
||||
info->mask);
|
||||
}
|
||||
@@ -146,7 +146,7 @@ rawsnat_tg6_save(const void *entry, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||
|
||||
printf("--to-source %s/%u ",
|
||||
printf(" --to-source %s/%u ",
|
||||
xtables_ip6addr_to_numeric(&info->addr.in6),
|
||||
info->mask);
|
||||
}
|
||||
|
@@ -105,9 +105,9 @@ static void tee_tg_print(const void *ip, const struct xt_entry_target *target,
|
||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (numeric)
|
||||
printf("TEE gw:%s ", xtables_ipaddr_to_numeric(&info->gw.in));
|
||||
printf(" TEE gw:%s ", xtables_ipaddr_to_numeric(&info->gw.in));
|
||||
else
|
||||
printf("TEE gw:%s ", xtables_ipaddr_to_anyname(&info->gw.in));
|
||||
printf(" TEE gw:%s ", xtables_ipaddr_to_anyname(&info->gw.in));
|
||||
}
|
||||
|
||||
static void tee_tg6_print(const void *ip, const struct xt_entry_target *target,
|
||||
@@ -116,23 +116,23 @@ static void tee_tg6_print(const void *ip, const struct xt_entry_target *target,
|
||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||
|
||||
if (numeric)
|
||||
printf("TEE gw:%s ", xtables_ip6addr_to_numeric(&info->gw.in6));
|
||||
printf(" TEE gw:%s ", xtables_ip6addr_to_numeric(&info->gw.in6));
|
||||
else
|
||||
printf("TEE gw:%s ", xtables_ip6addr_to_anyname(&info->gw.in6));
|
||||
printf(" TEE gw:%s ", xtables_ip6addr_to_anyname(&info->gw.in6));
|
||||
}
|
||||
|
||||
static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||
|
||||
printf("--gateway %s ", xtables_ipaddr_to_numeric(&info->gw.in));
|
||||
printf(" --gateway %s ", xtables_ipaddr_to_numeric(&info->gw.in));
|
||||
}
|
||||
|
||||
static void tee_tg6_save(const void *ip, const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||
|
||||
printf("--gateway %s ", xtables_ip6addr_to_numeric(&info->gw.in6));
|
||||
printf(" --gateway %s ", xtables_ip6addr_to_numeric(&info->gw.in6));
|
||||
}
|
||||
|
||||
static struct xtables_target tee_tg_reg = {
|
||||
|
@@ -67,7 +67,7 @@ static void condition_print(const void *ip, const struct xt_entry_match *match,
|
||||
{
|
||||
const struct xt_condition_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("condition %s%s ", (info->invert) ? "!" : "", info->name);
|
||||
printf(" condition %s%s ", (info->invert) ? "!" : "", info->name);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ static void condition_save(const void *ip, const struct xt_entry_match *match)
|
||||
{
|
||||
const struct xt_condition_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("%s--condition \"%s\" ", info->invert ? "! " : "", info->name);
|
||||
printf("%s --condition \"%s\" ", info->invert ? " !" : "", info->name);
|
||||
}
|
||||
|
||||
static struct xtables_match condition_mt_reg = {
|
||||
|
@@ -67,7 +67,7 @@ static void dhcpmac_mt_print(const void *ip,
|
||||
{
|
||||
const struct dhcpmac_info *info = (void *)match->data;
|
||||
|
||||
printf("dhcpmac %s" DH_MAC_FMT "/%u ",
|
||||
printf(" dhcpmac %s" DH_MAC_FMT "/%u ",
|
||||
info->invert ? "!" : "", DH_MAC_HEX(info->addr), info->mask);
|
||||
}
|
||||
|
||||
@@ -77,8 +77,8 @@ static void dhcpmac_mt_save(const void *ip,
|
||||
const struct dhcpmac_info *info = (void *)match->data;
|
||||
|
||||
if (info->invert)
|
||||
printf("! ");
|
||||
printf("--mac " DH_MAC_FMT "/%u ",
|
||||
printf(" !");
|
||||
printf(" --mac " DH_MAC_FMT "/%u ",
|
||||
DH_MAC_HEX(info->addr), info->mask);
|
||||
}
|
||||
|
||||
|
@@ -88,7 +88,7 @@ static void fuzzy_mt_print(const void *ip, const struct xt_entry_match *match,
|
||||
{
|
||||
const struct xt_fuzzy_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("fuzzy: lower limit = %u pps - upper limit = %u pps ",
|
||||
printf(" fuzzy: lower limit = %u pps - upper limit = %u pps ",
|
||||
info->minimum_rate, info->maximum_rate);
|
||||
}
|
||||
|
||||
@@ -96,8 +96,8 @@ static void fuzzy_mt_save(const void *ip, const struct xt_entry_match *match)
|
||||
{
|
||||
const struct xt_fuzzy_mtinfo *info = (const void *)match->data;
|
||||
|
||||
printf("--lower-limit %u ", info->minimum_rate);
|
||||
printf("--upper-limit %u ", info->maximum_rate);
|
||||
printf(" --lower-limit %u ", info->minimum_rate);
|
||||
printf(" --upper-limit %u ", info->maximum_rate);
|
||||
}
|
||||
|
||||
static struct xtables_match fuzzy_mt_reg = {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user