mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2026-04-26 13:59:43 +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
|
Xtables-addons uses the well-known configure(autotools) infrastructure
|
||||||
in combination with the kernel's Kbuild system.
|
in combination with the kernel's Kbuild system.
|
||||||
|
|
||||||
$ ./configure --with-xtlibdir=SEE_BELOW
|
$ ./configure
|
||||||
$ make
|
$ make
|
||||||
# make install
|
# make install
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ Supported configurations for this release
|
|||||||
|
|
||||||
* iptables >= 1.4.3
|
* iptables >= 1.4.3
|
||||||
|
|
||||||
* kernel-source >= 2.6.17, no upper bound known
|
* kernel-source >= 2.6.29
|
||||||
with prepared build/output directory
|
with prepared build/output directory
|
||||||
- CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK
|
- CONFIG_NF_CONNTRACK or CONFIG_IP_NF_CONNTRACK
|
||||||
- CONFIG_NF_CONNTRACK_MARK or CONFIG_IP_NF_CONNTRACK_MARK
|
- 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
|
- CONFIG_CONNECTOR y/m if you wish to receive userspace
|
||||||
notifications from pknock through netlink/connector
|
notifications from pknock through netlink/connector
|
||||||
|
|
||||||
Extra notes:
|
For ipset-6 you need:
|
||||||
|
|
||||||
* 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:
|
|
||||||
|
|
||||||
* libmnl
|
* libmnl
|
||||||
|
|
||||||
@@ -60,11 +54,12 @@ Configuring and compiling
|
|||||||
--with-xtlibdir=
|
--with-xtlibdir=
|
||||||
|
|
||||||
Specifies the path to where the newly built extensions should
|
Specifies the path to where the newly built extensions should
|
||||||
be installed when `make install` is run. It uses the same
|
be installed when `make install` is run. The default is to
|
||||||
default as the Xtables/iptables package, ${libexecdir}/xtables,
|
use the same path that Xtables/iptables modules use, as
|
||||||
but you may need to specify this nevertheless, as autotools
|
determined by `pkg-config xtables --variable xtlibdir`.
|
||||||
defaults to using /usr/local as prefix, and distributions put
|
Thus, this option normally does NOT need to be specified
|
||||||
the files in differing locations.
|
anymore, even if your distribution put modules in a strange
|
||||||
|
location.
|
||||||
|
|
||||||
If you want to enable debugging, use
|
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.
|
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
|
Inclusion into a kernel tree
|
||||||
============================
|
============================
|
||||||
|
|
||||||
|
|||||||
79
configure.ac
79
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_HEADERS([config.h])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
AC_PROG_INSTALL
|
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
|
AC_PROG_CC
|
||||||
AM_PROG_CC_C_O
|
AM_PROG_CC_C_O
|
||||||
AC_DISABLE_STATIC
|
AC_DISABLE_STATIC
|
||||||
@@ -40,44 +40,41 @@ regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
|
|||||||
-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
|
-Wmissing-prototypes -Wredundant-decls -Wshadow -Wstrict-prototypes \
|
||||||
-Winline -pipe";
|
-Winline -pipe";
|
||||||
|
|
||||||
#
|
if test -n "$kbuilddir"; then
|
||||||
# check kernel version
|
AC_MSG_CHECKING([kernel version that we will build against])
|
||||||
#
|
krel="$(make -sC "$kbuilddir" M=. kernelrelease)";
|
||||||
if grep -q "CentOS release 5\." /etc/redhat-release 2>/dev/null ||
|
kmajor="${krel%%[[^0-9]]*}";
|
||||||
grep -q "Red Hat Enterprise Linux Server release 5" /etc/redhat-release 2>/dev/null; then
|
kmajor="$(($kmajor+0))";
|
||||||
# しまった!
|
krel="${krel:${#kmajor}}";
|
||||||
# Well, just a warning. Maybe the admin updated the kernel.
|
krel="${krel#.}";
|
||||||
echo "WARNING: This distribution's shipped kernel is not supported.";
|
kminor="${krel%%[[^0-9]]*}";
|
||||||
fi;
|
kminor="$(($kminor+0))";
|
||||||
AC_MSG_CHECKING([kernel version that we will build against])
|
krel="${krel:${#kminor}}";
|
||||||
krel="$(make -sC "$kbuilddir" M=. kernelrelease)";
|
krel="${krel#.}";
|
||||||
kmajor="${krel%%[[^0-9]]*}";
|
kmicro="${krel%%[[^0-9]]*}";
|
||||||
kmajor="$(($kmajor+0))";
|
kmicro="$(($kmicro+0))";
|
||||||
krel="${krel:${#kmajor}}";
|
krel="${krel:${#kmicro}}";
|
||||||
krel="${krel#.}";
|
krel="${krel#.}";
|
||||||
kminor="${krel%%[[^0-9]]*}";
|
kstable="${krel%%[[^0-9]]*}";
|
||||||
kminor="$(($kminor+0))";
|
kstable="$(($kstable+0))";
|
||||||
krel="${krel:${#kminor}}";
|
if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then
|
||||||
krel="${krel#.}";
|
echo "WARNING: Version detection did not succeed. Continue at own luck.";
|
||||||
kmicro="${krel%%[[^0-9]]*}";
|
else
|
||||||
kmicro="$(($kmicro+0))";
|
echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
|
||||||
krel="${krel:${#kmicro}}";
|
if test "$kmajor" -gt 2 -o "$kminor" -gt 6 -o "$kmicro" -gt 38; then
|
||||||
krel="${krel#.}";
|
echo "WARNING: You are trying a newer kernel. Results may vary. :-)";
|
||||||
kstable="${krel%%[[^0-9]]*}";
|
elif test "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -ge 29; then
|
||||||
kstable="$(($kstable+0))";
|
:; # everything ok
|
||||||
if test -z "$kmajor" -o -z "$kminor" -o -z "$kmicro"; then
|
elif test \( "$kmajor" -lt 2 -o \
|
||||||
echo "WARNING: Version detection did not succeed. Continue at own luck.";
|
\( "$kmajor" -eq 2 -a "$kminor" -lt 6 \) -o \
|
||||||
else
|
\( "$kmajor" -eq 2 -a "$kminor" -eq 0 -a "$kmicro" -lt 17 \) -o \
|
||||||
echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
|
\( "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -eq 18 -a \
|
||||||
if test "$kmajor" -gt 2 -o "$kminor" -gt 6 -o "$kmicro" -gt 36; then
|
"$kstable" -lt 5 \) \); then
|
||||||
echo "WARNING: You are trying a newer kernel. Results may vary. :-)";
|
echo "ERROR: That kernel version is not supported at all. Please see INSTALL for minimum configuration.";
|
||||||
elif test \( "$kmajor" -lt 2 -o \
|
exit 1;
|
||||||
\( "$kmajor" -eq 2 -a "$kminor" -lt 6 \) -o \
|
else
|
||||||
\( "$kmajor" -eq 2 -a "$kminor" -eq 0 -a "$kmicro" -lt 17 \) -o \
|
echo "WARNING: That kernel version has been recently deprecated for use with Xtables-addons). Compilation may fail.";
|
||||||
\( "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -eq 18 -a \
|
fi;
|
||||||
"$kstable" -lt 5 \) \); then
|
|
||||||
echo "ERROR: That kernel version is not supported. Please see INSTALL for minimum configuration.";
|
|
||||||
exit 1;
|
|
||||||
fi;
|
fi;
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
@@ -87,6 +84,6 @@ AC_SUBST([kbuilddir])
|
|||||||
AC_SUBST([xtlibdir])
|
AC_SUBST([xtlibdir])
|
||||||
AC_CONFIG_FILES([Makefile Makefile.iptrules Makefile.mans geoip/Makefile
|
AC_CONFIG_FILES([Makefile Makefile.iptrules Makefile.mans geoip/Makefile
|
||||||
extensions/Makefile extensions/ACCOUNT/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])
|
extensions/pknock/Makefile])
|
||||||
AC_OUTPUT
|
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)
|
v1.32 (2011-01-04)
|
||||||
==================
|
==================
|
||||||
Fixes:
|
Fixes:
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# -*- Makefile -*-
|
# -*- Makefile -*-
|
||||||
|
|
||||||
|
AM_CPPFLAGS = ${regular_CPPFLAGS} -I${abs_top_srcdir}/extensions
|
||||||
|
AM_CFLAGS = ${regular_CFLAGS}
|
||||||
|
|
||||||
include ../../Makefile.extra
|
include ../../Makefile.extra
|
||||||
|
|
||||||
sbin_PROGRAMS = iptaccount
|
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;
|
struct in_addr a;
|
||||||
|
|
||||||
if (!do_prefix)
|
if (!do_prefix)
|
||||||
printf("ACCOUNT ");
|
printf(" ACCOUNT ");
|
||||||
|
|
||||||
// Network information
|
// Network information
|
||||||
if (do_prefix)
|
if (do_prefix)
|
||||||
printf("--");
|
printf(" --");
|
||||||
printf("%s ", account_tg_opts[0].name);
|
printf("%s ", account_tg_opts[0].name);
|
||||||
|
|
||||||
a.s_addr = accountinfo->net_ip;
|
a.s_addr = accountinfo->net_ip;
|
||||||
@@ -119,7 +119,7 @@ static void account_tg_print_it(const void *ip,
|
|||||||
|
|
||||||
printf(" ");
|
printf(" ");
|
||||||
if (do_prefix)
|
if (do_prefix)
|
||||||
printf("--");
|
printf(" --");
|
||||||
|
|
||||||
printf("%s %s", account_tg_opts[1].name, accountinfo->table_name);
|
printf("%s %s", account_tg_opts[1].name, accountinfo->table_name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* See http://www.intra2net.com/opensource/ipt_account *
|
* See http://www.intra2net.com/opensource/ipt_account *
|
||||||
* for further information *
|
* for further information *
|
||||||
* *
|
* *
|
||||||
* Copyright (C) 2004-2008 by Intra2net AG *
|
* Copyright (C) 2004-2011 by Intra2net AG *
|
||||||
* opensource@intra2net.com *
|
* opensource@intra2net.com *
|
||||||
* *
|
* *
|
||||||
* This program is free software; you can redistribute it and/or modify *
|
* 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_CHECKSUM} += xt_CHECKSUM.o
|
||||||
obj-${build_DELUDE} += xt_DELUDE.o
|
obj-${build_DELUDE} += xt_DELUDE.o
|
||||||
obj-${build_DHCPMAC} += xt_DHCPMAC.o
|
obj-${build_DHCPMAC} += xt_DHCPMAC.o
|
||||||
|
obj-${build_DNETMAP} += xt_DNETMAP.o
|
||||||
obj-${build_ECHO} += xt_ECHO.o
|
obj-${build_ECHO} += xt_ECHO.o
|
||||||
obj-${build_IPMARK} += xt_IPMARK.o
|
obj-${build_IPMARK} += xt_IPMARK.o
|
||||||
obj-${build_LOGMARK} += xt_LOGMARK.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_iface} += xt_iface.o
|
||||||
obj-${build_ipp2p} += xt_ipp2p.o
|
obj-${build_ipp2p} += xt_ipp2p.o
|
||||||
obj-${build_ipset4} += ipset-4/
|
obj-${build_ipset4} += ipset-4/
|
||||||
obj-${build_ipset5} += ipset-5/
|
obj-${build_ipset6} += ipset-6/
|
||||||
obj-${build_ipv4options} += xt_ipv4options.o
|
obj-${build_ipv4options} += xt_ipv4options.o
|
||||||
obj-${build_length2} += xt_length2.o
|
obj-${build_length2} += xt_length2.o
|
||||||
obj-${build_lscan} += xt_lscan.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_CHECKSUM} += libxt_CHECKSUM.so
|
||||||
obj-${build_DELUDE} += libxt_DELUDE.so
|
obj-${build_DELUDE} += libxt_DELUDE.so
|
||||||
obj-${build_DHCPMAC} += libxt_DHCPMAC.so libxt_dhcpmac.so
|
obj-${build_DHCPMAC} += libxt_DHCPMAC.so libxt_dhcpmac.so
|
||||||
|
obj-${build_DNETMAP} += libxt_DNETMAP.so
|
||||||
obj-${build_ECHO} += libxt_ECHO.so
|
obj-${build_ECHO} += libxt_ECHO.so
|
||||||
obj-${build_IPMARK} += libxt_IPMARK.so
|
obj-${build_IPMARK} += libxt_IPMARK.so
|
||||||
obj-${build_LOGMARK} += libxt_LOGMARK.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_iface} += libxt_iface.so
|
||||||
obj-${build_ipp2p} += libxt_ipp2p.so
|
obj-${build_ipp2p} += libxt_ipp2p.so
|
||||||
obj-${build_ipset4} += ipset-4/
|
obj-${build_ipset4} += ipset-4/
|
||||||
obj-${build_ipset5} += ipset-5/
|
obj-${build_ipset6} += ipset-6/
|
||||||
obj-${build_ipv4options} += libxt_ipv4options.so
|
obj-${build_ipv4options} += libxt_ipv4options.so
|
||||||
obj-${build_length2} += libxt_length2.so
|
obj-${build_length2} += libxt_length2.so
|
||||||
obj-${build_lscan} += libxt_lscan.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_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_ipportip.o ip_set_hash_ipportnet.o ip_set_hash_net.o
|
||||||
obj-m += ip_set_hash_netport.o ip_set_list_set.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 -*-
|
# -*- Makefile -*-
|
||||||
|
|
||||||
AM_CFLAGS = ${regular_CFLAGS} ${libmnl_CFLAGS} -Iinclude
|
AM_CPPFLAGS = -I${srcdir}/include -DNDEBUG
|
||||||
|
AM_CFLAGS = ${regular_CFLAGS} ${libmnl_CFLAGS}
|
||||||
|
|
||||||
include ../../Makefile.extra
|
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>
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
* Patrick Schaaf <bof@bof.de>
|
* Patrick Schaaf <bof@bof.de>
|
||||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* The protocol version */
|
/* The protocol version */
|
||||||
#define IPSET_PROTOCOL 5
|
#define IPSET_PROTOCOL 6
|
||||||
|
|
||||||
/* The max length of strings including NUL: set and type identifiers */
|
/* The max length of strings including NUL: set and type identifiers */
|
||||||
#define IPSET_MAXNAMELEN 32
|
#define IPSET_MAXNAMELEN 32
|
||||||
@@ -118,7 +118,7 @@ enum {
|
|||||||
|
|
||||||
/* Error codes */
|
/* Error codes */
|
||||||
enum ipset_errno {
|
enum ipset_errno {
|
||||||
IPSET_ERR_PRIVATE = 128,
|
IPSET_ERR_PRIVATE = 4096,
|
||||||
IPSET_ERR_PROTOCOL,
|
IPSET_ERR_PROTOCOL,
|
||||||
IPSET_ERR_FIND_TYPE,
|
IPSET_ERR_FIND_TYPE,
|
||||||
IPSET_ERR_MAX_SETS,
|
IPSET_ERR_MAX_SETS,
|
||||||
@@ -135,7 +135,7 @@ enum ipset_errno {
|
|||||||
IPSET_ERR_IPADDR_IPV6,
|
IPSET_ERR_IPADDR_IPV6,
|
||||||
|
|
||||||
/* Type specific error codes */
|
/* Type specific error codes */
|
||||||
IPSET_ERR_TYPE_SPECIFIC = 160,
|
IPSET_ERR_TYPE_SPECIFIC = 4352,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags at command level */
|
/* Flags at command level */
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#define IPSET_PROTO_SEPARATOR ":"
|
#define IPSET_PROTO_SEPARATOR ":"
|
||||||
|
|
||||||
struct ipset_session;
|
struct ipset_session;
|
||||||
|
struct ipset_arg;
|
||||||
|
|
||||||
typedef int (*ipset_parsefn)(struct ipset_session *s,
|
typedef int (*ipset_parsefn)(struct ipset_session *s,
|
||||||
enum ipset_opt opt, const char *str);
|
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,
|
extern int ipset_parse_elem(struct ipset_session *session,
|
||||||
enum ipset_opt opt, const char *str);
|
enum ipset_opt opt, const char *str);
|
||||||
extern int ipset_call_parser(struct ipset_session *session,
|
extern int ipset_call_parser(struct ipset_session *session,
|
||||||
ipset_parsefn parse, const char *optstr,
|
const struct ipset_arg *arg,
|
||||||
enum ipset_opt optional, const char *str);
|
const char *str);
|
||||||
|
|
||||||
/* Compatibility parser functions */
|
/* Compatibility parser functions */
|
||||||
extern int ipset_parse_iptimeout(struct ipset_session *session,
|
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_data * ipset_session_data(const struct ipset_session *session);
|
||||||
extern struct ipset_handle * ipset_session_handle(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 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 {
|
enum ipset_err_type {
|
||||||
IPSET_ERROR,
|
IPSET_ERROR,
|
||||||
@@ -70,7 +70,7 @@ struct ipset_elem {
|
|||||||
* but for the readability the full list is supported.
|
* but for the readability the full list is supported.
|
||||||
*/
|
*/
|
||||||
struct ipset_type {
|
struct ipset_type {
|
||||||
char name[IPSET_MAXNAMELEN]; /* type name */
|
const char *name;
|
||||||
uint8_t revision; /* revision number */
|
uint8_t revision; /* revision number */
|
||||||
uint8_t family; /* supported family */
|
uint8_t family; /* supported family */
|
||||||
uint8_t dimension; /* elem dimension */
|
uint8_t dimension; /* elem dimension */
|
||||||
@@ -25,6 +25,11 @@
|
|||||||
#define MAX(a, b) (a > b ? a : b)
|
#define MAX(a, b) (a > b ? a : b)
|
||||||
|
|
||||||
#define UNUSED __attribute__ ((unused))
|
#define UNUSED __attribute__ ((unused))
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define ASSERT_UNUSED UNUSED
|
||||||
|
#else
|
||||||
|
#define ASSERT_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ARRAY_SIZE
|
#ifndef ARRAY_SIZE
|
||||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
||||||
@@ -4,15 +4,17 @@
|
|||||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
* Patrick Schaaf <bof@bof.de>
|
* Patrick Schaaf <bof@bof.de>
|
||||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
* 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
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/netlink.h>
|
||||||
|
|
||||||
/* The protocol version */
|
/* The protocol version */
|
||||||
#define IPSET_PROTOCOL 5
|
#define IPSET_PROTOCOL 6
|
||||||
|
|
||||||
/* The max length of strings including NUL: set and type identifiers */
|
/* The max length of strings including NUL: set and type identifiers */
|
||||||
#define IPSET_MAXNAMELEN 32
|
#define IPSET_MAXNAMELEN 32
|
||||||
@@ -118,7 +120,7 @@ enum {
|
|||||||
|
|
||||||
/* Error codes */
|
/* Error codes */
|
||||||
enum ipset_errno {
|
enum ipset_errno {
|
||||||
IPSET_ERR_PRIVATE = 128,
|
IPSET_ERR_PRIVATE = 4096,
|
||||||
IPSET_ERR_PROTOCOL,
|
IPSET_ERR_PROTOCOL,
|
||||||
IPSET_ERR_FIND_TYPE,
|
IPSET_ERR_FIND_TYPE,
|
||||||
IPSET_ERR_MAX_SETS,
|
IPSET_ERR_MAX_SETS,
|
||||||
@@ -135,7 +137,7 @@ enum ipset_errno {
|
|||||||
IPSET_ERR_IPADDR_IPV6,
|
IPSET_ERR_IPADDR_IPV6,
|
||||||
|
|
||||||
/* Type specific error codes */
|
/* Type specific error codes */
|
||||||
IPSET_ERR_TYPE_SPECIFIC = 160,
|
IPSET_ERR_TYPE_SPECIFIC = 4352,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Flags at command level */
|
/* Flags at command level */
|
||||||
@@ -214,7 +216,8 @@ enum ip_set_feature {
|
|||||||
|
|
||||||
struct ip_set;
|
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 */
|
/* Set type, variant-specific part */
|
||||||
struct ip_set_type_variant {
|
struct ip_set_type_variant {
|
||||||
@@ -229,7 +232,7 @@ struct ip_set_type_variant {
|
|||||||
* returns negative error code,
|
* returns negative error code,
|
||||||
* zero for no match/success to add/delete
|
* zero for no match/success to add/delete
|
||||||
* positive for matching element */
|
* 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);
|
enum ipset_adt adt, u32 *lineno, u32 flags);
|
||||||
|
|
||||||
/* Low level add/del/test functions */
|
/* Low level add/del/test functions */
|
||||||
@@ -272,13 +275,17 @@ struct ip_set_type {
|
|||||||
u8 revision;
|
u8 revision;
|
||||||
|
|
||||||
/* Create set */
|
/* Create set */
|
||||||
int (*create)(struct ip_set *set,
|
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
|
||||||
struct nlattr *head, int len, 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 */
|
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
|
||||||
struct module *me;
|
struct module *me;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* register and unregister set type */
|
||||||
extern int ip_set_type_register(struct ip_set_type *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);
|
extern void ip_set_type_unregister(struct ip_set_type *set_type);
|
||||||
|
|
||||||
@@ -289,9 +296,9 @@ struct ip_set {
|
|||||||
/* Lock protecting the set data */
|
/* Lock protecting the set data */
|
||||||
rwlock_t lock;
|
rwlock_t lock;
|
||||||
/* References to the set */
|
/* References to the set */
|
||||||
atomic_t ref;
|
u32 ref;
|
||||||
/* The core set type */
|
/* The core set type */
|
||||||
const struct ip_set_type *type;
|
struct ip_set_type *type;
|
||||||
/* The type variant doing the real job */
|
/* The type variant doing the real job */
|
||||||
const struct ip_set_type_variant *variant;
|
const struct ip_set_type_variant *variant;
|
||||||
/* The actual INET family of the set */
|
/* 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,
|
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
|
||||||
u8 family, u8 dim, u8 flags);
|
u8 family, u8 dim, u8 flags);
|
||||||
|
|
||||||
/* Allocate members */
|
/* Utility functions */
|
||||||
static inline void *
|
extern void * ip_set_alloc(size_t size);
|
||||||
ip_set_alloc(size_t size, gfp_t gfp_mask)
|
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 (ret)
|
||||||
|
return ret;
|
||||||
if (members) {
|
*ipaddr = ntohl(ip);
|
||||||
pr_debug("%p: allocated with kmalloc", members);
|
return 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore IPSET_ERR_EXIST errors if asked to do so? */
|
/* 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);
|
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 */
|
/* Useful converters */
|
||||||
static inline u32
|
static inline u32
|
||||||
ip_set_get_h32(const struct nlattr *attr)
|
ip_set_get_h32(const struct nlattr *attr)
|
||||||
{
|
{
|
||||||
u32 value = nla_get_u32(attr);
|
return ntohl(nla_get_be32(attr));
|
||||||
|
|
||||||
return attr->nla_type & NLA_F_NET_BYTEORDER ? ntohl(value) : value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u16
|
static inline u16
|
||||||
ip_set_get_h16(const struct nlattr *attr)
|
ip_set_get_h16(const struct nlattr *attr)
|
||||||
{
|
{
|
||||||
u16 value = nla_get_u16(attr);
|
return ntohs(nla_get_be16(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED)
|
#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 ipset_nest_end(skb, start) nla_nest_end(skb, start)
|
||||||
|
|
||||||
#define NLA_PUT_NET32(skb, type, value) \
|
#ifndef NLA_PUT_NET16
|
||||||
NLA_PUT_BE32(skb, type | NLA_F_NET_BYTEORDER, value)
|
#define NLA_PUT_NET16(skb, attrtype, value) \
|
||||||
|
NLA_PUT_BE16(skb, attrtype | NLA_F_NET_BYTEORDER, value)
|
||||||
#define NLA_PUT_NET16(skb, type, value) \
|
#endif
|
||||||
NLA_PUT_BE16(skb, type | NLA_F_NET_BYTEORDER, value)
|
#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) \
|
#define NLA_PUT_IPADDR4(skb, type, ipaddr) \
|
||||||
do { \
|
do { \
|
||||||
@@ -465,14 +412,14 @@ do { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Get address from skbuff */
|
/* Get address from skbuff */
|
||||||
static inline u32
|
static inline __be32
|
||||||
ip4addr(const struct sk_buff *skb, bool src)
|
ip4addr(const struct sk_buff *skb, bool src)
|
||||||
{
|
{
|
||||||
return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
|
return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
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;
|
*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);
|
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 */
|
/* Interface to iptables/ip6tables */
|
||||||
|
|
||||||
#define SO_IP_SET 83
|
#define SO_IP_SET 83
|
||||||
@@ -63,7 +63,7 @@ struct ip_set_hash {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Compute htable_bits from the user input parameter hashsize */
|
/* Compute htable_bits from the user input parameter hashsize */
|
||||||
static inline u8
|
static u8
|
||||||
htable_bits(u32 hashsize)
|
htable_bits(u32 hashsize)
|
||||||
{
|
{
|
||||||
/* Assume that hashsize == 2^htable_bits */
|
/* Assume that hashsize == 2^htable_bits */
|
||||||
@@ -81,14 +81,14 @@ htable_bits(u32 hashsize)
|
|||||||
|
|
||||||
/* Network cidr size book keeping when the hash stores different
|
/* Network cidr size book keeping when the hash stores different
|
||||||
* sized networks */
|
* sized networks */
|
||||||
static inline void
|
static void
|
||||||
add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
||||||
{
|
{
|
||||||
u8 i;
|
u8 i;
|
||||||
|
|
||||||
++h->nets[cidr-1].nets;
|
++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)
|
if (h->nets[cidr-1].nets > 1)
|
||||||
return;
|
return;
|
||||||
@@ -103,14 +103,14 @@ add_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
|||||||
h->nets[i].cidr = cidr;
|
h->nets[i].cidr = cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
del_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
del_cidr(struct ip_set_hash *h, u8 cidr, u8 host_mask)
|
||||||
{
|
{
|
||||||
u8 i;
|
u8 i;
|
||||||
|
|
||||||
--h->nets[cidr-1].nets;
|
--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)
|
if (h->nets[cidr-1].nets != 0)
|
||||||
return;
|
return;
|
||||||
@@ -142,7 +142,7 @@ ahash_destroy(struct htable *t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Calculate the actual memory size of the set data */
|
/* 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)
|
ahash_memsize(const struct ip_set_hash *h, size_t dsize, u8 host_mask)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
@@ -311,8 +311,7 @@ retry:
|
|||||||
/* In case we have plenty of memory :-) */
|
/* In case we have plenty of memory :-) */
|
||||||
return -IPSET_ERR_HASH_FULL;
|
return -IPSET_ERR_HASH_FULL;
|
||||||
t = ip_set_alloc(sizeof(*t)
|
t = ip_set_alloc(sizeof(*t)
|
||||||
+ jhash_size(htable_bits) * sizeof(struct hbucket),
|
+ jhash_size(htable_bits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!t)
|
if (!t)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
t->htable_bits = htable_bits;
|
t->htable_bits = htable_bits;
|
||||||
@@ -340,7 +339,7 @@ retry:
|
|||||||
/* Give time to other readers of the set */
|
/* Give time to other readers of the set */
|
||||||
synchronize_rcu_bh();
|
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);
|
orig->htable_bits, orig, t->htable_bits, t);
|
||||||
ahash_destroy(orig);
|
ahash_destroy(orig);
|
||||||
|
|
||||||
@@ -350,7 +349,7 @@ retry:
|
|||||||
/* Add an element to a hash and update the internal counters when succeeded,
|
/* Add an element to a hash and update the internal counters when succeeded,
|
||||||
* otherwise report the proper error code. */
|
* otherwise report the proper error code. */
|
||||||
static int
|
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 ip_set_hash *h = set->data;
|
||||||
struct htable *t;
|
struct htable *t;
|
||||||
@@ -389,7 +388,7 @@ out:
|
|||||||
* and free up space if possible.
|
* and free up space if possible.
|
||||||
*/
|
*/
|
||||||
static int
|
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 ip_set_hash *h = set->data;
|
||||||
struct htable *t = h->table;
|
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
|
/* Special test function which takes into account the different network
|
||||||
* sizes added to the set */
|
* 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)
|
type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||||
{
|
{
|
||||||
struct ip_set_hash *h = set->data;
|
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;
|
u32 key;
|
||||||
u8 host_mask = SET_HOST_MASK(set->family);
|
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++) {
|
for (; j < host_mask && h->nets[j].cidr; j++) {
|
||||||
type_pf_data_netmask(d, h->nets[j].cidr);
|
type_pf_data_netmask(d, h->nets[j].cidr);
|
||||||
key = HKEY(d, h->initval, t->htable_bits);
|
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 */
|
/* Test whether the element is added to the set */
|
||||||
static int
|
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 ip_set_hash *h = set->data;
|
||||||
struct htable *t = h->table;
|
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)
|
if (h->netmask != HOST_MASK)
|
||||||
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask);
|
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, h->netmask);
|
||||||
#endif
|
#endif
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||||
htonl(atomic_read(&set->ref) - 1));
|
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize));
|
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize));
|
||||||
if (with_timeout(h->timeout))
|
if (with_timeout(h->timeout))
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(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;
|
return 0;
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reply a LIST/SAVE request: dump the elements of the specified set */
|
/* 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);
|
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||||
if (!atd)
|
if (!atd)
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
pr_debug("list hash set %s", set->name);
|
pr_debug("list hash set %s\n", set->name);
|
||||||
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
|
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
|
||||||
incomplete = skb_tail_pointer(skb);
|
incomplete = skb_tail_pointer(skb);
|
||||||
n = hbucket(t, cb->args[2]);
|
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++) {
|
for (i = 0; i < n->pos; i++) {
|
||||||
data = ahash_data(n, 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);
|
cb->args[2], n, i, data);
|
||||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||||
if (!nested) {
|
if (!nested) {
|
||||||
if (cb->args[2] == first) {
|
if (cb->args[2] == first) {
|
||||||
nla_nest_cancel(skb, atd);
|
nla_nest_cancel(skb, atd);
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
} else
|
} else
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
@@ -581,6 +579,7 @@ nla_put_failure:
|
|||||||
pr_warning("Can't list set %s: one bucket does not fit into "
|
pr_warning("Can't list set %s: one bucket does not fit into "
|
||||||
"a message. Please report it!\n", set->name);
|
"a message. Please report it!\n", set->name);
|
||||||
cb->args[2] = 0;
|
cb->args[2] = 0;
|
||||||
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -589,7 +588,7 @@ static int
|
|||||||
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
|
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
|
||||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
|
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
|
||||||
static int
|
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);
|
enum ipset_adt adt, u32 *lineno, u32 flags);
|
||||||
|
|
||||||
static const struct ip_set_type_variant type_pf_variant = {
|
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++) {
|
for (j = 0; j < n->pos; j++) {
|
||||||
data = ahash_tdata(n, j);
|
data = ahash_tdata(n, j);
|
||||||
if (type_pf_data_expired(data)) {
|
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
|
#ifdef IP_SET_HASH_WITH_NETS
|
||||||
del_cidr(h, data->cidr, HOST_MASK);
|
del_cidr(h, data->cidr, HOST_MASK);
|
||||||
#endif
|
#endif
|
||||||
@@ -701,7 +700,7 @@ type_pf_expire(struct ip_set_hash *h)
|
|||||||
if (n->pos + AHASH_INIT_SIZE < n->size) {
|
if (n->pos + AHASH_INIT_SIZE < n->size) {
|
||||||
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
|
void *tmp = kzalloc((n->size - AHASH_INIT_SIZE)
|
||||||
* sizeof(struct type_pf_telem),
|
* sizeof(struct type_pf_telem),
|
||||||
GFP_KERNEL);
|
GFP_ATOMIC);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
/* Still try to delete expired elements */
|
/* Still try to delete expired elements */
|
||||||
continue;
|
continue;
|
||||||
@@ -742,8 +741,7 @@ retry:
|
|||||||
/* In case we have plenty of memory :-) */
|
/* In case we have plenty of memory :-) */
|
||||||
return -IPSET_ERR_HASH_FULL;
|
return -IPSET_ERR_HASH_FULL;
|
||||||
t = ip_set_alloc(sizeof(*t)
|
t = ip_set_alloc(sizeof(*t)
|
||||||
+ jhash_size(htable_bits) * sizeof(struct hbucket),
|
+ jhash_size(htable_bits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!t)
|
if (!t)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
t->htable_bits = htable_bits;
|
t->htable_bits = htable_bits;
|
||||||
@@ -778,7 +776,7 @@ retry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 ip_set_hash *h = set->data;
|
||||||
struct htable *t = h->table;
|
struct htable *t = h->table;
|
||||||
@@ -786,6 +784,7 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout)
|
|||||||
struct hbucket *n;
|
struct hbucket *n;
|
||||||
struct type_pf_elem *data;
|
struct type_pf_elem *data;
|
||||||
int ret = 0, i, j = AHASH_MAX_SIZE + 1;
|
int ret = 0, i, j = AHASH_MAX_SIZE + 1;
|
||||||
|
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||||
u32 key;
|
u32 key;
|
||||||
|
|
||||||
if (h->elements >= h->maxelem)
|
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++) {
|
for (i = 0; i < n->pos; i++) {
|
||||||
data = ahash_tdata(n, i);
|
data = ahash_tdata(n, i);
|
||||||
if (type_pf_data_equal(data, d)) {
|
if (type_pf_data_equal(data, d)) {
|
||||||
if (type_pf_data_expired(data))
|
if (type_pf_data_expired(data) || flag_exist)
|
||||||
j = i;
|
j = i;
|
||||||
else {
|
else {
|
||||||
ret = -IPSET_ERR_EXIST;
|
ret = -IPSET_ERR_EXIST;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
} else if (j == AHASH_MAX_SIZE + 1
|
} else if (j == AHASH_MAX_SIZE + 1 &&
|
||||||
&& type_pf_data_expired(data))
|
type_pf_data_expired(data))
|
||||||
j = i;
|
j = i;
|
||||||
}
|
}
|
||||||
if (j != AHASH_MAX_SIZE + 1) {
|
if (j != AHASH_MAX_SIZE + 1) {
|
||||||
@@ -835,7 +834,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 ip_set_hash *h = set->data;
|
||||||
struct htable *t = h->table;
|
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
|
#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)
|
type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||||
{
|
{
|
||||||
struct ip_set_hash *h = set->data;
|
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
|
#endif
|
||||||
|
|
||||||
static int
|
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 ip_set_hash *h = set->data;
|
||||||
struct htable *t = h->table;
|
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);
|
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||||
if (!atd)
|
if (!atd)
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
|
for (; cb->args[2] < jhash_size(t->htable_bits); cb->args[2]++) {
|
||||||
incomplete = skb_tail_pointer(skb);
|
incomplete = skb_tail_pointer(skb);
|
||||||
n = hbucket(t, cb->args[2]);
|
n = hbucket(t, cb->args[2]);
|
||||||
for (i = 0; i < n->pos; i++) {
|
for (i = 0; i < n->pos; i++) {
|
||||||
data = ahash_tdata(n, 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))
|
if (type_pf_data_expired(data))
|
||||||
continue;
|
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);
|
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||||
if (!nested) {
|
if (!nested) {
|
||||||
if (cb->args[2] == first) {
|
if (cb->args[2] == first) {
|
||||||
nla_nest_cancel(skb, atd);
|
nla_nest_cancel(skb, atd);
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
} else
|
} else
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
@@ -982,6 +981,7 @@ nla_put_failure:
|
|||||||
pr_warning("Can't list set %s: one bucket does not fit into "
|
pr_warning("Can't list set %s: one bucket does not fit into "
|
||||||
"a message. Please report it!\n", set->name);
|
"a message. Please report it!\n", set->name);
|
||||||
cb->args[2] = 0;
|
cb->args[2] = 0;
|
||||||
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
return 0;
|
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 *set = (struct ip_set *) ul_set;
|
||||||
struct ip_set_hash *h = set->data;
|
struct ip_set_hash *h = set->data;
|
||||||
|
|
||||||
pr_debug("called");
|
pr_debug("called\n");
|
||||||
write_lock_bh(&set->lock);
|
write_lock_bh(&set->lock);
|
||||||
type_pf_expire(h);
|
type_pf_expire(h);
|
||||||
write_unlock_bh(&set->lock);
|
write_unlock_bh(&set->lock);
|
||||||
@@ -1017,7 +1017,7 @@ type_pf_gc(unsigned long ul_set)
|
|||||||
add_timer(&h->gc);
|
add_timer(&h->gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
type_pf_gc_init(struct ip_set *set)
|
type_pf_gc_init(struct ip_set *set)
|
||||||
{
|
{
|
||||||
struct ip_set_hash *h = set->data;
|
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.function = type_pf_gc;
|
||||||
h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
|
h->gc.expires = jiffies + IPSET_GC_PERIOD(h->timeout) * HZ;
|
||||||
add_timer(&h->gc);
|
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));
|
IPSET_GC_PERIOD(h->timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
* Patrick Schaaf <bof@bof.de>
|
* 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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the bitmap:ip type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
@@ -23,6 +21,7 @@
|
|||||||
#include <net/netlink.h>
|
#include <net/netlink.h>
|
||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_bitmap.h"
|
#include "ip_set_bitmap.h"
|
||||||
#define IP_SET_BITMAP_TIMEOUT
|
#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_DESCRIPTION("bitmap:ip type of IP sets");
|
||||||
MODULE_ALIAS("ip_set_bitmap:ip");
|
MODULE_ALIAS("ip_set_bitmap:ip");
|
||||||
|
|
||||||
/* Base variant */
|
/* Type structure */
|
||||||
|
|
||||||
struct bitmap_ip {
|
struct bitmap_ip {
|
||||||
void *members; /* the set members */
|
void *members; /* the set members */
|
||||||
u32 first_ip; /* host byte order, included in range */
|
u32 first_ip; /* host byte order, included in range */
|
||||||
@@ -43,43 +41,188 @@ struct bitmap_ip {
|
|||||||
u32 hosts; /* number of hosts in a subnet */
|
u32 hosts; /* number of hosts in a subnet */
|
||||||
size_t memsize; /* members size */
|
size_t memsize; /* members size */
|
||||||
u8 netmask; /* subnet netmask */
|
u8 netmask; /* subnet netmask */
|
||||||
|
u32 timeout; /* timeout parameter */
|
||||||
|
struct timer_list gc; /* garbage collection */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Base variant */
|
||||||
|
|
||||||
static inline u32
|
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
|
static int
|
||||||
bitmap_ip_test(const struct bitmap_ip *map, u32 id)
|
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);
|
return !!test_bit(id, map->members);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static int
|
||||||
bitmap_ip_add(struct bitmap_ip *map, u32 id)
|
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))
|
if (test_and_set_bit(id, map->members))
|
||||||
return -IPSET_ERR_EXIST;
|
return -IPSET_ERR_EXIST;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static int
|
||||||
bitmap_ip_del(struct bitmap_ip *map, u32 id)
|
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))
|
if (!test_and_clear_bit(id, map->members))
|
||||||
return -IPSET_ERR_EXIST;
|
return -IPSET_ERR_EXIST;
|
||||||
|
|
||||||
return 0;
|
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
|
static int
|
||||||
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||||
{
|
{
|
||||||
struct bitmap_ip *map = set->data;
|
struct bitmap_ip *map = set->data;
|
||||||
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
u32 ip;
|
u32 ip;
|
||||||
|
|
||||||
ip = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
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);
|
ip = ip_to_id(map, ip);
|
||||||
|
|
||||||
switch (adt) {
|
return adtfn(set, &ip, map->timeout, flags);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
struct bitmap_ip *map = set->data;
|
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;
|
u32 ip, ip_to, id;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
bitmap_ip_adt_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ip = ntohl(ip);
|
|
||||||
|
|
||||||
if (ip < map->first_ip || ip > map->last_ip)
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
return -IPSET_ERR_BITMAP_RANGE;
|
return -IPSET_ERR_BITMAP_RANGE;
|
||||||
|
|
||||||
/* Set was defined without timeout support:
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
* don't ignore the attribute silently */
|
if (!with_timeout(map->timeout))
|
||||||
if (tb[IPSET_ATTR_TIMEOUT])
|
return -IPSET_ERR_TIMEOUT;
|
||||||
return -IPSET_ERR_TIMEOUT;
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST)
|
if (adt == IPSET_TEST) {
|
||||||
return bitmap_ip_test(map, ip_to_id(map, ip));
|
id = ip_to_id(map, ip);
|
||||||
|
return adtfn(set, &id, timeout, flags);
|
||||||
|
}
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_IP_TO]) {
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ip_to = ntohl(ip_to);
|
|
||||||
if (ip > ip_to) {
|
if (ip > ip_to) {
|
||||||
swap(ip, ip_to);
|
swap(ip, ip_to);
|
||||||
if (ip < map->first_ip)
|
if (ip < map->first_ip)
|
||||||
@@ -155,8 +283,8 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
|
|
||||||
if (cidr > 32)
|
if (cidr > 32)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
ip &= HOSTMASK(cidr);
|
ip &= ip_set_hostmask(cidr);
|
||||||
ip_to = ip | ~HOSTMASK(cidr);
|
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||||
} else
|
} else
|
||||||
ip_to = ip;
|
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) {
|
for (; !before(ip_to, ip); ip += map->hosts) {
|
||||||
id = ip_to_id(map, ip);
|
id = ip_to_id(map, ip);
|
||||||
ret = adt == IPSET_ADD ? bitmap_ip_add(map, id)
|
ret = adtfn(set, &id, timeout, flags);
|
||||||
: bitmap_ip_del(map, id);
|
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
return ret;
|
||||||
@@ -181,6 +308,9 @@ bitmap_ip_destroy(struct ip_set *set)
|
|||||||
{
|
{
|
||||||
struct bitmap_ip *map = set->data;
|
struct bitmap_ip *map = set->data;
|
||||||
|
|
||||||
|
if (with_timeout(map->timeout))
|
||||||
|
del_timer_sync(&map->gc);
|
||||||
|
|
||||||
ip_set_free(map->members);
|
ip_set_free(map->members);
|
||||||
kfree(map);
|
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));
|
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
|
||||||
if (map->netmask != 32)
|
if (map->netmask != 32)
|
||||||
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
|
NLA_PUT_U8(skb, IPSET_ATTR_NETMASK, map->netmask);
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||||
htonl(atomic_read(&set->ref) - 1));
|
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||||
htonl(sizeof(*map) + map->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);
|
ipset_nest_end(skb, nested);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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 *x = a->data;
|
||||||
const struct bitmap_ip *y = b->data;
|
const struct bitmap_ip *y = b->data;
|
||||||
|
|
||||||
return x->first_ip == y->first_ip
|
return x->first_ip == y->first_ip &&
|
||||||
&& x->last_ip == y->last_ip
|
x->last_ip == y->last_ip &&
|
||||||
&& x->netmask == y->netmask;
|
x->netmask == y->netmask &&
|
||||||
|
x->timeout == y->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ip_set_type_variant bitmap_ip = {
|
static const struct ip_set_type_variant bitmap_ip = {
|
||||||
.kadt = bitmap_ip_kadt,
|
.kadt = bitmap_ip_kadt,
|
||||||
.uadt = bitmap_ip_uadt,
|
.uadt = bitmap_ip_uadt,
|
||||||
|
.adt = {
|
||||||
|
[IPSET_ADD] = bitmap_ip_add,
|
||||||
|
[IPSET_DEL] = bitmap_ip_del,
|
||||||
|
[IPSET_TEST] = bitmap_ip_test,
|
||||||
|
},
|
||||||
.destroy = bitmap_ip_destroy,
|
.destroy = bitmap_ip_destroy,
|
||||||
.flush = bitmap_ip_flush,
|
.flush = bitmap_ip_flush,
|
||||||
.head = bitmap_ip_head,
|
.head = bitmap_ip_head,
|
||||||
@@ -278,259 +377,26 @@ static const struct ip_set_type_variant bitmap_ip = {
|
|||||||
.same_set = bitmap_ip_same_set,
|
.same_set = bitmap_ip_same_set,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Timeout variant */
|
static const struct ip_set_type_variant bitmap_tip = {
|
||||||
|
.kadt = bitmap_ip_kadt,
|
||||||
struct bitmap_ip_timeout {
|
.uadt = bitmap_ip_uadt,
|
||||||
unsigned long *members; /* the set members */
|
.adt = {
|
||||||
u32 first_ip; /* host byte order, included in range */
|
[IPSET_ADD] = bitmap_ip_tadd,
|
||||||
u32 last_ip; /* host byte order, included in range */
|
[IPSET_DEL] = bitmap_ip_tdel,
|
||||||
u32 elements; /* number of max elements in the set */
|
[IPSET_TEST] = bitmap_ip_ttest,
|
||||||
u32 hosts; /* number of hosts in a subnet */
|
},
|
||||||
size_t memsize; /* members size */
|
.destroy = bitmap_ip_destroy,
|
||||||
u8 netmask; /* subnet netmask */
|
.flush = bitmap_ip_flush,
|
||||||
|
.head = bitmap_ip_head,
|
||||||
u32 timeout; /* timeout parameter */
|
.list = bitmap_ip_tlist,
|
||||||
struct timer_list gc; /* garbage collection */
|
.same_set = bitmap_ip_same_set,
|
||||||
};
|
|
||||||
|
|
||||||
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 void
|
static void
|
||||||
bitmap_ip_gc(unsigned long ul_set)
|
bitmap_ip_gc(unsigned long ul_set)
|
||||||
{
|
{
|
||||||
struct ip_set *set = (struct ip_set *) 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;
|
unsigned long *table = map->members;
|
||||||
u32 id;
|
u32 id;
|
||||||
|
|
||||||
@@ -546,10 +412,10 @@ bitmap_ip_gc(unsigned long ul_set)
|
|||||||
add_timer(&map->gc);
|
add_timer(&map->gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
bitmap_ip_gc_init(struct ip_set *set)
|
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);
|
init_timer(&map->gc);
|
||||||
map->gc.data = (unsigned long) set;
|
map->gc.data = (unsigned long) set;
|
||||||
@@ -560,21 +426,12 @@ bitmap_ip_gc_init(struct ip_set *set)
|
|||||||
|
|
||||||
/* Create bitmap:ip type of sets */
|
/* 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
|
static bool
|
||||||
init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
||||||
u32 first_ip, u32 last_ip,
|
u32 first_ip, u32 last_ip,
|
||||||
u32 elements, u32 hosts, u8 netmask)
|
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)
|
if (!map->members)
|
||||||
return false;
|
return false;
|
||||||
map->first_ip = first_ip;
|
map->first_ip = first_ip;
|
||||||
@@ -582,6 +439,7 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
|||||||
map->elements = elements;
|
map->elements = elements;
|
||||||
map->hosts = hosts;
|
map->hosts = hosts;
|
||||||
map->netmask = netmask;
|
map->netmask = netmask;
|
||||||
|
map->timeout = IPSET_NO_TIMEOUT;
|
||||||
|
|
||||||
set->data = map;
|
set->data = map;
|
||||||
set->family = AF_INET;
|
set->family = AF_INET;
|
||||||
@@ -590,28 +448,25 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
|
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||||
u32 flags)
|
|
||||||
{
|
{
|
||||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
struct bitmap_ip *map;
|
||||||
u32 first_ip, last_ip, hosts, elements;
|
u32 first_ip, last_ip, hosts, elements;
|
||||||
u8 netmask = 32;
|
u8 netmask = 32;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
bitmap_ip_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
first_ip = ntohl(first_ip);
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_IP_TO]) {
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
last_ip = htonl(last_ip);
|
|
||||||
if (first_ip > last_ip) {
|
if (first_ip > last_ip) {
|
||||||
u32 tmp = first_ip;
|
u32 tmp = first_ip;
|
||||||
|
|
||||||
@@ -623,7 +478,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
|
|
||||||
if (cidr >= 32)
|
if (cidr >= 32)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
last_ip = first_ip | ~HOSTMASK(cidr);
|
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
@@ -633,8 +488,8 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
if (netmask > 32)
|
if (netmask > 32)
|
||||||
return -IPSET_ERR_INVALID_NETMASK;
|
return -IPSET_ERR_INVALID_NETMASK;
|
||||||
|
|
||||||
first_ip &= HOSTMASK(netmask);
|
first_ip &= ip_set_hostmask(netmask);
|
||||||
last_ip |= ~HOSTMASK(netmask);
|
last_ip |= ~ip_set_hostmask(netmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (netmask == 32) {
|
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);
|
mask = range_to_mask(first_ip, last_ip, &mask_bits);
|
||||||
|
|
||||||
if ((!mask && (first_ip || last_ip != 0xFFFFFFFF))
|
if ((!mask && (first_ip || last_ip != 0xFFFFFFFF)) ||
|
||||||
|| netmask <= mask_bits)
|
netmask <= mask_bits)
|
||||||
return -IPSET_ERR_BITMAP_RANGE;
|
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);
|
hosts = 2 << (32 - netmask - 1);
|
||||||
elements = 2 << (netmask - mask_bits - 1);
|
elements = 2 << (netmask - mask_bits - 1);
|
||||||
}
|
}
|
||||||
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
|
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
|
||||||
return -IPSET_ERR_BITMAP_RANGE_SIZE;
|
return -IPSET_ERR_BITMAP_RANGE_SIZE;
|
||||||
|
|
||||||
pr_debug("hosts %u, elements %u", hosts, elements);
|
pr_debug("hosts %u, elements %u\n", hosts, elements);
|
||||||
|
|
||||||
|
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||||
|
if (!map)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
struct bitmap_ip_timeout *map;
|
|
||||||
|
|
||||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
|
||||||
if (!map)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
map->memsize = elements * sizeof(unsigned long);
|
map->memsize = elements * sizeof(unsigned long);
|
||||||
|
|
||||||
if (!init_map_ip(set, (struct bitmap_ip *)map,
|
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||||
first_ip, last_ip,
|
|
||||||
elements, hosts, netmask)) {
|
elements, hosts, netmask)) {
|
||||||
kfree(map);
|
kfree(map);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
set->variant = &bitmap_ip_timeout;
|
set->variant = &bitmap_tip;
|
||||||
|
|
||||||
bitmap_ip_gc_init(set);
|
bitmap_ip_gc_init(set);
|
||||||
} else {
|
} else {
|
||||||
struct bitmap_ip *map;
|
|
||||||
|
|
||||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
|
||||||
if (!map)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
map->memsize = bitmap_bytes(0, elements - 1);
|
map->memsize = bitmap_bytes(0, elements - 1);
|
||||||
|
|
||||||
if (!init_map_ip(set, map,
|
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||||
first_ip, last_ip,
|
|
||||||
elements, hosts, netmask)) {
|
elements, hosts, netmask)) {
|
||||||
kfree(map);
|
kfree(map);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -708,6 +553,20 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
|
|||||||
.family = AF_INET,
|
.family = AF_INET,
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
.create = bitmap_ip_create,
|
.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,
|
.me = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
* Patrick Schaaf <bof@bof.de>
|
* Patrick Schaaf <bof@bof.de>
|
||||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
* 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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the bitmap:ip,mac type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <net/netlink.h>
|
#include <net/netlink.h>
|
||||||
|
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_timeout.h"
|
#include "ip_set_timeout.h"
|
||||||
#include "ip_set_bitmap.h"
|
#include "ip_set_bitmap.h"
|
||||||
@@ -94,15 +91,15 @@ bitmap_expired(const struct bitmap_ipmac *map, u32 id)
|
|||||||
static inline int
|
static inline int
|
||||||
bitmap_ipmac_exist(const struct ipmac_telem *elem)
|
bitmap_ipmac_exist(const struct ipmac_telem *elem)
|
||||||
{
|
{
|
||||||
return elem->match == MAC_UNSET
|
return elem->match == MAC_UNSET ||
|
||||||
|| (elem->match == MAC_FILLED
|
(elem->match == MAC_FILLED &&
|
||||||
&& !ip_set_timeout_expired(elem->timeout));
|
!ip_set_timeout_expired(elem->timeout));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Base variant */
|
/* Base variant */
|
||||||
|
|
||||||
static int
|
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 bitmap_ipmac *map = set->data;
|
||||||
const struct ipmac *data = value;
|
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 */
|
/* Trigger kernel to fill out the ethernet address */
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
case MAC_FILLED:
|
case MAC_FILLED:
|
||||||
return data->ether == NULL
|
return data->ether == NULL ||
|
||||||
|| compare_ether_addr(data->ether, elem->ether) == 0;
|
compare_ether_addr(data->ether, elem->ether) == 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct bitmap_ipmac *map = set->data;
|
||||||
const struct ipmac *data = value;
|
const struct ipmac *data = value;
|
||||||
@@ -149,7 +146,7 @@ bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct bitmap_ipmac *map = set->data;
|
||||||
const struct ipmac *data = value;
|
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);
|
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||||
if (!atd)
|
if (!atd)
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||||
id = cb->args[2];
|
id = cb->args[2];
|
||||||
elem = bitmap_ipmac_elem(map, id);
|
elem = bitmap_ipmac_elem(map, id);
|
||||||
@@ -185,7 +182,7 @@ bitmap_ipmac_list(const struct ip_set *set,
|
|||||||
if (!nested) {
|
if (!nested) {
|
||||||
if (id == first) {
|
if (id == first) {
|
||||||
nla_nest_cancel(skb, atd);
|
nla_nest_cancel(skb, atd);
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
} else
|
} else
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
@@ -205,13 +202,17 @@ bitmap_ipmac_list(const struct ip_set *set,
|
|||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
nla_nest_cancel(skb, nested);
|
nla_nest_cancel(skb, nested);
|
||||||
ipset_nest_end(skb, atd);
|
ipset_nest_end(skb, atd);
|
||||||
|
if (unlikely(id == first)) {
|
||||||
|
cb->args[2] = 0;
|
||||||
|
return -EMSGSIZE;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Timeout variant */
|
/* Timeout variant */
|
||||||
|
|
||||||
static int
|
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 bitmap_ipmac *map = set->data;
|
||||||
const struct ipmac *data = value;
|
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 */
|
/* Trigger kernel to fill out the ethernet address */
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
case MAC_FILLED:
|
case MAC_FILLED:
|
||||||
return (data->ether == NULL
|
return (data->ether == NULL ||
|
||||||
|| compare_ether_addr(data->ether, elem->ether) == 0)
|
compare_ether_addr(data->ether, elem->ether) == 0) &&
|
||||||
&& !bitmap_expired(map, data->id);
|
!bitmap_expired(map, data->id);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct bitmap_ipmac *map = set->data;
|
||||||
const struct ipmac *data = value;
|
const struct ipmac *data = value;
|
||||||
struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
|
struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
|
||||||
|
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||||
|
|
||||||
switch (elem->match) {
|
switch (elem->match) {
|
||||||
case MAC_UNSET:
|
case MAC_UNSET:
|
||||||
if (!data->ether)
|
if (!(data->ether || flag_exist))
|
||||||
/* Already added without ethernet address */
|
/* Already added without ethernet address */
|
||||||
return -IPSET_ERR_EXIST;
|
return -IPSET_ERR_EXIST;
|
||||||
/* Fill the MAC address and activate the timer */
|
/* 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);
|
elem->timeout = ip_set_timeout_set(timeout);
|
||||||
break;
|
break;
|
||||||
case MAC_FILLED:
|
case MAC_FILLED:
|
||||||
if (!bitmap_expired(map, data->id))
|
if (!(bitmap_expired(map, data->id) || flag_exist))
|
||||||
return -IPSET_ERR_EXIST;
|
return -IPSET_ERR_EXIST;
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
case MAC_EMPTY:
|
case MAC_EMPTY:
|
||||||
@@ -272,7 +274,7 @@ bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct bitmap_ipmac *map = set->data;
|
||||||
const struct ipmac *data = value;
|
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);
|
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||||
if (!atd)
|
if (!atd)
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||||
id = cb->args[2];
|
id = cb->args[2];
|
||||||
elem = bitmap_ipmac_elem(map, id);
|
elem = bitmap_ipmac_elem(map, id);
|
||||||
@@ -308,7 +310,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
|
|||||||
if (!nested) {
|
if (!nested) {
|
||||||
if (id == first) {
|
if (id == first) {
|
||||||
nla_nest_cancel(skb, atd);
|
nla_nest_cancel(skb, atd);
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
} else
|
} else
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
@@ -331,7 +333,7 @@ bitmap_ipmac_tlist(const struct ip_set *set,
|
|||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
nla_nest_cancel(skb, nested);
|
nla_nest_cancel(skb, nested);
|
||||||
ipset_nest_end(skb, atd);
|
ipset_nest_end(skb, atd);
|
||||||
return 0;
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct ipmac data;
|
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));
|
data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
||||||
if (data.id < map->first_ip || data.id > map->last_ip)
|
if (data.id < map->first_ip || data.id > map->last_ip)
|
||||||
return -IPSET_ERR_BITMAP_RANGE;
|
return -IPSET_ERR_BITMAP_RANGE;
|
||||||
|
|
||||||
/* Backward compatibility: we don't check the second flag */
|
/* Backward compatibility: we don't check the second flag */
|
||||||
if (skb_mac_header(skb) < skb->head
|
if (skb_mac_header(skb) < skb->head ||
|
||||||
|| (skb_mac_header(skb) + ETH_HLEN) > skb->data)
|
(skb_mac_header(skb) + ETH_HLEN) > skb->data)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
data.id -= map->first_ip;
|
data.id -= map->first_ip;
|
||||||
data.ether = eth_hdr(skb)->h_source;
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct bitmap_ipmac *map = set->data;
|
const struct bitmap_ipmac *map = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct ipmac data;
|
struct ipmac data;
|
||||||
u32 timeout = map->timeout;
|
u32 timeout = map->timeout;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
bitmap_ipmac_adt_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
data.id = ntohl(data.id);
|
|
||||||
|
|
||||||
if (data.id < map->first_ip || data.id > map->last_ip)
|
if (data.id < map->first_ip || data.id > map->last_ip)
|
||||||
return -IPSET_ERR_BITMAP_RANGE;
|
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;
|
data.id -= map->first_ip;
|
||||||
|
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
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;
|
goto nla_put_failure;
|
||||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, htonl(map->first_ip));
|
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_IPADDR4(skb, IPSET_ATTR_IP_TO, htonl(map->last_ip));
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||||
htonl(atomic_read(&set->ref) - 1));
|
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||||
htonl(sizeof(*map)
|
htonl(sizeof(*map)
|
||||||
+ (map->last_ip - map->first_ip + 1) * map->dsize));
|
+ (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;
|
return 0;
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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 *x = a->data;
|
||||||
const struct bitmap_ipmac *y = b->data;
|
const struct bitmap_ipmac *y = b->data;
|
||||||
|
|
||||||
return x->first_ip == y->first_ip
|
return x->first_ip == y->first_ip &&
|
||||||
&& x->last_ip == y->last_ip
|
x->last_ip == y->last_ip &&
|
||||||
&& x->timeout == y->timeout;
|
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,
|
.kadt = bitmap_ipmac_kadt,
|
||||||
.uadt = bitmap_ipmac_uadt,
|
.uadt = bitmap_ipmac_uadt,
|
||||||
.adt = {
|
.adt = {
|
||||||
@@ -483,7 +478,7 @@ const struct ip_set_type_variant bitmap_ipmac = {
|
|||||||
.same_set = bitmap_ipmac_same_set,
|
.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,
|
.kadt = bitmap_ipmac_kadt,
|
||||||
.uadt = bitmap_ipmac_uadt,
|
.uadt = bitmap_ipmac_uadt,
|
||||||
.adt = {
|
.adt = {
|
||||||
@@ -511,8 +506,8 @@ bitmap_ipmac_gc(unsigned long ul_set)
|
|||||||
read_lock_bh(&set->lock);
|
read_lock_bh(&set->lock);
|
||||||
for (id = 0; id <= last; id++) {
|
for (id = 0; id <= last; id++) {
|
||||||
elem = bitmap_ipmac_elem(map, id);
|
elem = bitmap_ipmac_elem(map, id);
|
||||||
if (elem->match == MAC_FILLED
|
if (elem->match == MAC_FILLED &&
|
||||||
&& ip_set_timeout_expired(elem->timeout))
|
ip_set_timeout_expired(elem->timeout))
|
||||||
elem->match = MAC_EMPTY;
|
elem->match = MAC_EMPTY;
|
||||||
}
|
}
|
||||||
read_unlock_bh(&set->lock);
|
read_unlock_bh(&set->lock);
|
||||||
@@ -521,7 +516,7 @@ bitmap_ipmac_gc(unsigned long ul_set)
|
|||||||
add_timer(&map->gc);
|
add_timer(&map->gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
bitmap_ipmac_gc_init(struct ip_set *set)
|
bitmap_ipmac_gc_init(struct ip_set *set)
|
||||||
{
|
{
|
||||||
struct bitmap_ipmac *map = set->data;
|
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 */
|
/* 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
|
static bool
|
||||||
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
||||||
u32 first_ip, u32 last_ip)
|
u32 first_ip, u32 last_ip)
|
||||||
{
|
{
|
||||||
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize,
|
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
|
||||||
GFP_KERNEL);
|
|
||||||
if (!map->members)
|
if (!map->members)
|
||||||
return false;
|
return false;
|
||||||
map->first_ip = first_ip;
|
map->first_ip = first_ip;
|
||||||
@@ -561,28 +548,25 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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)
|
u32 flags)
|
||||||
{
|
{
|
||||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
|
||||||
u32 first_ip, last_ip, elements;
|
u32 first_ip, last_ip, elements;
|
||||||
struct bitmap_ipmac *map;
|
struct bitmap_ipmac *map;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
bitmap_ipmac_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
first_ip = ntohl(first_ip);
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_IP_TO]) {
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
last_ip = ntohl(last_ip);
|
|
||||||
if (first_ip > last_ip) {
|
if (first_ip > last_ip) {
|
||||||
u32 tmp = first_ip;
|
u32 tmp = first_ip;
|
||||||
|
|
||||||
@@ -594,7 +578,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
|
|
||||||
if (cidr >= 32)
|
if (cidr >= 32)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
last_ip = first_ip | ~HOSTMASK(cidr);
|
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
@@ -633,7 +617,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ip_set_type bitmap_ipmac_type = {
|
static struct ip_set_type bitmap_ipmac_type = {
|
||||||
.name = "bitmap:ip,mac",
|
.name = "bitmap:ip,mac",
|
||||||
.protocol = IPSET_PROTOCOL,
|
.protocol = IPSET_PROTOCOL,
|
||||||
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
||||||
@@ -641,6 +625,18 @@ struct ip_set_type bitmap_ipmac_type = {
|
|||||||
.family = AF_INET,
|
.family = AF_INET,
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
.create = bitmap_ipmac_create,
|
.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,
|
.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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the hash:ip type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include "jhash.h"
|
#include "jhash.h"
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
@@ -23,6 +19,7 @@
|
|||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_timeout.h"
|
#include "ip_set_timeout.h"
|
||||||
#include "ip_set_hash.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 */
|
/* Member elements without timeout */
|
||||||
struct hash_ip4_elem {
|
struct hash_ip4_elem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Member elements with timeout support */
|
/* Member elements with timeout support */
|
||||||
struct hash_ip4_telem {
|
struct hash_ip4_telem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
unsigned long timeout;
|
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;
|
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 */
|
/* Zero valued IP addresses cannot be stored */
|
||||||
static inline void
|
static inline void
|
||||||
hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
|
hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
|
||||||
@@ -96,7 +87,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
|
hash_ip4_data_tlist(struct sk_buff *skb, const struct hash_ip4_elem *data)
|
||||||
{
|
{
|
||||||
const struct hash_ip4_telem *tdata =
|
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;
|
const struct ip_set_hash *h = set->data;
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
|
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
|
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &ip);
|
||||||
ip &= NETMASK(h->netmask);
|
ip &= ip_set_netmask(h->netmask);
|
||||||
if (ip == 0)
|
if (ip == 0)
|
||||||
return -EINVAL;
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
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;
|
int ret = 0;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_ip4_adt_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ip &= NETMASK(h->netmask);
|
ip &= ip_set_hostmask(h->netmask);
|
||||||
if (ip == 0)
|
|
||||||
return -IPSET_ERR_HASH_ELEM;
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST)
|
if (adt == IPSET_TEST) {
|
||||||
return adtfn(set, &ip, timeout);
|
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]) {
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ip_to = ntohl(ip_to);
|
|
||||||
if (ip > ip_to)
|
if (ip > ip_to)
|
||||||
swap(ip, ip_to);
|
swap(ip, ip_to);
|
||||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
} 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)
|
if (cidr > 32)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
ip &= HOSTMASK(cidr);
|
ip &= ip_set_hostmask(cidr);
|
||||||
ip_to = ip | ~HOSTMASK(cidr);
|
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||||
} else
|
} else
|
||||||
ip_to = ip;
|
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) {
|
for (; !before(ip_to, ip); ip += hosts) {
|
||||||
nip = htonl(ip);
|
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))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
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;
|
const struct ip_set_hash *y = b->data;
|
||||||
|
|
||||||
/* Resizing changes htable_bits, so we ignore it */
|
/* Resizing changes htable_bits, so we ignore it */
|
||||||
return x->maxelem == y->maxelem
|
return x->maxelem == y->maxelem &&
|
||||||
&& x->timeout == y->timeout
|
x->timeout == y->timeout &&
|
||||||
&& x->netmask == y->netmask;
|
x->netmask == y->netmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The type variant functions: IPv6 */
|
/* 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);
|
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
|
static inline void
|
||||||
hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
|
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
|
static inline void
|
||||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||||
{
|
{
|
||||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
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)
|
hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
|
||||||
{
|
{
|
||||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||||
@@ -284,7 +259,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
|
hash_ip6_data_tlist(struct sk_buff *skb, const struct hash_ip6_elem *data)
|
||||||
{
|
{
|
||||||
const struct hash_ip6_telem *e =
|
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))
|
if (ipv6_addr_any(&ip.in6))
|
||||||
return -EINVAL;
|
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] = {
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_ip6_adt_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||||
|
tb[IPSET_ATTR_IP_TO] ||
|
||||||
|
tb[IPSET_ATTR_CIDR]))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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]);
|
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;
|
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create hash:ip type of sets */
|
/* 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
|
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;
|
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||||
u8 netmask, hbits;
|
u8 netmask, hbits;
|
||||||
struct ip_set_hash *h;
|
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))
|
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||||
return -IPSET_ERR_INVALID_FAMILY;
|
return -IPSET_ERR_INVALID_FAMILY;
|
||||||
netmask = set->family == AF_INET ? 32 : 128;
|
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");
|
set->name, set->family == AF_INET ? "inet" : "inet6");
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||||
hash_ip_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||||
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
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]) {
|
if (tb[IPSET_ATTR_NETMASK]) {
|
||||||
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
|
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
|
||||||
|
|
||||||
if ((set->family == AF_INET && netmask > 32)
|
if ((set->family == AF_INET && netmask > 32) ||
|
||||||
|| (set->family == AF_INET6 && netmask > 128)
|
(set->family == AF_INET6 && netmask > 128) ||
|
||||||
|| netmask == 0)
|
netmask == 0)
|
||||||
return -IPSET_ERR_INVALID_NETMASK;
|
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);
|
hbits = htable_bits(hashsize);
|
||||||
h->table = ip_set_alloc(
|
h->table = ip_set_alloc(
|
||||||
sizeof(struct htable)
|
sizeof(struct htable)
|
||||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!h->table) {
|
if (!h->table) {
|
||||||
kfree(h);
|
kfree(h);
|
||||||
return -ENOMEM;
|
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;
|
? &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),
|
set->name, jhash_size(h->table->htable_bits),
|
||||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
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,
|
.family = AF_UNSPEC,
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
.create = hash_ip_create,
|
.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,
|
.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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the hash:ip,port type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include "jhash.h"
|
#include "jhash.h"
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
@@ -23,6 +19,7 @@
|
|||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_timeout.h"
|
#include "ip_set_timeout.h"
|
||||||
#include "ip_set_getport.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 */
|
/* Member elements without timeout */
|
||||||
struct hash_ipport4_elem {
|
struct hash_ipport4_elem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Member elements with timeout support */
|
/* Member elements with timeout support */
|
||||||
struct hash_ipport4_telem {
|
struct hash_ipport4_telem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -65,9 +62,9 @@ static inline bool
|
|||||||
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
|
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
|
||||||
const struct hash_ipport4_elem *ip2)
|
const struct hash_ipport4_elem *ip2)
|
||||||
{
|
{
|
||||||
return ip1->ip == ip2->ip
|
return ip1->ip == ip2->ip &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto;
|
ip1->proto == ip2->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -85,22 +82,13 @@ hash_ipport4_data_copy(struct hash_ipport4_elem *dst,
|
|||||||
dst->proto = src->proto;
|
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
|
static inline void
|
||||||
hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
|
hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
|
||||||
{
|
{
|
||||||
elem->proto = 0;
|
elem->proto = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipport4_data_list(struct sk_buff *skb,
|
hash_ipport4_data_list(struct sk_buff *skb,
|
||||||
const struct hash_ipport4_elem *data)
|
const struct hash_ipport4_elem *data)
|
||||||
{
|
{
|
||||||
@@ -113,7 +101,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipport4_data_tlist(struct sk_buff *skb,
|
hash_ipport4_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_ipport4_elem *data)
|
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];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipport4_elem data = { };
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipport4_elem data = { };
|
struct hash_ipport4_elem data = { };
|
||||||
u32 ip, ip_to, p, port, port_to;
|
u32 ip, ip_to, p, port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_ipport_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMP:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST ||
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
|
tb[IPSET_ATTR_PORT_TO])) {
|
||||||
|| tb[IPSET_ATTR_PORT_TO])) {
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = ntohl(data.ip);
|
ip = ntohl(data.ip);
|
||||||
if (tb[IPSET_ATTR_IP_TO]) {
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ip_to = ntohl(ip_to);
|
|
||||||
if (ip > ip_to)
|
if (ip > ip_to)
|
||||||
swap(ip, ip_to);
|
swap(ip, ip_to);
|
||||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
} 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)
|
if (cidr > 32)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
ip &= HOSTMASK(cidr);
|
ip &= ip_set_hostmask(cidr);
|
||||||
ip_to = ip | ~HOSTMASK(cidr);
|
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||||
} else
|
} else
|
||||||
ip_to = ip;
|
ip_to = ip;
|
||||||
|
|
||||||
port = ntohs(data.port);
|
port_to = port = ntohs(data.port);
|
||||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||||
if (port > port_to)
|
if (port > port_to)
|
||||||
swap(port, port_to);
|
swap(port, port_to);
|
||||||
} else
|
}
|
||||||
port_to = port;
|
|
||||||
|
|
||||||
for (; !before(ip_to, ip); ip++)
|
for (; !before(ip_to, ip); ip++)
|
||||||
for (p = port; p <= port_to; p++) {
|
for (p = port; p <= port_to; p++) {
|
||||||
data.ip = htonl(ip);
|
data.ip = htonl(ip);
|
||||||
data.port = htons(p);
|
data.port = htons(p);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
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;
|
const struct ip_set_hash *y = b->data;
|
||||||
|
|
||||||
/* Resizing changes htable_bits, so we ignore it */
|
/* Resizing changes htable_bits, so we ignore it */
|
||||||
return x->maxelem == y->maxelem
|
return x->maxelem == y->maxelem &&
|
||||||
&& x->timeout == y->timeout;
|
x->timeout == y->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The type variant functions: IPv6 */
|
/* The type variant functions: IPv6 */
|
||||||
|
|
||||||
struct hash_ipport6_elem {
|
struct hash_ipport6_elem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hash_ipport6_telem {
|
struct hash_ipport6_telem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -297,9 +266,9 @@ static inline bool
|
|||||||
hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
|
hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
|
||||||
const struct hash_ipport6_elem *ip2)
|
const struct hash_ipport6_elem *ip2)
|
||||||
{
|
{
|
||||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto;
|
ip1->proto == ip2->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -315,24 +284,13 @@ hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
|
|||||||
memcpy(dst, src, sizeof(*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
|
static inline void
|
||||||
hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
|
hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
|
||||||
{
|
{
|
||||||
elem->proto = 0;
|
elem->proto = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipport6_data_list(struct sk_buff *skb,
|
hash_ipport6_data_list(struct sk_buff *skb,
|
||||||
const struct hash_ipport6_elem *data)
|
const struct hash_ipport6_elem *data)
|
||||||
{
|
{
|
||||||
@@ -345,7 +303,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipport6_data_tlist(struct sk_buff *skb,
|
hash_ipport6_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_ipport6_elem *data)
|
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];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipport6_elem data = { };
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipport6_elem data = { };
|
struct hash_ipport6_elem data = { };
|
||||||
u32 port, port_to;
|
u32 port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_ipport_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMPV6:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
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++) {
|
for (; port <= port_to; port++) {
|
||||||
data.port = htons(port);
|
data.port = htons(port);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
return ret;
|
||||||
@@ -465,20 +419,9 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
|
|
||||||
/* Create hash:ip type of sets */
|
/* 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
|
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;
|
struct ip_set_hash *h;
|
||||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||||
u8 hbits;
|
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))
|
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||||
return -IPSET_ERR_INVALID_FAMILY;
|
return -IPSET_ERR_INVALID_FAMILY;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||||
hash_ipport_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||||
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
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);
|
hbits = htable_bits(hashsize);
|
||||||
h->table = ip_set_alloc(
|
h->table = ip_set_alloc(
|
||||||
sizeof(struct htable)
|
sizeof(struct htable)
|
||||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!h->table) {
|
if (!h->table) {
|
||||||
kfree(h);
|
kfree(h);
|
||||||
return -ENOMEM;
|
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;
|
? &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),
|
set->name, jhash_size(h->table->htable_bits),
|
||||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
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,
|
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||||
.dimension = IPSET_DIM_TWO,
|
.dimension = IPSET_DIM_TWO,
|
||||||
.family = AF_UNSPEC,
|
.family = AF_UNSPEC,
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.create = hash_ipport_create,
|
.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,
|
.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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the hash:ip,port,ip type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include "jhash.h"
|
#include "jhash.h"
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
@@ -23,6 +19,7 @@
|
|||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_timeout.h"
|
#include "ip_set_timeout.h"
|
||||||
#include "ip_set_getport.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 */
|
/* Member elements without timeout */
|
||||||
struct hash_ipportip4_elem {
|
struct hash_ipportip4_elem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u32 ip2;
|
__be32 ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Member elements with timeout support */
|
/* Member elements with timeout support */
|
||||||
struct hash_ipportip4_telem {
|
struct hash_ipportip4_telem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u32 ip2;
|
__be32 ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -67,10 +64,10 @@ static inline bool
|
|||||||
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
|
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
|
||||||
const struct hash_ipportip4_elem *ip2)
|
const struct hash_ipportip4_elem *ip2)
|
||||||
{
|
{
|
||||||
return ip1->ip == ip2->ip
|
return ip1->ip == ip2->ip &&
|
||||||
&& ip1->ip2 == ip2->ip2
|
ip1->ip2 == ip2->ip2 &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto;
|
ip1->proto == ip2->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -86,24 +83,13 @@ hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
|
|||||||
memcpy(dst, src, sizeof(*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
|
static inline void
|
||||||
hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
|
hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
|
||||||
{
|
{
|
||||||
elem->proto = 0;
|
elem->proto = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportip4_data_list(struct sk_buff *skb,
|
hash_ipportip4_data_list(struct sk_buff *skb,
|
||||||
const struct hash_ipportip4_elem *data)
|
const struct hash_ipportip4_elem *data)
|
||||||
{
|
{
|
||||||
@@ -117,7 +103,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportip4_data_tlist(struct sk_buff *skb,
|
hash_ipportip4_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_ipportip4_elem *data)
|
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];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipportip4_elem data = { };
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipportip4_elem data = { };
|
struct hash_ipportip4_elem data = { };
|
||||||
u32 ip, ip_to, p, port, port_to;
|
u32 ip, ip_to, p, port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||||
hash_ipportip_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMP:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST ||
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
|
tb[IPSET_ATTR_PORT_TO])) {
|
||||||
|| tb[IPSET_ATTR_PORT_TO])) {
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = ntohl(data.ip);
|
ip = ntohl(data.ip);
|
||||||
if (tb[IPSET_ATTR_IP_TO]) {
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ip_to = ntohl(ip_to);
|
|
||||||
if (ip > ip_to)
|
if (ip > ip_to)
|
||||||
swap(ip, ip_to);
|
swap(ip, ip_to);
|
||||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
} 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)
|
if (cidr > 32)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
ip &= HOSTMASK(cidr);
|
ip &= ip_set_hostmask(cidr);
|
||||||
ip_to = ip | ~HOSTMASK(cidr);
|
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||||
} else
|
} else
|
||||||
ip_to = ip;
|
ip_to = ip;
|
||||||
|
|
||||||
port = ntohs(data.port);
|
port_to = port = ntohs(data.port);
|
||||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||||
if (port > port_to)
|
if (port > port_to)
|
||||||
swap(port, port_to);
|
swap(port, port_to);
|
||||||
} else
|
}
|
||||||
port_to = port;
|
|
||||||
|
|
||||||
for (; !before(ip_to, ip); ip++)
|
for (; !before(ip_to, ip); ip++)
|
||||||
for (p = port; p <= port_to; p++) {
|
for (p = port; p <= port_to; p++) {
|
||||||
data.ip = htonl(ip);
|
data.ip = htonl(ip);
|
||||||
data.port = htons(p);
|
data.port = htons(p);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
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;
|
const struct ip_set_hash *y = b->data;
|
||||||
|
|
||||||
/* Resizing changes htable_bits, so we ignore it */
|
/* Resizing changes htable_bits, so we ignore it */
|
||||||
return x->maxelem == y->maxelem
|
return x->maxelem == y->maxelem &&
|
||||||
&& x->timeout == y->timeout;
|
x->timeout == y->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The type variant functions: IPv6 */
|
/* 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 {
|
struct hash_ipportip6_elem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
union nf_inet_addr ip2;
|
union nf_inet_addr ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
};
|
};
|
||||||
@@ -300,7 +266,7 @@ struct hash_ipportip6_elem {
|
|||||||
struct hash_ipportip6_telem {
|
struct hash_ipportip6_telem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
union nf_inet_addr ip2;
|
union nf_inet_addr ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -310,10 +276,10 @@ static inline bool
|
|||||||
hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
|
hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
|
||||||
const struct hash_ipportip6_elem *ip2)
|
const struct hash_ipportip6_elem *ip2)
|
||||||
{
|
{
|
||||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||||
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
|
ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto;
|
ip1->proto == ip2->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -329,24 +295,13 @@ hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
|
|||||||
memcpy(dst, src, sizeof(*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
|
static inline void
|
||||||
hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
|
hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
|
||||||
{
|
{
|
||||||
elem->proto = 0;
|
elem->proto = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportip6_data_list(struct sk_buff *skb,
|
hash_ipportip6_data_list(struct sk_buff *skb,
|
||||||
const struct hash_ipportip6_elem *data)
|
const struct hash_ipportip6_elem *data)
|
||||||
{
|
{
|
||||||
@@ -360,7 +315,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportip6_data_tlist(struct sk_buff *skb,
|
hash_ipportip6_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_ipportip6_elem *data)
|
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];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipportip6_elem data = { };
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipportip6_elem data = { };
|
struct hash_ipportip6_elem data = { };
|
||||||
u32 port, port_to;
|
u32 port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||||
hash_ipportip_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMPV6:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
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++) {
|
for (; port <= port_to; port++) {
|
||||||
data.port = htons(port);
|
data.port = htons(port);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
return ret;
|
||||||
@@ -486,20 +437,9 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
|
|
||||||
/* Create hash:ip type of sets */
|
/* 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
|
static int
|
||||||
hash_ipportip_create(struct ip_set *set, struct nlattr *head,
|
hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||||
int len, u32 flags)
|
|
||||||
{
|
{
|
||||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
|
||||||
struct ip_set_hash *h;
|
struct ip_set_hash *h;
|
||||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||||
u8 hbits;
|
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))
|
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||||
return -IPSET_ERR_INVALID_FAMILY;
|
return -IPSET_ERR_INVALID_FAMILY;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||||
hash_ipportip_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||||
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||||
@@ -531,8 +472,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
|
|||||||
hbits = htable_bits(hashsize);
|
hbits = htable_bits(hashsize);
|
||||||
h->table = ip_set_alloc(
|
h->table = ip_set_alloc(
|
||||||
sizeof(struct htable)
|
sizeof(struct htable)
|
||||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!h->table) {
|
if (!h->table) {
|
||||||
kfree(h);
|
kfree(h);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -556,7 +496,7 @@ hash_ipportip_create(struct ip_set *set, struct nlattr *head,
|
|||||||
? &hash_ipportip4_variant : &hash_ipportip6_variant;
|
? &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),
|
set->name, jhash_size(h->table->htable_bits),
|
||||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
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,
|
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||||
.dimension = IPSET_DIM_THREE,
|
.dimension = IPSET_DIM_THREE,
|
||||||
.family = AF_UNSPEC,
|
.family = AF_UNSPEC,
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.create = hash_ipportip_create,
|
.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,
|
.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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the hash:ip,port,net type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include "jhash.h"
|
#include "jhash.h"
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <asm/uaccess.h>
|
|
||||||
#include <asm/bitops.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
@@ -23,6 +19,7 @@
|
|||||||
#include <net/tcp.h>
|
#include <net/tcp.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_timeout.h"
|
#include "ip_set_timeout.h"
|
||||||
#include "ip_set_getport.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 */
|
/* Member elements without timeout */
|
||||||
struct hash_ipportnet4_elem {
|
struct hash_ipportnet4_elem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u32 ip2;
|
__be32 ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Member elements with timeout support */
|
/* Member elements with timeout support */
|
||||||
struct hash_ipportnet4_telem {
|
struct hash_ipportnet4_telem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u32 ip2;
|
__be32 ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -67,11 +64,11 @@ static inline bool
|
|||||||
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
|
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
|
||||||
const struct hash_ipportnet4_elem *ip2)
|
const struct hash_ipportnet4_elem *ip2)
|
||||||
{
|
{
|
||||||
return ip1->ip == ip2->ip
|
return ip1->ip == ip2->ip &&
|
||||||
&& ip1->ip2 == ip2->ip2
|
ip1->ip2 == ip2->ip2 &&
|
||||||
&& ip1->cidr == ip2->cidr
|
ip1->cidr == ip2->cidr &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto;
|
ip1->proto == ip2->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -87,21 +84,10 @@ hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
|
|||||||
memcpy(dst, src, sizeof(*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
|
static inline void
|
||||||
hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
|
hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
|
||||||
{
|
{
|
||||||
elem->ip2 &= NETMASK(cidr);
|
elem->ip2 &= ip_set_netmask(cidr);
|
||||||
elem->cidr = cidr;
|
elem->cidr = cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +97,7 @@ hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
|
|||||||
elem->proto = 0;
|
elem->proto = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportnet4_data_list(struct sk_buff *skb,
|
hash_ipportnet4_data_list(struct sk_buff *skb,
|
||||||
const struct hash_ipportnet4_elem *data)
|
const struct hash_ipportnet4_elem *data)
|
||||||
{
|
{
|
||||||
@@ -126,7 +112,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportnet4_data_tlist(struct sk_buff *skb,
|
hash_ipportnet4_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_ipportnet4_elem *data)
|
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)
|
if (adt == IPSET_TEST)
|
||||||
data.cidr = HOST_MASK;
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
|
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
|
||||||
u32 ip, ip_to, p, port, port_to;
|
u32 ip, ip_to, p, port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||||
hash_ipportnet_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -226,30 +200,24 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
if (!data.cidr)
|
if (!data.cidr)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
|
|
||||||
data.ip2 &= NETMASK(data.cidr);
|
data.ip2 &= ip_set_netmask(data.cidr);
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMP:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST ||
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||||
|| !(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR]
|
tb[IPSET_ATTR_PORT_TO])) {
|
||||||
|| tb[IPSET_ATTR_PORT_TO])) {
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = ntohl(data.ip);
|
ip = ntohl(data.ip);
|
||||||
if (tb[IPSET_ATTR_IP_TO]) {
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ip_to = ntohl(ip_to);
|
|
||||||
if (ip > ip_to)
|
if (ip > ip_to)
|
||||||
swap(ip, ip_to);
|
swap(ip, ip_to);
|
||||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
} 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)
|
if (cidr > 32)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
ip &= HOSTMASK(cidr);
|
ip &= ip_set_hostmask(cidr);
|
||||||
ip_to = ip | ~HOSTMASK(cidr);
|
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||||
} else
|
} else
|
||||||
ip_to = ip;
|
ip_to = ip;
|
||||||
|
|
||||||
port = ntohs(data.port);
|
port_to = port = ntohs(data.port);
|
||||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||||
if (port > port_to)
|
if (port > port_to)
|
||||||
swap(port, port_to);
|
swap(port, port_to);
|
||||||
} else
|
}
|
||||||
port_to = port;
|
|
||||||
|
|
||||||
for (; !before(ip_to, ip); ip++)
|
for (; !before(ip_to, ip); ip++)
|
||||||
for (p = port; p <= port_to; p++) {
|
for (p = port; p <= port_to; p++) {
|
||||||
data.ip = htonl(ip);
|
data.ip = htonl(ip);
|
||||||
data.port = htons(p);
|
data.port = htons(p);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
return ret;
|
||||||
@@ -310,10 +275,10 @@ hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b)
|
|||||||
{
|
{
|
||||||
const struct ip_set_hash *x = a->data;
|
const struct ip_set_hash *x = a->data;
|
||||||
const struct ip_set_hash *y = b->data;
|
const struct ip_set_hash *y = b->data;
|
||||||
|
|
||||||
/* Resizing changes htable_bits, so we ignore it */
|
/* Resizing changes htable_bits, so we ignore it */
|
||||||
return x->maxelem == y->maxelem
|
return x->maxelem == y->maxelem &&
|
||||||
&& x->timeout == y->timeout;
|
x->timeout == y->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The type variant functions: IPv6 */
|
/* 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 {
|
struct hash_ipportnet6_elem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
union nf_inet_addr ip2;
|
union nf_inet_addr ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
};
|
};
|
||||||
@@ -329,7 +294,7 @@ struct hash_ipportnet6_elem {
|
|||||||
struct hash_ipportnet6_telem {
|
struct hash_ipportnet6_telem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
union nf_inet_addr ip2;
|
union nf_inet_addr ip2;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -339,11 +304,11 @@ static inline bool
|
|||||||
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
|
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
|
||||||
const struct hash_ipportnet6_elem *ip2)
|
const struct hash_ipportnet6_elem *ip2)
|
||||||
{
|
{
|
||||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||||
&& ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0
|
ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
|
||||||
&& ip1->cidr == ip2->cidr
|
ip1->cidr == ip2->cidr &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto;
|
ip1->proto == ip2->proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -359,17 +324,6 @@ hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
|
|||||||
memcpy(dst, src, sizeof(*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
|
static inline void
|
||||||
hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
|
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
|
static inline void
|
||||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||||
{
|
{
|
||||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -392,7 +346,7 @@ hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
|
|||||||
elem->cidr = cidr;
|
elem->cidr = cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportnet6_data_list(struct sk_buff *skb,
|
hash_ipportnet6_data_list(struct sk_buff *skb,
|
||||||
const struct hash_ipportnet6_elem *data)
|
const struct hash_ipportnet6_elem *data)
|
||||||
{
|
{
|
||||||
@@ -407,13 +361,13 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_ipportnet6_data_tlist(struct sk_buff *skb,
|
hash_ipportnet6_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_ipportnet6_elem *data)
|
const struct hash_ipportnet6_elem *data)
|
||||||
{
|
{
|
||||||
const struct hash_ipportnet6_telem *e =
|
const struct hash_ipportnet6_telem *e =
|
||||||
(const struct hash_ipportnet6_telem *)data;
|
(const struct hash_ipportnet6_telem *)data;
|
||||||
|
|
||||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
|
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
|
||||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||||
@@ -448,41 +402,45 @@ hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||||||
if (adt == IPSET_TEST)
|
if (adt == IPSET_TEST)
|
||||||
data.cidr = HOST_MASK;
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||||
ip6_netmask(&data.ip2, data.cidr);
|
ip6_netmask(&data.ip2, data.cidr);
|
||||||
|
|
||||||
return adtfn(set, &data, h->timeout);
|
return adtfn(set, &data, h->timeout, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
|
struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
|
||||||
u32 port, port_to;
|
u32 port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||||
hash_ipportnet_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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)
|
if (ret)
|
||||||
return 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);
|
ip6_netmask(&data.ip2, data.cidr);
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMPV6:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
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++) {
|
for (; port <= port_to; port++) {
|
||||||
data.port = htons(port);
|
data.port = htons(port);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
return ret;
|
||||||
@@ -549,20 +499,9 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
|
|
||||||
/* Create hash:ip type of sets */
|
/* 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
|
static int
|
||||||
hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||||
int len, u32 flags)
|
|
||||||
{
|
{
|
||||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
|
||||||
struct ip_set_hash *h;
|
struct ip_set_hash *h;
|
||||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||||
u8 hbits;
|
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))
|
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||||
return -IPSET_ERR_INVALID_FAMILY;
|
return -IPSET_ERR_INVALID_FAMILY;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||||
hash_ipportnet_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||||
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||||
@@ -596,8 +536,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
|||||||
hbits = htable_bits(hashsize);
|
hbits = htable_bits(hashsize);
|
||||||
h->table = ip_set_alloc(
|
h->table = ip_set_alloc(
|
||||||
sizeof(struct htable)
|
sizeof(struct htable)
|
||||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!h->table) {
|
if (!h->table) {
|
||||||
kfree(h);
|
kfree(h);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@@ -608,7 +547,7 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
|||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
|
|
||||||
set->variant = set->family == AF_INET
|
set->variant = set->family == AF_INET
|
||||||
? &hash_ipportnet4_tvariant
|
? &hash_ipportnet4_tvariant
|
||||||
: &hash_ipportnet6_tvariant;
|
: &hash_ipportnet6_tvariant;
|
||||||
@@ -621,11 +560,11 @@ hash_ipportnet_create(struct ip_set *set, struct nlattr *head,
|
|||||||
set->variant = set->family == AF_INET
|
set->variant = set->family == AF_INET
|
||||||
? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
|
? &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),
|
set->name, jhash_size(h->table->htable_bits),
|
||||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,8 +574,27 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
|||||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||||
.dimension = IPSET_DIM_THREE,
|
.dimension = IPSET_DIM_THREE,
|
||||||
.family = AF_UNSPEC,
|
.family = AF_UNSPEC,
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.create = hash_ipportnet_create,
|
.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,
|
.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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the hash:net type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include "jhash.h"
|
#include "jhash.h"
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/netlink.h>
|
#include <net/netlink.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_timeout.h"
|
#include "ip_set_timeout.h"
|
||||||
#include "ip_set_hash.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 */
|
/* Member elements without timeout */
|
||||||
struct hash_net4_elem {
|
struct hash_net4_elem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u16 padding0;
|
u16 padding0;
|
||||||
u8 padding1;
|
u8 padding1;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
@@ -52,7 +49,7 @@ struct hash_net4_elem {
|
|||||||
|
|
||||||
/* Member elements with timeout support */
|
/* Member elements with timeout support */
|
||||||
struct hash_net4_telem {
|
struct hash_net4_telem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u16 padding0;
|
u16 padding0;
|
||||||
u8 padding1;
|
u8 padding1;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
@@ -80,18 +77,10 @@ hash_net4_data_copy(struct hash_net4_elem *dst,
|
|||||||
dst->cidr = src->cidr;
|
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
|
static inline void
|
||||||
hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
|
hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
|
||||||
{
|
{
|
||||||
elem->ip &= NETMASK(cidr);
|
elem->ip &= ip_set_netmask(cidr);
|
||||||
elem->cidr = cidr;
|
elem->cidr = cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +91,7 @@ hash_net4_data_zero_out(struct hash_net4_elem *elem)
|
|||||||
elem->cidr = 0;
|
elem->cidr = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
|
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
|
||||||
{
|
{
|
||||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||||
@@ -113,7 +102,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
|
hash_net4_data_tlist(struct sk_buff *skb, const struct hash_net4_elem *data)
|
||||||
{
|
{
|
||||||
const struct hash_net4_telem *tdata =
|
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;
|
data.cidr = HOST_MASK;
|
||||||
|
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_net4_elem data = { .cidr = HOST_MASK };
|
struct hash_net4_elem data = { .cidr = HOST_MASK };
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_net_adt_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -189,7 +171,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
if (!data.cidr)
|
if (!data.cidr)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
|
|
||||||
data.ip &= NETMASK(data.cidr);
|
data.ip &= ip_set_netmask(data.cidr);
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
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;
|
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;
|
const struct ip_set_hash *y = b->data;
|
||||||
|
|
||||||
/* Resizing changes htable_bits, so we ignore it */
|
/* Resizing changes htable_bits, so we ignore it */
|
||||||
return x->maxelem == y->maxelem
|
return x->maxelem == y->maxelem &&
|
||||||
&& x->timeout == y->timeout;
|
x->timeout == y->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The type variant functions: IPv6 */
|
/* The type variant functions: IPv6 */
|
||||||
@@ -234,8 +216,8 @@ static inline bool
|
|||||||
hash_net6_data_equal(const struct hash_net6_elem *ip1,
|
hash_net6_data_equal(const struct hash_net6_elem *ip1,
|
||||||
const struct hash_net6_elem *ip2)
|
const struct hash_net6_elem *ip2)
|
||||||
{
|
{
|
||||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||||
&& ip1->cidr == ip2->cidr;
|
ip1->cidr == ip2->cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -252,16 +234,6 @@ hash_net6_data_copy(struct hash_net6_elem *dst,
|
|||||||
dst->cidr = src->cidr;
|
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
|
static inline void
|
||||||
hash_net6_data_zero_out(struct hash_net6_elem *elem)
|
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
|
static inline void
|
||||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||||
{
|
{
|
||||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -284,7 +256,7 @@ hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
|
|||||||
elem->cidr = cidr;
|
elem->cidr = cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
|
hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
|
||||||
{
|
{
|
||||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||||
@@ -295,7 +267,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
|
hash_net6_data_tlist(struct sk_buff *skb, const struct hash_net6_elem *data)
|
||||||
{
|
{
|
||||||
const struct hash_net6_telem *e =
|
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);
|
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||||
ip6_netmask(&data.ip, data.cidr);
|
ip6_netmask(&data.ip, data.cidr);
|
||||||
|
|
||||||
return adtfn(set, &data, h->timeout);
|
return adtfn(set, &data, h->timeout, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_net6_elem data = { .cidr = HOST_MASK };
|
struct hash_net6_elem data = { .cidr = HOST_MASK };
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_net_adt_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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]);
|
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;
|
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create hash:ip type of sets */
|
/* 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
|
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;
|
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||||
struct ip_set_hash *h;
|
struct ip_set_hash *h;
|
||||||
u8 hbits;
|
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))
|
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||||
return -IPSET_ERR_INVALID_FAMILY;
|
return -IPSET_ERR_INVALID_FAMILY;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||||
hash_net_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||||
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
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);
|
hbits = htable_bits(hashsize);
|
||||||
h->table = ip_set_alloc(
|
h->table = ip_set_alloc(
|
||||||
sizeof(struct htable)
|
sizeof(struct htable)
|
||||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!h->table) {
|
if (!h->table) {
|
||||||
kfree(h);
|
kfree(h);
|
||||||
return -ENOMEM;
|
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;
|
? &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),
|
set->name, jhash_size(h->table->htable_bits),
|
||||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
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,
|
.family = AF_UNSPEC,
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
.create = hash_net_create,
|
.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,
|
.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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the hash:net,port type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include "jhash.h"
|
#include "jhash.h"
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/spinlock.h>
|
|
||||||
#include <linux/random.h>
|
#include <linux/random.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
#include <net/ipv6.h>
|
#include <net/ipv6.h>
|
||||||
#include <net/netlink.h>
|
#include <net/netlink.h>
|
||||||
|
|
||||||
#include <linux/netfilter.h>
|
#include <linux/netfilter.h>
|
||||||
|
#include "pfxlen.h"
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
#include "ip_set_timeout.h"
|
#include "ip_set_timeout.h"
|
||||||
#include "ip_set_getport.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 */
|
/* Member elements without timeout */
|
||||||
struct hash_netport4_elem {
|
struct hash_netport4_elem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Member elements with timeout support */
|
/* Member elements with timeout support */
|
||||||
struct hash_netport4_telem {
|
struct hash_netport4_telem {
|
||||||
u32 ip;
|
__be32 ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -64,10 +61,10 @@ static inline bool
|
|||||||
hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
|
hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
|
||||||
const struct hash_netport4_elem *ip2)
|
const struct hash_netport4_elem *ip2)
|
||||||
{
|
{
|
||||||
return ip1->ip == ip2->ip
|
return ip1->ip == ip2->ip &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto
|
ip1->proto == ip2->proto &&
|
||||||
&& ip1->cidr == ip2->cidr;
|
ip1->cidr == ip2->cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -86,20 +83,10 @@ hash_netport4_data_copy(struct hash_netport4_elem *dst,
|
|||||||
dst->cidr = src->cidr;
|
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
|
static inline void
|
||||||
hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
|
hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
|
||||||
{
|
{
|
||||||
elem->ip &= NETMASK(cidr);
|
elem->ip &= ip_set_netmask(cidr);
|
||||||
elem->cidr = cidr;
|
elem->cidr = cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +96,7 @@ hash_netport4_data_zero_out(struct hash_netport4_elem *elem)
|
|||||||
elem->proto = 0;
|
elem->proto = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_netport4_data_list(struct sk_buff *skb,
|
hash_netport4_data_list(struct sk_buff *skb,
|
||||||
const struct hash_netport4_elem *data)
|
const struct hash_netport4_elem *data)
|
||||||
{
|
{
|
||||||
@@ -123,7 +110,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_netport4_data_tlist(struct sk_buff *skb,
|
hash_netport4_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_netport4_elem *data)
|
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)
|
if (adt == IPSET_TEST)
|
||||||
data.cidr = HOST_MASK;
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_netport4_elem data = { .cidr = HOST_MASK };
|
struct hash_netport4_elem data = { .cidr = HOST_MASK };
|
||||||
u32 port, port_to;
|
u32 port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_netport_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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]);
|
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||||
if (!data.cidr)
|
if (!data.cidr)
|
||||||
return -IPSET_ERR_INVALID_CIDR;
|
return -IPSET_ERR_INVALID_CIDR;
|
||||||
data.ip &= NETMASK(data.cidr);
|
data.ip &= ip_set_netmask(data.cidr);
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMP:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
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++) {
|
for (; port <= port_to; port++) {
|
||||||
data.port = htons(port);
|
data.port = htons(port);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
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;
|
const struct ip_set_hash *y = b->data;
|
||||||
|
|
||||||
/* Resizing changes htable_bits, so we ignore it */
|
/* Resizing changes htable_bits, so we ignore it */
|
||||||
return x->maxelem == y->maxelem
|
return x->maxelem == y->maxelem &&
|
||||||
&& x->timeout == y->timeout;
|
x->timeout == y->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The type variant functions: IPv6 */
|
/* The type variant functions: IPv6 */
|
||||||
|
|
||||||
struct hash_netport6_elem {
|
struct hash_netport6_elem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hash_netport6_telem {
|
struct hash_netport6_telem {
|
||||||
union nf_inet_addr ip;
|
union nf_inet_addr ip;
|
||||||
u16 port;
|
__be16 port;
|
||||||
u8 proto;
|
u8 proto;
|
||||||
u8 cidr;
|
u8 cidr;
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
@@ -299,10 +269,10 @@ static inline bool
|
|||||||
hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
|
hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
|
||||||
const struct hash_netport6_elem *ip2)
|
const struct hash_netport6_elem *ip2)
|
||||||
{
|
{
|
||||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0
|
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||||
&& ip1->port == ip2->port
|
ip1->port == ip2->port &&
|
||||||
&& ip1->proto == ip2->proto
|
ip1->proto == ip2->proto &&
|
||||||
&& ip1->cidr == ip2->cidr;
|
ip1->cidr == ip2->cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -318,17 +288,6 @@ hash_netport6_data_copy(struct hash_netport6_elem *dst,
|
|||||||
memcpy(dst, src, sizeof(*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
|
static inline void
|
||||||
hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
|
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
|
static inline void
|
||||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||||
{
|
{
|
||||||
ip->ip6[0] &= NETMASK6(prefix)[0];
|
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||||
ip->ip6[1] &= NETMASK6(prefix)[1];
|
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||||
ip->ip6[2] &= NETMASK6(prefix)[2];
|
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||||
ip->ip6[3] &= NETMASK6(prefix)[3];
|
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -351,7 +310,7 @@ hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
|
|||||||
elem->cidr = cidr;
|
elem->cidr = cidr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_netport6_data_list(struct sk_buff *skb,
|
hash_netport6_data_list(struct sk_buff *skb,
|
||||||
const struct hash_netport6_elem *data)
|
const struct hash_netport6_elem *data)
|
||||||
{
|
{
|
||||||
@@ -365,7 +324,7 @@ nla_put_failure:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
hash_netport6_data_tlist(struct sk_buff *skb,
|
hash_netport6_data_tlist(struct sk_buff *skb,
|
||||||
const struct hash_netport6_elem *data)
|
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)
|
if (adt == IPSET_TEST)
|
||||||
data.cidr = HOST_MASK;
|
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))
|
&data.port, &data.proto))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||||
ip6_netmask(&data.ip, data.cidr);
|
ip6_netmask(&data.ip, data.cidr);
|
||||||
|
|
||||||
return adtfn(set, &data, h->timeout);
|
return adtfn(set, &data, h->timeout, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
const struct ip_set_hash *h = set->data;
|
const struct ip_set_hash *h = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||||
struct hash_netport6_elem data = { .cidr = HOST_MASK };
|
struct hash_netport6_elem data = { .cidr = HOST_MASK };
|
||||||
u32 port, port_to;
|
u32 port, port_to;
|
||||||
u32 timeout = h->timeout;
|
u32 timeout = h->timeout;
|
||||||
|
bool with_ports = false;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||||
hash_netport_adt_policy))
|
!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;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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)
|
if (ret)
|
||||||
return 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);
|
ip6_netmask(&data.ip, data.cidr);
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PORT])
|
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
|
else
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_PROTO]) {
|
if (tb[IPSET_ATTR_PROTO]) {
|
||||||
data.proto = nla_get_u8(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)
|
if (data.proto == 0)
|
||||||
return -IPSET_ERR_INVALID_PROTO;
|
return -IPSET_ERR_INVALID_PROTO;
|
||||||
} else
|
} else
|
||||||
return -IPSET_ERR_MISSING_PROTO;
|
return -IPSET_ERR_MISSING_PROTO;
|
||||||
|
|
||||||
switch (data.proto) {
|
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||||
case IPPROTO_UDP:
|
|
||||||
case IPPROTO_TCP:
|
|
||||||
case IPPROTO_ICMPV6:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data.port = 0;
|
data.port = 0;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||||
if (!with_timeout(h->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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (adt == IPSET_TEST
|
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||||
|| !(data.proto == IPPROTO_TCP || data.proto == IPPROTO_UDP)
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|| !tb[IPSET_ATTR_PORT_TO]) {
|
|
||||||
ret = adtfn(set, &data, timeout);
|
|
||||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
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++) {
|
for (; port <= port_to; port++) {
|
||||||
data.port = htons(port);
|
data.port = htons(port);
|
||||||
ret = adtfn(set, &data, timeout);
|
ret = adtfn(set, &data, timeout, flags);
|
||||||
|
|
||||||
if (ret && !ip_set_eexist(ret, flags))
|
if (ret && !ip_set_eexist(ret, flags))
|
||||||
return ret;
|
return ret;
|
||||||
@@ -499,20 +452,9 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
|
|
||||||
/* Create hash:ip type of sets */
|
/* 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
|
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;
|
struct ip_set_hash *h;
|
||||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||||
u8 hbits;
|
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))
|
if (!(set->family == AF_INET || set->family == AF_INET6))
|
||||||
return -IPSET_ERR_INVALID_FAMILY;
|
return -IPSET_ERR_INVALID_FAMILY;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||||
hash_netport_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||||
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
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);
|
hbits = htable_bits(hashsize);
|
||||||
h->table = ip_set_alloc(
|
h->table = ip_set_alloc(
|
||||||
sizeof(struct htable)
|
sizeof(struct htable)
|
||||||
+ jhash_size(hbits) * sizeof(struct hbucket),
|
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||||
GFP_KERNEL);
|
|
||||||
if (!h->table) {
|
if (!h->table) {
|
||||||
kfree(h);
|
kfree(h);
|
||||||
return -ENOMEM;
|
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;
|
? &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),
|
set->name, jhash_size(h->table->htable_bits),
|
||||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
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,
|
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||||
.dimension = IPSET_DIM_TWO,
|
.dimension = IPSET_DIM_TWO,
|
||||||
.family = AF_UNSPEC,
|
.family = AF_UNSPEC,
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.create = hash_netport_create,
|
.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,
|
.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
|
* 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
|
* 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 */
|
/* Kernel module implementing an IP set type: the list:set type */
|
||||||
|
|
||||||
#include "ip_set_kernel.h"
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/ip.h>
|
#include <linux/ip.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
@@ -44,14 +43,19 @@ struct list_set {
|
|||||||
static inline struct set_elem *
|
static inline struct set_elem *
|
||||||
list_set_elem(const struct list_set *map, u32 id)
|
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
|
static inline bool
|
||||||
list_set_timeout(const struct list_set *map, u32 id)
|
list_set_timeout(const struct list_set *map, u32 id)
|
||||||
{
|
{
|
||||||
const struct set_telem *elem =
|
const struct set_telem *elem = list_set_telem(map, id);
|
||||||
(const struct set_telem *) list_set_elem(map, id);
|
|
||||||
|
|
||||||
return ip_set_timeout_test(elem->timeout);
|
return ip_set_timeout_test(elem->timeout);
|
||||||
}
|
}
|
||||||
@@ -59,19 +63,11 @@ list_set_timeout(const struct list_set *map, u32 id)
|
|||||||
static inline bool
|
static inline bool
|
||||||
list_set_expired(const struct list_set *map, u32 id)
|
list_set_expired(const struct list_set *map, u32 id)
|
||||||
{
|
{
|
||||||
const struct set_telem *elem =
|
const struct set_telem *elem = list_set_telem(map, id);
|
||||||
(const struct set_telem *) list_set_elem(map, id);
|
|
||||||
|
|
||||||
return ip_set_timeout_expired(elem->timeout);
|
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 */
|
/* Set list without and with timeout */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -112,32 +108,35 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct nla_policy list_set_adt_policy[IPSET_ATTR_ADT_MAX+1] = {
|
static bool
|
||||||
[IPSET_ATTR_NAME] = { .type = NLA_STRING,
|
id_eq(const struct list_set *map, u32 i, ip_set_id_t id)
|
||||||
.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)
|
|
||||||
{
|
{
|
||||||
const struct set_elem *elem;
|
const struct set_elem *elem;
|
||||||
|
|
||||||
if (i + 1 < map->size) {
|
if (i < map->size) {
|
||||||
elem = list_set_elem(map, i + 1);
|
elem = list_set_elem(map, i);
|
||||||
return !!(elem->id == id
|
return elem->id == id;
|
||||||
&& !(with_timeout(map->timeout)
|
|
||||||
&& list_set_expired(map, i + 1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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)
|
list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
|
||||||
{
|
{
|
||||||
struct set_elem *e;
|
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,
|
list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
|
||||||
unsigned long timeout)
|
unsigned long timeout)
|
||||||
{
|
{
|
||||||
struct set_telem *e;
|
struct set_telem *e;
|
||||||
|
|
||||||
for (; i < map->size; i++) {
|
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->id, id);
|
||||||
|
swap(e->timeout, timeout);
|
||||||
if (e->id == IPSET_INVALID_ID)
|
if (e->id == IPSET_INVALID_ID)
|
||||||
break;
|
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 */
|
/* Last element replaced: e.g. add new,before,last */
|
||||||
ip_set_put_byindex(e->id);
|
ip_set_put_byindex(e->id);
|
||||||
if (with_timeout(map->timeout))
|
if (with_timeout(map->timeout))
|
||||||
list_elem_tadd(map, i, id, timeout);
|
list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
|
||||||
else
|
else
|
||||||
list_elem_add(map, i, id);
|
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
|
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;
|
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++) {
|
for (; i < map->size - 1; i++) {
|
||||||
b = list_set_elem(map, i + 1);
|
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;
|
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
|
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)
|
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||||
{
|
{
|
||||||
struct list_set *map = set->data;
|
struct list_set *map = set->data;
|
||||||
struct nlattr *tb[IPSET_ATTR_ADT_MAX+1];
|
|
||||||
bool with_timeout = with_timeout(map->timeout);
|
bool with_timeout = with_timeout(map->timeout);
|
||||||
|
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||||
int before = 0;
|
int before = 0;
|
||||||
u32 timeout = map->timeout;
|
u32 timeout = map->timeout;
|
||||||
ip_set_id_t id, refid = IPSET_INVALID_ID;
|
ip_set_id_t id, refid = IPSET_INVALID_ID;
|
||||||
@@ -219,24 +231,22 @@ list_set_uadt(struct ip_set *set, struct nlattr *head, int len,
|
|||||||
u32 i;
|
u32 i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_ADT_MAX, head, len,
|
if (unlikely(!tb[IPSET_ATTR_NAME] ||
|
||||||
list_set_adt_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||||
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_LINENO])
|
if (tb[IPSET_ATTR_LINENO])
|
||||||
*lineno = nla_get_u32(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);
|
||||||
id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
|
if (id == IPSET_INVALID_ID)
|
||||||
if (id == IPSET_INVALID_ID)
|
return -IPSET_ERR_NAME;
|
||||||
return -IPSET_ERR_NAME;
|
/* "Loop detection" */
|
||||||
/* "Loop detection" */
|
if (s->type->features & IPSET_TYPE_NAME) {
|
||||||
if (s->type->features & IPSET_TYPE_NAME) {
|
ret = -IPSET_ERR_LOOP;
|
||||||
ret = -IPSET_ERR_LOOP;
|
goto finish;
|
||||||
goto finish;
|
}
|
||||||
}
|
|
||||||
} else
|
|
||||||
return -IPSET_ERR_PROTOCOL;
|
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||||
u32 f = ip_set_get_h32(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]);
|
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||||
}
|
}
|
||||||
|
if (with_timeout && adt != IPSET_TEST)
|
||||||
|
cleanup_entries(map);
|
||||||
|
|
||||||
switch (adt) {
|
switch (adt) {
|
||||||
case IPSET_TEST:
|
case IPSET_TEST:
|
||||||
for (i = 0; i < map->size && !ret; i++) {
|
for (i = 0; i < map->size && !ret; i++) {
|
||||||
elem = list_set_elem(map, i);
|
elem = list_set_elem(map, i);
|
||||||
if (elem->id == IPSET_INVALID_ID
|
if (elem->id == IPSET_INVALID_ID ||
|
||||||
|| (before != 0 && i + 1 >= map->size))
|
(before != 0 && i + 1 >= map->size))
|
||||||
break;
|
break;
|
||||||
else if (with_timeout && list_set_expired(map, i))
|
else if (with_timeout && list_set_expired(map, i))
|
||||||
continue;
|
continue;
|
||||||
else if (before > 0 && elem->id == id)
|
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)
|
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)
|
else if (before == 0 && elem->id == id)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case IPSET_ADD:
|
case IPSET_ADD:
|
||||||
for (i = 0; i < map->size && !ret; i++) {
|
for (i = 0; i < map->size; i++) {
|
||||||
elem = list_set_elem(map, i);
|
elem = list_set_elem(map, i);
|
||||||
if (elem->id == id
|
if (elem->id != id)
|
||||||
&& !(with_timeout && list_set_expired(map, i)))
|
continue;
|
||||||
|
if (!(with_timeout && flag_exist)) {
|
||||||
ret = -IPSET_ERR_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;
|
ret = -IPSET_ERR_LIST_FULL;
|
||||||
for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
|
for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
|
||||||
elem = list_set_elem(map, 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);
|
: list_set_add(map, i, id, timeout);
|
||||||
else if (elem->id != refid)
|
else if (elem->id != refid)
|
||||||
continue;
|
continue;
|
||||||
else if (with_timeout && list_set_expired(map, i))
|
else if (before > 0)
|
||||||
ret = -IPSET_ERR_REF_EXIST;
|
|
||||||
else if (before)
|
|
||||||
ret = list_set_add(map, i, id, timeout);
|
ret = list_set_add(map, i, id, timeout);
|
||||||
else if (i + 1 < map->size)
|
else if (i + 1 < map->size)
|
||||||
ret = list_set_add(map, i + 1, id, timeout);
|
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
|
ret = before != 0 ? -IPSET_ERR_REF_EXIST
|
||||||
: -IPSET_ERR_EXIST;
|
: -IPSET_ERR_EXIST;
|
||||||
break;
|
break;
|
||||||
} else if (with_timeout && list_set_expired(map, i))
|
} else if (elem->id == id &&
|
||||||
continue;
|
(before == 0 ||
|
||||||
else if (elem->id == id
|
(before > 0 && id_eq(map, i + 1, refid))))
|
||||||
&& (before == 0
|
ret = list_set_del(map, i);
|
||||||
|| (before > 0
|
else if (elem->id == refid &&
|
||||||
&& next_id_eq(map, i, refid))))
|
before < 0 && id_eq(map, i + 1, id))
|
||||||
ret = list_set_del(map, id, i);
|
ret = list_set_del(map, i + 1);
|
||||||
else if (before < 0
|
|
||||||
&& elem->id == refid
|
|
||||||
&& next_id_eq(map, i, id))
|
|
||||||
ret = list_set_del(map, id, i + 1);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
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));
|
NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size));
|
||||||
if (with_timeout(map->timeout))
|
if (with_timeout(map->timeout))
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
|
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES,
|
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||||
htonl(atomic_read(&set->ref) - 1));
|
|
||||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||||
htonl(sizeof(*map) + map->size * map->dsize));
|
htonl(sizeof(*map) + map->size * map->dsize));
|
||||||
ipset_nest_end(skb, nested);
|
ipset_nest_end(skb, nested);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -405,7 +425,7 @@ list_set_list(const struct ip_set *set,
|
|||||||
|
|
||||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||||
if (!atd)
|
if (!atd)
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
for (; cb->args[2] < map->size; cb->args[2]++) {
|
for (; cb->args[2] < map->size; cb->args[2]++) {
|
||||||
i = cb->args[2];
|
i = cb->args[2];
|
||||||
e = list_set_elem(map, i);
|
e = list_set_elem(map, i);
|
||||||
@@ -417,7 +437,7 @@ list_set_list(const struct ip_set *set,
|
|||||||
if (!nested) {
|
if (!nested) {
|
||||||
if (i == first) {
|
if (i == first) {
|
||||||
nla_nest_cancel(skb, atd);
|
nla_nest_cancel(skb, atd);
|
||||||
return -EFAULT;
|
return -EMSGSIZE;
|
||||||
} else
|
} else
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
}
|
}
|
||||||
@@ -440,6 +460,10 @@ finish:
|
|||||||
nla_put_failure:
|
nla_put_failure:
|
||||||
nla_nest_cancel(skb, nested);
|
nla_nest_cancel(skb, nested);
|
||||||
ipset_nest_end(skb, atd);
|
ipset_nest_end(skb, atd);
|
||||||
|
if (unlikely(i == first)) {
|
||||||
|
cb->args[2] = 0;
|
||||||
|
return -EMSGSIZE;
|
||||||
|
}
|
||||||
return 0;
|
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 *x = a->data;
|
||||||
const struct list_set *y = b->data;
|
const struct list_set *y = b->data;
|
||||||
|
|
||||||
return x->size == y->size
|
return x->size == y->size &&
|
||||||
&& x->timeout == y->timeout;
|
x->timeout == y->timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ip_set_type_variant list_set = {
|
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 ip_set *set = (struct ip_set *) ul_set;
|
||||||
struct list_set *map = set->data;
|
struct list_set *map = set->data;
|
||||||
struct set_telem *e;
|
|
||||||
u32 i;
|
|
||||||
|
|
||||||
/* We run parallel with other readers (test element)
|
write_lock_bh(&set->lock);
|
||||||
* but adding/deleting new entries is locked out */
|
cleanup_entries(map);
|
||||||
read_lock_bh(&set->lock);
|
write_unlock_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);
|
|
||||||
|
|
||||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||||
add_timer(&map->gc);
|
add_timer(&map->gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static void
|
||||||
list_set_gc_init(struct ip_set *set)
|
list_set_gc_init(struct ip_set *set)
|
||||||
{
|
{
|
||||||
struct list_set *map = set->data;
|
struct list_set *map = set->data;
|
||||||
@@ -500,13 +515,7 @@ list_set_gc_init(struct ip_set *set)
|
|||||||
|
|
||||||
/* Create list:set type of sets */
|
/* Create list:set type of sets */
|
||||||
|
|
||||||
static const struct nla_policy
|
static bool
|
||||||
list_set_create_policy[IPSET_ATTR_CREATE_MAX+1] = {
|
|
||||||
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
|
|
||||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline bool
|
|
||||||
init_list_set(struct ip_set *set, u32 size, size_t dsize,
|
init_list_set(struct ip_set *set, u32 size, size_t dsize,
|
||||||
unsigned long timeout)
|
unsigned long timeout)
|
||||||
{
|
{
|
||||||
@@ -532,14 +541,12 @@ init_list_set(struct ip_set *set, u32 size, size_t dsize,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
list_set_create(struct ip_set *set, struct nlattr *head, int len,
|
list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||||
u32 flags)
|
|
||||||
{
|
{
|
||||||
struct nlattr *tb[IPSET_ATTR_CREATE_MAX+1];
|
|
||||||
u32 size = IP_SET_LIST_DEFAULT_SIZE;
|
u32 size = IP_SET_LIST_DEFAULT_SIZE;
|
||||||
|
|
||||||
if (nla_parse(tb, IPSET_ATTR_CREATE_MAX, head, len,
|
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
|
||||||
list_set_create_policy))
|
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||||
return -IPSET_ERR_PROTOCOL;
|
return -IPSET_ERR_PROTOCOL;
|
||||||
|
|
||||||
if (tb[IPSET_ATTR_SIZE])
|
if (tb[IPSET_ATTR_SIZE])
|
||||||
@@ -570,6 +577,19 @@ static struct ip_set_type list_set_type __read_mostly = {
|
|||||||
.family = AF_UNSPEC,
|
.family = AF_UNSPEC,
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
.create = list_set_create,
|
.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,
|
.me = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#ifndef _IP_SET_TIMEOUT_H
|
#ifndef _IP_SET_TIMEOUT_H
|
||||||
#define _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
|
* 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
|
* 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
|
static inline bool
|
||||||
ip_set_timeout_test(unsigned long timeout)
|
ip_set_timeout_test(unsigned long timeout)
|
||||||
{
|
{
|
||||||
return timeout != IPSET_ELEM_UNSET
|
return timeout != IPSET_ELEM_UNSET &&
|
||||||
&& (timeout == IPSET_ELEM_PERMANENT
|
(timeout == IPSET_ELEM_PERMANENT ||
|
||||||
|| time_after(timeout, jiffies));
|
time_after(timeout, jiffies));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
ip_set_timeout_expired(unsigned long timeout)
|
ip_set_timeout_expired(unsigned long timeout)
|
||||||
{
|
{
|
||||||
return timeout != IPSET_ELEM_UNSET
|
return timeout != IPSET_ELEM_UNSET &&
|
||||||
&& timeout != IPSET_ELEM_PERMANENT
|
timeout != IPSET_ELEM_PERMANENT &&
|
||||||
&& time_before(timeout, jiffies);
|
time_before(timeout, jiffies);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
static inline unsigned long
|
||||||
@@ -88,15 +88,15 @@ ip_set_timeout_get(unsigned long timeout)
|
|||||||
static inline bool
|
static inline bool
|
||||||
ip_set_timeout_test(unsigned long timeout)
|
ip_set_timeout_test(unsigned long timeout)
|
||||||
{
|
{
|
||||||
return timeout == IPSET_ELEM_PERMANENT
|
return timeout == IPSET_ELEM_PERMANENT ||
|
||||||
|| time_after(timeout, jiffies);
|
time_after(timeout, jiffies);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
ip_set_timeout_expired(unsigned long timeout)
|
ip_set_timeout_expired(unsigned long timeout)
|
||||||
{
|
{
|
||||||
return timeout != IPSET_ELEM_PERMANENT
|
return timeout != IPSET_ELEM_PERMANENT &&
|
||||||
&& time_before(timeout, jiffies);
|
time_before(timeout, jiffies);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned long
|
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
|
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
|
\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.
|
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
|
.SS bitmap:ip
|
||||||
The \fBbitmap:ip\fR set type uses a memory range to store either IPv4 host
|
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
|
(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,
|
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.
|
the timer starts off when the IP and MAC address pair is complete.
|
||||||
.PP
|
.PP
|
||||||
Please note, the \fBset\fR match and \fBSET\fR target netfilter kernel modules
|
The \fBbitmap:ip,mac\fR type of sets require two \fBsrc/dst\fR parameters of
|
||||||
\fBalways\fR use the source MAC address from the packet to match, add or delete
|
the \fBset\fR match and \fBSET\fR target netfilter kernel modules and the second
|
||||||
entries from a \fBbitmap:ip,mac\fR type of set.
|
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
|
.PP
|
||||||
Examples:
|
Examples:
|
||||||
.IP
|
.IP
|
||||||
@@ -330,6 +333,9 @@ Mandatory options to use when creating a \fBbitmap:port\fR type of set:
|
|||||||
\fBrange\fP \fIfromport\fP\-\fItoport\fR
|
\fBrange\fP \fIfromport\fP\-\fItoport\fR
|
||||||
Create the set from the specified inclusive port range.
|
Create the set from the specified inclusive port range.
|
||||||
.PP
|
.PP
|
||||||
|
The \fBset\fR match and \fBSET\fR target netfilter kernel modules interpret
|
||||||
|
the stored numbers as TCP or UDP port numbers.
|
||||||
|
.PP
|
||||||
Examples:
|
Examples:
|
||||||
.IP
|
.IP
|
||||||
ipset create foo bitmap:port range 0\-1024
|
ipset create foo bitmap:port range 0\-1024
|
||||||
@@ -380,9 +386,9 @@ a range or a network:
|
|||||||
.PP
|
.PP
|
||||||
Examples:
|
Examples:
|
||||||
.IP
|
.IP
|
||||||
ipset create foo hash:ip netmask 24
|
ipset create foo hash:ip netmask 30
|
||||||
.IP
|
.IP
|
||||||
ipset add foo 192.168.1.1\-192.168.1.2
|
ipset add foo 192.168.1.0/24
|
||||||
.IP
|
.IP
|
||||||
ipset test foo 192.168.1.2
|
ipset test foo 192.168.1.2
|
||||||
.SS hash:net
|
.SS hash:net
|
||||||
@@ -414,8 +420,10 @@ correct value.
|
|||||||
The maximal number of elements which can be stored in the set, default 65536.
|
The maximal number of elements which can be stored in the set, default 65536.
|
||||||
.PP
|
.PP
|
||||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
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
|
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||||
elements are not checked.
|
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
|
.PP
|
||||||
From the \fBset\fR netfilter match point of view the searching for a match
|
From the \fBset\fR netfilter match point of view the searching for a match
|
||||||
always starts from the smallest size of netblock (most specific
|
always starts from the smallest size of netblock (most specific
|
||||||
@@ -431,7 +439,7 @@ Examples:
|
|||||||
.IP
|
.IP
|
||||||
ipset create foo hash:net
|
ipset create foo hash:net
|
||||||
.IP
|
.IP
|
||||||
ipset add foo 192.168.0/24
|
ipset add foo 192.168.0.0/24
|
||||||
.IP
|
.IP
|
||||||
ipset add foo 10.1.0.0/16
|
ipset add foo 10.1.0.0/16
|
||||||
.IP
|
.IP
|
||||||
@@ -481,8 +489,8 @@ TCP port or range of ports expressed in TCP portname identifiers from /etc/servi
|
|||||||
\fIportnumber[\-portnumber]\fR
|
\fIportnumber[\-portnumber]\fR
|
||||||
TCP port or range of ports expressed in TCP port numbers
|
TCP port or range of ports expressed in TCP port numbers
|
||||||
.TP
|
.TP
|
||||||
\fBtcp\fR|\fBudp\fR:\fIportname\fR|\fIportnumber\fR[\-\fIportname\fR|\fIportnumber\fR]
|
\fBtcp\fR|\fBsctp\fR|\fBudp\fR|\fBudplite\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)
|
TCP, SCTP, UDP or UDPLITE port or port range expressed in port name(s) or port number(s)
|
||||||
.TP
|
.TP
|
||||||
\fBicmp\fR:\fIcodename\fR|\fItype\fR/\fIcode\fR
|
\fBicmp\fR:\fIcodename\fR|\fItype\fR/\fIcode\fR
|
||||||
ICMP codename or type/code. The supported ICMP codename identifiers can always
|
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
|
.IP
|
||||||
ipset add foo 192.168.1.1,udp:53
|
ipset add foo 192.168.1.1,udp:53
|
||||||
.IP
|
.IP
|
||||||
ipset add foo 192.168.1.1,ospf:0
|
ipset add foo 192.168.1.1,vrrp:0
|
||||||
.IP
|
.IP
|
||||||
ipset test foo 192.168.1.1,80
|
ipset test foo 192.168.1.1,80
|
||||||
.SS hash:net,port
|
.SS hash:net,port
|
||||||
@@ -547,8 +555,10 @@ part of the elements see the description at the
|
|||||||
\fBhash:ip,port\fR set type.
|
\fBhash:ip,port\fR set type.
|
||||||
.PP
|
.PP
|
||||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
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
|
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||||
elements are not checked.
|
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
|
.PP
|
||||||
From the \fBset\fR netfilter match point of view the searching for a match
|
From the \fBset\fR netfilter match point of view the searching for a match
|
||||||
always starts from the smallest size of netblock (most specific
|
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_FLUSH-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||||
[IPSET_CMD_RENAME-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_SWAP-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||||
[IPSET_CMD_LIST-1] = NLM_F_REQUEST,
|
[IPSET_CMD_LIST-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||||
[IPSET_CMD_SAVE-1] = NLM_F_REQUEST,
|
[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_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_DEL-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
|
||||||
[IPSET_CMD_TEST-1] = NLM_F_REQUEST|NLM_F_ACK,
|
[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;
|
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||||
if (cmdflags[cmd-1] & NLM_F_ACK)
|
if (cmdflags[cmd-1] & NLM_F_ACK)
|
||||||
nlh->nlmsg_flags |= 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 = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||||
ghdr->cmd = cmd;
|
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->portid = mnl_socket_get_portid(handle->h);
|
||||||
handle->cb_ctl = cb_ctl;
|
handle->cb_ctl = cb_ctl;
|
||||||
handle->data = data;
|
handle->data = data;
|
||||||
|
handle->seq = time(NULL);
|
||||||
|
|
||||||
if (ipset_mnl_getid(handle, false) < 0)
|
if (ipset_mnl_getid(handle, false) < 0)
|
||||||
goto close_nl;
|
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);
|
p = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
|
||||||
switch (p) {
|
switch (p) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
proto = tmp;
|
case IPPROTO_SCTP:
|
||||||
tmp = a;
|
|
||||||
goto parse_port;
|
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
|
case IPPROTO_UDPLITE:
|
||||||
proto = tmp;
|
proto = tmp;
|
||||||
tmp = a;
|
tmp = a;
|
||||||
goto parse_port;
|
goto parse_port;
|
||||||
@@ -711,6 +710,14 @@ enum ipaddr_type {
|
|||||||
IPADDR_RANGE,
|
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
|
static int
|
||||||
parse_ip(struct ipset_session *session,
|
parse_ip(struct ipset_session *session,
|
||||||
enum ipset_opt opt, const char *str, enum ipaddr_type addrtype)
|
enum ipset_opt opt, const char *str, enum ipaddr_type addrtype)
|
||||||
@@ -725,7 +732,8 @@ parse_ip(struct ipset_session *session,
|
|||||||
|
|
||||||
switch (addrtype) {
|
switch (addrtype) {
|
||||||
case IPADDR_PLAIN:
|
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",
|
return syntax_err("plain IP address must be supplied: %s",
|
||||||
str);
|
str);
|
||||||
break;
|
break;
|
||||||
@@ -836,7 +844,7 @@ ipset_parse_net(struct ipset_session *session,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_parse_range(struct ipset_session *session,
|
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(session);
|
||||||
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
||||||
@@ -1313,7 +1321,7 @@ ipset_parse_flag(struct ipset_session *session,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_parse_typename(struct ipset_session *session,
|
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 struct ipset_type *type;
|
||||||
const char *typename;
|
const char *typename;
|
||||||
@@ -1407,15 +1415,14 @@ ipset_parse_ignored(struct ipset_session *session,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_call_parser(struct ipset_session *session,
|
ipset_call_parser(struct ipset_session *session,
|
||||||
ipset_parsefn parse, const char *optstr,
|
const struct ipset_arg *arg,
|
||||||
enum ipset_opt opt, const char *str)
|
const char *str)
|
||||||
{
|
{
|
||||||
if (ipset_data_flags_test(ipset_session_data(session),
|
if (ipset_data_flags_test(ipset_session_data(session),
|
||||||
IPSET_FLAG(opt)))
|
IPSET_FLAG(arg->opt)))
|
||||||
syntax_err("%s already specified", optstr);
|
syntax_err("%s already specified", arg->name[0]);
|
||||||
|
|
||||||
return parse(session, opt, parse == ipset_parse_ignored
|
return arg->parse(session, arg->opt, str);
|
||||||
? optstr : str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define parse_elem(s, t, d, str) \
|
#define parse_elem(s, t, d, str) \
|
||||||
@@ -89,7 +89,8 @@ ipset_print_ether(char *buf, unsigned int len,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_print_family(char *buf, unsigned int len,
|
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 env UNUSED)
|
||||||
{
|
{
|
||||||
uint8_t family;
|
uint8_t family;
|
||||||
@@ -157,7 +158,8 @@ __getnameinfo##f(char *buf, unsigned int len, \
|
|||||||
sizeof(saddr), \
|
sizeof(saddr), \
|
||||||
buf, len, NULL, 0, flags); \
|
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, \
|
err = getnameinfo((const struct sockaddr *)&saddr, \
|
||||||
sizeof(saddr), \
|
sizeof(saddr), \
|
||||||
buf, len, NULL, 0, \
|
buf, len, NULL, 0, \
|
||||||
@@ -228,7 +230,7 @@ ipset_print_ip(char *buf, unsigned int len,
|
|||||||
D("CIDR: %u", cidr);
|
D("CIDR: %u", cidr);
|
||||||
} else
|
} else
|
||||||
cidr = family == AF_INET6 ? 128 : 32;
|
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);
|
ip = ipset_data_get(data, opt);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
@@ -295,7 +297,7 @@ ipset_print_ipaddr(char *buf, unsigned int len,
|
|||||||
cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
|
cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
|
||||||
else
|
else
|
||||||
cidr = family == AF_INET6 ? 128 : 32;
|
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);
|
ip = ipset_data_get(data, opt);
|
||||||
assert(ip);
|
assert(ip);
|
||||||
@@ -410,7 +412,8 @@ ipset_print_name(char *buf, unsigned int len,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_print_port(char *buf, unsigned int len,
|
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)
|
uint8_t env UNUSED)
|
||||||
{
|
{
|
||||||
const uint16_t *port;
|
const uint16_t *port;
|
||||||
@@ -454,7 +457,8 @@ ipset_print_port(char *buf, unsigned int len,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_print_proto(char *buf, unsigned int len,
|
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)
|
uint8_t env UNUSED)
|
||||||
{
|
{
|
||||||
const struct protoent *protoent;
|
const struct protoent *protoent;
|
||||||
@@ -490,7 +494,8 @@ ipset_print_proto(char *buf, unsigned int len,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_print_icmp(char *buf, unsigned int len,
|
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)
|
uint8_t env UNUSED)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -523,7 +528,8 @@ ipset_print_icmp(char *buf, unsigned int len,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_print_icmpv6(char *buf, unsigned int len,
|
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)
|
uint8_t env UNUSED)
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -556,7 +562,8 @@ ipset_print_icmpv6(char *buf, unsigned int len,
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
ipset_print_proto_port(char *buf, unsigned int len,
|
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)
|
uint8_t env UNUSED)
|
||||||
{
|
{
|
||||||
int size, offset = 0;
|
int size, offset = 0;
|
||||||
@@ -578,7 +585,9 @@ ipset_print_proto_port(char *buf, unsigned int len,
|
|||||||
|
|
||||||
switch (proto) {
|
switch (proto) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
|
case IPPROTO_SCTP:
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
|
case IPPROTO_UDPLITE:
|
||||||
break;
|
break;
|
||||||
case IPPROTO_ICMP:
|
case IPPROTO_ICMP:
|
||||||
return ipset_print_icmp(buf + offset, len, data,
|
return ipset_print_icmp(buf + offset, len, data,
|
||||||
@@ -100,6 +100,19 @@ ipset_saved_type(const struct ipset_session *session)
|
|||||||
return session->saved_type;
|
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
|
* Environment options
|
||||||
*/
|
*/
|
||||||
@@ -198,7 +198,7 @@ create_type_get(struct ipset_session *session)
|
|||||||
struct ipset_data *data;
|
struct ipset_data *data;
|
||||||
const char *typename;
|
const char *typename;
|
||||||
uint8_t family, tmin = 0, tmax = 0;
|
uint8_t family, tmin = 0, tmax = 0;
|
||||||
const uint8_t *kmin, *kmax;
|
uint8_t kmin, kmax;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
data = ipset_session_data(session);
|
data = ipset_session_data(session);
|
||||||
@@ -216,7 +216,7 @@ create_type_get(struct ipset_session *session)
|
|||||||
&& MATCH_FAMILY(t, family)) {
|
&& MATCH_FAMILY(t, family)) {
|
||||||
if (match == NULL) {
|
if (match == NULL) {
|
||||||
match = t;
|
match = t;
|
||||||
tmax = t->revision;
|
tmin = tmax = t->revision;
|
||||||
} else if (t->family == match->family)
|
} else if (t->family == match->family)
|
||||||
tmin = t->revision;
|
tmin = t->revision;
|
||||||
}
|
}
|
||||||
@@ -240,32 +240,31 @@ create_type_get(struct ipset_session *session)
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return NULL;
|
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))
|
if (ipset_data_test(data, IPSET_OPT_REVISION_MIN))
|
||||||
kmin = ipset_data_get(data, IPSET_OPT_REVISION_MIN);
|
kmin = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION_MIN);
|
||||||
else
|
|
||||||
kmin = kmax;
|
if (MAX(tmin, kmin) > MIN(tmax, kmax)) {
|
||||||
if (MAX(tmin, *kmin) > MIN(tmax, *kmax)) {
|
if (kmin > tmax)
|
||||||
if (*kmin > tmax)
|
|
||||||
return ipset_errptr(session,
|
return ipset_errptr(session,
|
||||||
"Kernel supports %s type with family %s "
|
"Kernel supports %s type, family %s "
|
||||||
"in minimal revision %u while ipset library "
|
"with minimal revision %u while ipset program "
|
||||||
"in maximal revision %u. "
|
"with maximal revision %u.\n"
|
||||||
"You need to upgrade your ipset library.",
|
"You need to upgrade your ipset program.",
|
||||||
typename,
|
typename,
|
||||||
family == AF_INET ? "INET" :
|
family == AF_INET ? "INET" :
|
||||||
family == AF_INET6 ? "INET6" : "UNSPEC",
|
family == AF_INET6 ? "INET6" : "UNSPEC",
|
||||||
*kmin, tmax);
|
kmin, tmax);
|
||||||
else
|
else
|
||||||
return ipset_errptr(session,
|
return ipset_errptr(session,
|
||||||
"Kernel supports %s type with family %s "
|
"Kernel supports %s type, family %s "
|
||||||
"in maximal revision %u while ipset library "
|
"with maximal revision %u while ipset program "
|
||||||
"in minimal revision %u. "
|
"with minimal revision %u.\n"
|
||||||
"You need to upgrade your kernel.",
|
"You need to upgrade your kernel.",
|
||||||
typename,
|
typename,
|
||||||
family == AF_INET ? "INET" :
|
family == AF_INET ? "INET" :
|
||||||
family == AF_INET6 ? "INET6" : "UNSPEC",
|
family == AF_INET6 ? "INET6" : "UNSPEC",
|
||||||
*kmax, tmin);
|
kmax, tmin);
|
||||||
}
|
}
|
||||||
|
|
||||||
match->kernel_check = IPSET_KERNEL_OK;
|
match->kernel_check = IPSET_KERNEL_OK;
|
||||||
@@ -441,13 +440,15 @@ ipset_type_add(struct ipset_type *type)
|
|||||||
|
|
||||||
assert(type);
|
assert(type);
|
||||||
|
|
||||||
|
if (strlen(type->name) > IPSET_MAXNAMELEN - 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
/* Add to the list: higher revision numbers first */
|
/* Add to the list: higher revision numbers first */
|
||||||
for (t = typelist, prev = NULL; t != NULL; t = t->next) {
|
for (t = typelist, prev = NULL; t != NULL; t = t->next) {
|
||||||
if (STREQ(t->name, type->name)) {
|
if (STREQ(t->name, type->name)) {
|
||||||
if (t->revision == type->revision) {
|
if (t->revision == type->revision)
|
||||||
errno = EEXIST;
|
return -EEXIST;
|
||||||
return -1;
|
else if (t->revision < type->revision) {
|
||||||
} else if (t->revision < type->revision) {
|
|
||||||
type->next = t;
|
type->next = t;
|
||||||
if (prev)
|
if (prev)
|
||||||
prev->next = type;
|
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 != NULL && STREQ(t->next->name, type->name)) {
|
||||||
if (t->next->revision == type->revision) {
|
if (t->next->revision == type->revision)
|
||||||
errno = EEXIST;
|
return -EEXIST;
|
||||||
return -1;
|
else if (t->next->revision < type->revision) {
|
||||||
} else if (t->next->revision < type->revision) {
|
|
||||||
type->next = t->next;
|
type->next = t->next;
|
||||||
t->next = type;
|
t->next = type;
|
||||||
return 0;
|
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 */
|
/* Core kernel error codes */
|
||||||
static const struct ipset_errcode_table core_errcode_table[] = {
|
static const struct ipset_errcode_table core_errcode_table[] = {
|
||||||
/* Generic error codes */
|
/* Generic error codes */
|
||||||
{ EEXIST, 0,
|
{ ENOENT, 0,
|
||||||
"The set with the given name does not exist" },
|
"The set with the given name does not exist" },
|
||||||
|
{ EMSGSIZE, 0,
|
||||||
|
"Kernel error received: message could not be created" },
|
||||||
{ IPSET_ERR_PROTOCOL, 0,
|
{ IPSET_ERR_PROTOCOL, 0,
|
||||||
"Kernel error received: ipset protocol error" },
|
"Kernel error received: ipset protocol error" },
|
||||||
|
|
||||||
@@ -30,14 +32,14 @@ static const struct ipset_errcode_table core_errcode_table[] = {
|
|||||||
{ EEXIST, IPSET_CMD_CREATE,
|
{ EEXIST, IPSET_CMD_CREATE,
|
||||||
"Set cannot be created: set with the same name already exists" },
|
"Set cannot be created: set with the same name already exists" },
|
||||||
{ IPSET_ERR_FIND_TYPE, 0,
|
{ 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,
|
{ IPSET_ERR_MAX_SETS, 0,
|
||||||
"Kernel error received: maximal number of sets reached, "
|
"Kernel error received: maximal number of sets reached, "
|
||||||
"cannot create more." },
|
"cannot create more." },
|
||||||
{ IPSET_ERR_INVALID_NETMASK, 0,
|
{ IPSET_ERR_INVALID_NETMASK, 0,
|
||||||
"The value of the netmask parameter is invalid" },
|
"The value of the netmask parameter is invalid" },
|
||||||
{ IPSET_ERR_INVALID_FAMILY, 0,
|
{ 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 */
|
/* DESTROY specific error codes */
|
||||||
{ IPSET_ERR_BUSY, IPSET_CMD_DESTROY,
|
{ IPSET_ERR_BUSY, IPSET_CMD_DESTROY,
|
||||||
@@ -206,62 +206,54 @@ restore(char *argv0)
|
|||||||
static int
|
static int
|
||||||
call_parser(int *argc, char *argv[], const struct ipset_arg *args)
|
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 struct ipset_arg *arg;
|
||||||
const char *optstr;
|
const char *optstr;
|
||||||
|
|
||||||
/* Currently CREATE and ADT may have got additional arguments */
|
/* Currently CREATE and ADT may have got additional arguments */
|
||||||
if (!args)
|
if (!args && *argc > 1)
|
||||||
goto done;
|
goto err_unknown;
|
||||||
for (arg = args; arg->opt; arg++) {
|
while (*argc > 1) {
|
||||||
for (i = 1; i < *argc; ) {
|
for (arg = args; arg->opt; arg++) {
|
||||||
D("argc: %u, i: %u: %s vs %s",
|
D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]);
|
||||||
*argc, i, argv[i], arg->name[0]);
|
if (!(ipset_match_option(argv[1], arg->name)))
|
||||||
if (!(ipset_match_option(argv[i], arg->name))) {
|
|
||||||
i++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
optstr = argv[i];
|
optstr = argv[1];
|
||||||
/* Shift off matched option */
|
/* Shift off matched option */
|
||||||
D("match %s", arg->name[0]);
|
D("match %s", arg->name[0]);
|
||||||
ipset_shift_argv(argc, argv, i);
|
ipset_shift_argv(argc, argv, 1);
|
||||||
D("argc: %u, i: %u", *argc, i);
|
|
||||||
switch (arg->has_arg) {
|
switch (arg->has_arg) {
|
||||||
case IPSET_MANDATORY_ARG:
|
case IPSET_MANDATORY_ARG:
|
||||||
if (i + 1 > *argc)
|
if (*argc < 2)
|
||||||
return exit_error(PARAMETER_PROBLEM,
|
return exit_error(PARAMETER_PROBLEM,
|
||||||
"Missing mandatory argument "
|
"Missing mandatory argument "
|
||||||
"of option `%s'",
|
"of option `%s'",
|
||||||
arg->name[0]);
|
arg->name[0]);
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
case IPSET_OPTIONAL_ARG:
|
case IPSET_OPTIONAL_ARG:
|
||||||
if (i + 1 <= *argc) {
|
if (*argc >= 2) {
|
||||||
ret = ipset_call_parser(session,
|
ret = ipset_call_parser(session, arg, argv[1]);
|
||||||
arg->parse,
|
|
||||||
optstr, arg->opt,
|
|
||||||
argv[i]);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
ipset_shift_argv(argc, argv, i);
|
ipset_shift_argv(argc, argv, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
default:
|
default:
|
||||||
ret = ipset_call_parser(session,
|
ret = ipset_call_parser(session, arg, optstr);
|
||||||
arg->parse,
|
|
||||||
optstr, arg->opt,
|
|
||||||
optstr);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
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;
|
return ret;
|
||||||
|
|
||||||
|
err_unknown:
|
||||||
|
return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum ipset_adt
|
static enum ipset_adt
|
||||||
@@ -431,13 +423,8 @@ parse_commandline(int argc, char *argv[])
|
|||||||
const struct ipset_commands *command;
|
const struct ipset_commands *command;
|
||||||
const struct ipset_type *type;
|
const struct ipset_type *type;
|
||||||
|
|
||||||
/* Initialize session */
|
/* Set session lineno to report parser errors correctly */
|
||||||
if (session == NULL) {
|
ipset_session_lineno(session, restore_line);
|
||||||
session = ipset_session_init(printf);
|
|
||||||
if (session == NULL)
|
|
||||||
return exit_error(OTHER_PROBLEM,
|
|
||||||
"Cannot initialize ipset session, aborting.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Commandline parsing, somewhat similar to that of 'ip' */
|
/* Commandline parsing, somewhat similar to that of 'ip' */
|
||||||
|
|
||||||
@@ -481,61 +468,57 @@ parse_commandline(int argc, char *argv[])
|
|||||||
|
|
||||||
/* Second: parse command */
|
/* Second: parse command */
|
||||||
for (command = ipset_commands;
|
for (command = ipset_commands;
|
||||||
command->cmd && cmd == IPSET_CMD_NONE;
|
argc > 1 && command->cmd && cmd == IPSET_CMD_NONE;
|
||||||
command++) {
|
command++) {
|
||||||
for (i = 1; i < argc; ) {
|
if (!ipset_match_cmd(argv[1], command->name))
|
||||||
if (!ipset_match_cmd(argv[1], command->name)) {
|
continue;
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (restore_line != 0
|
|
||||||
&& (command->cmd == IPSET_CMD_RESTORE
|
|
||||||
|| command->cmd == IPSET_CMD_VERSION
|
|
||||||
|| command->cmd == IPSET_CMD_HELP))
|
|
||||||
return exit_error(PARAMETER_PROBLEM,
|
|
||||||
"Command `%s' is invalid "
|
|
||||||
"in restore mode.",
|
|
||||||
command->name[0]);
|
|
||||||
if (interactive
|
|
||||||
&& command->cmd == IPSET_CMD_RESTORE) {
|
|
||||||
printf("Restore command ignored "
|
|
||||||
"in interactive mode\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift off matched command arg */
|
if (restore_line != 0
|
||||||
ipset_shift_argv(&argc, argv, i);
|
&& (command->cmd == IPSET_CMD_RESTORE
|
||||||
cmd = command->cmd;
|
|| command->cmd == IPSET_CMD_VERSION
|
||||||
switch (command->has_arg) {
|
|| command->cmd == IPSET_CMD_HELP))
|
||||||
case IPSET_MANDATORY_ARG:
|
return exit_error(PARAMETER_PROBLEM,
|
||||||
case IPSET_MANDATORY_ARG2:
|
"Command `%s' is invalid "
|
||||||
if (i + 1 > argc)
|
"in restore mode.",
|
||||||
return exit_error(PARAMETER_PROBLEM,
|
command->name[0]);
|
||||||
"Missing mandatory argument "
|
if (interactive && command->cmd == IPSET_CMD_RESTORE) {
|
||||||
"to command %s",
|
printf("Restore command ignored "
|
||||||
command->name[0]);
|
"in interactive mode\n");
|
||||||
/* Fall through */
|
return 0;
|
||||||
case IPSET_OPTIONAL_ARG:
|
}
|
||||||
arg0 = argv[i];
|
|
||||||
if (i + 1 <= argc)
|
/* Shift off matched command arg */
|
||||||
/* Shift off first arg */
|
ipset_shift_argv(&argc, argv, 1);
|
||||||
ipset_shift_argv(&argc, argv, i);
|
cmd = command->cmd;
|
||||||
break;
|
switch (command->has_arg) {
|
||||||
default:
|
case IPSET_MANDATORY_ARG:
|
||||||
break;
|
case IPSET_MANDATORY_ARG2:
|
||||||
}
|
if (argc < 2)
|
||||||
if (command->has_arg == IPSET_MANDATORY_ARG2) {
|
return exit_error(PARAMETER_PROBLEM,
|
||||||
if (i + 1 > argc)
|
"Missing mandatory argument "
|
||||||
return exit_error(PARAMETER_PROBLEM,
|
"to command %s",
|
||||||
"Missing second mandatory "
|
command->name[0]);
|
||||||
"argument to command %s",
|
/* Fall through */
|
||||||
command->name[0]);
|
case IPSET_OPTIONAL_ARG:
|
||||||
arg1 = argv[i];
|
arg0 = argv[1];
|
||||||
/* Shift off second arg */
|
if (argc >= 2)
|
||||||
ipset_shift_argv(&argc, argv, i);
|
/* Shift off first arg */
|
||||||
}
|
ipset_shift_argv(&argc, argv, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (command->has_arg == IPSET_MANDATORY_ARG2) {
|
||||||
|
if (argc < 2)
|
||||||
|
return exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Missing second mandatory "
|
||||||
|
"argument to command %s",
|
||||||
|
command->name[0]);
|
||||||
|
arg1 = argv[1];
|
||||||
|
/* Shift off second arg */
|
||||||
|
ipset_shift_argv(&argc, argv, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Third: catch interactive mode, handle help, version */
|
/* Third: catch interactive mode, handle help, version */
|
||||||
@@ -570,7 +553,8 @@ parse_commandline(int argc, char *argv[])
|
|||||||
argv[1]);
|
argv[1]);
|
||||||
return exit_error(PARAMETER_PROBLEM, "No command specified.");
|
return exit_error(PARAMETER_PROBLEM, "No command specified.");
|
||||||
case IPSET_CMD_VERSION:
|
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)
|
if (interactive)
|
||||||
return 0;
|
return 0;
|
||||||
return exit_error(NO_PROBLEM, NULL);
|
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_hash_ipportnet0);
|
||||||
ipset_type_add(&ipset_list_set0);
|
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);
|
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"
|
" IP is a valid IPv4 or IPv6 address (or hostname).\n"
|
||||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||||
" is supported for IPv4.\n"
|
" is supported for IPv4.\n"
|
||||||
" Adding/deleting multiple elements with TCP/UDP port range\n"
|
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||||
" is supported both for IPv4 and IPv6.\n";
|
" port range is supported both for IPv4 and IPv6.\n";
|
||||||
|
|
||||||
struct ipset_type ipset_hash_ipport0 = {
|
struct ipset_type ipset_hash_ipport0 = {
|
||||||
.name = "hash:ip,port",
|
.name = "hash:ip,port",
|
||||||
.alias = { "ipporthash", NULL },
|
.alias = { "ipporthash", NULL },
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.family = AF_INET46,
|
.family = AF_INET46,
|
||||||
.dimension = IPSET_DIM_TWO,
|
.dimension = IPSET_DIM_TWO,
|
||||||
.elem = {
|
.elem = {
|
||||||
@@ -82,13 +82,13 @@ static const char hash_ipportip_usage[] =
|
|||||||
" IP is a valid IPv4 or IPv6 address (or hostname).\n"
|
" IP is a valid IPv4 or IPv6 address (or hostname).\n"
|
||||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||||
" in the first IP component is supported for IPv4.\n"
|
" in the first IP component is supported for IPv4.\n"
|
||||||
" Adding/deleting multiple elements with TCP/UDP port range\n"
|
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||||
" is supported both for IPv4 and IPv6.\n";
|
" port range is supported both for IPv4 and IPv6.\n";
|
||||||
|
|
||||||
struct ipset_type ipset_hash_ipportip0 = {
|
struct ipset_type ipset_hash_ipportip0 = {
|
||||||
.name = "hash:ip,port,ip",
|
.name = "hash:ip,port,ip",
|
||||||
.alias = { "ipportiphash", NULL },
|
.alias = { "ipportiphash", NULL },
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.family = AF_INET46,
|
.family = AF_INET46,
|
||||||
.dimension = IPSET_DIM_THREE,
|
.dimension = IPSET_DIM_THREE,
|
||||||
.elem = {
|
.elem = {
|
||||||
@@ -83,13 +83,13 @@ static const char hash_ipportnet_usage[] =
|
|||||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||||
" in the first IP component is supported for IPv4.\n"
|
" in the first IP component is supported for IPv4.\n"
|
||||||
" Adding/deleting multiple elements with TCP/UDP port range\n"
|
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||||
" is supported both for IPv4 and IPv6.\n";
|
" port range is supported both for IPv4 and IPv6.\n";
|
||||||
|
|
||||||
struct ipset_type ipset_hash_ipportnet0 = {
|
struct ipset_type ipset_hash_ipportnet0 = {
|
||||||
.name = "hash:ip,port,net",
|
.name = "hash:ip,port,net",
|
||||||
.alias = { "ipportnethash", NULL },
|
.alias = { "ipportnethash", NULL },
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.family = AF_INET46,
|
.family = AF_INET46,
|
||||||
.dimension = IPSET_DIM_THREE,
|
.dimension = IPSET_DIM_THREE,
|
||||||
.elem = {
|
.elem = {
|
||||||
@@ -60,12 +60,13 @@ static const char hash_netport_usage[] =
|
|||||||
"where depending on the INET family\n"
|
"where depending on the INET family\n"
|
||||||
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
||||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\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 = {
|
struct ipset_type ipset_hash_netport0 = {
|
||||||
.name = "hash:net,port",
|
.name = "hash:net,port",
|
||||||
.alias = { "netporthash", NULL },
|
.alias = { "netporthash", NULL },
|
||||||
.revision = 0,
|
.revision = 1,
|
||||||
.family = AF_INET46,
|
.family = AF_INET46,
|
||||||
.dimension = IPSET_DIM_TWO,
|
.dimension = IPSET_DIM_TWO,
|
||||||
.elem = {
|
.elem = {
|
||||||
@@ -23,9 +23,9 @@
|
|||||||
const struct ipset_commands ipset_commands[] = {
|
const struct ipset_commands ipset_commands[] = {
|
||||||
/* Order is important */
|
/* Order is important */
|
||||||
|
|
||||||
{ /* c[reate], --create, n, -N */
|
{ /* c[reate], --create, n[ew], -N */
|
||||||
.cmd = IPSET_CMD_CREATE,
|
.cmd = IPSET_CMD_CREATE,
|
||||||
.name = { "create", "n" },
|
.name = { "create", "new" },
|
||||||
.has_arg = IPSET_MANDATORY_ARG2,
|
.has_arg = IPSET_MANDATORY_ARG2,
|
||||||
.help = "SETNAME TYPENAME [type-specific-options]\n"
|
.help = "SETNAME TYPENAME [type-specific-options]\n"
|
||||||
" Create a new set",
|
" Create a new set",
|
||||||
@@ -143,14 +143,14 @@ ipset_match_cmd(const char *arg, const char * const name[])
|
|||||||
|
|
||||||
if (len > strlen(name[0]) || !len)
|
if (len > strlen(name[0]) || !len)
|
||||||
return false;
|
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;
|
return true;
|
||||||
else if (len != 1)
|
else if (len != 1)
|
||||||
return false;
|
return false;
|
||||||
else if (name[1] == NULL)
|
else return tolower(arg[0]) == name[0][0] ||
|
||||||
return tolower(arg[0]) == name[0][0];
|
(name[1] != NULL && tolower(arg[0]) == name[1][0]);
|
||||||
else
|
|
||||||
return tolower(arg[0]) == name[1][0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct ipset_envopts ipset_envopts[] = {
|
const struct ipset_envopts ipset_envopts[] = {
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
* Patrick Schaaf <bof@bof.de>
|
* Patrick Schaaf <bof@bof.de>
|
||||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
* 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
|
* 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
|
* 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)
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||||
#define CHECK_OK 1
|
#define CHECK_OK 1
|
||||||
#define CHECK_FAIL 0
|
#define CHECK_FAIL(err) 0
|
||||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||||
#define CHECK_OK 0
|
#define CHECK_OK 0
|
||||||
#define CHECK_FAIL (-EINVAL)
|
#define CHECK_FAIL(err) (err)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
#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);
|
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||||
|
|
||||||
if (index == IPSET_INVALID_ID) {
|
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);
|
info->match_set.index);
|
||||||
return CHECK_FAIL; /* error */
|
return CHECK_FAIL(-ENOENT); /* error */
|
||||||
}
|
}
|
||||||
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||||
pr_warning("That's nasty!");
|
pr_warning("Protocol error: set match dimension "
|
||||||
return CHECK_FAIL; /* error */
|
"is over the limit!\n");
|
||||||
|
ip_set_nfnl_put(info->match_set.index);
|
||||||
|
return CHECK_FAIL(-ERANGE); /* error */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill out compatibility data */
|
/* 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) {
|
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||||
if (index == IPSET_INVALID_ID) {
|
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);
|
info->add_set.index);
|
||||||
return CHECK_FAIL; /* error */
|
return CHECK_FAIL(-ENOENT); /* error */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||||
if (index == IPSET_INVALID_ID) {
|
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);
|
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
|
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|
||||||
|| info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||||
pr_warning("That's nasty!");
|
pr_warning("Protocol error: SET target dimension "
|
||||||
return CHECK_FAIL; /* error */
|
"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 */
|
/* 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);
|
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||||
|
|
||||||
if (index == IPSET_INVALID_ID) {
|
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);
|
info->match_set.index);
|
||||||
return CHECK_FAIL; /* error */
|
return CHECK_FAIL(-ENOENT); /* error */
|
||||||
}
|
}
|
||||||
if (info->match_set.dim > IPSET_DIM_MAX) {
|
if (info->match_set.dim > IPSET_DIM_MAX) {
|
||||||
pr_warning("That's nasty!");
|
pr_warning("Protocol error: set match dimension "
|
||||||
return CHECK_FAIL; /* error */
|
"is over the limit!\n");
|
||||||
|
ip_set_nfnl_put(info->match_set.index);
|
||||||
|
return CHECK_FAIL(-ERANGE); /* error */
|
||||||
}
|
}
|
||||||
|
|
||||||
return CHECK_OK;
|
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)
|
if (info->del_set.index != IPSET_INVALID_ID)
|
||||||
ip_set_del(info->del_set.index,
|
ip_set_del(info->del_set.index,
|
||||||
skb, par->family,
|
skb, par->family,
|
||||||
info->add_set.dim,
|
info->del_set.dim,
|
||||||
info->del_set.flags);
|
info->del_set.flags);
|
||||||
|
|
||||||
return XT_CONTINUE;
|
return XT_CONTINUE;
|
||||||
@@ -295,24 +306,31 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
|||||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||||
if (index == IPSET_INVALID_ID) {
|
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);
|
info->add_set.index);
|
||||||
return CHECK_FAIL; /* error */
|
return CHECK_FAIL(-ENOENT); /* error */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||||
if (index == IPSET_INVALID_ID) {
|
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);
|
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
|
if (info->add_set.dim > IPSET_DIM_MAX ||
|
||||||
|| info->del_set.flags > IPSET_DIM_MAX) {
|
info->del_set.dim > IPSET_DIM_MAX) {
|
||||||
pr_warning("That's nasty!");
|
pr_warning("Protocol error: SET target dimension "
|
||||||
return CHECK_FAIL; /* error */
|
"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;
|
return CHECK_OK;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef _XT_SET_H
|
#ifndef _XT_SET_H
|
||||||
#define _XT_SET_H
|
#define _XT_SET_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
#include "ip_set.h"
|
#include "ip_set.h"
|
||||||
|
|
||||||
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
||||||
@@ -71,10 +71,10 @@ static void chaos_tg_print(const void *ip,
|
|||||||
|
|
||||||
switch (info->variant) {
|
switch (info->variant) {
|
||||||
case XTCHAOS_DELUDE:
|
case XTCHAOS_DELUDE:
|
||||||
printf("DELUDE ");
|
printf(" DELUDE ");
|
||||||
break;
|
break;
|
||||||
case XTCHAOS_TARPIT:
|
case XTCHAOS_TARPIT:
|
||||||
printf("TARPIT ");
|
printf(" TARPIT ");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,10 +85,10 @@ static void chaos_tg_save(const void *ip, const struct xt_entry_target *target)
|
|||||||
|
|
||||||
switch (info->variant) {
|
switch (info->variant) {
|
||||||
case XTCHAOS_DELUDE:
|
case XTCHAOS_DELUDE:
|
||||||
printf("--delude ");
|
printf(" --delude ");
|
||||||
break;
|
break;
|
||||||
case XTCHAOS_TARPIT:
|
case XTCHAOS_TARPIT:
|
||||||
printf("--tarpit ");
|
printf(" --tarpit ");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ static void CHECKSUM_print(const void *ip, const struct xt_entry_target *target,
|
|||||||
printf("CHECKSUM ");
|
printf("CHECKSUM ");
|
||||||
|
|
||||||
if (einfo->operation & XT_CHECKSUM_OP_FILL)
|
if (einfo->operation & XT_CHECKSUM_OP_FILL)
|
||||||
printf("fill ");
|
printf(" fill ");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CHECKSUM_save(const void *ip, const struct xt_entry_target *target)
|
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;
|
(const struct xt_CHECKSUM_info *)target->data;
|
||||||
|
|
||||||
if (einfo->operation & XT_CHECKSUM_OP_FILL)
|
if (einfo->operation & XT_CHECKSUM_OP_FILL)
|
||||||
printf("--checksum-fill ");
|
printf(" --checksum-fill ");
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xtables_target checksum_tg_reg = {
|
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;
|
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);
|
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;
|
const struct dhcpmac_info *info = (const void *)target->data;
|
||||||
|
|
||||||
if (info->invert)
|
if (info->invert)
|
||||||
printf("! ");
|
printf(" !");
|
||||||
printf("--set-mac " DH_MAC_FMT "/%u ",
|
printf(" --set-mac " DH_MAC_FMT "/%u ",
|
||||||
DH_MAC_HEX(info->addr), info->mask);
|
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;
|
const struct xt_ipmark_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (info->selector == XT_IPMARK_SRC)
|
if (info->selector == XT_IPMARK_SRC)
|
||||||
printf("IPMARK src ip ");
|
printf(" IPMARK src ip ");
|
||||||
else
|
else
|
||||||
printf("IPMARK dst ip ");
|
printf(" IPMARK dst ip ");
|
||||||
|
|
||||||
if (info->shift != 0)
|
if (info->shift != 0)
|
||||||
printf("shift %u ", (unsigned int)info->shift);
|
printf(" shift %u ", (unsigned int)info->shift);
|
||||||
if (info->andmask != ~0U)
|
if (info->andmask != ~0U)
|
||||||
printf("and 0x%x ", (unsigned int)info->andmask);
|
printf(" and 0x%x ", (unsigned int)info->andmask);
|
||||||
if (info->ormask != 0)
|
if (info->ormask != 0)
|
||||||
printf("or 0x%x ", (unsigned int)info->ormask);
|
printf(" or 0x%x ", (unsigned int)info->ormask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
const struct xt_ipmark_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (info->selector == XT_IPMARK_SRC)
|
if (info->selector == XT_IPMARK_SRC)
|
||||||
printf("--addr src ");
|
printf(" --addr src ");
|
||||||
else
|
else
|
||||||
printf("--addr dst ");
|
printf(" --addr dst ");
|
||||||
|
|
||||||
if (info->shift != 0)
|
if (info->shift != 0)
|
||||||
printf("--shift %u ", (unsigned int)info->shift);
|
printf(" --shift %u ", (unsigned int)info->shift);
|
||||||
if (info->andmask != ~0U)
|
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)
|
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 = {
|
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;
|
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
|
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;
|
const struct xt_logmark_tginfo *info = (void *)target->data;
|
||||||
|
|
||||||
if (info->level != 4)
|
if (info->level != 4)
|
||||||
printf("--log-level %u ", info->level);
|
printf(" --log-level %u ", info->level);
|
||||||
if (*info->prefix != '\0')
|
if (*info->prefix != '\0')
|
||||||
printf("--log-prefix \"%s\" ", info->prefix);
|
printf(" --log-prefix \"%s\" ", info->prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xtables_target logmark_tg_reg = {
|
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;
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (!numeric && info->mask == 32)
|
if (!numeric && info->mask == 32)
|
||||||
printf("to-destination %s ",
|
printf(" to-destination %s ",
|
||||||
xtables_ipaddr_to_anyname(&info->addr.in));
|
xtables_ipaddr_to_anyname(&info->addr.in));
|
||||||
else
|
else
|
||||||
printf("to-destination %s/%u ",
|
printf(" to-destination %s/%u ",
|
||||||
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
|
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;
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (!numeric && info->mask == 128)
|
if (!numeric && info->mask == 128)
|
||||||
printf("to-destination %s ",
|
printf(" to-destination %s ",
|
||||||
xtables_ip6addr_to_anyname(&info->addr.in6));
|
xtables_ip6addr_to_anyname(&info->addr.in6));
|
||||||
else
|
else
|
||||||
printf("to-destination %s/%u ",
|
printf(" to-destination %s/%u ",
|
||||||
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
|
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;
|
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),
|
xtables_ipaddr_to_numeric(&info->addr.in),
|
||||||
info->mask);
|
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;
|
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),
|
xtables_ip6addr_to_numeric(&info->addr.in6),
|
||||||
info->mask);
|
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;
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (!numeric && info->mask == 32)
|
if (!numeric && info->mask == 32)
|
||||||
printf("to-source %s ",
|
printf(" to-source %s ",
|
||||||
xtables_ipaddr_to_anyname(&info->addr.in));
|
xtables_ipaddr_to_anyname(&info->addr.in));
|
||||||
else
|
else
|
||||||
printf("to-source %s/%u ",
|
printf(" to-source %s/%u ",
|
||||||
xtables_ipaddr_to_numeric(&info->addr.in), info->mask);
|
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;
|
const struct xt_rawnat_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (!numeric && info->mask == 128)
|
if (!numeric && info->mask == 128)
|
||||||
printf("to-source %s ",
|
printf(" to-source %s ",
|
||||||
xtables_ip6addr_to_anyname(&info->addr.in6));
|
xtables_ip6addr_to_anyname(&info->addr.in6));
|
||||||
else
|
else
|
||||||
printf("to-source %s/%u ",
|
printf(" to-source %s/%u ",
|
||||||
xtables_ip6addr_to_numeric(&info->addr.in6), info->mask);
|
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;
|
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),
|
xtables_ipaddr_to_numeric(&info->addr.in),
|
||||||
info->mask);
|
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;
|
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),
|
xtables_ip6addr_to_numeric(&info->addr.in6),
|
||||||
info->mask);
|
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;
|
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (numeric)
|
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
|
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,
|
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;
|
const struct xt_tee_tginfo *info = (const void *)target->data;
|
||||||
|
|
||||||
if (numeric)
|
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
|
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)
|
static void tee_tg_save(const void *ip, const struct xt_entry_target *target)
|
||||||
{
|
{
|
||||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
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)
|
static void tee_tg6_save(const void *ip, const struct xt_entry_target *target)
|
||||||
{
|
{
|
||||||
const struct xt_tee_tginfo *info = (const void *)target->data;
|
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 = {
|
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;
|
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;
|
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 = {
|
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;
|
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);
|
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;
|
const struct dhcpmac_info *info = (void *)match->data;
|
||||||
|
|
||||||
if (info->invert)
|
if (info->invert)
|
||||||
printf("! ");
|
printf(" !");
|
||||||
printf("--mac " DH_MAC_FMT "/%u ",
|
printf(" --mac " DH_MAC_FMT "/%u ",
|
||||||
DH_MAC_HEX(info->addr), info->mask);
|
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;
|
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);
|
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;
|
const struct xt_fuzzy_mtinfo *info = (const void *)match->data;
|
||||||
|
|
||||||
printf("--lower-limit %u ", info->minimum_rate);
|
printf(" --lower-limit %u ", info->minimum_rate);
|
||||||
printf("--upper-limit %u ", info->maximum_rate);
|
printf(" --upper-limit %u ", info->maximum_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct xtables_match fuzzy_mt_reg = {
|
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