mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2026-01-04 06:13:51 +01:00
src: remove ipset6-genl
As scheduled, perform the removal of ipset from the tree.
This commit is contained in:
6
INSTALL
6
INSTALL
@@ -22,12 +22,6 @@ Supported configurations for this release
|
||||
- CONFIG_CONNECTOR y/m if you wish to receive userspace
|
||||
notifications from pknock through netlink/connector
|
||||
|
||||
Compilation of ipset-genl-6.x is disabled by default. It has
|
||||
additional requirements.
|
||||
|
||||
* libmnl
|
||||
* Linux kernel >= 2.6.35
|
||||
|
||||
|
||||
Selecting extensions
|
||||
====================
|
||||
|
||||
1
README
1
README
@@ -18,7 +18,6 @@ simplified, and sped up.
|
||||
|
||||
Included in this package
|
||||
========================
|
||||
- ipset 6.10-genl
|
||||
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ AC_CHECK_HEADERS([linux/netfilter/x_tables.h], [],
|
||||
[AC_MSG_ERROR([You need to have linux/netfilter/x_tables.h, see INSTALL file for details])])
|
||||
PKG_CHECK_MODULES([libxtables], [xtables >= 1.4.5])
|
||||
xtlibdir="$(pkg-config --variable=xtlibdir xtables)"
|
||||
PKG_CHECK_MODULES([libmnl], [libmnl >= 1], [:], [:])
|
||||
|
||||
AC_ARG_WITH([xtlibdir],
|
||||
AS_HELP_STRING([--with-xtlibdir=PATH],
|
||||
@@ -81,6 +80,5 @@ AC_SUBST([kbuilddir])
|
||||
AC_SUBST([xtlibdir])
|
||||
AC_CONFIG_FILES([Makefile Makefile.iptrules Makefile.mans geoip/Makefile
|
||||
extensions/Makefile extensions/ACCOUNT/Makefile
|
||||
extensions/ipset-6/Makefile
|
||||
extensions/pknock/Makefile])
|
||||
AC_OUTPUT
|
||||
|
||||
@@ -5,6 +5,9 @@ Fixes:
|
||||
- compat_xtables: fixed mistranslation of checkentry return values
|
||||
(affected kernels < 2.6.23)
|
||||
- xt_SYSRQ: fix compile error when crypto is turned off
|
||||
Changes:
|
||||
- ipset6-genl has been dropped from the tree;
|
||||
the libmnl build-time dependency is thus no longer needed
|
||||
Enhancements:
|
||||
- Support for Linux 3.3, 3.4
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ obj-${build_fuzzy} += xt_fuzzy.o
|
||||
obj-${build_geoip} += xt_geoip.o
|
||||
obj-${build_iface} += xt_iface.o
|
||||
obj-${build_ipp2p} += xt_ipp2p.o
|
||||
obj-${build_ipset6} += ipset-6/
|
||||
obj-${build_ipv4options} += xt_ipv4options.o
|
||||
obj-${build_length2} += xt_length2.o
|
||||
obj-${build_lscan} += xt_lscan.o
|
||||
|
||||
@@ -19,7 +19,6 @@ obj-${build_fuzzy} += libxt_fuzzy.so
|
||||
obj-${build_geoip} += libxt_geoip.so
|
||||
obj-${build_iface} += libxt_iface.so
|
||||
obj-${build_ipp2p} += libxt_ipp2p.so
|
||||
obj-${build_ipset6} += ipset-6/
|
||||
obj-${build_ipv4options} += libxt_ipv4options.so
|
||||
obj-${build_length2} += libxt_length2.so
|
||||
obj-${build_lscan} += libxt_lscan.so
|
||||
|
||||
1
extensions/ipset-6/.gitignore
vendored
1
extensions/ipset-6/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
/ipset
|
||||
@@ -1,11 +0,0 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
obj-m += xt_set.o
|
||||
obj-m += ip_set.o ip_set_bitmap_ip.o ip_set_bitmap_ipmac.o
|
||||
obj-m += ip_set_bitmap_port.o ip_set_hash_ip.o ip_set_hash_ipport.o
|
||||
obj-m += ip_set_hash_ipportip.o ip_set_hash_ipportnet.o ip_set_hash_net.o
|
||||
obj-m += ip_set_hash_netiface.o 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,25 +0,0 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
AM_CPPFLAGS = -I${srcdir}/include -DNDEBUG
|
||||
AM_CFLAGS = ${regular_CFLAGS} ${libmnl_CFLAGS}
|
||||
|
||||
include ../../Makefile.extra
|
||||
|
||||
lib_LTLIBRARIES = libipset.la
|
||||
libipset_la_SOURCES = libipset/data.c libipset/icmp.c libipset/icmpv6.c \
|
||||
libipset/mnl.c libipset/parse.c libipset/print.c \
|
||||
libipset/session.c libipset/types.c libipset/errcode.c
|
||||
libipset_la_LIBADD = ${libmnl_LIBS}
|
||||
libipset_la_LDFLAGS = -version-info 1:0:0
|
||||
|
||||
sbin_PROGRAMS = ipset
|
||||
ipset_SOURCES = src/ipset.c src/ui.c src/ipset_bitmap_ip.c \
|
||||
src/ipset_bitmap_ipmac.c src/ipset_bitmap_port.c \
|
||||
src/ipset_hash_ip.c src/ipset_hash_ipport.c \
|
||||
src/ipset_hash_ipportip.c src/ipset_hash_ipportnet.c \
|
||||
src/ipset_hash_net.c src/ipset_hash_netiface.c \
|
||||
src/ipset_hash_netport.c \
|
||||
src/ipset_list_set.c
|
||||
ipset_LDADD = libipset.la
|
||||
|
||||
man_MANS = src/ipset.8
|
||||
@@ -1,2 +0,0 @@
|
||||
# -*- Makefile -*-
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
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 +0,0 @@
|
||||
5.4.1-genl
|
||||
@@ -1,138 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_DATA_H
|
||||
#define LIBIPSET_DATA_H
|
||||
|
||||
#include <stdbool.h> /* bool */
|
||||
#include <libipset/nf_inet_addr.h> /* union nf_inet_addr */
|
||||
|
||||
/* Data options */
|
||||
enum ipset_opt {
|
||||
IPSET_OPT_NONE = 0,
|
||||
/* Common ones */
|
||||
IPSET_SETNAME,
|
||||
IPSET_OPT_TYPENAME,
|
||||
IPSET_OPT_FAMILY,
|
||||
/* CADT options */
|
||||
IPSET_OPT_IP,
|
||||
IPSET_OPT_IP_FROM = IPSET_OPT_IP,
|
||||
IPSET_OPT_IP_TO,
|
||||
IPSET_OPT_CIDR,
|
||||
IPSET_OPT_PORT,
|
||||
IPSET_OPT_PORT_FROM = IPSET_OPT_PORT,
|
||||
IPSET_OPT_PORT_TO,
|
||||
IPSET_OPT_TIMEOUT,
|
||||
/* Create-specific options */
|
||||
IPSET_OPT_GC,
|
||||
IPSET_OPT_HASHSIZE,
|
||||
IPSET_OPT_MAXELEM,
|
||||
IPSET_OPT_NETMASK,
|
||||
IPSET_OPT_PROBES,
|
||||
IPSET_OPT_RESIZE,
|
||||
IPSET_OPT_SIZE,
|
||||
/* Create-specific options, filled out by the kernel */
|
||||
IPSET_OPT_ELEMENTS,
|
||||
IPSET_OPT_REFERENCES,
|
||||
IPSET_OPT_MEMSIZE,
|
||||
/* ADT-specific options */
|
||||
IPSET_OPT_ETHER,
|
||||
IPSET_OPT_NAME,
|
||||
IPSET_OPT_NAMEREF,
|
||||
IPSET_OPT_IP2,
|
||||
IPSET_OPT_CIDR2,
|
||||
IPSET_OPT_IP2_TO,
|
||||
IPSET_OPT_PROTO,
|
||||
IPSET_OPT_IFACE,
|
||||
/* Swap/rename to */
|
||||
IPSET_OPT_SETNAME2,
|
||||
/* Flags */
|
||||
IPSET_OPT_EXIST,
|
||||
IPSET_OPT_BEFORE,
|
||||
IPSET_OPT_PHYSDEV,
|
||||
/* Internal options */
|
||||
IPSET_OPT_FLAGS = 48, /* IPSET_FLAG_EXIST| */
|
||||
IPSET_OPT_CADT_FLAGS, /* IPSET_FLAG_BEFORE| */
|
||||
IPSET_OPT_ELEM,
|
||||
IPSET_OPT_TYPE,
|
||||
IPSET_OPT_LINENO,
|
||||
IPSET_OPT_REVISION,
|
||||
IPSET_OPT_REVISION_MIN,
|
||||
IPSET_OPT_MAX,
|
||||
};
|
||||
|
||||
#define IPSET_FLAG(opt) (1LL << (opt))
|
||||
#define IPSET_FLAGS_ALL (~0LL)
|
||||
|
||||
#define IPSET_CREATE_FLAGS \
|
||||
(IPSET_FLAG(IPSET_OPT_FAMILY) \
|
||||
| IPSET_FLAG(IPSET_OPT_TYPENAME)\
|
||||
| IPSET_FLAG(IPSET_OPT_TYPE) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO) \
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR) \
|
||||
| IPSET_FLAG(IPSET_OPT_PORT) \
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO) \
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT) \
|
||||
| IPSET_FLAG(IPSET_OPT_GC) \
|
||||
| IPSET_FLAG(IPSET_OPT_HASHSIZE)\
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM) \
|
||||
| IPSET_FLAG(IPSET_OPT_NETMASK) \
|
||||
| IPSET_FLAG(IPSET_OPT_PROBES) \
|
||||
| IPSET_FLAG(IPSET_OPT_RESIZE) \
|
||||
| IPSET_FLAG(IPSET_OPT_SIZE))
|
||||
|
||||
#define IPSET_ADT_FLAGS \
|
||||
(IPSET_FLAG(IPSET_OPT_IP) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO) \
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR) \
|
||||
| IPSET_FLAG(IPSET_OPT_PORT) \
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO) \
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT) \
|
||||
| IPSET_FLAG(IPSET_OPT_ETHER) \
|
||||
| IPSET_FLAG(IPSET_OPT_NAME) \
|
||||
| IPSET_FLAG(IPSET_OPT_NAMEREF) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP2) \
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2) \
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO) \
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE) \
|
||||
| IPSET_FLAG(IPSET_OPT_CADT_FLAGS)\
|
||||
| IPSET_FLAG(IPSET_OPT_BEFORE) \
|
||||
| IPSET_FLAG(IPSET_OPT_PHYSDEV))
|
||||
|
||||
struct ipset_data;
|
||||
|
||||
extern void ipset_strlcpy(char *dst, const char *src, size_t len);
|
||||
extern bool ipset_data_flags_test(const struct ipset_data *data,
|
||||
uint64_t flags);
|
||||
extern void ipset_data_flags_set(struct ipset_data *data, uint64_t flags);
|
||||
extern void ipset_data_flags_unset(struct ipset_data *data, uint64_t flags);
|
||||
extern bool ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt);
|
||||
|
||||
extern int ipset_data_set(struct ipset_data *data, enum ipset_opt opt,
|
||||
const void *value);
|
||||
extern const void *ipset_data_get(const struct ipset_data *data,
|
||||
enum ipset_opt opt);
|
||||
|
||||
static inline bool
|
||||
ipset_data_test(const struct ipset_data *data, enum ipset_opt opt)
|
||||
{
|
||||
return ipset_data_flags_test(data, IPSET_FLAG(opt));
|
||||
}
|
||||
|
||||
/* Shortcuts */
|
||||
extern const char *ipset_data_setname(const struct ipset_data *data);
|
||||
extern uint8_t ipset_data_family(const struct ipset_data *data);
|
||||
extern uint8_t ipset_data_cidr(const struct ipset_data *data);
|
||||
extern uint64_t ipset_data_flags(const struct ipset_data *data);
|
||||
|
||||
extern void ipset_data_reset(struct ipset_data *data);
|
||||
extern struct ipset_data *ipset_data_init(void);
|
||||
extern void ipset_data_fini(struct ipset_data *data);
|
||||
|
||||
extern size_t ipset_data_sizeof(enum ipset_opt opt, uint8_t family);
|
||||
|
||||
#endif /* LIBIPSET_DATA_H */
|
||||
@@ -1,33 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_DEBUG_H
|
||||
#define LIBIPSET_DEBUG_H
|
||||
|
||||
#ifdef IPSET_DEBUG
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#define D(fmt, args...) \
|
||||
fprintf(stderr, "%s: %s: " fmt "\n", __FILE__, __func__ , ## args)
|
||||
#define IF_D(test, fmt, args...) \
|
||||
if (test) \
|
||||
D(fmt , ## args)
|
||||
|
||||
static inline void
|
||||
dump_nla(struct nlattr *nla[], int maxlen)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < maxlen; i++)
|
||||
D("nla[%u] does%s exist", i, nla[i] ? "" : " NOT");
|
||||
}
|
||||
#else
|
||||
#define D(fmt, args...)
|
||||
#define IF_D(test, fmt, args...)
|
||||
#define dump_nla(nla, maxlen)
|
||||
#endif
|
||||
|
||||
#endif /* LIBIPSET_DEBUG_H */
|
||||
@@ -1,24 +0,0 @@
|
||||
/* Copyright 2007-2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#ifndef LIBIPSET_ERRCODE_H
|
||||
#define LIBIPSET_ERRCODE_H
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* enum ipset_cmd */
|
||||
|
||||
struct ipset_session;
|
||||
|
||||
/* Kernel error code to message table */
|
||||
struct ipset_errcode_table {
|
||||
int errcode; /* error code returned by the kernel */
|
||||
enum ipset_cmd cmd; /* issued command */
|
||||
const char *message; /* error message the code translated to */
|
||||
};
|
||||
|
||||
extern int ipset_errcode(struct ipset_session *session, enum ipset_cmd cmd,
|
||||
int errcode);
|
||||
|
||||
#endif /* LIBIPSET_ERRCODE_H */
|
||||
@@ -1,16 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_ICMP_H
|
||||
#define LIBIPSET_ICMP_H
|
||||
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
|
||||
extern const char *id_to_icmp(uint8_t id);
|
||||
extern const char *icmp_to_name(uint8_t type, uint8_t code);
|
||||
extern int name_to_icmp(const char *str, uint16_t *typecode);
|
||||
|
||||
#endif /* LIBIPSET_ICMP_H */
|
||||
@@ -1,16 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_ICMPV6_H
|
||||
#define LIBIPSET_ICMPV6_H
|
||||
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
|
||||
extern const char *id_to_icmpv6(uint8_t id);
|
||||
extern const char *icmpv6_to_name(uint8_t type, uint8_t code);
|
||||
extern int name_to_icmpv6(const char *str, uint16_t *typecode);
|
||||
|
||||
#endif /* LIBIPSET_ICMPV6_H */
|
||||
@@ -1,199 +0,0 @@
|
||||
#ifndef _IP_SET_H
|
||||
#define _IP_SET_H
|
||||
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 0x60
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
|
||||
/* Message types and commands */
|
||||
enum ipset_cmd {
|
||||
IPSET_CMD_NONE,
|
||||
IPSET_CMD_PROTOCOL, /* 1: Return protocol version */
|
||||
IPSET_CMD_CREATE, /* 2: Create a new (empty) set */
|
||||
IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */
|
||||
IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */
|
||||
IPSET_CMD_RENAME, /* 5: Rename a set */
|
||||
IPSET_CMD_SWAP, /* 6: Swap two sets */
|
||||
IPSET_CMD_LIST, /* 7: List sets */
|
||||
IPSET_CMD_SAVE, /* 8: Save sets */
|
||||
IPSET_CMD_ADD, /* 9: Add an element to a set */
|
||||
IPSET_CMD_DEL, /* 10: Delete an element from a set */
|
||||
IPSET_CMD_TEST, /* 11: Test an element in a set */
|
||||
IPSET_CMD_HEADER, /* 12: Get set header data only */
|
||||
IPSET_CMD_TYPE, /* 13: Get set type */
|
||||
IPSET_MSG_MAX, /* Netlink message commands */
|
||||
|
||||
/* Commands in userspace: */
|
||||
IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
|
||||
IPSET_CMD_HELP, /* 15: Get help */
|
||||
IPSET_CMD_VERSION, /* 16: Get program version */
|
||||
IPSET_CMD_QUIT, /* 17: Quit from interactive mode */
|
||||
|
||||
IPSET_CMD_MAX,
|
||||
|
||||
IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
|
||||
};
|
||||
|
||||
/* Attributes at command level */
|
||||
enum {
|
||||
IPSET_ATTR_UNSPEC,
|
||||
IPSET_ATTR_PROTOCOL, /* 1: Protocol version */
|
||||
IPSET_ATTR_SETNAME, /* 2: Name of the set */
|
||||
IPSET_ATTR_TYPENAME, /* 3: Typename */
|
||||
IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */
|
||||
IPSET_ATTR_REVISION, /* 4: Settype revision */
|
||||
IPSET_ATTR_FAMILY, /* 5: Settype family */
|
||||
IPSET_ATTR_FLAGS, /* 6: Flags at command level */
|
||||
IPSET_ATTR_DATA, /* 7: Nested attributes */
|
||||
IPSET_ATTR_ADT, /* 8: Multiple data containers */
|
||||
IPSET_ATTR_LINENO, /* 9: Restore lineno */
|
||||
IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
|
||||
IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
|
||||
__IPSET_ATTR_CMD_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
|
||||
|
||||
/* CADT specific attributes */
|
||||
enum {
|
||||
IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1,
|
||||
IPSET_ATTR_IP_FROM = IPSET_ATTR_IP,
|
||||
IPSET_ATTR_IP_TO, /* 2 */
|
||||
IPSET_ATTR_CIDR, /* 3 */
|
||||
IPSET_ATTR_PORT, /* 4 */
|
||||
IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
|
||||
IPSET_ATTR_PORT_TO, /* 5 */
|
||||
IPSET_ATTR_TIMEOUT, /* 6 */
|
||||
IPSET_ATTR_PROTO, /* 7 */
|
||||
IPSET_ATTR_CADT_FLAGS, /* 8 */
|
||||
IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */
|
||||
/* Reserve empty slots */
|
||||
IPSET_ATTR_CADT_MAX = 16,
|
||||
/* Create-only specific attributes */
|
||||
IPSET_ATTR_GC,
|
||||
IPSET_ATTR_HASHSIZE,
|
||||
IPSET_ATTR_MAXELEM,
|
||||
IPSET_ATTR_NETMASK,
|
||||
IPSET_ATTR_PROBES,
|
||||
IPSET_ATTR_RESIZE,
|
||||
IPSET_ATTR_SIZE,
|
||||
/* Kernel-only */
|
||||
IPSET_ATTR_ELEMENTS,
|
||||
IPSET_ATTR_REFERENCES,
|
||||
IPSET_ATTR_MEMSIZE,
|
||||
|
||||
__IPSET_ATTR_CREATE_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1)
|
||||
|
||||
/* ADT specific attributes */
|
||||
enum {
|
||||
IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1,
|
||||
IPSET_ATTR_NAME,
|
||||
IPSET_ATTR_NAMEREF,
|
||||
IPSET_ATTR_IP2,
|
||||
IPSET_ATTR_CIDR2,
|
||||
IPSET_ATTR_IP2_TO,
|
||||
IPSET_ATTR_IFACE,
|
||||
__IPSET_ATTR_ADT_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
|
||||
|
||||
/* IP specific attributes */
|
||||
enum {
|
||||
IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1,
|
||||
IPSET_ATTR_IPADDR_IPV6,
|
||||
__IPSET_ATTR_IPADDR_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1)
|
||||
|
||||
/* Error codes */
|
||||
enum ipset_errno {
|
||||
IPSET_ERR_PRIVATE = 4096,
|
||||
IPSET_ERR_PROTOCOL,
|
||||
IPSET_ERR_FIND_TYPE,
|
||||
IPSET_ERR_MAX_SETS,
|
||||
IPSET_ERR_BUSY,
|
||||
IPSET_ERR_EXIST_SETNAME2,
|
||||
IPSET_ERR_TYPE_MISMATCH,
|
||||
IPSET_ERR_EXIST,
|
||||
IPSET_ERR_INVALID_CIDR,
|
||||
IPSET_ERR_INVALID_NETMASK,
|
||||
IPSET_ERR_INVALID_FAMILY,
|
||||
IPSET_ERR_TIMEOUT,
|
||||
IPSET_ERR_REFERENCED,
|
||||
IPSET_ERR_IPADDR_IPV4,
|
||||
IPSET_ERR_IPADDR_IPV6,
|
||||
|
||||
/* Type specific error codes */
|
||||
IPSET_ERR_TYPE_SPECIFIC = 4352,
|
||||
};
|
||||
|
||||
/* Flags at command level */
|
||||
enum ipset_cmd_flags {
|
||||
IPSET_FLAG_BIT_EXIST = 0,
|
||||
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
|
||||
IPSET_FLAG_BIT_LIST_SETNAME = 1,
|
||||
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
|
||||
IPSET_FLAG_BIT_LIST_HEADER = 2,
|
||||
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
|
||||
};
|
||||
|
||||
/* Flags at CADT attribute level */
|
||||
enum ipset_cadt_flags {
|
||||
IPSET_FLAG_BIT_BEFORE = 0,
|
||||
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
|
||||
IPSET_FLAG_BIT_PHYSDEV = 1,
|
||||
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
|
||||
};
|
||||
|
||||
/* Commands with settype-specific attributes */
|
||||
enum ipset_adt {
|
||||
IPSET_ADD,
|
||||
IPSET_DEL,
|
||||
IPSET_TEST,
|
||||
IPSET_ADT_MAX,
|
||||
IPSET_CREATE = IPSET_ADT_MAX,
|
||||
IPSET_CADT_MAX,
|
||||
};
|
||||
|
||||
/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
|
||||
* and IPSET_INVALID_ID if you want to increase the max number of sets.
|
||||
*/
|
||||
typedef __u16 ip_set_id_t;
|
||||
|
||||
#define IPSET_INVALID_ID 65535
|
||||
|
||||
enum ip_set_dim {
|
||||
IPSET_DIM_ZERO = 0,
|
||||
IPSET_DIM_ONE,
|
||||
IPSET_DIM_TWO,
|
||||
IPSET_DIM_THREE,
|
||||
/* Max dimension in elements.
|
||||
* If changed, new revision of iptables match/target is required.
|
||||
*/
|
||||
IPSET_DIM_MAX = 6,
|
||||
};
|
||||
|
||||
/* Option flags for kernel operations */
|
||||
enum ip_set_kopt {
|
||||
IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO),
|
||||
IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
|
||||
IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
|
||||
IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_H */
|
||||
@@ -1,12 +0,0 @@
|
||||
#ifndef __IP_SET_BITMAP_H
|
||||
#define __IP_SET_BITMAP_H
|
||||
|
||||
/* Bitmap type specific error codes */
|
||||
enum {
|
||||
/* The element is out of the range of the set */
|
||||
IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC,
|
||||
/* The range exceeds the size limit of the set type */
|
||||
IPSET_ERR_BITMAP_RANGE_SIZE,
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_BITMAP_H */
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef __IP_SET_HASH_H
|
||||
#define __IP_SET_HASH_H
|
||||
|
||||
/* Hash type specific error codes */
|
||||
enum {
|
||||
/* Hash is full */
|
||||
IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC,
|
||||
/* Null-valued element */
|
||||
IPSET_ERR_HASH_ELEM,
|
||||
/* Invalid protocol */
|
||||
IPSET_ERR_INVALID_PROTO,
|
||||
/* Protocol missing but must be specified */
|
||||
IPSET_ERR_MISSING_PROTO,
|
||||
/* Range not supported */
|
||||
IPSET_ERR_HASH_RANGE_UNSUPPORTED,
|
||||
/* Invalid range */
|
||||
IPSET_ERR_HASH_RANGE,
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_HASH_H */
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef __IP_SET_LIST_H
|
||||
#define __IP_SET_LIST_H
|
||||
|
||||
/* List type specific error codes */
|
||||
enum {
|
||||
/* Set name to be added/deleted/tested does not exist. */
|
||||
IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC,
|
||||
/* list:set type is not permitted to add */
|
||||
IPSET_ERR_LOOP,
|
||||
/* Missing reference set */
|
||||
IPSET_ERR_BEFORE,
|
||||
/* Reference set does not exist */
|
||||
IPSET_ERR_NAMEREF,
|
||||
/* Set is full */
|
||||
IPSET_ERR_LIST_FULL,
|
||||
/* Reference set is not added to the set */
|
||||
IPSET_ERR_REF_EXIST,
|
||||
};
|
||||
|
||||
#endif /* __IP_SET_LIST_H */
|
||||
@@ -1,29 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_MNL_H
|
||||
#define LIBIPSET_MNL_H
|
||||
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
#include <libmnl/libmnl.h> /* libmnl backend */
|
||||
|
||||
#include <libipset/transport.h> /* struct ipset_transport */
|
||||
|
||||
#ifndef NFNETLINK_V0
|
||||
#define NFNETLINK_V0 0
|
||||
|
||||
struct nfgenmsg {
|
||||
uint8_t nfgen_family;
|
||||
uint8_t version;
|
||||
uint16_t res_id;
|
||||
};
|
||||
#endif
|
||||
|
||||
extern int ipset_get_nlmsg_type(const struct nlmsghdr *nlh);
|
||||
|
||||
extern const struct ipset_transport ipset_mnl_transport;
|
||||
|
||||
#endif /* LIBIPSET_MNL_H */
|
||||
@@ -1,22 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_NF_INET_ADDR_H
|
||||
#define LIBIPSET_NF_INET_ADDR_H
|
||||
|
||||
#include <stdint.h> /* uint32_t */
|
||||
#include <netinet/in.h> /* struct in[6]_addr */
|
||||
|
||||
/* The structure to hold IP addresses, same as in linux/netfilter.h */
|
||||
union nf_inet_addr {
|
||||
uint32_t all[4];
|
||||
uint32_t ip;
|
||||
uint32_t ip6[4];
|
||||
struct in_addr in;
|
||||
struct in6_addr in6;
|
||||
};
|
||||
|
||||
#endif /* LIBIPSET_NF_INET_ADDR_H */
|
||||
@@ -1,19 +0,0 @@
|
||||
#ifndef LIBIPSET_NFPROTO_H
|
||||
#define LIBIPSET_NFPROTO_H
|
||||
|
||||
/*
|
||||
* The constants to select, same as in linux/netfilter.h.
|
||||
* Like nf_inet_addr.h, this is just here so that we need not to rely on
|
||||
* the presence of a recent-enough netfilter.h.
|
||||
*/
|
||||
enum {
|
||||
NFPROTO_UNSPEC = 0,
|
||||
NFPROTO_IPV4 = 2,
|
||||
NFPROTO_ARP = 3,
|
||||
NFPROTO_BRIDGE = 7,
|
||||
NFPROTO_IPV6 = 10,
|
||||
NFPROTO_DECNET = 12,
|
||||
NFPROTO_NUMPROTO,
|
||||
};
|
||||
|
||||
#endif /* LIBIPSET_NFPROTO_H */
|
||||
@@ -1,101 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_PARSE_H
|
||||
#define LIBIPSET_PARSE_H
|
||||
|
||||
#include <libipset/data.h> /* enum ipset_opt */
|
||||
|
||||
/* For parsing/printing data */
|
||||
#define IPSET_CIDR_SEPARATOR "/"
|
||||
#define IPSET_RANGE_SEPARATOR "-"
|
||||
#define IPSET_ELEM_SEPARATOR ","
|
||||
#define IPSET_NAME_SEPARATOR ","
|
||||
#define IPSET_PROTO_SEPARATOR ":"
|
||||
|
||||
struct ipset_session;
|
||||
struct ipset_arg;
|
||||
|
||||
typedef int (*ipset_parsefn)(struct ipset_session *s,
|
||||
enum ipset_opt opt, const char *str);
|
||||
|
||||
extern int ipset_parse_ether(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_port(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str,
|
||||
const char *proto);
|
||||
extern int ipset_parse_tcpudp_port(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str,
|
||||
const char *proto);
|
||||
extern int ipset_parse_tcp_port(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_single_tcp_port(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_proto(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_icmp(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_icmpv6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_proto_port(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_family(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_ip(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_single_ip(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_net(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_range(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_netrange(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_iprange(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_ipnet(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_ip4_single6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_ip4_net6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_name(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_before(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_after(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_setname(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_uint32(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_uint8(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_netmask(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_flag(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_typename(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_iface(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_output(struct ipset_session *session,
|
||||
int opt, const char *str);
|
||||
extern int ipset_parse_ignored(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_elem(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_call_parser(struct ipset_session *session,
|
||||
const struct ipset_arg *arg,
|
||||
const char *str);
|
||||
|
||||
/* Compatibility parser functions */
|
||||
extern int ipset_parse_iptimeout(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_name_compat(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
|
||||
#endif /* LIBIPSET_PARSE_H */
|
||||
@@ -1,157 +0,0 @@
|
||||
#ifndef _NET_PFXLEN_H
|
||||
#define _NET_PFXLEN_H 1
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#ifdef HAVE_PFXLEN_H
|
||||
#include <linux/netfilter/pfxlen.h>
|
||||
#else
|
||||
|
||||
#include <libipset/nf_inet_addr.h> /* union nf_inet_addr */
|
||||
|
||||
#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 prefixlen_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),
|
||||
};
|
||||
#endif /* !HAVE_PFXLEN_H */
|
||||
|
||||
#define PFXLEN(n) prefixlen_netmask_map[n].ip
|
||||
#define PFXLEN6(n) prefixlen_netmask_map[n].ip6
|
||||
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_PRINT_H
|
||||
#define LIBIPSET_PRINT_H
|
||||
|
||||
#include <libipset/data.h> /* enum ipset_opt */
|
||||
|
||||
typedef int (*ipset_printfn)(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
|
||||
extern int ipset_print_ether(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_family(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_type(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_ip(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_ipaddr(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_number(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_name(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_port(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_iface(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_proto(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_icmp(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_icmpv6(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_proto_port(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_flag(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
extern int ipset_print_elem(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
|
||||
#define ipset_print_portnum ipset_print_number
|
||||
|
||||
extern int ipset_print_data(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt, uint8_t env);
|
||||
|
||||
#endif /* LIBIPSET_PRINT_H */
|
||||
@@ -1,105 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_SESSION_H
|
||||
#define LIBIPSET_SESSION_H
|
||||
|
||||
#include <stdbool.h> /* bool */
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
#include <stdio.h> /* printf */
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* enum ipset_cmd */
|
||||
|
||||
/* Report and output buffer sizes */
|
||||
#define IPSET_ERRORBUFLEN 1024
|
||||
#define IPSET_OUTBUFLEN 8192
|
||||
|
||||
struct ipset_session;
|
||||
struct ipset_data;
|
||||
struct ipset_handle;
|
||||
|
||||
extern struct ipset_data *
|
||||
ipset_session_data(const struct ipset_session *session);
|
||||
extern struct ipset_handle *
|
||||
ipset_session_handle(const struct ipset_session *session);
|
||||
extern const struct ipset_type *
|
||||
ipset_saved_type(const struct ipset_session *session);
|
||||
extern void ipset_session_lineno(struct ipset_session *session,
|
||||
uint32_t lineno);
|
||||
|
||||
enum ipset_err_type {
|
||||
IPSET_ERROR,
|
||||
IPSET_WARNING,
|
||||
};
|
||||
|
||||
extern int ipset_session_report(struct ipset_session *session,
|
||||
enum ipset_err_type type,
|
||||
const char *fmt, ...);
|
||||
|
||||
#define ipset_err(session, fmt, args...) \
|
||||
ipset_session_report(session, IPSET_ERROR, fmt , ## args)
|
||||
|
||||
#define ipset_warn(session, fmt, args...) \
|
||||
ipset_session_report(session, IPSET_WARNING, fmt , ## args)
|
||||
|
||||
#define ipset_errptr(session, fmt, args...) ({ \
|
||||
ipset_session_report(session, IPSET_ERROR, fmt , ## args); \
|
||||
NULL; \
|
||||
})
|
||||
|
||||
extern void ipset_session_report_reset(struct ipset_session *session);
|
||||
extern const char *ipset_session_error(const struct ipset_session *session);
|
||||
extern const char *ipset_session_warning(const struct ipset_session *session);
|
||||
|
||||
#define ipset_session_data_set(session, opt, value) \
|
||||
ipset_data_set(ipset_session_data(session), opt, value)
|
||||
#define ipset_session_data_get(session, opt) \
|
||||
ipset_data_get(ipset_session_data(session), opt)
|
||||
|
||||
/* Environment option flags */
|
||||
enum ipset_envopt {
|
||||
IPSET_ENV_BIT_SORTED = 0,
|
||||
IPSET_ENV_SORTED = (1 << IPSET_ENV_BIT_SORTED),
|
||||
IPSET_ENV_BIT_QUIET = 1,
|
||||
IPSET_ENV_QUIET = (1 << IPSET_ENV_BIT_QUIET),
|
||||
IPSET_ENV_BIT_RESOLVE = 2,
|
||||
IPSET_ENV_RESOLVE = (1 << IPSET_ENV_BIT_RESOLVE),
|
||||
IPSET_ENV_BIT_EXIST = 3,
|
||||
IPSET_ENV_EXIST = (1 << IPSET_ENV_BIT_EXIST),
|
||||
IPSET_ENV_BIT_LIST_SETNAME = 4,
|
||||
IPSET_ENV_LIST_SETNAME = (1 << IPSET_ENV_BIT_LIST_SETNAME),
|
||||
IPSET_ENV_BIT_LIST_HEADER = 5,
|
||||
IPSET_ENV_LIST_HEADER = (1 << IPSET_ENV_BIT_LIST_HEADER),
|
||||
};
|
||||
|
||||
extern int ipset_envopt_parse(struct ipset_session *session,
|
||||
int env, const char *str);
|
||||
extern bool ipset_envopt_test(struct ipset_session *session,
|
||||
enum ipset_envopt env);
|
||||
|
||||
enum ipset_output_mode {
|
||||
IPSET_LIST_NONE,
|
||||
IPSET_LIST_PLAIN,
|
||||
IPSET_LIST_SAVE,
|
||||
IPSET_LIST_XML,
|
||||
};
|
||||
|
||||
extern int ipset_session_output(struct ipset_session *session,
|
||||
enum ipset_output_mode mode);
|
||||
|
||||
extern int ipset_commit(struct ipset_session *session);
|
||||
extern int ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd,
|
||||
uint32_t lineno);
|
||||
|
||||
typedef int (*ipset_outfn)(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
extern struct ipset_session *ipset_session_init(ipset_outfn outfn);
|
||||
extern int ipset_session_fini(struct ipset_session *session);
|
||||
|
||||
extern void ipset_debug_msg(const char *dir, void *buffer, int len);
|
||||
|
||||
#endif /* LIBIPSET_SESSION_H */
|
||||
@@ -1,27 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_TRANSPORT_H
|
||||
#define LIBIPSET_TRANSPORT_H
|
||||
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
#include <linux/netlink.h> /* struct nlmsghdr */
|
||||
|
||||
#include <libmnl/libmnl.h> /* mnl_cb_t */
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* enum ipset_cmd */
|
||||
|
||||
struct ipset_handle;
|
||||
|
||||
struct ipset_transport {
|
||||
struct ipset_handle * (*init)(mnl_cb_t *cb_ctl, void *data);
|
||||
int (*fini)(struct ipset_handle *handle);
|
||||
void (*fill_hdr)(struct ipset_handle *handle, enum ipset_cmd cmd,
|
||||
void *buffer, size_t len, uint8_t envflags);
|
||||
int (*query)(struct ipset_handle *handle, void *buffer, size_t len);
|
||||
};
|
||||
|
||||
#endif /* LIBIPSET_TRANSPORT_H */
|
||||
@@ -1,109 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_TYPES_H
|
||||
#define LIBIPSET_TYPES_H
|
||||
|
||||
#include <stddef.h> /* NULL */
|
||||
#include <stdint.h> /* uintxx_t */
|
||||
|
||||
#include <libipset/data.h> /* enum ipset_opt */
|
||||
#include <libipset/parse.h> /* ipset_parsefn */
|
||||
#include <libipset/print.h> /* ipset_printfn */
|
||||
#include <libipset/linux_ip_set.h> /* IPSET_MAXNAMELEN */
|
||||
#include <libipset/nfproto.h> /* for NFPROTO_ */
|
||||
|
||||
/* Family rules:
|
||||
* - NFPROTO_UNSPEC: type is family-neutral
|
||||
* - NFPROTO_IPV4: type supports IPv4 only
|
||||
* - NFPROTO_IPV6: type supports IPv6 only
|
||||
* Special (userspace) ipset-only extra value:
|
||||
* - NFPROTO_IPSET_IPV46: type supports both IPv4 and IPv6
|
||||
*/
|
||||
enum {
|
||||
NFPROTO_IPSET_IPV46 = 255,
|
||||
};
|
||||
|
||||
/* The maximal type dimension userspace supports */
|
||||
#define IPSET_DIM_UMAX 3
|
||||
|
||||
/* Parser options */
|
||||
enum {
|
||||
IPSET_NO_ARG = -1,
|
||||
IPSET_OPTIONAL_ARG,
|
||||
IPSET_MANDATORY_ARG,
|
||||
IPSET_MANDATORY_ARG2,
|
||||
};
|
||||
|
||||
struct ipset_session;
|
||||
|
||||
/* Parse and print type-specific arguments */
|
||||
struct ipset_arg {
|
||||
const char *name[2]; /* option names */
|
||||
int has_arg; /* mandatory/optional/no arg */
|
||||
enum ipset_opt opt; /* argumentum type */
|
||||
ipset_parsefn parse; /* parser function */
|
||||
ipset_printfn print; /* printing function */
|
||||
};
|
||||
|
||||
/* Type check against the kernel */
|
||||
enum {
|
||||
IPSET_KERNEL_MISMATCH = -1,
|
||||
IPSET_KERNEL_CHECK_NEEDED,
|
||||
IPSET_KERNEL_OK,
|
||||
};
|
||||
|
||||
/* How element parts are parsed */
|
||||
struct ipset_elem {
|
||||
ipset_parsefn parse; /* elem parser function */
|
||||
ipset_printfn print; /* elem print function */
|
||||
enum ipset_opt opt; /* elem option */
|
||||
};
|
||||
|
||||
/* The set types in userspace
|
||||
* we could collapse 'args' and 'mandatory' to two-element lists
|
||||
* but for the readability the full list is supported.
|
||||
*/
|
||||
struct ipset_type {
|
||||
const char *name;
|
||||
uint8_t revision; /* revision number */
|
||||
uint8_t family; /* supported family */
|
||||
uint8_t dimension; /* elem dimension */
|
||||
int8_t kernel_check; /* kernel check */
|
||||
bool last_elem_optional; /* last element optional */
|
||||
struct ipset_elem elem[IPSET_DIM_UMAX]; /* parse elem */
|
||||
ipset_parsefn compat_parse_elem; /* compatibility parser */
|
||||
const struct ipset_arg *args[IPSET_CADT_MAX]; /* create/ADT args besides elem */
|
||||
uint64_t mandatory[IPSET_CADT_MAX]; /* create/ADT mandatory flags */
|
||||
uint64_t full[IPSET_CADT_MAX]; /* full args flags */
|
||||
const char *usage; /* terse usage */
|
||||
void (*usagefn)(void); /* additional usage */
|
||||
|
||||
struct ipset_type *next;
|
||||
const char *alias[]; /* name alias(es) */
|
||||
};
|
||||
|
||||
extern int ipset_cache_add(const char *name, const struct ipset_type *type,
|
||||
uint8_t family);
|
||||
extern int ipset_cache_del(const char *name);
|
||||
extern int ipset_cache_rename(const char *from, const char *to);
|
||||
extern int ipset_cache_swap(const char *from, const char *to);
|
||||
|
||||
extern int ipset_cache_init(void);
|
||||
extern void ipset_cache_fini(void);
|
||||
|
||||
extern const struct ipset_type *
|
||||
ipset_type_get(struct ipset_session *session, enum ipset_cmd cmd);
|
||||
extern const struct ipset_type *
|
||||
ipset_type_check(struct ipset_session *session);
|
||||
|
||||
extern int ipset_type_add(struct ipset_type *type);
|
||||
extern const struct ipset_type *ipset_types(void);
|
||||
extern const char *ipset_typename_resolve(const char *str);
|
||||
extern bool ipset_match_typename(const char *str,
|
||||
const struct ipset_type *t);
|
||||
|
||||
#endif /* LIBIPSET_TYPES_H */
|
||||
@@ -1,44 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_UI_H
|
||||
#define LIBIPSET_UI_H
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* enum ipset_cmd */
|
||||
|
||||
/* Commands in userspace */
|
||||
struct ipset_commands {
|
||||
enum ipset_cmd cmd;
|
||||
int has_arg;
|
||||
const char *name[2];
|
||||
const char *help;
|
||||
};
|
||||
|
||||
extern const struct ipset_commands ipset_commands[];
|
||||
|
||||
struct ipset_session;
|
||||
struct ipset_data;
|
||||
|
||||
/* Environment options */
|
||||
struct ipset_envopts {
|
||||
int flag;
|
||||
int has_arg;
|
||||
const char *name[2];
|
||||
const char *help;
|
||||
int (*parse)(struct ipset_session *s, int flag, const char *str);
|
||||
int (*print)(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, int flag, uint8_t env);
|
||||
};
|
||||
|
||||
extern const struct ipset_envopts ipset_envopts[];
|
||||
|
||||
extern bool ipset_match_cmd(const char *arg, const char * const name[]);
|
||||
extern bool ipset_match_option(const char *arg, const char * const name[]);
|
||||
extern bool ipset_match_envopt(const char *arg, const char * const name[]);
|
||||
extern void ipset_shift_argv(int *argc, char *argv[], int from);
|
||||
extern void ipset_port_usage(void);
|
||||
|
||||
#endif /* LIBIPSET_UI_H */
|
||||
@@ -1,50 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#ifndef LIBIPSET_UTILS_H
|
||||
#define LIBIPSET_UTILS_H
|
||||
|
||||
#include <string.h> /* strcmp */
|
||||
#include <netinet/in.h> /* struct in[6]_addr */
|
||||
|
||||
/* String equality tests */
|
||||
#define STREQ(a, b) (strcmp(a, b) == 0)
|
||||
#define STRNEQ(a, b, n) (strncmp(a, b, n) == 0)
|
||||
#define STRCASEQ(a, b) (strcasecmp(a, b) == 0)
|
||||
#define STRNCASEQ(a, b, n) (strncasecmp(a, b, n) == 0)
|
||||
|
||||
/* Stringify tokens */
|
||||
#define _STR(c) #c
|
||||
#define STR(c) _STR(c)
|
||||
|
||||
/* Min/max */
|
||||
#define MIN(a, b) (a < b ? a : b)
|
||||
#define MAX(a, b) (a > b ? a : b)
|
||||
|
||||
#define UNUSED __attribute__ ((unused))
|
||||
#ifdef NDEBUG
|
||||
#define ASSERT_UNUSED UNUSED
|
||||
#else
|
||||
#define ASSERT_UNUSED
|
||||
#endif
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
in4cpy(struct in_addr *dest, const struct in_addr *src)
|
||||
{
|
||||
dest->s_addr = src->s_addr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
in6cpy(struct in6_addr *dest, const struct in6_addr *src)
|
||||
{
|
||||
memcpy(dest, src, sizeof(struct in6_addr));
|
||||
}
|
||||
|
||||
#endif /* LIBIPSET_UTILS_H */
|
||||
@@ -1,499 +0,0 @@
|
||||
#ifndef _IP_SET_H
|
||||
#define _IP_SET_H
|
||||
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* Copyright (C) 2003-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 0x60
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
|
||||
/* Message types and commands */
|
||||
enum ipset_cmd {
|
||||
IPSET_CMD_NONE,
|
||||
IPSET_CMD_PROTOCOL, /* 1: Return protocol version */
|
||||
IPSET_CMD_CREATE, /* 2: Create a new (empty) set */
|
||||
IPSET_CMD_DESTROY, /* 3: Destroy a (empty) set */
|
||||
IPSET_CMD_FLUSH, /* 4: Remove all elements from a set */
|
||||
IPSET_CMD_RENAME, /* 5: Rename a set */
|
||||
IPSET_CMD_SWAP, /* 6: Swap two sets */
|
||||
IPSET_CMD_LIST, /* 7: List sets */
|
||||
IPSET_CMD_SAVE, /* 8: Save sets */
|
||||
IPSET_CMD_ADD, /* 9: Add an element to a set */
|
||||
IPSET_CMD_DEL, /* 10: Delete an element from a set */
|
||||
IPSET_CMD_TEST, /* 11: Test an element in a set */
|
||||
IPSET_CMD_HEADER, /* 12: Get set header data only */
|
||||
IPSET_CMD_TYPE, /* 13: Get set type */
|
||||
IPSET_MSG_MAX, /* Netlink message commands */
|
||||
|
||||
/* Commands in userspace: */
|
||||
IPSET_CMD_RESTORE = IPSET_MSG_MAX, /* 14: Enter restore mode */
|
||||
IPSET_CMD_HELP, /* 15: Get help */
|
||||
IPSET_CMD_VERSION, /* 16: Get program version */
|
||||
IPSET_CMD_QUIT, /* 17: Quit from interactive mode */
|
||||
|
||||
IPSET_CMD_MAX,
|
||||
|
||||
IPSET_CMD_COMMIT = IPSET_CMD_MAX, /* 18: Commit buffered commands */
|
||||
};
|
||||
|
||||
/* Attributes at command level */
|
||||
enum {
|
||||
IPSET_ATTR_UNSPEC,
|
||||
IPSET_ATTR_PROTOCOL, /* 1: Protocol version */
|
||||
IPSET_ATTR_SETNAME, /* 2: Name of the set */
|
||||
IPSET_ATTR_TYPENAME, /* 3: Typename */
|
||||
IPSET_ATTR_SETNAME2 = IPSET_ATTR_TYPENAME, /* Setname at rename/swap */
|
||||
IPSET_ATTR_REVISION, /* 4: Settype revision */
|
||||
IPSET_ATTR_FAMILY, /* 5: Settype family */
|
||||
IPSET_ATTR_FLAGS, /* 6: Flags at command level */
|
||||
IPSET_ATTR_DATA, /* 7: Nested attributes */
|
||||
IPSET_ATTR_ADT, /* 8: Multiple data containers */
|
||||
IPSET_ATTR_LINENO, /* 9: Restore lineno */
|
||||
IPSET_ATTR_PROTOCOL_MIN, /* 10: Minimal supported version number */
|
||||
IPSET_ATTR_REVISION_MIN = IPSET_ATTR_PROTOCOL_MIN, /* type rev min */
|
||||
__IPSET_ATTR_CMD_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_CMD_MAX (__IPSET_ATTR_CMD_MAX - 1)
|
||||
|
||||
/* CADT specific attributes */
|
||||
enum {
|
||||
IPSET_ATTR_IP = IPSET_ATTR_UNSPEC + 1,
|
||||
IPSET_ATTR_IP_FROM = IPSET_ATTR_IP,
|
||||
IPSET_ATTR_IP_TO, /* 2 */
|
||||
IPSET_ATTR_CIDR, /* 3 */
|
||||
IPSET_ATTR_PORT, /* 4 */
|
||||
IPSET_ATTR_PORT_FROM = IPSET_ATTR_PORT,
|
||||
IPSET_ATTR_PORT_TO, /* 5 */
|
||||
IPSET_ATTR_TIMEOUT, /* 6 */
|
||||
IPSET_ATTR_PROTO, /* 7 */
|
||||
IPSET_ATTR_CADT_FLAGS, /* 8 */
|
||||
IPSET_ATTR_CADT_LINENO = IPSET_ATTR_LINENO, /* 9 */
|
||||
/* Reserve empty slots */
|
||||
IPSET_ATTR_CADT_MAX = 16,
|
||||
/* Create-only specific attributes */
|
||||
IPSET_ATTR_GC,
|
||||
IPSET_ATTR_HASHSIZE,
|
||||
IPSET_ATTR_MAXELEM,
|
||||
IPSET_ATTR_NETMASK,
|
||||
IPSET_ATTR_PROBES,
|
||||
IPSET_ATTR_RESIZE,
|
||||
IPSET_ATTR_SIZE,
|
||||
/* Kernel-only */
|
||||
IPSET_ATTR_ELEMENTS,
|
||||
IPSET_ATTR_REFERENCES,
|
||||
IPSET_ATTR_MEMSIZE,
|
||||
|
||||
__IPSET_ATTR_CREATE_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_CREATE_MAX (__IPSET_ATTR_CREATE_MAX - 1)
|
||||
|
||||
/* ADT specific attributes */
|
||||
enum {
|
||||
IPSET_ATTR_ETHER = IPSET_ATTR_CADT_MAX + 1,
|
||||
IPSET_ATTR_NAME,
|
||||
IPSET_ATTR_NAMEREF,
|
||||
IPSET_ATTR_IP2,
|
||||
IPSET_ATTR_CIDR2,
|
||||
IPSET_ATTR_IP2_TO,
|
||||
IPSET_ATTR_IFACE,
|
||||
__IPSET_ATTR_ADT_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_ADT_MAX (__IPSET_ATTR_ADT_MAX - 1)
|
||||
|
||||
/* IP specific attributes */
|
||||
enum {
|
||||
IPSET_ATTR_IPADDR_IPV4 = IPSET_ATTR_UNSPEC + 1,
|
||||
IPSET_ATTR_IPADDR_IPV6,
|
||||
__IPSET_ATTR_IPADDR_MAX,
|
||||
};
|
||||
#define IPSET_ATTR_IPADDR_MAX (__IPSET_ATTR_IPADDR_MAX - 1)
|
||||
|
||||
/* Error codes */
|
||||
enum ipset_errno {
|
||||
IPSET_ERR_PRIVATE = 4096,
|
||||
IPSET_ERR_PROTOCOL,
|
||||
IPSET_ERR_FIND_TYPE,
|
||||
IPSET_ERR_MAX_SETS,
|
||||
IPSET_ERR_BUSY,
|
||||
IPSET_ERR_EXIST_SETNAME2,
|
||||
IPSET_ERR_TYPE_MISMATCH,
|
||||
IPSET_ERR_EXIST,
|
||||
IPSET_ERR_INVALID_CIDR,
|
||||
IPSET_ERR_INVALID_NETMASK,
|
||||
IPSET_ERR_INVALID_FAMILY,
|
||||
IPSET_ERR_TIMEOUT,
|
||||
IPSET_ERR_REFERENCED,
|
||||
IPSET_ERR_IPADDR_IPV4,
|
||||
IPSET_ERR_IPADDR_IPV6,
|
||||
|
||||
/* Type specific error codes */
|
||||
IPSET_ERR_TYPE_SPECIFIC = 4352,
|
||||
};
|
||||
|
||||
/* Flags at command level */
|
||||
enum ipset_cmd_flags {
|
||||
IPSET_FLAG_BIT_EXIST = 0,
|
||||
IPSET_FLAG_EXIST = (1 << IPSET_FLAG_BIT_EXIST),
|
||||
IPSET_FLAG_BIT_LIST_SETNAME = 1,
|
||||
IPSET_FLAG_LIST_SETNAME = (1 << IPSET_FLAG_BIT_LIST_SETNAME),
|
||||
IPSET_FLAG_BIT_LIST_HEADER = 2,
|
||||
IPSET_FLAG_LIST_HEADER = (1 << IPSET_FLAG_BIT_LIST_HEADER),
|
||||
};
|
||||
|
||||
/* Flags at CADT attribute level */
|
||||
enum ipset_cadt_flags {
|
||||
IPSET_FLAG_BIT_BEFORE = 0,
|
||||
IPSET_FLAG_BEFORE = (1 << IPSET_FLAG_BIT_BEFORE),
|
||||
IPSET_FLAG_BIT_PHYSDEV = 1,
|
||||
IPSET_FLAG_PHYSDEV = (1 << IPSET_FLAG_BIT_PHYSDEV),
|
||||
};
|
||||
|
||||
/* Commands with settype-specific attributes */
|
||||
enum ipset_adt {
|
||||
IPSET_ADD,
|
||||
IPSET_DEL,
|
||||
IPSET_TEST,
|
||||
IPSET_ADT_MAX,
|
||||
IPSET_CREATE = IPSET_ADT_MAX,
|
||||
IPSET_CADT_MAX,
|
||||
};
|
||||
|
||||
/* Sets are identified by an index in kernel space. Tweak with ip_set_id_t
|
||||
* and IPSET_INVALID_ID if you want to increase the max number of sets.
|
||||
*/
|
||||
typedef __u16 ip_set_id_t;
|
||||
|
||||
#define IPSET_INVALID_ID 65535
|
||||
|
||||
enum ip_set_dim {
|
||||
IPSET_DIM_ZERO = 0,
|
||||
IPSET_DIM_ONE,
|
||||
IPSET_DIM_TWO,
|
||||
IPSET_DIM_THREE,
|
||||
/* Max dimension in elements.
|
||||
* If changed, new revision of iptables match/target is required.
|
||||
*/
|
||||
IPSET_DIM_MAX = 6,
|
||||
};
|
||||
|
||||
/* Option flags for kernel operations */
|
||||
enum ip_set_kopt {
|
||||
IPSET_INV_MATCH = (1 << IPSET_DIM_ZERO),
|
||||
IPSET_DIM_ONE_SRC = (1 << IPSET_DIM_ONE),
|
||||
IPSET_DIM_TWO_SRC = (1 << IPSET_DIM_TWO),
|
||||
IPSET_DIM_THREE_SRC = (1 << IPSET_DIM_THREE),
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
/* Set features */
|
||||
enum ip_set_feature {
|
||||
IPSET_TYPE_IP_FLAG = 0,
|
||||
IPSET_TYPE_IP = (1 << IPSET_TYPE_IP_FLAG),
|
||||
IPSET_TYPE_PORT_FLAG = 1,
|
||||
IPSET_TYPE_PORT = (1 << IPSET_TYPE_PORT_FLAG),
|
||||
IPSET_TYPE_MAC_FLAG = 2,
|
||||
IPSET_TYPE_MAC = (1 << IPSET_TYPE_MAC_FLAG),
|
||||
IPSET_TYPE_IP2_FLAG = 3,
|
||||
IPSET_TYPE_IP2 = (1 << IPSET_TYPE_IP2_FLAG),
|
||||
IPSET_TYPE_NAME_FLAG = 4,
|
||||
IPSET_TYPE_NAME = (1 << IPSET_TYPE_NAME_FLAG),
|
||||
IPSET_TYPE_IFACE_FLAG = 5,
|
||||
IPSET_TYPE_IFACE = (1 << IPSET_TYPE_IFACE_FLAG),
|
||||
/* Strictly speaking not a feature, but a flag for dumping:
|
||||
* this settype must be dumped last */
|
||||
IPSET_DUMP_LAST_FLAG = 7,
|
||||
IPSET_DUMP_LAST = (1 << IPSET_DUMP_LAST_FLAG),
|
||||
};
|
||||
|
||||
struct ip_set;
|
||||
|
||||
typedef int (*ipset_adtfn)(struct ip_set *set, void *value,
|
||||
u32 timeout, u32 flags);
|
||||
|
||||
/* Kernel API function options */
|
||||
struct ip_set_adt_opt {
|
||||
u8 family; /* Actual protocol family */
|
||||
u8 dim; /* Dimension of match/target */
|
||||
u8 flags; /* Direction and negation flags */
|
||||
u32 cmdflags; /* Command-like flags */
|
||||
u32 timeout; /* Timeout value */
|
||||
};
|
||||
|
||||
/* Set type, variant-specific part */
|
||||
struct ip_set_type_variant {
|
||||
/* Kernelspace: test/add/del entries
|
||||
* returns negative error code,
|
||||
* zero for no match/success to add/delete
|
||||
* positive for matching element */
|
||||
int (*kadt)(struct ip_set *set, const struct sk_buff * skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt);
|
||||
|
||||
/* Userspace: test/add/del entries
|
||||
* returns negative error code,
|
||||
* zero for no match/success to add/delete
|
||||
* positive for matching element */
|
||||
int (*uadt)(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
|
||||
|
||||
/* Low level add/del/test functions */
|
||||
ipset_adtfn adt[IPSET_ADT_MAX];
|
||||
|
||||
/* When adding entries and set is full, try to resize the set */
|
||||
int (*resize)(struct ip_set *set, bool retried);
|
||||
/* Destroy the set */
|
||||
void (*destroy)(struct ip_set *set);
|
||||
/* Flush the elements */
|
||||
void (*flush)(struct ip_set *set);
|
||||
/* Expire entries before listing */
|
||||
void (*expire)(struct ip_set *set);
|
||||
/* List set header data */
|
||||
int (*head)(struct ip_set *set, struct sk_buff *skb);
|
||||
/* List elements */
|
||||
int (*list)(const struct ip_set *set, struct sk_buff *skb,
|
||||
struct netlink_callback *cb);
|
||||
|
||||
/* Return true if "b" set is the same as "a"
|
||||
* according to the create set parameters */
|
||||
bool (*same_set)(const struct ip_set *a, const struct ip_set *b);
|
||||
};
|
||||
|
||||
/* The core set type structure */
|
||||
struct ip_set_type {
|
||||
struct list_head list;
|
||||
|
||||
/* Typename */
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
/* Protocol version */
|
||||
u8 protocol;
|
||||
/* Set features to control swapping */
|
||||
u8 features;
|
||||
/* Set type dimension */
|
||||
u8 dimension;
|
||||
/*
|
||||
* Supported family: may be NFPROTO_UNSPEC for both
|
||||
* NFPROTO_IPV4/NFPROTO_IPV6.
|
||||
*/
|
||||
u8 family;
|
||||
/* Type revisions */
|
||||
u8 revision_min, revision_max;
|
||||
|
||||
/* Create set */
|
||||
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
|
||||
|
||||
/* Attribute policies */
|
||||
const struct nla_policy create_policy[IPSET_ATTR_CREATE_MAX + 1];
|
||||
const struct nla_policy adt_policy[IPSET_ATTR_ADT_MAX + 1];
|
||||
|
||||
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
|
||||
struct module *me;
|
||||
};
|
||||
|
||||
/* register and unregister set type */
|
||||
extern int ip_set_type_register(struct ip_set_type *set_type);
|
||||
extern void ip_set_type_unregister(struct ip_set_type *set_type);
|
||||
|
||||
/* A generic IP set */
|
||||
struct ip_set {
|
||||
/* The name of the set */
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
/* Lock protecting the set data */
|
||||
rwlock_t lock;
|
||||
/* References to the set */
|
||||
u32 ref;
|
||||
/* The core set type */
|
||||
struct ip_set_type *type;
|
||||
/* The type variant doing the real job */
|
||||
const struct ip_set_type_variant *variant;
|
||||
/* The actual INET family of the set */
|
||||
u8 family;
|
||||
/* The type revision */
|
||||
u8 revision;
|
||||
/* The type specific data */
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* register and unregister set references */
|
||||
extern ip_set_id_t ip_set_get_byname(const char *name, struct ip_set **set);
|
||||
extern void ip_set_put_byindex(ip_set_id_t index);
|
||||
extern const char *ip_set_name_byindex(ip_set_id_t index);
|
||||
extern ip_set_id_t ip_set_nfnl_get(const char *name);
|
||||
extern ip_set_id_t ip_set_nfnl_get_byindex(ip_set_id_t index);
|
||||
extern void ip_set_nfnl_put(ip_set_id_t index);
|
||||
|
||||
/* API for iptables set match, and SET target */
|
||||
|
||||
extern int ip_set_add(ip_set_id_t id, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
extern int ip_set_del(ip_set_id_t id, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
extern int ip_set_test(ip_set_id_t id, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt);
|
||||
|
||||
/* Utility functions */
|
||||
extern void *ip_set_alloc(size_t size);
|
||||
extern void ip_set_free(void *members);
|
||||
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
|
||||
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
|
||||
|
||||
static inline int
|
||||
ip_set_get_hostipaddr4(struct nlattr *nla, u32 *ipaddr)
|
||||
{
|
||||
__be32 ip;
|
||||
int ret = ip_set_get_ipaddr4(nla, &ip);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
*ipaddr = ntohl(ip);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ignore IPSET_ERR_EXIST errors if asked to do so? */
|
||||
static inline bool
|
||||
ip_set_eexist(int ret, u32 flags)
|
||||
{
|
||||
return ret == -IPSET_ERR_EXIST && (flags & IPSET_FLAG_EXIST);
|
||||
}
|
||||
|
||||
/* Check the NLA_F_NET_BYTEORDER flag */
|
||||
static inline bool
|
||||
ip_set_attr_netorder(struct nlattr *tb[], int type)
|
||||
{
|
||||
return tb[type] && (tb[type]->nla_type & NLA_F_NET_BYTEORDER);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_optattr_netorder(struct nlattr *tb[], int type)
|
||||
{
|
||||
return !tb[type] || (tb[type]->nla_type & NLA_F_NET_BYTEORDER);
|
||||
}
|
||||
|
||||
/* Useful converters */
|
||||
static inline u32
|
||||
ip_set_get_h32(const struct nlattr *attr)
|
||||
{
|
||||
return ntohl(nla_get_be32(attr));
|
||||
}
|
||||
|
||||
static inline u16
|
||||
ip_set_get_h16(const struct nlattr *attr)
|
||||
{
|
||||
return ntohs(nla_get_be16(attr));
|
||||
}
|
||||
|
||||
#define ipset_nest_start(skb, attr) nla_nest_start(skb, attr | NLA_F_NESTED)
|
||||
#define ipset_nest_end(skb, start) nla_nest_end(skb, start)
|
||||
|
||||
#ifndef NLA_PUT_NET16
|
||||
#define NLA_PUT_NET16(skb, attrtype, value) \
|
||||
NLA_PUT_BE16(skb, attrtype | NLA_F_NET_BYTEORDER, value)
|
||||
#endif
|
||||
#ifndef NLA_PUT_NET32
|
||||
#define NLA_PUT_NET32(skb, attrtype, value) \
|
||||
NLA_PUT_BE32(skb, attrtype | NLA_F_NET_BYTEORDER, value)
|
||||
#endif
|
||||
#ifndef NLA_PUT_NET64
|
||||
#define NLA_PUT_NET64(skb, attrtype, value) \
|
||||
NLA_PUT_BE64(skb, attrtype | NLA_F_NET_BYTEORDER, value)
|
||||
#endif
|
||||
|
||||
#define NLA_PUT_IPADDR4(skb, type, ipaddr) \
|
||||
do { \
|
||||
struct nlattr *__nested = ipset_nest_start(skb, type); \
|
||||
\
|
||||
if (!__nested) \
|
||||
goto nla_put_failure; \
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_IPADDR_IPV4, ipaddr); \
|
||||
ipset_nest_end(skb, __nested); \
|
||||
} while (0)
|
||||
|
||||
#define NLA_PUT_IPADDR6(skb, type, ipaddrptr) \
|
||||
do { \
|
||||
struct nlattr *__nested = ipset_nest_start(skb, type); \
|
||||
\
|
||||
if (!__nested) \
|
||||
goto nla_put_failure; \
|
||||
NLA_PUT(skb, IPSET_ATTR_IPADDR_IPV6, \
|
||||
sizeof(struct in6_addr), ipaddrptr); \
|
||||
ipset_nest_end(skb, __nested); \
|
||||
} while (0)
|
||||
|
||||
/* Get address from skbuff */
|
||||
static inline __be32
|
||||
ip4addr(const struct sk_buff *skb, bool src)
|
||||
{
|
||||
return src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip4addrptr(const struct sk_buff *skb, bool src, __be32 *addr)
|
||||
{
|
||||
*addr = src ? ip_hdr(skb)->saddr : ip_hdr(skb)->daddr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip6addrptr(const struct sk_buff *skb, bool src, struct in6_addr *addr)
|
||||
{
|
||||
memcpy(addr, src ? &ipv6_hdr(skb)->saddr : &ipv6_hdr(skb)->daddr,
|
||||
sizeof(*addr));
|
||||
}
|
||||
|
||||
/* Calculate the bytes required to store the inclusive range of a-b */
|
||||
static inline int
|
||||
bitmap_bytes(u32 a, u32 b)
|
||||
{
|
||||
return 4 * ((((b - a + 8) / 8) + 3) / 4);
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/* Interface to iptables/ip6tables */
|
||||
|
||||
#define SO_IP_SET 83
|
||||
|
||||
union ip_set_name_index {
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
ip_set_id_t index;
|
||||
};
|
||||
|
||||
#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
|
||||
struct ip_set_req_get_set {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
union ip_set_name_index set;
|
||||
};
|
||||
|
||||
#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
|
||||
/* Uses ip_set_req_get_set */
|
||||
|
||||
#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
|
||||
struct ip_set_req_version {
|
||||
unsigned op;
|
||||
unsigned version;
|
||||
};
|
||||
|
||||
#endif /*_IP_SET_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +0,0 @@
|
||||
#ifndef __IP_SET_BITMAP_H
|
||||
#define __IP_SET_BITMAP_H
|
||||
|
||||
/* Bitmap type specific error codes */
|
||||
enum {
|
||||
/* The element is out of the range of the set */
|
||||
IPSET_ERR_BITMAP_RANGE = IPSET_ERR_TYPE_SPECIFIC,
|
||||
/* The range exceeds the size limit of the set type */
|
||||
IPSET_ERR_BITMAP_RANGE_SIZE,
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define IPSET_BITMAP_MAX_RANGE 0x0000FFFF
|
||||
|
||||
/* Common functions */
|
||||
|
||||
static inline u32
|
||||
range_to_mask(u32 from, u32 to, u8 *bits)
|
||||
{
|
||||
u32 mask = 0xFFFFFFFE;
|
||||
|
||||
*bits = 32;
|
||||
while (--(*bits) > 0 && mask && (to & mask) != from)
|
||||
mask <<= 1;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __IP_SET_BITMAP_H */
|
||||
@@ -1,587 +0,0 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* 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:ip type */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.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 <net/tcp.h>
|
||||
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_bitmap.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:ip type of IP sets");
|
||||
MODULE_ALIAS("ip_set_bitmap:ip");
|
||||
|
||||
/* Type structure */
|
||||
struct bitmap_ip {
|
||||
void *members; /* the set members */
|
||||
u32 first_ip; /* host byte order, included in range */
|
||||
u32 last_ip; /* host byte order, included in range */
|
||||
u32 elements; /* number of max elements in the set */
|
||||
u32 hosts; /* number of hosts in a subnet */
|
||||
size_t memsize; /* members size */
|
||||
u8 netmask; /* subnet netmask */
|
||||
u32 timeout; /* timeout parameter */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
};
|
||||
|
||||
/* Base variant */
|
||||
|
||||
static inline u32
|
||||
ip_to_id(const struct bitmap_ip *m, u32 ip)
|
||||
{
|
||||
return ((ip & ip_set_hostmask(m->netmask)) - m->first_ip)/m->hosts;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
return !!test_bit(id, map->members);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (test_and_set_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (!test_and_clear_bit(id, map->members))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
struct nlattr *atd, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->elements; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!test_bit(id, map->members))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id * map->hosts));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, atd);
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, atd);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Timeout variant */
|
||||
|
||||
static int
|
||||
bitmap_ip_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
const unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
return ip_set_timeout_test(members[id]);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
|
||||
if (ip_set_timeout_test(members[id]) && !(flags & IPSET_FLAG_EXIST))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
members[id] = ip_set_timeout_set(timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
unsigned long *members = map->members;
|
||||
u16 id = *(u16 *)value;
|
||||
int ret = -IPSET_ERR_EXIST;
|
||||
|
||||
if (ip_set_timeout_test(members[id]))
|
||||
ret = 0;
|
||||
|
||||
members[id] = IPSET_ELEM_UNSET;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_tlist(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ip *map = set->data;
|
||||
struct nlattr *adt, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
const unsigned long *members = map->members;
|
||||
|
||||
adt = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!adt)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->elements; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
if (!ip_set_timeout_test(members[id]))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (id == first) {
|
||||
nla_nest_cancel(skb, adt);
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP,
|
||||
htonl(map->first_ip + id * map->hosts));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(members[id])));
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
ipset_nest_end(skb, adt);
|
||||
|
||||
/* Set listing finished */
|
||||
cb->args[2] = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
nla_nest_cancel(skb, nested);
|
||||
ipset_nest_end(skb, adt);
|
||||
if (unlikely(id == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 ip;
|
||||
|
||||
ip = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
ip = ip_to_id(map, ip);
|
||||
|
||||
return adtfn(set, &ip, opt_timeout(opt, map), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 timeout = map->timeout;
|
||||
u32 ip, ip_to, id;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ip < map->first_ip || ip > map->last_ip)
|
||||
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 = ip_to_id(map, ip);
|
||||
return adtfn(set, &id, timeout, flags);
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
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_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
if (ip_to > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
for (; !before(ip_to, ip); ip += map->hosts) {
|
||||
id = ip_to_id(map, ip);
|
||||
ret = adtfn(set, &id, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_ip_destroy(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
|
||||
if (with_timeout(map->timeout))
|
||||
del_timer_sync(&map->gc);
|
||||
|
||||
ip_set_free(map->members);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_ip_flush(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
|
||||
memset(map->members, 0, map->memsize);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct bitmap_ip *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_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_ip_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
{
|
||||
const struct bitmap_ip *x = a->data;
|
||||
const struct bitmap_ip *y = b->data;
|
||||
|
||||
return x->first_ip == y->first_ip &&
|
||||
x->last_ip == y->last_ip &&
|
||||
x->netmask == y->netmask &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
static const struct ip_set_type_variant bitmap_ip = {
|
||||
.kadt = bitmap_ip_kadt,
|
||||
.uadt = bitmap_ip_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_ip_add,
|
||||
[IPSET_DEL] = bitmap_ip_del,
|
||||
[IPSET_TEST] = bitmap_ip_test,
|
||||
},
|
||||
.destroy = bitmap_ip_destroy,
|
||||
.flush = bitmap_ip_flush,
|
||||
.head = bitmap_ip_head,
|
||||
.list = bitmap_ip_list,
|
||||
.same_set = bitmap_ip_same_set,
|
||||
};
|
||||
|
||||
static const struct ip_set_type_variant bitmap_tip = {
|
||||
.kadt = bitmap_ip_kadt,
|
||||
.uadt = bitmap_ip_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_ip_tadd,
|
||||
[IPSET_DEL] = bitmap_ip_tdel,
|
||||
[IPSET_TEST] = bitmap_ip_ttest,
|
||||
},
|
||||
.destroy = bitmap_ip_destroy,
|
||||
.flush = bitmap_ip_flush,
|
||||
.head = bitmap_ip_head,
|
||||
.list = bitmap_ip_tlist,
|
||||
.same_set = bitmap_ip_same_set,
|
||||
};
|
||||
|
||||
static void
|
||||
bitmap_ip_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct bitmap_ip *map = set->data;
|
||||
unsigned long *table = map->members;
|
||||
u32 id;
|
||||
|
||||
/* 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 < map->elements; 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_ip_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = bitmap_ip_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_ip(struct ip_set *set, struct bitmap_ip *map,
|
||||
u32 first_ip, u32 last_ip,
|
||||
u32 elements, u32 hosts, u8 netmask)
|
||||
{
|
||||
map->members = ip_set_alloc(map->memsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
map->first_ip = first_ip;
|
||||
map->last_ip = last_ip;
|
||||
map->elements = elements;
|
||||
map->hosts = hosts;
|
||||
map->netmask = netmask;
|
||||
map->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
set->data = map;
|
||||
set->family = NFPROTO_IPV4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct bitmap_ip *map;
|
||||
u32 first_ip, last_ip, hosts, elements;
|
||||
u8 netmask = 32;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (first_ip > last_ip) {
|
||||
u32 tmp = first_ip;
|
||||
|
||||
first_ip = last_ip;
|
||||
last_ip = tmp;
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip_set_mask_from_to(first_ip, last_ip, cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_NETMASK]) {
|
||||
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
|
||||
|
||||
if (netmask > 32)
|
||||
return -IPSET_ERR_INVALID_NETMASK;
|
||||
|
||||
first_ip &= ip_set_hostmask(netmask);
|
||||
last_ip |= ~ip_set_hostmask(netmask);
|
||||
}
|
||||
|
||||
if (netmask == 32) {
|
||||
hosts = 1;
|
||||
elements = last_ip - first_ip + 1;
|
||||
} else {
|
||||
u8 mask_bits;
|
||||
u32 mask;
|
||||
|
||||
mask = range_to_mask(first_ip, last_ip, &mask_bits);
|
||||
|
||||
if ((!mask && (first_ip || last_ip != 0xFFFFFFFF)) ||
|
||||
netmask <= mask_bits)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
pr_debug("mask_bits %u, netmask %u\n", mask_bits, netmask);
|
||||
hosts = 2 << (32 - netmask - 1);
|
||||
elements = 2 << (netmask - mask_bits - 1);
|
||||
}
|
||||
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
|
||||
return -IPSET_ERR_BITMAP_RANGE_SIZE;
|
||||
|
||||
pr_debug("hosts %u, elements %u\n", hosts, elements);
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->memsize = elements * sizeof(unsigned long);
|
||||
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
set->variant = &bitmap_tip;
|
||||
|
||||
bitmap_ip_gc_init(set);
|
||||
} else {
|
||||
map->memsize = bitmap_bytes(0, elements - 1);
|
||||
|
||||
if (!init_map_ip(set, map, first_ip, last_ip,
|
||||
elements, hosts, netmask)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
set->variant = &bitmap_ip;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type bitmap_ip_type __read_mostly = {
|
||||
.name = "bitmap:ip",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
bitmap_ip_init(void)
|
||||
{
|
||||
return ip_set_type_register(&bitmap_ip_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
bitmap_ip_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&bitmap_ip_type);
|
||||
}
|
||||
|
||||
module_init(bitmap_ip_init);
|
||||
module_exit(bitmap_ip_fini);
|
||||
@@ -1,659 +0,0 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* 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:ip,mac type */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/timer.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_bitmap.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("bitmap:ip,mac type of IP sets");
|
||||
MODULE_ALIAS("ip_set_bitmap:ip,mac");
|
||||
|
||||
enum {
|
||||
MAC_EMPTY, /* element is not set */
|
||||
MAC_FILLED, /* element is set with MAC */
|
||||
MAC_UNSET, /* element is set, without MAC */
|
||||
};
|
||||
|
||||
/* Type structure */
|
||||
struct bitmap_ipmac {
|
||||
void *members; /* the set members */
|
||||
u32 first_ip; /* host byte order, included in range */
|
||||
u32 last_ip; /* host byte order, included in range */
|
||||
u32 timeout; /* timeout value */
|
||||
struct timer_list gc; /* garbage collector */
|
||||
size_t dsize; /* size of element */
|
||||
};
|
||||
|
||||
/* ADT structure for generic function args */
|
||||
struct ipmac {
|
||||
u32 id; /* id in array */
|
||||
unsigned char *ether; /* ethernet address */
|
||||
};
|
||||
|
||||
/* Member element without and with timeout */
|
||||
|
||||
struct ipmac_elem {
|
||||
unsigned char ether[ETH_ALEN];
|
||||
unsigned char match;
|
||||
} __attribute__ ((aligned));
|
||||
|
||||
struct ipmac_telem {
|
||||
unsigned char ether[ETH_ALEN];
|
||||
unsigned char match;
|
||||
unsigned long timeout;
|
||||
} __attribute__ ((aligned));
|
||||
|
||||
static inline void *
|
||||
bitmap_ipmac_elem(const struct bitmap_ipmac *map, u32 id)
|
||||
{
|
||||
return (void *)((char *)map->members + id * map->dsize);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmap_timeout(const struct bitmap_ipmac *map, u32 id)
|
||||
{
|
||||
const struct ipmac_telem *elem = bitmap_ipmac_elem(map, id);
|
||||
|
||||
return ip_set_timeout_test(elem->timeout);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
bitmap_expired(const struct bitmap_ipmac *map, u32 id)
|
||||
{
|
||||
const struct ipmac_telem *elem = bitmap_ipmac_elem(map, id);
|
||||
|
||||
return ip_set_timeout_expired(elem->timeout);
|
||||
}
|
||||
|
||||
static inline int
|
||||
bitmap_ipmac_exist(const struct ipmac_telem *elem)
|
||||
{
|
||||
return elem->match == MAC_UNSET ||
|
||||
(elem->match == MAC_FILLED &&
|
||||
!ip_set_timeout_expired(elem->timeout));
|
||||
}
|
||||
|
||||
/* Base variant */
|
||||
|
||||
static int
|
||||
bitmap_ipmac_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
|
||||
|
||||
switch (elem->match) {
|
||||
case MAC_UNSET:
|
||||
/* Trigger kernel to fill out the ethernet address */
|
||||
return -EAGAIN;
|
||||
case MAC_FILLED:
|
||||
return data->ether == NULL ||
|
||||
compare_ether_addr(data->ether, elem->ether) == 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
|
||||
|
||||
switch (elem->match) {
|
||||
case MAC_UNSET:
|
||||
if (!data->ether)
|
||||
/* Already added without ethernet address */
|
||||
return -IPSET_ERR_EXIST;
|
||||
/* Fill the MAC address */
|
||||
memcpy(elem->ether, data->ether, ETH_ALEN);
|
||||
elem->match = MAC_FILLED;
|
||||
break;
|
||||
case MAC_FILLED:
|
||||
return -IPSET_ERR_EXIST;
|
||||
case MAC_EMPTY:
|
||||
if (data->ether) {
|
||||
memcpy(elem->ether, data->ether, ETH_ALEN);
|
||||
elem->match = MAC_FILLED;
|
||||
} else
|
||||
elem->match = MAC_UNSET;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
|
||||
|
||||
if (elem->match == MAC_EMPTY)
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
elem->match = MAC_EMPTY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac_elem *elem;
|
||||
struct nlattr *atd, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
u32 last = map->last_ip - map->first_ip;
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
elem = bitmap_ipmac_elem(map, id);
|
||||
if (elem->match == MAC_EMPTY)
|
||||
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));
|
||||
if (elem->match == MAC_FILLED)
|
||||
NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
|
||||
elem->ether);
|
||||
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_ipmac_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
const struct ipmac_elem *elem = bitmap_ipmac_elem(map, data->id);
|
||||
|
||||
switch (elem->match) {
|
||||
case MAC_UNSET:
|
||||
/* Trigger kernel to fill out the ethernet address */
|
||||
return -EAGAIN;
|
||||
case MAC_FILLED:
|
||||
return (data->ether == NULL ||
|
||||
compare_ether_addr(data->ether, elem->ether) == 0) &&
|
||||
!bitmap_expired(map, data->id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
|
||||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
|
||||
switch (elem->match) {
|
||||
case MAC_UNSET:
|
||||
if (!(data->ether || flag_exist))
|
||||
/* Already added without ethernet address */
|
||||
return -IPSET_ERR_EXIST;
|
||||
/* Fill the MAC address and activate the timer */
|
||||
memcpy(elem->ether, data->ether, ETH_ALEN);
|
||||
elem->match = MAC_FILLED;
|
||||
if (timeout == map->timeout)
|
||||
/* Timeout was not specified, get stored one */
|
||||
timeout = elem->timeout;
|
||||
elem->timeout = ip_set_timeout_set(timeout);
|
||||
break;
|
||||
case MAC_FILLED:
|
||||
if (!(bitmap_expired(map, data->id) || flag_exist))
|
||||
return -IPSET_ERR_EXIST;
|
||||
/* Fall through */
|
||||
case MAC_EMPTY:
|
||||
if (data->ether) {
|
||||
memcpy(elem->ether, data->ether, ETH_ALEN);
|
||||
elem->match = MAC_FILLED;
|
||||
} else
|
||||
elem->match = MAC_UNSET;
|
||||
/* If MAC is unset yet, we store plain timeout value
|
||||
* because the timer is not activated yet
|
||||
* and we can reuse it later when MAC is filled out,
|
||||
* possibly by the kernel */
|
||||
elem->timeout = data->ether ? ip_set_timeout_set(timeout)
|
||||
: timeout;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac *data = value;
|
||||
struct ipmac_telem *elem = bitmap_ipmac_elem(map, data->id);
|
||||
|
||||
if (elem->match == MAC_EMPTY || bitmap_expired(map, data->id))
|
||||
return -IPSET_ERR_EXIST;
|
||||
|
||||
elem->match = MAC_EMPTY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_tlist(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
const struct ipmac_telem *elem;
|
||||
struct nlattr *atd, *nested;
|
||||
u32 id, first = cb->args[2];
|
||||
u32 timeout, last = map->last_ip - map->first_ip;
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] <= last; cb->args[2]++) {
|
||||
id = cb->args[2];
|
||||
elem = bitmap_ipmac_elem(map, id);
|
||||
if (!bitmap_ipmac_exist(elem))
|
||||
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));
|
||||
if (elem->match == MAC_FILLED)
|
||||
NLA_PUT(skb, IPSET_ATTR_ETHER, ETH_ALEN,
|
||||
elem->ether);
|
||||
timeout = elem->match == MAC_UNSET ? elem->timeout
|
||||
: ip_set_timeout_get(elem->timeout);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(timeout));
|
||||
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 -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct ipmac data;
|
||||
|
||||
/* MAC can be src only */
|
||||
if (!(opt->flags & IPSET_DIM_TWO_SRC))
|
||||
return 0;
|
||||
|
||||
data.id = ntohl(ip4addr(skb, opt->flags & IPSET_DIM_ONE_SRC));
|
||||
if (data.id < map->first_ip || data.id > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
/* Backward compatibility: we don't check the second flag */
|
||||
if (skb_mac_header(skb) < skb->head ||
|
||||
(skb_mac_header(skb) + ETH_HLEN) > skb->data)
|
||||
return -EINVAL;
|
||||
|
||||
data.id -= map->first_ip;
|
||||
data.ether = eth_hdr(skb)->h_source;
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, map), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct ipmac data;
|
||||
u32 timeout = map->timeout;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &data.id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (data.id < map->first_ip || data.id > map->last_ip)
|
||||
return -IPSET_ERR_BITMAP_RANGE;
|
||||
|
||||
if (tb[IPSET_ATTR_ETHER])
|
||||
data.ether = nla_data(tb[IPSET_ATTR_ETHER]);
|
||||
else
|
||||
data.ether = NULL;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(map->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
data.id -= map->first_ip;
|
||||
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_ipmac_destroy(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ipmac *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_ipmac_flush(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
|
||||
memset(map->members, 0,
|
||||
(map->last_ip - map->first_ip + 1) * map->dsize);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct bitmap_ipmac *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));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map)
|
||||
+ (map->last_ip - map->first_ip + 1) * map->dsize));
|
||||
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_ipmac_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
{
|
||||
const struct bitmap_ipmac *x = a->data;
|
||||
const struct bitmap_ipmac *y = b->data;
|
||||
|
||||
return x->first_ip == y->first_ip &&
|
||||
x->last_ip == y->last_ip &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
static const struct ip_set_type_variant bitmap_ipmac = {
|
||||
.kadt = bitmap_ipmac_kadt,
|
||||
.uadt = bitmap_ipmac_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_ipmac_add,
|
||||
[IPSET_DEL] = bitmap_ipmac_del,
|
||||
[IPSET_TEST] = bitmap_ipmac_test,
|
||||
},
|
||||
.destroy = bitmap_ipmac_destroy,
|
||||
.flush = bitmap_ipmac_flush,
|
||||
.head = bitmap_ipmac_head,
|
||||
.list = bitmap_ipmac_list,
|
||||
.same_set = bitmap_ipmac_same_set,
|
||||
};
|
||||
|
||||
static const struct ip_set_type_variant bitmap_tipmac = {
|
||||
.kadt = bitmap_ipmac_kadt,
|
||||
.uadt = bitmap_ipmac_uadt,
|
||||
.adt = {
|
||||
[IPSET_ADD] = bitmap_ipmac_tadd,
|
||||
[IPSET_DEL] = bitmap_ipmac_tdel,
|
||||
[IPSET_TEST] = bitmap_ipmac_ttest,
|
||||
},
|
||||
.destroy = bitmap_ipmac_destroy,
|
||||
.flush = bitmap_ipmac_flush,
|
||||
.head = bitmap_ipmac_head,
|
||||
.list = bitmap_ipmac_tlist,
|
||||
.same_set = bitmap_ipmac_same_set,
|
||||
};
|
||||
|
||||
static void
|
||||
bitmap_ipmac_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
struct ipmac_telem *elem;
|
||||
u32 id, last = map->last_ip - map->first_ip;
|
||||
|
||||
/* 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++) {
|
||||
elem = bitmap_ipmac_elem(map, id);
|
||||
if (elem->match == MAC_FILLED &&
|
||||
ip_set_timeout_expired(elem->timeout))
|
||||
elem->match = MAC_EMPTY;
|
||||
}
|
||||
read_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static void
|
||||
bitmap_ipmac_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct bitmap_ipmac *map = set->data;
|
||||
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = bitmap_ipmac_gc;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
/* Create bitmap:ip,mac type of sets */
|
||||
|
||||
static bool
|
||||
init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
|
||||
u32 first_ip, u32 last_ip)
|
||||
{
|
||||
map->members = ip_set_alloc((last_ip - first_ip + 1) * map->dsize);
|
||||
if (!map->members)
|
||||
return false;
|
||||
map->first_ip = first_ip;
|
||||
map->last_ip = last_ip;
|
||||
map->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
set->data = map;
|
||||
set->family = NFPROTO_IPV4;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
|
||||
u32 flags)
|
||||
{
|
||||
u32 first_ip, last_ip, elements;
|
||||
struct bitmap_ipmac *map;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &first_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &last_ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (first_ip > last_ip) {
|
||||
u32 tmp = first_ip;
|
||||
|
||||
first_ip = last_ip;
|
||||
last_ip = tmp;
|
||||
}
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip_set_mask_from_to(first_ip, last_ip, cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
elements = last_ip - first_ip + 1;
|
||||
|
||||
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
|
||||
return -IPSET_ERR_BITMAP_RANGE_SIZE;
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
map->dsize = sizeof(struct ipmac_telem);
|
||||
|
||||
if (!init_map_ipmac(set, map, first_ip, last_ip)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
map->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = &bitmap_tipmac;
|
||||
|
||||
bitmap_ipmac_gc_init(set);
|
||||
} else {
|
||||
map->dsize = sizeof(struct ipmac_elem);
|
||||
|
||||
if (!init_map_ipmac(set, map, first_ip, last_ip)) {
|
||||
kfree(map);
|
||||
return -ENOMEM;
|
||||
}
|
||||
set->variant = &bitmap_ipmac;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type bitmap_ipmac_type = {
|
||||
.name = "bitmap:ip,mac",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_ipmac_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY,
|
||||
.len = ETH_ALEN },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
bitmap_ipmac_init(void)
|
||||
{
|
||||
return ip_set_type_register(&bitmap_ipmac_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
bitmap_ipmac_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&bitmap_ipmac_type);
|
||||
}
|
||||
|
||||
module_init(bitmap_ipmac_init);
|
||||
module_exit(bitmap_ipmac_fini);
|
||||
@@ -1,517 +0,0 @@
|
||||
/* 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,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
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, opt->family,
|
||||
opt->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, opt_timeout(opt, map), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
bitmap_port_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
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 = NFPROTO_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 = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
.revision_max = 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
@@ -1,161 +0,0 @@
|
||||
/* 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/version.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;
|
||||
__be16 frag_off;
|
||||
|
||||
nexthdr = ipv6_hdr(skb)->nexthdr;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 2, 0)
|
||||
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr);
|
||||
#else
|
||||
protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr, &frag_off);
|
||||
#endif
|
||||
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 NFPROTO_IPV4:
|
||||
ret = ip_set_get_ip4_port(skb, src, port, &proto);
|
||||
break;
|
||||
case NFPROTO_IPV6:
|
||||
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);
|
||||
@@ -1,33 +0,0 @@
|
||||
#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,30 +0,0 @@
|
||||
#ifndef __IP_SET_HASH_H
|
||||
#define __IP_SET_HASH_H
|
||||
|
||||
/* Hash type specific error codes */
|
||||
enum {
|
||||
/* Hash is full */
|
||||
IPSET_ERR_HASH_FULL = IPSET_ERR_TYPE_SPECIFIC,
|
||||
/* Null-valued element */
|
||||
IPSET_ERR_HASH_ELEM,
|
||||
/* Invalid protocol */
|
||||
IPSET_ERR_INVALID_PROTO,
|
||||
/* Protocol missing but must be specified */
|
||||
IPSET_ERR_MISSING_PROTO,
|
||||
/* Range not supported */
|
||||
IPSET_ERR_HASH_RANGE_UNSUPPORTED,
|
||||
/* Invalid range */
|
||||
IPSET_ERR_HASH_RANGE,
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define IPSET_DEFAULT_HASHSIZE 1024
|
||||
#define IPSET_MIMINAL_HASHSIZE 64
|
||||
#define IPSET_DEFAULT_MAXELEM 65536
|
||||
#define IPSET_DEFAULT_PROBES 4
|
||||
#define IPSET_DEFAULT_RESIZE 100
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __IP_SET_HASH_H */
|
||||
@@ -1,481 +0,0 @@
|
||||
/* 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 hash:ip type */
|
||||
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_hash.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("hash:ip type of IP sets");
|
||||
MODULE_ALIAS("ip_set_hash:ip");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define TYPE hash_ip
|
||||
|
||||
static bool
|
||||
hash_ip_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
#define hash_ip4_same_set hash_ip_same_set
|
||||
#define hash_ip6_same_set hash_ip_same_set
|
||||
|
||||
/* The type variant functions: IPv4 */
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ip4_elem {
|
||||
__be32 ip;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ip4_telem {
|
||||
__be32 ip;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
|
||||
const struct hash_ip4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ip4_data_isnull(const struct hash_ip4_elem *elem)
|
||||
{
|
||||
return elem->ip == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ip4_data_copy(struct hash_ip4_elem *dst, const struct hash_ip4_elem *src)
|
||||
{
|
||||
dst->ip = src->ip;
|
||||
}
|
||||
|
||||
/* Zero valued IP addresses cannot be stored */
|
||||
static inline void
|
||||
hash_ip4_data_zero_out(struct hash_ip4_elem *elem)
|
||||
{
|
||||
elem->ip = 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ip4_data_list(struct sk_buff *skb, const struct hash_ip4_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
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 *)data;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(tdata->timeout)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define IP_SET_HASH_WITH_NETMASK
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ip4_data_next(struct ip_set_hash *h, const struct hash_ip4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
__be32 ip;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip);
|
||||
ip &= ip_set_netmask(h->netmask);
|
||||
if (ip == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
u32 ip, ip_to, hosts, timeout = h->timeout;
|
||||
__be32 nip;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ip &= ip_set_hostmask(h->netmask);
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST) {
|
||||
nip = htonl(ip);
|
||||
if (nip == 0)
|
||||
return -IPSET_ERR_HASH_ELEM;
|
||||
return adtfn(set, &nip, timeout, flags);
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
hosts = h->netmask == 32 ? 1 : 2 << (32 - h->netmask - 1);
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip += hosts) {
|
||||
nip = htonl(ip);
|
||||
if (nip == 0)
|
||||
return -IPSET_ERR_HASH_ELEM;
|
||||
ret = adtfn(set, &nip, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ip_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 *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout &&
|
||||
x->netmask == y->netmask;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_ip6_elem {
|
||||
union nf_inet_addr ip;
|
||||
};
|
||||
|
||||
struct hash_ip6_telem {
|
||||
union nf_inet_addr ip;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
|
||||
const struct hash_ip6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ip6_data_isnull(const struct hash_ip6_elem *elem)
|
||||
{
|
||||
return ipv6_addr_any(&elem->ip.in6);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ip6_data_copy(struct hash_ip6_elem *dst, const struct hash_ip6_elem *src)
|
||||
{
|
||||
dst->ip.in6 = src->ip.in6;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ip6_data_zero_out(struct hash_ip6_elem *elem)
|
||||
{
|
||||
ipv6_addr_set(&elem->ip.in6, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ip6_data_list(struct sk_buff *skb, const struct hash_ip6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
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 *)data;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(e->timeout)));
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ip6_data_next(struct ip_set_hash *h, const struct hash_ip6_elem *d)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
union nf_inet_addr ip;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &ip.in6);
|
||||
ip6_netmask(&ip, h->netmask);
|
||||
if (ipv6_addr_any(&ip.in6))
|
||||
return -EINVAL;
|
||||
|
||||
return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int
|
||||
hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
union nf_inet_addr ip;
|
||||
u32 timeout = h->timeout;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ip6_netmask(&ip, h->netmask);
|
||||
if (ipv6_addr_any(&ip.in6))
|
||||
return -IPSET_ERR_HASH_ELEM;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
ret = adtfn(set, &ip, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static int
|
||||
hash_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 netmask, hbits;
|
||||
struct ip_set_hash *h;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
netmask = set->family == NFPROTO_IPV4 ? 32 : 128;
|
||||
pr_debug("Create set %s with family %s\n",
|
||||
set->name, set->family == NFPROTO_IPV4 ? "inet" : "inet6");
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
|
||||
if (hashsize < IPSET_MIMINAL_HASHSIZE)
|
||||
hashsize = IPSET_MIMINAL_HASHSIZE;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_MAXELEM])
|
||||
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
|
||||
|
||||
if (tb[IPSET_ATTR_NETMASK]) {
|
||||
netmask = nla_get_u8(tb[IPSET_ATTR_NETMASK]);
|
||||
|
||||
if ((set->family == NFPROTO_IPV4 && netmask > 32) ||
|
||||
(set->family == NFPROTO_IPV6 && netmask > 128) ||
|
||||
netmask == 0)
|
||||
return -IPSET_ERR_INVALID_NETMASK;
|
||||
}
|
||||
|
||||
h = kzalloc(sizeof(*h), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->maxelem = maxelem;
|
||||
h->netmask = netmask;
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
|
||||
set->data = h;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ip4_tvariant : &hash_ip6_tvariant;
|
||||
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
hash_ip4_gc_init(set);
|
||||
else
|
||||
hash_ip6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ip4_variant : &hash_ip6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_ip_type __read_mostly = {
|
||||
.name = "hash:ip",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = hash_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_MAXELEM] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_PROBES] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_RESIZE] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_NETMASK] = { .type = NLA_U8 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_ip_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_ip_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_ip_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_ip_type);
|
||||
}
|
||||
|
||||
module_init(hash_ip_init);
|
||||
module_exit(hash_ip_fini);
|
||||
@@ -1,555 +0,0 @@
|
||||
/* 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 hash:ip,port type */
|
||||
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
#include "ip_set_hash.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("hash:ip,port type of IP sets");
|
||||
MODULE_ALIAS("ip_set_hash:ip,port");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define TYPE hash_ipport
|
||||
|
||||
static bool
|
||||
hash_ipport_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
#define hash_ipport4_same_set hash_ipport_same_set
|
||||
#define hash_ipport6_same_set hash_ipport_same_set
|
||||
|
||||
/* The type variant functions: IPv4 */
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ipport4_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ipport4_telem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
|
||||
const struct hash_ipport4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ipport4_data_isnull(const struct hash_ipport4_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport4_data_copy(struct hash_ipport4_elem *dst,
|
||||
const struct hash_ipport4_elem *src)
|
||||
{
|
||||
dst->ip = src->ip;
|
||||
dst->port = src->port;
|
||||
dst->proto = src->proto;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport4_data_zero_out(struct hash_ipport4_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipport4_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipport4_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipport4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipport4_elem *data)
|
||||
{
|
||||
const struct hash_ipport4_telem *tdata =
|
||||
(const struct hash_ipport4_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(tdata->timeout)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipport4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipport4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport4_elem data = { };
|
||||
u32 ip, ip_to = 0, p = 0, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||
tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip = ntohl(data.ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
port_to = port = ntohs(data.port);
|
||||
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip++) {
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipport_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 *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_ipport6_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
struct hash_ipport6_telem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
|
||||
const struct hash_ipport6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ipport6_data_isnull(const struct hash_ipport6_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport6_data_copy(struct hash_ipport6_elem *dst,
|
||||
const struct hash_ipport6_elem *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipport6_data_zero_out(struct hash_ipport6_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipport6_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipport6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipport6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipport6_elem *data)
|
||||
{
|
||||
const struct hash_ipport6_telem *e =
|
||||
(const struct hash_ipport6_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(e->timeout)));
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipport6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipport6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport6_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipport6_elem data = { };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
port = ntohs(data.port);
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static int
|
||||
hash_ipport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
|
||||
if (hashsize < IPSET_MIMINAL_HASHSIZE)
|
||||
hashsize = IPSET_MIMINAL_HASHSIZE;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_MAXELEM])
|
||||
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
|
||||
|
||||
h = kzalloc(sizeof(*h), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->maxelem = maxelem;
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
|
||||
set->data = h;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ipport4_tvariant : &hash_ipport6_tvariant;
|
||||
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
hash_ipport4_gc_init(set);
|
||||
else
|
||||
hash_ipport6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ipport4_variant : &hash_ipport6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_ipport_type __read_mostly = {
|
||||
.name = "hash:ip,port",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* SCTP and UDPLITE support added */
|
||||
.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,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_ipport_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_ipport_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_ipport_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_ipport_type);
|
||||
}
|
||||
|
||||
module_init(hash_ipport_init);
|
||||
module_exit(hash_ipport_fini);
|
||||
@@ -1,573 +0,0 @@
|
||||
/* 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 hash:ip,port,ip type */
|
||||
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
#include "ip_set_hash.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("hash:ip,port,ip type of IP sets");
|
||||
MODULE_ALIAS("ip_set_hash:ip,port,ip");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define TYPE hash_ipportip
|
||||
|
||||
static bool
|
||||
hash_ipportip_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
#define hash_ipportip4_same_set hash_ipportip_same_set
|
||||
#define hash_ipportip6_same_set hash_ipportip_same_set
|
||||
|
||||
/* The type variant functions: IPv4 */
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ipportip4_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ipportip4_telem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
|
||||
const struct hash_ipportip4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->ip2 == ip2->ip2 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ipportip4_data_isnull(const struct hash_ipportip4_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip4_data_copy(struct hash_ipportip4_elem *dst,
|
||||
const struct hash_ipportip4_elem *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip4_data_zero_out(struct hash_ipportip4_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportip4_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportip4_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportip4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportip4_elem *data)
|
||||
{
|
||||
const struct hash_ipportip4_telem *tdata =
|
||||
(const struct hash_ipportip4_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(tdata->timeout)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportip4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportip4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip4_elem data = { };
|
||||
u32 ip, ip_to = 0, p = 0, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||
tb[IPSET_ATTR_PORT_TO])) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip = ntohl(data.ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
port_to = port = ntohs(data.port);
|
||||
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip++) {
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportip_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 *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_ipportip6_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
};
|
||||
|
||||
struct hash_ipportip6_telem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 padding;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
|
||||
const struct hash_ipportip6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ipportip6_data_isnull(const struct hash_ipportip6_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip6_data_copy(struct hash_ipportip6_elem *dst,
|
||||
const struct hash_ipportip6_elem *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportip6_data_zero_out(struct hash_ipportip6_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportip6_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportip6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportip6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportip6_elem *data)
|
||||
{
|
||||
const struct hash_ipportip6_telem *e =
|
||||
(const struct hash_ipportip6_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(e->timeout)));
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportip6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportip6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip6_elem data = { };
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportip6_elem data = { };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
port = ntohs(data.port);
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static int
|
||||
hash_ipportip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
|
||||
if (hashsize < IPSET_MIMINAL_HASHSIZE)
|
||||
hashsize = IPSET_MIMINAL_HASHSIZE;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_MAXELEM])
|
||||
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
|
||||
|
||||
h = kzalloc(sizeof(*h), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->maxelem = maxelem;
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
|
||||
set->data = h;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ipportip4_tvariant : &hash_ipportip6_tvariant;
|
||||
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
hash_ipportip4_gc_init(set);
|
||||
else
|
||||
hash_ipportip6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ipportip4_variant : &hash_ipportip6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_ipportip_type __read_mostly = {
|
||||
.name = "hash:ip,port,ip",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* SCTP and UDPLITE support added */
|
||||
.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,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_ipportip_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_ipportip_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_ipportip_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_ipportip_type);
|
||||
}
|
||||
|
||||
module_init(hash_ipportip_init);
|
||||
module_exit(hash_ipportip_fini);
|
||||
@@ -1,665 +0,0 @@
|
||||
/* 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 hash:ip,port,net type */
|
||||
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
#include "ip_set_hash.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("hash:ip,port,net type of IP sets");
|
||||
MODULE_ALIAS("ip_set_hash:ip,port,net");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define TYPE hash_ipportnet
|
||||
|
||||
static bool
|
||||
hash_ipportnet_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
#define hash_ipportnet4_same_set hash_ipportnet_same_set
|
||||
#define hash_ipportnet6_same_set hash_ipportnet_same_set
|
||||
|
||||
/* The type variant functions: IPv4 */
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_ipportnet4_elem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_ipportnet4_telem {
|
||||
__be32 ip;
|
||||
__be32 ip2;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
|
||||
const struct hash_ipportnet4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->ip2 == ip2->ip2 &&
|
||||
ip1->cidr == ip2->cidr &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ipportnet4_data_isnull(const struct hash_ipportnet4_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet4_data_copy(struct hash_ipportnet4_elem *dst,
|
||||
const struct hash_ipportnet4_elem *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet4_data_netmask(struct hash_ipportnet4_elem *elem, u8 cidr)
|
||||
{
|
||||
elem->ip2 &= ip_set_netmask(cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet4_data_zero_out(struct hash_ipportnet4_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportnet4_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportnet4_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, data->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportnet4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportnet4_elem *data)
|
||||
{
|
||||
const struct hash_ipportnet4_telem *tdata =
|
||||
(const struct hash_ipportnet4_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP2, tdata->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(tdata->timeout)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define IP_SET_HASH_WITH_PROTO
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportnet4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportnet4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
h->next.ip2 = ntohl(d->ip2);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet4_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
data.ip2 &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet4_elem data = { .cidr = HOST_MASK };
|
||||
u32 ip, ip_to = 0, p = 0, port, port_to;
|
||||
u32 ip2_from = 0, ip2_to, ip2_last, ip2;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
|
||||
if (adt == IPSET_TEST ||
|
||||
!(tb[IPSET_ATTR_CIDR] || tb[IPSET_ATTR_IP_TO] || with_ports ||
|
||||
tb[IPSET_ATTR_IP2_TO])) {
|
||||
data.ip = htonl(ip);
|
||||
data.ip2 = htonl(ip2_from & ip_set_hostmask(data.cidr));
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip > ip_to)
|
||||
swap(ip, ip_to);
|
||||
} else if (tb[IPSET_ATTR_CIDR]) {
|
||||
u8 cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
}
|
||||
|
||||
port_to = port = ntohs(data.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 (tb[IPSET_ATTR_IP2_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2_TO], &ip2_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip2_from > ip2_to)
|
||||
swap(ip2_from, ip2_to);
|
||||
if (ip2_from + UINT_MAX == ip2_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
} else {
|
||||
ip_set_mask_from_to(ip2_from, ip2_to, data.cidr);
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
for (; !before(ip_to, ip); ip++) {
|
||||
data.ip = htonl(ip);
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.port = htons(p);
|
||||
ip2 = retried && ip == h->next.ip && p == h->next.port
|
||||
? h->next.ip2 : ip2_from;
|
||||
while (!after(ip2, ip2_to)) {
|
||||
data.ip2 = htonl(ip2);
|
||||
ip2_last = ip_set_range_to_cidr(ip2, ip2_to,
|
||||
&data.cidr);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip2 = ip2_last + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
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 *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_ipportnet6_elem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
};
|
||||
|
||||
struct hash_ipportnet6_telem {
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip2;
|
||||
__be16 port;
|
||||
u8 cidr;
|
||||
u8 proto;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
|
||||
const struct hash_ipportnet6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ipv6_addr_cmp(&ip1->ip2.in6, &ip2->ip2.in6) == 0 &&
|
||||
ip1->cidr == ip2->cidr &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_ipportnet6_data_isnull(const struct hash_ipportnet6_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet6_data_copy(struct hash_ipportnet6_elem *dst,
|
||||
const struct hash_ipportnet6_elem *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet6_data_zero_out(struct hash_ipportnet6_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_ipportnet6_data_netmask(struct hash_ipportnet6_elem *elem, u8 cidr)
|
||||
{
|
||||
ip6_netmask(&elem->ip2, cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportnet6_data_list(struct sk_buff *skb,
|
||||
const struct hash_ipportnet6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_ipportnet6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_ipportnet6_elem *data)
|
||||
{
|
||||
const struct hash_ipportnet6_telem *e =
|
||||
(const struct hash_ipportnet6_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP2, &data->ip2);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR2, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(e->timeout)));
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_ipportnet6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_ipportnet6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet6_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
ip6_netmask(&data.ip2, data.cidr);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_ipportnet6_elem data = { .cidr = HOST_MASK };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
tb[IPSET_ATTR_IP_TO] ||
|
||||
tb[IPSET_ATTR_CIDR]))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2])
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
ip6_netmask(&data.ip2, data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
port = ntohs(data.port);
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static int
|
||||
hash_ipportnet_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
|
||||
if (hashsize < IPSET_MIMINAL_HASHSIZE)
|
||||
hashsize = IPSET_MIMINAL_HASHSIZE;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_MAXELEM])
|
||||
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
|
||||
|
||||
h = kzalloc(sizeof(*h)
|
||||
+ sizeof(struct ip_set_hash_nets)
|
||||
* (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->maxelem = maxelem;
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
|
||||
set->data = h;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ipportnet4_tvariant
|
||||
: &hash_ipportnet6_tvariant;
|
||||
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
hash_ipportnet4_gc_init(set);
|
||||
else
|
||||
hash_ipportnet6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_ipportnet4_variant : &hash_ipportnet6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
||||
.name = "hash:ip,port,net",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
.revision_max = 2, /* Range as input support for IPv4 added */
|
||||
.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_IP2_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_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,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_ipportnet_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_ipportnet_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_ipportnet_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_ipportnet_type);
|
||||
}
|
||||
|
||||
module_init(hash_ipportnet_init);
|
||||
module_exit(hash_ipportnet_fini);
|
||||
@@ -1,508 +0,0 @@
|
||||
/* 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 hash:net type */
|
||||
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_hash.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("hash:net type of IP sets");
|
||||
MODULE_ALIAS("ip_set_hash:net");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define TYPE hash_net
|
||||
|
||||
static bool
|
||||
hash_net_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
#define hash_net4_same_set hash_net_same_set
|
||||
#define hash_net6_same_set hash_net_same_set
|
||||
|
||||
/* The type variant functions: IPv4 */
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_net4_elem {
|
||||
__be32 ip;
|
||||
u16 padding0;
|
||||
u8 padding1;
|
||||
u8 cidr;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_net4_telem {
|
||||
__be32 ip;
|
||||
u16 padding0;
|
||||
u8 padding1;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_net4_data_equal(const struct hash_net4_elem *ip1,
|
||||
const struct hash_net4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_net4_data_isnull(const struct hash_net4_elem *elem)
|
||||
{
|
||||
return elem->cidr == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net4_data_copy(struct hash_net4_elem *dst,
|
||||
const struct hash_net4_elem *src)
|
||||
{
|
||||
dst->ip = src->ip;
|
||||
dst->cidr = src->cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net4_data_netmask(struct hash_net4_elem *elem, u8 cidr)
|
||||
{
|
||||
elem->ip &= ip_set_netmask(cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
/* Zero CIDR values cannot be stored */
|
||||
static inline void
|
||||
hash_net4_data_zero_out(struct hash_net4_elem *elem)
|
||||
{
|
||||
elem->cidr = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_net4_data_list(struct sk_buff *skb, const struct hash_net4_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
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 *)data;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, tdata->cidr);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(tdata->timeout)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_net4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_net4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net4_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net4_elem data = { .cidr = HOST_MASK };
|
||||
u32 timeout = h->timeout;
|
||||
u32 ip = 0, ip_to, last;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
|
||||
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
ip_to = ip;
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip_to < ip)
|
||||
swap(ip, ip_to);
|
||||
if (ip + UINT_MAX == ip_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
}
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
while (!after(ip, ip_to)) {
|
||||
data.ip = htonl(ip);
|
||||
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip = last + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_net_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 *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_net6_elem {
|
||||
union nf_inet_addr ip;
|
||||
u16 padding0;
|
||||
u8 padding1;
|
||||
u8 cidr;
|
||||
};
|
||||
|
||||
struct hash_net6_telem {
|
||||
union nf_inet_addr ip;
|
||||
u16 padding0;
|
||||
u8 padding1;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_net6_data_equal(const struct hash_net6_elem *ip1,
|
||||
const struct hash_net6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->cidr == ip2->cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_net6_data_isnull(const struct hash_net6_elem *elem)
|
||||
{
|
||||
return elem->cidr == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net6_data_copy(struct hash_net6_elem *dst,
|
||||
const struct hash_net6_elem *src)
|
||||
{
|
||||
dst->ip.in6 = src->ip.in6;
|
||||
dst->cidr = src->cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net6_data_zero_out(struct hash_net6_elem *elem)
|
||||
{
|
||||
elem->cidr = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_net6_data_netmask(struct hash_net6_elem *elem, u8 cidr)
|
||||
{
|
||||
ip6_netmask(&elem->ip, cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_net6_data_list(struct sk_buff *skb, const struct hash_net6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
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 *)data;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, e->cidr);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(e->timeout)));
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_net6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_net6_elem *d)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net6_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_net6_elem data = { .cidr = HOST_MASK };
|
||||
u32 timeout = h->timeout;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static int
|
||||
hash_net_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
struct ip_set_hash *h;
|
||||
u8 hbits;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
|
||||
if (hashsize < IPSET_MIMINAL_HASHSIZE)
|
||||
hashsize = IPSET_MIMINAL_HASHSIZE;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_MAXELEM])
|
||||
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
|
||||
|
||||
h = kzalloc(sizeof(*h)
|
||||
+ sizeof(struct ip_set_hash_nets)
|
||||
* (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->maxelem = maxelem;
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
|
||||
set->data = h;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_net4_tvariant : &hash_net6_tvariant;
|
||||
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
hash_net4_gc_init(set);
|
||||
else
|
||||
hash_net6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_net4_variant : &hash_net6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_net_type __read_mostly = {
|
||||
.name = "hash:net",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* Range as input support for IPv4 added */
|
||||
.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_IP_TO] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_net_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_net_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_net_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_net_type);
|
||||
}
|
||||
|
||||
module_init(hash_net_init);
|
||||
module_exit(hash_net_fini);
|
||||
@@ -1,786 +0,0 @@
|
||||
/* Copyright (C) 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 hash:net,iface type */
|
||||
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_hash.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("hash:net,iface type of IP sets");
|
||||
MODULE_ALIAS("ip_set_hash:net,iface");
|
||||
|
||||
/* Interface name rbtree */
|
||||
|
||||
struct iface_node {
|
||||
struct rb_node node;
|
||||
char iface[IFNAMSIZ];
|
||||
};
|
||||
|
||||
#define iface_data(n) (rb_entry(n, struct iface_node, node)->iface)
|
||||
|
||||
static inline long
|
||||
ifname_compare(const char *_a, const char *_b)
|
||||
{
|
||||
const long *a = (const long *)_a;
|
||||
const long *b = (const long *)_b;
|
||||
|
||||
BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long));
|
||||
if (a[0] != b[0])
|
||||
return a[0] - b[0];
|
||||
if (IFNAMSIZ > sizeof(long)) {
|
||||
if (a[1] != b[1])
|
||||
return a[1] - b[1];
|
||||
}
|
||||
if (IFNAMSIZ > 2 * sizeof(long)) {
|
||||
if (a[2] != b[2])
|
||||
return a[2] - b[2];
|
||||
}
|
||||
if (IFNAMSIZ > 3 * sizeof(long)) {
|
||||
if (a[3] != b[3])
|
||||
return a[3] - b[3];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rbtree_destroy(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *p, *n = root->rb_node;
|
||||
struct iface_node *node;
|
||||
|
||||
/* Non-recursive destroy, like in ext3 */
|
||||
while (n) {
|
||||
if (n->rb_left) {
|
||||
n = n->rb_left;
|
||||
continue;
|
||||
}
|
||||
if (n->rb_right) {
|
||||
n = n->rb_right;
|
||||
continue;
|
||||
}
|
||||
p = rb_parent(n);
|
||||
node = rb_entry(n, struct iface_node, node);
|
||||
if (!p)
|
||||
*root = RB_ROOT;
|
||||
else if (p->rb_left == n)
|
||||
p->rb_left = NULL;
|
||||
else if (p->rb_right == n)
|
||||
p->rb_right = NULL;
|
||||
|
||||
kfree(node);
|
||||
n = p;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
iface_test(struct rb_root *root, const char **iface)
|
||||
{
|
||||
struct rb_node *n = root->rb_node;
|
||||
|
||||
while (n) {
|
||||
const char *d = iface_data(n);
|
||||
long res = ifname_compare(*iface, d);
|
||||
|
||||
if (res < 0)
|
||||
n = n->rb_left;
|
||||
else if (res > 0)
|
||||
n = n->rb_right;
|
||||
else {
|
||||
*iface = d;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
iface_add(struct rb_root *root, const char **iface)
|
||||
{
|
||||
struct rb_node **n = &(root->rb_node), *p = NULL;
|
||||
struct iface_node *d;
|
||||
|
||||
while (*n) {
|
||||
char *ifname = iface_data(*n);
|
||||
long res = ifname_compare(*iface, ifname);
|
||||
|
||||
p = *n;
|
||||
if (res < 0)
|
||||
n = &((*n)->rb_left);
|
||||
else if (res > 0)
|
||||
n = &((*n)->rb_right);
|
||||
else {
|
||||
*iface = ifname;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
d = kzalloc(sizeof(*d), GFP_ATOMIC);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
strcpy(d->iface, *iface);
|
||||
|
||||
rb_link_node(&d->node, p, n);
|
||||
rb_insert_color(&d->node, root);
|
||||
|
||||
*iface = d->iface;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define TYPE hash_netiface
|
||||
|
||||
static bool
|
||||
hash_netiface_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
#define hash_netiface4_same_set hash_netiface_same_set
|
||||
#define hash_netiface6_same_set hash_netiface_same_set
|
||||
|
||||
#define STREQ(a, b) (strcmp(a, b) == 0)
|
||||
|
||||
/* The type variant functions: IPv4 */
|
||||
|
||||
struct hash_netiface4_elem_hashed {
|
||||
__be32 ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u16 padding;
|
||||
};
|
||||
|
||||
#define HKEY_DATALEN sizeof(struct hash_netiface4_elem_hashed)
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_netiface4_elem {
|
||||
__be32 ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u16 padding;
|
||||
const char *iface;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_netiface4_telem {
|
||||
__be32 ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u16 padding;
|
||||
const char *iface;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_netiface4_data_equal(const struct hash_netiface4_elem *ip1,
|
||||
const struct hash_netiface4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->cidr == ip2->cidr &&
|
||||
(++*multi) &&
|
||||
ip1->physdev == ip2->physdev &&
|
||||
ip1->iface == ip2->iface;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_netiface4_data_isnull(const struct hash_netiface4_elem *elem)
|
||||
{
|
||||
return elem->cidr == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netiface4_data_copy(struct hash_netiface4_elem *dst,
|
||||
const struct hash_netiface4_elem *src) {
|
||||
dst->ip = src->ip;
|
||||
dst->cidr = src->cidr;
|
||||
dst->physdev = src->physdev;
|
||||
dst->iface = src->iface;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netiface4_data_netmask(struct hash_netiface4_elem *elem, u8 cidr)
|
||||
{
|
||||
elem->ip &= ip_set_netmask(cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netiface4_data_zero_out(struct hash_netiface4_elem *elem)
|
||||
{
|
||||
elem->cidr = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netiface4_data_list(struct sk_buff *skb,
|
||||
const struct hash_netiface4_elem *data)
|
||||
{
|
||||
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
|
||||
if (flags)
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netiface4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_netiface4_elem *data)
|
||||
{
|
||||
const struct hash_netiface4_telem *tdata =
|
||||
(const struct hash_netiface4_telem *)data;
|
||||
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
|
||||
if (flags)
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(tdata->timeout)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
#define IP_SET_HASH_WITH_RBTREE
|
||||
#define IP_SET_HASH_WITH_MULTI
|
||||
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_netiface4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_netiface4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netiface4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface4_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
#define IFACE(dir) (par->dir ? par->dir->name : NULL)
|
||||
#define PHYSDEV(dir) (nf_bridge->dir ? nf_bridge->dir->name : NULL)
|
||||
#define SRCDIR (opt->flags & IPSET_DIM_TWO_SRC)
|
||||
|
||||
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
|
||||
|
||||
if (!nf_bridge)
|
||||
return -EINVAL;
|
||||
data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
|
||||
data.physdev = 1;
|
||||
#else
|
||||
data.iface = NULL;
|
||||
#endif
|
||||
} else
|
||||
data.iface = SRCDIR ? IFACE(in) : IFACE(out);
|
||||
|
||||
if (!data.iface)
|
||||
return -EINVAL;
|
||||
ret = iface_test(&h->rbtree, &data.iface);
|
||||
if (adt == IPSET_ADD) {
|
||||
if (!ret) {
|
||||
ret = iface_add(&h->rbtree, &data.iface);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else if (!ret)
|
||||
return ret;
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface4_elem data = { .cidr = HOST_MASK };
|
||||
u32 ip = 0, ip_to, last;
|
||||
u32 timeout = h->timeout;
|
||||
char iface[IFNAMSIZ] = {};
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!tb[IPSET_ATTR_IFACE] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
|
||||
data.iface = iface;
|
||||
ret = iface_test(&h->rbtree, &data.iface);
|
||||
if (adt == IPSET_ADD) {
|
||||
if (!ret) {
|
||||
ret = iface_add(&h->rbtree, &data.iface);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else if (!ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_PHYSDEV)
|
||||
data.physdev = 1;
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
|
||||
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip_to < ip)
|
||||
swap(ip, ip_to);
|
||||
if (ip + UINT_MAX == ip_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
} else {
|
||||
ip_set_mask_from_to(ip, ip_to, data.cidr);
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
while (!after(ip, ip_to)) {
|
||||
data.ip = htonl(ip);
|
||||
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip = last + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netiface_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 *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_netiface6_elem_hashed {
|
||||
union nf_inet_addr ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u16 padding;
|
||||
};
|
||||
|
||||
#define HKEY_DATALEN sizeof(struct hash_netiface6_elem_hashed)
|
||||
|
||||
struct hash_netiface6_elem {
|
||||
union nf_inet_addr ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u16 padding;
|
||||
const char *iface;
|
||||
};
|
||||
|
||||
struct hash_netiface6_telem {
|
||||
union nf_inet_addr ip;
|
||||
u8 physdev;
|
||||
u8 cidr;
|
||||
u16 padding;
|
||||
const char *iface;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_netiface6_data_equal(const struct hash_netiface6_elem *ip1,
|
||||
const struct hash_netiface6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->cidr == ip2->cidr &&
|
||||
(++*multi) &&
|
||||
ip1->physdev == ip2->physdev &&
|
||||
ip1->iface == ip2->iface;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_netiface6_data_isnull(const struct hash_netiface6_elem *elem)
|
||||
{
|
||||
return elem->cidr == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netiface6_data_copy(struct hash_netiface6_elem *dst,
|
||||
const struct hash_netiface6_elem *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netiface6_data_zero_out(struct hash_netiface6_elem *elem)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netiface6_data_netmask(struct hash_netiface6_elem *elem, u8 cidr)
|
||||
{
|
||||
ip6_netmask(&elem->ip, cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netiface6_data_list(struct sk_buff *skb,
|
||||
const struct hash_netiface6_elem *data)
|
||||
{
|
||||
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
|
||||
if (flags)
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netiface6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_netiface6_elem *data)
|
||||
{
|
||||
const struct hash_netiface6_telem *e =
|
||||
(const struct hash_netiface6_telem *)data;
|
||||
u32 flags = data->physdev ? IPSET_FLAG_PHYSDEV : 0;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_STRING(skb, IPSET_ATTR_IFACE, data->iface);
|
||||
if (flags)
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_CADT_FLAGS, flags);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(e->timeout)));
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_netiface6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_netiface6_elem *d)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netiface6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface6_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
if (opt->cmdflags & IPSET_FLAG_PHYSDEV) {
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
const struct nf_bridge_info *nf_bridge = skb->nf_bridge;
|
||||
|
||||
if (!nf_bridge)
|
||||
return -EINVAL;
|
||||
data.iface = SRCDIR ? PHYSDEV(physindev) : PHYSDEV(physoutdev);
|
||||
data.physdev = 1;
|
||||
#else
|
||||
data.iface = NULL;
|
||||
#endif
|
||||
} else
|
||||
data.iface = SRCDIR ? IFACE(in) : IFACE(out);
|
||||
|
||||
if (!data.iface)
|
||||
return -EINVAL;
|
||||
ret = iface_test(&h->rbtree, &data.iface);
|
||||
if (adt == IPSET_ADD) {
|
||||
if (!ret) {
|
||||
ret = iface_add(&h->rbtree, &data.iface);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else if (!ret)
|
||||
return ret;
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netiface6_elem data = { .cidr = HOST_MASK };
|
||||
u32 timeout = h->timeout;
|
||||
char iface[IFNAMSIZ] = {};
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!tb[IPSET_ATTR_IFACE] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
strcpy(iface, nla_data(tb[IPSET_ATTR_IFACE]));
|
||||
data.iface = iface;
|
||||
ret = iface_test(&h->rbtree, &data.iface);
|
||||
if (adt == IPSET_ADD) {
|
||||
if (!ret) {
|
||||
ret = iface_add(&h->rbtree, &data.iface);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
} else if (!ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
if (cadt_flags & IPSET_FLAG_PHYSDEV)
|
||||
data.physdev = 1;
|
||||
}
|
||||
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static int
|
||||
hash_netiface_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
|
||||
if (hashsize < IPSET_MIMINAL_HASHSIZE)
|
||||
hashsize = IPSET_MIMINAL_HASHSIZE;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_MAXELEM])
|
||||
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
|
||||
|
||||
h = kzalloc(sizeof(*h)
|
||||
+ sizeof(struct ip_set_hash_nets)
|
||||
* (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->maxelem = maxelem;
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
h->ahash_max = AHASH_MAX_SIZE;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
h->rbtree = RB_ROOT;
|
||||
|
||||
set->data = h;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_netiface4_tvariant : &hash_netiface6_tvariant;
|
||||
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
hash_netiface4_gc_init(set);
|
||||
else
|
||||
hash_netiface6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_netiface4_variant : &hash_netiface6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_netiface_type __read_mostly = {
|
||||
.name = "hash:net,iface",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_IFACE,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
.create = hash_netiface_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_IFACE] = { .type = NLA_NUL_STRING,
|
||||
.len = IPSET_MAXNAMELEN - 1 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_CIDR] = { .type = NLA_U8 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_netiface_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_netiface_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_netiface_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_netiface_type);
|
||||
}
|
||||
|
||||
module_init(hash_netiface_init);
|
||||
module_exit(hash_netiface_fini);
|
||||
@@ -1,615 +0,0 @@
|
||||
/* 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 hash:net,port type */
|
||||
|
||||
#include "jhash.h"
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/random.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include "pfxlen.h"
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_getport.h"
|
||||
#include "ip_set_hash.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("hash:net,port type of IP sets");
|
||||
MODULE_ALIAS("ip_set_hash:net,port");
|
||||
|
||||
/* Type specific function prefix */
|
||||
#define TYPE hash_netport
|
||||
|
||||
static bool
|
||||
hash_netport_same_set(const struct ip_set *a, const struct ip_set *b);
|
||||
|
||||
#define hash_netport4_same_set hash_netport_same_set
|
||||
#define hash_netport6_same_set hash_netport_same_set
|
||||
|
||||
/* The type variant functions: IPv4 */
|
||||
|
||||
/* Member elements without timeout */
|
||||
struct hash_netport4_elem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
};
|
||||
|
||||
/* Member elements with timeout support */
|
||||
struct hash_netport4_telem {
|
||||
__be32 ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
|
||||
const struct hash_netport4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto &&
|
||||
ip1->cidr == ip2->cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_netport4_data_isnull(const struct hash_netport4_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport4_data_copy(struct hash_netport4_elem *dst,
|
||||
const struct hash_netport4_elem *src)
|
||||
{
|
||||
dst->ip = src->ip;
|
||||
dst->port = src->port;
|
||||
dst->proto = src->proto;
|
||||
dst->cidr = src->cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport4_data_netmask(struct hash_netport4_elem *elem, u8 cidr)
|
||||
{
|
||||
elem->ip &= ip_set_netmask(cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport4_data_zero_out(struct hash_netport4_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netport4_data_list(struct sk_buff *skb,
|
||||
const struct hash_netport4_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, data->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netport4_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_netport4_elem *data)
|
||||
{
|
||||
const struct hash_netport4_telem *tdata =
|
||||
(const struct hash_netport4_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR4(skb, IPSET_ATTR_IP, tdata->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, tdata->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(tdata->timeout)));
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define IP_SET_HASH_WITH_PROTO
|
||||
#define IP_SET_HASH_WITH_NETS
|
||||
|
||||
#define PF 4
|
||||
#define HOST_MASK 32
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_netport4_data_next(struct ip_set_hash *h,
|
||||
const struct hash_netport4_elem *d)
|
||||
{
|
||||
h->next.ip = ntohl(d->ip);
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport4_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport4_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport4_elem data = { .cidr = HOST_MASK };
|
||||
u32 port, port_to, p = 0, ip = 0, ip_to, last;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMP))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
with_ports = with_ports && tb[IPSET_ATTR_PORT_TO];
|
||||
if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
|
||||
data.ip = htonl(ip & ip_set_hostmask(data.cidr));
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
port = port_to = ntohs(data.port);
|
||||
if (tb[IPSET_ATTR_PORT_TO]) {
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port_to < port)
|
||||
swap(port, port_to);
|
||||
}
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ip_to < ip)
|
||||
swap(ip, ip_to);
|
||||
if (ip + UINT_MAX == ip_to)
|
||||
return -IPSET_ERR_HASH_RANGE;
|
||||
} else {
|
||||
ip_set_mask_from_to(ip, ip_to, data.cidr);
|
||||
}
|
||||
|
||||
if (retried)
|
||||
ip = h->next.ip;
|
||||
while (!after(ip, ip_to)) {
|
||||
data.ip = htonl(ip);
|
||||
last = ip_set_range_to_cidr(ip, ip_to, &data.cidr);
|
||||
p = retried && ip == h->next.ip ? h->next.port : port;
|
||||
for (; p <= port_to; p++) {
|
||||
data.port = htons(p);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
ip = last + 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netport_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 *y = b->data;
|
||||
|
||||
/* Resizing changes htable_bits, so we ignore it */
|
||||
return x->maxelem == y->maxelem &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
/* The type variant functions: IPv6 */
|
||||
|
||||
struct hash_netport6_elem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
};
|
||||
|
||||
struct hash_netport6_telem {
|
||||
union nf_inet_addr ip;
|
||||
__be16 port;
|
||||
u8 proto;
|
||||
u8 cidr;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
static inline bool
|
||||
hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
|
||||
const struct hash_netport6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
ip1->proto == ip2->proto &&
|
||||
ip1->cidr == ip2->cidr;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hash_netport6_data_isnull(const struct hash_netport6_elem *elem)
|
||||
{
|
||||
return elem->proto == 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport6_data_copy(struct hash_netport6_elem *dst,
|
||||
const struct hash_netport6_elem *src)
|
||||
{
|
||||
memcpy(dst, src, sizeof(*dst));
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport6_data_zero_out(struct hash_netport6_elem *elem)
|
||||
{
|
||||
elem->proto = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ip6_netmask(union nf_inet_addr *ip, u8 prefix)
|
||||
{
|
||||
ip->ip6[0] &= ip_set_netmask6(prefix)[0];
|
||||
ip->ip6[1] &= ip_set_netmask6(prefix)[1];
|
||||
ip->ip6[2] &= ip_set_netmask6(prefix)[2];
|
||||
ip->ip6[3] &= ip_set_netmask6(prefix)[3];
|
||||
}
|
||||
|
||||
static inline void
|
||||
hash_netport6_data_netmask(struct hash_netport6_elem *elem, u8 cidr)
|
||||
{
|
||||
ip6_netmask(&elem->ip, cidr);
|
||||
elem->cidr = cidr;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netport6_data_list(struct sk_buff *skb,
|
||||
const struct hash_netport6_elem *data)
|
||||
{
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &data->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_netport6_data_tlist(struct sk_buff *skb,
|
||||
const struct hash_netport6_elem *data)
|
||||
{
|
||||
const struct hash_netport6_telem *e =
|
||||
(const struct hash_netport6_telem *)data;
|
||||
|
||||
NLA_PUT_IPADDR6(skb, IPSET_ATTR_IP, &e->ip);
|
||||
NLA_PUT_NET16(skb, IPSET_ATTR_PORT, data->port);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_CIDR, data->cidr);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTO, data->proto);
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(e->timeout)));
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return 1;
|
||||
}
|
||||
|
||||
#undef PF
|
||||
#undef HOST_MASK
|
||||
|
||||
#define PF 6
|
||||
#define HOST_MASK 128
|
||||
#include "ip_set_ahash.h"
|
||||
|
||||
static inline void
|
||||
hash_netport6_data_next(struct ip_set_hash *h,
|
||||
const struct hash_netport6_elem *d)
|
||||
{
|
||||
h->next.port = ntohs(d->port);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport6_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport6_elem data = {
|
||||
.cidr = h->nets[0].cidr ? h->nets[0].cidr : HOST_MASK
|
||||
};
|
||||
|
||||
if (data.cidr == 0)
|
||||
return -EINVAL;
|
||||
if (adt == IPSET_TEST)
|
||||
data.cidr = HOST_MASK;
|
||||
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static int
|
||||
hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct ip_set_hash *h = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
struct hash_netport6_elem data = { .cidr = HOST_MASK };
|
||||
u32 port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_IP] ||
|
||||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
if (unlikely(tb[IPSET_ATTR_IP_TO]))
|
||||
return -IPSET_ERR_HASH_RANGE_UNSUPPORTED;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr6(tb[IPSET_ATTR_IP], &data.ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_PROTO]) {
|
||||
data.proto = nla_get_u8(tb[IPSET_ATTR_PROTO]);
|
||||
with_ports = ip_set_proto_with_ports(data.proto);
|
||||
|
||||
if (data.proto == 0)
|
||||
return -IPSET_ERR_INVALID_PROTO;
|
||||
} else
|
||||
return -IPSET_ERR_MISSING_PROTO;
|
||||
|
||||
if (!(with_ports || data.proto == IPPROTO_ICMPV6))
|
||||
data.port = 0;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
return -IPSET_ERR_TIMEOUT;
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
port = ntohs(data.port);
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
if (retried)
|
||||
port = h->next.port;
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create hash:ip type of sets */
|
||||
|
||||
static int
|
||||
hash_netport_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
struct ip_set_hash *h;
|
||||
u32 hashsize = IPSET_DEFAULT_HASHSIZE, maxelem = IPSET_DEFAULT_MAXELEM;
|
||||
u8 hbits;
|
||||
|
||||
if (!(set->family == NFPROTO_IPV4 || set->family == NFPROTO_IPV6))
|
||||
return -IPSET_ERR_INVALID_FAMILY;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_HASHSIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_MAXELEM) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_HASHSIZE]) {
|
||||
hashsize = ip_set_get_h32(tb[IPSET_ATTR_HASHSIZE]);
|
||||
if (hashsize < IPSET_MIMINAL_HASHSIZE)
|
||||
hashsize = IPSET_MIMINAL_HASHSIZE;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_MAXELEM])
|
||||
maxelem = ip_set_get_h32(tb[IPSET_ATTR_MAXELEM]);
|
||||
|
||||
h = kzalloc(sizeof(*h)
|
||||
+ sizeof(struct ip_set_hash_nets)
|
||||
* (set->family == NFPROTO_IPV4 ? 32 : 128), GFP_KERNEL);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->maxelem = maxelem;
|
||||
get_random_bytes(&h->initval, sizeof(h->initval));
|
||||
h->timeout = IPSET_NO_TIMEOUT;
|
||||
|
||||
hbits = htable_bits(hashsize);
|
||||
h->table = ip_set_alloc(
|
||||
sizeof(struct htable)
|
||||
+ jhash_size(hbits) * sizeof(struct hbucket));
|
||||
if (!h->table) {
|
||||
kfree(h);
|
||||
return -ENOMEM;
|
||||
}
|
||||
h->table->htable_bits = hbits;
|
||||
|
||||
set->data = h;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
h->timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_netport4_tvariant : &hash_netport6_tvariant;
|
||||
|
||||
if (set->family == NFPROTO_IPV4)
|
||||
hash_netport4_gc_init(set);
|
||||
else
|
||||
hash_netport6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == NFPROTO_IPV4
|
||||
? &hash_netport4_variant : &hash_netport6_variant;
|
||||
}
|
||||
|
||||
pr_debug("create %s hashsize %u (%u) maxelem %u: %p(%p)\n",
|
||||
set->name, jhash_size(h->table->htable_bits),
|
||||
h->table->htable_bits, h->maxelem, set->data, h->table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type hash_netport_type __read_mostly = {
|
||||
.name = "hash:net,port",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
/* 1 SCTP and UDPLITE support added */
|
||||
.revision_max = 2, /* Range as input support for IPv4 added */
|
||||
.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_IP_TO] = { .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,
|
||||
};
|
||||
|
||||
static int __init
|
||||
hash_netport_init(void)
|
||||
{
|
||||
return ip_set_type_register(&hash_netport_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
hash_netport_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&hash_netport_type);
|
||||
}
|
||||
|
||||
module_init(hash_netport_init);
|
||||
module_exit(hash_netport_fini);
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef __IP_SET_LIST_H
|
||||
#define __IP_SET_LIST_H
|
||||
|
||||
/* List type specific error codes */
|
||||
enum {
|
||||
/* Set name to be added/deleted/tested does not exist. */
|
||||
IPSET_ERR_NAME = IPSET_ERR_TYPE_SPECIFIC,
|
||||
/* list:set type is not permitted to add */
|
||||
IPSET_ERR_LOOP,
|
||||
/* Missing reference set */
|
||||
IPSET_ERR_BEFORE,
|
||||
/* Reference set does not exist */
|
||||
IPSET_ERR_NAMEREF,
|
||||
/* Set is full */
|
||||
IPSET_ERR_LIST_FULL,
|
||||
/* Reference set is not added to the set */
|
||||
IPSET_ERR_REF_EXIST,
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define IP_SET_LIST_DEFAULT_SIZE 8
|
||||
#define IP_SET_LIST_MIN_SIZE 4
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __IP_SET_LIST_H */
|
||||
@@ -1,611 +0,0 @@
|
||||
/* Copyright (C) 2008-2011 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
/* Kernel module implementing an IP set type: the list:set type */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "ip_set.h"
|
||||
#include "ip_set_timeout.h"
|
||||
#include "ip_set_list.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("list:set type of IP sets");
|
||||
MODULE_ALIAS("ip_set_list:set");
|
||||
|
||||
/* Member elements without and with timeout */
|
||||
struct set_elem {
|
||||
ip_set_id_t id;
|
||||
};
|
||||
|
||||
struct set_telem {
|
||||
ip_set_id_t id;
|
||||
unsigned long timeout;
|
||||
};
|
||||
|
||||
/* Type structure */
|
||||
struct list_set {
|
||||
size_t dsize; /* element size */
|
||||
u32 size; /* size of set list array */
|
||||
u32 timeout; /* timeout value */
|
||||
struct timer_list gc; /* garbage collection */
|
||||
struct set_elem members[0]; /* the set members */
|
||||
};
|
||||
|
||||
static inline struct set_elem *
|
||||
list_set_elem(const struct list_set *map, u32 id)
|
||||
{
|
||||
return (struct set_elem *)((void *)map->members + id * map->dsize);
|
||||
}
|
||||
|
||||
static inline struct set_telem *
|
||||
list_set_telem(const struct list_set *map, u32 id)
|
||||
{
|
||||
return (struct set_telem *)((void *)map->members + id * map->dsize);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
list_set_timeout(const struct list_set *map, u32 id)
|
||||
{
|
||||
const struct set_telem *elem = list_set_telem(map, id);
|
||||
|
||||
return ip_set_timeout_test(elem->timeout);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
list_set_expired(const struct list_set *map, u32 id)
|
||||
{
|
||||
const struct set_telem *elem = list_set_telem(map, id);
|
||||
|
||||
return ip_set_timeout_expired(elem->timeout);
|
||||
}
|
||||
|
||||
/* Set list without and with timeout */
|
||||
|
||||
static int
|
||||
list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
struct set_elem *elem;
|
||||
u32 i;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id == IPSET_INVALID_ID)
|
||||
return 0;
|
||||
if (with_timeout(map->timeout) && list_set_expired(map, i))
|
||||
continue;
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
ret = ip_set_test(elem->id, skb, par, opt);
|
||||
if (ret > 0)
|
||||
return ret;
|
||||
break;
|
||||
case IPSET_ADD:
|
||||
ret = ip_set_add(elem->id, skb, par, opt);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
break;
|
||||
case IPSET_DEL:
|
||||
ret = ip_set_del(elem->id, skb, par, opt);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static bool
|
||||
id_eq(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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
id_eq_timeout(const struct list_set *map, u32 i, ip_set_id_t id)
|
||||
{
|
||||
const struct set_elem *elem;
|
||||
|
||||
if (i < map->size) {
|
||||
elem = list_set_elem(map, i);
|
||||
return !!(elem->id == id &&
|
||||
!(with_timeout(map->timeout) &&
|
||||
list_set_expired(map, i)));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
list_elem_add(struct list_set *map, u32 i, ip_set_id_t id)
|
||||
{
|
||||
struct set_elem *e;
|
||||
|
||||
for (; i < map->size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
swap(e->id, id);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
list_elem_tadd(struct list_set *map, u32 i, ip_set_id_t id,
|
||||
unsigned long timeout)
|
||||
{
|
||||
struct set_telem *e;
|
||||
|
||||
for (; i < map->size; i++) {
|
||||
e = list_set_telem(map, i);
|
||||
swap(e->id, id);
|
||||
swap(e->timeout, timeout);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_add(struct list_set *map, u32 i, ip_set_id_t id,
|
||||
unsigned long timeout)
|
||||
{
|
||||
const struct set_elem *e = list_set_elem(map, i);
|
||||
|
||||
if (i == map->size - 1 && e->id != IPSET_INVALID_ID)
|
||||
/* Last element replaced: e.g. add new,before,last */
|
||||
ip_set_put_byindex(e->id);
|
||||
if (with_timeout(map->timeout))
|
||||
list_elem_tadd(map, i, id, ip_set_timeout_set(timeout));
|
||||
else
|
||||
list_elem_add(map, i, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_del(struct list_set *map, u32 i)
|
||||
{
|
||||
struct set_elem *a = list_set_elem(map, i), *b;
|
||||
|
||||
ip_set_put_byindex(a->id);
|
||||
|
||||
for (; i < map->size - 1; i++) {
|
||||
b = list_set_elem(map, i + 1);
|
||||
a->id = b->id;
|
||||
if (with_timeout(map->timeout))
|
||||
((struct set_telem *)a)->timeout =
|
||||
((struct set_telem *)b)->timeout;
|
||||
a = b;
|
||||
if (a->id == IPSET_INVALID_ID)
|
||||
break;
|
||||
}
|
||||
/* Last element */
|
||||
a->id = IPSET_INVALID_ID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_entries(struct list_set *map)
|
||||
{
|
||||
struct set_telem *e;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
e = list_set_telem(map, i);
|
||||
if (e->id != IPSET_INVALID_ID && list_set_expired(map, i))
|
||||
list_set_del(map, i);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
bool with_timeout = with_timeout(map->timeout);
|
||||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
int before = 0;
|
||||
u32 timeout = map->timeout;
|
||||
ip_set_id_t id, refid = IPSET_INVALID_ID;
|
||||
const struct set_elem *elem;
|
||||
struct ip_set *s;
|
||||
u32 i;
|
||||
int ret = 0;
|
||||
|
||||
if (unlikely(!tb[IPSET_ATTR_NAME] ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s);
|
||||
if (id == IPSET_INVALID_ID)
|
||||
return -IPSET_ERR_NAME;
|
||||
/* "Loop detection" */
|
||||
if (s->type->features & IPSET_TYPE_NAME) {
|
||||
ret = -IPSET_ERR_LOOP;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_CADT_FLAGS]) {
|
||||
u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
|
||||
before = f & IPSET_FLAG_BEFORE;
|
||||
}
|
||||
|
||||
if (before && !tb[IPSET_ATTR_NAMEREF]) {
|
||||
ret = -IPSET_ERR_BEFORE;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_NAMEREF]) {
|
||||
refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]),
|
||||
&s);
|
||||
if (refid == IPSET_INVALID_ID) {
|
||||
ret = -IPSET_ERR_NAMEREF;
|
||||
goto finish;
|
||||
}
|
||||
if (!before)
|
||||
before = -1;
|
||||
}
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout) {
|
||||
ret = -IPSET_ERR_TIMEOUT;
|
||||
goto finish;
|
||||
}
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
if (with_timeout && adt != IPSET_TEST)
|
||||
cleanup_entries(map);
|
||||
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
for (i = 0; i < map->size && !ret; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id == IPSET_INVALID_ID ||
|
||||
(before != 0 && i + 1 >= map->size))
|
||||
break;
|
||||
else if (with_timeout && list_set_expired(map, i))
|
||||
continue;
|
||||
else if (before > 0 && elem->id == id)
|
||||
ret = id_eq_timeout(map, i + 1, refid);
|
||||
else if (before < 0 && elem->id == refid)
|
||||
ret = id_eq_timeout(map, i + 1, id);
|
||||
else if (before == 0 && elem->id == id)
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
case IPSET_ADD:
|
||||
for (i = 0; i < map->size; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id != id)
|
||||
continue;
|
||||
if (!(with_timeout && flag_exist)) {
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
goto finish;
|
||||
} else {
|
||||
struct set_telem *e = list_set_telem(map, i);
|
||||
|
||||
if ((before > 1 &&
|
||||
!id_eq(map, i + 1, refid)) ||
|
||||
(before < 0 &&
|
||||
(i == 0 || !id_eq(map, i - 1, refid)))) {
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
goto finish;
|
||||
}
|
||||
e->timeout = ip_set_timeout_set(timeout);
|
||||
ip_set_put_byindex(id);
|
||||
ret = 0;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
ret = -IPSET_ERR_LIST_FULL;
|
||||
for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id == IPSET_INVALID_ID)
|
||||
ret = before != 0 ? -IPSET_ERR_REF_EXIST
|
||||
: list_set_add(map, i, id, timeout);
|
||||
else if (elem->id != refid)
|
||||
continue;
|
||||
else if (before > 0)
|
||||
ret = list_set_add(map, i, id, timeout);
|
||||
else if (i + 1 < map->size)
|
||||
ret = list_set_add(map, i + 1, id, timeout);
|
||||
}
|
||||
break;
|
||||
case IPSET_DEL:
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id == IPSET_INVALID_ID) {
|
||||
ret = before != 0 ? -IPSET_ERR_REF_EXIST
|
||||
: -IPSET_ERR_EXIST;
|
||||
break;
|
||||
} else if (elem->id == id &&
|
||||
(before == 0 ||
|
||||
(before > 0 && id_eq(map, i + 1, refid))))
|
||||
ret = list_set_del(map, i);
|
||||
else if (elem->id == refid &&
|
||||
before < 0 && id_eq(map, i + 1, id))
|
||||
ret = list_set_del(map, i + 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
finish:
|
||||
if (refid != IPSET_INVALID_ID)
|
||||
ip_set_put_byindex(refid);
|
||||
if (adt != IPSET_ADD || ret)
|
||||
ip_set_put_byindex(id);
|
||||
|
||||
return ip_set_eexist(ret, flags) ? 0 : ret;
|
||||
}
|
||||
|
||||
static void
|
||||
list_set_flush(struct ip_set *set)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
struct set_elem *elem;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < map->size; i++) {
|
||||
elem = list_set_elem(map, i);
|
||||
if (elem->id != IPSET_INVALID_ID) {
|
||||
ip_set_put_byindex(elem->id);
|
||||
elem->id = IPSET_INVALID_ID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
list_set_destroy(struct ip_set *set)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
|
||||
if (with_timeout(map->timeout))
|
||||
del_timer_sync(&map->gc);
|
||||
list_set_flush(set);
|
||||
kfree(map);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_head(struct ip_set *set, struct sk_buff *skb)
|
||||
{
|
||||
const struct list_set *map = set->data;
|
||||
struct nlattr *nested;
|
||||
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested)
|
||||
goto nla_put_failure;
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_SIZE, htonl(map->size));
|
||||
if (with_timeout(map->timeout))
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT, htonl(map->timeout));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1));
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_MEMSIZE,
|
||||
htonl(sizeof(*map) + map->size * map->dsize));
|
||||
ipset_nest_end(skb, nested);
|
||||
|
||||
return 0;
|
||||
nla_put_failure:
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_list(const struct ip_set *set,
|
||||
struct sk_buff *skb, struct netlink_callback *cb)
|
||||
{
|
||||
const struct list_set *map = set->data;
|
||||
struct nlattr *atd, *nested;
|
||||
u32 i, first = cb->args[2];
|
||||
const struct set_elem *e;
|
||||
|
||||
atd = ipset_nest_start(skb, IPSET_ATTR_ADT);
|
||||
if (!atd)
|
||||
return -EMSGSIZE;
|
||||
for (; cb->args[2] < map->size; cb->args[2]++) {
|
||||
i = cb->args[2];
|
||||
e = list_set_elem(map, i);
|
||||
if (e->id == IPSET_INVALID_ID)
|
||||
goto finish;
|
||||
if (with_timeout(map->timeout) && list_set_expired(map, i))
|
||||
continue;
|
||||
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
|
||||
if (!nested) {
|
||||
if (i == first) {
|
||||
nla_nest_cancel(skb, atd);
|
||||
return -EMSGSIZE;
|
||||
} else
|
||||
goto nla_put_failure;
|
||||
}
|
||||
NLA_PUT_STRING(skb, IPSET_ATTR_NAME,
|
||||
ip_set_name_byindex(e->id));
|
||||
if (with_timeout(map->timeout)) {
|
||||
const struct set_telem *te =
|
||||
(const struct set_telem *) e;
|
||||
NLA_PUT_NET32(skb, IPSET_ATTR_TIMEOUT,
|
||||
htonl(ip_set_timeout_get(te->timeout)));
|
||||
}
|
||||
ipset_nest_end(skb, nested);
|
||||
}
|
||||
finish:
|
||||
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(i == first)) {
|
||||
cb->args[2] = 0;
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
list_set_same_set(const struct ip_set *a, const struct ip_set *b)
|
||||
{
|
||||
const struct list_set *x = a->data;
|
||||
const struct list_set *y = b->data;
|
||||
|
||||
return x->size == y->size &&
|
||||
x->timeout == y->timeout;
|
||||
}
|
||||
|
||||
static const struct ip_set_type_variant list_set = {
|
||||
.kadt = list_set_kadt,
|
||||
.uadt = list_set_uadt,
|
||||
.destroy = list_set_destroy,
|
||||
.flush = list_set_flush,
|
||||
.head = list_set_head,
|
||||
.list = list_set_list,
|
||||
.same_set = list_set_same_set,
|
||||
};
|
||||
|
||||
static void
|
||||
list_set_gc(unsigned long ul_set)
|
||||
{
|
||||
struct ip_set *set = (struct ip_set *) ul_set;
|
||||
struct list_set *map = set->data;
|
||||
|
||||
write_lock_bh(&set->lock);
|
||||
cleanup_entries(map);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
static void
|
||||
list_set_gc_init(struct ip_set *set)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
|
||||
init_timer(&map->gc);
|
||||
map->gc.data = (unsigned long) set;
|
||||
map->gc.function = list_set_gc;
|
||||
map->gc.expires = jiffies + IPSET_GC_PERIOD(map->timeout) * HZ;
|
||||
add_timer(&map->gc);
|
||||
}
|
||||
|
||||
/* Create list:set type of sets */
|
||||
|
||||
static bool
|
||||
init_list_set(struct ip_set *set, u32 size, size_t dsize,
|
||||
unsigned long timeout)
|
||||
{
|
||||
struct list_set *map;
|
||||
struct set_elem *e;
|
||||
u32 i;
|
||||
|
||||
map = kzalloc(sizeof(*map) + size * dsize, GFP_KERNEL);
|
||||
if (!map)
|
||||
return false;
|
||||
|
||||
map->size = size;
|
||||
map->dsize = dsize;
|
||||
map->timeout = timeout;
|
||||
set->data = map;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
e = list_set_elem(map, i);
|
||||
e->id = IPSET_INVALID_ID;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
list_set_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
{
|
||||
u32 size = IP_SET_LIST_DEFAULT_SIZE;
|
||||
|
||||
if (unlikely(!ip_set_optattr_netorder(tb, IPSET_ATTR_SIZE) ||
|
||||
!ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT)))
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (tb[IPSET_ATTR_SIZE])
|
||||
size = ip_set_get_h32(tb[IPSET_ATTR_SIZE]);
|
||||
if (size < IP_SET_LIST_MIN_SIZE)
|
||||
size = IP_SET_LIST_MIN_SIZE;
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!init_list_set(set, size, sizeof(struct set_telem),
|
||||
ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT])))
|
||||
return -ENOMEM;
|
||||
|
||||
list_set_gc_init(set);
|
||||
} else {
|
||||
if (!init_list_set(set, size, sizeof(struct set_elem),
|
||||
IPSET_NO_TIMEOUT))
|
||||
return -ENOMEM;
|
||||
}
|
||||
set->variant = &list_set;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ip_set_type list_set_type __read_mostly = {
|
||||
.name = "list:set",
|
||||
.protocol = IPSET_PROTOCOL,
|
||||
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = list_set_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_NAME] = { .type = NLA_STRING,
|
||||
.len = IPSET_MAXNAMELEN },
|
||||
[IPSET_ATTR_NAMEREF] = { .type = NLA_STRING,
|
||||
.len = IPSET_MAXNAMELEN },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .type = NLA_U32 },
|
||||
},
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init
|
||||
list_set_init(void)
|
||||
{
|
||||
return ip_set_type_register(&list_set_type);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
list_set_fini(void)
|
||||
{
|
||||
ip_set_type_unregister(&list_set_type);
|
||||
}
|
||||
|
||||
module_init(list_set_init);
|
||||
module_exit(list_set_fini);
|
||||
@@ -1,132 +0,0 @@
|
||||
#ifndef _IP_SET_TIMEOUT_H
|
||||
#define _IP_SET_TIMEOUT_H
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/* How often should the gc be run by default */
|
||||
#define IPSET_GC_TIME (3 * 60)
|
||||
|
||||
/* Timeout period depending on the timeout value of the given set */
|
||||
#define IPSET_GC_PERIOD(timeout) \
|
||||
((timeout/3) ? min_t(u32, (timeout)/3, IPSET_GC_TIME) : 1)
|
||||
|
||||
/* Set is defined without timeout support: timeout value may be 0 */
|
||||
#define IPSET_NO_TIMEOUT UINT_MAX
|
||||
|
||||
#define with_timeout(timeout) ((timeout) != IPSET_NO_TIMEOUT)
|
||||
|
||||
#define opt_timeout(opt, map) \
|
||||
(with_timeout((opt)->timeout) ? (opt)->timeout : (map)->timeout)
|
||||
|
||||
static inline unsigned int
|
||||
ip_set_timeout_uget(struct nlattr *tb)
|
||||
{
|
||||
unsigned int timeout = ip_set_get_h32(tb);
|
||||
|
||||
/* Userspace supplied TIMEOUT parameter: adjust crazy size */
|
||||
return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
|
||||
}
|
||||
|
||||
#ifdef IP_SET_BITMAP_TIMEOUT
|
||||
|
||||
/* Bitmap specific timeout constants and macros for the entries */
|
||||
|
||||
/* Bitmap entry is unset */
|
||||
#define IPSET_ELEM_UNSET 0
|
||||
/* Bitmap entry is set with no timeout value */
|
||||
#define IPSET_ELEM_PERMANENT (UINT_MAX/2)
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
(timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_is_after_jiffies(timeout));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_is_before_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
ip_set_timeout_set(u32 timeout)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! */
|
||||
t++;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* Hash specific timeout constants and macros for the entries */
|
||||
|
||||
/* Hash entry is set with no timeout value */
|
||||
#define IPSET_ELEM_PERMANENT 0
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_is_after_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_is_before_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
ip_set_timeout_set(u32 timeout)
|
||||
{
|
||||
unsigned long t;
|
||||
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! :-) */
|
||||
t++;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
}
|
||||
#endif /* ! IP_SET_BITMAP_TIMEOUT */
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _IP_SET_TIMEOUT_H */
|
||||
@@ -1,169 +0,0 @@
|
||||
#ifndef _LINUX_JHASH_H
|
||||
#define _LINUX_JHASH_H
|
||||
|
||||
/* jhash.h: Jenkins hash support.
|
||||
*
|
||||
* Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
|
||||
*
|
||||
* http://burtleburtle.net/bob/hash/
|
||||
*
|
||||
* These are the credits from Bob's sources:
|
||||
*
|
||||
* lookup3.c, by Bob Jenkins, May 2006, Public Domain.
|
||||
*
|
||||
* These are functions for producing 32-bit hashes for hash table lookup.
|
||||
* hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
|
||||
* are externally useful functions. Routines to test the hash are included
|
||||
* if SELF_TEST is defined. You can use this free for any purpose. It's in
|
||||
* the public domain. It has no warranty.
|
||||
*
|
||||
* Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||
*
|
||||
* I've modified Bob's hash to be useful in the Linux kernel, and
|
||||
* any bugs present are my fault.
|
||||
* Jozsef
|
||||
*/
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/unaligned/packed_struct.h>
|
||||
|
||||
/* Best hash sizes are of power of two */
|
||||
#define jhash_size(n) ((u32)1<<(n))
|
||||
/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */
|
||||
#define jhash_mask(n) (jhash_size(n)-1)
|
||||
|
||||
/* __jhash_mix -- mix 3 32-bit values reversibly. */
|
||||
#define __jhash_mix(a, b, c) \
|
||||
{ \
|
||||
a -= c; a ^= rol32(c, 4); c += b; \
|
||||
b -= a; b ^= rol32(a, 6); a += c; \
|
||||
c -= b; c ^= rol32(b, 8); b += a; \
|
||||
a -= c; a ^= rol32(c, 16); c += b; \
|
||||
b -= a; b ^= rol32(a, 19); a += c; \
|
||||
c -= b; c ^= rol32(b, 4); b += a; \
|
||||
}
|
||||
|
||||
/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
|
||||
#define __jhash_final(a, b, c) \
|
||||
{ \
|
||||
c ^= b; c -= rol32(b, 14); \
|
||||
a ^= c; a -= rol32(c, 11); \
|
||||
b ^= a; b -= rol32(a, 25); \
|
||||
c ^= b; c -= rol32(b, 16); \
|
||||
a ^= c; a -= rol32(c, 4); \
|
||||
b ^= a; b -= rol32(a, 14); \
|
||||
c ^= b; c -= rol32(b, 24); \
|
||||
}
|
||||
|
||||
/* An arbitrary initial parameter */
|
||||
#define JHASH_INITVAL 0xdeadbeef
|
||||
|
||||
/* jhash - hash an arbitrary key
|
||||
* @k: sequence of bytes as key
|
||||
* @length: the length of the key
|
||||
* @initval: the previous hash, or an arbitray value
|
||||
*
|
||||
* The generic version, hashes an arbitrary sequence of bytes.
|
||||
* No alignment or length assumptions are made about the input key.
|
||||
*
|
||||
* Returns the hash value of the key. The result depends on endianness.
|
||||
*/
|
||||
static inline u32 jhash(const void *key, u32 length, u32 initval)
|
||||
{
|
||||
u32 a, b, c;
|
||||
const u8 *k = key;
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = JHASH_INITVAL + length + initval;
|
||||
|
||||
/* All but the last block: affect some 32 bits of (a,b,c) */
|
||||
while (length > 12) {
|
||||
a += __get_unaligned_cpu32(k);
|
||||
b += __get_unaligned_cpu32(k + 4);
|
||||
c += __get_unaligned_cpu32(k + 8);
|
||||
__jhash_mix(a, b, c);
|
||||
length -= 12;
|
||||
k += 12;
|
||||
}
|
||||
/* Last block: affect all 32 bits of (c) */
|
||||
/* All the case statements fall through */
|
||||
switch (length) {
|
||||
case 12: c += (u32)k[11]<<24;
|
||||
case 11: c += (u32)k[10]<<16;
|
||||
case 10: c += (u32)k[9]<<8;
|
||||
case 9: c += k[8];
|
||||
case 8: b += (u32)k[7]<<24;
|
||||
case 7: b += (u32)k[6]<<16;
|
||||
case 6: b += (u32)k[5]<<8;
|
||||
case 5: b += k[4];
|
||||
case 4: a += (u32)k[3]<<24;
|
||||
case 3: a += (u32)k[2]<<16;
|
||||
case 2: a += (u32)k[1]<<8;
|
||||
case 1: a += k[0];
|
||||
__jhash_final(a, b, c);
|
||||
case 0: /* Nothing left to add */
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* jhash2 - hash an array of u32's
|
||||
* @k: the key which must be an array of u32's
|
||||
* @length: the number of u32's in the key
|
||||
* @initval: the previous hash, or an arbitray value
|
||||
*
|
||||
* Returns the hash value of the key.
|
||||
*/
|
||||
static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
|
||||
{
|
||||
u32 a, b, c;
|
||||
|
||||
/* Set up the internal state */
|
||||
a = b = c = JHASH_INITVAL + (length<<2) + initval;
|
||||
|
||||
/* Handle most of the key */
|
||||
while (length > 3) {
|
||||
a += k[0];
|
||||
b += k[1];
|
||||
c += k[2];
|
||||
__jhash_mix(a, b, c);
|
||||
length -= 3;
|
||||
k += 3;
|
||||
}
|
||||
|
||||
/* Handle the last 3 u32's: all the case statements fall through */
|
||||
switch (length) {
|
||||
case 3: c += k[2];
|
||||
case 2: b += k[1];
|
||||
case 1: a += k[0];
|
||||
__jhash_final(a, b, c);
|
||||
case 0: /* Nothing left to add */
|
||||
break;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/* jhash_3words - hash exactly 3, 2 or 1 word(s) */
|
||||
static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
|
||||
{
|
||||
a += JHASH_INITVAL;
|
||||
b += JHASH_INITVAL;
|
||||
c += initval;
|
||||
|
||||
__jhash_final(a, b, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline u32 jhash_2words(u32 a, u32 b, u32 initval)
|
||||
{
|
||||
return jhash_3words(a, b, 0, initval);
|
||||
}
|
||||
|
||||
static inline u32 jhash_1word(u32 a, u32 initval)
|
||||
{
|
||||
return jhash_3words(a, 0, 0, initval);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_JHASH_H */
|
||||
@@ -1,588 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <assert.h> /* assert */
|
||||
#include <arpa/inet.h> /* ntoh* */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* memset */
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* IPSET_MAXNAMELEN */
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/types.h> /* struct ipset_type */
|
||||
#include <libipset/utils.h> /* inXcpy */
|
||||
#include <libipset/data.h> /* prototypes */
|
||||
|
||||
/* Internal data structure to hold
|
||||
* a) input data entered by the user or
|
||||
* b) data received from kernel
|
||||
*
|
||||
* We always store the data in host order, *except* IP addresses.
|
||||
*/
|
||||
|
||||
struct ipset_data {
|
||||
/* Option bits: which fields are set */
|
||||
uint64_t bits;
|
||||
/* Option bits: which options are ignored */
|
||||
uint64_t ignored;
|
||||
/* Setname */
|
||||
char setname[IPSET_MAXNAMELEN];
|
||||
/* Set type */
|
||||
const struct ipset_type *type;
|
||||
/* Common CADT options */
|
||||
uint8_t cidr;
|
||||
uint8_t family;
|
||||
uint32_t flags; /* command level flags */
|
||||
uint32_t cadt_flags; /* data level flags */
|
||||
uint32_t timeout;
|
||||
union nf_inet_addr ip;
|
||||
union nf_inet_addr ip_to;
|
||||
uint16_t port;
|
||||
uint16_t port_to;
|
||||
union {
|
||||
/* RENAME/SWAP */
|
||||
char setname2[IPSET_MAXNAMELEN];
|
||||
/* CREATE/LIST/SAVE */
|
||||
struct {
|
||||
uint8_t probes;
|
||||
uint8_t resize;
|
||||
uint8_t netmask;
|
||||
uint32_t hashsize;
|
||||
uint32_t maxelem;
|
||||
uint32_t gc;
|
||||
uint32_t size;
|
||||
/* Filled out by kernel */
|
||||
uint32_t references;
|
||||
uint32_t elements;
|
||||
uint32_t memsize;
|
||||
char typename[IPSET_MAXNAMELEN];
|
||||
uint8_t revision_min;
|
||||
uint8_t revision;
|
||||
} create;
|
||||
/* ADT/LIST/SAVE */
|
||||
struct {
|
||||
union nf_inet_addr ip2;
|
||||
union nf_inet_addr ip2_to;
|
||||
uint8_t cidr2;
|
||||
uint8_t proto;
|
||||
char ether[ETH_ALEN];
|
||||
char name[IPSET_MAXNAMELEN];
|
||||
char nameref[IPSET_MAXNAMELEN];
|
||||
char iface[IFNAMSIZ];
|
||||
} adt;
|
||||
};
|
||||
};
|
||||
|
||||
static void
|
||||
copy_addr(uint8_t family, union nf_inet_addr *ip, const void *value)
|
||||
{
|
||||
if (family == NFPROTO_IPV4)
|
||||
in4cpy(&ip->in, value);
|
||||
else
|
||||
in6cpy(&ip->in6, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_strlcpy - copy the string from src to dst
|
||||
* @dst: the target string buffer
|
||||
* @src: the source string buffer
|
||||
* @len: the length of bytes to copy, including the terminating null byte.
|
||||
*
|
||||
* Copy the string from src to destination, but at most len bytes are
|
||||
* copied. The target is unconditionally terminated by the null byte.
|
||||
*/
|
||||
void
|
||||
ipset_strlcpy(char *dst, const char *src, size_t len)
|
||||
{
|
||||
assert(dst);
|
||||
assert(src);
|
||||
|
||||
strncpy(dst, src, len);
|
||||
dst[len - 1] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_flags_test - test option bits in the data blob
|
||||
* @data: data blob
|
||||
* @flags: the option flags to test
|
||||
*
|
||||
* Returns true if the options are already set in the data blob.
|
||||
*/
|
||||
bool
|
||||
ipset_data_flags_test(const struct ipset_data *data, uint64_t flags)
|
||||
{
|
||||
assert(data);
|
||||
return !!(data->bits & flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_flags_set - set option bits in the data blob
|
||||
* @data: data blob
|
||||
* @flags: the option flags to set
|
||||
*
|
||||
* The function sets the flags in the data blob so that
|
||||
* the corresponding fields are regarded as if filled with proper data.
|
||||
*/
|
||||
void
|
||||
ipset_data_flags_set(struct ipset_data *data, uint64_t flags)
|
||||
{
|
||||
assert(data);
|
||||
data->bits |= flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_flags_unset - unset option bits in the data blob
|
||||
* @data: data blob
|
||||
* @flags: the option flags to unset
|
||||
*
|
||||
* The function unsets the flags in the data blob.
|
||||
* This is the quick way to clear specific fields.
|
||||
*/
|
||||
void
|
||||
ipset_data_flags_unset(struct ipset_data *data, uint64_t flags)
|
||||
{
|
||||
assert(data);
|
||||
data->bits &= ~flags;
|
||||
}
|
||||
|
||||
#define flag_type_attr(data, opt, flag) \
|
||||
do { \
|
||||
data->flags |= flag; \
|
||||
opt = IPSET_OPT_FLAGS; \
|
||||
} while (0)
|
||||
|
||||
#define cadt_flag_type_attr(data, opt, flag) \
|
||||
do { \
|
||||
data->cadt_flags |= flag; \
|
||||
opt = IPSET_OPT_CADT_FLAGS; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* ipset_data_ignored - test and set ignored bits in the data blob
|
||||
* @data: data blob
|
||||
* @flags: the option flag to be ignored
|
||||
*
|
||||
* Returns true if the option was not already ignored.
|
||||
*/
|
||||
bool
|
||||
ipset_data_ignored(struct ipset_data *data, enum ipset_opt opt)
|
||||
{
|
||||
bool ignored;
|
||||
assert(data);
|
||||
|
||||
ignored = data->ignored & IPSET_FLAG(opt);
|
||||
data->ignored |= IPSET_FLAG(opt);
|
||||
|
||||
return ignored;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_set - put data into the data blob
|
||||
* @data: data blob
|
||||
* @opt: the option kind of the data
|
||||
* @value: the value of the data
|
||||
*
|
||||
* Put a given kind of data into the data blob and mark the
|
||||
* option kind as already set in the blob.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
{
|
||||
assert(data);
|
||||
assert(opt != IPSET_OPT_NONE);
|
||||
assert(value);
|
||||
|
||||
switch (opt) {
|
||||
/* Common ones */
|
||||
case IPSET_SETNAME:
|
||||
ipset_strlcpy(data->setname, value, IPSET_MAXNAMELEN);
|
||||
break;
|
||||
case IPSET_OPT_TYPE:
|
||||
data->type = value;
|
||||
break;
|
||||
case IPSET_OPT_FAMILY:
|
||||
data->family = *(const uint8_t *) value;
|
||||
D("family set to %u", data->family);
|
||||
break;
|
||||
/* CADT options */
|
||||
case IPSET_OPT_IP:
|
||||
if (!(data->family == NFPROTO_IPV4 || data->family == NFPROTO_IPV6))
|
||||
return -1;
|
||||
copy_addr(data->family, &data->ip, value);
|
||||
break;
|
||||
case IPSET_OPT_IP_TO:
|
||||
if (!(data->family == NFPROTO_IPV4 || data->family == NFPROTO_IPV6))
|
||||
return -1;
|
||||
copy_addr(data->family, &data->ip_to, value);
|
||||
break;
|
||||
case IPSET_OPT_CIDR:
|
||||
data->cidr = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_PORT:
|
||||
data->port = *(const uint16_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_PORT_TO:
|
||||
data->port_to = *(const uint16_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_TIMEOUT:
|
||||
data->timeout = *(const uint32_t *) value;
|
||||
break;
|
||||
/* Create-specific options */
|
||||
case IPSET_OPT_GC:
|
||||
data->create.gc = *(const uint32_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_HASHSIZE:
|
||||
data->create.hashsize = *(const uint32_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_MAXELEM:
|
||||
data->create.maxelem = *(const uint32_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_NETMASK:
|
||||
data->create.netmask = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_PROBES:
|
||||
data->create.probes = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_RESIZE:
|
||||
data->create.resize = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_SIZE:
|
||||
data->create.size = *(const uint32_t *) value;
|
||||
break;
|
||||
/* Create-specific options, filled out by the kernel */
|
||||
case IPSET_OPT_ELEMENTS:
|
||||
data->create.elements = *(const uint32_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_REFERENCES:
|
||||
data->create.references = *(const uint32_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_MEMSIZE:
|
||||
data->create.memsize = *(const uint32_t *) value;
|
||||
break;
|
||||
/* Create-specific options, type */
|
||||
case IPSET_OPT_TYPENAME:
|
||||
ipset_strlcpy(data->create.typename, value,
|
||||
IPSET_MAXNAMELEN);
|
||||
break;
|
||||
case IPSET_OPT_REVISION:
|
||||
data->create.revision = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_REVISION_MIN:
|
||||
data->create.revision_min = *(const uint8_t *) value;
|
||||
break;
|
||||
/* ADT-specific options */
|
||||
case IPSET_OPT_ETHER:
|
||||
memcpy(data->adt.ether, value, ETH_ALEN);
|
||||
break;
|
||||
case IPSET_OPT_NAME:
|
||||
ipset_strlcpy(data->adt.name, value, IPSET_MAXNAMELEN);
|
||||
break;
|
||||
case IPSET_OPT_NAMEREF:
|
||||
ipset_strlcpy(data->adt.nameref, value, IPSET_MAXNAMELEN);
|
||||
break;
|
||||
case IPSET_OPT_IP2:
|
||||
if (!(data->family == NFPROTO_IPV4 || data->family == NFPROTO_IPV6))
|
||||
return -1;
|
||||
copy_addr(data->family, &data->adt.ip2, value);
|
||||
break;
|
||||
case IPSET_OPT_IP2_TO:
|
||||
if (!(data->family == NFPROTO_IPV4 || data->family == NFPROTO_IPV6))
|
||||
return -1;
|
||||
copy_addr(data->family, &data->adt.ip2_to, value);
|
||||
break;
|
||||
case IPSET_OPT_CIDR2:
|
||||
data->adt.cidr2 = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_PROTO:
|
||||
data->adt.proto = *(const uint8_t *) value;
|
||||
break;
|
||||
case IPSET_OPT_IFACE:
|
||||
ipset_strlcpy(data->adt.iface, value, IFNAMSIZ);
|
||||
break;
|
||||
/* Swap/rename */
|
||||
case IPSET_OPT_SETNAME2:
|
||||
ipset_strlcpy(data->setname2, value, IPSET_MAXNAMELEN);
|
||||
break;
|
||||
/* flags */
|
||||
case IPSET_OPT_EXIST:
|
||||
flag_type_attr(data, opt, IPSET_FLAG_EXIST);
|
||||
break;
|
||||
case IPSET_OPT_BEFORE:
|
||||
cadt_flag_type_attr(data, opt, IPSET_FLAG_BEFORE);
|
||||
break;
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
cadt_flag_type_attr(data, opt, IPSET_FLAG_PHYSDEV);
|
||||
break;
|
||||
case IPSET_OPT_FLAGS:
|
||||
data->flags = *(const uint32_t *)value;
|
||||
break;
|
||||
case IPSET_OPT_CADT_FLAGS:
|
||||
data->cadt_flags = *(const uint32_t *)value;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
};
|
||||
|
||||
ipset_data_flags_set(data, IPSET_FLAG(opt));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_get - get data from the data blob
|
||||
* @data: data blob
|
||||
* @opt: option kind of the requested data
|
||||
*
|
||||
* Returns the pointer to the requested kind of data from the data blob
|
||||
* if it is set. If the option kind is not set or is an unkown type,
|
||||
* NULL is returned.
|
||||
*/
|
||||
const void *
|
||||
ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
{
|
||||
assert(data);
|
||||
assert(opt != IPSET_OPT_NONE);
|
||||
|
||||
if (!(opt == IPSET_OPT_TYPENAME || ipset_data_test(data, opt)))
|
||||
return NULL;
|
||||
|
||||
switch (opt) {
|
||||
/* Common ones */
|
||||
case IPSET_SETNAME:
|
||||
return data->setname;
|
||||
case IPSET_OPT_TYPE:
|
||||
return data->type;
|
||||
case IPSET_OPT_TYPENAME:
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
return data->type->name;
|
||||
else if (ipset_data_test(data, IPSET_OPT_TYPENAME))
|
||||
return data->create.typename;
|
||||
return NULL;
|
||||
case IPSET_OPT_FAMILY:
|
||||
return &data->family;
|
||||
/* CADT options */
|
||||
case IPSET_OPT_IP:
|
||||
return &data->ip;
|
||||
case IPSET_OPT_IP_TO:
|
||||
return &data->ip_to;
|
||||
case IPSET_OPT_CIDR:
|
||||
return &data->cidr;
|
||||
case IPSET_OPT_PORT:
|
||||
return &data->port;
|
||||
case IPSET_OPT_PORT_TO:
|
||||
return &data->port_to;
|
||||
case IPSET_OPT_TIMEOUT:
|
||||
return &data->timeout;
|
||||
/* Create-specific options */
|
||||
case IPSET_OPT_GC:
|
||||
return &data->create.gc;
|
||||
case IPSET_OPT_HASHSIZE:
|
||||
return &data->create.hashsize;
|
||||
case IPSET_OPT_MAXELEM:
|
||||
return &data->create.maxelem;
|
||||
case IPSET_OPT_NETMASK:
|
||||
return &data->create.netmask;
|
||||
case IPSET_OPT_PROBES:
|
||||
return &data->create.probes;
|
||||
case IPSET_OPT_RESIZE:
|
||||
return &data->create.resize;
|
||||
case IPSET_OPT_SIZE:
|
||||
return &data->create.size;
|
||||
/* Create-specific options, filled out by the kernel */
|
||||
case IPSET_OPT_ELEMENTS:
|
||||
return &data->create.elements;
|
||||
case IPSET_OPT_REFERENCES:
|
||||
return &data->create.references;
|
||||
case IPSET_OPT_MEMSIZE:
|
||||
return &data->create.memsize;
|
||||
/* Create-specific options, TYPE */
|
||||
case IPSET_OPT_REVISION:
|
||||
return &data->create.revision;
|
||||
case IPSET_OPT_REVISION_MIN:
|
||||
return &data->create.revision_min;
|
||||
/* ADT-specific options */
|
||||
case IPSET_OPT_ETHER:
|
||||
return data->adt.ether;
|
||||
case IPSET_OPT_NAME:
|
||||
return data->adt.name;
|
||||
case IPSET_OPT_NAMEREF:
|
||||
return data->adt.nameref;
|
||||
case IPSET_OPT_IP2:
|
||||
return &data->adt.ip2;
|
||||
case IPSET_OPT_IP2_TO:
|
||||
return &data->adt.ip2_to;
|
||||
case IPSET_OPT_CIDR2:
|
||||
return &data->adt.cidr2;
|
||||
case IPSET_OPT_PROTO:
|
||||
return &data->adt.proto;
|
||||
case IPSET_OPT_IFACE:
|
||||
return &data->adt.iface;
|
||||
/* Swap/rename */
|
||||
case IPSET_OPT_SETNAME2:
|
||||
return data->setname2;
|
||||
/* flags */
|
||||
case IPSET_OPT_FLAGS:
|
||||
case IPSET_OPT_EXIST:
|
||||
return &data->flags;
|
||||
case IPSET_OPT_CADT_FLAGS:
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return &data->cadt_flags;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_sizeof - calculates the size of the data type
|
||||
* @opt: option kind of the data
|
||||
* @family: INET family
|
||||
*
|
||||
* Returns the size required to store the given data type.
|
||||
*/
|
||||
size_t
|
||||
ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
|
||||
{
|
||||
assert(opt != IPSET_OPT_NONE);
|
||||
|
||||
switch (opt) {
|
||||
case IPSET_OPT_IP:
|
||||
case IPSET_OPT_IP_TO:
|
||||
case IPSET_OPT_IP2:
|
||||
case IPSET_OPT_IP2_TO:
|
||||
return family == NFPROTO_IPV4 ? sizeof(uint32_t)
|
||||
: sizeof(struct in6_addr);
|
||||
case IPSET_OPT_PORT:
|
||||
case IPSET_OPT_PORT_TO:
|
||||
return sizeof(uint16_t);
|
||||
case IPSET_SETNAME:
|
||||
case IPSET_OPT_NAME:
|
||||
case IPSET_OPT_NAMEREF:
|
||||
return IPSET_MAXNAMELEN;
|
||||
case IPSET_OPT_TIMEOUT:
|
||||
case IPSET_OPT_GC:
|
||||
case IPSET_OPT_HASHSIZE:
|
||||
case IPSET_OPT_MAXELEM:
|
||||
case IPSET_OPT_SIZE:
|
||||
case IPSET_OPT_ELEMENTS:
|
||||
case IPSET_OPT_REFERENCES:
|
||||
case IPSET_OPT_MEMSIZE:
|
||||
return sizeof(uint32_t);
|
||||
case IPSET_OPT_CIDR:
|
||||
case IPSET_OPT_CIDR2:
|
||||
case IPSET_OPT_NETMASK:
|
||||
case IPSET_OPT_PROBES:
|
||||
case IPSET_OPT_RESIZE:
|
||||
case IPSET_OPT_PROTO:
|
||||
return sizeof(uint8_t);
|
||||
case IPSET_OPT_ETHER:
|
||||
return ETH_ALEN;
|
||||
/* Flags doesn't counted once :-( */
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return sizeof(uint32_t);
|
||||
default:
|
||||
return 0;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_setname - return the name of the set from the data blob
|
||||
* @data: data blob
|
||||
*
|
||||
* Return the name of the set from the data blob or NULL if the
|
||||
* name not set yet.
|
||||
*/
|
||||
const char *
|
||||
ipset_data_setname(const struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
return ipset_data_test(data, IPSET_SETNAME) ? data->setname : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_family - return the INET family of the set from the data blob
|
||||
* @data: data blob
|
||||
*
|
||||
* Return the INET family supported by the set from the data blob.
|
||||
* If the family is not set yet, NFPROTO_UNSPEC is returned.
|
||||
*/
|
||||
uint8_t
|
||||
ipset_data_family(const struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
return ipset_data_test(data, IPSET_OPT_FAMILY)
|
||||
? data->family : NFPROTO_UNSPEC;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_cidr - return the value of IPSET_OPT_CIDR
|
||||
* @data: data blob
|
||||
*
|
||||
* Return the value of IPSET_OPT_CIDR stored in the data blob.
|
||||
* If it is not set, then the returned value corresponds to
|
||||
* the default one according to the family type or zero.
|
||||
*/
|
||||
uint8_t
|
||||
ipset_data_cidr(const struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
return ipset_data_test(data, IPSET_OPT_CIDR) ? data->cidr :
|
||||
data->family == NFPROTO_IPV4 ? 32 :
|
||||
data->family == NFPROTO_IPV6 ? 128 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_flags - return which fields are set in the data blob
|
||||
* @data: data blob
|
||||
*
|
||||
* Returns the value of the bit field which elements are set.
|
||||
*/
|
||||
uint64_t
|
||||
ipset_data_flags(const struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
return data->bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_reset - reset the data blob to unset
|
||||
* @data: data blob
|
||||
*
|
||||
* Resets the data blob to the unset state for every field.
|
||||
*/
|
||||
void
|
||||
ipset_data_reset(struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
memset(data, 0, sizeof(*data));
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_init - create a new data blob
|
||||
*
|
||||
* Return the new data blob initialized to empty. In case of
|
||||
* an error, NULL is retured.
|
||||
*/
|
||||
struct ipset_data *
|
||||
ipset_data_init(void)
|
||||
{
|
||||
return calloc(1, sizeof(struct ipset_data));
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_data_fini - release a data blob created by ipset_data_init
|
||||
*
|
||||
* Release the data blob created by ipset_data_init previously.
|
||||
*/
|
||||
void
|
||||
ipset_data_fini(struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
free(data);
|
||||
}
|
||||
@@ -1,288 +0,0 @@
|
||||
/* Copyright 2011 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h> /* inet_ntop */
|
||||
#include <libmnl/libmnl.h> /* libmnl backend */
|
||||
|
||||
struct ipset_attrname {
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static const struct ipset_attrname cmdattr2name[] = {
|
||||
[IPSET_ATTR_PROTOCOL] = { .name = "PROTOCOL" },
|
||||
[IPSET_ATTR_SETNAME] = { .name = "SETNAME" },
|
||||
[IPSET_ATTR_TYPENAME] = { .name = "TYPENAME" },
|
||||
[IPSET_ATTR_REVISION] = { .name = "REVISION" },
|
||||
[IPSET_ATTR_FAMILY] = { .name = "FAMILY" },
|
||||
[IPSET_ATTR_FLAGS] = { .name = "FLAGS" },
|
||||
[IPSET_ATTR_DATA] = { .name = "DATA" },
|
||||
[IPSET_ATTR_ADT] = { .name = "ADT" },
|
||||
[IPSET_ATTR_LINENO] = { .name = "LINENO" },
|
||||
[IPSET_ATTR_PROTOCOL_MIN] = { .name = "PROTO_MIN" },
|
||||
};
|
||||
|
||||
static const struct ipset_attrname createattr2name[] = {
|
||||
[IPSET_ATTR_IP] = { .name = "IP" },
|
||||
[IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
|
||||
[IPSET_ATTR_CIDR] = { .name = "CIDR" },
|
||||
[IPSET_ATTR_PORT] = { .name = "PORT" },
|
||||
[IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
|
||||
[IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
|
||||
[IPSET_ATTR_PROTO] = { .name = "PROTO" },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
|
||||
[IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
|
||||
[IPSET_ATTR_GC] = { .name = "GC" },
|
||||
[IPSET_ATTR_HASHSIZE] = { .name = "HASHSIZE" },
|
||||
[IPSET_ATTR_MAXELEM] = { .name = "MAXELEM" },
|
||||
[IPSET_ATTR_NETMASK] = { .name = "NETMASK" },
|
||||
[IPSET_ATTR_PROBES] = { .name = "PROBES" },
|
||||
[IPSET_ATTR_RESIZE] = { .name = "RESIZE" },
|
||||
[IPSET_ATTR_SIZE] = { .name = "SIZE" },
|
||||
[IPSET_ATTR_ELEMENTS] = { .name = "ELEMENTS" },
|
||||
[IPSET_ATTR_REFERENCES] = { .name = "REFERENCES" },
|
||||
[IPSET_ATTR_MEMSIZE] = { .name = "MEMSIZE" },
|
||||
};
|
||||
|
||||
static const struct ipset_attrname adtattr2name[] = {
|
||||
[IPSET_ATTR_IP] = { .name = "IP" },
|
||||
[IPSET_ATTR_IP_TO] = { .name = "IP_TO" },
|
||||
[IPSET_ATTR_CIDR] = { .name = "CIDR" },
|
||||
[IPSET_ATTR_PORT] = { .name = "PORT" },
|
||||
[IPSET_ATTR_PORT_TO] = { .name = "PORT_TO" },
|
||||
[IPSET_ATTR_TIMEOUT] = { .name = "TIMEOUT" },
|
||||
[IPSET_ATTR_PROTO] = { .name = "PROTO" },
|
||||
[IPSET_ATTR_CADT_FLAGS] = { .name = "CADT_FLAGS" },
|
||||
[IPSET_ATTR_CADT_LINENO] = { .name = "CADT_LINENO" },
|
||||
[IPSET_ATTR_ETHER] = { .name = "ETHER" },
|
||||
[IPSET_ATTR_NAME] = { .name = "NAME" },
|
||||
[IPSET_ATTR_NAMEREF] = { .name = "NAMEREF" },
|
||||
[IPSET_ATTR_IP2] = { .name = "IP2" },
|
||||
[IPSET_ATTR_CIDR2] = { .name = "CIDR2" },
|
||||
[IPSET_ATTR_IP2_TO] = { .name = "IP2_TO" },
|
||||
[IPSET_ATTR_IFACE] = { .name = "IFACE" },
|
||||
};
|
||||
|
||||
static void
|
||||
debug_cadt_attrs(int max, const struct ipset_attr_policy *policy,
|
||||
const struct ipset_attrname attr2name[],
|
||||
struct nlattr *nla[])
|
||||
{
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "\t\t%s attributes:\n",
|
||||
policy == create_attrs ? "CREATE" : "ADT");
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= max; i++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (policy[i].type) {
|
||||
case MNL_TYPE_U8:
|
||||
v = *(uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, v);
|
||||
break;
|
||||
case MNL_TYPE_U16:
|
||||
v = *(uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, ntohs(v));
|
||||
break;
|
||||
case MNL_TYPE_U32:
|
||||
v = *(uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t\t%s: %u\n",
|
||||
attr2name[i].name, ntohl(v));
|
||||
break;
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name,
|
||||
(const char *) mnl_attr_get_payload(nla[i]));
|
||||
break;
|
||||
case MNL_TYPE_NESTED: {
|
||||
struct nlattr *ipattr[IPSET_ATTR_IPADDR_MAX+1] = {};
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
void *d;
|
||||
|
||||
if (mnl_attr_parse_nested(nla[i], ipaddr_attr_cb,
|
||||
ipattr) < 0) {
|
||||
fprintf(stderr,
|
||||
"\t\tIPADDR: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
if (ipattr[IPSET_ATTR_IPADDR_IPV4]) {
|
||||
d = mnl_attr_get_payload(
|
||||
ipattr[IPSET_ATTR_IPADDR_IPV4]);
|
||||
|
||||
inet_ntop(NFPROTO_IPV4, d, addr, INET6_ADDRSTRLEN);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name, addr);
|
||||
} else if (ipattr[IPSET_ATTR_IPADDR_IPV6]) {
|
||||
d = mnl_attr_get_payload(
|
||||
ipattr[IPSET_ATTR_IPADDR_IPV6]);
|
||||
|
||||
inet_ntop(NFPROTO_IPV6, d, addr, INET6_ADDRSTRLEN);
|
||||
fprintf(stderr, "\t\t%s: %s\n",
|
||||
attr2name[i].name, addr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "\t\t%s: unresolved!\n",
|
||||
attr2name[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
debug_cmd_attrs(int cmd, struct nlattr *nla[])
|
||||
{
|
||||
struct nlattr *adt[IPSET_ATTR_ADT_MAX+1] = {};
|
||||
struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
uint32_t v;
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "\tCommand attributes:\n");
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_CMD_MAX; i++) {
|
||||
if (!nla[i])
|
||||
continue;
|
||||
switch (cmd_attrs[i].type) {
|
||||
case MNL_TYPE_U8:
|
||||
v = *(uint8_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, v);
|
||||
break;
|
||||
case MNL_TYPE_U16:
|
||||
v = *(uint16_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, ntohs(v));
|
||||
break;
|
||||
case MNL_TYPE_U32:
|
||||
v = *(uint32_t *) mnl_attr_get_payload(nla[i]);
|
||||
fprintf(stderr, "\t%s: %u\n",
|
||||
cmdattr2name[i].name, ntohl(v));
|
||||
break;
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
fprintf(stderr, "\t%s: %s\n",
|
||||
cmdattr2name[i].name,
|
||||
(const char *) mnl_attr_get_payload(nla[i]));
|
||||
break;
|
||||
case MNL_TYPE_NESTED:
|
||||
if (i == IPSET_ATTR_DATA) {
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_ADD:
|
||||
case IPSET_CMD_DEL:
|
||||
case IPSET_CMD_TEST:
|
||||
if (mnl_attr_parse_nested(nla[i],
|
||||
adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tADT: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
adt_attrs,
|
||||
adtattr2name,
|
||||
adt);
|
||||
break;
|
||||
default:
|
||||
if (mnl_attr_parse_nested(nla[i],
|
||||
create_attr_cb,
|
||||
cattr) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tCREATE: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_CREATE_MAX,
|
||||
create_attrs,
|
||||
createattr2name,
|
||||
cattr);
|
||||
}
|
||||
} else {
|
||||
struct nlattr *tb;
|
||||
mnl_attr_for_each_nested(tb, nla[i]) {
|
||||
memset(adt, 0, sizeof(adt));
|
||||
if (mnl_attr_parse_nested(tb,
|
||||
adt_attr_cb, adt) < 0) {
|
||||
fprintf(stderr,
|
||||
"\tADT: cannot validate "
|
||||
"and parse attributes\n");
|
||||
continue;
|
||||
}
|
||||
debug_cadt_attrs(IPSET_ATTR_ADT_MAX,
|
||||
adt_attrs,
|
||||
adtattr2name,
|
||||
adt);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "\t%s: unresolved!\n",
|
||||
cmdattr2name[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ipset_debug_msg(const char *dir, void *buffer, int len)
|
||||
{
|
||||
const struct nlmsghdr *nlh = buffer;
|
||||
struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
|
||||
int cmd, nfmsglen = MNL_ALIGN(sizeof(struct nfgenmsg));
|
||||
|
||||
debug = 0;
|
||||
while (mnl_nlmsg_ok(nlh, len)) {
|
||||
switch (nlh->nlmsg_type) {
|
||||
case NLMSG_NOOP:
|
||||
case NLMSG_DONE:
|
||||
case NLMSG_OVERRUN:
|
||||
fprintf(stderr, "Message header: %s msg %s\n"
|
||||
"\tlen %d\n"
|
||||
"\tseq %u\n",
|
||||
dir,
|
||||
nlh->nlmsg_type == NLMSG_NOOP ? "NOOP" :
|
||||
nlh->nlmsg_type == NLMSG_DONE ? "DONE" :
|
||||
"OVERRUN",
|
||||
len, nlh->nlmsg_seq);
|
||||
goto next_msg;
|
||||
case NLMSG_ERROR: {
|
||||
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
|
||||
fprintf(stderr, "Message header: %s msg ERROR\n"
|
||||
"\tlen %d\n"
|
||||
"\terrcode %d\n"
|
||||
"\tseq %u\n",
|
||||
dir, len, err->error, nlh->nlmsg_seq);
|
||||
goto next_msg;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
cmd = ipset_get_nlmsg_type(nlh);
|
||||
fprintf(stderr, "Message header: %s cmd %s (%d)\n"
|
||||
"\tlen %d\n"
|
||||
"\tflag %s\n"
|
||||
"\tseq %u\n",
|
||||
dir,
|
||||
cmd <= IPSET_CMD_NONE ? "NONE!" :
|
||||
cmd >= IPSET_CMD_MAX ? "MAX!" : cmd2name[cmd], cmd,
|
||||
len,
|
||||
!(nlh->nlmsg_flags & NLM_F_EXCL) ? "EXIST" : "none",
|
||||
nlh->nlmsg_seq);
|
||||
if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_CMD_MAX)
|
||||
goto next_msg;
|
||||
memset(nla, 0, sizeof(nla));
|
||||
if (mnl_attr_parse(nlh, nfmsglen,
|
||||
cmd_attr_cb, nla) < MNL_CB_STOP) {
|
||||
fprintf(stderr, "\tcannot validate "
|
||||
"and parse attributes\n");
|
||||
goto next_msg;
|
||||
}
|
||||
debug_cmd_attrs(cmd, nla);
|
||||
next_msg:
|
||||
nlh = mnl_nlmsg_next(nlh, &len);
|
||||
}
|
||||
debug = 1;
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <assert.h> /* assert */
|
||||
#include <errno.h> /* errno */
|
||||
#include <string.h> /* strerror */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* ipset_data_get */
|
||||
#include <libipset/session.h> /* ipset_err */
|
||||
#include <libipset/types.h> /* struct ipset_type */
|
||||
#include <libipset/utils.h> /* STRNEQ */
|
||||
#include <libipset/errcode.h> /* prototypes */
|
||||
#include <libipset/linux_ip_set_bitmap.h> /* bitmap specific errcodes */
|
||||
#include <libipset/linux_ip_set_hash.h> /* hash specific errcodes */
|
||||
#include <libipset/linux_ip_set_list.h> /* list specific errcodes */
|
||||
|
||||
/* Core kernel error codes */
|
||||
static const struct ipset_errcode_table core_errcode_table[] = {
|
||||
/* Generic error codes */
|
||||
{ ENOENT, 0,
|
||||
"The set with the given name does not exist" },
|
||||
{ EMSGSIZE, 0,
|
||||
"Kernel error received: message could not be created" },
|
||||
{ IPSET_ERR_PROTOCOL, 0,
|
||||
"Kernel error received: ipset protocol error" },
|
||||
|
||||
/* CREATE specific error codes */
|
||||
{ EEXIST, IPSET_CMD_CREATE,
|
||||
"Set cannot be created: set with the same name already exists" },
|
||||
{ IPSET_ERR_FIND_TYPE, 0,
|
||||
"Kernel error received: set type not supported" },
|
||||
{ IPSET_ERR_MAX_SETS, 0,
|
||||
"Kernel error received: maximal number of sets reached, "
|
||||
"cannot create more." },
|
||||
{ IPSET_ERR_INVALID_NETMASK, 0,
|
||||
"The value of the netmask parameter is invalid" },
|
||||
{ IPSET_ERR_INVALID_FAMILY, 0,
|
||||
"Protocol family not supported by the set type" },
|
||||
|
||||
/* DESTROY specific error codes */
|
||||
{ IPSET_ERR_BUSY, IPSET_CMD_DESTROY,
|
||||
"Set cannot be destroyed: it is in use by a kernel component" },
|
||||
|
||||
/* FLUSH specific error codes */
|
||||
|
||||
/* RENAME specific error codes */
|
||||
{ IPSET_ERR_EXIST_SETNAME2, IPSET_CMD_RENAME,
|
||||
"Set cannot be renamed: a set with the new name already exists" },
|
||||
{ IPSET_ERR_REFERENCED, IPSET_CMD_RENAME,
|
||||
"Set cannot be renamed: it is in use by another system" },
|
||||
|
||||
/* SWAP specific error codes */
|
||||
{ IPSET_ERR_EXIST_SETNAME2, IPSET_CMD_SWAP,
|
||||
"Sets cannot be swapped: the second set does not exist" },
|
||||
{ IPSET_ERR_TYPE_MISMATCH, IPSET_CMD_SWAP,
|
||||
"The sets cannot be swapped: they type does not match" },
|
||||
|
||||
/* LIST/SAVE specific error codes */
|
||||
|
||||
/* Generic (CADT) error codes */
|
||||
{ IPSET_ERR_INVALID_CIDR, 0,
|
||||
"The value of the CIDR parameter of the IP address is invalid" },
|
||||
{ IPSET_ERR_TIMEOUT, 0,
|
||||
"Timeout cannot be used: set was created without timeout support" },
|
||||
{ IPSET_ERR_IPADDR_IPV4, 0,
|
||||
"An IPv4 address is expected, but not received" },
|
||||
{ IPSET_ERR_IPADDR_IPV6, 0,
|
||||
"An IPv6 address is expected, but not received" },
|
||||
|
||||
/* ADD specific error codes */
|
||||
{ IPSET_ERR_EXIST, IPSET_CMD_ADD,
|
||||
"Element cannot be added to the set: it's already added" },
|
||||
|
||||
/* DEL specific error codes */
|
||||
{ IPSET_ERR_EXIST, IPSET_CMD_DEL,
|
||||
"Element cannot be deleted from the set: it's not added" },
|
||||
|
||||
/* TEST specific error codes */
|
||||
|
||||
/* HEADER specific error codes */
|
||||
|
||||
/* TYPE specific error codes */
|
||||
{ EEXIST, IPSET_CMD_TYPE,
|
||||
"Kernel error received: set type does not supported" },
|
||||
|
||||
/* PROTOCOL specific error codes */
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
/* Bitmap type-specific error codes */
|
||||
static const struct ipset_errcode_table bitmap_errcode_table[] = {
|
||||
/* Generic (CADT) error codes */
|
||||
{ IPSET_ERR_BITMAP_RANGE, 0,
|
||||
"Element is out of the range of the set" },
|
||||
{ IPSET_ERR_BITMAP_RANGE_SIZE, IPSET_CMD_CREATE,
|
||||
"The range you specified exceeds the size limit of the set type" },
|
||||
{ },
|
||||
};
|
||||
|
||||
/* Hash type-specific error codes */
|
||||
static const struct ipset_errcode_table hash_errcode_table[] = {
|
||||
/* Generic (CADT) error codes */
|
||||
{ IPSET_ERR_HASH_FULL, 0,
|
||||
"Hash is full, cannot add more elements" },
|
||||
{ IPSET_ERR_HASH_ELEM, 0,
|
||||
"Null-valued element, cannot be stored in a hash type of set" },
|
||||
{ IPSET_ERR_INVALID_PROTO, 0,
|
||||
"Invalid protocol specified" },
|
||||
{ IPSET_ERR_MISSING_PROTO, 0,
|
||||
"Protocol missing, but must be specified" },
|
||||
{ IPSET_ERR_HASH_RANGE_UNSUPPORTED, 0,
|
||||
"Range is not supported in the \"net\" component of the element" },
|
||||
{ IPSET_ERR_HASH_RANGE, 0,
|
||||
"Invalid range, covers the whole address space" },
|
||||
{ },
|
||||
};
|
||||
|
||||
/* List type-specific error codes */
|
||||
static const struct ipset_errcode_table list_errcode_table[] = {
|
||||
/* Generic (CADT) error codes */
|
||||
{ IPSET_ERR_NAME, 0,
|
||||
"Set to be added/deleted/tested as element does not exist." },
|
||||
{ IPSET_ERR_LOOP, 0,
|
||||
"Sets with list:set type cannot be added to the set." },
|
||||
{ IPSET_ERR_BEFORE, 0,
|
||||
"No reference set specified." },
|
||||
{ IPSET_ERR_NAMEREF, 0,
|
||||
"The set to which you referred with 'before' or 'after' "
|
||||
"does not exist." },
|
||||
{ IPSET_ERR_LIST_FULL, 0,
|
||||
"The set is full, more elements cannot be added." },
|
||||
{ IPSET_ERR_REF_EXIST, 0,
|
||||
"The set to which you referred with 'before' or 'after' "
|
||||
"is not added to the set." },
|
||||
{ },
|
||||
};
|
||||
|
||||
#define MATCH_TYPENAME(a, b) STRNEQ(a, b, strlen(b))
|
||||
|
||||
/**
|
||||
* ipset_errcode - interpret a kernel error code
|
||||
* @session: session structure
|
||||
* @errcode: errcode
|
||||
*
|
||||
* Find the error code and print the appropriate
|
||||
* error message into the error buffer.
|
||||
*
|
||||
* Returns -1.
|
||||
*/
|
||||
int
|
||||
ipset_errcode(struct ipset_session *session, enum ipset_cmd cmd, int errcode)
|
||||
{
|
||||
const struct ipset_errcode_table *table = core_errcode_table;
|
||||
int i, generic;
|
||||
|
||||
if (errcode >= IPSET_ERR_TYPE_SPECIFIC) {
|
||||
const struct ipset_type *type;
|
||||
|
||||
type = ipset_saved_type(session);
|
||||
if (type) {
|
||||
if (MATCH_TYPENAME(type->name, "bitmap:"))
|
||||
table = bitmap_errcode_table;
|
||||
else if (MATCH_TYPENAME(type->name, "hash:"))
|
||||
table = hash_errcode_table;
|
||||
else if (MATCH_TYPENAME(type->name, "list:"))
|
||||
table = list_errcode_table;
|
||||
}
|
||||
}
|
||||
|
||||
retry:
|
||||
for (i = 0, generic = -1; table[i].errcode; i++) {
|
||||
if (table[i].errcode == errcode &&
|
||||
(table[i].cmd == cmd || table[i].cmd == 0)) {
|
||||
if (table[i].cmd == 0) {
|
||||
generic = i;
|
||||
continue;
|
||||
}
|
||||
return ipset_err(session, table[i].message);
|
||||
}
|
||||
}
|
||||
if (generic != -1)
|
||||
return ipset_err(session, table[generic].message);
|
||||
/* Fall back to the core table */
|
||||
if (table != core_errcode_table) {
|
||||
table = core_errcode_table;
|
||||
goto retry;
|
||||
}
|
||||
if (errcode < IPSET_ERR_PRIVATE)
|
||||
return ipset_err(session, "Kernel error received: %s",
|
||||
strerror(errcode));
|
||||
else
|
||||
return ipset_err(session,
|
||||
"Undecoded error %u received from kernel",
|
||||
errcode);
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/utils.h> /* STRNEQ */
|
||||
#include <libipset/icmp.h> /* prototypes */
|
||||
|
||||
struct icmp_names {
|
||||
const char *name;
|
||||
uint8_t type, code;
|
||||
};
|
||||
|
||||
static const struct icmp_names icmp_typecodes[] = {
|
||||
{ "echo-reply", 0, 0 },
|
||||
{ "pong", 0, 0 },
|
||||
{ "network-unreachable", 3, 0 },
|
||||
{ "host-unreachable", 3, 1 },
|
||||
{ "protocol-unreachable", 3, 2 },
|
||||
{ "port-unreachable", 3, 3 },
|
||||
{ "fragmentation-needed", 3, 4 },
|
||||
{ "source-route-failed", 3, 5 },
|
||||
{ "network-unknown", 3, 6 },
|
||||
{ "host-unknown", 3, 7 },
|
||||
{ "network-prohibited", 3, 9 },
|
||||
{ "host-prohibited", 3, 10 },
|
||||
{ "TOS-network-unreachable", 3, 11 },
|
||||
{ "TOS-host-unreachable", 3, 12 },
|
||||
{ "communication-prohibited", 3, 13 },
|
||||
{ "host-precedence-violation", 3, 14 },
|
||||
{ "precedence-cutoff", 3, 15 },
|
||||
{ "source-quench", 4, 0 },
|
||||
{ "network-redirect", 5, 0 },
|
||||
{ "host-redirect", 5, 1 },
|
||||
{ "TOS-network-redirect", 5, 2 },
|
||||
{ "TOS-host-redirect", 5, 3 },
|
||||
{ "echo-request", 8, 0 },
|
||||
{ "ping", 8, 0 },
|
||||
{ "router-advertisement", 9, 0 },
|
||||
{ "router-solicitation", 10, 0 },
|
||||
{ "ttl-zero-during-transit", 11, 0 },
|
||||
{ "ttl-zero-during-reassembly", 11, 1 },
|
||||
{ "ip-header-bad", 12, 0 },
|
||||
{ "required-option-missing", 12, 1 },
|
||||
{ "timestamp-request", 13, 0 },
|
||||
{ "timestamp-reply", 14, 0 },
|
||||
{ "address-mask-request", 17, 0 },
|
||||
{ "address-mask-reply", 18, 0 },
|
||||
};
|
||||
|
||||
const char *id_to_icmp(uint8_t id)
|
||||
{
|
||||
return id < ARRAY_SIZE(icmp_typecodes) ? icmp_typecodes[id].name : NULL;
|
||||
}
|
||||
|
||||
const char *icmp_to_name(uint8_t type, uint8_t code)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++)
|
||||
if (icmp_typecodes[i].type == type &&
|
||||
icmp_typecodes[i].code == code)
|
||||
return icmp_typecodes[i].name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int name_to_icmp(const char *str, uint16_t *typecode)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmp_typecodes); i++)
|
||||
if (STRNCASEQ(icmp_typecodes[i].name, str, strlen(str))) {
|
||||
*typecode = (icmp_typecodes[i].type << 8) |
|
||||
icmp_typecodes[i].code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/utils.h> /* STRNEQ */
|
||||
#include <libipset/icmpv6.h> /* prototypes */
|
||||
|
||||
struct icmpv6_names {
|
||||
const char *name;
|
||||
uint8_t type, code;
|
||||
};
|
||||
|
||||
static const struct icmpv6_names icmpv6_typecodes[] = {
|
||||
{ "no-route", 1, 0 },
|
||||
{ "communication-prohibited", 1, 1 },
|
||||
{ "address-unreachable", 1, 3 },
|
||||
{ "port-unreachable", 1, 4 },
|
||||
{ "packet-too-big", 2, 0 },
|
||||
{ "ttl-zero-during-transit", 3, 0 },
|
||||
{ "ttl-zero-during-reassembly", 3, 1 },
|
||||
{ "bad-header", 4, 0 },
|
||||
{ "unknown-header-type", 4, 1 },
|
||||
{ "unknown-option", 4, 2 },
|
||||
{ "echo-request", 128, 0 },
|
||||
{ "ping", 128, 0 },
|
||||
{ "echo-reply", 129, 0 },
|
||||
{ "pong", 129, 0 },
|
||||
{ "router-solicitation", 133, 0 },
|
||||
{ "router-advertisement", 134, 0 },
|
||||
{ "neighbour-solicitation", 135, 0 },
|
||||
{ "neigbour-solicitation", 135, 0 },
|
||||
{ "neighbour-advertisement", 136, 0 },
|
||||
{ "neigbour-advertisement", 136, 0 },
|
||||
{ "redirect", 137, 0 },
|
||||
};
|
||||
|
||||
const char *id_to_icmpv6(uint8_t id)
|
||||
{
|
||||
return id < ARRAY_SIZE(icmpv6_typecodes) ?
|
||||
icmpv6_typecodes[id].name : NULL;
|
||||
}
|
||||
|
||||
const char *icmpv6_to_name(uint8_t type, uint8_t code)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++)
|
||||
if (icmpv6_typecodes[i].type == type &&
|
||||
icmpv6_typecodes[i].code == code)
|
||||
return icmpv6_typecodes[i].name;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int name_to_icmpv6(const char *str, uint16_t *typecode)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(icmpv6_typecodes); i++)
|
||||
if (STRNCASEQ(icmpv6_typecodes[i].name, str, strlen(str))) {
|
||||
*typecode = (icmpv6_typecodes[i].type << 8) |
|
||||
icmpv6_typecodes[i].code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <assert.h> /* assert */
|
||||
#include <errno.h> /* errno */
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h> /* calloc, free */
|
||||
#include <time.h> /* time */
|
||||
#include <arpa/inet.h> /* hto* */
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* enum ipset_cmd */
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/session.h> /* ipset_session_handle */
|
||||
#include <libipset/ui.h> /* IPSET_ENV_EXIST */
|
||||
#include <libipset/utils.h> /* UNUSED */
|
||||
#include <libipset/mnl.h> /* prototypes */
|
||||
|
||||
#include <libmnl/libmnl.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#ifndef NFNL_SUBSYS_IPSET
|
||||
#define NFNL_SUBSYS_IPSET 6
|
||||
#endif
|
||||
|
||||
/* Internal data structure for the kernel-userspace communication parameters */
|
||||
struct ipset_handle {
|
||||
struct mnl_socket *h; /* the mnl socket */
|
||||
unsigned int seq; /* netlink message sequence number */
|
||||
unsigned int portid; /* the socket port identifier */
|
||||
mnl_cb_t *cb_ctl; /* control block callbacks */
|
||||
void *data; /* data pointer */
|
||||
unsigned int genl_id; /* genetlink ID of ip_set */
|
||||
};
|
||||
|
||||
/* Netlink flags of the commands */
|
||||
static const uint16_t cmdflags[] = {
|
||||
[IPSET_CMD_CREATE-1] = NLM_F_REQUEST|NLM_F_ACK|
|
||||
NLM_F_CREATE|NLM_F_EXCL,
|
||||
[IPSET_CMD_DESTROY-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_SWAP-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_LIST-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_SAVE-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_ADD-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
|
||||
[IPSET_CMD_DEL-1] = NLM_F_REQUEST|NLM_F_ACK|NLM_F_EXCL,
|
||||
[IPSET_CMD_TEST-1] = NLM_F_REQUEST|NLM_F_ACK,
|
||||
[IPSET_CMD_HEADER-1] = NLM_F_REQUEST,
|
||||
[IPSET_CMD_TYPE-1] = NLM_F_REQUEST,
|
||||
[IPSET_CMD_PROTOCOL-1] = NLM_F_REQUEST,
|
||||
};
|
||||
|
||||
/**
|
||||
* ipset_get_nlmsg_type - get ipset netlink message type
|
||||
* @nlh: pointer to the netlink message header
|
||||
*
|
||||
* Returns the ipset netlink message type, i.e. the ipset command.
|
||||
*/
|
||||
int
|
||||
ipset_get_nlmsg_type(const struct nlmsghdr *nlh)
|
||||
{
|
||||
const struct genlmsghdr *ghdr = mnl_nlmsg_get_payload(nlh);
|
||||
|
||||
return ghdr->cmd;
|
||||
}
|
||||
|
||||
static void
|
||||
ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
|
||||
void *buffer, size_t len UNUSED, uint8_t envflags)
|
||||
{
|
||||
struct nlmsghdr *nlh;
|
||||
struct genlmsghdr *ghdr;
|
||||
|
||||
assert(handle);
|
||||
assert(buffer);
|
||||
assert(cmd > IPSET_CMD_NONE && cmd < IPSET_MSG_MAX);
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buffer);
|
||||
nlh->nlmsg_type = handle->genl_id;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
if (cmdflags[cmd-1] & NLM_F_ACK)
|
||||
nlh->nlmsg_flags |= NLM_F_ACK;
|
||||
|
||||
ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||
ghdr->cmd = cmd;
|
||||
/* (ge)netlink is dumb, NLM_F_CREATE and NLM_F_DUMP overlap, get misinterpreted. */
|
||||
ghdr->reserved = cmdflags[cmd-1];
|
||||
if (envflags & IPSET_ENV_EXIST)
|
||||
ghdr->reserved &= ~NLM_F_EXCL;
|
||||
}
|
||||
|
||||
static int
|
||||
ipset_mnl_query(struct ipset_handle *handle, void *buffer, size_t len)
|
||||
{
|
||||
struct nlmsghdr *nlh = buffer;
|
||||
int ret;
|
||||
|
||||
assert(handle);
|
||||
assert(buffer);
|
||||
|
||||
nlh->nlmsg_seq = ++handle->seq;
|
||||
#ifdef IPSET_DEBUG
|
||||
ipset_debug_msg("sent", nlh, nlh->nlmsg_len);
|
||||
#endif
|
||||
if (mnl_socket_sendto(handle->h, nlh, nlh->nlmsg_len) < 0)
|
||||
return -ECOMM;
|
||||
|
||||
ret = mnl_socket_recvfrom(handle->h, buffer, len);
|
||||
#ifdef IPSET_DEBUG
|
||||
ipset_debug_msg("received", buffer, ret);
|
||||
#endif
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run2(buffer, ret,
|
||||
handle->seq, handle->portid,
|
||||
handle->cb_ctl[NLMSG_MIN_TYPE],
|
||||
handle->data,
|
||||
handle->cb_ctl, NLMSG_MIN_TYPE);
|
||||
D("nfln_cb_run2, ret: %d, errno %d", ret, errno);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(handle->h, buffer, len);
|
||||
D("message received, ret: %d", ret);
|
||||
}
|
||||
return ret > 0 ? 0 : ret;
|
||||
}
|
||||
|
||||
static int ipset_mnl_getid_acb(const struct nlattr *attr, void *datap)
|
||||
{
|
||||
const struct nlattr **tb = datap;
|
||||
uint16_t type = mnl_attr_get_type(attr);
|
||||
|
||||
if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
|
||||
return MNL_CB_OK;
|
||||
tb[type] = attr;
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int ipset_mnl_getid_cb(const struct nlmsghdr *nlhdr, void *datap)
|
||||
{
|
||||
struct ipset_handle *h = datap;
|
||||
const struct nlattr *tb[CTRL_ATTR_MAX+1] = {0};
|
||||
const struct genlmsghdr *ghdr = mnl_nlmsg_get_payload(nlhdr);
|
||||
int ret;
|
||||
|
||||
ret = mnl_attr_parse(nlhdr, sizeof(*ghdr), ipset_mnl_getid_acb, tb);
|
||||
if (ret != MNL_CB_OK)
|
||||
return ret;
|
||||
if (tb[CTRL_ATTR_FAMILY_ID] != NULL)
|
||||
h->genl_id = mnl_attr_get_u16(tb[CTRL_ATTR_FAMILY_ID]);
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the GENL identifier for the ip_set subsystem, and store it in
|
||||
* @h->genl_id. On success, 0 is returned, otherwise error encoded as
|
||||
* negative number.
|
||||
*/
|
||||
static int ipset_mnl_getid(struct ipset_handle *h, bool modprobe)
|
||||
{
|
||||
size_t buf_size = 8192; //MNL_SOCKET_BUFFER_SIZE;
|
||||
struct nlmsghdr *nlhdr;
|
||||
struct genlmsghdr *ghdr;
|
||||
char *buf;
|
||||
int ret = -ENOENT;
|
||||
|
||||
h->genl_id = 0;
|
||||
|
||||
if (modprobe) {
|
||||
/* genetlink has no autoloading like nfnetlink... */
|
||||
system("/sbin/modprobe -q ip_set");
|
||||
}
|
||||
|
||||
buf = malloc(buf_size);
|
||||
if (buf == NULL)
|
||||
return -errno;
|
||||
|
||||
nlhdr = mnl_nlmsg_put_header(buf);
|
||||
nlhdr->nlmsg_type = GENL_ID_CTRL;
|
||||
nlhdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
ghdr = mnl_nlmsg_put_extra_header(nlhdr, sizeof(struct genlmsghdr));
|
||||
ghdr->cmd = CTRL_CMD_GETFAMILY;
|
||||
ghdr->version = 2;
|
||||
if (!mnl_attr_put_strz_check(nlhdr, buf_size,
|
||||
CTRL_ATTR_FAMILY_NAME, "ip_set"))
|
||||
goto out;
|
||||
|
||||
ret = mnl_socket_sendto(h->h, buf, nlhdr->nlmsg_len);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
ret = mnl_socket_recvfrom(h->h, buf, buf_size);
|
||||
while (ret > 0) {
|
||||
ret = mnl_cb_run(buf, ret, 0, 0, ipset_mnl_getid_cb, h);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(h->h, buf, buf_size);
|
||||
}
|
||||
if (h->genl_id == 0 && !modprobe)
|
||||
/* Redo, with modprobe this time. */
|
||||
ret = ipset_mnl_getid(h, true);
|
||||
if (h->genl_id > 0)
|
||||
ret = 0;
|
||||
out:
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct ipset_handle *
|
||||
ipset_mnl_init(mnl_cb_t *cb_ctl, void *data)
|
||||
{
|
||||
struct ipset_handle *handle;
|
||||
|
||||
assert(cb_ctl);
|
||||
assert(data);
|
||||
|
||||
handle = calloc(1, sizeof(*handle));
|
||||
if (!handle)
|
||||
return NULL;
|
||||
|
||||
handle->h = mnl_socket_open(NETLINK_GENERIC);
|
||||
if (!handle->h)
|
||||
goto free_handle;
|
||||
|
||||
if (mnl_socket_bind(handle->h, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||
goto close_nl;
|
||||
|
||||
handle->portid = mnl_socket_get_portid(handle->h);
|
||||
handle->cb_ctl = cb_ctl;
|
||||
handle->data = data;
|
||||
handle->seq = time(NULL);
|
||||
|
||||
if (ipset_mnl_getid(handle, false) < 0)
|
||||
goto close_nl;
|
||||
return handle;
|
||||
|
||||
close_nl:
|
||||
mnl_socket_close(handle->h);
|
||||
free_handle:
|
||||
free(handle);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
ipset_mnl_fini(struct ipset_handle *handle)
|
||||
{
|
||||
assert(handle);
|
||||
|
||||
if (handle->h)
|
||||
mnl_socket_close(handle->h);
|
||||
|
||||
free(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ipset_transport ipset_mnl_transport = {
|
||||
.init = ipset_mnl_init,
|
||||
.fini = ipset_mnl_fini,
|
||||
.fill_hdr = ipset_mnl_fill_hdr,
|
||||
.query = ipset_mnl_query,
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,820 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <assert.h> /* assert */
|
||||
#include <errno.h> /* errno */
|
||||
#include <stdio.h> /* snprintf */
|
||||
#include <netdb.h> /* getservbyport */
|
||||
#include <sys/types.h> /* inet_ntop */
|
||||
#include <sys/socket.h> /* inet_ntop */
|
||||
#include <arpa/inet.h> /* inet_ntop */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* ipset_data_* */
|
||||
#include <libipset/icmp.h> /* icmp_to_name */
|
||||
#include <libipset/icmpv6.h> /* icmpv6_to_name */
|
||||
#include <libipset/parse.h> /* IPSET_*_SEPARATOR */
|
||||
#include <libipset/types.h> /* ipset set types */
|
||||
#include <libipset/session.h> /* IPSET_FLAG_ */
|
||||
#include <libipset/utils.h> /* UNUSED */
|
||||
#include <libipset/ui.h> /* IPSET_ENV_* */
|
||||
#include <libipset/print.h> /* prototypes */
|
||||
|
||||
/* Print data (to output buffer). All function must follow snprintf. */
|
||||
|
||||
#define SNPRINTF_FAILURE(size, len, offset) \
|
||||
do { \
|
||||
if (size < 0 || (unsigned int) size >= len) \
|
||||
return size; \
|
||||
offset += size; \
|
||||
len -= size; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* ipset_print_ether - print ethernet address to string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print Ethernet address to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_ether(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const unsigned char *ether;
|
||||
int i, size, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_ETHER);
|
||||
|
||||
if (len < ETH_ALEN*3)
|
||||
return -1;
|
||||
|
||||
ether = ipset_data_get(data, opt);
|
||||
assert(ether);
|
||||
|
||||
size = snprintf(buf, len, "%02X", ether[0]);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
for (i = 1; i < ETH_ALEN; i++) {
|
||||
size = snprintf(buf + offset, len, ":%02X", ether[i]);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_family - print INET family
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print INET family string to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_family(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
uint8_t family;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_FAMILY);
|
||||
|
||||
if (len < strlen("inet6") + 1)
|
||||
return -1;
|
||||
|
||||
family = ipset_data_family(data);
|
||||
|
||||
return snprintf(buf, len, "%s",
|
||||
family == AF_INET ? "inet" :
|
||||
family == AF_INET6 ? "inet6" : "any");
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_type - print ipset type string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print ipset module string identifier to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_type(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const struct ipset_type *type;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_TYPE);
|
||||
|
||||
type = ipset_data_get(data, opt);
|
||||
assert(type);
|
||||
if (len < strlen(type->name) + 1)
|
||||
return -1;
|
||||
|
||||
return snprintf(buf, len, "%s", type->name);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__getnameinfo4(char *buf, unsigned int len,
|
||||
int flags, const union nf_inet_addr *addr)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
int err;
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
in4cpy(&saddr.sin_addr, &addr->in);
|
||||
saddr.sin_family = NFPROTO_IPV4;
|
||||
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0, flags);
|
||||
|
||||
if (!(flags & NI_NUMERICHOST) &&
|
||||
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0,
|
||||
flags | NI_NUMERICHOST);
|
||||
D("getnameinfo err: %i, errno %i", err, errno);
|
||||
return (err == 0 ? (int)strlen(buf) :
|
||||
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__getnameinfo6(char *buf, unsigned int len,
|
||||
int flags, const union nf_inet_addr *addr)
|
||||
{
|
||||
struct sockaddr_in6 saddr;
|
||||
int err;
|
||||
|
||||
memset(&saddr, 0, sizeof(saddr));
|
||||
in6cpy(&saddr.sin6_addr, &addr->in6);
|
||||
saddr.sin6_family = NFPROTO_IPV6;
|
||||
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0, flags);
|
||||
|
||||
if (!(flags & NI_NUMERICHOST) &&
|
||||
(err == EAI_AGAIN || (err == 0 && strchr(buf, '-') != NULL)))
|
||||
err = getnameinfo((const struct sockaddr *)&saddr,
|
||||
sizeof(saddr),
|
||||
buf, len, NULL, 0,
|
||||
flags | NI_NUMERICHOST);
|
||||
D("getnameinfo err: %i, errno %i", err, errno);
|
||||
return (err == 0 ? (int)strlen(buf) :
|
||||
(err == EAI_OVERFLOW || err == EAI_SYSTEM) ? (int)len : -1);
|
||||
}
|
||||
|
||||
#define SNPRINTF_IP(mask, f) \
|
||||
static int \
|
||||
snprintf_ipv##f(char *buf, unsigned int len, int flags, \
|
||||
const union nf_inet_addr *ip, uint8_t cidr) \
|
||||
{ \
|
||||
int size, offset = 0; \
|
||||
\
|
||||
size = __getnameinfo##f(buf, len, flags, ip); \
|
||||
SNPRINTF_FAILURE(size, len, offset); \
|
||||
\
|
||||
D("cidr %u mask %u", cidr, mask); \
|
||||
if (cidr == mask) \
|
||||
return offset; \
|
||||
D("print cidr"); \
|
||||
size = snprintf(buf + offset, len, \
|
||||
"%s%u", IPSET_CIDR_SEPARATOR, cidr); \
|
||||
SNPRINTF_FAILURE(size, len, offset); \
|
||||
return offset; \
|
||||
}
|
||||
|
||||
SNPRINTF_IP(32, 4)
|
||||
|
||||
SNPRINTF_IP(128, 6)
|
||||
|
||||
/**
|
||||
* ipset_print_ip - print IPv4|IPv6 address to string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print IPv4|IPv6 address, address/cidr or address range to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_ip(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env)
|
||||
{
|
||||
const union nf_inet_addr *ip;
|
||||
uint8_t family, cidr;
|
||||
int flags, size, offset = 0;
|
||||
enum ipset_opt cidropt;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
||||
|
||||
D("len: %u", len);
|
||||
family = ipset_data_family(data);
|
||||
cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2;
|
||||
if (ipset_data_test(data, cidropt)) {
|
||||
cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
|
||||
D("CIDR: %u", cidr);
|
||||
} else
|
||||
cidr = family == NFPROTO_IPV6 ? 128 : 32;
|
||||
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
|
||||
ip = ipset_data_get(data, opt);
|
||||
assert(ip);
|
||||
if (family == NFPROTO_IPV4)
|
||||
size = snprintf_ipv4(buf, len, flags, ip, cidr);
|
||||
else if (family == NFPROTO_IPV6)
|
||||
size = snprintf_ipv6(buf, len, flags, ip, cidr);
|
||||
else
|
||||
return -1;
|
||||
D("size %i, len %u", size, len);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
D("len: %u, offset %u", len, offset);
|
||||
if (!ipset_data_test(data, IPSET_OPT_IP_TO))
|
||||
return offset;
|
||||
|
||||
size = snprintf(buf + offset, len, "%s", IPSET_RANGE_SEPARATOR);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
ip = ipset_data_get(data, IPSET_OPT_IP_TO);
|
||||
if (family == NFPROTO_IPV4)
|
||||
size = snprintf_ipv4(buf + offset, len, flags, ip, cidr);
|
||||
else if (family == NFPROTO_IPV6)
|
||||
size = snprintf_ipv6(buf + offset, len, flags, ip, cidr);
|
||||
else
|
||||
return -1;
|
||||
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_ipaddr - print IPv4|IPv6 address to string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print IPv4|IPv6 address or address/cidr to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_ipaddr(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env)
|
||||
{
|
||||
const union nf_inet_addr *ip;
|
||||
uint8_t family, cidr;
|
||||
enum ipset_opt cidropt;
|
||||
int flags;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_IP ||
|
||||
opt == IPSET_OPT_IP_TO ||
|
||||
opt == IPSET_OPT_IP2);
|
||||
|
||||
family = ipset_data_family(data);
|
||||
cidropt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR : IPSET_OPT_CIDR2;
|
||||
if (ipset_data_test(data, cidropt))
|
||||
cidr = *(const uint8_t *) ipset_data_get(data, cidropt);
|
||||
else
|
||||
cidr = family == NFPROTO_IPV6 ? 128 : 32;
|
||||
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
|
||||
ip = ipset_data_get(data, opt);
|
||||
assert(ip);
|
||||
if (family == NFPROTO_IPV4)
|
||||
return snprintf_ipv4(buf, len, flags, ip, cidr);
|
||||
else if (family == NFPROTO_IPV6)
|
||||
return snprintf_ipv6(buf, len, flags, ip, cidr);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_number - print number to string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print number to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_number(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
size_t maxsize;
|
||||
const void *number;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
|
||||
number = ipset_data_get(data, opt);
|
||||
maxsize = ipset_data_sizeof(opt, AF_INET);
|
||||
D("opt: %u, maxsize %zu", opt, maxsize);
|
||||
if (maxsize == sizeof(uint8_t))
|
||||
return snprintf(buf, len, "%u", *(const uint8_t *) number);
|
||||
else if (maxsize == sizeof(uint16_t))
|
||||
return snprintf(buf, len, "%u", *(const uint16_t *) number);
|
||||
else if (maxsize == sizeof(uint32_t))
|
||||
return snprintf(buf, len, "%lu",
|
||||
(long unsigned) *(const uint32_t *) number);
|
||||
else
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_name - print setname element string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print setname element string to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_name(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const char *name;
|
||||
int size, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_NAME);
|
||||
|
||||
if (len < 2*IPSET_MAXNAMELEN + 2 + strlen("before"))
|
||||
return -1;
|
||||
|
||||
name = ipset_data_get(data, opt);
|
||||
assert(name);
|
||||
size = snprintf(buf, len, "%s", name);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
if (ipset_data_test(data, IPSET_OPT_NAMEREF)) {
|
||||
bool before = false;
|
||||
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_FLAGS))) {
|
||||
const uint32_t *flags =
|
||||
ipset_data_get(data, IPSET_OPT_FLAGS);
|
||||
before = (*flags) & IPSET_FLAG_BEFORE;
|
||||
}
|
||||
size = snprintf(buf + offset, len,
|
||||
" %s %s", before ? "before" : "after",
|
||||
(const char *) ipset_data_get(data,
|
||||
IPSET_OPT_NAMEREF));
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_port - print port or port range
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print port or port range to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_port(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const uint16_t *port;
|
||||
int size, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_PORT);
|
||||
|
||||
if (len < 2*strlen("65535") + 2)
|
||||
return -1;
|
||||
|
||||
port = ipset_data_get(data, IPSET_OPT_PORT);
|
||||
assert(port);
|
||||
size = snprintf(buf, len, "%u", *port);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
if (ipset_data_test(data, IPSET_OPT_PORT_TO)) {
|
||||
port = ipset_data_get(data, IPSET_OPT_PORT_TO);
|
||||
size = snprintf(buf + offset, len,
|
||||
"%s%u",
|
||||
IPSET_RANGE_SEPARATOR, *port);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_iface - print interface element string
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print interface element string to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_iface(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const char *name;
|
||||
int size, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_IFACE);
|
||||
|
||||
if (len < IFNAMSIZ + strlen("physdev:"))
|
||||
return -1;
|
||||
|
||||
if (ipset_data_test(data, IPSET_OPT_PHYSDEV)) {
|
||||
size = snprintf(buf, len, "physdev:");
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
name = ipset_data_get(data, opt);
|
||||
assert(name);
|
||||
size = snprintf(buf, len, "%s", name);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_proto - print protocol name
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print protocol name to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_proto(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const struct protoent *protoent;
|
||||
uint8_t proto;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_PROTO);
|
||||
|
||||
proto = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
|
||||
assert(proto);
|
||||
|
||||
protoent = getprotobynumber(proto);
|
||||
if (protoent)
|
||||
return snprintf(buf, len, "%s", protoent->p_name);
|
||||
|
||||
/* Should not happen */
|
||||
return snprintf(buf, len, "%u", proto);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_icmp - print ICMP code name or type/code
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print ICMP code name or type/code name to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_icmp(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const char *name;
|
||||
uint16_t typecode;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_PORT);
|
||||
|
||||
typecode = *(const uint16_t *) ipset_data_get(data, IPSET_OPT_PORT);
|
||||
name = icmp_to_name(typecode >> 8, typecode & 0xFF);
|
||||
if (name != NULL)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
else
|
||||
return snprintf(buf, len, "%u/%u",
|
||||
typecode >> 8, typecode & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_icmpv6 - print ICMPv6 code name or type/code
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print ICMPv6 code name or type/code name to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_icmpv6(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
const char *name;
|
||||
uint16_t typecode;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_PORT);
|
||||
|
||||
typecode = *(const uint16_t *) ipset_data_get(data, IPSET_OPT_PORT);
|
||||
name = icmpv6_to_name(typecode >> 8, typecode & 0xFF);
|
||||
if (name != NULL)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
else
|
||||
return snprintf(buf, len, "%u/%u",
|
||||
typecode >> 8, typecode & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_proto_port - print proto:port
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print protocol and port to output buffer.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_proto_port(char *buf, unsigned int len,
|
||||
const struct ipset_data *data,
|
||||
enum ipset_opt opt ASSERT_UNUSED,
|
||||
uint8_t env UNUSED)
|
||||
{
|
||||
int size, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_PORT);
|
||||
|
||||
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_PROTO))) {
|
||||
uint8_t proto = *(const uint8_t *) ipset_data_get(data,
|
||||
IPSET_OPT_PROTO);
|
||||
size = ipset_print_proto(buf, len, data, IPSET_OPT_PROTO, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
if (len < 2)
|
||||
return -ENOSPC;
|
||||
size = snprintf(buf + offset, len, IPSET_PROTO_SEPARATOR);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
switch (proto) {
|
||||
case IPPROTO_TCP:
|
||||
case IPPROTO_SCTP:
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
break;
|
||||
case IPPROTO_ICMP:
|
||||
return ipset_print_icmp(buf + offset, len, data,
|
||||
IPSET_OPT_PORT, env);
|
||||
case IPPROTO_ICMPV6:
|
||||
return ipset_print_icmpv6(buf + offset, len, data,
|
||||
IPSET_OPT_PORT, env);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
size = ipset_print_port(buf + offset, len, data, IPSET_OPT_PORT, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
#define print_second(data) \
|
||||
ipset_data_flags_test(data, \
|
||||
IPSET_FLAG(IPSET_OPT_PORT)|IPSET_FLAG(IPSET_OPT_ETHER))
|
||||
|
||||
#define print_third(data) \
|
||||
ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_IP2))
|
||||
|
||||
/**
|
||||
* ipset_print_elem - print ADT elem according to settype
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print (multipart) element according to settype
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_elem(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt UNUSED,
|
||||
uint8_t env)
|
||||
{
|
||||
const struct ipset_type *type;
|
||||
int size, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
|
||||
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
if (!type)
|
||||
return -1;
|
||||
|
||||
size = type->elem[IPSET_DIM_ONE - 1].print(buf, len, data,
|
||||
type->elem[IPSET_DIM_ONE - 1].opt, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO - 1].opt),
|
||||
"print second elem");
|
||||
if (type->dimension == IPSET_DIM_ONE ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_TWO - 1].opt)))
|
||||
return offset;
|
||||
|
||||
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
size = type->elem[IPSET_DIM_TWO - 1].print(buf + offset, len, data,
|
||||
type->elem[IPSET_DIM_TWO - 1].opt, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
if (type->dimension == IPSET_DIM_TWO ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_THREE - 1].opt)))
|
||||
return offset;
|
||||
|
||||
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
size = type->elem[IPSET_DIM_THREE - 1].print(buf + offset, len, data,
|
||||
type->elem[IPSET_DIM_THREE - 1].opt, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_flag - print a flag
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Print a flag, i.e. option without value
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_flag(char *buf UNUSED, unsigned int len UNUSED,
|
||||
const struct ipset_data *data UNUSED,
|
||||
enum ipset_opt opt UNUSED, uint8_t env UNUSED)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_print_data - print data, generic fuction
|
||||
* @buf: printing buffer
|
||||
* @len: length of available buffer space
|
||||
* @data: data blob
|
||||
* @opt: the option kind
|
||||
* @env: environment flags
|
||||
*
|
||||
* Generic wrapper of the printing functions.
|
||||
*
|
||||
* Return lenght of printed string or error size.
|
||||
*/
|
||||
int
|
||||
ipset_print_data(char *buf, unsigned int len,
|
||||
const struct ipset_data *data, enum ipset_opt opt,
|
||||
uint8_t env)
|
||||
{
|
||||
int size = 0, offset = 0;
|
||||
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
|
||||
switch (opt) {
|
||||
case IPSET_OPT_FAMILY:
|
||||
size = ipset_print_family(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_TYPE:
|
||||
size = ipset_print_type(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_SETNAME:
|
||||
size = snprintf(buf, len, "%s", ipset_data_setname(data));
|
||||
break;
|
||||
case IPSET_OPT_ELEM:
|
||||
size = ipset_print_elem(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_IP:
|
||||
size = ipset_print_ip(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_PORT:
|
||||
size = ipset_print_port(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_IFACE:
|
||||
size = ipset_print_iface(buf, len, data, opt, env);
|
||||
break;
|
||||
case IPSET_OPT_GC:
|
||||
case IPSET_OPT_HASHSIZE:
|
||||
case IPSET_OPT_MAXELEM:
|
||||
case IPSET_OPT_NETMASK:
|
||||
case IPSET_OPT_PROBES:
|
||||
case IPSET_OPT_RESIZE:
|
||||
case IPSET_OPT_TIMEOUT:
|
||||
case IPSET_OPT_REFERENCES:
|
||||
case IPSET_OPT_ELEMENTS:
|
||||
case IPSET_OPT_SIZE:
|
||||
size = ipset_print_number(buf, len, data, opt, env);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
return offset;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,556 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <assert.h> /* assert */
|
||||
#include <errno.h> /* errno */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <netinet/in.h> /* struct in6_addr */
|
||||
#include <sys/socket.h> /* AF_ */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <stdio.h> /* FIXME: debug */
|
||||
#include <libmnl/libmnl.h> /* MNL_ALIGN */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* ipset_data_* */
|
||||
#include <libipset/session.h> /* ipset_cmd */
|
||||
#include <libipset/utils.h> /* STREQ */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Userspace cache of sets which exists in the kernel */
|
||||
|
||||
struct ipset {
|
||||
char name[IPSET_MAXNAMELEN]; /* set name */
|
||||
const struct ipset_type *type; /* set type */
|
||||
uint8_t family; /* family */
|
||||
struct ipset *next;
|
||||
};
|
||||
|
||||
static struct ipset_type *typelist; /* registered set types */
|
||||
static struct ipset *setlist; /* cached sets */
|
||||
|
||||
/**
|
||||
* ipset_cache_add - add a set to the cache
|
||||
* @name: set name
|
||||
* @type: set type structure
|
||||
*
|
||||
* Add the named set to the internal cache with the specified
|
||||
* set type. The set name must be unique.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_cache_add(const char *name, const struct ipset_type *type,
|
||||
uint8_t family)
|
||||
{
|
||||
struct ipset *s, *n;
|
||||
|
||||
assert(name);
|
||||
assert(type);
|
||||
|
||||
n = malloc(sizeof(*n));
|
||||
if (n == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ipset_strlcpy(n->name, name, IPSET_MAXNAMELEN);
|
||||
n->type = type;
|
||||
n->family = family;
|
||||
n->next = NULL;
|
||||
|
||||
if (setlist == NULL) {
|
||||
setlist = n;
|
||||
return 0;
|
||||
}
|
||||
for (s = setlist; s->next != NULL; s = s->next) {
|
||||
if (STREQ(name, s->name)) {
|
||||
free(n);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
s->next = n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_cache_del - delete set from the cache
|
||||
* @name: set name
|
||||
*
|
||||
* Delete the named set from the internal cache. If NULL is
|
||||
* specified as setname, the whole cache is emptied.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_cache_del(const char *name)
|
||||
{
|
||||
struct ipset *s, *match = NULL, *prev = NULL;
|
||||
|
||||
if (!name) {
|
||||
for (s = setlist; s != NULL; ) {
|
||||
prev = s;
|
||||
s = s->next;
|
||||
free(prev);
|
||||
}
|
||||
setlist = NULL;
|
||||
return 0;
|
||||
}
|
||||
for (s = setlist; s != NULL && match == NULL; s = s->next) {
|
||||
if (STREQ(s->name, name)) {
|
||||
match = s;
|
||||
if (prev == NULL)
|
||||
setlist = match->next;
|
||||
else
|
||||
prev->next = match->next;
|
||||
}
|
||||
prev = s;
|
||||
}
|
||||
if (match == NULL)
|
||||
return -EEXIST;
|
||||
|
||||
free(match);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_cache_rename - rename a set in the cache
|
||||
* @from: the set to rename
|
||||
* @to: the new name of the set
|
||||
*
|
||||
* Rename the given set in the cache.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_cache_rename(const char *from, const char *to)
|
||||
{
|
||||
struct ipset *s;
|
||||
|
||||
assert(from);
|
||||
assert(to);
|
||||
|
||||
for (s = setlist; s != NULL; s = s->next) {
|
||||
if (STREQ(s->name, from)) {
|
||||
ipset_strlcpy(s->name, to, IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_cache_swap - swap two sets in the cache
|
||||
* @from: the first set
|
||||
* @to: the second set
|
||||
*
|
||||
* Swap two existing sets in the cache.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_cache_swap(const char *from, const char *to)
|
||||
{
|
||||
struct ipset *s, *a = NULL, *b = NULL;
|
||||
|
||||
assert(from);
|
||||
assert(to);
|
||||
|
||||
for (s = setlist; s != NULL && (a == NULL || b == NULL); s = s->next) {
|
||||
if (a == NULL && STREQ(s->name, from))
|
||||
a = s;
|
||||
if (b == NULL && STREQ(s->name, to))
|
||||
b = s;
|
||||
}
|
||||
if (a != NULL && b != NULL) {
|
||||
ipset_strlcpy(a->name, to, IPSET_MAXNAMELEN);
|
||||
ipset_strlcpy(b->name, from, IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
#define MATCH_FAMILY(type, f) \
|
||||
(f == NFPROTO_UNSPEC || type->family == f || \
|
||||
type->family == NFPROTO_IPSET_IPV46)
|
||||
|
||||
bool
|
||||
ipset_match_typename(const char *name, const struct ipset_type *type)
|
||||
{
|
||||
const char * const *alias = type->alias;
|
||||
|
||||
if (STREQ(name, type->name))
|
||||
return true;
|
||||
|
||||
while (alias[0]) {
|
||||
if (STREQ(name, alias[0]))
|
||||
return true;
|
||||
alias++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline const struct ipset_type *
|
||||
create_type_get(struct ipset_session *session)
|
||||
{
|
||||
struct ipset_type *t, *match = NULL;
|
||||
struct ipset_data *data;
|
||||
const char *typename;
|
||||
uint8_t family, tmin = 0, tmax = 0;
|
||||
uint8_t kmin, kmax;
|
||||
int ret;
|
||||
|
||||
data = ipset_session_data(session);
|
||||
assert(data);
|
||||
typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
|
||||
assert(typename);
|
||||
family = ipset_data_family(data);
|
||||
|
||||
/* Check registered types in userspace */
|
||||
for (t = typelist; t != NULL; t = t->next) {
|
||||
/* Skip revisions which are unsupported by the kernel */
|
||||
if (t->kernel_check == IPSET_KERNEL_MISMATCH)
|
||||
continue;
|
||||
if (ipset_match_typename(typename, t)
|
||||
&& MATCH_FAMILY(t, family)) {
|
||||
if (match == NULL) {
|
||||
match = t;
|
||||
tmin = tmax = t->revision;
|
||||
} else if (t->family == match->family)
|
||||
tmin = t->revision;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
return ipset_errptr(session,
|
||||
"Syntax error: unknown settype %s",
|
||||
typename);
|
||||
|
||||
/* Family is unspecified yet: set from matching set type */
|
||||
if (family == NFPROTO_UNSPEC && match->family != NFPROTO_UNSPEC) {
|
||||
family = match->family == NFPROTO_IPSET_IPV46 ?
|
||||
NFPROTO_IPV4 : match->family;
|
||||
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
|
||||
}
|
||||
|
||||
if (match->kernel_check == IPSET_KERNEL_OK)
|
||||
goto found;
|
||||
|
||||
/* Check kernel */
|
||||
ret = ipset_cmd(session, IPSET_CMD_TYPE, 0);
|
||||
if (ret != 0)
|
||||
return NULL;
|
||||
|
||||
kmin = kmax = *(const uint8_t *)ipset_data_get(data,
|
||||
IPSET_OPT_REVISION);
|
||||
if (ipset_data_test(data, IPSET_OPT_REVISION_MIN))
|
||||
kmin = *(const uint8_t *)ipset_data_get(data,
|
||||
IPSET_OPT_REVISION_MIN);
|
||||
|
||||
if (MAX(tmin, kmin) > MIN(tmax, kmax)) {
|
||||
if (kmin > tmax)
|
||||
return ipset_errptr(session,
|
||||
"Kernel supports %s type, family %s "
|
||||
"with minimal revision %u while ipset program "
|
||||
"with maximal revision %u.\n"
|
||||
"You need to upgrade your ipset program.",
|
||||
typename,
|
||||
family == NFPROTO_IPV4 ? "INET" :
|
||||
family == NFPROTO_IPV6 ? "INET6" : "UNSPEC",
|
||||
kmin, tmax);
|
||||
else
|
||||
return ipset_errptr(session,
|
||||
"Kernel supports %s type, family %s "
|
||||
"with maximal revision %u while ipset program "
|
||||
"with minimal revision %u.\n"
|
||||
"You need to upgrade your kernel.",
|
||||
typename,
|
||||
family == NFPROTO_IPV4 ? "INET" :
|
||||
family == NFPROTO_IPV6 ? "INET6" : "UNSPEC",
|
||||
kmax, tmin);
|
||||
}
|
||||
|
||||
/* Disable unsupported revisions */
|
||||
for (match = NULL, t = typelist; t != NULL; t = t->next) {
|
||||
/* Skip revisions which are unsupported by the kernel */
|
||||
if (t->kernel_check == IPSET_KERNEL_MISMATCH)
|
||||
continue;
|
||||
if (ipset_match_typename(typename, t)
|
||||
&& MATCH_FAMILY(t, family)) {
|
||||
if (t->revision < kmin || t->revision > kmax)
|
||||
t->kernel_check = IPSET_KERNEL_MISMATCH;
|
||||
else if (match == NULL)
|
||||
match = t;
|
||||
}
|
||||
}
|
||||
match->kernel_check = IPSET_KERNEL_OK;
|
||||
found:
|
||||
ipset_data_set(data, IPSET_OPT_TYPE, match);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
#define set_family_and_type(data, match, family) do { \
|
||||
if (family == NFPROTO_UNSPEC && match->family != NFPROTO_UNSPEC) \
|
||||
family = match->family == NFPROTO_IPSET_IPV46 ? \
|
||||
NFPROTO_IPV4 : match->family;\
|
||||
ipset_data_set(data, IPSET_OPT_FAMILY, &family); \
|
||||
ipset_data_set(data, IPSET_OPT_TYPE, match); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static inline const struct ipset_type *
|
||||
adt_type_get(struct ipset_session *session)
|
||||
{
|
||||
struct ipset_data *data;
|
||||
struct ipset *s;
|
||||
struct ipset_type *t;
|
||||
const struct ipset_type *match;
|
||||
const char *setname, *typename;
|
||||
const uint8_t *revision;
|
||||
uint8_t family = NFPROTO_UNSPEC;
|
||||
int ret;
|
||||
|
||||
data = ipset_session_data(session);
|
||||
assert(data);
|
||||
setname = ipset_data_setname(data);
|
||||
assert(setname);
|
||||
|
||||
/* Check existing sets in cache */
|
||||
for (s = setlist; s != NULL; s = s->next) {
|
||||
if (STREQ(setname, s->name)) {
|
||||
ipset_data_set(data, IPSET_OPT_FAMILY, &s->family);
|
||||
ipset_data_set(data, IPSET_OPT_TYPE, s->type);
|
||||
return s->type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check kernel */
|
||||
ret = ipset_cmd(session, IPSET_CMD_HEADER, 0);
|
||||
if (ret != 0)
|
||||
return NULL;
|
||||
|
||||
typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
|
||||
revision = ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
family = ipset_data_family(data);
|
||||
|
||||
/* Check registered types */
|
||||
for (t = typelist, match = NULL;
|
||||
t != NULL && match == NULL; t = t->next) {
|
||||
if (t->kernel_check == IPSET_KERNEL_MISMATCH)
|
||||
continue;
|
||||
if (STREQ(typename, t->name)
|
||||
&& MATCH_FAMILY(t, family)
|
||||
&& *revision == t->revision) {
|
||||
t->kernel_check = IPSET_KERNEL_OK;
|
||||
match = t;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
return ipset_errptr(session,
|
||||
"Kernel-library incompatibility: "
|
||||
"set %s in kernel has got settype %s "
|
||||
"with family %s and revision %u while "
|
||||
"ipset library does not support the "
|
||||
"settype with that family and revision.",
|
||||
setname, typename,
|
||||
family == NFPROTO_IPV4 ? "inet" :
|
||||
family == NFPROTO_IPV6 ? "inet6" : "unspec",
|
||||
*revision);
|
||||
|
||||
set_family_and_type(data, match, family);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_type_get - get a set type from the kernel
|
||||
* @session: session structure
|
||||
* @cmd: the command which needs the set type
|
||||
*
|
||||
* Build up and send a private message to the kernel in order to
|
||||
* get the set type. When creating the set, we send the typename
|
||||
* and family and get the supported revisions of the given set type.
|
||||
* When adding/deleting/testing an entry, we send the setname and
|
||||
* receive the typename, family and revision.
|
||||
*
|
||||
* Returns the set type for success and NULL for failure.
|
||||
*/
|
||||
const struct ipset_type *
|
||||
ipset_type_get(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
{
|
||||
assert(session);
|
||||
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_CREATE:
|
||||
return create_type_get(session);
|
||||
case IPSET_CMD_ADD:
|
||||
case IPSET_CMD_DEL:
|
||||
case IPSET_CMD_TEST:
|
||||
return adt_type_get(session);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
assert(cmd == IPSET_CMD_NONE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_type_check - check the set type received from kernel
|
||||
* @session: session structure
|
||||
*
|
||||
* Check the set type received from the kernel (typename, revision,
|
||||
* family) against the userspace types looking for a matching type.
|
||||
*
|
||||
* Returns the set type for success and NULL for failure.
|
||||
*/
|
||||
const struct ipset_type *
|
||||
ipset_type_check(struct ipset_session *session)
|
||||
{
|
||||
const struct ipset_type *t, *match = NULL;
|
||||
struct ipset_data *data;
|
||||
const char *typename;
|
||||
uint8_t family = NFPROTO_UNSPEC, revision;
|
||||
|
||||
assert(session);
|
||||
data = ipset_session_data(session);
|
||||
assert(data);
|
||||
|
||||
typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
|
||||
family = ipset_data_family(data);
|
||||
revision = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
|
||||
/* Check registered types */
|
||||
for (t = typelist; t != NULL && match == NULL; t = t->next) {
|
||||
if (t->kernel_check == IPSET_KERNEL_MISMATCH)
|
||||
continue;
|
||||
if (ipset_match_typename(typename, t)
|
||||
&& MATCH_FAMILY(t, family)
|
||||
&& t->revision == revision)
|
||||
match = t;
|
||||
}
|
||||
if (!match)
|
||||
return ipset_errptr(session,
|
||||
"Kernel and userspace incompatible: "
|
||||
"settype %s with revision %u not supported ",
|
||||
"by userspace.", typename, revision);
|
||||
|
||||
set_family_and_type(data, match, family);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_type_add - add (register) a userspace set type
|
||||
* @type: pointer to the set type structure
|
||||
*
|
||||
* Add the given set type to the type list. The types
|
||||
* are added sorted, in descending revision number.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_type_add(struct ipset_type *type)
|
||||
{
|
||||
struct ipset_type *t, *prev;
|
||||
|
||||
assert(type);
|
||||
|
||||
if (strlen(type->name) > IPSET_MAXNAMELEN - 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* Add to the list: higher revision numbers first */
|
||||
for (t = typelist, prev = NULL; t != NULL; t = t->next) {
|
||||
if (STREQ(t->name, type->name)) {
|
||||
if (t->revision == type->revision)
|
||||
return -EEXIST;
|
||||
else if (t->revision < type->revision) {
|
||||
type->next = t;
|
||||
if (prev)
|
||||
prev->next = type;
|
||||
else
|
||||
typelist = type;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (t->next != NULL && STREQ(t->next->name, type->name)) {
|
||||
if (t->next->revision == type->revision)
|
||||
return -EEXIST;
|
||||
else if (t->next->revision < type->revision) {
|
||||
type->next = t->next;
|
||||
t->next = type;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
prev = t;
|
||||
}
|
||||
type->next = typelist;
|
||||
typelist = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_typename_resolve - resolve typename alias
|
||||
* @str: typename or alias
|
||||
*
|
||||
* Check the typenames (and aliases) and return the
|
||||
* preferred name of the set type.
|
||||
*
|
||||
* Returns the name of the matching set type or NULL.
|
||||
*/
|
||||
const char *
|
||||
ipset_typename_resolve(const char *str)
|
||||
{
|
||||
const struct ipset_type *t;
|
||||
|
||||
for (t = typelist; t != NULL; t = t->next)
|
||||
if (ipset_match_typename(str, t))
|
||||
return t->name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_types - return the list of the set types
|
||||
*
|
||||
* The types can be unchecked with respect of the running kernel.
|
||||
* Only useful for type specific help.
|
||||
*
|
||||
* Returns the list of the set types.
|
||||
*/
|
||||
const struct ipset_type *
|
||||
ipset_types(void)
|
||||
{
|
||||
return typelist;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_cache_init - initialize set cache
|
||||
*
|
||||
* Initialize the set cache in userspace.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_cache_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_cache_fini - release the set cache
|
||||
*
|
||||
* Release the set cache.
|
||||
*/
|
||||
void
|
||||
ipset_cache_fini(void)
|
||||
{
|
||||
struct ipset *set;
|
||||
|
||||
while (setlist) {
|
||||
set = setlist;
|
||||
setlist = setlist->next;
|
||||
free(set);
|
||||
}
|
||||
}
|
||||
@@ -1,312 +0,0 @@
|
||||
#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);
|
||||
|
||||
/* Find the largest network which matches the range from left, in host order. */
|
||||
u32
|
||||
ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr)
|
||||
{
|
||||
u32 last;
|
||||
u8 i;
|
||||
|
||||
for (i = 1; i < 32; i++) {
|
||||
if ((from & ip_set_hostmask(i)) != from)
|
||||
continue;
|
||||
last = from | ~ip_set_hostmask(i);
|
||||
if (!after(last, to)) {
|
||||
*cidr = i;
|
||||
return last;
|
||||
}
|
||||
}
|
||||
*cidr = 32;
|
||||
return from;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip_set_range_to_cidr);
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef _PFXLEN_H
|
||||
#define _PFXLEN_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/tcp.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];
|
||||
}
|
||||
|
||||
extern u32 ip_set_range_to_cidr(u32 from, u32 to, u8 *cidr);
|
||||
|
||||
#define ip_set_mask_from_to(from, to, cidr) \
|
||||
do { \
|
||||
from &= ip_set_hostmask(cidr); \
|
||||
to = from | ~ip_set_hostmask(cidr); \
|
||||
} while (0)
|
||||
|
||||
#endif /*_PFXLEN_H */
|
||||
@@ -1,857 +0,0 @@
|
||||
.\" Man page written by 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 as published by
|
||||
.\" the Free Software Foundation; either version 2 of the License, or
|
||||
.\" (at your option) any later version.
|
||||
.\"
|
||||
.\" This program is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public License
|
||||
.\" along with this program; if not, write to the Free Software
|
||||
.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
.TH "IPSET" "8" "Oct 15, 2010" "Jozsef Kadlecsik" ""
|
||||
.SH "NAME"
|
||||
ipset \(em administration tool for IP sets
|
||||
.SH "SYNOPSIS"
|
||||
\fBipset\fR [ \fIOPTIONS\fR ] \fICOMMAND\fR [ \fICOMMAND\-OPTIONS\fR ]
|
||||
.PP
|
||||
COMMANDS := { \fBcreate\fR | \fBadd\fR | \fBdel\fR | \fBtest\fR | \fBdestroy\fR | \fBlist\fR | \fBsave\fR | \fBrestore\fR | \fBflush\fR | \fBrename\fR | \fBswap\fR | \fBhelp\fR | \fBversion\fR | \fB\-\fR }
|
||||
.PP
|
||||
\fIOPTIONS\fR := { \fB\-exist\fR | \fB\-output\fR { \fBplain\fR | \fBsave\fR | \fBxml\fR } | \fB\-quiet\fR | \fB\-resolve\fR | \fB\-sorted\fR | \fB\-name\fR | \fB\-terse\fR }
|
||||
.PP
|
||||
\fBipset\fR \fBcreate\fR \fISETNAME\fR \fITYPENAME\fR [ \fICREATE\-OPTIONS\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBadd\fR \fISETNAME\fR \fIADD\-ENTRY\fR [ \fIADD\-OPTIONS\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBdel\fR \fISETNAME\fR \fIDEL\-ENTRY\fR [ \fIDEL\-OPTIONS\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBtest\fR \fISETNAME\fR \fITEST\-ENTRY\fR [ \fITEST\-OPTIONS\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBdestroy\fR [ \fISETNAME\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBlist\fR [ \fISETNAME\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBsave\fR [ \fISETNAME\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBrestore\fR
|
||||
.PP
|
||||
\fBipset\fR \fBflush\fR [ \fISETNAME\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBrename\fR \fISETNAME\-FROM\fR \fISETNAME\-TO\fR
|
||||
.PP
|
||||
\fBipset\fR \fBswap\fR \fISETNAME\-FROM\fR \fISETNAME\-TO\fR
|
||||
.PP
|
||||
\fBipset\fR \fBhelp\fR [ \fITYPENAME\fR ]
|
||||
.PP
|
||||
\fBipset\fR \fBversion\fR
|
||||
.PP
|
||||
\fBipset\fR \fB\-\fR
|
||||
.SH "DESCRIPTION"
|
||||
\fBipset\fR
|
||||
is used to set up, maintain and inspect so called IP sets in the Linux
|
||||
kernel. Depending on the type of the set, an IP set may store IP(v4/v6)
|
||||
addresses, (TCP/UDP) port numbers, IP and MAC address pairs, IP address
|
||||
and port number pairs, etc. See the set type definitions below.
|
||||
.PP
|
||||
\fBIptables\fR
|
||||
matches and targets referring to sets create references, which
|
||||
protect the given sets in the kernel. A set cannot be destroyed
|
||||
while there is a single reference pointing to it.
|
||||
.SH "OPTIONS"
|
||||
The options that are recognized by
|
||||
\fBipset\fR
|
||||
can be divided into several different groups.
|
||||
.SS COMMANDS
|
||||
These options specify the desired action to perform. Only one of them
|
||||
can be specified on the command line unless otherwise specified below.
|
||||
For all the long versions of the command names, you need to use only enough
|
||||
letters to ensure that
|
||||
\fBipset\fR
|
||||
can differentiate it from all other commands. The
|
||||
\fBipset\fR
|
||||
parser follows the order here when looking for the shortest match
|
||||
in the long command names.
|
||||
.TP
|
||||
\fBn\fP, \fBcreate\fP \fISETNAME\fP \fITYPENAME\fP [ \fICREATE\-OPTIONS\fP ]
|
||||
Create a set identified with setname and specified type. The type may require
|
||||
type specific options. If the
|
||||
\fB\-exist\fR
|
||||
option is specified,
|
||||
\fBipset\fR
|
||||
ignores the error otherwise raised when the same set (setname and create parameters
|
||||
are identical) already exists.
|
||||
.TP
|
||||
\fBadd\fP \fISETNAME\fP \fIADD\-ENTRY\fP [ \fIADD\-OPTIONS\fP ]
|
||||
Add a given entry to the set. If the
|
||||
\fB\-exist\fR
|
||||
option is specified,
|
||||
\fBipset\fR
|
||||
ignores if the entry already added to the set.
|
||||
.TP
|
||||
\fBdel\fP \fISETNAME\fP \fIDEL\-ENTRY\fP [ \fIDEL\-OPTIONS\fP ]
|
||||
Delete an entry from a set. If the
|
||||
\fB\-exist\fR
|
||||
option is specified,
|
||||
\fBipset\fR
|
||||
ignores if the entry does not added to (already expired from) the set.
|
||||
.TP
|
||||
\fBtest\fP \fISETNAME\fP \fITEST\-ENTRY\fP [ \fITEST\-OPTIONS\fP ]
|
||||
Test wether an entry is in a set or not. Exit status number is zero
|
||||
if the tested entry is in the set and nonzero if it is missing from
|
||||
the set.
|
||||
.TP
|
||||
\fBx\fP, \fBdestroy\fP [ \fISETNAME\fP ]
|
||||
Destroy the specified set or all the sets if none is given.
|
||||
|
||||
If the set has got reference(s), nothing is done and no set destroyed.
|
||||
.TP
|
||||
\fBlist\fP [ \fISETNAME\fP ] [ \fIOPTIONS\fP ]
|
||||
List the header data and the entries for the specified set, or for
|
||||
all sets if none is given. The
|
||||
\fB\-resolve\fP
|
||||
option can be used to force name lookups (which may be slow). When the
|
||||
\fB\-sorted\fP
|
||||
option is given, the entries are listed sorted (if the given set
|
||||
type supports the operation). The option
|
||||
\fB\-output\fR
|
||||
can be used to control the format of the listing:
|
||||
\fBplain\fR, \fBsave\fR or \fBxml\fR.
|
||||
(The default is
|
||||
\fBplain\fR.)
|
||||
If the option
|
||||
\fB\-name\fR
|
||||
is specified, just the names of the existing sets are listed. If the option
|
||||
\fB\-terse\fR
|
||||
is specified, just the set names and headers are listed.
|
||||
.TP
|
||||
\fBsave\fP [ \fISETNAME\fP ]
|
||||
Save the given set, or all sets if none is given
|
||||
to stdout in a format that
|
||||
\fBrestore\fP
|
||||
can read.
|
||||
.TP
|
||||
\fBrestore\fP
|
||||
Restore a saved session generated by
|
||||
\fBsave\fP.
|
||||
The saved session can be fed from stdin.
|
||||
.TP
|
||||
\fBflush\fP [ \fISETNAME\fP ]
|
||||
Flush all entries from the specified set or flush
|
||||
all sets if none is given.
|
||||
.TP
|
||||
\fBe\fP, \fBrename\fP \fISETNAME\-FROM\fP \fISETNAME\-TO\fP
|
||||
Rename a set. Set identified by
|
||||
\fISETNAME\-TO\fR
|
||||
must not exist.
|
||||
.TP
|
||||
\fBw\fP, \fBswap\fP \fISETNAME\-FROM\fP \fISETNAME\-TO\fP
|
||||
Swap the content of two sets, or in another words,
|
||||
exchange the name of two sets. The referred sets must exist and
|
||||
identical type of sets can be swapped only.
|
||||
.TP
|
||||
\fBhelp\fP [ \fITYPENAME\fP ]
|
||||
Print help and set type specific help if
|
||||
\fITYPENAME\fR
|
||||
is specified.
|
||||
.TP
|
||||
\fBversion\fP
|
||||
Print program version.
|
||||
.TP
|
||||
\fB\-\fP
|
||||
If a dash is specified as command, then
|
||||
\fBipset\fR
|
||||
enters a simple interactive mode and the commands are read from the standard input.
|
||||
The interactive mode can be finished by entering the pseudo\-command
|
||||
\fBquit\fR.
|
||||
.P
|
||||
.SS "OTHER OPTIONS"
|
||||
The following additional options can be specified. The long option names
|
||||
cannot be abbreviated.
|
||||
.TP
|
||||
\fB\-!\fP, \fB\-exist\fP
|
||||
Ignore errors when the exactly the same set is to be created or already
|
||||
added entry is added or missing entry is deleted.
|
||||
.TP
|
||||
\fB\-o\fP, \fB\-output\fP { \fBplain\fR | \fBsave\fR | \fBxml\fR }
|
||||
Select the output format to the
|
||||
\fBlist\fR
|
||||
command.
|
||||
.TP
|
||||
\fB\-q\fP, \fB\-quiet\fP
|
||||
Suppress any output to stdout and stderr.
|
||||
\fBipset\fR
|
||||
will still exit with error if it cannot continue.
|
||||
.TP
|
||||
\fB\-r\fP, \fB\-resolve\fP
|
||||
When listing sets, enforce name lookup. The
|
||||
program will try to display the IP entries resolved to
|
||||
host names which requires
|
||||
\fBslow\fR
|
||||
DNS lookups.
|
||||
.TP
|
||||
\fB\-s\fP, \fB\-sorted\fP
|
||||
Sorted output. When listing sets entries are listed sorted. Not supported yet.
|
||||
.TP
|
||||
\fB\-n\fP, \fB\-name\fP
|
||||
List just the names of the existing sets, i.e. suppress listing of set headers and members.
|
||||
.TP
|
||||
\fB\-t\fP, \fB\-terse\fP
|
||||
List the set names and headers, i.e. suppress listing of set members.
|
||||
|
||||
.SH "SET TYPES"
|
||||
A set type comprises of the storage method by which the data is stored and
|
||||
the data type(s) which are stored in the set. Therefore the
|
||||
\fITYPENAME\fR
|
||||
parameter of the
|
||||
\fBcreate\fR
|
||||
command follows the syntax
|
||||
|
||||
\fITYPENAME\fR := \fImethod\fR\fB:\fR\fIdatatype\fR[\fB,\fR\fIdatatype\fR[\fB,\fR\fIdatatype\fR]]
|
||||
|
||||
where the current list of the methods are
|
||||
\fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types
|
||||
are \fBip\fR, \fBnet\fR, \fBmac\fR, \fBport\fR and \fBiface\fR.
|
||||
The dimension of a set is equal to the number of data types in its type name.
|
||||
|
||||
When adding, deleting or testing entries in a set, the same comma separated
|
||||
data syntax must be used for the entry parameter of the commands, i.e
|
||||
|
||||
ipset add foo ipaddr,portnum,ipaddr
|
||||
|
||||
The \fBbitmap\fR and \fBlist\fR types use a fixed sized storage. The \fBhash\fR
|
||||
types use a hash to store the elements. In order to avoid clashes in the hash,
|
||||
a limited number of chaining, and if that is exhausted, the doubling of the hash size
|
||||
is performed when adding entries by the
|
||||
\fBipset\fR
|
||||
command. When entries added by the
|
||||
\fBSET\fR
|
||||
target of
|
||||
\fBiptables/ip6tables\fR,
|
||||
then the hash size is fixed and the set won't be duplicated, even if the new
|
||||
entry cannot be added to the set.
|
||||
|
||||
All set types support the optional
|
||||
|
||||
\fBtimeout\fR \fIvalue\fR
|
||||
|
||||
parameter when creating a set and adding entries. The value of the \fBtimeout\fR
|
||||
parameter for the \fBcreate\fR command means the default timeout value (in seconds)
|
||||
for new entries. If a set is created with timeout support, then the same
|
||||
\fBtimeout\fR option can be used to specify non\-default timeout values
|
||||
when adding entries. Zero timeout value means the entry is added permanent to the set.
|
||||
The timeout value of already added elements can be changed by readding the element
|
||||
using the \fB\-exist\fR option.
|
||||
.SS bitmap:ip
|
||||
The \fBbitmap:ip\fR set type uses a memory range to store either IPv4 host
|
||||
(default) or IPv4 network addresses. A \fBbitmap:ip\fR type of set can store up
|
||||
to 65536 entries.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := { \fIip\fR | \fIfromip\fR\-\fItoip\fR | \fIip\fR/\fIcidr\fR }
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := { \fIip\fR | \fIfromip\fR\-\fItoip\fR | \fIip\fR/\fIcidr\fR }
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIip\fR
|
||||
.PP
|
||||
Mandatory \fBcreate\fR options:
|
||||
.TP
|
||||
\fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR
|
||||
Create the set from the specified inclusive address range expressed in an
|
||||
IPv4 address range or network. The size of the range (in entries) cannot exceed
|
||||
the limit of maximum 65536 elements.
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBnetmask\fP \fIcidr\fP
|
||||
When the optional \fBnetmask\fP parameter specified, network addresses will be
|
||||
stored in the set instead of IP host addresses. The \fIcidr\fR prefix value must be
|
||||
between 1\-32.
|
||||
An IP address will be in the set if the network address, which is resulted by
|
||||
masking the address with the specified netmask calculated from the prefix,
|
||||
can be found in the set.
|
||||
.PP
|
||||
The \fBbitmap:ip\fR type supports adding or deleting multiple entries in one
|
||||
command.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo bitmap:ip range 192.168.0.0/16
|
||||
.IP
|
||||
ipset add foo 192.168.1/24
|
||||
.IP
|
||||
ipset test foo 192.168.1.1
|
||||
.SS bitmap:ip,mac
|
||||
The \fBbitmap:ip,mac\fR set type uses a memory range to store IPv4 and a MAC address pairs. A \fBbitmap:ip,mac\fR type of set can store up to 65536 entries.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIip\fR[,\fImacaddr\fR]
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIip\fR[,\fImacaddr\fR]
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIip\fR[,\fImacaddr\fR]
|
||||
.PP
|
||||
Mandatory options to use when creating a \fBbitmap:ip,mac\fR type of set:
|
||||
.TP
|
||||
\fBrange\fP \fIfromip\fP\-\fItoip\fR|\fIip\fR/\fIcidr\fR
|
||||
Create the set from the specified inclusive address range expressed in an
|
||||
IPv4 address range or network. The size of the range cannot exceed the limit
|
||||
of maximum 65536 entries.
|
||||
.PP
|
||||
The \fBbitmap:ip,mac\fR type is exceptional in the sense that the MAC part can
|
||||
be left out when adding/deleting/testing entries in the set. If we add an entry
|
||||
without the MAC address specified, then when the first time the entry is
|
||||
matched by the kernel, it will automatically fill out the missing MAC address with the
|
||||
source MAC address from the packet. If the entry was specified with a timeout value,
|
||||
the timer starts off when the IP and MAC address pair is complete.
|
||||
.PP
|
||||
The \fBbitmap:ip,mac\fR type of sets require two \fBsrc/dst\fR parameters of
|
||||
the \fBset\fR match and \fBSET\fR target netfilter kernel modules and the second
|
||||
one must be \fBsrc\fR to match, add or delete entries because the \fBset\fR match
|
||||
and \fBSET\fR target have access to the source MAC address only.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo bitmap:ip,mac range 192.168.0.0/16
|
||||
.IP
|
||||
ipset add foo 192.168.1.1,12:34:56:78:9A:BC
|
||||
.IP
|
||||
ipset test foo 192.168.1.1
|
||||
.SS bitmap:port
|
||||
The \fBbitmap:port\fR set type uses a memory range to store port numbers
|
||||
and such a set can store up to 65536 ports.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := \fBrange\fP \fIfromport\fP\-\fItoport [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := { \fIport\fR | \fIfromport\fR\-\fItoport\fR }
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := { \fIport\fR | \fIfromport\fR\-\fItoport\fR }
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIport\fR
|
||||
.PP
|
||||
Mandatory options to use when creating a \fBbitmap:port\fR type of set:
|
||||
.TP
|
||||
\fBrange\fP \fIfromport\fP\-\fItoport\fR
|
||||
Create the set from the specified inclusive port range.
|
||||
.PP
|
||||
The \fBset\fR match and \fBSET\fR target netfilter kernel modules interpret
|
||||
the stored numbers as TCP or UDP port numbers.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo bitmap:port range 0\-1024
|
||||
.IP
|
||||
ipset add foo 80
|
||||
.IP
|
||||
ipset test foo 80
|
||||
.SS hash:ip
|
||||
The \fBhash:ip\fR set type uses a hash to store IP host addresses (default) or
|
||||
network addresses. Zero valued IP address cannot be stored in a \fBhash:ip\fR
|
||||
type of set.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBnetmask\fP \fIcidr\fP ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIipaddr\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
|
||||
The protocol family of the IP addresses to be stored in the set. The default is
|
||||
\fBinet\fR, i.e IPv4.
|
||||
.TP
|
||||
\fBhashsize\fR \fIvalue\fR
|
||||
The initial hash size for the set, default is 1024. The hash size must be a power
|
||||
of two, the kernel automatically rounds up non power of two hash sizes to the first
|
||||
correct value.
|
||||
.TP
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.TP
|
||||
\fBnetmask\fP \fIcidr\fP
|
||||
When the optional \fBnetmask\fP parameter specified, network addresses will be
|
||||
stored in the set instead of IP host addresses. The \fIcidr\fP prefix value must be
|
||||
between 1\-32 for IPv4 and between 1\-128 for IPv6. An IP address will be in the set
|
||||
if the network address, which is resulted by masking the address with the netmask
|
||||
calculated from the prefix, can be found in the set.
|
||||
.PP
|
||||
For the \fBinet\fR family one can add or delete multiple entries by specifying
|
||||
a range or a network:
|
||||
.PP
|
||||
\fIipaddr\fR := { \fIip\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIip\fR/\fIcidr\fR }
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:ip netmask 30
|
||||
.IP
|
||||
ipset add foo 192.168.1.0/24
|
||||
.IP
|
||||
ipset test foo 192.168.1.2
|
||||
.SS hash:net
|
||||
The \fBhash:net\fR set type uses a hash to store different sized IP network addresses.
|
||||
Network address with zero prefix size cannot be stored in this type of sets.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
|
||||
The protocol family of the IP addresses to be stored in the set. The default is
|
||||
\fBinet\fR, i.e IPv4.
|
||||
.TP
|
||||
\fBhashsize\fR \fIvalue\fR
|
||||
The initial hash size for the set, default is 1024. The hash size must be a power
|
||||
of two, the kernel automatically rounds up non power of two hash sizes to the first
|
||||
correct value.
|
||||
.TP
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
For the \fBinet\fR family one can add or delete multiple entries by specifying
|
||||
a range, which is converted internally to network(s) equal to the range:
|
||||
.PP
|
||||
\fInetaddr\fR := { \fIip\fR[/\fIcidr\fR] | \fIfromaddr\fR\-\fItoaddr\fR }
|
||||
.PP
|
||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
||||
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||
element is added/deleted and overlapping elements are not checked by the kernel.
|
||||
When testing entries, if a host address is tested, then the kernel tries to match
|
||||
the host address in the networks added to the set and reports the result accordingly.
|
||||
.PP
|
||||
From the \fBset\fR netfilter match point of view the searching for a match
|
||||
always starts from the smallest size of netblock (most specific
|
||||
prefix) to the largest one (least specific prefix) added to the set.
|
||||
When adding/deleting IP addresses to the set by the \fBSET\fR netfilter target,
|
||||
it will be added/deleted by the most specific prefix which can be found in the
|
||||
set, or by the host prefix value if the set is empty.
|
||||
.PP
|
||||
The lookup time grows linearly with the number of the different prefix
|
||||
values added to the set.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:net
|
||||
.IP
|
||||
ipset add foo 192.168.0.0/24
|
||||
.IP
|
||||
ipset add foo 10.1.0.0/16
|
||||
.IP
|
||||
ipset test foo 192.168.0/24
|
||||
.SS hash:ip,port
|
||||
The \fBhash:ip,port\fR set type uses a hash to store IP address and port number pairs.
|
||||
The port number is interpreted together with a protocol (default TCP) and zero
|
||||
protocol number cannot be used.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
|
||||
The protocol family of the IP addresses to be stored in the set. The default is
|
||||
\fBinet\fR, i.e IPv4.
|
||||
.TP
|
||||
\fBhashsize\fR \fIvalue\fR
|
||||
The initial hash size for the set, default is 1024. The hash size must be a power
|
||||
of two, the kernel automatically rounds up non power of two hash sizes to the first
|
||||
correct value
|
||||
.TP
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
For the \fBinet\fR family one can add or delete multiple entries by specifying
|
||||
a range or a network of IPv4 addresses in the IP address part of the entry:
|
||||
.PP
|
||||
\fIipaddr\fR := { \fIip\fR | \fIfromaddr\fR\-\fItoaddr\fR | \fIip\fR/\fIcidr\fR }
|
||||
.PP
|
||||
The
|
||||
[\fIproto\fR:]\fIport\fR
|
||||
part of the elements may be expressed in the following forms, where the range
|
||||
variations are valid when adding or deleting entries:
|
||||
.TP
|
||||
\fIportname[\-portname]\fR
|
||||
TCP port or range of ports expressed in TCP portname identifiers from /etc/services
|
||||
.TP
|
||||
\fIportnumber[\-portnumber]\fR
|
||||
TCP port or range of ports expressed in TCP port numbers
|
||||
.TP
|
||||
\fBtcp\fR|\fBsctp\fR|\fBudp\fR|\fBudplite\fR:\fIportname\fR|\fIportnumber\fR[\-\fIportname\fR|\fIportnumber\fR]
|
||||
TCP, SCTP, UDP or UDPLITE port or port range expressed in port name(s) or port number(s)
|
||||
.TP
|
||||
\fBicmp\fR:\fIcodename\fR|\fItype\fR/\fIcode\fR
|
||||
ICMP codename or type/code. The supported ICMP codename identifiers can always
|
||||
be listed by the help command.
|
||||
.TP
|
||||
\fBicmpv6\fR:\fIcodename\fR|\fItype\fR/\fIcode\fR
|
||||
ICMPv6 codename or type/code. The supported ICMPv6 codename identifiers can always
|
||||
be listed by the help command.
|
||||
.TP
|
||||
\fIproto\fR:0
|
||||
All other protocols, as an identifier from /etc/protocols or number. The pseudo
|
||||
port number must be zero.
|
||||
.PP
|
||||
The \fBhash:ip,port\fR type of sets require
|
||||
two \fBsrc\fR/\fBdst\fR parameters of the \fBset\fR match and \fBSET\fR
|
||||
target kernel modules.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:ip,port
|
||||
.IP
|
||||
ipset add foo 192.168.1.0/24,80\-82
|
||||
.IP
|
||||
ipset add foo 192.168.1.1,udp:53
|
||||
.IP
|
||||
ipset add foo 192.168.1.1,vrrp:0
|
||||
.IP
|
||||
ipset test foo 192.168.1.1,80
|
||||
.SS hash:net,port
|
||||
The \fBhash:net,port\fR set type uses a hash to store different sized IP network
|
||||
address and port pairs. The port number is interpreted together with a protocol
|
||||
(default TCP) and zero protocol number cannot be used. Network
|
||||
address with zero prefix size is not accepted either.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
|
||||
The protocol family of the IP addresses to be stored in the set. The default is
|
||||
\fBinet\fR, i.e IPv4.
|
||||
.TP
|
||||
\fBhashsize\fR \fIvalue\fR
|
||||
The initial hash size for the set, default is 1024. The hash size must be a power
|
||||
of two, the kernel automatically rounds up non power of two hash sizes to the first
|
||||
correct value.
|
||||
.TP
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
For the \fInetaddr\fR part of the elements
|
||||
see the description at the \fBhash:net\fR set type. For the
|
||||
[\fIproto\fR:]\fIport\fR
|
||||
part of the elements see the description at the
|
||||
\fBhash:ip,port\fR set type.
|
||||
.PP
|
||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
||||
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||
element is added/deleted and overlapping elements are not checked by the kernel.
|
||||
When testing entries, if a host address is tested, then the kernel tries to match
|
||||
the host address in the networks added to the set and reports the result accordingly.
|
||||
.PP
|
||||
From the \fBset\fR netfilter match point of view the searching for a match
|
||||
always starts from the smallest size of netblock (most specific
|
||||
prefix) to the largest one (least specific prefix) added to the set.
|
||||
When adding/deleting IP
|
||||
addresses to the set by the \fBSET\fR netfilter target, it will be
|
||||
added/deleted by the most specific prefix which can be found in the
|
||||
set, or by the host prefix value if the set is empty.
|
||||
.PP
|
||||
The lookup time grows linearly with the number of the different prefix
|
||||
values added to the set.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:net,port
|
||||
.IP
|
||||
ipset add foo 192.168.0/24,25
|
||||
.IP
|
||||
ipset add foo 10.1.0.0/16,80
|
||||
.IP
|
||||
ipset test foo 192.168.0/24,25
|
||||
.SS hash:ip,port,ip
|
||||
The \fBhash:ip,port,ip\fR set type uses a hash to store IP address, port number
|
||||
and a second IP address triples. The port number is interpreted together with a
|
||||
protocol (default TCP) and zero protocol number cannot be used.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR
|
||||
.PP
|
||||
For the first \fIipaddr\fR and
|
||||
[\fIproto\fR:]\fIport\fR
|
||||
parts of the elements see the descriptions at the
|
||||
\fBhash:ip,port\fR set type.
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
|
||||
The protocol family of the IP addresses to be stored in the set. The default is
|
||||
\fBinet\fR, i.e IPv4.
|
||||
.TP
|
||||
\fBhashsize\fR \fIvalue\fR
|
||||
The initial hash size for the set, default is 1024. The hash size must be a power
|
||||
of two, the kernel automatically rounds up non power of two hash sizes to the first
|
||||
correct value.
|
||||
.TP
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
The \fBhash:ip,port,ip\fR type of sets require
|
||||
three \fBsrc\fR/\fBdst\fR parameters of the \fBset\fR match and \fBSET\fR
|
||||
target kernel modules.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:ip,port,ip
|
||||
.IP
|
||||
ipset add foo 192.168.1.1,80,10.0.0.1
|
||||
.IP
|
||||
ipset test foo 192.168.1.1,udp:53,10.0.0.1
|
||||
.SS hash:ip,port,net
|
||||
The \fBhash:ip,port,net\fR set type uses a hash to store IP address, port number
|
||||
and IP network address triples. The port number is interpreted together with a
|
||||
protocol (default TCP) and zero protocol number cannot be used. Network
|
||||
address with zero prefix size cannot be stored either.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
For the \fIipaddr\fR and
|
||||
[\fIproto\fR:]\fIport\fR
|
||||
parts of the elements see the descriptions at the
|
||||
\fBhash:ip,port\fR set type. For the \fInetaddr\fR part of the elements
|
||||
see the description at the \fBhash:net\fR set type.
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
|
||||
The protocol family of the IP addresses to be stored in the set. The default is
|
||||
\fBinet\fR, i.e IPv4.
|
||||
.TP
|
||||
\fBhashsize\fR \fIvalue\fR
|
||||
The initial hash size for the set, default is 1024. The hash size must be a power
|
||||
of two, the kernel automatically rounds up non power of two hash sizes to the first
|
||||
correct value.
|
||||
.TP
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
From the \fBset\fR netfilter match point of view the searching for a match
|
||||
always starts from the smallest size of netblock (most specific
|
||||
cidr) to the largest one (least specific cidr) added to the set.
|
||||
When adding/deleting triples
|
||||
to the set by the \fBSET\fR netfilter target, it will be
|
||||
added/deleted by the most specific cidr which can be found in the
|
||||
set, or by the host cidr value if the set is empty.
|
||||
.PP
|
||||
The lookup time grows linearly with the number of the different \fIcidr\fR
|
||||
values added to the set.
|
||||
.PP
|
||||
The \fBhash:ip,port,net\fR type of sets require three \fBsrc\fR/\fBdst\fR parameters of
|
||||
the \fBset\fR match and \fBSET\fR target kernel modules.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:ip,port,net
|
||||
.IP
|
||||
ipset add foo 192.168.1,80,10.0.0/24
|
||||
.IP
|
||||
ipset add foo 192.168.2,25,10.1.0.0/16
|
||||
.IP
|
||||
ipset test foo 192.168.1,80.10.0.0/24
|
||||
.SS hash:net,iface
|
||||
The \fBhash:net,iface\fR set type uses a hash to store different sized IP network
|
||||
address and interface name pairs. Network address with zero prefix size is not
|
||||
accepted.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBfamily\fR { \fBinet\fR | \fBinet6\fR } ] | [ \fBhashsize\fR \fIvalue\fR ] [ \fBmaxelem\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fBphysdev\fR:]\fIiface\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBfamily\fR { \fBinet\fR | \fBinet6\fR }
|
||||
The protocol family of the IP addresses to be stored in the set. The default is
|
||||
\fBinet\fR, i.e IPv4.
|
||||
.TP
|
||||
\fBhashsize\fR \fIvalue\fR
|
||||
The initial hash size for the set, default is 1024. The hash size must be a power
|
||||
of two, the kernel automatically rounds up non power of two hash sizes to the first
|
||||
correct value.
|
||||
.TP
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
For the \fInetaddr\fR part of the elements
|
||||
see the description at the \fBhash:net\fR set type.
|
||||
.PP
|
||||
When adding/deleting/testing entries, if the cidr prefix parameter is not specified,
|
||||
then the host prefix value is assumed. When adding/deleting entries, the exact
|
||||
element is added/deleted and overlapping elements are not checked by the kernel.
|
||||
When testing entries, if a host address is tested, then the kernel tries to match
|
||||
the host address in the networks added to the set and reports the result accordingly.
|
||||
.PP
|
||||
From the \fBset\fR netfilter match point of view the searching for a match
|
||||
always starts from the smallest size of netblock (most specific
|
||||
prefix) to the largest one (least specific prefix) added to the set.
|
||||
When adding/deleting IP
|
||||
addresses to the set by the \fBSET\fR netfilter target, it will be
|
||||
added/deleted by the most specific prefix which can be found in the
|
||||
set, or by the host prefix value if the set is empty.
|
||||
.PP
|
||||
The second direction parameter of the \fBset\fR match and
|
||||
\fBSET\fR target modules corresponds to the incoming/outgoing interface
|
||||
: \fBsrc\fR to the incoming, while \fBdst\fR to the outgoing. When
|
||||
the interface is flagged with \fBphysdev:\fR, the interface is interpreted
|
||||
as the incoming/outgoing bridge port.
|
||||
.PP
|
||||
The lookup time grows linearly with the number of the different prefix
|
||||
values added to the set.
|
||||
.PP
|
||||
The internal restriction of the \fBhash:net,iface\fR set type is that
|
||||
the same network prefix cannot be stored with more than 64 different interfaces
|
||||
in a single set.
|
||||
.PP
|
||||
Examples:
|
||||
.IP
|
||||
ipset create foo hash:net,iface
|
||||
.IP
|
||||
ipset add foo 192.168.0/24,eth0
|
||||
.IP
|
||||
ipset add foo 10.1.0.0/16,eth1
|
||||
.IP
|
||||
ipset test foo 192.168.0/24,eth0
|
||||
.SS list:set
|
||||
The \fBlist:set\fR type uses a simple list in which you can store
|
||||
set names.
|
||||
.PP
|
||||
\fICREATE\-OPTIONS\fR := [ \fBsize\fR \fIvalue\fR ] [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIADD\-ENTRY\fR := \fIsetname\fR [ { \fBbefore\fR | \fBafter\fR } \fIsetname\fR ]
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIsetname\fR [ { \fBbefore\fR | \fBafter\fR } \fIsetname\fR ]
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIsetname\fR [ { \fBbefore\fR | \fBafter\fR } \fIsetname\fR ]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
\fBsize\fR \fIvalue\fR
|
||||
The size of the list, the default is 8.
|
||||
.PP
|
||||
By the \fBipset\fR commad you can add, delete and test set names in a
|
||||
\fBlist:set\fR type of set.
|
||||
.PP
|
||||
By the \fBset\fR match or \fBSET\fR target of netfilter
|
||||
you can test, add or delete entries in the sets added to the \fBlist:set\fR
|
||||
type of set. The match will try to find a matching entry in the sets and
|
||||
the target will try to add an entry to the first set to which it can be added.
|
||||
The number of direction options of the match and target are important: sets which
|
||||
require more parameters than specified are skipped, while sets with equal
|
||||
or less parameters are checked, elements added/deleted. For example if \fIa\fR and
|
||||
\fIb\fR are \fBlist:set\fR type of sets then in the command
|
||||
.IP
|
||||
iptables \-m set \-\-match\-set a src,dst \-j SET \-\-add\-set b src,dst
|
||||
.PP
|
||||
the match and target will skip any set in \fIa\fR and \fIb\fR
|
||||
which stores data triples, but will match all sets with single or double
|
||||
data storage in \fIa\fR set and stop matching at the first successful set,
|
||||
and add src to the first single or src,dst to the first double data storage set
|
||||
in \fIb\fR to which the entry can be added. You can imagine a \fBlist:set\fR
|
||||
type of set as an ordered union of the set elements.
|
||||
.PP
|
||||
Please note: by the \fBipset\fR commad you can add, delete and \fBtest\fR
|
||||
the setnames in a \fBlist:set\fR type of set, and \fBnot\fR the presence of
|
||||
a set's member (such as an IP address).
|
||||
.SH "GENERAL RESTRICTIONS"
|
||||
Zero valued set entries cannot be used with hash methods. Zero protocol value with ports
|
||||
cannot be used.
|
||||
.SH "COMMENTS"
|
||||
If you want to store same size subnets from a given network
|
||||
(say /24 blocks from a /8 network), use the \fBbitmap:ip\fR set type.
|
||||
If you want to store random same size networks (say random /24 blocks),
|
||||
use the \fBhash:ip\fR set type. If you have got random size of netblocks,
|
||||
use \fBhash:net\fR.
|
||||
.PP
|
||||
Backward compatibility is maintained and old \fBipset\fR syntax is still supported.
|
||||
.PP
|
||||
The \fBiptree\fR and \fBiptreemap\fR set types are removed: if you refer to them,
|
||||
they are automatically replaced by \fBhash:ip\fR type of sets.
|
||||
.SH "DIAGNOSTICS"
|
||||
Various error messages are printed to standard error. The exit code
|
||||
is 0 for correct functioning.
|
||||
.SH "BUGS"
|
||||
Bugs? No, just funny features. :\-)
|
||||
OK, just kidding...
|
||||
.SH "SEE ALSO"
|
||||
\fBiptables\fR(8),
|
||||
\fBip6tables\fR(8)
|
||||
.SH "AUTHORS"
|
||||
Jozsef Kadlecsik wrote ipset, which is based on ippool by
|
||||
Joakim Axelsson, Patrick Schaaf and Martin Josefsson.
|
||||
.br
|
||||
Sven Wegener wrote the iptreemap type.
|
||||
.SH "LAST REMARK"
|
||||
\fBI stand on the shoulders of giants.\fR
|
||||
@@ -1,755 +0,0 @@
|
||||
/* Copyright 2000-2002 Joakim Axelsson (gozem@linux.nu)
|
||||
* Patrick Schaaf (bof@bof.de)
|
||||
* Copyright 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.
|
||||
*/
|
||||
#include <ctype.h> /* isspace */
|
||||
#include <stdarg.h> /* va_* */
|
||||
#include <stdbool.h> /* bool */
|
||||
#include <stdio.h> /* fprintf, fgets */
|
||||
#include <stdlib.h> /* exit */
|
||||
#include <string.h> /* str* */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* enum ipset_data */
|
||||
#include <libipset/parse.h> /* ipset_parse_* */
|
||||
#include <libipset/session.h> /* ipset_session_* */
|
||||
#include <libipset/types.h> /* struct ipset_type */
|
||||
#include <libipset/ui.h> /* core options, commands */
|
||||
#include <libipset/utils.h> /* STREQ */
|
||||
|
||||
static char program_name[] = "ipset";
|
||||
static char program_version[] = "6.10-genl-xta";
|
||||
|
||||
static struct ipset_session *session;
|
||||
static uint32_t restore_line;
|
||||
static bool interactive;
|
||||
static char cmdline[1024];
|
||||
static char *newargv[255];
|
||||
static int newargc;
|
||||
|
||||
/* The known set types: (typename, revision, family) is unique */
|
||||
extern struct ipset_type ipset_bitmap_ip0;
|
||||
extern struct ipset_type ipset_bitmap_ipmac0;
|
||||
extern struct ipset_type ipset_bitmap_port0;
|
||||
extern struct ipset_type ipset_hash_ip0;
|
||||
extern struct ipset_type ipset_hash_net0;
|
||||
extern struct ipset_type ipset_hash_net1;
|
||||
extern struct ipset_type ipset_hash_netport1;
|
||||
extern struct ipset_type ipset_hash_netport2;
|
||||
extern struct ipset_type ipset_hash_netiface0;
|
||||
extern struct ipset_type ipset_hash_ipport1;
|
||||
extern struct ipset_type ipset_hash_ipportip1;
|
||||
extern struct ipset_type ipset_hash_ipportnet1;
|
||||
extern struct ipset_type ipset_hash_ipportnet2;
|
||||
extern struct ipset_type ipset_list_set0;
|
||||
|
||||
enum exittype {
|
||||
NO_PROBLEM = 0,
|
||||
OTHER_PROBLEM,
|
||||
PARAMETER_PROBLEM,
|
||||
VERSION_PROBLEM,
|
||||
SESSION_PROBLEM,
|
||||
};
|
||||
|
||||
static int __attribute__((format(printf, 2, 3)))
|
||||
exit_error(int status, const char *msg, ...)
|
||||
{
|
||||
bool quiet = !interactive &&
|
||||
session &&
|
||||
ipset_envopt_test(session, IPSET_ENV_QUIET);
|
||||
|
||||
if (status && msg && !quiet) {
|
||||
va_list args;
|
||||
|
||||
fprintf(stderr, "%s v%s: ", program_name, program_version);
|
||||
va_start(args, msg);
|
||||
vfprintf(stderr, msg, args);
|
||||
va_end(args);
|
||||
if (status != SESSION_PROBLEM)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (status == PARAMETER_PROBLEM)
|
||||
fprintf(stderr,
|
||||
"Try `%s help' for more information.\n",
|
||||
program_name);
|
||||
}
|
||||
/* Ignore errors in interactive mode */
|
||||
if (status && interactive) {
|
||||
if (session)
|
||||
ipset_session_report_reset(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (session)
|
||||
ipset_session_fini(session);
|
||||
|
||||
D("status: %u", status);
|
||||
exit(status > VERSION_PROBLEM ? OTHER_PROBLEM : status);
|
||||
/* Unreached */
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_error(void)
|
||||
{
|
||||
if (ipset_session_warning(session) &&
|
||||
!ipset_envopt_test(session, IPSET_ENV_QUIET))
|
||||
fprintf(stderr, "Warning: %s\n",
|
||||
ipset_session_warning(session));
|
||||
if (ipset_session_error(session))
|
||||
return exit_error(SESSION_PROBLEM, "%s",
|
||||
ipset_session_error(session));
|
||||
|
||||
if (!interactive) {
|
||||
ipset_session_fini(session);
|
||||
exit(OTHER_PROBLEM);
|
||||
}
|
||||
|
||||
ipset_session_report_reset(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
help(void)
|
||||
{
|
||||
const struct ipset_commands *c;
|
||||
const struct ipset_envopts *opt = ipset_envopts;
|
||||
|
||||
printf("%s v%s\n\n"
|
||||
"Usage: %s [options] COMMAND\n\nCommands:\n",
|
||||
program_name, program_version, program_name);
|
||||
|
||||
for (c = ipset_commands; c->cmd; c++)
|
||||
printf("%s %s\n", c->name[0], c->help);
|
||||
printf("\nOptions:\n");
|
||||
|
||||
while (opt->flag) {
|
||||
if (opt->help)
|
||||
printf("%s %s\n", opt->name[0], opt->help);
|
||||
opt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build faked argv from parsed line */
|
||||
static void
|
||||
build_argv(char *buffer)
|
||||
{
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
/* Reset */
|
||||
for (i = 1; i < newargc; i++)
|
||||
newargv[i] = NULL;
|
||||
newargc = 1;
|
||||
|
||||
ptr = strtok(buffer, " \t\r\n");
|
||||
newargv[newargc++] = ptr;
|
||||
while ((ptr = strtok(NULL, " \t\r\n")) != NULL) {
|
||||
if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
|
||||
newargv[newargc++] = ptr;
|
||||
else {
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Line is too long to parse.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Main parser function, workhorse */
|
||||
int parse_commandline(int argc, char *argv[]);
|
||||
|
||||
/*
|
||||
* Performs a restore from stdin
|
||||
*/
|
||||
static int
|
||||
restore(char *argv0)
|
||||
{
|
||||
int ret = 0;
|
||||
char *c;
|
||||
|
||||
/* Initialize newargv/newargc */
|
||||
newargc = 0;
|
||||
newargv[newargc++] = argv0;
|
||||
|
||||
while (fgets(cmdline, sizeof(cmdline), stdin)) {
|
||||
restore_line++;
|
||||
c = cmdline;
|
||||
while (isspace(c[0]))
|
||||
c++;
|
||||
if (c[0] == '\0' || c[0] == '#')
|
||||
continue;
|
||||
else if (STREQ(c, "COMMIT\n") || STREQ(c, "COMMIT\r\n")) {
|
||||
ret = ipset_commit(session);
|
||||
if (ret < 0)
|
||||
handle_error();
|
||||
continue;
|
||||
}
|
||||
/* Build faked argv, argc */
|
||||
build_argv(c);
|
||||
|
||||
/* Execute line */
|
||||
ret = parse_commandline(newargc, newargv);
|
||||
if (ret < 0)
|
||||
handle_error();
|
||||
}
|
||||
/* implicit "COMMIT" at EOF */
|
||||
ret = ipset_commit(session);
|
||||
if (ret < 0)
|
||||
handle_error();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
call_parser(int *argc, char *argv[], const struct ipset_arg *args)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct ipset_arg *arg;
|
||||
const char *optstr;
|
||||
|
||||
/* Currently CREATE and ADT may have got additional arguments */
|
||||
if (!args && *argc > 1)
|
||||
goto err_unknown;
|
||||
while (*argc > 1) {
|
||||
for (arg = args; arg->opt; arg++) {
|
||||
D("argc: %u, %s vs %s", *argc, argv[1], arg->name[0]);
|
||||
if (!(ipset_match_option(argv[1], arg->name)))
|
||||
continue;
|
||||
|
||||
optstr = argv[1];
|
||||
/* Shift off matched option */
|
||||
D("match %s", arg->name[0]);
|
||||
ipset_shift_argv(argc, argv, 1);
|
||||
switch (arg->has_arg) {
|
||||
case IPSET_MANDATORY_ARG:
|
||||
if (*argc < 2)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Missing mandatory argument "
|
||||
"of option `%s'",
|
||||
arg->name[0]);
|
||||
/* Fall through */
|
||||
case IPSET_OPTIONAL_ARG:
|
||||
if (*argc >= 2) {
|
||||
ret = ipset_call_parser(session,
|
||||
arg, argv[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipset_shift_argv(argc, argv, 1);
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
default:
|
||||
ret = ipset_call_parser(session, arg, optstr);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!arg->opt)
|
||||
goto err_unknown;
|
||||
}
|
||||
return ret;
|
||||
|
||||
err_unknown:
|
||||
return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'", argv[1]);
|
||||
}
|
||||
|
||||
static enum ipset_adt
|
||||
cmd2cmd(int cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_ADD:
|
||||
return IPSET_ADD;
|
||||
case IPSET_CMD_DEL:
|
||||
return IPSET_DEL;
|
||||
case IPSET_CMD_TEST:
|
||||
return IPSET_TEST;
|
||||
case IPSET_CMD_CREATE:
|
||||
return IPSET_CREATE;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_mandatory(const struct ipset_type *type, enum ipset_cmd command)
|
||||
{
|
||||
enum ipset_adt cmd = cmd2cmd(command);
|
||||
uint64_t flags = ipset_data_flags(ipset_session_data(session));
|
||||
uint64_t mandatory = type->mandatory[cmd];
|
||||
const struct ipset_arg *arg = type->args[cmd];
|
||||
|
||||
/* Range can be expressed by ip/cidr */
|
||||
if (flags & IPSET_FLAG(IPSET_OPT_CIDR))
|
||||
flags |= IPSET_FLAG(IPSET_OPT_IP_TO);
|
||||
|
||||
mandatory &= ~flags;
|
||||
if (!mandatory)
|
||||
return;
|
||||
if (!arg) {
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"There are missing mandatory flags "
|
||||
"but can't check them. "
|
||||
"It's a bug, please report the problem.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (; arg->opt; arg++)
|
||||
if (mandatory & IPSET_FLAG(arg->opt)) {
|
||||
exit_error(PARAMETER_PROBLEM,
|
||||
"Mandatory option `%s' is missing",
|
||||
arg->name[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *
|
||||
cmd2name(enum ipset_cmd cmd)
|
||||
{
|
||||
const struct ipset_commands *c;
|
||||
|
||||
for (c = ipset_commands; c->cmd; c++)
|
||||
if (cmd == c->cmd)
|
||||
return c->name[0];
|
||||
return "unknown command";
|
||||
}
|
||||
|
||||
static const char *
|
||||
session_family(void)
|
||||
{
|
||||
switch (ipset_data_family(ipset_session_data(session))) {
|
||||
case NFPROTO_IPV4:
|
||||
return "inet";
|
||||
case NFPROTO_IPV6:
|
||||
return "inet6";
|
||||
default:
|
||||
return "unspec";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_allowed(const struct ipset_type *type, enum ipset_cmd command)
|
||||
{
|
||||
uint64_t flags = ipset_data_flags(ipset_session_data(session));
|
||||
enum ipset_adt cmd = cmd2cmd(command);
|
||||
uint64_t allowed = type->full[cmd];
|
||||
uint64_t cmdflags = command == IPSET_CMD_CREATE
|
||||
? IPSET_CREATE_FLAGS : IPSET_ADT_FLAGS;
|
||||
const struct ipset_arg *arg = type->args[cmd];
|
||||
enum ipset_opt i;
|
||||
|
||||
/* Range can be expressed by ip/cidr or from-to */
|
||||
if (allowed & IPSET_FLAG(IPSET_OPT_IP_TO))
|
||||
allowed |= IPSET_FLAG(IPSET_OPT_CIDR);
|
||||
|
||||
for (i = IPSET_OPT_IP; i < IPSET_OPT_FLAGS; i++) {
|
||||
if (!(cmdflags & IPSET_FLAG(i)) ||
|
||||
(allowed & IPSET_FLAG(i)) ||
|
||||
!(flags & IPSET_FLAG(i)))
|
||||
continue;
|
||||
/* Not allowed element-expressions */
|
||||
switch (i) {
|
||||
case IPSET_OPT_CIDR:
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"IP/CIDR range is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
case IPSET_OPT_IP_TO:
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"FROM-TO IP range is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
case IPSET_OPT_PORT_TO:
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"FROM-TO port range is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Other options */
|
||||
if (!arg) {
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"There are not allowed options (%u) "
|
||||
"but option list is NULL. "
|
||||
"It's a bug, please report the problem.", i);
|
||||
return;
|
||||
}
|
||||
for (; arg->opt; arg++) {
|
||||
if (arg->opt != i)
|
||||
continue;
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"%s parameter is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
arg->name[0],
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
}
|
||||
exit_error(OTHER_PROBLEM,
|
||||
"There are not allowed options (%u) "
|
||||
"but can't resolve them. "
|
||||
"It's a bug, please report the problem.", i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct ipset_type *
|
||||
type_find(const char *name)
|
||||
{
|
||||
const struct ipset_type *t = ipset_types();
|
||||
|
||||
while (t) {
|
||||
if (ipset_match_typename(name, t))
|
||||
return t;
|
||||
t = t->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Workhorse */
|
||||
int
|
||||
parse_commandline(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
enum ipset_cmd cmd = IPSET_CMD_NONE;
|
||||
int i;
|
||||
char *arg0 = NULL, *arg1 = NULL, *c;
|
||||
const struct ipset_envopts *opt;
|
||||
const struct ipset_commands *command;
|
||||
const struct ipset_type *type;
|
||||
|
||||
/* Set session lineno to report parser errors correctly */
|
||||
ipset_session_lineno(session, restore_line);
|
||||
|
||||
/* Commandline parsing, somewhat similar to that of 'ip' */
|
||||
|
||||
/* First: parse core options */
|
||||
for (opt = ipset_envopts; opt->flag; opt++) {
|
||||
for (i = 1; i < argc; ) {
|
||||
if (!ipset_match_envopt(argv[i], opt->name)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
/* Shift off matched option */
|
||||
ipset_shift_argv(&argc, argv, i);
|
||||
switch (opt->has_arg) {
|
||||
case IPSET_MANDATORY_ARG:
|
||||
if (i + 1 > argc)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Missing mandatory argument "
|
||||
"to option %s",
|
||||
opt->name[0]);
|
||||
/* Fall through */
|
||||
case IPSET_OPTIONAL_ARG:
|
||||
if (i + 1 <= argc) {
|
||||
ret = opt->parse(session, opt->flag,
|
||||
argv[i]);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
ipset_shift_argv(&argc, argv, i);
|
||||
}
|
||||
break;
|
||||
case IPSET_NO_ARG:
|
||||
ret = opt->parse(session, opt->flag,
|
||||
opt->name[0]);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Second: parse command */
|
||||
for (command = ipset_commands;
|
||||
argc > 1 && command->cmd && cmd == IPSET_CMD_NONE;
|
||||
command++) {
|
||||
if (!ipset_match_cmd(argv[1], command->name))
|
||||
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 */
|
||||
ipset_shift_argv(&argc, argv, 1);
|
||||
cmd = command->cmd;
|
||||
switch (command->has_arg) {
|
||||
case IPSET_MANDATORY_ARG:
|
||||
case IPSET_MANDATORY_ARG2:
|
||||
if (argc < 2)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Missing mandatory argument "
|
||||
"to command %s",
|
||||
command->name[0]);
|
||||
/* Fall through */
|
||||
case IPSET_OPTIONAL_ARG:
|
||||
arg0 = argv[1];
|
||||
if (argc >= 2)
|
||||
/* Shift off first arg */
|
||||
ipset_shift_argv(&argc, argv, 1);
|
||||
break;
|
||||
default:
|
||||
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 */
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_NONE:
|
||||
if (interactive) {
|
||||
printf("No command specified\n");
|
||||
return 0;
|
||||
}
|
||||
if (argc > 1 && STREQ(argv[1], "-")) {
|
||||
interactive = true;
|
||||
printf("%s> ", program_name);
|
||||
/* Initialize newargv/newargc */
|
||||
newargv[newargc++] = program_name;
|
||||
while (fgets(cmdline, sizeof(cmdline), stdin)) {
|
||||
c = cmdline;
|
||||
while (isspace(c[0]))
|
||||
c++;
|
||||
if (c[0] == '\0' || c[0] == '#')
|
||||
continue;
|
||||
/* Build fake argv, argc */
|
||||
build_argv(c);
|
||||
/* Execute line: ignore errors */
|
||||
parse_commandline(newargc, newargv);
|
||||
printf("%s> ", program_name);
|
||||
}
|
||||
return exit_error(NO_PROBLEM, NULL);
|
||||
}
|
||||
if (argc > 1)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"No command specified: unknown argument %s",
|
||||
argv[1]);
|
||||
return exit_error(PARAMETER_PROBLEM, "No command specified.");
|
||||
case IPSET_CMD_VERSION:
|
||||
printf("%s v%s, protocol version: %u\n",
|
||||
program_name, program_version, IPSET_PROTOCOL);
|
||||
if (interactive)
|
||||
return 0;
|
||||
return exit_error(NO_PROBLEM, NULL);
|
||||
case IPSET_CMD_HELP:
|
||||
help();
|
||||
|
||||
if (interactive ||
|
||||
!ipset_envopt_test(session, IPSET_ENV_QUIET)) {
|
||||
if (arg0) {
|
||||
/* Type-specific help, without kernel checking */
|
||||
type = type_find(arg0);
|
||||
if (!type)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Unknown settype: `%s'", arg0);
|
||||
printf("\n%s type specific options:\n\n%s",
|
||||
type->name, type->usage);
|
||||
if (type->usagefn)
|
||||
type->usagefn();
|
||||
if (type->family == NFPROTO_UNSPEC)
|
||||
printf("\nType %s is family neutral.\n",
|
||||
type->name);
|
||||
else if (type->family == NFPROTO_IPSET_IPV46)
|
||||
printf("\nType %s supports INET "
|
||||
"and INET6.\n",
|
||||
type->name);
|
||||
else
|
||||
printf("\nType %s supports family "
|
||||
"%s only.\n",
|
||||
type->name,
|
||||
type->family == NFPROTO_IPV4
|
||||
? "INET" : "INET6");
|
||||
} else {
|
||||
printf("\nSupported set types:\n");
|
||||
type = ipset_types();
|
||||
while (type) {
|
||||
printf(" %s\n", type->name);
|
||||
type = type->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (interactive)
|
||||
return 0;
|
||||
return exit_error(NO_PROBLEM, NULL);
|
||||
case IPSET_CMD_QUIT:
|
||||
return exit_error(NO_PROBLEM, NULL);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Forth: parse command args and issue the command */
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_CREATE:
|
||||
/* Args: setname typename [type specific options] */
|
||||
ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
|
||||
ret = ipset_parse_typename(session, IPSET_OPT_TYPENAME, arg1);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
|
||||
type = ipset_type_get(session, cmd);
|
||||
if (type == NULL)
|
||||
return handle_error();
|
||||
|
||||
/* Parse create options */
|
||||
ret = call_parser(&argc, argv, type->args[IPSET_CREATE]);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
else if (ret)
|
||||
return ret;
|
||||
|
||||
/* Check mandatory, then allowed options */
|
||||
check_mandatory(type, cmd);
|
||||
check_allowed(type, cmd);
|
||||
|
||||
break;
|
||||
case IPSET_CMD_DESTROY:
|
||||
case IPSET_CMD_FLUSH:
|
||||
case IPSET_CMD_LIST:
|
||||
case IPSET_CMD_SAVE:
|
||||
/* Args: [setname] */
|
||||
if (arg0) {
|
||||
ret = ipset_parse_setname(session,
|
||||
IPSET_SETNAME, arg0);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
}
|
||||
break;
|
||||
|
||||
case IPSET_CMD_RENAME:
|
||||
case IPSET_CMD_SWAP:
|
||||
/* Args: from-setname to-setname */
|
||||
ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
ret = ipset_parse_setname(session, IPSET_OPT_SETNAME2, arg1);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
break;
|
||||
|
||||
case IPSET_CMD_RESTORE:
|
||||
/* Restore mode */
|
||||
if (argc > 1)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Unknown argument %s", argv[1]);
|
||||
return restore(argv[0]);
|
||||
case IPSET_CMD_ADD:
|
||||
case IPSET_CMD_DEL:
|
||||
case IPSET_CMD_TEST:
|
||||
D("ADT: setname %s", arg0);
|
||||
/* Args: setname ip [options] */
|
||||
ret = ipset_parse_setname(session, IPSET_SETNAME, arg0);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
|
||||
type = ipset_type_get(session, cmd);
|
||||
if (type == NULL)
|
||||
return handle_error();
|
||||
|
||||
ret = ipset_parse_elem(session, type->last_elem_optional, arg1);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
|
||||
/* Parse additional ADT options */
|
||||
ret = call_parser(&argc, argv, type->args[cmd2cmd(cmd)]);
|
||||
if (ret < 0)
|
||||
return handle_error();
|
||||
else if (ret)
|
||||
return ret;
|
||||
|
||||
/* Check mandatory, then allowed options */
|
||||
check_mandatory(type, cmd);
|
||||
check_allowed(type, cmd);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
return exit_error(PARAMETER_PROBLEM,
|
||||
"Unknown argument %s", argv[1]);
|
||||
ret = ipset_cmd(session, cmd, restore_line);
|
||||
D("ret %d", ret);
|
||||
/* Special case for TEST and non-quiet mode */
|
||||
if (cmd == IPSET_CMD_TEST && ipset_session_warning(session)) {
|
||||
if (!ipset_envopt_test(session, IPSET_ENV_QUIET))
|
||||
fprintf(stderr, "%s", ipset_session_warning(session));
|
||||
ipset_session_report_reset(session);
|
||||
}
|
||||
if (ret < 0)
|
||||
handle_error();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Register types */
|
||||
ipset_type_add(&ipset_bitmap_ip0);
|
||||
ipset_type_add(&ipset_bitmap_ipmac0);
|
||||
ipset_type_add(&ipset_bitmap_port0);
|
||||
ipset_type_add(&ipset_hash_ip0);
|
||||
ipset_type_add(&ipset_hash_net0);
|
||||
ipset_type_add(&ipset_hash_net1);
|
||||
ipset_type_add(&ipset_hash_netport1);
|
||||
ipset_type_add(&ipset_hash_netport2);
|
||||
ipset_type_add(&ipset_hash_netiface0);
|
||||
ipset_type_add(&ipset_hash_ipport1);
|
||||
ipset_type_add(&ipset_hash_ipportip1);
|
||||
ipset_type_add(&ipset_hash_ipportnet1);
|
||||
ipset_type_add(&ipset_hash_ipportnet2);
|
||||
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.");
|
||||
|
||||
ret = parse_commandline(argc, argv);
|
||||
|
||||
ipset_session_fini(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg bitmap_ip_create_args[] = {
|
||||
{ .name = { "range", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_netrange, .print = ipset_print_ip,
|
||||
},
|
||||
{ .name = { "netmask", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_NETMASK,
|
||||
.parse = ipset_parse_netmask, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Backward compatibility */
|
||||
{ .name = { "from", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_single_ip,
|
||||
},
|
||||
{ .name = { "to", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP_TO,
|
||||
.parse = ipset_parse_single_ip,
|
||||
},
|
||||
{ .name = { "network", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_net,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg bitmap_ip_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char bitmap_ip_usage[] =
|
||||
"create SETNAME bitmap:ip range IP/CIDR|FROM-TO\n"
|
||||
" [netmask CIDR] [timeout VALUE]\n"
|
||||
"add SETNAME IP|IP/CIDR|FROM-TO [timeout VALUE]\n"
|
||||
"del SETNAME IP|IP/CIDR|FROM-TO\n"
|
||||
"test SETNAME IP\n\n"
|
||||
"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
|
||||
" CIDR is a valid IPv4 CIDR prefix.\n";
|
||||
|
||||
struct ipset_type ipset_bitmap_ip0 = {
|
||||
.name = "bitmap:ip",
|
||||
.alias = { "ipmap", NULL },
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = bitmap_ip_create_args,
|
||||
[IPSET_ADD] = bitmap_ip_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_NETMASK)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
|
||||
.usage = bitmap_ip_usage,
|
||||
};
|
||||
@@ -1,100 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg bitmap_ipmac_create_args[] = {
|
||||
{ .name = { "range", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_netrange, .print = ipset_print_ip,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Backward compatibility */
|
||||
{ .name = { "from", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_single_ip,
|
||||
},
|
||||
{ .name = { "to", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP_TO,
|
||||
.parse = ipset_parse_single_ip,
|
||||
},
|
||||
{ .name = { "network", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_net,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg bitmap_ipmac_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char bitmap_ipmac_usage[] =
|
||||
"create SETNAME bitmap:ip,mac range IP/CIDR|FROM-TO\n"
|
||||
" [matchunset] [timeout VALUE]\n"
|
||||
"add SETNAME IP[,MAC] [timeout VALUE]\n"
|
||||
"del SETNAME IP[,MAC]\n"
|
||||
"test SETNAME IP[,MAC]\n\n"
|
||||
"where IP, FROM and TO are IPv4 addresses (or hostnames),\n"
|
||||
" CIDR is a valid IPv4 CIDR prefix,\n"
|
||||
" MAC is a valid MAC address.\n";
|
||||
|
||||
struct ipset_type ipset_bitmap_ipmac0 = {
|
||||
.name = "bitmap:ip,mac",
|
||||
.alias = { "macipmap", NULL },
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.last_elem_optional = true,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_single_ip,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_ether,
|
||||
.print = ipset_print_ether,
|
||||
.opt = IPSET_OPT_ETHER
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = bitmap_ipmac_create_args,
|
||||
[IPSET_ADD] = bitmap_ipmac_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_ETHER)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_ETHER),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_ETHER),
|
||||
},
|
||||
|
||||
.usage = bitmap_ipmac_usage,
|
||||
};
|
||||
@@ -1,87 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg bitmap_port_create_args[] = {
|
||||
{ .name = { "range", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PORT,
|
||||
.parse = ipset_parse_tcp_port, .print = ipset_print_port,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Backward compatibility */
|
||||
{ .name = { "from", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PORT,
|
||||
.parse = ipset_parse_single_tcp_port,
|
||||
},
|
||||
{ .name = { "to", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PORT_TO,
|
||||
.parse = ipset_parse_single_tcp_port,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg bitmap_port_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char bitmap_port_usage[] =
|
||||
"create SETNAME bitmap:port range FROM-TO\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME PORT|FROM-TO [timeout VALUE]\n"
|
||||
"del SETNAME PORT|FROM-TO\n"
|
||||
"test SETNAME PORT\n\n"
|
||||
"where PORT, FROM and TO are port numbers or port names from /etc/services.\n";
|
||||
|
||||
struct ipset_type ipset_bitmap_port0 = {
|
||||
.name = "bitmap:port",
|
||||
.alias = { "portmap", NULL },
|
||||
.revision = 0,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_tcp_port,
|
||||
.print = ipset_print_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = bitmap_port_create_args,
|
||||
[IPSET_ADD] = bitmap_port_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_PORT),
|
||||
},
|
||||
|
||||
.usage = bitmap_port_usage,
|
||||
};
|
||||
@@ -1,119 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg hash_ip_create_args[] = {
|
||||
{ .name = { "family", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family, .print = ipset_print_family,
|
||||
},
|
||||
/* Alias: family inet */
|
||||
{ .name = { "-4", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
/* Alias: family inet6 */
|
||||
{ .name = { "-6", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
{ .name = { "hashsize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "maxelem", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "netmask", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_NETMASK,
|
||||
.parse = ipset_parse_netmask, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Ignored options: backward compatibilty */
|
||||
{ .name = { "probes", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "resize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_RESIZE,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "gc", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_GC,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_ip_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_ip_usage[] =
|
||||
"create SETNAME hash:ip\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [netmask CIDR] [timeout VALUE]\n"
|
||||
"add SETNAME IP [timeout VALUE]\n"
|
||||
"del SETNAME IP\n"
|
||||
"test SETNAME IP\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" is supported for IPv4.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ip0 = {
|
||||
.name = "hash:ip",
|
||||
.alias = { "iphash", NULL },
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ip_create_args,
|
||||
[IPSET_ADD] = hash_ip_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_NETMASK)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
|
||||
.usage = hash_ip_usage,
|
||||
};
|
||||
@@ -1,144 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/ui.h> /* ipset_port_usage */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg hash_ipport_create_args[] = {
|
||||
{ .name = { "family", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family, .print = ipset_print_family,
|
||||
},
|
||||
/* Alias: family inet */
|
||||
{ .name = { "-4", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
/* Alias: family inet6 */
|
||||
{ .name = { "-6", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
{ .name = { "hashsize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "maxelem", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Backward compatibility */
|
||||
{ .name = { "probes", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "resize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_RESIZE,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "from", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ .name = { "to", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP_TO,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ .name = { "network", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_ipport_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_ipport1_usage[] =
|
||||
"create SETNAME hash:ip,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP,PROTO:PORT [timeout VALUE]\n"
|
||||
"del SETNAME IP,PROTO:PORT\n"
|
||||
"test SETNAME IP,PROTO:PORT\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname).\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" is supported for IPv4.\n"
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipport1 = {
|
||||
.name = "hash:ip,port",
|
||||
.alias = { "ipporthash", NULL },
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ipport_create_args,
|
||||
[IPSET_ADD] = hash_ipport_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
},
|
||||
|
||||
.usage = hash_ipport1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
@@ -1,155 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/ui.h> /* ipset_port_usage */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg hash_ipportip_create_args[] = {
|
||||
{ .name = { "family", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family, .print = ipset_print_family,
|
||||
},
|
||||
/* Alias: family inet */
|
||||
{ .name = { "-4", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
/* Alias: family inet6 */
|
||||
{ .name = { "-6", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
{ .name = { "hashsize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "maxelem", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Backward compatibility */
|
||||
{ .name = { "probes", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "resize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_RESIZE,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "from", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ .name = { "to", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP_TO,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ .name = { "network", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_ipportip_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_ipportip1_usage[] =
|
||||
"create SETNAME hash:ip,port,ip\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP,PROTO:PORT,IP [timeout VALUE]\n"
|
||||
"del SETNAME IP,PROTO:PORT,IP\n"
|
||||
"test SETNAME IP,PROTO:PORT,IP\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname).\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" in the first IP component is supported for IPv4.\n"
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportip1 = {
|
||||
.name = "hash:ip,port,ip",
|
||||
.alias = { "ipportiphash", NULL },
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
[IPSET_DIM_THREE - 1] = {
|
||||
.parse = ipset_parse_single_ip,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP2
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ipportip_create_args,
|
||||
[IPSET_ADD] = hash_ipportip_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportip1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
@@ -1,254 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/ui.h> /* ipset_port_usage */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg hash_ipportnet_create_args[] = {
|
||||
{ .name = { "family", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family, .print = ipset_print_family,
|
||||
},
|
||||
/* Alias: family inet */
|
||||
{ .name = { "-4", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
/* Alias: family inet6 */
|
||||
{ .name = { "-6", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
{ .name = { "hashsize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "maxelem", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Backward compatibility */
|
||||
{ .name = { "probes", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "resize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_RESIZE,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "from", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ .name = { "to", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP_TO,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ .name = { "network", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_IP,
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_ipportnet_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_ipportnet1_usage[] =
|
||||
"create SETNAME hash:ip,port,net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n"
|
||||
"del SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
|
||||
"test SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" in the first IP component is supported for IPv4.\n"
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportnet1 = {
|
||||
.name = "hash:ip,port,net",
|
||||
.alias = { "ipportnethash", NULL },
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
[IPSET_DIM_THREE - 1] = {
|
||||
.parse = ipset_parse_ipnet,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP2
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ipportnet_create_args,
|
||||
[IPSET_ADD] = hash_ipportnet_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportnet1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
||||
static const char hash_ipportnet2_usage[] =
|
||||
"create SETNAME hash:ip,port,net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP,PROTO:PORT,IP[/CIDR] [timeout VALUE]\n"
|
||||
"del SETNAME IP,PROTO:PORT,IP[/CIDR]\n"
|
||||
"test SETNAME IP,PROTO:PORT,IP[/CIDR]\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP are valid IPv4 or IPv6 addresses (or hostnames),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements in IP/CIDR or FROM-TO form\n"
|
||||
" in both IP components are supported for IPv4.\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_ipportnet2 = {
|
||||
.name = "hash:ip,port,net",
|
||||
.alias = { "ipportnethash", NULL },
|
||||
.revision = 2,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
[IPSET_DIM_THREE - 1] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP2
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ipportnet_create_args,
|
||||
[IPSET_ADD] = hash_ipportnet_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2_TO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_IP2)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportnet2_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg hash_net_create_args[] = {
|
||||
{ .name = { "family", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family, .print = ipset_print_family,
|
||||
},
|
||||
/* Alias: family inet */
|
||||
{ .name = { "-4", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
/* Alias: family inet6 */
|
||||
{ .name = { "-6", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
{ .name = { "hashsize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "maxelem", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
/* Ignored options: backward compatibilty */
|
||||
{ .name = { "probes", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_PROBES,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "resize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_RESIZE,
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_net_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_net0_usage[] =
|
||||
"create SETNAME hash:net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP[/CIDR] [timeout VALUE]\n"
|
||||
"del SETNAME IP[/CIDR]\n"
|
||||
"test SETNAME IP[/CIDR]\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is an IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n";
|
||||
|
||||
struct ipset_type ipset_hash_net0 = {
|
||||
.name = "hash:net",
|
||||
.alias = { "nethash", NULL },
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ipnet,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_net_create_args,
|
||||
[IPSET_ADD] = hash_net_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_net0_usage,
|
||||
};
|
||||
|
||||
static const char hash_net1_usage[] =
|
||||
"create SETNAME hash:net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP[/CIDR]|FROM-TO [timeout VALUE]\n"
|
||||
"del SETNAME IP[/CIDR]|FROM-TO\n"
|
||||
"test SETNAME IP[/CIDR]\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is an IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" IP range is not supported with IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_net1 = {
|
||||
.name = "hash:net",
|
||||
.alias = { "nethash", NULL },
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_net_create_args,
|
||||
[IPSET_ADD] = hash_net_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_net1_usage,
|
||||
};
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/* Copyright 2011 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/ui.h> /* ipset_port_usage */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg hash_netiface_create_args[] = {
|
||||
{ .name = { "family", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family, .print = ipset_print_family,
|
||||
},
|
||||
/* Alias: family inet */
|
||||
{ .name = { "-4", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
/* Alias: family inet6 */
|
||||
{ .name = { "-6", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
{ .name = { "hashsize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "maxelem", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_netiface_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_netiface_usage[] =
|
||||
"create SETNAME hash:net,iface\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE [timeout VALUE]\n"
|
||||
"del SETNAME IP[/CIDR]|FROM-TO,[physdev:]IFACE\n"
|
||||
"test SETNAME IP[/CIDR],[physdev:]IFACE\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements with IPv4 is supported.\n";
|
||||
|
||||
struct ipset_type ipset_hash_netiface0 = {
|
||||
.name = "hash:net,iface",
|
||||
.alias = { "netifacehash", NULL },
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_iface,
|
||||
.print = ipset_print_iface,
|
||||
.opt = IPSET_OPT_IFACE
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_netiface_create_args,
|
||||
[IPSET_ADD] = hash_netiface_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE)
|
||||
| IPSET_FLAG(IPSET_OPT_PHYSDEV)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE)
|
||||
| IPSET_FLAG(IPSET_OPT_PHYSDEV),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_IFACE)
|
||||
| IPSET_FLAG(IPSET_OPT_PHYSDEV),
|
||||
},
|
||||
|
||||
.usage = hash_netiface_usage,
|
||||
};
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/ui.h> /* ipset_port_usage */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg hash_netport_create_args[] = {
|
||||
{ .name = { "family", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family, .print = ipset_print_family,
|
||||
},
|
||||
/* Alias: family inet */
|
||||
{ .name = { "-4", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
/* Alias: family inet6 */
|
||||
{ .name = { "-6", NULL },
|
||||
.has_arg = IPSET_NO_ARG, .opt = IPSET_OPT_FAMILY,
|
||||
.parse = ipset_parse_family,
|
||||
},
|
||||
{ .name = { "hashsize", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_HASHSIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "maxelem", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_MAXELEM,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_netport_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char hash_netport1_usage[] =
|
||||
"create SETNAME hash:net,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP[/CIDR],PROTO:PORT [timeout VALUE]\n"
|
||||
"del SETNAME IP[/CIDR],PROTO:PORT\n"
|
||||
"test SETNAME IP[/CIDR],PROTO:PORT\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_netport1 = {
|
||||
.name = "hash:net,port",
|
||||
.alias = { "netporthash", NULL },
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ipnet,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_netport_create_args,
|
||||
[IPSET_ADD] = hash_netport_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_netport1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
||||
static const char hash_netport2_usage[] =
|
||||
"create SETNAME hash:net,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
" [timeout VALUE]\n"
|
||||
"add SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT [timeout VALUE]\n"
|
||||
"del SETNAME IP[/CIDR]|FROM-TO,PROTO:PORT\n"
|
||||
"test SETNAME IP[/CIDR],PROTO:PORT\n\n"
|
||||
"where depending on the INET family\n"
|
||||
" IP is a valid IPv4 or IPv6 address (or hostname),\n"
|
||||
" CIDR is a valid IPv4 or IPv6 CIDR prefix.\n"
|
||||
" Adding/deleting multiple elements with IPv4 is 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_netport2 = {
|
||||
.name = "hash:net,port",
|
||||
.alias = { "netporthash", NULL },
|
||||
.revision = 2,
|
||||
.family = NFPROTO_IPSET_IPV46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO - 1] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
},
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_netport_create_args,
|
||||
[IPSET_ADD] = hash_netport_add_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_HASHSIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_MAXELEM)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT_TO)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_IP)
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR)
|
||||
| IPSET_FLAG(IPSET_OPT_PORT)
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
},
|
||||
|
||||
.usage = hash_netport2_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
@@ -1,91 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
#include <libipset/parse.h> /* parser functions */
|
||||
#include <libipset/print.h> /* printing functions */
|
||||
#include <libipset/types.h> /* prototypes */
|
||||
|
||||
/* Parse commandline arguments */
|
||||
static const struct ipset_arg list_set_create_args[] = {
|
||||
{ .name = { "size", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_SIZE,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct ipset_arg list_set_adt_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_TIMEOUT,
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ .name = { "before", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_NAMEREF,
|
||||
.parse = ipset_parse_before,
|
||||
},
|
||||
{ .name = { "after", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .opt = IPSET_OPT_NAMEREF,
|
||||
.parse = ipset_parse_after,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const char list_set_usage[] =
|
||||
"create SETNAME list:set\n"
|
||||
" [size VALUE] [timeout VALUE]\n"
|
||||
"add SETNAME NAME [before|after NAME] [timeout VALUE]\n"
|
||||
"del SETNAME NAME [before|after NAME]\n"
|
||||
"test SETNAME NAME [before|after NAME]\n\n"
|
||||
"where NAME are existing set names.\n";
|
||||
|
||||
struct ipset_type ipset_list_set0 = {
|
||||
.name = "list:set",
|
||||
.alias = { "setlist", NULL },
|
||||
.revision = 0,
|
||||
.family = NFPROTO_UNSPEC,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE - 1] = {
|
||||
.parse = ipset_parse_setname,
|
||||
.print = ipset_print_name,
|
||||
.opt = IPSET_OPT_NAME
|
||||
},
|
||||
},
|
||||
.compat_parse_elem = ipset_parse_name_compat,
|
||||
.args = {
|
||||
[IPSET_CREATE] = list_set_create_args,
|
||||
[IPSET_ADD] = list_set_adt_args,
|
||||
[IPSET_DEL] = list_set_adt_args,
|
||||
[IPSET_TEST] = list_set_adt_args,
|
||||
},
|
||||
.mandatory = {
|
||||
[IPSET_CREATE] = 0,
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME),
|
||||
},
|
||||
.full = {
|
||||
[IPSET_CREATE] = IPSET_FLAG(IPSET_OPT_SIZE)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_ADD] = IPSET_FLAG(IPSET_OPT_NAME)
|
||||
| IPSET_FLAG(IPSET_OPT_BEFORE)
|
||||
| IPSET_FLAG(IPSET_OPT_NAMEREF)
|
||||
| IPSET_FLAG(IPSET_OPT_TIMEOUT),
|
||||
[IPSET_DEL] = IPSET_FLAG(IPSET_OPT_NAME)
|
||||
| IPSET_FLAG(IPSET_OPT_BEFORE)
|
||||
| IPSET_FLAG(IPSET_OPT_NAMEREF),
|
||||
[IPSET_TEST] = IPSET_FLAG(IPSET_OPT_NAME)
|
||||
| IPSET_FLAG(IPSET_OPT_BEFORE)
|
||||
| IPSET_FLAG(IPSET_OPT_NAMEREF),
|
||||
},
|
||||
|
||||
.usage = list_set_usage,
|
||||
};
|
||||
@@ -1,289 +0,0 @@
|
||||
/* Copyright 2007-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.
|
||||
*/
|
||||
#include <assert.h> /* assert */
|
||||
#include <ctype.h> /* tolower */
|
||||
#include <string.h> /* memcmp, str* */
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* IPSET_CMD_* */
|
||||
#include <libipset/icmp.h> /* id_to_icmp */
|
||||
#include <libipset/icmpv6.h> /* id_to_icmpv6 */
|
||||
#include <libipset/types.h> /* IPSET_*_ARG */
|
||||
#include <libipset/session.h> /* ipset_envopt_parse */
|
||||
#include <libipset/parse.h> /* ipset_parse_family */
|
||||
#include <libipset/print.h> /* ipset_print_family */
|
||||
#include <libipset/utils.h> /* STREQ */
|
||||
#include <libipset/ui.h> /* prototypes */
|
||||
|
||||
/* Commands and environment options */
|
||||
|
||||
const struct ipset_commands ipset_commands[] = {
|
||||
/* Order is important */
|
||||
|
||||
{ /* c[reate], --create, n[ew], -N */
|
||||
.cmd = IPSET_CMD_CREATE,
|
||||
.name = { "create", "new" },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "SETNAME TYPENAME [type-specific-options]\n"
|
||||
" Create a new set",
|
||||
},
|
||||
{ /* a[dd], --add, -A */
|
||||
.cmd = IPSET_CMD_ADD,
|
||||
.name = { "add", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "SETNAME ENTRY\n"
|
||||
" Add entry to the named set",
|
||||
},
|
||||
{ /* d[el], --del, -D */
|
||||
.cmd = IPSET_CMD_DEL,
|
||||
.name = { "del", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "SETNAME ENTRY\n"
|
||||
" Delete entry from the named set",
|
||||
},
|
||||
{ /* t[est], --test, -T */
|
||||
.cmd = IPSET_CMD_TEST,
|
||||
.name = { "test", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "SETNAME ENTRY\n"
|
||||
" Test entry in the named set",
|
||||
},
|
||||
{ /* des[troy], --destroy, x, -X */
|
||||
.cmd = IPSET_CMD_DESTROY,
|
||||
.name = { "destroy", "x" },
|
||||
.has_arg = IPSET_OPTIONAL_ARG,
|
||||
.help = "[SETNAME]\n"
|
||||
" Destroy a named set or all sets",
|
||||
},
|
||||
{ /* l[ist], --list, -L */
|
||||
.cmd = IPSET_CMD_LIST,
|
||||
.name = { "list", NULL },
|
||||
.has_arg = IPSET_OPTIONAL_ARG,
|
||||
.help = "[SETNAME]\n"
|
||||
" List the entries of a named set or all sets",
|
||||
},
|
||||
{ /* s[save], --save, -S */
|
||||
.cmd = IPSET_CMD_SAVE,
|
||||
.name = { "save", NULL },
|
||||
.has_arg = IPSET_OPTIONAL_ARG,
|
||||
.help = "[SETNAME]\n"
|
||||
" Save the named set or all sets to stdout",
|
||||
},
|
||||
{ /* r[estore], --restore, -R */
|
||||
.cmd = IPSET_CMD_RESTORE,
|
||||
.name = { "restore", NULL },
|
||||
.has_arg = IPSET_NO_ARG,
|
||||
.help = "\n"
|
||||
" Restore a saved state",
|
||||
},
|
||||
{ /* f[lush], --flush, -F */
|
||||
.cmd = IPSET_CMD_FLUSH,
|
||||
.name = { "flush", NULL },
|
||||
.has_arg = IPSET_OPTIONAL_ARG,
|
||||
.help = "[SETNAME]\n"
|
||||
" Flush a named set or all sets",
|
||||
},
|
||||
{ /* ren[ame], --rename, e, -E */
|
||||
.cmd = IPSET_CMD_RENAME,
|
||||
.name = { "rename", "e" },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "FROM-SETNAME TO-SETNAME\n"
|
||||
" Rename two sets",
|
||||
},
|
||||
{ /* sw[ap], --swap, w, -W */
|
||||
.cmd = IPSET_CMD_SWAP,
|
||||
.name = { "swap", "w" },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "FROM-SETNAME TO-SETNAME\n"
|
||||
" Swap the contect of two existing sets",
|
||||
},
|
||||
{ /* h[elp, --help, -H */
|
||||
.cmd = IPSET_CMD_HELP,
|
||||
.name = { "help", NULL },
|
||||
.has_arg = IPSET_OPTIONAL_ARG,
|
||||
.help = "[TYPENAME]\n"
|
||||
" Print help, and settype specific help",
|
||||
},
|
||||
{ /* v[ersion], --version, -V */
|
||||
.cmd = IPSET_CMD_VERSION,
|
||||
.name = { "version", NULL },
|
||||
.has_arg = IPSET_NO_ARG,
|
||||
.help = "\n"
|
||||
" Print version information",
|
||||
},
|
||||
{ /* q[uit] */
|
||||
.cmd = IPSET_CMD_QUIT,
|
||||
.name = { "quit", NULL },
|
||||
.has_arg = IPSET_NO_ARG,
|
||||
.help = "\n"
|
||||
" Quit interactive mode",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
/* Match a command: try to match as a prefix or letter-command */
|
||||
bool
|
||||
ipset_match_cmd(const char *arg, const char * const name[])
|
||||
{
|
||||
size_t len;
|
||||
|
||||
assert(arg);
|
||||
assert(name && name[0]);
|
||||
|
||||
/* Ignore (two) leading dashes */
|
||||
if (arg[0] == '-')
|
||||
arg++;
|
||||
if (arg[0] == '-')
|
||||
arg++;
|
||||
|
||||
len = strlen(arg);
|
||||
|
||||
if (len > strlen(name[0]) || !len)
|
||||
return false;
|
||||
else if (len > 1 &&
|
||||
((strncmp(arg, name[0], len) == 0) ||
|
||||
(name[1] != NULL && (strncmp(arg, name[1], len) == 0))))
|
||||
return true;
|
||||
else if (len != 1)
|
||||
return false;
|
||||
else
|
||||
return tolower(arg[0]) == name[0][0] ||
|
||||
(name[1] != NULL && tolower(arg[0]) == name[1][0]);
|
||||
}
|
||||
|
||||
const struct ipset_envopts ipset_envopts[] = {
|
||||
{ .name = { "-o", "-output" },
|
||||
.has_arg = IPSET_MANDATORY_ARG, .flag = IPSET_OPT_MAX,
|
||||
.parse = ipset_parse_output,
|
||||
.help = "plain|save|xml\n"
|
||||
" Specify output mode for listing sets.\n"
|
||||
" Default value for \"list\" command is mode \"plain\"\n"
|
||||
" and for \"save\" command is mode \"save\".",
|
||||
},
|
||||
{ .name = { "-s", "-sorted" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_SORTED,
|
||||
.help = "\n"
|
||||
" Print elements sorted (if supported by the set type).",
|
||||
},
|
||||
{ .name = { "-q", "-quiet" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_QUIET,
|
||||
.help = "\n"
|
||||
" Suppress any notice or warning message.",
|
||||
},
|
||||
{ .name = { "-r", "-resolve" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_RESOLVE,
|
||||
.help = "\n"
|
||||
" Try to resolve IP addresses in the output (slow!)",
|
||||
},
|
||||
{ .name = { "-!", "-exist" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_EXIST,
|
||||
.help = "\n"
|
||||
" Ignore errors when creating already created sets,\n"
|
||||
" when adding already existing elements\n"
|
||||
" or when deleting non-existing elements.",
|
||||
},
|
||||
{ .name = { "-n", "-name" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_SETNAME,
|
||||
.help = "\n"
|
||||
" When listing, list just setnames from kernel.\n",
|
||||
},
|
||||
{ .name = { "-t", "-terse" },
|
||||
.parse = ipset_envopt_parse,
|
||||
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_HEADER,
|
||||
.help = "\n"
|
||||
" When listing, list setnames and set headers\n"
|
||||
" from kernel only.",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
/* Strict option matching */
|
||||
bool
|
||||
ipset_match_option(const char *arg, const char * const name[])
|
||||
{
|
||||
assert(arg);
|
||||
assert(name && name[0]);
|
||||
|
||||
/* Skip two leading dashes */
|
||||
if (arg[0] == '-' && arg[1] == '-')
|
||||
arg++, arg++;
|
||||
|
||||
return STREQ(arg, name[0]) ||
|
||||
(name[1] != NULL && STREQ(arg, name[1]));
|
||||
}
|
||||
|
||||
/* Strict envopt matching */
|
||||
bool
|
||||
ipset_match_envopt(const char *arg, const char * const name[])
|
||||
{
|
||||
assert(arg);
|
||||
assert(name && name[0]);
|
||||
|
||||
/* Skip one leading dash */
|
||||
if (arg[0] == '-' && arg[1] == '-')
|
||||
arg++;
|
||||
|
||||
return STREQ(arg, name[0]) ||
|
||||
(name[1] != NULL && STREQ(arg, name[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_shift_argv - shift off an argument
|
||||
* @arc: argument count
|
||||
* @argv: array of argument strings
|
||||
* @from: from where shift off an argument
|
||||
*
|
||||
* Shift off the argument at "from" from the array of
|
||||
* arguments argv of size argc.
|
||||
*/
|
||||
void
|
||||
ipset_shift_argv(int *argc, char *argv[], int from)
|
||||
{
|
||||
int i;
|
||||
|
||||
assert(*argc >= from + 1);
|
||||
|
||||
for (i = from + 1; i <= *argc; i++)
|
||||
argv[i-1] = argv[i];
|
||||
(*argc)--;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_port_usage - prints the usage for the port parameter
|
||||
*
|
||||
* Print the usage for the port parameter to stdout.
|
||||
*/
|
||||
void
|
||||
ipset_port_usage(void)
|
||||
{
|
||||
int i;
|
||||
const char *name;
|
||||
|
||||
printf(" [PROTO:]PORT is a valid pattern of the following:\n"
|
||||
" PORTNAME TCP port name from /etc/services\n"
|
||||
" PORTNUMBER TCP port number identifier\n"
|
||||
" tcp|sctp|udp|udplite:PORTNAME|PORTNUMBER\n"
|
||||
" icmp:CODENAME supported ICMP codename\n"
|
||||
" icmp:TYPE/CODE ICMP type/code value\n"
|
||||
" icmpv6:CODENAME supported ICMPv6 codename\n"
|
||||
" icmpv6:TYPE/CODE ICMPv6 type/code value\n"
|
||||
" PROTO:0 all other protocols\n\n");
|
||||
|
||||
printf(" Supported ICMP codenames:\n");
|
||||
i = 0;
|
||||
while ((name = id_to_icmp(i++)) != NULL)
|
||||
printf(" %s\n", name);
|
||||
printf(" Supported ICMPv6 codenames:\n");
|
||||
i = 0;
|
||||
while ((name = id_to_icmpv6(i++)) != NULL)
|
||||
printf(" %s\n", name);
|
||||
}
|
||||
@@ -1,422 +0,0 @@
|
||||
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||
* Patrick Schaaf <bof@bof.de>
|
||||
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||
* 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 which implements the set match and SET target
|
||||
* for netfilter/iptables. */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "xt_set.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||
MODULE_DESCRIPTION("Xtables: IP set match and target module");
|
||||
MODULE_ALIAS("xt_SET");
|
||||
MODULE_ALIAS("ipt_set");
|
||||
MODULE_ALIAS("ip6t_set");
|
||||
MODULE_ALIAS("ipt_SET");
|
||||
MODULE_ALIAS("ip6t_SET");
|
||||
|
||||
static inline int
|
||||
match_set(ip_set_id_t index, const struct sk_buff *skb,
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt, int inv)
|
||||
{
|
||||
if (ip_set_test(index, skb, par, opt))
|
||||
inv = !inv;
|
||||
return inv;
|
||||
}
|
||||
|
||||
#define ADT_OPT(n, f, d, fs, cfs, t) \
|
||||
const struct ip_set_adt_opt n = { \
|
||||
.family = f, \
|
||||
.dim = d, \
|
||||
.flags = fs, \
|
||||
.cmdflags = cfs, \
|
||||
.timeout = t, \
|
||||
}
|
||||
|
||||
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
||||
|
||||
static bool
|
||||
set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
|
||||
info->match_set.u.compat.flags, 0, UINT_MAX);
|
||||
|
||||
return match_set(info->match_set.index, skb, par, &opt,
|
||||
info->match_set.u.compat.flags & IPSET_INV_MATCH);
|
||||
}
|
||||
|
||||
static void
|
||||
compat_flags(struct xt_set_info_v0 *info)
|
||||
{
|
||||
u_int8_t i;
|
||||
|
||||
/* Fill out compatibility data according to enum ip_set_kopt */
|
||||
info->u.compat.dim = IPSET_DIM_ZERO;
|
||||
if (info->u.flags[0] & IPSET_MATCH_INV)
|
||||
info->u.compat.flags |= IPSET_INV_MATCH;
|
||||
for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
|
||||
info->u.compat.dim++;
|
||||
if (info->u.flags[i] & IPSET_SRC)
|
||||
info->u.compat.flags |= (1<<info->u.compat.dim);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->match_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_match_v0_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
|
||||
info->add_set.u.compat.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
|
||||
info->del_set.u.compat.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|
||||
info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->add_set);
|
||||
compat_flags(&info->del_set);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_v0_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Revision 1 match and target */
|
||||
|
||||
static bool
|
||||
set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
ADT_OPT(opt, par->family, info->match_set.dim,
|
||||
info->match_set.flags, 0, UINT_MAX);
|
||||
|
||||
return match_set(info->match_set.index, skb, par, &opt,
|
||||
info->match_set.flags & IPSET_INV_MATCH);
|
||||
}
|
||||
|
||||
static int
|
||||
set_match_v1_checkentry(const struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
if (info->match_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("Protocol error: set match dimension "
|
||||
"is over the limit!\n");
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_match_v1_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, 0, UINT_MAX);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
static int
|
||||
set_target_v1_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->add_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->del_set.index != IPSET_INVALID_ID) {
|
||||
index = ip_set_nfnl_get_byindex(info->del_set.index);
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find del_set index %u as target\n",
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.dim > IPSET_DIM_MAX ||
|
||||
info->del_set.dim > IPSET_DIM_MAX) {
|
||||
pr_warning("Protocol error: SET target dimension "
|
||||
"is over the limit!\n");
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_v1_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* Revision 2 target */
|
||||
|
||||
static unsigned int
|
||||
set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target_v2 *info = par->targinfo;
|
||||
ADT_OPT(add_opt, par->family, info->add_set.dim,
|
||||
info->add_set.flags, info->flags, info->timeout);
|
||||
ADT_OPT(del_opt, par->family, info->del_set.dim,
|
||||
info->del_set.flags, 0, UINT_MAX);
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_add(info->add_set.index, skb, par, &add_opt);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#define set_target_v2_checkentry set_target_v1_checkentry
|
||||
#define set_target_v2_destroy set_target_v1_destroy
|
||||
|
||||
static struct xt_match set_matches[] __read_mostly = {
|
||||
{
|
||||
.name = "set",
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision = 0,
|
||||
.match = set_match_v0,
|
||||
.matchsize = sizeof(struct xt_set_info_match_v0),
|
||||
.checkentry = set_match_v0_checkentry,
|
||||
.destroy = set_match_v0_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "set",
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision = 1,
|
||||
.match = set_match_v1,
|
||||
.matchsize = sizeof(struct xt_set_info_match_v1),
|
||||
.checkentry = set_match_v1_checkentry,
|
||||
.destroy = set_match_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "set",
|
||||
.family = NFPROTO_IPV6,
|
||||
.revision = 1,
|
||||
.match = set_match_v1,
|
||||
.matchsize = sizeof(struct xt_set_info_match_v1),
|
||||
.checkentry = set_match_v1_checkentry,
|
||||
.destroy = set_match_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
};
|
||||
|
||||
static struct xt_target set_targets[] __read_mostly = {
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = set_target_v0,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v0),
|
||||
.checkentry = set_target_v0_checkentry,
|
||||
.destroy = set_target_v0_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = set_target_v1,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v1),
|
||||
.checkentry = set_target_v1_checkentry,
|
||||
.destroy = set_target_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPV6,
|
||||
.target = set_target_v1,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v1),
|
||||
.checkentry = set_target_v1_checkentry,
|
||||
.destroy = set_target_v1_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 2,
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = set_target_v2,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v2),
|
||||
.checkentry = set_target_v2_checkentry,
|
||||
.destroy = set_target_v2_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
{
|
||||
.name = "SET",
|
||||
.revision = 2,
|
||||
.family = NFPROTO_IPV6,
|
||||
.target = set_target_v2,
|
||||
.targetsize = sizeof(struct xt_set_info_target_v2),
|
||||
.checkentry = set_target_v2_checkentry,
|
||||
.destroy = set_target_v2_destroy,
|
||||
.me = THIS_MODULE
|
||||
},
|
||||
};
|
||||
|
||||
static int __init xt_set_init(void)
|
||||
{
|
||||
int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
|
||||
|
||||
if (!ret) {
|
||||
ret = xt_register_targets(set_targets,
|
||||
ARRAY_SIZE(set_targets));
|
||||
if (ret)
|
||||
xt_unregister_matches(set_matches,
|
||||
ARRAY_SIZE(set_matches));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit xt_set_fini(void)
|
||||
{
|
||||
xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
|
||||
xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
|
||||
}
|
||||
|
||||
module_init(xt_set_init);
|
||||
module_exit(xt_set_fini);
|
||||
@@ -1,65 +0,0 @@
|
||||
#ifndef _XT_SET_H
|
||||
#define _XT_SET_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "ip_set.h"
|
||||
|
||||
/* Revision 0 interface: backward compatible with netfilter/iptables */
|
||||
|
||||
/*
|
||||
* Option flags for kernel operations (xt_set_info_v0)
|
||||
*/
|
||||
#define IPSET_SRC 0x01 /* Source match/add */
|
||||
#define IPSET_DST 0x02 /* Destination match/add */
|
||||
#define IPSET_MATCH_INV 0x04 /* Inverse matching */
|
||||
|
||||
struct xt_set_info_v0 {
|
||||
ip_set_id_t index;
|
||||
union {
|
||||
__u32 flags[IPSET_DIM_MAX + 1];
|
||||
struct {
|
||||
__u32 __flags[IPSET_DIM_MAX];
|
||||
__u8 dim;
|
||||
__u8 flags;
|
||||
} compat;
|
||||
} u;
|
||||
};
|
||||
|
||||
/* match and target infos */
|
||||
struct xt_set_info_match_v0 {
|
||||
struct xt_set_info_v0 match_set;
|
||||
};
|
||||
|
||||
struct xt_set_info_target_v0 {
|
||||
struct xt_set_info_v0 add_set;
|
||||
struct xt_set_info_v0 del_set;
|
||||
};
|
||||
|
||||
/* Revision 1 match and target */
|
||||
|
||||
struct xt_set_info {
|
||||
ip_set_id_t index;
|
||||
__u8 dim;
|
||||
__u8 flags;
|
||||
};
|
||||
|
||||
/* match and target infos */
|
||||
struct xt_set_info_match_v1 {
|
||||
struct xt_set_info match_set;
|
||||
};
|
||||
|
||||
struct xt_set_info_target_v1 {
|
||||
struct xt_set_info add_set;
|
||||
struct xt_set_info del_set;
|
||||
};
|
||||
|
||||
/* Revision 2 target */
|
||||
|
||||
struct xt_set_info_target_v2 {
|
||||
struct xt_set_info add_set;
|
||||
struct xt_set_info del_set;
|
||||
__u32 flags;
|
||||
__u32 timeout;
|
||||
};
|
||||
|
||||
#endif /*_XT_SET_H*/
|
||||
Reference in New Issue
Block a user