mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-20 19:44:56 +02:00
Compare commits
42 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
65b75fc19c | ||
![]() |
bac406bff5 | ||
![]() |
aa53733851 | ||
![]() |
9ccd32d840 | ||
![]() |
939d3c8b27 | ||
![]() |
c2d93e16fd | ||
![]() |
04aed87cb6 | ||
![]() |
5ef3a7c436 | ||
![]() |
27a77b62f5 | ||
![]() |
c10e974bd6 | ||
![]() |
01d864f4fc | ||
![]() |
071c95b750 | ||
![]() |
a141cc311c | ||
![]() |
7e92ce7ce6 | ||
![]() |
21da1dfea5 | ||
![]() |
6c17eb46b5 | ||
![]() |
74ea647303 | ||
![]() |
e0154bfa4c | ||
![]() |
cd18e2479c | ||
![]() |
d2f3541cda | ||
![]() |
1fed8bbf09 | ||
![]() |
6e8fb7f231 | ||
![]() |
eceaee3431 | ||
![]() |
77b29a62ee | ||
![]() |
33db992c39 | ||
![]() |
85d8f98dd7 | ||
![]() |
e84391ce66 | ||
![]() |
ef7fb0db7f | ||
![]() |
4203259e5a | ||
![]() |
e3956498ac | ||
![]() |
6f730f3ab2 | ||
![]() |
2b590a35fd | ||
![]() |
3dd33dfe93 | ||
![]() |
d417077816 | ||
![]() |
d057f6d6f0 | ||
![]() |
b2fc85c589 | ||
![]() |
fa1348455d | ||
![]() |
1a5c079e6b | ||
![]() |
75b3762ef4 | ||
![]() |
cfb72bf468 | ||
![]() |
1b0790d151 | ||
![]() |
a5355e74ea |
6
INSTALL
6
INSTALL
@@ -22,12 +22,14 @@ Supported configurations for this release
|
||||
- CONFIG_CONNECTOR y/m if you wish to receive userspace
|
||||
notifications from pknock through netlink/connector
|
||||
|
||||
For ipset-6 you need:
|
||||
Compilation of ipset-genl-6.x is enabled by default. This additionally
|
||||
requires
|
||||
|
||||
* libmnl
|
||||
|
||||
* Linux kernel >= 2.6.35
|
||||
|
||||
so if you do not have these, turn it off in mconfig before compilation.
|
||||
|
||||
|
||||
Selecting extensions
|
||||
====================
|
||||
|
2
README
2
README
@@ -19,7 +19,7 @@ simplified, and sped up.
|
||||
Included in this package
|
||||
========================
|
||||
- ipset 4.5
|
||||
- ipset 5.4.1
|
||||
- ipset 6.7-genl
|
||||
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
|
||||
|
||||
|
||||
|
20
configure.ac
20
configure.ac
@@ -1,5 +1,4 @@
|
||||
|
||||
AC_INIT([xtables-addons], [1.35])
|
||||
AC_INIT([xtables-addons], [1.38])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_PROG_INSTALL
|
||||
@@ -42,7 +41,7 @@ regular_CFLAGS="-Wall -Waggregate-return -Wmissing-declarations \
|
||||
|
||||
if test -n "$kbuilddir"; then
|
||||
AC_MSG_CHECKING([kernel version that we will build against])
|
||||
krel="$(make -sC "$kbuilddir" M=. kernelrelease)";
|
||||
krel="$(make -sC "$kbuilddir" M=$PWD kernelrelease)";
|
||||
kmajor="${krel%%[[^0-9]]*}";
|
||||
kmajor="$(($kmajor+0))";
|
||||
krel="${krel:${#kmajor}}";
|
||||
@@ -61,19 +60,14 @@ if test -n "$kbuilddir"; then
|
||||
echo "WARNING: Version detection did not succeed. Continue at own luck.";
|
||||
else
|
||||
echo "$kmajor.$kminor.$kmicro.$kstable in $kbuilddir";
|
||||
if test "$kmajor" -gt 2 -o "$kminor" -gt 6 -o "$kmicro" -gt 38; then
|
||||
if test "$kmajor" -gt 3 -o "$kmajor" -eq 3 -a "$kminor" -gt 1; then
|
||||
echo "WARNING: You are trying a newer kernel. Results may vary. :-)";
|
||||
elif test "$kmajor" -eq 3; then
|
||||
:;
|
||||
elif test "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -ge 29; then
|
||||
:; # everything ok
|
||||
elif test \( "$kmajor" -lt 2 -o \
|
||||
\( "$kmajor" -eq 2 -a "$kminor" -lt 6 \) -o \
|
||||
\( "$kmajor" -eq 2 -a "$kminor" -eq 0 -a "$kmicro" -lt 17 \) -o \
|
||||
\( "$kmajor" -eq 2 -a "$kminor" -eq 6 -a "$kmicro" -eq 18 -a \
|
||||
"$kstable" -lt 5 \) \); then
|
||||
echo "ERROR: That kernel version is not supported at all. Please see INSTALL for minimum configuration.";
|
||||
exit 1;
|
||||
:;
|
||||
else
|
||||
echo "WARNING: That kernel version has been recently deprecated for use with Xtables-addons). Compilation may fail.";
|
||||
echo "WARNING: That kernel version is not supported.";
|
||||
fi;
|
||||
fi;
|
||||
fi;
|
||||
|
@@ -3,6 +3,38 @@ HEAD
|
||||
====
|
||||
|
||||
|
||||
v1.38 (2011-08-20)
|
||||
==================
|
||||
- xt_CHECKSUM: abort build when the feature is already provided by mainline
|
||||
- xt_SYSRQ: fix UDPLITE header lookup in IPv6
|
||||
- xt_TARPIT: fix kernel warning about RTAX_HOPLIMIT being used
|
||||
- xt_TEE: abort build when the feature is already provided by mainline
|
||||
- xt_ipp2p: support UDPLITE
|
||||
- xt_pknock: support UDPLITE
|
||||
- xt_psd: restore functionality with UDP
|
||||
- xt_psd: support UDPLITE
|
||||
- update to ipset 6.8
|
||||
- support for Linux 3.1
|
||||
|
||||
|
||||
v1.37 (2011-06-25)
|
||||
==================
|
||||
Fixes:
|
||||
- xt_SYSRQ: make IPv6 trigger work again
|
||||
- xt_SYSRQ: improve security: include host address in digest
|
||||
- xt_TARPIT: fix a kernel oops in --reset mode
|
||||
|
||||
|
||||
v1.36 (2011-06-03)
|
||||
==================
|
||||
Changes:
|
||||
- xt_geoip: avoid recursive function calls
|
||||
- xt_TARPIT: unlock for use in all tables
|
||||
- xt_TARPIT: honeypot and reset modes
|
||||
- update to ipset 6.7
|
||||
- support for Linux 3.0
|
||||
|
||||
|
||||
v1.35 (2011-04-11)
|
||||
==================
|
||||
Enhancements:
|
||||
|
@@ -9,3 +9,5 @@ sbin_PROGRAMS = iptaccount
|
||||
iptaccount_LDADD = libxt_ACCOUNT_cl.la
|
||||
|
||||
lib_LTLIBRARIES = libxt_ACCOUNT_cl.la
|
||||
|
||||
man_MANS = iptaccount.8
|
||||
|
26
extensions/ACCOUNT/iptaccount.8
Normal file
26
extensions/ACCOUNT/iptaccount.8
Normal file
@@ -0,0 +1,26 @@
|
||||
.TH iptaccount 8 "v1.16" "" "v1.16"
|
||||
.SH Name
|
||||
iptaccount \(em administrative utility to access xt_ACCOUNT statistics
|
||||
.SH Syntax
|
||||
\fBiptaccount\fP [\fB\-acfhu\fP] [\fB\-l\fP \fIname\fP]
|
||||
.SH Options
|
||||
.PP
|
||||
\fB\-a\fP
|
||||
List all (accounting) table names.
|
||||
.PP
|
||||
\fB\-c\fP
|
||||
Loop every second (abort with CTRL+C).
|
||||
.PP
|
||||
\fB\-f\fP
|
||||
Flush data after display.
|
||||
.PP
|
||||
\fB\-h\fP
|
||||
Free all kernel handles. (Experts only!)
|
||||
.PP
|
||||
\fB\-l\fP \fIname\fP
|
||||
Show data in accounting table called by \fIname\fP.
|
||||
.TP
|
||||
\fB\-u\fP
|
||||
Show kernel handle usage.
|
||||
.SH "See also"
|
||||
\fBxtables-addons\fP(8)
|
@@ -40,19 +40,7 @@ to account the overall traffic to/from your internet provider.
|
||||
.PP
|
||||
The data can be queried using the userspace libxt_ACCOUNT_cl library,
|
||||
and by the reference implementation to show usage of this library,
|
||||
the \fBiptaccount\fP(8) tool, which features following options:
|
||||
.PP
|
||||
[\fB\-u\fP] show kernel handle usage
|
||||
.PP
|
||||
[\fB\-h\fP] free all kernel handles (experts only!)
|
||||
.PP
|
||||
[\fB\-a\fP] list all table names
|
||||
.PP
|
||||
[\fB\-l\fP \fIname\fP] show data in table \fIname\fP
|
||||
.PP
|
||||
[\fB\-f\fP] flush data after showing
|
||||
.PP
|
||||
[\fB\-c\fP] loop every second (abort with CTRL+C)
|
||||
the \fBiptaccount\fP(8) tool.
|
||||
.PP
|
||||
Here is an example of use:
|
||||
.PP
|
||||
|
@@ -4,7 +4,7 @@ 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_netport.o ip_set_list_set.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
|
||||
|
||||
|
@@ -17,8 +17,9 @@ ipset_SOURCES = src/ipset.c src/errcode.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_netport.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 = ipset.8
|
||||
man_MANS = src/ipset.8
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -44,12 +44,15 @@ enum ipset_opt {
|
||||
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| */
|
||||
@@ -65,7 +68,7 @@ enum ipset_opt {
|
||||
#define IPSET_FLAGS_ALL (~0LL)
|
||||
|
||||
#define IPSET_CREATE_FLAGS \
|
||||
( IPSET_FLAG(IPSET_OPT_FAMILY) \
|
||||
(IPSET_FLAG(IPSET_OPT_FAMILY) \
|
||||
| IPSET_FLAG(IPSET_OPT_TYPENAME)\
|
||||
| IPSET_FLAG(IPSET_OPT_TYPE) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP) \
|
||||
@@ -83,7 +86,7 @@ enum ipset_opt {
|
||||
| IPSET_FLAG(IPSET_OPT_SIZE))
|
||||
|
||||
#define IPSET_ADT_FLAGS \
|
||||
( IPSET_FLAG(IPSET_OPT_IP) \
|
||||
(IPSET_FLAG(IPSET_OPT_IP) \
|
||||
| IPSET_FLAG(IPSET_OPT_IP_TO) \
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR) \
|
||||
| IPSET_FLAG(IPSET_OPT_PORT) \
|
||||
@@ -95,8 +98,10 @@ enum ipset_opt {
|
||||
| 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_BEFORE) \
|
||||
| IPSET_FLAG(IPSET_OPT_PHYSDEV))
|
||||
|
||||
struct ipset_data;
|
||||
|
||||
@@ -109,8 +114,8 @@ 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);
|
||||
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)
|
||||
@@ -119,13 +124,13 @@ ipset_data_test(const struct ipset_data *data, enum ipset_opt opt)
|
||||
}
|
||||
|
||||
/* Shortcuts */
|
||||
extern const char * ipset_data_setname(const struct ipset_data *data);
|
||||
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 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);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <linux/netlink.h>
|
||||
#define D(fmt, args...) \
|
||||
fprintf(stderr, "%s: %s: " fmt "\n", __FILE__, __FUNCTION__ , ## args)
|
||||
fprintf(stderr, "%s: %s: " fmt "\n", __FILE__, __func__ , ## args)
|
||||
#define IF_D(test, fmt, args...) \
|
||||
if (test) \
|
||||
D(fmt , ## args)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -13,9 +13,9 @@ 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 */
|
||||
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,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
#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 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,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
#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 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 */
|
||||
|
@@ -12,7 +12,7 @@
|
||||
*/
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 6
|
||||
#define IPSET_PROTOCOL 0x60
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
@@ -104,6 +104,8 @@ enum {
|
||||
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)
|
||||
@@ -142,12 +144,18 @@ enum ipset_errno {
|
||||
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 */
|
||||
|
@@ -11,6 +11,10 @@ enum {
|
||||
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,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -23,7 +23,7 @@ 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);
|
||||
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);
|
||||
@@ -35,23 +35,23 @@ extern int ipset_parse_tcp_port(struct ipset_session *session,
|
||||
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);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_icmp(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_icmpv6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
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);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_ip(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
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);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_range(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
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,
|
||||
@@ -60,33 +60,37 @@ 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);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_before(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_after(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_setname(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_uint32(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_uint8(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_netmask(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_flag(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
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);
|
||||
int opt, const char *str);
|
||||
extern int ipset_parse_ignored(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_parse_elem(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str);
|
||||
enum ipset_opt opt, const char *str);
|
||||
extern int ipset_call_parser(struct ipset_session *session,
|
||||
const struct ipset_arg *arg,
|
||||
const char *str);
|
||||
const struct ipset_arg *arg,
|
||||
const char *str);
|
||||
|
||||
/* Compatibility parser functions */
|
||||
extern int ipset_parse_iptimeout(struct ipset_session *session,
|
||||
|
@@ -12,7 +12,7 @@
|
||||
{.ip6 = { \
|
||||
__constant_htonl(a), __constant_htonl(b), \
|
||||
__constant_htonl(c), __constant_htonl(d), \
|
||||
}}
|
||||
} }
|
||||
|
||||
/*
|
||||
* This table works for both IPv4 and IPv6;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -37,6 +37,9 @@ extern int ipset_print_name(char *buf, unsigned int len,
|
||||
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);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -21,10 +21,14 @@ 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);
|
||||
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,
|
||||
@@ -47,8 +51,8 @@ extern int ipset_session_report(struct ipset_session *session,
|
||||
})
|
||||
|
||||
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);
|
||||
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)
|
||||
@@ -65,6 +69,10 @@ enum ipset_envopt {
|
||||
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,
|
||||
@@ -89,7 +97,9 @@ extern int ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd,
|
||||
typedef int (*ipset_outfn)(const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 1, 2)));
|
||||
|
||||
extern struct ipset_session * ipset_session_init(ipset_outfn outfn);
|
||||
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,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include <libmnl/libmnl.h> /* mnl_cb_t */
|
||||
|
||||
#include <libipset/linux_ip_set.h> /* enum ipset_cmd */
|
||||
#include <libipset/linux_ip_set.h> /* enum ipset_cmd */
|
||||
|
||||
struct ipset_handle;
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -97,13 +97,14 @@ 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 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 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);
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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
|
||||
@@ -11,10 +11,10 @@
|
||||
#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)
|
||||
#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
|
||||
|
@@ -14,7 +14,7 @@
|
||||
#include <linux/netlink.h>
|
||||
|
||||
/* The protocol version */
|
||||
#define IPSET_PROTOCOL 6
|
||||
#define IPSET_PROTOCOL 0x60
|
||||
|
||||
/* The max length of strings including NUL: set and type identifiers */
|
||||
#define IPSET_MAXNAMELEN 32
|
||||
@@ -106,6 +106,8 @@ enum {
|
||||
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)
|
||||
@@ -144,12 +146,18 @@ enum ipset_errno {
|
||||
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 */
|
||||
@@ -167,6 +175,7 @@ enum ipset_adt {
|
||||
#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>
|
||||
|
||||
@@ -208,6 +217,8 @@ enum ip_set_feature {
|
||||
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,
|
||||
@@ -219,6 +230,15 @@ 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
|
||||
@@ -226,14 +246,15 @@ struct ip_set_type_variant {
|
||||
* zero for no match/success to add/delete
|
||||
* positive for matching element */
|
||||
int (*kadt)(struct ip_set *set, const struct sk_buff * skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
|
||||
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);
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
|
||||
|
||||
/* Low level add/del/test functions */
|
||||
ipset_adtfn adt[IPSET_ADT_MAX];
|
||||
@@ -271,8 +292,8 @@ struct ip_set_type {
|
||||
u8 dimension;
|
||||
/* Supported family: may be AF_UNSPEC for both AF_INET/AF_INET6 */
|
||||
u8 family;
|
||||
/* Type revision */
|
||||
u8 revision;
|
||||
/* Type revisions */
|
||||
u8 revision_min, revision_max;
|
||||
|
||||
/* Create set */
|
||||
int (*create)(struct ip_set *set, struct nlattr *tb[], u32 flags);
|
||||
@@ -303,6 +324,8 @@ struct ip_set {
|
||||
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;
|
||||
};
|
||||
@@ -310,21 +333,25 @@ struct ip_set {
|
||||
/* 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 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,
|
||||
u8 family, u8 dim, u8 flags);
|
||||
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,
|
||||
u8 family, u8 dim, u8 flags);
|
||||
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,
|
||||
u8 family, u8 dim, u8 flags);
|
||||
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_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);
|
||||
@@ -334,7 +361,7 @@ 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);
|
||||
|
@@ -5,6 +5,11 @@
|
||||
#include "jhash.h"
|
||||
#include "ip_set_timeout.h"
|
||||
|
||||
#define CONCAT(a, b, c) a##b##c
|
||||
#define TOKEN(a, b, c) CONCAT(a, b, c)
|
||||
|
||||
#define type_pf_next TOKEN(TYPE, PF, _elem)
|
||||
|
||||
/* Hashing which uses arrays to resolve clashing. The hash table is resized
|
||||
* (doubled) when searching becomes too long.
|
||||
* Internally jhash is used with the assumption that the size of the
|
||||
@@ -23,7 +28,32 @@
|
||||
/* Number of elements to store in an initial array block */
|
||||
#define AHASH_INIT_SIZE 4
|
||||
/* Max number of elements to store in an array block */
|
||||
#define AHASH_MAX_SIZE (3*4)
|
||||
#define AHASH_MAX_SIZE (3*AHASH_INIT_SIZE)
|
||||
|
||||
/* Max number of elements can be tuned */
|
||||
#ifdef IP_SET_HASH_WITH_MULTI
|
||||
#define AHASH_MAX(h) ((h)->ahash_max)
|
||||
|
||||
static inline u8
|
||||
tune_ahash_max(u8 curr, u32 multi)
|
||||
{
|
||||
u32 n;
|
||||
|
||||
if (multi < curr)
|
||||
return curr;
|
||||
|
||||
n = curr + AHASH_INIT_SIZE;
|
||||
/* Currently, at listing one hash bucket must fit into a message.
|
||||
* Therefore we have a hard limit here.
|
||||
*/
|
||||
return n > curr && n <= 64 ? n : curr;
|
||||
}
|
||||
#define TUNE_AHASH_MAX(h, multi) \
|
||||
((h)->ahash_max = tune_ahash_max((h)->ahash_max, multi))
|
||||
#else
|
||||
#define AHASH_MAX(h) AHASH_MAX_SIZE
|
||||
#define TUNE_AHASH_MAX(h, multi)
|
||||
#endif
|
||||
|
||||
/* A hash bucket */
|
||||
struct hbucket {
|
||||
@@ -38,7 +68,7 @@ struct htable {
|
||||
struct hbucket bucket[0]; /* hashtable buckets */
|
||||
};
|
||||
|
||||
#define hbucket(h, i) &((h)->bucket[i])
|
||||
#define hbucket(h, i) (&((h)->bucket[i]))
|
||||
|
||||
/* Book-keeping of the prefixes added to the set */
|
||||
struct ip_set_hash_nets {
|
||||
@@ -54,9 +84,16 @@ struct ip_set_hash {
|
||||
u32 initval; /* random jhash init value */
|
||||
u32 timeout; /* timeout value, if enabled */
|
||||
struct timer_list gc; /* garbage collection when timeout enabled */
|
||||
struct type_pf_next next; /* temporary storage for uadd */
|
||||
#ifdef IP_SET_HASH_WITH_MULTI
|
||||
u8 ahash_max; /* max elements in an array block */
|
||||
#endif
|
||||
#ifdef IP_SET_HASH_WITH_NETMASK
|
||||
u8 netmask; /* netmask value for subnets to store */
|
||||
#endif
|
||||
#ifdef IP_SET_HASH_WITH_RBTREE
|
||||
struct rb_root rbtree;
|
||||
#endif
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
struct ip_set_hash_nets nets[0]; /* book-keeping of prefixes */
|
||||
#endif
|
||||
@@ -194,17 +231,24 @@ ip_set_hash_destroy(struct ip_set *set)
|
||||
del_timer_sync(&h->gc);
|
||||
|
||||
ahash_destroy(h->table);
|
||||
#ifdef IP_SET_HASH_WITH_RBTREE
|
||||
rbtree_destroy(&h->rbtree);
|
||||
#endif
|
||||
kfree(h);
|
||||
|
||||
set->data = NULL;
|
||||
}
|
||||
|
||||
#define HKEY(data, initval, htable_bits) \
|
||||
(jhash2((u32 *)(data), sizeof(struct type_pf_elem)/sizeof(u32), initval) \
|
||||
& jhash_mask(htable_bits))
|
||||
|
||||
#endif /* _IP_SET_AHASH_H */
|
||||
|
||||
#ifndef HKEY_DATALEN
|
||||
#define HKEY_DATALEN sizeof(struct type_pf_elem)
|
||||
#endif
|
||||
|
||||
#define HKEY(data, initval, htable_bits) \
|
||||
(jhash2((u32 *)(data), HKEY_DATALEN/sizeof(u32), initval) \
|
||||
& jhash_mask(htable_bits))
|
||||
|
||||
#define CONCAT(a, b, c) a##b##c
|
||||
#define TOKEN(a, b, c) CONCAT(a, b, c)
|
||||
|
||||
@@ -217,6 +261,7 @@ ip_set_hash_destroy(struct ip_set *set)
|
||||
#define type_pf_data_netmask TOKEN(TYPE, PF, _data_netmask)
|
||||
#define type_pf_data_list TOKEN(TYPE, PF, _data_list)
|
||||
#define type_pf_data_tlist TOKEN(TYPE, PF, _data_tlist)
|
||||
#define type_pf_data_next TOKEN(TYPE, PF, _data_next)
|
||||
|
||||
#define type_pf_elem TOKEN(TYPE, PF, _elem)
|
||||
#define type_pf_telem TOKEN(TYPE, PF, _telem)
|
||||
@@ -262,12 +307,13 @@ ip_set_hash_destroy(struct ip_set *set)
|
||||
/* Add an element to the hash table when resizing the set:
|
||||
* we spare the maintenance of the internal counters. */
|
||||
static int
|
||||
type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value)
|
||||
type_pf_elem_add(struct hbucket *n, const struct type_pf_elem *value,
|
||||
u8 ahash_max)
|
||||
{
|
||||
if (n->pos >= n->size) {
|
||||
void *tmp;
|
||||
|
||||
if (n->size >= AHASH_MAX_SIZE)
|
||||
if (n->size >= ahash_max)
|
||||
/* Trigger rehashing */
|
||||
return -EAGAIN;
|
||||
|
||||
@@ -322,7 +368,7 @@ retry:
|
||||
for (j = 0; j < n->pos; j++) {
|
||||
data = ahash_data(n, j);
|
||||
m = hbucket(t, HKEY(data, h->initval, htable_bits));
|
||||
ret = type_pf_elem_add(m, data);
|
||||
ret = type_pf_elem_add(m, data, AHASH_MAX(h));
|
||||
if (ret < 0) {
|
||||
read_unlock_bh(&set->lock);
|
||||
ahash_destroy(t);
|
||||
@@ -346,6 +392,9 @@ retry:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
type_pf_data_next(struct ip_set_hash *h, const struct type_pf_elem *d);
|
||||
|
||||
/* Add an element to a hash and update the internal counters when succeeded,
|
||||
* otherwise report the proper error code. */
|
||||
static int
|
||||
@@ -356,7 +405,7 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
const struct type_pf_elem *d = value;
|
||||
struct hbucket *n;
|
||||
int i, ret = 0;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
|
||||
if (h->elements >= h->maxelem)
|
||||
return -IPSET_ERR_HASH_FULL;
|
||||
@@ -366,14 +415,17 @@ type_pf_add(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
key = HKEY(value, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++)
|
||||
if (type_pf_data_equal(ahash_data(n, i), d)) {
|
||||
if (type_pf_data_equal(ahash_data(n, i), d, &multi)) {
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = type_pf_elem_add(n, value);
|
||||
if (ret != 0)
|
||||
TUNE_AHASH_MAX(h, multi);
|
||||
ret = type_pf_elem_add(n, value, AHASH_MAX(h));
|
||||
if (ret != 0) {
|
||||
if (ret == -EAGAIN)
|
||||
type_pf_data_next(h, d);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
add_cidr(h, d->cidr, HOST_MASK);
|
||||
@@ -396,13 +448,13 @@ type_pf_del(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
struct hbucket *n;
|
||||
int i;
|
||||
struct type_pf_elem *data;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
|
||||
key = HKEY(value, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i);
|
||||
if (!type_pf_data_equal(data, d))
|
||||
if (!type_pf_data_equal(data, d, &multi))
|
||||
continue;
|
||||
if (i != n->pos - 1)
|
||||
/* Not last one */
|
||||
@@ -443,17 +495,17 @@ type_pf_test_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||
struct hbucket *n;
|
||||
const struct type_pf_elem *data;
|
||||
int i, j = 0;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
u8 host_mask = SET_HOST_MASK(set->family);
|
||||
|
||||
pr_debug("test by nets\n");
|
||||
for (; j < host_mask && h->nets[j].cidr; j++) {
|
||||
for (; j < host_mask && h->nets[j].cidr && !multi; j++) {
|
||||
type_pf_data_netmask(d, h->nets[j].cidr);
|
||||
key = HKEY(d, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i);
|
||||
if (type_pf_data_equal(data, d))
|
||||
if (type_pf_data_equal(data, d, &multi))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -471,7 +523,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
struct hbucket *n;
|
||||
const struct type_pf_elem *data;
|
||||
int i;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
/* If we test an IP address and not a network address,
|
||||
@@ -484,7 +536,7 @@ type_pf_test(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_data(n, i);
|
||||
if (type_pf_data_equal(data, d))
|
||||
if (type_pf_data_equal(data, d, &multi))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@@ -586,10 +638,11 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
type_pf_kadt(struct ip_set *set, const struct sk_buff * skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags);
|
||||
const struct xt_action_param *par,
|
||||
enum ipset_adt adt, const struct ip_set_adt_opt *opt);
|
||||
static int
|
||||
type_pf_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags);
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried);
|
||||
|
||||
static const struct ip_set_type_variant type_pf_variant = {
|
||||
.kadt = type_pf_kadt,
|
||||
@@ -640,14 +693,14 @@ type_pf_data_timeout_set(struct type_pf_elem *data, u32 timeout)
|
||||
|
||||
static int
|
||||
type_pf_elem_tadd(struct hbucket *n, const struct type_pf_elem *value,
|
||||
u32 timeout)
|
||||
u8 ahash_max, u32 timeout)
|
||||
{
|
||||
struct type_pf_elem *data;
|
||||
|
||||
if (n->pos >= n->size) {
|
||||
void *tmp;
|
||||
|
||||
if (n->size >= AHASH_MAX_SIZE)
|
||||
if (n->size >= ahash_max)
|
||||
/* Trigger rehashing */
|
||||
return -EAGAIN;
|
||||
|
||||
@@ -752,7 +805,7 @@ retry:
|
||||
for (j = 0; j < n->pos; j++) {
|
||||
data = ahash_tdata(n, j);
|
||||
m = hbucket(t, HKEY(data, h->initval, htable_bits));
|
||||
ret = type_pf_elem_tadd(m, data,
|
||||
ret = type_pf_elem_tadd(m, data, AHASH_MAX(h),
|
||||
type_pf_data_timeout(data));
|
||||
if (ret < 0) {
|
||||
read_unlock_bh(&set->lock);
|
||||
@@ -783,9 +836,9 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
const struct type_pf_elem *d = value;
|
||||
struct hbucket *n;
|
||||
struct type_pf_elem *data;
|
||||
int ret = 0, i, j = AHASH_MAX_SIZE + 1;
|
||||
int ret = 0, i, j = AHASH_MAX(h) + 1;
|
||||
bool flag_exist = flags & IPSET_FLAG_EXIST;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
|
||||
if (h->elements >= h->maxelem)
|
||||
/* FIXME: when set is full, we slow down here */
|
||||
@@ -799,18 +852,18 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_tdata(n, i);
|
||||
if (type_pf_data_equal(data, d)) {
|
||||
if (type_pf_data_equal(data, d, &multi)) {
|
||||
if (type_pf_data_expired(data) || flag_exist)
|
||||
j = i;
|
||||
else {
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
goto out;
|
||||
}
|
||||
} else if (j == AHASH_MAX_SIZE + 1 &&
|
||||
} else if (j == AHASH_MAX(h) + 1 &&
|
||||
type_pf_data_expired(data))
|
||||
j = i;
|
||||
}
|
||||
if (j != AHASH_MAX_SIZE + 1) {
|
||||
if (j != AHASH_MAX(h) + 1) {
|
||||
data = ahash_tdata(n, j);
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
del_cidr(h, data->cidr, HOST_MASK);
|
||||
@@ -820,9 +873,13 @@ type_pf_tadd(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
type_pf_data_timeout_set(data, timeout);
|
||||
goto out;
|
||||
}
|
||||
ret = type_pf_elem_tadd(n, d, timeout);
|
||||
if (ret != 0)
|
||||
TUNE_AHASH_MAX(h, multi);
|
||||
ret = type_pf_elem_tadd(n, d, AHASH_MAX(h), timeout);
|
||||
if (ret != 0) {
|
||||
if (ret == -EAGAIN)
|
||||
type_pf_data_next(h, d);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
add_cidr(h, d->cidr, HOST_MASK);
|
||||
@@ -840,18 +897,18 @@ type_pf_tdel(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
struct htable *t = h->table;
|
||||
const struct type_pf_elem *d = value;
|
||||
struct hbucket *n;
|
||||
int i, ret = 0;
|
||||
int i;
|
||||
struct type_pf_elem *data;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
|
||||
key = HKEY(value, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_tdata(n, i);
|
||||
if (!type_pf_data_equal(data, d))
|
||||
if (!type_pf_data_equal(data, d, &multi))
|
||||
continue;
|
||||
if (type_pf_data_expired(data))
|
||||
ret = -IPSET_ERR_EXIST;
|
||||
return -IPSET_ERR_EXIST;
|
||||
if (i != n->pos - 1)
|
||||
/* Not last one */
|
||||
type_pf_data_copy(data, ahash_tdata(n, n->pos - 1));
|
||||
@@ -888,16 +945,16 @@ type_pf_ttest_cidrs(struct ip_set *set, struct type_pf_elem *d, u32 timeout)
|
||||
struct type_pf_elem *data;
|
||||
struct hbucket *n;
|
||||
int i, j = 0;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
u8 host_mask = SET_HOST_MASK(set->family);
|
||||
|
||||
for (; j < host_mask && h->nets[j].cidr; j++) {
|
||||
for (; j < host_mask && h->nets[j].cidr && !multi; j++) {
|
||||
type_pf_data_netmask(d, h->nets[j].cidr);
|
||||
key = HKEY(d, h->initval, t->htable_bits);
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_tdata(n, i);
|
||||
if (type_pf_data_equal(data, d))
|
||||
if (type_pf_data_equal(data, d, &multi))
|
||||
return !type_pf_data_expired(data);
|
||||
}
|
||||
}
|
||||
@@ -913,7 +970,7 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
struct type_pf_elem *data, *d = value;
|
||||
struct hbucket *n;
|
||||
int i;
|
||||
u32 key;
|
||||
u32 key, multi = 0;
|
||||
|
||||
#ifdef IP_SET_HASH_WITH_NETS
|
||||
if (d->cidr == SET_HOST_MASK(set->family))
|
||||
@@ -923,7 +980,7 @@ type_pf_ttest(struct ip_set *set, void *value, u32 timeout, u32 flags)
|
||||
n = hbucket(t, key);
|
||||
for (i = 0; i < n->pos; i++) {
|
||||
data = ahash_tdata(n, i);
|
||||
if (type_pf_data_equal(data, d))
|
||||
if (type_pf_data_equal(data, d, &multi))
|
||||
return !type_pf_data_expired(data);
|
||||
}
|
||||
return 0;
|
||||
@@ -1031,6 +1088,8 @@ type_pf_gc_init(struct ip_set *set)
|
||||
IPSET_GC_PERIOD(h->timeout));
|
||||
}
|
||||
|
||||
#undef HKEY_DATALEN
|
||||
#undef HKEY
|
||||
#undef type_pf_data_equal
|
||||
#undef type_pf_data_isnull
|
||||
#undef type_pf_data_copy
|
||||
|
@@ -219,24 +219,25 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
bitmap_ip_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, flags & IPSET_DIM_ONE_SRC));
|
||||
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, map->timeout, flags);
|
||||
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)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct bitmap_ip *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -283,8 +284,7 @@ bitmap_ip_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -478,7 +478,7 @@ bitmap_ip_create(struct ip_set *set, struct nlattr *tb[], u32 flags)
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(first_ip, last_ip, cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
@@ -551,7 +551,8 @@ static struct ip_set_type bitmap_ip_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_INET,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
|
@@ -338,17 +338,18 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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 (!(flags & IPSET_DIM_TWO_SRC))
|
||||
if (!(opt->flags & IPSET_DIM_TWO_SRC))
|
||||
return 0;
|
||||
|
||||
data.id = ntohl(ip4addr(skb, flags & IPSET_DIM_ONE_SRC));
|
||||
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;
|
||||
|
||||
@@ -360,12 +361,12 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
data.id -= map->first_ip;
|
||||
data.ether = eth_hdr(skb)->h_source;
|
||||
|
||||
return adtfn(set, &data, map->timeout, flags);
|
||||
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)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
const struct bitmap_ipmac *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -578,7 +579,7 @@ bitmap_ipmac_create(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr >= 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
last_ip = first_ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(first_ip, last_ip, cidr);
|
||||
} else
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
@@ -623,7 +624,8 @@ static struct ip_set_type bitmap_ipmac_type = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_MAC,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_INET,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_ipmac_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
@@ -633,7 +635,8 @@ static struct ip_set_type bitmap_ipmac_type = {
|
||||
},
|
||||
.adt_policy = {
|
||||
[IPSET_ATTR_IP] = { .type = NLA_NESTED },
|
||||
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY, .len = ETH_ALEN },
|
||||
[IPSET_ATTR_ETHER] = { .type = NLA_BINARY,
|
||||
.len = ETH_ALEN },
|
||||
[IPSET_ATTR_TIMEOUT] = { .type = NLA_U32 },
|
||||
[IPSET_ATTR_LINENO] = { .type = NLA_U32 },
|
||||
},
|
||||
|
@@ -208,14 +208,16 @@ nla_put_failure:
|
||||
|
||||
static int
|
||||
bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, pf, flags & IPSET_DIM_ONE_SRC, &__port))
|
||||
if (!ip_set_get_ip_port(skb, opt->family,
|
||||
opt->flags & IPSET_DIM_ONE_SRC, &__port))
|
||||
return -EINVAL;
|
||||
|
||||
port = ntohs(__port);
|
||||
@@ -225,12 +227,12 @@ bitmap_port_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
|
||||
port -= map->first_port;
|
||||
|
||||
return adtfn(set, &port, map->timeout, flags);
|
||||
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)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct bitmap_port *map = set->data;
|
||||
ipset_adtfn adtfn = set->variant->adt[adt];
|
||||
@@ -482,7 +484,8 @@ static struct ip_set_type bitmap_port_type = {
|
||||
.features = IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = bitmap_port_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_PORT] = { .type = NLA_U16 },
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@
|
||||
#include <net/netlink.h>
|
||||
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include "ip_set.h"
|
||||
#include <net/genetlink.h>
|
||||
@@ -75,7 +76,8 @@ find_set_type(const char *name, u8 family, u8 revision)
|
||||
list_for_each_entry_rcu(type, &ip_set_type_list, list)
|
||||
if (STREQ(type->name, name) &&
|
||||
(type->family == family || type->family == AF_UNSPEC) &&
|
||||
type->revision == revision)
|
||||
revision >= type->revision_min &&
|
||||
revision <= type->revision_max)
|
||||
return type;
|
||||
return NULL;
|
||||
}
|
||||
@@ -148,10 +150,10 @@ retry:
|
||||
if (STREQ(type->name, name) &&
|
||||
(type->family == family || type->family == AF_UNSPEC)) {
|
||||
found = true;
|
||||
if (type->revision < *min)
|
||||
*min = type->revision;
|
||||
if (type->revision > *max)
|
||||
*max = type->revision;
|
||||
if (type->revision_min < *min)
|
||||
*min = type->revision_min;
|
||||
if (type->revision_max > *max)
|
||||
*max = type->revision_max;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
if (found)
|
||||
@@ -175,25 +177,27 @@ ip_set_type_register(struct ip_set_type *type)
|
||||
int ret = 0;
|
||||
|
||||
if (type->protocol != IPSET_PROTOCOL) {
|
||||
pr_warning("ip_set type %s, family %s, revision %u uses "
|
||||
pr_warning("ip_set type %s, family %s, revision %u:%u uses "
|
||||
"wrong protocol version %u (want %u)\n",
|
||||
type->name, family_name(type->family),
|
||||
type->revision, type->protocol, IPSET_PROTOCOL);
|
||||
type->revision_min, type->revision_max,
|
||||
type->protocol, IPSET_PROTOCOL);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ip_set_type_lock();
|
||||
if (find_set_type(type->name, type->family, type->revision)) {
|
||||
if (find_set_type(type->name, type->family, type->revision_min)) {
|
||||
/* Duplicate! */
|
||||
pr_warning("ip_set type %s, family %s, revision %u "
|
||||
pr_warning("ip_set type %s, family %s with revision min %u "
|
||||
"already registered!\n", type->name,
|
||||
family_name(type->family), type->revision);
|
||||
family_name(type->family), type->revision_min);
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
list_add_rcu(&type->list, &ip_set_type_list);
|
||||
pr_debug("type %s, family %s, revision %u registered.\n",
|
||||
type->name, family_name(type->family), type->revision);
|
||||
pr_debug("type %s, family %s, revision %u:%u registered.\n",
|
||||
type->name, family_name(type->family),
|
||||
type->revision_min, type->revision_max);
|
||||
unlock:
|
||||
ip_set_type_unlock();
|
||||
return ret;
|
||||
@@ -205,15 +209,15 @@ void
|
||||
ip_set_type_unregister(struct ip_set_type *type)
|
||||
{
|
||||
ip_set_type_lock();
|
||||
if (!find_set_type(type->name, type->family, type->revision)) {
|
||||
pr_warning("ip_set type %s, family %s, revision %u "
|
||||
if (!find_set_type(type->name, type->family, type->revision_min)) {
|
||||
pr_warning("ip_set type %s, family %s with revision min %u "
|
||||
"not registered\n", type->name,
|
||||
family_name(type->family), type->revision);
|
||||
family_name(type->family), type->revision_min);
|
||||
goto unlock;
|
||||
}
|
||||
list_del_rcu(&type->list);
|
||||
pr_debug("type %s, family %s, revision %u unregistered.\n",
|
||||
type->name, family_name(type->family), type->revision);
|
||||
pr_debug("type %s, family %s with revision min %u unregistered.\n",
|
||||
type->name, family_name(type->family), type->revision_min);
|
||||
unlock:
|
||||
ip_set_type_unlock();
|
||||
|
||||
@@ -346,7 +350,8 @@ __ip_set_put(ip_set_id_t index)
|
||||
|
||||
int
|
||||
ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret = 0;
|
||||
@@ -354,19 +359,19 @@ ip_set_test(ip_set_id_t index, const struct sk_buff *skb,
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
!(family == set->family || set->family == AF_UNSPEC))
|
||||
if (opt->dim < set->type->dimension ||
|
||||
!(opt->family == set->family || set->family == AF_UNSPEC))
|
||||
return 0;
|
||||
|
||||
read_lock_bh(&set->lock);
|
||||
ret = set->variant->kadt(set, skb, IPSET_TEST, family, dim, flags);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_TEST, opt);
|
||||
read_unlock_bh(&set->lock);
|
||||
|
||||
if (ret == -EAGAIN) {
|
||||
/* Type requests element to be completed */
|
||||
pr_debug("element must be competed, ADD is triggered\n");
|
||||
write_lock_bh(&set->lock);
|
||||
set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
|
||||
set->variant->kadt(set, skb, par, IPSET_ADD, opt);
|
||||
write_unlock_bh(&set->lock);
|
||||
ret = 1;
|
||||
}
|
||||
@@ -378,7 +383,8 @@ EXPORT_SYMBOL_GPL(ip_set_test);
|
||||
|
||||
int
|
||||
ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret;
|
||||
@@ -386,12 +392,12 @@ ip_set_add(ip_set_id_t index, const struct sk_buff *skb,
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
!(family == set->family || set->family == AF_UNSPEC))
|
||||
if (opt->dim < set->type->dimension ||
|
||||
!(opt->family == set->family || set->family == AF_UNSPEC))
|
||||
return 0;
|
||||
|
||||
write_lock_bh(&set->lock);
|
||||
ret = set->variant->kadt(set, skb, IPSET_ADD, family, dim, flags);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_ADD, opt);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
return ret;
|
||||
@@ -400,7 +406,8 @@ EXPORT_SYMBOL_GPL(ip_set_add);
|
||||
|
||||
int
|
||||
ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 family, u8 dim, u8 flags)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt)
|
||||
{
|
||||
struct ip_set *set = ip_set_list[index];
|
||||
int ret = 0;
|
||||
@@ -408,12 +415,12 @@ ip_set_del(ip_set_id_t index, const struct sk_buff *skb,
|
||||
BUG_ON(set == NULL);
|
||||
pr_debug("set %s, index %u\n", set->name, index);
|
||||
|
||||
if (dim < set->type->dimension ||
|
||||
!(family == set->family || set->family == AF_UNSPEC))
|
||||
if (opt->dim < set->type->dimension ||
|
||||
!(opt->family == set->family || set->family == AF_UNSPEC))
|
||||
return 0;
|
||||
|
||||
write_lock_bh(&set->lock);
|
||||
ret = set->variant->kadt(set, skb, IPSET_DEL, family, dim, flags);
|
||||
ret = set->variant->kadt(set, skb, par, IPSET_DEL, opt);
|
||||
write_unlock_bh(&set->lock);
|
||||
|
||||
return ret;
|
||||
@@ -668,6 +675,7 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
rwlock_init(&set->lock);
|
||||
strlcpy(set->name, name, IPSET_MAXNAMELEN);
|
||||
set->family = family;
|
||||
set->revision = revision;
|
||||
|
||||
/*
|
||||
* Next, check that we know the type, and take
|
||||
@@ -687,8 +695,8 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
if (attr[IPSET_ATTR_DATA] &&
|
||||
nla_parse_nested(tb, IPSET_ATTR_CREATE_MAX, attr[IPSET_ATTR_DATA],
|
||||
set->type->create_policy)) {
|
||||
ret = -IPSET_ERR_PROTOCOL;
|
||||
goto put_out;
|
||||
ret = -IPSET_ERR_PROTOCOL;
|
||||
goto put_out;
|
||||
}
|
||||
|
||||
ret = set->type->create(set, tb, flags);
|
||||
@@ -708,7 +716,8 @@ ip_set_create(struct sk_buff *skb, struct genl_info *info)
|
||||
(flags & IPSET_FLAG_EXIST) &&
|
||||
STREQ(set->type->name, clash->type->name) &&
|
||||
set->type->family == clash->type->family &&
|
||||
set->type->revision == clash->type->revision &&
|
||||
set->type->revision_min == clash->type->revision_min &&
|
||||
set->type->revision_max == clash->type->revision_max &&
|
||||
set->variant->same_set(set, clash))
|
||||
ret = 0;
|
||||
goto cleanup;
|
||||
@@ -778,7 +787,7 @@ ip_set_destroy(struct sk_buff *skb, struct genl_info *info)
|
||||
if (!attr[IPSET_ATTR_SETNAME]) {
|
||||
for (i = 0; i < ip_set_max; i++) {
|
||||
if (ip_set_list[i] != NULL && ip_set_list[i]->ref) {
|
||||
ret = IPSET_ERR_BUSY;
|
||||
ret = -IPSET_ERR_BUSY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -825,7 +834,7 @@ ip_set_flush(struct sk_buff *skb, struct genl_info *info)
|
||||
ip_set_id_t i;
|
||||
|
||||
if (unlikely(protocol_failed(attr)))
|
||||
return -EPROTO;
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
if (!attr[IPSET_ATTR_SETNAME]) {
|
||||
for (i = 0; i < ip_set_max; i++)
|
||||
@@ -947,10 +956,13 @@ ip_set_swap(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
/* List/save set data */
|
||||
|
||||
#define DUMP_INIT 0L
|
||||
#define DUMP_ALL 1L
|
||||
#define DUMP_ONE 2L
|
||||
#define DUMP_LAST 3L
|
||||
#define DUMP_INIT 0
|
||||
#define DUMP_ALL 1
|
||||
#define DUMP_ONE 2
|
||||
#define DUMP_LAST 3
|
||||
|
||||
#define DUMP_TYPE(arg) (((u32)(arg)) & 0x0000FFFF)
|
||||
#define DUMP_FLAGS(arg) (((u32)(arg)) >> 16)
|
||||
|
||||
static int
|
||||
ip_set_dump_done(struct netlink_callback *cb)
|
||||
@@ -983,6 +995,7 @@ dump_init(struct netlink_callback *cb)
|
||||
int min_len = NLMSG_SPACE(sizeof(struct genlmsghdr));
|
||||
struct nlattr *cda[IPSET_ATTR_CMD_MAX+1];
|
||||
struct nlattr *attr = (void *)nlh + min_len;
|
||||
u32 dump_type;
|
||||
ip_set_id_t index;
|
||||
|
||||
/* Second pass, so parser can't fail */
|
||||
@@ -994,17 +1007,22 @@ dump_init(struct netlink_callback *cb)
|
||||
* [..]: type specific
|
||||
*/
|
||||
|
||||
if (!cda[IPSET_ATTR_SETNAME]) {
|
||||
cb->args[0] = DUMP_ALL;
|
||||
return 0;
|
||||
if (cda[IPSET_ATTR_SETNAME]) {
|
||||
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
|
||||
if (index == IPSET_INVALID_ID)
|
||||
return -ENOENT;
|
||||
|
||||
dump_type = DUMP_ONE;
|
||||
cb->args[1] = index;
|
||||
} else
|
||||
dump_type = DUMP_ALL;
|
||||
|
||||
if (cda[IPSET_ATTR_FLAGS]) {
|
||||
u32 f = ip_set_get_h32(cda[IPSET_ATTR_FLAGS]);
|
||||
dump_type |= (f << 16);
|
||||
}
|
||||
cb->args[0] = dump_type;
|
||||
|
||||
index = find_set_id(nla_data(cda[IPSET_ATTR_SETNAME]));
|
||||
if (index == IPSET_INVALID_ID)
|
||||
return -ENOENT;
|
||||
|
||||
cb->args[0] = DUMP_ONE;
|
||||
cb->args[1] = index;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1015,9 +1033,10 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
struct ip_set *set = NULL;
|
||||
struct genlmsg_buf *nlh = NULL;
|
||||
unsigned int flags = NETLINK_CB(cb->skb).pid ? NLM_F_MULTI : 0;
|
||||
u32 dump_type, dump_flags;
|
||||
int ret = 0;
|
||||
|
||||
if (cb->args[0] == DUMP_INIT) {
|
||||
if (!cb->args[0]) {
|
||||
ret = dump_init(cb);
|
||||
if (ret < 0) {
|
||||
struct nlmsghdr *nlh = nlmsg_hdr(cb->skb);
|
||||
@@ -1032,13 +1051,17 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (cb->args[1] >= ip_set_max)
|
||||
goto out;
|
||||
|
||||
pr_debug("args[0]: %ld args[1]: %ld\n", cb->args[0], cb->args[1]);
|
||||
max = cb->args[0] == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
|
||||
dump_type = DUMP_TYPE(cb->args[0]);
|
||||
dump_flags = DUMP_FLAGS(cb->args[0]);
|
||||
max = dump_type == DUMP_ONE ? cb->args[1] + 1 : ip_set_max;
|
||||
dump_last:
|
||||
pr_debug("args[0]: %u %u args[1]: %ld\n",
|
||||
dump_type, dump_flags, cb->args[1]);
|
||||
for (; cb->args[1] < max; cb->args[1]++) {
|
||||
index = (ip_set_id_t) cb->args[1];
|
||||
set = ip_set_list[index];
|
||||
if (set == NULL) {
|
||||
if (cb->args[0] == DUMP_ONE) {
|
||||
if (dump_type == DUMP_ONE) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
@@ -1047,9 +1070,9 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
/* When dumping all sets, we must dump "sorted"
|
||||
* so that lists (unions of sets) are dumped last.
|
||||
*/
|
||||
if (cb->args[0] != DUMP_ONE &&
|
||||
!((cb->args[0] == DUMP_ALL) ^
|
||||
(set->type->features & IPSET_DUMP_LAST)))
|
||||
if (dump_type != DUMP_ONE &&
|
||||
((dump_type == DUMP_ALL) ==
|
||||
!!(set->type->features & IPSET_DUMP_LAST)))
|
||||
continue;
|
||||
pr_debug("List set: %s\n", set->name);
|
||||
if (!cb->args[2]) {
|
||||
@@ -1066,6 +1089,8 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
}
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_PROTOCOL, IPSET_PROTOCOL);
|
||||
NLA_PUT_STRING(skb, IPSET_ATTR_SETNAME, set->name);
|
||||
if (dump_flags & IPSET_FLAG_LIST_SETNAME)
|
||||
goto next_set;
|
||||
switch (cb->args[2]) {
|
||||
case 0:
|
||||
/* Core header data */
|
||||
@@ -1074,40 +1099,45 @@ ip_set_dump_start(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_FAMILY,
|
||||
set->family);
|
||||
NLA_PUT_U8(skb, IPSET_ATTR_REVISION,
|
||||
set->type->revision);
|
||||
set->revision);
|
||||
ret = set->variant->head(set, skb);
|
||||
if (ret < 0)
|
||||
goto release_refcount;
|
||||
if (dump_flags & IPSET_FLAG_LIST_HEADER)
|
||||
goto next_set;
|
||||
/* Fall through and add elements */
|
||||
default:
|
||||
read_lock_bh(&set->lock);
|
||||
ret = set->variant->list(set, skb, cb);
|
||||
read_unlock_bh(&set->lock);
|
||||
if (!cb->args[2]) {
|
||||
if (!cb->args[2])
|
||||
/* Set is done, proceed with next one */
|
||||
if (cb->args[0] == DUMP_ONE)
|
||||
cb->args[1] = IPSET_INVALID_ID;
|
||||
else
|
||||
cb->args[1]++;
|
||||
}
|
||||
goto next_set;
|
||||
goto release_refcount;
|
||||
}
|
||||
}
|
||||
/* If we dump all sets, continue with dumping last ones */
|
||||
if (dump_type == DUMP_ALL) {
|
||||
dump_type = DUMP_LAST;
|
||||
cb->args[0] = dump_type | (dump_flags << 16);
|
||||
cb->args[1] = 0;
|
||||
goto dump_last;
|
||||
}
|
||||
goto out;
|
||||
|
||||
nla_put_failure:
|
||||
ret = -EFAULT;
|
||||
next_set:
|
||||
if (dump_type == DUMP_ONE)
|
||||
cb->args[1] = IPSET_INVALID_ID;
|
||||
else
|
||||
cb->args[1]++;
|
||||
release_refcount:
|
||||
/* If there was an error or set is done, release set */
|
||||
if (ret || !cb->args[2]) {
|
||||
pr_debug("release set %s\n", ip_set_list[index]->name);
|
||||
ip_set_put_byindex(index);
|
||||
}
|
||||
|
||||
/* If we dump all sets, continue with dumping last ones */
|
||||
if (cb->args[0] == DUMP_ALL && cb->args[1] >= max && !cb->args[2])
|
||||
cb->args[0] = DUMP_LAST;
|
||||
|
||||
out:
|
||||
if (nlh) {
|
||||
genlmsg_end(skb, nlh);
|
||||
@@ -1130,9 +1160,13 @@ ip_set_dump(struct sk_buff *skb, struct genl_info *info)
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
genl_unlock();
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
|
||||
ret = netlink_dump_start(ctnl, skb, nlh, ip_set_dump_start, ip_set_dump_done, 0);
|
||||
#else
|
||||
ret = netlink_dump_start(ctnl, skb, nlh,
|
||||
ip_set_dump_start,
|
||||
ip_set_dump_done);
|
||||
#endif
|
||||
genl_lock();
|
||||
return ret;
|
||||
}
|
||||
@@ -1153,17 +1187,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
|
||||
struct nlattr *tb[], enum ipset_adt adt,
|
||||
u32 flags, bool use_lineno)
|
||||
{
|
||||
int ret, retried = 0;
|
||||
int ret;
|
||||
u32 lineno = 0;
|
||||
bool eexist = flags & IPSET_FLAG_EXIST;
|
||||
bool eexist = flags & IPSET_FLAG_EXIST, retried = false;
|
||||
|
||||
do {
|
||||
write_lock_bh(&set->lock);
|
||||
ret = set->variant->uadt(set, tb, adt, &lineno, flags);
|
||||
ret = set->variant->uadt(set, tb, adt, &lineno, flags, retried);
|
||||
write_unlock_bh(&set->lock);
|
||||
retried = true;
|
||||
} while (ret == -EAGAIN &&
|
||||
set->variant->resize &&
|
||||
(ret = set->variant->resize(set, retried++)) == 0);
|
||||
(ret = set->variant->resize(set, retried)) == 0);
|
||||
|
||||
if (!ret || (ret == -IPSET_ERR_EXIST && eexist))
|
||||
return 0;
|
||||
@@ -1338,7 +1373,7 @@ ip_set_utest(struct sk_buff *skb, struct genl_info *info)
|
||||
return -IPSET_ERR_PROTOCOL;
|
||||
|
||||
read_lock_bh(&set->lock);
|
||||
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0);
|
||||
ret = set->variant->uadt(set, tb, IPSET_TEST, NULL, 0, 0);
|
||||
read_unlock_bh(&set->lock);
|
||||
/* Userspace can't trigger element to be re-added */
|
||||
if (ret == -EAGAIN)
|
||||
@@ -1381,7 +1416,7 @@ ip_set_header(struct sk_buff *skb, struct genl_info *info)
|
||||
NLA_PUT_STRING(skb2, IPSET_ATTR_SETNAME, set->name);
|
||||
NLA_PUT_STRING(skb2, IPSET_ATTR_TYPENAME, set->type->name);
|
||||
NLA_PUT_U8(skb2, IPSET_ATTR_FAMILY, set->family);
|
||||
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->type->revision);
|
||||
NLA_PUT_U8(skb2, IPSET_ATTR_REVISION, set->revision);
|
||||
genlmsg_end(skb2, nlh2);
|
||||
|
||||
ret = genlmsg_unicast(genl_info_net(info), skb2, NETLINK_CB(skb).pid);
|
||||
|
@@ -11,6 +11,10 @@ enum {
|
||||
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__
|
||||
|
@@ -53,7 +53,8 @@ struct hash_ip4_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ip4_data_equal(const struct hash_ip4_elem *ip1,
|
||||
const struct hash_ip4_elem *ip2)
|
||||
const struct hash_ip4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip;
|
||||
}
|
||||
@@ -108,25 +109,32 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, flags & IPSET_DIM_ONE_SRC, &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, h->timeout, flags);
|
||||
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)
|
||||
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];
|
||||
@@ -171,13 +179,14 @@ hash_ip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(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)
|
||||
@@ -217,7 +226,8 @@ struct hash_ip6_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ip6_data_equal(const struct hash_ip6_elem *ip1,
|
||||
const struct hash_ip6_elem *ip2)
|
||||
const struct hash_ip6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0;
|
||||
}
|
||||
@@ -281,20 +291,26 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, flags & IPSET_DIM_ONE_SRC, &ip.in6);
|
||||
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, h->timeout, flags);
|
||||
return adtfn(set, &ip, opt_timeout(opt, h), opt->cmdflags);
|
||||
}
|
||||
|
||||
static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
@@ -305,7 +321,7 @@ static const struct nla_policy hash_ip6_adt_policy[IPSET_ATTR_ADT_MAX + 1] = {
|
||||
|
||||
static int
|
||||
hash_ip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
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];
|
||||
@@ -428,7 +444,8 @@ static struct ip_set_type hash_ip_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = hash_ip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@@ -60,7 +60,8 @@ struct hash_ipport4_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ipport4_data_equal(const struct hash_ipport4_elem *ip1,
|
||||
const struct hash_ipport4_elem *ip2)
|
||||
const struct hash_ipport4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->port == ip2->port &&
|
||||
@@ -124,31 +125,40 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
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)
|
||||
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, p, port, port_to;
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -208,8 +218,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -220,8 +229,11 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
swap(port, port_to);
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
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);
|
||||
@@ -231,6 +243,7 @@ hash_ipport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -264,7 +277,8 @@ struct hash_ipport6_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ipport6_data_equal(const struct hash_ipport6_elem *ip1,
|
||||
const struct hash_ipport6_elem *ip2)
|
||||
const struct hash_ipport6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
@@ -328,26 +342,34 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
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)
|
||||
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];
|
||||
@@ -405,6 +427,8 @@ hash_ipport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
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);
|
||||
@@ -491,7 +515,8 @@ static struct ip_set_type hash_ipport_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* SCTP and UDPLITE support added */
|
||||
.create = hash_ipport_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@@ -62,7 +62,8 @@ struct hash_ipportip4_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ipportip4_data_equal(const struct hash_ipportip4_elem *ip1,
|
||||
const struct hash_ipportip4_elem *ip2)
|
||||
const struct hash_ipportip4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->ip2 == ip2->ip2 &&
|
||||
@@ -127,32 +128,41 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
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)
|
||||
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, p, port, port_to;
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -216,8 +226,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
|
||||
@@ -228,8 +237,11 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
swap(port, port_to);
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
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);
|
||||
@@ -239,6 +251,7 @@ hash_ipportip4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
else
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -274,7 +287,8 @@ struct hash_ipportip6_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ipportip6_data_equal(const struct hash_ipportip6_elem *ip1,
|
||||
const struct hash_ipportip6_elem *ip2)
|
||||
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 &&
|
||||
@@ -341,27 +355,35 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
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, h->timeout, flags);
|
||||
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)
|
||||
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];
|
||||
@@ -423,6 +445,8 @@ hash_ipportip6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
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);
|
||||
@@ -509,7 +533,8 @@ static struct ip_set_type hash_ipportip_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.revision_min = 0,
|
||||
.revision_max = 1, /* SCTP and UDPLITE support added */
|
||||
.create = hash_ipportip_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_HASHSIZE] = { .type = NLA_U32 },
|
||||
|
@@ -62,7 +62,8 @@ struct hash_ipportnet4_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ipportnet4_data_equal(const struct hash_ipportnet4_elem *ip1,
|
||||
const struct hash_ipportnet4_elem *ip2)
|
||||
const struct hash_ipportnet4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->ip2 == ip2->ip2 &&
|
||||
@@ -140,39 +141,51 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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 || HOST_MASK };
|
||||
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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2);
|
||||
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, h->timeout, flags);
|
||||
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)
|
||||
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, p, port, port_to;
|
||||
u32 ip, ip_to, p = 0, port, port_to;
|
||||
u32 ip2_from = 0, ip2_to, ip2_last, ip2;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -186,21 +199,19 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP2], &data.ip2);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP2], &ip2_from);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR2])
|
||||
if (tb[IPSET_ATTR_CIDR2]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR2]);
|
||||
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
data.ip2 &= ip_set_netmask(data.cidr);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
@@ -225,14 +236,16 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
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_IP_TO] || tb[IPSET_ATTR_CIDR] ||
|
||||
tb[IPSET_ATTR_PORT_TO])) {
|
||||
!(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;
|
||||
}
|
||||
|
||||
ip = ntohl(data.ip);
|
||||
if (tb[IPSET_ATTR_IP_TO]) {
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP_TO], &ip_to);
|
||||
if (ret)
|
||||
@@ -244,29 +257,50 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
|
||||
if (cidr > 32)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
ip &= ip_set_hostmask(cidr);
|
||||
ip_to = ip | ~ip_set_hostmask(cidr);
|
||||
} else
|
||||
ip_to = ip;
|
||||
ip_set_mask_from_to(ip, ip_to, cidr);
|
||||
}
|
||||
|
||||
port_to = port = ntohs(data.port);
|
||||
if (with_ports && tb[IPSET_ATTR_PORT_TO]) {
|
||||
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);
|
||||
}
|
||||
|
||||
for (; !before(ip_to, ip); ip++)
|
||||
for (p = port; p <= port_to; p++) {
|
||||
data.ip = htonl(ip);
|
||||
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);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
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;
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
return ret;
|
||||
else
|
||||
ret = 0;
|
||||
ip2 = ip2_last + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -302,7 +336,8 @@ struct hash_ipportnet6_telem {
|
||||
|
||||
static inline bool
|
||||
hash_ipportnet6_data_equal(const struct hash_ipportnet6_elem *ip1,
|
||||
const struct hash_ipportnet6_elem *ip2)
|
||||
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 &&
|
||||
@@ -388,34 +423,43 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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 || HOST_MASK };
|
||||
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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, flags & IPSET_DIM_THREE_SRC, &data.ip2.in6);
|
||||
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, h->timeout, flags);
|
||||
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)
|
||||
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];
|
||||
@@ -432,6 +476,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
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]);
|
||||
@@ -485,6 +531,8 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
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);
|
||||
@@ -574,7 +622,9 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_TYPE_IP2,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.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 },
|
||||
@@ -587,6 +637,7 @@ static struct ip_set_type hash_ipportnet_type __read_mostly = {
|
||||
[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 },
|
||||
|
@@ -58,7 +58,8 @@ struct hash_net4_telem {
|
||||
|
||||
static inline bool
|
||||
hash_net4_data_equal(const struct hash_net4_elem *ip1,
|
||||
const struct hash_net4_elem *ip2)
|
||||
const struct hash_net4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip && ip1->cidr == ip2->cidr;
|
||||
}
|
||||
@@ -125,33 +126,44 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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 || HOST_MASK };
|
||||
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, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
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)
|
||||
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] ||
|
||||
@@ -161,17 +173,15 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_TIMEOUT]) {
|
||||
if (!with_timeout(h->timeout))
|
||||
@@ -179,9 +189,35 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
@@ -214,7 +250,8 @@ struct hash_net6_telem {
|
||||
|
||||
static inline bool
|
||||
hash_net6_data_equal(const struct hash_net6_elem *ip1,
|
||||
const struct hash_net6_elem *ip2)
|
||||
const struct hash_net6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->cidr == ip2->cidr;
|
||||
@@ -290,28 +327,37 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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 || HOST_MASK };
|
||||
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, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
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)
|
||||
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];
|
||||
@@ -322,6 +368,8 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
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]);
|
||||
@@ -425,7 +473,8 @@ static struct ip_set_type hash_net_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.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 },
|
||||
@@ -436,6 +485,7 @@ static struct ip_set_type hash_net_type __read_mostly = {
|
||||
},
|
||||
.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 },
|
||||
},
|
||||
|
786
extensions/ipset-6/ip_set_hash_netiface.c
Normal file
786
extensions/ipset-6/ip_set_hash_netiface.c
Normal file
@@ -0,0 +1,786 @@
|
||||
/* 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 == AF_INET || set->family == AF_INET6))
|
||||
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 == AF_INET ? 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 == AF_INET
|
||||
? &hash_netiface4_tvariant : &hash_netiface6_tvariant;
|
||||
|
||||
if (set->family == AF_INET)
|
||||
hash_netiface4_gc_init(set);
|
||||
else
|
||||
hash_netiface6_gc_init(set);
|
||||
} else {
|
||||
set->variant = set->family == AF_INET
|
||||
? &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 = AF_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);
|
@@ -59,7 +59,8 @@ struct hash_netport4_telem {
|
||||
|
||||
static inline bool
|
||||
hash_netport4_data_equal(const struct hash_netport4_elem *ip1,
|
||||
const struct hash_netport4_elem *ip2)
|
||||
const struct hash_netport4_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ip1->ip == ip2->ip &&
|
||||
ip1->port == ip2->port &&
|
||||
@@ -137,38 +138,48 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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 || HOST_MASK };
|
||||
.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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip4_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip4addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
ip4addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip);
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
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)
|
||||
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;
|
||||
u32 port, port_to, p = 0, ip = 0, ip_to, last;
|
||||
u32 timeout = h->timeout;
|
||||
bool with_ports = false;
|
||||
int ret;
|
||||
@@ -182,15 +193,15 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
if (tb[IPSET_ATTR_LINENO])
|
||||
*lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]);
|
||||
|
||||
ret = ip_set_get_ipaddr4(tb[IPSET_ATTR_IP], &data.ip);
|
||||
ret = ip_set_get_hostipaddr4(tb[IPSET_ATTR_IP], &ip);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tb[IPSET_ATTR_CIDR])
|
||||
if (tb[IPSET_ATTR_CIDR]) {
|
||||
data.cidr = nla_get_u8(tb[IPSET_ATTR_CIDR]);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
data.ip &= ip_set_netmask(data.cidr);
|
||||
if (!data.cidr)
|
||||
return -IPSET_ERR_INVALID_CIDR;
|
||||
}
|
||||
|
||||
if (tb[IPSET_ATTR_PORT])
|
||||
data.port = nla_get_be16(tb[IPSET_ATTR_PORT]);
|
||||
@@ -215,24 +226,47 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]);
|
||||
}
|
||||
|
||||
if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
|
||||
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 = ntohs(data.port);
|
||||
port_to = ip_set_get_h16(tb[IPSET_ATTR_PORT_TO]);
|
||||
if (port > port_to)
|
||||
swap(port, port_to);
|
||||
|
||||
for (; port <= port_to; port++) {
|
||||
data.port = htons(port);
|
||||
ret = adtfn(set, &data, timeout, flags);
|
||||
|
||||
if (ret && !ip_set_eexist(ret, flags))
|
||||
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;
|
||||
else
|
||||
ret = 0;
|
||||
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;
|
||||
}
|
||||
@@ -267,7 +301,8 @@ struct hash_netport6_telem {
|
||||
|
||||
static inline bool
|
||||
hash_netport6_data_equal(const struct hash_netport6_elem *ip1,
|
||||
const struct hash_netport6_elem *ip2)
|
||||
const struct hash_netport6_elem *ip2,
|
||||
u32 *multi)
|
||||
{
|
||||
return ipv6_addr_cmp(&ip1->ip.in6, &ip2->ip.in6) == 0 &&
|
||||
ip1->port == ip2->port &&
|
||||
@@ -350,33 +385,42 @@ nla_put_failure:
|
||||
#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,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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 || HOST_MASK };
|
||||
.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, flags & IPSET_DIM_TWO_SRC,
|
||||
if (!ip_set_get_ip6_port(skb, opt->flags & IPSET_DIM_TWO_SRC,
|
||||
&data.port, &data.proto))
|
||||
return -EINVAL;
|
||||
|
||||
ip6addrptr(skb, flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6addrptr(skb, opt->flags & IPSET_DIM_ONE_SRC, &data.ip.in6);
|
||||
ip6_netmask(&data.ip, data.cidr);
|
||||
|
||||
return adtfn(set, &data, h->timeout, flags);
|
||||
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)
|
||||
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];
|
||||
@@ -391,6 +435,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
!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]);
|
||||
@@ -438,6 +484,8 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
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);
|
||||
@@ -526,7 +574,9 @@ static struct ip_set_type hash_netport_type __read_mostly = {
|
||||
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 1,
|
||||
.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 },
|
||||
@@ -538,6 +588,7 @@ static struct ip_set_type hash_netport_type __read_mostly = {
|
||||
},
|
||||
.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 },
|
||||
|
@@ -72,7 +72,8 @@ list_set_expired(const struct list_set *map, u32 id)
|
||||
|
||||
static int
|
||||
list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
enum ipset_adt adt, u8 pf, u8 dim, u8 flags)
|
||||
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;
|
||||
@@ -87,17 +88,17 @@ list_set_kadt(struct ip_set *set, const struct sk_buff *skb,
|
||||
continue;
|
||||
switch (adt) {
|
||||
case IPSET_TEST:
|
||||
ret = ip_set_test(elem->id, skb, pf, dim, flags);
|
||||
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, pf, dim, flags);
|
||||
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, pf, dim, flags);
|
||||
ret = ip_set_del(elem->id, skb, par, opt);
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
break;
|
||||
@@ -218,7 +219,7 @@ cleanup_entries(struct list_set *map)
|
||||
|
||||
static int
|
||||
list_set_uadt(struct ip_set *set, struct nlattr *tb[],
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags)
|
||||
enum ipset_adt adt, u32 *lineno, u32 flags, bool retried)
|
||||
{
|
||||
struct list_set *map = set->data;
|
||||
bool with_timeout = with_timeout(map->timeout);
|
||||
@@ -575,7 +576,8 @@ static struct ip_set_type list_set_type __read_mostly = {
|
||||
.features = IPSET_TYPE_NAME | IPSET_DUMP_LAST,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.family = AF_UNSPEC,
|
||||
.revision = 0,
|
||||
.revision_min = 0,
|
||||
.revision_max = 0,
|
||||
.create = list_set_create,
|
||||
.create_policy = {
|
||||
[IPSET_ATTR_SIZE] = { .type = NLA_U32 },
|
||||
|
@@ -22,6 +22,9 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
@@ -45,7 +48,7 @@ ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
(timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_after(timeout, jiffies));
|
||||
time_is_after_jiffies(timeout));
|
||||
}
|
||||
|
||||
static inline bool
|
||||
@@ -53,7 +56,7 @@ ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_UNSET &&
|
||||
timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_before(timeout, jiffies);
|
||||
time_is_before_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
@@ -64,7 +67,7 @@ ip_set_timeout_set(u32 timeout)
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = timeout * HZ + jiffies;
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_UNSET || t == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! */
|
||||
t++;
|
||||
@@ -75,7 +78,8 @@ ip_set_timeout_set(u32 timeout)
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -89,14 +93,14 @@ static inline bool
|
||||
ip_set_timeout_test(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ||
|
||||
time_after(timeout, jiffies);
|
||||
time_is_after_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ip_set_timeout_expired(unsigned long timeout)
|
||||
{
|
||||
return timeout != IPSET_ELEM_PERMANENT &&
|
||||
time_before(timeout, jiffies);
|
||||
time_is_before_jiffies(timeout);
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
@@ -107,7 +111,7 @@ ip_set_timeout_set(u32 timeout)
|
||||
if (!timeout)
|
||||
return IPSET_ELEM_PERMANENT;
|
||||
|
||||
t = timeout * HZ + jiffies;
|
||||
t = msecs_to_jiffies(timeout * 1000) + jiffies;
|
||||
if (t == IPSET_ELEM_PERMANENT)
|
||||
/* Bingo! :-) */
|
||||
t++;
|
||||
@@ -118,7 +122,8 @@ ip_set_timeout_set(u32 timeout)
|
||||
static inline u32
|
||||
ip_set_timeout_get(unsigned long timeout)
|
||||
{
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 : (timeout - jiffies)/HZ;
|
||||
return timeout == IPSET_ELEM_PERMANENT ? 0 :
|
||||
jiffies_to_msecs(timeout - jiffies)/1000;
|
||||
}
|
||||
#endif /* ! IP_SET_BITMAP_TIMEOUT */
|
||||
|
||||
|
@@ -1,12 +1,13 @@
|
||||
/* 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
|
||||
* 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 <sys/socket.h> /* AF_ */
|
||||
#include <stdlib.h> /* malloc, free */
|
||||
#include <string.h> /* memset */
|
||||
@@ -17,7 +18,7 @@
|
||||
#include <libipset/utils.h> /* inXcpy */
|
||||
#include <libipset/data.h> /* prototypes */
|
||||
|
||||
/* Internal data structure to hold
|
||||
/* Internal data structure to hold
|
||||
* a) input data entered by the user or
|
||||
* b) data received from kernel
|
||||
*
|
||||
@@ -66,11 +67,13 @@ struct ipset_data {
|
||||
/* 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;
|
||||
};
|
||||
};
|
||||
@@ -171,7 +174,7 @@ 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);
|
||||
|
||||
@@ -289,12 +292,20 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
return -1;
|
||||
copy_addr(data->family, &data->adt.ip2, value);
|
||||
break;
|
||||
case IPSET_OPT_IP2_TO:
|
||||
if (!(data->family == AF_INET || data->family == AF_INET6))
|
||||
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);
|
||||
@@ -306,6 +317,9 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
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;
|
||||
@@ -315,7 +329,7 @@ ipset_data_set(struct ipset_data *data, enum ipset_opt opt, const void *value)
|
||||
default:
|
||||
return -1;
|
||||
};
|
||||
|
||||
|
||||
ipset_data_flags_set(data, IPSET_FLAG(opt));
|
||||
return 0;
|
||||
}
|
||||
@@ -334,7 +348,7 @@ 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;
|
||||
|
||||
@@ -401,10 +415,14 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
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;
|
||||
@@ -414,6 +432,7 @@ ipset_data_get(const struct ipset_data *data, enum ipset_opt opt)
|
||||
return &data->flags;
|
||||
case IPSET_OPT_CADT_FLAGS:
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return &data->cadt_flags;
|
||||
default:
|
||||
return NULL;
|
||||
@@ -436,6 +455,7 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
|
||||
case IPSET_OPT_IP:
|
||||
case IPSET_OPT_IP_TO:
|
||||
case IPSET_OPT_IP2:
|
||||
case IPSET_OPT_IP2_TO:
|
||||
return family == AF_INET ? sizeof(uint32_t)
|
||||
: sizeof(struct in6_addr);
|
||||
case IPSET_OPT_PORT:
|
||||
@@ -463,8 +483,9 @@ ipset_data_sizeof(enum ipset_opt opt, uint8_t family)
|
||||
return sizeof(uint8_t);
|
||||
case IPSET_OPT_ETHER:
|
||||
return ETH_ALEN;
|
||||
/* Flags counted once */
|
||||
/* Flags doesn't counted once :-( */
|
||||
case IPSET_OPT_BEFORE:
|
||||
case IPSET_OPT_PHYSDEV:
|
||||
return sizeof(uint32_t);
|
||||
default:
|
||||
return 0;
|
||||
@@ -512,8 +533,8 @@ uint8_t
|
||||
ipset_data_cidr(const struct ipset_data *data)
|
||||
{
|
||||
assert(data);
|
||||
return ipset_data_test(data, IPSET_OPT_CIDR) ? data->cidr :
|
||||
data->family == AF_INET ? 32 :
|
||||
return ipset_data_test(data, IPSET_OPT_CIDR) ? data->cidr :
|
||||
data->family == AF_INET ? 32 :
|
||||
data->family == AF_INET6 ? 128 : 0;
|
||||
}
|
||||
|
||||
|
288
extensions/ipset-6/libipset/debug.c
Normal file
288
extensions/ipset-6/libipset/debug.c
Normal file
@@ -0,0 +1,288 @@
|
||||
/* 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(AF_INET, 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(AF_INET6, 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,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -49,19 +49,20 @@ static const struct icmp_names icmp_typecodes[] = {
|
||||
{ "address-mask-reply", 18, 0 },
|
||||
};
|
||||
|
||||
const char * id_to_icmp(uint8_t id)
|
||||
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)
|
||||
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)
|
||||
if (icmp_typecodes[i].type == type &&
|
||||
icmp_typecodes[i].code == code)
|
||||
return icmp_typecodes[i].name;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -71,9 +72,10 @@ int name_to_icmp(const char *str, uint16_t *typecode)
|
||||
|
||||
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;
|
||||
*typecode = (icmp_typecodes[i].type << 8) |
|
||||
icmp_typecodes[i].code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -36,19 +36,21 @@ static const struct icmpv6_names icmpv6_typecodes[] = {
|
||||
{ "redirect", 137, 0 },
|
||||
};
|
||||
|
||||
const char * id_to_icmpv6(uint8_t id)
|
||||
const char *id_to_icmpv6(uint8_t id)
|
||||
{
|
||||
return id < ARRAY_SIZE(icmpv6_typecodes) ? icmpv6_typecodes[id].name : NULL;
|
||||
return id < ARRAY_SIZE(icmpv6_typecodes) ?
|
||||
icmpv6_typecodes[id].name : NULL;
|
||||
}
|
||||
|
||||
const char * icmpv6_to_name(uint8_t type, uint8_t code)
|
||||
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)
|
||||
if (icmpv6_typecodes[i].type == type &&
|
||||
icmpv6_typecodes[i].code == code)
|
||||
return icmpv6_typecodes[i].name;
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -58,9 +60,10 @@ int name_to_icmpv6(const char *str, uint16_t *typecode)
|
||||
|
||||
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;
|
||||
*typecode = (icmpv6_typecodes[i].type << 8) |
|
||||
icmpv6_typecodes[i].code;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -38,7 +38,8 @@ struct ipset_handle {
|
||||
|
||||
/* 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_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,
|
||||
@@ -83,7 +84,6 @@ ipset_mnl_fill_hdr(struct ipset_handle *handle, enum ipset_cmd cmd,
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST;
|
||||
if (cmdflags[cmd-1] & NLM_F_ACK)
|
||||
nlh->nlmsg_flags |= NLM_F_ACK;
|
||||
nlh->nlmsg_seq = ++handle->seq;
|
||||
|
||||
ghdr = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
|
||||
ghdr->cmd = cmd;
|
||||
@@ -102,19 +102,24 @@ ipset_mnl_query(struct ipset_handle *handle, void *buffer, size_t len)
|
||||
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;
|
||||
|
||||
D("message sent");
|
||||
ret = mnl_socket_recvfrom(handle->h, buffer, len);
|
||||
D("message received, ret: %d", ret);
|
||||
#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", ret);
|
||||
D("nfln_cb_run2, ret: %d, errno %d", ret, errno);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(handle->h, buffer, len);
|
||||
@@ -205,28 +210,28 @@ static int ipset_mnl_getid(struct ipset_handle *h, bool modprobe)
|
||||
|
||||
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;
|
||||
@@ -236,7 +241,7 @@ close_nl:
|
||||
free_handle:
|
||||
free(handle);
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <sys/types.h> /* getaddrinfo */
|
||||
#include <sys/socket.h> /* getaddrinfo, AF_ */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
#include <netinet/in.h> /* IPPROTO_ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
@@ -43,21 +44,23 @@ static char *
|
||||
ipset_strchr(const char *str, const char *sep)
|
||||
{
|
||||
char *match;
|
||||
|
||||
|
||||
assert(str);
|
||||
assert(sep);
|
||||
|
||||
for (; *sep != '\0'; sep++)
|
||||
if ((match = strchr(str, sep[0])) != NULL
|
||||
&& str[0] != sep[0]
|
||||
&& str[strlen(str)-1] != sep[0])
|
||||
|
||||
for (; *sep != '\0'; sep++) {
|
||||
match = strchr(str, sep[0]);
|
||||
if (match != NULL &&
|
||||
str[0] != sep[0] &&
|
||||
str[strlen(str)-1] != sep[0])
|
||||
return match;
|
||||
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parser functions, shamelessly taken from iptables.c, ip6tables.c
|
||||
/*
|
||||
* Parser functions, shamelessly taken from iptables.c, ip6tables.c
|
||||
* and parser.c from libnetfilter_conntrack.
|
||||
*/
|
||||
|
||||
@@ -66,7 +69,7 @@ ipset_strchr(const char *str, const char *sep)
|
||||
*/
|
||||
static int
|
||||
string_to_number_ll(struct ipset_session *session,
|
||||
const char *str,
|
||||
const char *str,
|
||||
unsigned long long min,
|
||||
unsigned long long max,
|
||||
unsigned long long *ret)
|
||||
@@ -113,7 +116,7 @@ string_to_cidr(struct ipset_session *session,
|
||||
const char *str, uint8_t min, uint8_t max, uint8_t *ret)
|
||||
{
|
||||
int err = string_to_u8(session, str, ret);
|
||||
|
||||
|
||||
if (!err && (*ret < min || *ret > max))
|
||||
return syntax_err("'%s' is out of range %u-%u",
|
||||
str, min, max);
|
||||
@@ -164,7 +167,7 @@ ipset_parse_ether(struct ipset_session *session,
|
||||
{
|
||||
unsigned int i = 0;
|
||||
unsigned char ether[ETH_ALEN];
|
||||
|
||||
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_ETHER);
|
||||
assert(str);
|
||||
@@ -178,9 +181,9 @@ ipset_parse_ether(struct ipset_session *session,
|
||||
|
||||
number = strtol(str + i * 3, &end, 16);
|
||||
|
||||
if (end == str + i * 3 + 2
|
||||
&& (*end == ':' || *end == '\0')
|
||||
&& number >= 0 && number <= 255)
|
||||
if (end == str + i * 3 + 2 &&
|
||||
(*end == ':' || *end == '\0') &&
|
||||
number >= 0 && number <= 255)
|
||||
ether[i] = number;
|
||||
else
|
||||
goto error;
|
||||
@@ -198,13 +201,13 @@ static int
|
||||
parse_portname(struct ipset_session *session, const char *str,
|
||||
uint16_t *port, const char *proto)
|
||||
{
|
||||
struct servent *service;
|
||||
struct servent *service = getservbyname(str, proto);
|
||||
|
||||
if ((service = getservbyname(str, proto)) != NULL) {
|
||||
if (service != NULL) {
|
||||
*port = ntohs((uint16_t) service->s_port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return syntax_err("cannot parse '%s' as a %s port", str, proto);
|
||||
}
|
||||
|
||||
@@ -232,8 +235,8 @@ ipset_parse_port(struct ipset_session *session,
|
||||
assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
|
||||
assert(str);
|
||||
|
||||
if ((err = string_to_u16(session, str, &port)) == 0
|
||||
|| (err = parse_portname(session, str, &port, proto)) == 0)
|
||||
if ((err = string_to_u16(session, str, &port)) == 0 ||
|
||||
(err = parse_portname(session, str, &port, proto)) == 0)
|
||||
err = ipset_session_data_set(session, opt, &port);
|
||||
|
||||
if (!err)
|
||||
@@ -351,7 +354,7 @@ ipset_parse_proto(struct ipset_session *session,
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_PROTO);
|
||||
assert(str);
|
||||
|
||||
|
||||
protoent = getprotobyname(strcasecmp(str, "icmpv6") == 0
|
||||
? "ipv6-icmp" : str);
|
||||
if (protoent == NULL)
|
||||
@@ -360,7 +363,7 @@ ipset_parse_proto(struct ipset_session *session,
|
||||
proto = protoent->p_proto;
|
||||
if (!proto)
|
||||
return syntax_err("Unsupported protocol '%s'", str);
|
||||
|
||||
|
||||
return ipset_session_data_set(session, opt, &proto);
|
||||
}
|
||||
|
||||
@@ -374,7 +377,7 @@ parse_icmp_typecode(struct ipset_session *session,
|
||||
uint8_t type, code;
|
||||
char *a, *saved, *tmp;
|
||||
int err;
|
||||
|
||||
|
||||
saved = tmp = strdup(str);
|
||||
if (tmp == NULL)
|
||||
return ipset_err(session,
|
||||
@@ -384,13 +387,14 @@ parse_icmp_typecode(struct ipset_session *session,
|
||||
if (a == NULL) {
|
||||
free(saved);
|
||||
return ipset_err(session,
|
||||
"Cannot parse %s as an %s type/code.", str, family);
|
||||
"Cannot parse %s as an %s type/code.",
|
||||
str, family);
|
||||
}
|
||||
*a++ = '\0';
|
||||
if ((err = string_to_u8(session, a, &type)) != 0
|
||||
|| (err = string_to_u8(session, tmp, &code)) != 0)
|
||||
goto error;
|
||||
|
||||
if ((err = string_to_u8(session, a, &type)) != 0 ||
|
||||
(err = string_to_u8(session, tmp, &code)) != 0)
|
||||
goto error;
|
||||
|
||||
typecode = (type << 8) | code;
|
||||
err = ipset_session_data_set(session, opt, &typecode);
|
||||
|
||||
@@ -496,7 +500,7 @@ ipset_parse_proto_port(struct ipset_session *session,
|
||||
err = ipset_parse_proto(session, IPSET_OPT_PROTO, tmp);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
|
||||
p = *(const uint8_t *) ipset_data_get(data, IPSET_OPT_PROTO);
|
||||
switch (p) {
|
||||
case IPPROTO_TCP:
|
||||
@@ -508,28 +512,31 @@ ipset_parse_proto_port(struct ipset_session *session,
|
||||
goto parse_port;
|
||||
case IPPROTO_ICMP:
|
||||
if (family != AF_INET) {
|
||||
syntax_err("Protocol ICMP can be used with family INET only");
|
||||
syntax_err("Protocol ICMP can be used "
|
||||
"with family INET only");
|
||||
goto error;
|
||||
}
|
||||
err = ipset_parse_icmp(session, opt, a);
|
||||
break;
|
||||
case IPPROTO_ICMPV6:
|
||||
if (family != AF_INET6) {
|
||||
syntax_err("Protocol ICMPv6 can be used with family INET6 only");
|
||||
syntax_err("Protocol ICMPv6 can be used "
|
||||
"with family INET6 only");
|
||||
goto error;
|
||||
}
|
||||
err = ipset_parse_icmpv6(session, opt, a);
|
||||
break;
|
||||
default:
|
||||
if (!STREQ(a, "0")) {
|
||||
syntax_err("Protocol %s can be used with pseudo port value 0 only.");
|
||||
syntax_err("Protocol %s can be used "
|
||||
"with pseudo port value 0 only.");
|
||||
goto error;
|
||||
}
|
||||
ipset_data_flags_set(data, IPSET_FLAG(opt));
|
||||
}
|
||||
goto error;
|
||||
} else {
|
||||
proto = "TCP";
|
||||
proto = "TCP";
|
||||
err = ipset_data_set(data, IPSET_OPT_PROTO, &p);
|
||||
if (err)
|
||||
goto error;
|
||||
@@ -559,7 +566,7 @@ ipset_parse_family(struct ipset_session *session,
|
||||
{
|
||||
struct ipset_data *data;
|
||||
uint8_t family;
|
||||
|
||||
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_FAMILY);
|
||||
assert(str);
|
||||
@@ -577,7 +584,7 @@ ipset_parse_family(struct ipset_session *session,
|
||||
family = AF_UNSPEC;
|
||||
else
|
||||
return syntax_err("unknown INET family %s", str);
|
||||
|
||||
|
||||
return ipset_data_set(data, opt, &family);
|
||||
}
|
||||
|
||||
@@ -585,27 +592,27 @@ ipset_parse_family(struct ipset_session *session,
|
||||
* Parse IPv4/IPv6 addresses, networks and ranges.
|
||||
* We resolve hostnames but just the first IP address is used.
|
||||
*/
|
||||
|
||||
|
||||
static struct addrinfo *
|
||||
call_getaddrinfo(struct ipset_session *session, const char *str,
|
||||
uint8_t family)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res;
|
||||
struct addrinfo *res;
|
||||
int err;
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_RAW;
|
||||
hints.ai_protocol = 0;
|
||||
hints.ai_next = NULL;
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = SOCK_RAW;
|
||||
hints.ai_protocol = 0;
|
||||
hints.ai_next = NULL;
|
||||
|
||||
if ((err = getaddrinfo(str, NULL, &hints, &res)) != 0) {
|
||||
syntax_err("cannot resolve '%s' to an %s address: %s",
|
||||
str, family == AF_INET6 ? "IPv6" : "IPv4",
|
||||
gai_strerror(err));
|
||||
return NULL;
|
||||
if ((err = getaddrinfo(str, NULL, &hints, &res)) != 0) {
|
||||
syntax_err("cannot resolve '%s' to an %s address: %s",
|
||||
str, family == AF_INET6 ? "IPv6" : "IPv4",
|
||||
gai_strerror(err));
|
||||
return NULL;
|
||||
} else
|
||||
return res;
|
||||
}
|
||||
@@ -617,10 +624,10 @@ get_addrinfo(struct ipset_session *session,
|
||||
struct addrinfo **info,
|
||||
uint8_t family)
|
||||
{
|
||||
struct addrinfo *i;
|
||||
struct addrinfo *i;
|
||||
size_t addrlen = family == AF_INET ? sizeof(struct sockaddr_in)
|
||||
: sizeof(struct sockaddr_in6);
|
||||
int found, err = 0;
|
||||
int found, err = 0;
|
||||
|
||||
if ((*info = call_getaddrinfo(session, str, family)) == NULL) {
|
||||
syntax_err("cannot parse %s: resolving to %s address failed",
|
||||
@@ -633,13 +640,21 @@ get_addrinfo(struct ipset_session *session,
|
||||
continue;
|
||||
if (found == 0) {
|
||||
if (family == AF_INET) {
|
||||
/* Workaround: direct cast increases required alignment on Sparc */
|
||||
const struct sockaddr_in *saddr = (void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session, opt, &saddr->sin_addr);
|
||||
/* Workaround: direct cast increases
|
||||
* required alignment on Sparc
|
||||
*/
|
||||
const struct sockaddr_in *saddr =
|
||||
(void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session,
|
||||
opt, &saddr->sin_addr);
|
||||
} else {
|
||||
/* Workaround: direct cast increases required alignment on Sparc */
|
||||
const struct sockaddr_in6 *saddr = (void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session, opt, &saddr->sin6_addr);
|
||||
/* Workaround: direct cast increases
|
||||
* required alignment on Sparc
|
||||
*/
|
||||
const struct sockaddr_in6 *saddr =
|
||||
(void *)i->ai_addr;
|
||||
err = ipset_session_data_set(session,
|
||||
opt, &saddr->sin6_addr);
|
||||
}
|
||||
} else if (found == 1) {
|
||||
ipset_warn(session,
|
||||
@@ -662,13 +677,20 @@ parse_ipaddr(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str,
|
||||
uint8_t family)
|
||||
{
|
||||
uint8_t m = family == AF_INET ? 32 : 128;
|
||||
int aerr = EINVAL, err = 0, range = 0;
|
||||
char *saved = strdup(str);
|
||||
char *a, *tmp = saved;
|
||||
struct addrinfo *info;
|
||||
enum ipset_opt copt = opt == IPSET_OPT_IP ? IPSET_OPT_CIDR
|
||||
: IPSET_OPT_CIDR2;
|
||||
uint8_t m = family == AF_INET ? 32 : 128;
|
||||
int aerr = EINVAL, err = 0, range = 0;
|
||||
char *saved = strdup(str);
|
||||
char *a, *tmp = saved;
|
||||
struct addrinfo *info;
|
||||
enum ipset_opt copt, opt2;
|
||||
|
||||
if (opt == IPSET_OPT_IP) {
|
||||
copt = IPSET_OPT_CIDR;
|
||||
opt2 = IPSET_OPT_IP_TO;
|
||||
} else {
|
||||
copt = IPSET_OPT_CIDR2;
|
||||
opt2 = IPSET_OPT_IP2_TO;
|
||||
}
|
||||
|
||||
if (tmp == NULL)
|
||||
return ipset_err(session,
|
||||
@@ -678,8 +700,8 @@ parse_ipaddr(struct ipset_session *session,
|
||||
/* IP/mask */
|
||||
*a++ = '\0';
|
||||
|
||||
if ((err = string_to_cidr(session, a, 0, m, &m)) != 0
|
||||
|| (err = ipset_session_data_set(session, copt, &m)) != 0)
|
||||
if ((err = string_to_cidr(session, a, 0, m, &m)) != 0 ||
|
||||
(err = ipset_session_data_set(session, copt, &m)) != 0)
|
||||
goto out;
|
||||
} else if ((a = range_separator(tmp)) != NULL) {
|
||||
/* IP-IP */
|
||||
@@ -687,11 +709,11 @@ parse_ipaddr(struct ipset_session *session,
|
||||
D("range %s", a);
|
||||
range++;
|
||||
}
|
||||
if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0
|
||||
|| !range)
|
||||
if ((aerr = get_addrinfo(session, opt, tmp, &info, family)) != 0 ||
|
||||
!range)
|
||||
goto out;
|
||||
freeaddrinfo(info);
|
||||
aerr = get_addrinfo(session, IPSET_OPT_IP_TO, a, &info, family);
|
||||
aerr = get_addrinfo(session, opt2, a, &info, family);
|
||||
|
||||
out:
|
||||
if (aerr != EINVAL)
|
||||
@@ -701,7 +723,7 @@ out:
|
||||
err = -1;
|
||||
free(saved);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
enum ipaddr_type {
|
||||
IPADDR_ANY,
|
||||
@@ -714,7 +736,7 @@ static inline bool
|
||||
cidr_hostaddr(const char *str, uint8_t family)
|
||||
{
|
||||
char *a = cidr_separator(str);
|
||||
|
||||
|
||||
return family == AF_INET ? STREQ(a, "/32") : STREQ(a, "/128");
|
||||
}
|
||||
|
||||
@@ -732,10 +754,10 @@ parse_ip(struct ipset_session *session,
|
||||
|
||||
switch (addrtype) {
|
||||
case IPADDR_PLAIN:
|
||||
if (range_separator(str)
|
||||
|| (cidr_separator(str) && !cidr_hostaddr(str, family)))
|
||||
return syntax_err("plain IP address must be supplied: %s",
|
||||
str);
|
||||
if (range_separator(str) ||
|
||||
(cidr_separator(str) && !cidr_hostaddr(str, family)))
|
||||
return syntax_err("plain IP address must be supplied: "
|
||||
"%s", str);
|
||||
break;
|
||||
case IPADDR_NET:
|
||||
if (!cidr_separator(str) || range_separator(str))
|
||||
@@ -788,7 +810,7 @@ ipset_parse_ip(struct ipset_session *session,
|
||||
* @opt: option kind of the data
|
||||
* @str: string to parse
|
||||
*
|
||||
* Parse string as an IPv4|IPv6 address or hostname. If family
|
||||
* Parse string as an IPv4|IPv6 address or hostname. If family
|
||||
* is not set yet in the data blob, INET is assumed.
|
||||
* The value is stored in the data blob of the session.
|
||||
*
|
||||
@@ -799,9 +821,9 @@ ipset_parse_single_ip(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
{
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_IP
|
||||
|| opt == IPSET_OPT_IP_TO
|
||||
|| opt == IPSET_OPT_IP2);
|
||||
assert(opt == IPSET_OPT_IP ||
|
||||
opt == IPSET_OPT_IP_TO ||
|
||||
opt == IPSET_OPT_IP2);
|
||||
assert(str);
|
||||
|
||||
return parse_ip(session, opt, str, IPADDR_PLAIN);
|
||||
@@ -813,7 +835,7 @@ ipset_parse_single_ip(struct ipset_session *session,
|
||||
* @opt: option kind of the data
|
||||
* @str: string to parse
|
||||
*
|
||||
* Parse string as an IPv4|IPv6 address/cidr pattern. If family
|
||||
* Parse string as an IPv4|IPv6 address/cidr pattern. If family
|
||||
* is not set yet in the data blob, INET is assumed.
|
||||
* The value is stored in the data blob of the session.
|
||||
*
|
||||
@@ -875,8 +897,8 @@ ipset_parse_netrange(struct ipset_session *session,
|
||||
assert(str);
|
||||
|
||||
if (!(range_separator(str) || cidr_separator(str)))
|
||||
return syntax_err("IP/cidr or IP-IP range must be specified: %s",
|
||||
str);
|
||||
return syntax_err("IP/cidr or IP-IP range must be specified: "
|
||||
"%s", str);
|
||||
return parse_ip(session, opt, str, IPADDR_ANY);
|
||||
}
|
||||
|
||||
@@ -902,8 +924,8 @@ ipset_parse_iprange(struct ipset_session *session,
|
||||
assert(str);
|
||||
|
||||
if (cidr_separator(str))
|
||||
return syntax_err("IP address or IP-IP range must be specified: %s",
|
||||
str);
|
||||
return syntax_err("IP address or IP-IP range must be "
|
||||
"specified: %s", str);
|
||||
return parse_ip(session, opt, str, IPADDR_ANY);
|
||||
}
|
||||
|
||||
@@ -959,20 +981,60 @@ ipset_parse_ip4_single6(struct ipset_session *session,
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
||||
assert(str);
|
||||
|
||||
|
||||
data = ipset_session_data(session);
|
||||
family = ipset_data_family(data);
|
||||
|
||||
|
||||
if (family == AF_UNSPEC) {
|
||||
family = AF_INET;
|
||||
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
|
||||
}
|
||||
|
||||
|
||||
return family == AF_INET ? ipset_parse_ip(session, opt, str)
|
||||
: ipset_parse_single_ip(session, opt, str);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_parse_ip4_net6 - parse IPv4|IPv6 address or address/cidr pattern
|
||||
* @session: session structure
|
||||
* @opt: option kind of the data
|
||||
* @str: string to parse
|
||||
*
|
||||
* Parse string as an IPv4|IPv6 address or address/cidr pattern. For IPv4,
|
||||
* address range is valid too.
|
||||
* If family is not set yet in the data blob, INET is assumed.
|
||||
* The values are stored in the data blob of the session.
|
||||
*
|
||||
* FIXME: if the hostname resolves to multiple addresses,
|
||||
* the first one is used only.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_parse_ip4_net6(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
{
|
||||
struct ipset_data *data;
|
||||
uint8_t family;
|
||||
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_IP || opt == IPSET_OPT_IP2);
|
||||
assert(str);
|
||||
|
||||
data = ipset_session_data(session);
|
||||
family = ipset_data_family(data);
|
||||
|
||||
if (family == AF_UNSPEC) {
|
||||
family = AF_INET;
|
||||
ipset_data_set(data, IPSET_OPT_FAMILY, &family);
|
||||
}
|
||||
|
||||
return family == AF_INET ? parse_ip(session, opt, str, IPADDR_ANY)
|
||||
: ipset_parse_ipnet(session, opt, str);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout
|
||||
* @session: session structure
|
||||
@@ -1002,8 +1064,8 @@ ipset_parse_iptimeout(struct ipset_session *session,
|
||||
if (ipset_data_flags_test(ipset_session_data(session),
|
||||
IPSET_FLAG(IPSET_OPT_TIMEOUT)))
|
||||
return syntax_err("mixed syntax, timeout already specified");
|
||||
|
||||
tmp = saved = strdup(str);
|
||||
|
||||
tmp = saved = strdup(str);
|
||||
if (saved == NULL)
|
||||
return ipset_err(session,
|
||||
"Cannot allocate memory to duplicate %s.",
|
||||
@@ -1025,12 +1087,12 @@ ipset_parse_iptimeout(struct ipset_session *session,
|
||||
|
||||
#define check_setname(str, saved) \
|
||||
do { \
|
||||
if (strlen(str) > IPSET_MAXNAMELEN - 1) { \
|
||||
if (saved != NULL) \
|
||||
free(saved); \
|
||||
return syntax_err("setname '%s' is longer than %u characters", \
|
||||
str, IPSET_MAXNAMELEN - 1); \
|
||||
} \
|
||||
if (strlen(str) > IPSET_MAXNAMELEN - 1) { \
|
||||
if (saved != NULL) \
|
||||
free(saved); \
|
||||
return syntax_err("setname '%s' is longer than %u characters",\
|
||||
str, IPSET_MAXNAMELEN - 1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -1065,7 +1127,7 @@ ipset_parse_name_compat(struct ipset_session *session,
|
||||
if (ipset_data_flags_test(data, IPSET_FLAG(IPSET_OPT_NAMEREF)))
|
||||
syntax_err("mixed syntax, before|after option already used");
|
||||
|
||||
tmp = saved = strdup(str);
|
||||
tmp = saved = strdup(str);
|
||||
if (saved == NULL)
|
||||
return ipset_err(session,
|
||||
"Cannot allocate memory to duplicate %s.",
|
||||
@@ -1075,8 +1137,8 @@ ipset_parse_name_compat(struct ipset_session *session,
|
||||
*a++ = '\0';
|
||||
if ((b = elem_separator(a)) != NULL)
|
||||
*b++ = '\0';
|
||||
if (b == NULL
|
||||
|| !(STREQ(a, "before") || STREQ(a, "after"))) {
|
||||
if (b == NULL ||
|
||||
!(STREQ(a, "before") || STREQ(a, "after"))) {
|
||||
err = ipset_err(session, "you must specify elements "
|
||||
"as setname%s[before|after]%ssetname",
|
||||
sep, sep);
|
||||
@@ -1117,9 +1179,9 @@ ipset_parse_setname(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
{
|
||||
assert(session);
|
||||
assert(opt == IPSET_SETNAME
|
||||
|| opt == IPSET_OPT_NAME
|
||||
|| opt == IPSET_OPT_SETNAME2);
|
||||
assert(opt == IPSET_SETNAME ||
|
||||
opt == IPSET_OPT_NAME ||
|
||||
opt == IPSET_OPT_SETNAME2);
|
||||
assert(str);
|
||||
|
||||
check_setname(str, NULL);
|
||||
@@ -1205,13 +1267,13 @@ ipset_parse_uint32(struct ipset_session *session,
|
||||
{
|
||||
uint32_t value;
|
||||
int err;
|
||||
|
||||
|
||||
assert(session);
|
||||
assert(str);
|
||||
|
||||
if ((err = string_to_u32(session, str, &value)) == 0)
|
||||
return ipset_session_data_set(session, opt, &value);
|
||||
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1232,7 +1294,7 @@ ipset_parse_uint8(struct ipset_session *session,
|
||||
{
|
||||
uint8_t value;
|
||||
int err;
|
||||
|
||||
|
||||
assert(session);
|
||||
assert(str);
|
||||
|
||||
@@ -1261,7 +1323,7 @@ ipset_parse_netmask(struct ipset_session *session,
|
||||
uint8_t family, cidr;
|
||||
struct ipset_data *data;
|
||||
int err = 0;
|
||||
|
||||
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_NETMASK);
|
||||
assert(str);
|
||||
@@ -1274,7 +1336,7 @@ ipset_parse_netmask(struct ipset_session *session,
|
||||
}
|
||||
|
||||
err = string_to_cidr(session, str,
|
||||
family == AF_INET ? 1 : 4,
|
||||
family == AF_INET ? 1 : 4,
|
||||
family == AF_INET ? 31 : 124,
|
||||
&cidr);
|
||||
|
||||
@@ -1303,7 +1365,7 @@ ipset_parse_flag(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str UNUSED)
|
||||
{
|
||||
assert(session);
|
||||
|
||||
|
||||
return ipset_session_data_set(session, opt, NULL);
|
||||
}
|
||||
|
||||
@@ -1343,10 +1405,45 @@ ipset_parse_typename(struct ipset_session *session,
|
||||
|
||||
if (type == NULL)
|
||||
return -1;
|
||||
|
||||
|
||||
return ipset_session_data_set(session, IPSET_OPT_TYPE, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_parse_iface - parse string as an interface name
|
||||
* @session: session structure
|
||||
* @opt: option kind of the data
|
||||
* @str: string to parse
|
||||
*
|
||||
* Parse string as an interface name, optionally with 'physdev:' prefix.
|
||||
* The value is stored in the data blob of the session.
|
||||
*
|
||||
* Returns 0 on success or a negative error code.
|
||||
*/
|
||||
int
|
||||
ipset_parse_iface(struct ipset_session *session,
|
||||
enum ipset_opt opt, const char *str)
|
||||
{
|
||||
struct ipset_data *data;
|
||||
int offset = 0, err = 0;
|
||||
|
||||
assert(session);
|
||||
assert(opt == IPSET_OPT_IFACE);
|
||||
assert(str);
|
||||
|
||||
data = ipset_session_data(session);
|
||||
if (STREQ(str, "physdev:")) {
|
||||
offset = 8;
|
||||
err = ipset_data_set(data, IPSET_OPT_PHYSDEV, str);
|
||||
}
|
||||
if (strlen(str + offset) > IFNAMSIZ - 1)
|
||||
return syntax_err("interface name '%s' is longer "
|
||||
"than %u characters",
|
||||
str + offset, IFNAMSIZ - 1);
|
||||
|
||||
return ipset_data_set(data, opt, str + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* ipset_parse_output - parse output format name
|
||||
* @session: session structure
|
||||
@@ -1395,7 +1492,8 @@ ipset_parse_ignored(struct ipset_session *session,
|
||||
|
||||
if (!ipset_data_ignored(ipset_session_data(session), opt))
|
||||
ipset_warn(session,
|
||||
"Option %s is ignored. Please upgrade your syntax.", str);
|
||||
"Option %s is ignored. "
|
||||
"Please upgrade your syntax.", str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1426,7 +1524,7 @@ ipset_call_parser(struct ipset_session *session,
|
||||
}
|
||||
|
||||
#define parse_elem(s, t, d, str) \
|
||||
do { \
|
||||
do { \
|
||||
if (!(t)->elem[d].parse) \
|
||||
goto internal; \
|
||||
ret = (t)->elem[d].parse(s, (t)->elem[d].opt, str); \
|
||||
@@ -1484,8 +1582,8 @@ ipset_parse_elem(struct ipset_session *session,
|
||||
} else if (a != NULL) {
|
||||
if (type->compat_parse_elem) {
|
||||
ret = type->compat_parse_elem(session,
|
||||
type->elem[IPSET_DIM_ONE].opt,
|
||||
saved);
|
||||
type->elem[IPSET_DIM_ONE].opt,
|
||||
saved);
|
||||
goto out;
|
||||
}
|
||||
elem_syntax_err("Elem separator in %s, "
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -12,6 +12,7 @@
|
||||
#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_* */
|
||||
@@ -53,15 +54,15 @@ ipset_print_ether(char *buf, unsigned int len,
|
||||
{
|
||||
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);
|
||||
|
||||
@@ -71,7 +72,7 @@ ipset_print_ether(char *buf, unsigned int len,
|
||||
size = snprintf(buf + offset, len, ":%02X", ether[i]);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -138,35 +139,60 @@ ipset_print_type(char *buf, unsigned int len,
|
||||
assert(type);
|
||||
if (len < strlen(type->name) + 1)
|
||||
return -1;
|
||||
|
||||
|
||||
return snprintf(buf, len, "%s", type->name);
|
||||
}
|
||||
|
||||
#define GETNAMEINFO(family, f, n) \
|
||||
static inline int \
|
||||
__getnameinfo##f(char *buf, unsigned int len, \
|
||||
int flags, const union nf_inet_addr *addr) \
|
||||
{ \
|
||||
struct sockaddr_in##n saddr; \
|
||||
int err; \
|
||||
\
|
||||
memset(&saddr, 0, sizeof(saddr)); \
|
||||
in##f##cpy(&saddr.sin##n##_addr, &addr->in##n); \
|
||||
saddr.sin##n##_family = family; \
|
||||
\
|
||||
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
|
||||
__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 = AF_INET;
|
||||
|
||||
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 = AF_INET6;
|
||||
|
||||
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) \
|
||||
@@ -189,10 +215,8 @@ snprintf_ipv##f(char *buf, unsigned int len, int flags, \
|
||||
return offset; \
|
||||
}
|
||||
|
||||
GETNAMEINFO(AF_INET, 4, )
|
||||
SNPRINTF_IP(32, 4)
|
||||
|
||||
GETNAMEINFO(AF_INET6, 6, 6)
|
||||
SNPRINTF_IP(128, 6)
|
||||
|
||||
/**
|
||||
@@ -231,7 +255,7 @@ ipset_print_ip(char *buf, unsigned int len,
|
||||
} else
|
||||
cidr = family == AF_INET6 ? 128 : 32;
|
||||
flags = (env & IPSET_ENV_RESOLVE) ? 0 : NI_NUMERICHOST;
|
||||
|
||||
|
||||
ip = ipset_data_get(data, opt);
|
||||
assert(ip);
|
||||
if (family == AF_INET)
|
||||
@@ -257,8 +281,8 @@ ipset_print_ip(char *buf, unsigned int len,
|
||||
size = snprintf_ipv6(buf + offset, len, flags, ip, cidr);
|
||||
else
|
||||
return -1;
|
||||
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
@@ -287,9 +311,9 @@ ipset_print_ipaddr(char *buf, unsigned int len,
|
||||
assert(buf);
|
||||
assert(len > 0);
|
||||
assert(data);
|
||||
assert(opt == IPSET_OPT_IP
|
||||
|| opt == IPSET_OPT_IP_TO
|
||||
|| opt == IPSET_OPT_IP2);
|
||||
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;
|
||||
@@ -332,7 +356,7 @@ ipset_print_number(char *buf, unsigned int len,
|
||||
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);
|
||||
@@ -379,7 +403,7 @@ ipset_print_name(char *buf, unsigned int len,
|
||||
name = ipset_data_get(data, opt);
|
||||
assert(name);
|
||||
size = snprintf(buf, len, "%s", name);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
if (ipset_data_test(data, IPSET_OPT_NAMEREF)) {
|
||||
bool before = false;
|
||||
@@ -389,10 +413,10 @@ ipset_print_name(char *buf, unsigned int len,
|
||||
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);
|
||||
" %s %s", before ? "before" : "after",
|
||||
(const char *) ipset_data_get(data,
|
||||
IPSET_OPT_NAMEREF));
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
@@ -430,19 +454,58 @@ ipset_print_port(char *buf, unsigned int len,
|
||||
port = ipset_data_get(data, IPSET_OPT_PORT);
|
||||
assert(port);
|
||||
size = snprintf(buf, len, "%u", *port);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
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);
|
||||
"%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
|
||||
@@ -471,12 +534,12 @@ ipset_print_proto(char *buf, unsigned int len,
|
||||
|
||||
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 */
|
||||
/* Should not happen */
|
||||
return snprintf(buf, len, "%u", proto);
|
||||
}
|
||||
|
||||
@@ -511,7 +574,8 @@ ipset_print_icmp(char *buf, unsigned int len,
|
||||
if (name != NULL)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
else
|
||||
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF);
|
||||
return snprintf(buf, len, "%u/%u",
|
||||
typecode >> 8, typecode & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,7 +609,8 @@ ipset_print_icmpv6(char *buf, unsigned int len,
|
||||
if (name != NULL)
|
||||
return snprintf(buf, len, "%s", name);
|
||||
else
|
||||
return snprintf(buf, len, "%u/%u", typecode >> 8, typecode & 0xFF);
|
||||
return snprintf(buf, len, "%u/%u",
|
||||
typecode >> 8, typecode & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -574,8 +639,8 @@ ipset_print_proto_port(char *buf, unsigned int len,
|
||||
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);
|
||||
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)
|
||||
@@ -601,16 +666,16 @@ ipset_print_proto_port(char *buf, unsigned int len,
|
||||
}
|
||||
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))
|
||||
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_data_flags_test(data, IPSET_FLAG(IPSET_OPT_IP2))
|
||||
|
||||
/**
|
||||
* ipset_print_elem - print ADT elem according to settype
|
||||
@@ -639,25 +704,25 @@ ipset_print_elem(char *buf, unsigned int len,
|
||||
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
if (!type)
|
||||
return -1;
|
||||
|
||||
|
||||
size = type->elem[IPSET_DIM_ONE].print(buf, len, data,
|
||||
type->elem[IPSET_DIM_ONE].opt, env);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
IF_D(ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt),
|
||||
"print second elem");
|
||||
if (type->dimension == IPSET_DIM_ONE
|
||||
|| (type->last_elem_optional
|
||||
&& !ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
|
||||
if (type->dimension == IPSET_DIM_ONE ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_TWO].opt)))
|
||||
return offset;
|
||||
|
||||
|
||||
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
size = type->elem[IPSET_DIM_TWO].print(buf + offset, len, data,
|
||||
type->elem[IPSET_DIM_TWO].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].opt)))
|
||||
if (type->dimension == IPSET_DIM_TWO ||
|
||||
(type->last_elem_optional &&
|
||||
!ipset_data_test(data, type->elem[IPSET_DIM_THREE].opt)))
|
||||
return offset;
|
||||
|
||||
size = snprintf(buf + offset, len, IPSET_ELEM_SEPARATOR);
|
||||
@@ -685,7 +750,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -731,6 +796,9 @@ ipset_print_data(char *buf, unsigned int len,
|
||||
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:
|
||||
@@ -747,6 +815,6 @@ ipset_print_data(char *buf, unsigned int len,
|
||||
return -1;
|
||||
}
|
||||
SNPRINTF_FAILURE(size, len, offset);
|
||||
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <string.h> /* str* */
|
||||
#include <unistd.h> /* getpagesize */
|
||||
#include <net/ethernet.h> /* ETH_ALEN */
|
||||
#include <net/if.h> /* IFNAMSIZ */
|
||||
|
||||
#include <libipset/debug.h> /* D() */
|
||||
#include <libipset/data.h> /* IPSET_OPT_* */
|
||||
@@ -37,6 +38,7 @@ struct ipset_session {
|
||||
/* Command state */
|
||||
enum ipset_cmd cmd; /* Current command */
|
||||
uint32_t lineno; /* Current lineno in restore mode */
|
||||
uint32_t printed_set; /* Printed sets so far */
|
||||
char saved_setname[IPSET_MAXNAMELEN]; /* Saved setname */
|
||||
const struct ipset_type *saved_type; /* Saved type */
|
||||
struct nlattr *nested[IPSET_NEST_MAX]; /* Pointer to nest levels */
|
||||
@@ -138,6 +140,8 @@ ipset_envopt_parse(struct ipset_session *session, int opt,
|
||||
case IPSET_ENV_QUIET:
|
||||
case IPSET_ENV_RESOLVE:
|
||||
case IPSET_ENV_EXIST:
|
||||
case IPSET_ENV_LIST_SETNAME:
|
||||
case IPSET_ENV_LIST_HEADER:
|
||||
session->envopts |= opt;
|
||||
return 0;
|
||||
default:
|
||||
@@ -196,14 +200,14 @@ ipset_session_output(struct ipset_session *session,
|
||||
*
|
||||
* Returns -1.
|
||||
*/
|
||||
int __attribute__((format(printf,3,4)))
|
||||
int __attribute__((format(printf, 3, 4)))
|
||||
ipset_session_report(struct ipset_session *session,
|
||||
enum ipset_err_type type,
|
||||
enum ipset_err_type type,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int len, offset = 0;
|
||||
va_list args;
|
||||
|
||||
|
||||
assert(session);
|
||||
assert(fmt);
|
||||
|
||||
@@ -212,13 +216,13 @@ ipset_session_report(struct ipset_session *session,
|
||||
session->lineno);
|
||||
}
|
||||
offset = strlen(session->report);
|
||||
|
||||
|
||||
va_start(args, fmt);
|
||||
len = vsnprintf(session->report + offset,
|
||||
IPSET_ERRORBUFLEN - 1 - offset,
|
||||
fmt, args);
|
||||
IPSET_ERRORBUFLEN - 1 - offset,
|
||||
fmt, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
if (len >= IPSET_ERRORBUFLEN - 1 - offset)
|
||||
session->report[IPSET_ERRORBUFLEN - 1] = '\0';
|
||||
if (strlen(session->report) < IPSET_ERRORBUFLEN - 1)
|
||||
@@ -468,6 +472,15 @@ static const struct ipset_attr_policy adt_attrs[] = {
|
||||
.type = MNL_TYPE_U8,
|
||||
.opt = IPSET_OPT_CIDR2,
|
||||
},
|
||||
[IPSET_ATTR_IP2_TO] = {
|
||||
.type = MNL_TYPE_NESTED,
|
||||
.opt = IPSET_OPT_IP2_TO,
|
||||
},
|
||||
[IPSET_ATTR_IFACE] = {
|
||||
.type = MNL_TYPE_NUL_STRING,
|
||||
.opt = IPSET_OPT_IFACE,
|
||||
.len = IFNAMSIZ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ipset_attr_policy ipaddr_attrs[] = {
|
||||
@@ -480,26 +493,30 @@ static const struct ipset_attr_policy ipaddr_attrs[] = {
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef IPSET_DEBUG
|
||||
static int debug = 1;
|
||||
#endif
|
||||
|
||||
static int
|
||||
generic_data_attr_cb(const struct nlattr *attr, void *data,
|
||||
int attr_max, const struct ipset_attr_policy *policy)
|
||||
{
|
||||
const struct nlattr **tb = data;
|
||||
int type = mnl_attr_get_type(attr);
|
||||
|
||||
D("attr type: %u, len %u", type, attr->nla_len);
|
||||
|
||||
IF_D(debug, "attr type: %u, len %u", type, attr->nla_len);
|
||||
if (mnl_attr_type_valid(attr, attr_max) < 0) {
|
||||
D("attr type: %u INVALID", type);
|
||||
IF_D(debug, "attr type: %u INVALID", type);
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
if (mnl_attr_validate(attr, policy[type].type) < 0) {
|
||||
D("attr type: %u POLICY, attrlen %u", type,
|
||||
mnl_attr_get_payload_len(attr));
|
||||
IF_D(debug, "attr type: %u POLICY, attrlen %u", type,
|
||||
mnl_attr_get_payload_len(attr));
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
if (policy[type].type == MNL_TYPE_NUL_STRING
|
||||
&& mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
|
||||
return MNL_CB_ERROR;
|
||||
if (policy[type].type == MNL_TYPE_NUL_STRING &&
|
||||
mnl_attr_get_payload_len(attr) > IPSET_MAXNAMELEN)
|
||||
return MNL_CB_ERROR;
|
||||
tb[type] = attr;
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
@@ -583,7 +600,7 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
|
||||
switch (attr->type) {
|
||||
case MNL_TYPE_U32: {
|
||||
uint32_t value;
|
||||
|
||||
|
||||
value = ntohl(*(const uint32_t *)d);
|
||||
|
||||
d = &value;
|
||||
@@ -591,7 +608,7 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
|
||||
}
|
||||
case MNL_TYPE_U16: {
|
||||
uint16_t value;
|
||||
|
||||
|
||||
value = ntohs(*(const uint16_t *)d);
|
||||
|
||||
d = &value;
|
||||
@@ -602,15 +619,15 @@ attr2data(struct ipset_session *session, struct nlattr *nla[],
|
||||
}
|
||||
}
|
||||
#ifdef IPSET_DEBUG
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
D("nla typename %s", (const char *) d);
|
||||
#endif
|
||||
ret = ipset_data_set(data, attr->opt, d);
|
||||
#ifdef IPSET_DEBUG
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
if (type == IPSET_ATTR_TYPENAME)
|
||||
D("nla typename %s",
|
||||
(const char *) ipset_data_get(data, IPSET_OPT_TYPENAME));
|
||||
#endif
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -639,16 +656,16 @@ static inline int
|
||||
call_outfn(struct ipset_session *session)
|
||||
{
|
||||
int ret = session->outfn("%s", session->outbuf);
|
||||
|
||||
|
||||
session->outbuf[0] = '\0';
|
||||
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
/* Handle printing failures */
|
||||
static jmp_buf printf_failure;
|
||||
|
||||
static int __attribute__((format(printf,2,3)))
|
||||
static int __attribute__((format(printf, 2, 3)))
|
||||
safe_snprintf(struct ipset_session *session, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
@@ -661,7 +678,7 @@ retry:
|
||||
ret = vsnprintf(session->outbuf + len, IPSET_OUTBUFLEN - len,
|
||||
fmt, args);
|
||||
va_end(args);
|
||||
|
||||
|
||||
if (ret < 0) {
|
||||
ipset_err(session,
|
||||
"Internal error at printing to output buffer");
|
||||
@@ -695,7 +712,7 @@ retry:
|
||||
D("len: %u, retry %u", len, loop);
|
||||
ret = fn(session->outbuf + len, IPSET_OUTBUFLEN - len,
|
||||
session->data, opt, session->envopts);
|
||||
|
||||
|
||||
if (ret < 0) {
|
||||
ipset_err(session,
|
||||
"Internal error at printing to output buffer");
|
||||
@@ -717,7 +734,7 @@ retry:
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
@@ -727,7 +744,7 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
uint8_t family;
|
||||
int i, found = 0;
|
||||
|
||||
D("enter");
|
||||
D("enter");
|
||||
/* Check and load type, family */
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
type = ipset_type_get(session, IPSET_CMD_ADD);
|
||||
@@ -758,7 +775,7 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
safe_dprintf(session, ipset_print_elem, IPSET_OPT_ELEM);
|
||||
|
||||
for (arg = type->args[IPSET_ADD]; arg != NULL && arg->print; arg++) {
|
||||
@@ -789,7 +806,7 @@ list_adt(struct ipset_session *session, struct nlattr *nla[])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (session->mode == IPSET_LIST_XML)
|
||||
safe_snprintf(session, "</member>\n");
|
||||
else
|
||||
@@ -829,8 +846,9 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
|
||||
type->name);
|
||||
break;
|
||||
case IPSET_LIST_PLAIN:
|
||||
safe_snprintf(session, "Name: %s\n"
|
||||
safe_snprintf(session, "%sName: %s\n"
|
||||
"Type: %s\nHeader: ",
|
||||
session->printed_set ? "\n" : "",
|
||||
ipset_data_setname(data),
|
||||
type->name);
|
||||
break;
|
||||
@@ -847,10 +865,10 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
|
||||
}
|
||||
|
||||
for (arg = type->args[IPSET_CREATE]; arg != NULL && arg->opt; arg++) {
|
||||
if (!arg->print
|
||||
|| !ipset_data_test(data, arg->opt)
|
||||
|| (arg->opt == IPSET_OPT_FAMILY
|
||||
&& family == type->family))
|
||||
if (!arg->print ||
|
||||
!ipset_data_test(data, arg->opt) ||
|
||||
(arg->opt == IPSET_OPT_FAMILY &&
|
||||
family == type->family))
|
||||
continue;
|
||||
switch (session->mode) {
|
||||
case IPSET_LIST_SAVE:
|
||||
@@ -887,18 +905,24 @@ list_create(struct ipset_session *session, struct nlattr *nla[])
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
|
||||
safe_snprintf(session, "\nReferences: ");
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
|
||||
safe_snprintf(session, "\nMembers:\n");
|
||||
safe_snprintf(session,
|
||||
session->envopts & IPSET_ENV_LIST_HEADER ?
|
||||
"\n" : "\nMembers:\n");
|
||||
break;
|
||||
case IPSET_LIST_XML:
|
||||
safe_snprintf(session, "</elements>\n <memsize>");
|
||||
safe_snprintf(session, " <memsize>");
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_MEMSIZE);
|
||||
safe_snprintf(session, "</memsize>\n <references>");
|
||||
safe_dprintf(session, ipset_print_number, IPSET_OPT_REFERENCES);
|
||||
safe_snprintf(session, "</references>\n </header>\n <members>\n");
|
||||
safe_snprintf(session,
|
||||
session->envopts & IPSET_ENV_LIST_HEADER ?
|
||||
"</references>\n </header>\n" :
|
||||
"</references>\n </header>\n <members>\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
session->printed_set++;
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
@@ -910,16 +934,17 @@ print_set_done(struct ipset_session *session)
|
||||
? "NONE" : session->saved_setname);
|
||||
switch (session->mode) {
|
||||
case IPSET_LIST_XML:
|
||||
if (session->saved_setname[0] == '\0')
|
||||
safe_snprintf(session, "\n");
|
||||
else
|
||||
if (session->envopts & IPSET_ENV_LIST_SETNAME)
|
||||
break;
|
||||
if (session->envopts & IPSET_ENV_LIST_HEADER) {
|
||||
if (session->saved_setname[0] != '\0')
|
||||
safe_snprintf(session, "</ipset>\n");
|
||||
break;
|
||||
}
|
||||
if (session->saved_setname[0] != '\0')
|
||||
safe_snprintf(session, " </members>\n</ipset>\n");
|
||||
break;
|
||||
case IPSET_LIST_SAVE:
|
||||
/* No empty lines between the sets */
|
||||
break;
|
||||
default:
|
||||
safe_snprintf(session, "\n");
|
||||
break;
|
||||
}
|
||||
return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_STOP;
|
||||
@@ -931,8 +956,11 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
{
|
||||
struct ipset_data *data = session->data;
|
||||
|
||||
if (setjmp(printf_failure))
|
||||
if (setjmp(printf_failure)) {
|
||||
session->saved_setname[0] = '\0';
|
||||
session->printed_set = 0;
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
if (!nla[IPSET_ATTR_SETNAME])
|
||||
FAILURE("Broken %s kernel message: missing setname!",
|
||||
@@ -940,17 +968,28 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_SETNAME, cmd_attrs);
|
||||
D("setname %s", ipset_data_setname(data));
|
||||
if (session->envopts & IPSET_ENV_LIST_SETNAME &&
|
||||
session->mode != IPSET_LIST_SAVE) {
|
||||
if (session->mode == IPSET_LIST_XML)
|
||||
safe_snprintf(session, "<ipset name=\"%s\"/>\n",
|
||||
ipset_data_setname(data));
|
||||
else
|
||||
safe_snprintf(session, "%s\n",
|
||||
ipset_data_setname(data));
|
||||
return call_outfn(session) ? MNL_CB_ERROR : MNL_CB_OK;
|
||||
}
|
||||
|
||||
if (STREQ(ipset_data_setname(data), session->saved_setname)) {
|
||||
/* Header part already seen */
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE)
|
||||
&& nla[IPSET_ATTR_DATA] != NULL)
|
||||
if (ipset_data_test(data, IPSET_OPT_TYPE) &&
|
||||
nla[IPSET_ATTR_DATA] != NULL)
|
||||
FAILURE("Broken %s kernel message: "
|
||||
"extra DATA received!", cmd2name[cmd]);
|
||||
} else {
|
||||
if (nla[IPSET_ATTR_DATA] == NULL)
|
||||
FAILURE("Broken %s kernel message: "
|
||||
"missing DATA part!", cmd2name[cmd]);
|
||||
|
||||
|
||||
/* Close previous set printing */
|
||||
if (session->saved_setname[0] != '\0')
|
||||
print_set_done(session);
|
||||
@@ -959,13 +998,14 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
if (nla[IPSET_ATTR_DATA] != NULL) {
|
||||
struct nlattr *cattr[IPSET_ATTR_CREATE_MAX+1] = {};
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_FAMILY]
|
||||
&& nla[IPSET_ATTR_REVISION]))
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_FAMILY] &&
|
||||
nla[IPSET_ATTR_REVISION]))
|
||||
FAILURE("Broken %s kernel message: missing %s!",
|
||||
cmd2name[cmd],
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
!nla[IPSET_ATTR_FAMILY] ? "family" : "revision");
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
!nla[IPSET_ATTR_FAMILY] ? "family" :
|
||||
"revision");
|
||||
|
||||
/* Reset CREATE specific flags */
|
||||
ipset_data_flags_unset(data, IPSET_CREATE_FLAGS);
|
||||
@@ -988,7 +1028,7 @@ callback_list(struct ipset_session *session, struct nlattr *nla[],
|
||||
return MNL_CB_ERROR;
|
||||
strcpy(session->saved_setname, ipset_data_setname(data));
|
||||
}
|
||||
|
||||
|
||||
if (nla[IPSET_ATTR_ADT] != NULL) {
|
||||
struct nlattr *tb, *adt[IPSET_ATTR_ADT_MAX+1];
|
||||
|
||||
@@ -1020,7 +1060,7 @@ static int
|
||||
callback_version(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
uint8_t min, max;
|
||||
|
||||
|
||||
min = max = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
|
||||
|
||||
if (nla[IPSET_ATTR_PROTOCOL_MIN]) {
|
||||
@@ -1034,8 +1074,8 @@ callback_version(struct ipset_session *session, struct nlattr *nla[])
|
||||
"while userspace supports protocol versions %u-%u",
|
||||
min, max, IPSET_PROTOCOL_MIN, IPSET_PROTOCOL_MAX);
|
||||
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)
|
||||
&& max != IPSET_PROTOCOL_MAX)
|
||||
if (!(session->envopts & IPSET_ENV_QUIET) &&
|
||||
max != IPSET_PROTOCOL_MAX)
|
||||
ipset_warn(session,
|
||||
"Kernel support protocol versions %u-%u "
|
||||
"while userspace supports protocol versions %u-%u",
|
||||
@@ -1051,7 +1091,7 @@ callback_header(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
const char *setname;
|
||||
const struct ipset_data *data = session->data;
|
||||
|
||||
|
||||
if (!nla[IPSET_ATTR_SETNAME])
|
||||
FAILURE("Broken HEADER kernel message: missing setname!");
|
||||
|
||||
@@ -1060,10 +1100,10 @@ callback_header(struct ipset_session *session, struct nlattr *nla[])
|
||||
FAILURE("Broken HEADER kernel message: sent setname `%s' "
|
||||
"does not match with received one `%s'!",
|
||||
ipset_data_setname(data), setname);
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_REVISION]
|
||||
&& nla[IPSET_ATTR_FAMILY]))
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_REVISION] &&
|
||||
nla[IPSET_ATTR_FAMILY]))
|
||||
FAILURE("Broken HEADER kernel message: "
|
||||
"missing attribute '%s'!",
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
@@ -1083,10 +1123,10 @@ callback_type(struct ipset_session *session, struct nlattr *nla[])
|
||||
{
|
||||
const struct ipset_data *data = session->data;
|
||||
const char *typename, *orig;
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME]
|
||||
&& nla[IPSET_ATTR_REVISION]
|
||||
&& nla[IPSET_ATTR_FAMILY]))
|
||||
|
||||
if (!(nla[IPSET_ATTR_TYPENAME] &&
|
||||
nla[IPSET_ATTR_REVISION] &&
|
||||
nla[IPSET_ATTR_FAMILY]))
|
||||
FAILURE("Broken TYPE kernel message: "
|
||||
"missing attribute '%s'!",
|
||||
!nla[IPSET_ATTR_TYPENAME] ? "typename" :
|
||||
@@ -1099,7 +1139,7 @@ callback_type(struct ipset_session *session, struct nlattr *nla[])
|
||||
FAILURE("Broken TYPE kernel message: sent typename `%s' "
|
||||
"does not match with received one `%s'!",
|
||||
orig, typename);
|
||||
|
||||
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_TYPENAME, cmd_attrs);
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_REVISION, cmd_attrs);
|
||||
ATTR2DATA(session, nla, IPSET_ATTR_FAMILY, cmd_attrs);
|
||||
@@ -1123,7 +1163,7 @@ mnl_attr_parse_dbg(const struct nlmsghdr *nlh, int offset,
|
||||
int ret = MNL_CB_OK;
|
||||
struct nlattr *attr = mnl_nlmsg_get_payload_offset(nlh, offset);
|
||||
int len = nlh->nlmsg_len - MNL_NLMSG_HDRLEN - MNL_ALIGN(offset);
|
||||
|
||||
|
||||
while (mnl_attr_ok(attr, len)) {
|
||||
D("attr: type %u, attrlen %u, len %u",
|
||||
mnl_attr_get_type(attr), attr->nla_len, len);
|
||||
@@ -1142,7 +1182,7 @@ callback_data(const struct nlmsghdr *nlh, void *data)
|
||||
struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
|
||||
uint8_t proto, cmd;
|
||||
int ret = MNL_CB_OK, nfmsglen = MNL_ALIGN(sizeof(struct genlmsghdr));
|
||||
|
||||
|
||||
D("called, nlmsg_len %u", nlh->nlmsg_len);
|
||||
cmd = ipset_get_nlmsg_type(nlh);
|
||||
if (cmd == IPSET_CMD_LIST && session->cmd == IPSET_CMD_SAVE)
|
||||
@@ -1162,8 +1202,8 @@ callback_data(const struct nlmsghdr *nlh, void *data)
|
||||
|
||||
if (!nla[IPSET_ATTR_PROTOCOL])
|
||||
FAILURE("Sad, sad day: kernel message %s "
|
||||
"does not carry the protocol version.",
|
||||
cmd2name[cmd]);
|
||||
"does not carry the protocol version.",
|
||||
cmd2name[cmd]);
|
||||
|
||||
proto = mnl_attr_get_u8(nla[IPSET_ATTR_PROTOCOL]);
|
||||
|
||||
@@ -1208,8 +1248,8 @@ callback_done(const struct nlmsghdr *nlh UNUSED, void *data)
|
||||
|
||||
D(" called");
|
||||
if (session->cmd == IPSET_CMD_LIST || session->cmd == IPSET_CMD_SAVE)
|
||||
return print_set_done(session);
|
||||
|
||||
return print_set_done(session);
|
||||
|
||||
FAILURE("Invalid message received in non LIST or SAVE state.");
|
||||
}
|
||||
|
||||
@@ -1221,7 +1261,7 @@ decode_errmsg(struct ipset_session *session, const struct nlmsghdr *nlh)
|
||||
struct nlattr *nla[IPSET_ATTR_CMD_MAX+1] = {};
|
||||
enum ipset_cmd cmd;
|
||||
int nfmsglen = MNL_ALIGN(sizeof(struct genlmsghdr));
|
||||
|
||||
|
||||
if (nlh->nlmsg_len < (uint32_t) MNL_ALIGN(sizeof(struct nlmsgerr))
|
||||
|| nlh->nlmsg_len < MNL_ALIGN(sizeof(struct nlmsgerr))
|
||||
+ msg->nlmsg_len)
|
||||
@@ -1244,15 +1284,15 @@ decode_errmsg(struct ipset_session *session, const struct nlmsghdr *nlh)
|
||||
FAILURE("Broken %s error report message: "
|
||||
"missing protocol attribute",
|
||||
cmd2name[cmd]);
|
||||
|
||||
|
||||
if (nla[IPSET_ATTR_LINENO]) {
|
||||
session->lineno = mnl_attr_get_u32(nla[IPSET_ATTR_LINENO]);
|
||||
if (nla[IPSET_ATTR_LINENO]->nla_type & NLA_F_NET_BYTEORDER)
|
||||
session->lineno = ntohl(session->lineno);
|
||||
}
|
||||
|
||||
|
||||
return ipset_errcode(session, cmd, -err->error);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
@@ -1285,16 +1325,20 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
break;
|
||||
case IPSET_CMD_RENAME:
|
||||
ipset_cache_rename(ipset_data_setname(data),
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2));
|
||||
ipset_data_get(data,
|
||||
IPSET_OPT_SETNAME2));
|
||||
break;
|
||||
case IPSET_CMD_SWAP:
|
||||
ipset_cache_swap(ipset_data_setname(data),
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2));
|
||||
ipset_data_get(data,
|
||||
IPSET_OPT_SETNAME2));
|
||||
break;
|
||||
case IPSET_CMD_TEST:
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)) {
|
||||
ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
|
||||
session->data, IPSET_OPT_NONE, 0);
|
||||
ipset_print_elem(session->report,
|
||||
IPSET_ERRORBUFLEN,
|
||||
session->data,
|
||||
IPSET_OPT_NONE, 0);
|
||||
ipset_warn(session, " is in set %s.",
|
||||
ipset_data_setname(data));
|
||||
}
|
||||
@@ -1308,7 +1352,8 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
print_set_done(session);
|
||||
break;
|
||||
default:
|
||||
FAILURE("ACK message received to command %s[%u], which is not expected",
|
||||
FAILURE("ACK message received to command %s[%u], "
|
||||
"which is not expected",
|
||||
session->cmd < IPSET_MSG_MAX
|
||||
? cmd2name[session->cmd] : "unknown",
|
||||
session->cmd);
|
||||
@@ -1318,10 +1363,10 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
D("nlmsgerr error: %u", -err->error);
|
||||
|
||||
/* Error messages */
|
||||
|
||||
|
||||
/* Special case for IPSET_CMD_TEST */
|
||||
if (session->cmd == IPSET_CMD_TEST
|
||||
&& err->error == -IPSET_ERR_EXIST) {
|
||||
if (session->cmd == IPSET_CMD_TEST &&
|
||||
err->error == -IPSET_ERR_EXIST) {
|
||||
if (!(session->envopts & IPSET_ENV_QUIET)) {
|
||||
ipset_print_elem(session->report, IPSET_ERRORBUFLEN,
|
||||
session->data, IPSET_OPT_NONE, 0);
|
||||
@@ -1332,7 +1377,7 @@ callback_error(const struct nlmsghdr *nlh, void *cbdata)
|
||||
}
|
||||
|
||||
decode_errmsg(session, nlh);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1386,7 +1431,8 @@ attr_len(const struct ipset_attr_policy *attr, uint8_t family, uint16_t *flags)
|
||||
}
|
||||
|
||||
#define BUFFER_FULL(bufsize, nlmsg_len, nestlen, attrlen) \
|
||||
(nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize)
|
||||
(nlmsg_len + nestlen + MNL_ATTR_HDRLEN + MNL_ALIGN(alen) + \
|
||||
MNL_ALIGN(sizeof(struct nlmsgerr)) > bufsize)
|
||||
|
||||
static int
|
||||
rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
@@ -1406,14 +1452,15 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
: IPSET_ATTR_IPADDR_IPV6;
|
||||
|
||||
alen = attr_len(attr, family, &flags);
|
||||
if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len, MNL_ATTR_HDRLEN, alen))
|
||||
if (BUFFER_FULL(session->bufsize, nlh->nlmsg_len,
|
||||
MNL_ATTR_HDRLEN, alen))
|
||||
return 1;
|
||||
nested = mnl_attr_nest_start(nlh, type);
|
||||
D("family: %s", family == AF_INET ? "INET" :
|
||||
family == AF_INET6 ? "INET6" : "UNSPEC");
|
||||
mnl_attr_put(nlh, atype | flags, alen, d);
|
||||
mnl_attr_nest_end(nlh, nested);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1422,22 +1469,25 @@ rawdata2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
return 1;
|
||||
|
||||
switch (attr->type) {
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
alen = strlen((const char *)d) + 1;
|
||||
break;
|
||||
case MNL_TYPE_U32: {
|
||||
uint32_t value = htonl(*(const uint32_t *)d);
|
||||
|
||||
|
||||
d = &value;
|
||||
break;
|
||||
}
|
||||
case MNL_TYPE_U16: {
|
||||
uint16_t value = htons(*(const uint16_t *)d);
|
||||
|
||||
|
||||
d = &value;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
mnl_attr_put(nlh, type | flags, alen, d);
|
||||
|
||||
return 0;
|
||||
@@ -1464,7 +1514,7 @@ data2attr(struct ipset_session *session, struct nlmsghdr *nlh,
|
||||
data2attr(session, nlh, data, IPSET_ATTR_SETNAME, AF_INET, cmd_attrs)
|
||||
|
||||
#define ADDATTR_IF(session, nlh, data, type, family, attrs) \
|
||||
ipset_data_test(data, attrs[type].opt) ? \
|
||||
ipset_data_test(data, attrs[type].opt) ? \
|
||||
data2attr(session, nlh, data, type, family, attrs) : 0
|
||||
|
||||
#define ADDATTR_RAW(session, nlh, data, type, attrs) \
|
||||
@@ -1485,7 +1535,7 @@ addattr_adt(struct ipset_session *session,
|
||||
struct nlmsghdr *nlh, struct ipset_data *data, uint8_t family)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
for (i = IPSET_ATTR_UNSPEC + 1; i <= IPSET_ATTR_ADT_MAX; i++)
|
||||
if (ADDATTR_IF(session, nlh, data, i, family, adt_attrs))
|
||||
return 1;
|
||||
@@ -1497,7 +1547,7 @@ addattr_adt(struct ipset_session *session,
|
||||
static int
|
||||
build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
{
|
||||
char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned));
|
||||
char buffer[PRIVATE_MSG_BUFLEN] __attribute__ ((aligned)) = {};
|
||||
struct nlmsghdr *nlh = (void *)buffer;
|
||||
struct ipset_data *data = session->data;
|
||||
int len = PRIVATE_MSG_BUFLEN, ret;
|
||||
@@ -1505,7 +1555,7 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
|
||||
/* Initialize header */
|
||||
session->transport->fill_hdr(session->handle, cmd, buffer, len, 0);
|
||||
|
||||
|
||||
ADDATTR_PROTOCOL(nlh);
|
||||
|
||||
switch (cmd) {
|
||||
@@ -1523,9 +1573,11 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
return ipset_err(session,
|
||||
"Invalid internal TYPE command: "
|
||||
"missing settype");
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME, AF_INET, cmd_attrs);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
|
||||
AF_INET, cmd_attrs);
|
||||
if (ipset_data_test(data, IPSET_OPT_FAMILY))
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
|
||||
AF_INET, cmd_attrs);
|
||||
else
|
||||
/* bitmap:port and list:set types */
|
||||
mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC);
|
||||
@@ -1546,10 +1598,10 @@ build_send_private_msg(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
static inline bool
|
||||
may_aggregate_ad(struct ipset_session *session, enum ipset_cmd cmd)
|
||||
{
|
||||
return session->lineno != 0
|
||||
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)
|
||||
&& cmd == session->cmd
|
||||
&& STREQ(ipset_data_setname(session->data), session->saved_setname);
|
||||
return session->lineno != 0 &&
|
||||
(cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL) &&
|
||||
cmd == session->cmd &&
|
||||
STREQ(ipset_data_setname(session->data), session->saved_setname);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1582,17 +1634,23 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
return ipset_err(session,
|
||||
"Invalid create command: missing settype");
|
||||
|
||||
|
||||
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
/* Core attributes:
|
||||
* setname, typename, revision, family, flags (optional) */
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME, AF_INET, cmd_attrs);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_TYPENAME,
|
||||
AF_INET, cmd_attrs);
|
||||
ADDATTR_RAW(session, nlh, &type->revision,
|
||||
IPSET_ATTR_REVISION, cmd_attrs);
|
||||
D("family: %u, type family %u",
|
||||
ipset_data_family(data), type->family);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY, AF_INET, cmd_attrs);
|
||||
if (ipset_data_test(data, IPSET_OPT_FAMILY))
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FAMILY,
|
||||
AF_INET, cmd_attrs);
|
||||
else
|
||||
/* bitmap:port and list:set types */
|
||||
mnl_attr_put_u8(nlh, IPSET_ATTR_FAMILY, AF_UNSPEC);
|
||||
|
||||
/* Type-specific create attributes */
|
||||
D("call open_nested");
|
||||
@@ -1604,23 +1662,41 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
}
|
||||
case IPSET_CMD_DESTROY:
|
||||
case IPSET_CMD_FLUSH:
|
||||
case IPSET_CMD_LIST:
|
||||
case IPSET_CMD_SAVE:
|
||||
if (ipset_data_test(data, IPSET_SETNAME))
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
break;
|
||||
case IPSET_CMD_LIST: {
|
||||
uint32_t flags = 0;
|
||||
|
||||
if (session->envopts & IPSET_ENV_LIST_SETNAME)
|
||||
flags |= IPSET_FLAG_LIST_SETNAME;
|
||||
if (session->envopts & IPSET_ENV_LIST_HEADER)
|
||||
flags |= IPSET_FLAG_LIST_HEADER;
|
||||
if (ipset_data_test(data, IPSET_SETNAME))
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
if (flags && session->mode != IPSET_LIST_SAVE) {
|
||||
ipset_data_set(data, IPSET_OPT_FLAGS, &flags);
|
||||
ADDATTR(session, nlh, data, IPSET_ATTR_FLAGS, AF_INET,
|
||||
cmd_attrs);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IPSET_CMD_RENAME:
|
||||
case IPSET_CMD_SWAP:
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing from-setname",
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" : "rename");
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" :
|
||||
"rename");
|
||||
if (!ipset_data_test(data, IPSET_OPT_SETNAME2))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing to-setname",
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" : "rename");
|
||||
session->cmd == IPSET_CMD_SWAP ? "swap" :
|
||||
"rename");
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
ADDATTR_RAW(session, nlh, ipset_data_get(data, IPSET_OPT_SETNAME2),
|
||||
ADDATTR_RAW(session, nlh,
|
||||
ipset_data_get(data, IPSET_OPT_SETNAME2),
|
||||
IPSET_ATTR_SETNAME2, cmd_attrs);
|
||||
break;
|
||||
case IPSET_CMD_ADD:
|
||||
@@ -1632,12 +1708,14 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing setname",
|
||||
session->cmd == IPSET_CMD_ADD ? "add" : "del");
|
||||
session->cmd == IPSET_CMD_ADD ? "add" :
|
||||
"del");
|
||||
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
return ipset_err(session,
|
||||
"Invalid %s command: missing settype",
|
||||
session->cmd == IPSET_CMD_ADD ? "add" : "del");
|
||||
session->cmd == IPSET_CMD_ADD ? "add" :
|
||||
"del");
|
||||
|
||||
/* Core options: setname */
|
||||
ADDATTR_SETNAME(session, nlh, data);
|
||||
@@ -1655,11 +1733,12 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
D("open_nested failed");
|
||||
return 1;
|
||||
}
|
||||
if (addattr_adt(session, nlh, data, ipset_data_family(data))
|
||||
|| ADDATTR_RAW(session, nlh, &session->lineno,
|
||||
IPSET_ATTR_LINENO, cmd_attrs)) {
|
||||
if (addattr_adt(session, nlh, data, ipset_data_family(data)) ||
|
||||
ADDATTR_RAW(session, nlh, &session->lineno,
|
||||
IPSET_ATTR_LINENO, cmd_attrs)) {
|
||||
/* Cancel last, unfinished nested attribute */
|
||||
mnl_attr_nest_cancel(nlh, session->nested[session->nestid-1]);
|
||||
mnl_attr_nest_cancel(nlh,
|
||||
session->nested[session->nestid-1]);
|
||||
session->nested[--session->nestid] = NULL;
|
||||
return 1;
|
||||
}
|
||||
@@ -1671,7 +1750,7 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
/* Return codes are not aggregated, so tests cannot be either */
|
||||
|
||||
/* Setname, type not checked/added yet */
|
||||
|
||||
|
||||
if (!ipset_data_test(data, IPSET_SETNAME))
|
||||
return ipset_err(session,
|
||||
"Invalid test command: missing setname");
|
||||
@@ -1679,7 +1758,7 @@ build_msg(struct ipset_session *session, bool aggregate)
|
||||
if (!ipset_data_test(data, IPSET_OPT_TYPE))
|
||||
return ipset_err(session,
|
||||
"Invalid test command: missing settype");
|
||||
|
||||
|
||||
type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
D("family: %u, type family %u",
|
||||
ipset_data_family(data), type->family);
|
||||
@@ -1713,7 +1792,8 @@ ipset_commit(struct ipset_session *session)
|
||||
assert(session);
|
||||
|
||||
nlh = session->buffer;
|
||||
D("send buffer: len %u, cmd %s", nlh->nlmsg_len, cmd2name[session->cmd]);
|
||||
D("send buffer: len %u, cmd %s",
|
||||
nlh->nlmsg_len, cmd2name[session->cmd]);
|
||||
if (nlh->nlmsg_len == 0)
|
||||
/* Nothing to do */
|
||||
return 0;
|
||||
@@ -1729,6 +1809,7 @@ ipset_commit(struct ipset_session *session)
|
||||
|
||||
/* Reset saved data and nested state */
|
||||
session->saved_setname[0] = '\0';
|
||||
session->printed_set = 0;
|
||||
for (i = session->nestid - 1; i >= 0; i--)
|
||||
session->nested[i] = NULL;
|
||||
session->nestid = 0;
|
||||
@@ -1741,7 +1822,7 @@ ipset_commit(struct ipset_session *session)
|
||||
return -1;
|
||||
else
|
||||
return ipset_err(session,
|
||||
"Internal protocol error");
|
||||
"Internal protocol error");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1753,7 +1834,7 @@ static mnl_cb_t cb_ctl[] = {
|
||||
[NLMSG_OVERRUN] = callback_noop,
|
||||
[NLMSG_MIN_TYPE] = callback_data,
|
||||
};
|
||||
|
||||
|
||||
static inline struct ipset_handle *
|
||||
init_transport(struct ipset_session *session)
|
||||
{
|
||||
@@ -1782,7 +1863,7 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
struct ipset_data *data;
|
||||
bool aggregate = false;
|
||||
int ret = -1;
|
||||
|
||||
|
||||
assert(session);
|
||||
|
||||
if (cmd <= IPSET_CMD_NONE || cmd >= IPSET_MSG_MAX)
|
||||
@@ -1802,9 +1883,9 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
}
|
||||
|
||||
/* Private commands */
|
||||
if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
|
||||
if (cmd == IPSET_CMD_TYPE || cmd == IPSET_CMD_HEADER)
|
||||
return build_send_private_msg(session, cmd);
|
||||
|
||||
|
||||
/* Check aggregatable commands */
|
||||
aggregate = may_aggregate_ad(session, cmd);
|
||||
if (!aggregate) {
|
||||
@@ -1817,7 +1898,7 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
/* Real command: update lineno too */
|
||||
session->cmd = cmd;
|
||||
session->lineno = lineno;
|
||||
|
||||
|
||||
/* Set default output mode */
|
||||
if (cmd == IPSET_CMD_LIST) {
|
||||
if (session->mode == IPSET_LIST_NONE)
|
||||
@@ -1845,8 +1926,8 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
|
||||
/* We have to save the type for error handling */
|
||||
session->saved_type = ipset_data_get(data, IPSET_OPT_TYPE);
|
||||
if (session->lineno != 0
|
||||
&& (cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
|
||||
if (session->lineno != 0 &&
|
||||
(cmd == IPSET_CMD_ADD || cmd == IPSET_CMD_DEL)) {
|
||||
/* Save setname for the next possible aggregated restore line */
|
||||
strcpy(session->saved_setname, ipset_data_setname(data));
|
||||
ipset_data_reset(data);
|
||||
@@ -1855,7 +1936,7 @@ ipset_cmd(struct ipset_session *session, enum ipset_cmd cmd, uint32_t lineno)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
D("call commit");
|
||||
D("call commit");
|
||||
ret = ipset_commit(session);
|
||||
|
||||
cleanup:
|
||||
@@ -1887,10 +1968,10 @@ ipset_session_init(ipset_outfn outfn)
|
||||
|
||||
/* The single transport method yet */
|
||||
session->transport = &ipset_mnl_transport;
|
||||
|
||||
|
||||
/* Output function */
|
||||
session->outfn = outfn;
|
||||
|
||||
|
||||
/* Initialize data structures */
|
||||
session->data = ipset_data_init();
|
||||
if (session->data == NULL)
|
||||
@@ -1900,8 +1981,8 @@ ipset_session_init(ipset_outfn outfn)
|
||||
return session;
|
||||
|
||||
free_session:
|
||||
free(session);
|
||||
return NULL;
|
||||
free(session);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1926,3 +2007,7 @@ ipset_session_fini(struct ipset_session *session)
|
||||
free(session);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef IPSET_DEBUG
|
||||
#include "debug.c"
|
||||
#endif
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -28,8 +28,8 @@ struct ipset {
|
||||
struct ipset *next;
|
||||
};
|
||||
|
||||
static struct ipset_type *typelist = NULL; /* registered set types */
|
||||
static struct ipset *setlist = NULL; /* cached sets */
|
||||
static struct ipset_type *typelist; /* registered set types */
|
||||
static struct ipset *setlist; /* cached sets */
|
||||
|
||||
/**
|
||||
* ipset_cache_add - add a set to the cache
|
||||
@@ -57,7 +57,7 @@ ipset_cache_add(const char *name, const struct ipset_type *type,
|
||||
ipset_strlcpy(n->name, name, IPSET_MAXNAMELEN);
|
||||
n->type = type;
|
||||
n->family = family;
|
||||
n->next = NULL;
|
||||
n->next = NULL;
|
||||
|
||||
if (setlist == NULL) {
|
||||
setlist = n;
|
||||
@@ -109,7 +109,7 @@ ipset_cache_del(const char *name)
|
||||
}
|
||||
if (match == NULL)
|
||||
return -EEXIST;
|
||||
|
||||
|
||||
free(match);
|
||||
return 0;
|
||||
}
|
||||
@@ -168,7 +168,7 @@ ipset_cache_swap(const char *from, const char *to)
|
||||
ipset_strlcpy(b->name, from, IPSET_MAXNAMELEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return -EEXIST;
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ ipset_cache_swap(const char *from, const char *to)
|
||||
bool
|
||||
ipset_match_typename(const char *name, const struct ipset_type *type)
|
||||
{
|
||||
const char * const * alias = type->alias;
|
||||
const char * const *alias = type->alias;
|
||||
|
||||
if (STREQ(name, type->name))
|
||||
return true;
|
||||
@@ -189,7 +189,7 @@ ipset_match_typename(const char *name, const struct ipset_type *type)
|
||||
alias++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline const struct ipset_type *
|
||||
create_type_get(struct ipset_session *session)
|
||||
@@ -215,17 +215,17 @@ create_type_get(struct ipset_session *session)
|
||||
if (ipset_match_typename(typename, t)
|
||||
&& MATCH_FAMILY(t, family)) {
|
||||
if (match == NULL) {
|
||||
match = t;
|
||||
tmin = tmax = t->revision;
|
||||
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 == AF_UNSPEC && match->family != AF_UNSPEC) {
|
||||
family = match->family == AF_INET46 ? AF_INET : match->family;
|
||||
@@ -240,9 +240,11 @@ create_type_get(struct ipset_session *session)
|
||||
if (ret != 0)
|
||||
return NULL;
|
||||
|
||||
kmin = kmax = *(const uint8_t *)ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
kmin = kmax = *(const uint8_t *)ipset_data_get(data,
|
||||
IPSET_OPT_REVISION);
|
||||
if (ipset_data_test(data, IPSET_OPT_REVISION_MIN))
|
||||
kmin = *(const uint8_t *)ipset_data_get(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)
|
||||
@@ -266,11 +268,24 @@ create_type_get(struct ipset_session *session)
|
||||
family == AF_INET6 ? "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;
|
||||
}
|
||||
|
||||
@@ -314,7 +329,7 @@ adt_type_get(struct ipset_session *session)
|
||||
return NULL;
|
||||
|
||||
typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
|
||||
revision = ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
revision = ipset_data_get(data, IPSET_OPT_REVISION);
|
||||
family = ipset_data_family(data);
|
||||
|
||||
/* Check registered types */
|
||||
@@ -529,7 +544,7 @@ void
|
||||
ipset_cache_fini(void)
|
||||
{
|
||||
struct ipset *set;
|
||||
|
||||
|
||||
while (setlist) {
|
||||
set = setlist;
|
||||
setlist = setlist->next;
|
||||
|
@@ -148,7 +148,7 @@ const union nf_inet_addr ip_set_netmask_map[] = {
|
||||
EXPORT_SYMBOL_GPL(ip_set_netmask_map);
|
||||
|
||||
#undef E
|
||||
#define E(a, b, c, d) \
|
||||
#define E(a, b, c, d) \
|
||||
{.ip6 = { (__force __be32) a, (__force __be32) b, \
|
||||
(__force __be32) c, (__force __be32) d, \
|
||||
} }
|
||||
@@ -289,3 +289,24 @@ const union nf_inet_addr ip_set_hostmask_map[] = {
|
||||
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);
|
||||
|
@@ -2,7 +2,8 @@
|
||||
#define _PFXLEN_H
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <linux/netfilter.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
/* Prefixlen maps, by Jan Engelhardt */
|
||||
extern const union nf_inet_addr ip_set_netmask_map[];
|
||||
@@ -32,4 +33,12 @@ 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,89 +0,0 @@
|
||||
#ifndef _IP_SET_SLIST_H
|
||||
#define _IP_SET_SLIST_H
|
||||
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
/*
|
||||
* Single linked lists with a single pointer.
|
||||
* Mostly useful for hash tables where the two pointer list head
|
||||
* and list node is too wasteful.
|
||||
*/
|
||||
|
||||
struct slist {
|
||||
struct slist *next;
|
||||
};
|
||||
|
||||
#define SLIST(name) struct slist name = { .next = NULL }
|
||||
#define INIT_SLIST(ptr) ((ptr)->next = NULL)
|
||||
|
||||
#define slist_entry(ptr, type, member) container_of(ptr, type, member)
|
||||
|
||||
#define slist_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos && ({ prefetch(pos->next); 1; }); \
|
||||
pos = pos->next)
|
||||
|
||||
#define slist_for_each_prev(prev, pos, head) \
|
||||
for (prev = head, pos = (head)->next; \
|
||||
pos && ({ prefetch(pos->next); 1; }); \
|
||||
prev = pos, pos = pos->next)
|
||||
|
||||
#define slist_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next; pos && ({ n = pos->next; 1; }); \
|
||||
pos = n)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry - iterate over list of given type
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry(tpos, pos, head, member) \
|
||||
for (pos = (head)->next; \
|
||||
pos && ({ prefetch(pos->next); 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry_continue - iterate over a hlist continuing
|
||||
* after current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry_continue(tpos, pos, member) \
|
||||
for (pos = (pos)->next; \
|
||||
pos && ({ prefetch(pos->next); 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry_from - iterate over a hlist continuing
|
||||
* from current point
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry_from(tpos, pos, member) \
|
||||
for (; pos && ({ prefetch(pos->next); 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = pos->next)
|
||||
|
||||
/**
|
||||
* slist_for_each_entry_safe - iterate over list of given type safe against
|
||||
* removal of list entry
|
||||
* @tpos: the type * to use as a loop cursor.
|
||||
* @pos: the &struct slist to use as a loop cursor.
|
||||
* @n: another &struct slist to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the slist within the struct.
|
||||
*/
|
||||
#define slist_for_each_entry_safe(tpos, pos, n, head, member) \
|
||||
for (pos = (head)->next; \
|
||||
pos && ({ n = pos->next; 1; }) && \
|
||||
({ tpos = slist_entry(pos, typeof(*tpos), member); 1; });\
|
||||
pos = n)
|
||||
|
||||
#endif /* _IP_SET_SLIST_H */
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -70,7 +70,7 @@ static const struct ipset_errcode_table core_errcode_table[] = {
|
||||
"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" },
|
||||
@@ -113,6 +113,10 @@ static const struct ipset_errcode_table hash_errcode_table[] = {
|
||||
"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" },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -153,10 +157,10 @@ 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:"))
|
||||
@@ -170,11 +174,11 @@ ipset_errcode(struct ipset_session *session, enum ipset_cmd cmd, int errcode)
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
@@ -21,7 +21,7 @@ ipset \(em administration tool for IP sets
|
||||
.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 }
|
||||
\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
|
||||
@@ -109,7 +109,7 @@ 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 ]
|
||||
\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
|
||||
@@ -120,8 +120,13 @@ 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.
|
||||
(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
|
||||
@@ -190,6 +195,13 @@ 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
|
||||
@@ -202,8 +214,8 @@ command follows the syntax
|
||||
|
||||
where the current list of the methods are
|
||||
\fBbitmap\fR, \fBhash\fR, and \fBlist\fR and the possible data types
|
||||
are \fBip\fR, \fBmac\fR and \fBport\fR. The dimension of a set
|
||||
is equal to the number of data types in its type name.
|
||||
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
|
||||
@@ -397,13 +409,16 @@ 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 := \fIip\fR[/\fIcidr\fR]
|
||||
\fIADD\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
|
||||
\fIDEL\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIip\fR[/\fIcidr\fR]
|
||||
\fITEST\-ENTRY\fR := \fInetaddr\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
@@ -419,6 +434,11 @@ correct value.
|
||||
\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.
|
||||
@@ -527,13 +547,16 @@ 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 := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
|
||||
\fIADD\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fIADD\-OPTIONS\fR := [ \fBtimeout\fR \fIvalue\fR ]
|
||||
.PP
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
|
||||
\fIDEL\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR[/\fIcidr\fR],[\fIproto\fR:]\fIport\fR
|
||||
\fITEST\-ENTRY\fR := \fInetaddr\fR,[\fIproto\fR:]\fIport\fR
|
||||
.PP
|
||||
where
|
||||
\fInetaddr\fR := \fIip\fR[/\fIcidr\fR]
|
||||
.PP
|
||||
Optional \fBcreate\fR options:
|
||||
.TP
|
||||
@@ -549,7 +572,8 @@ correct value.
|
||||
\fBmaxelem\fR \fIvalue\fR
|
||||
The maximal number of elements which can be stored in the set, default 65536.
|
||||
.PP
|
||||
For the
|
||||
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.
|
||||
@@ -633,18 +657,22 @@ 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,\fIip\fR[/\fIcidr\fR]
|
||||
\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,\fIip\fR[/\fIcidr\fR]
|
||||
\fIDEL\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fIip\fR[/\fIcidr\fR]
|
||||
\fITEST\-ENTRY\fR := \fIipaddr\fR,[\fIproto\fR:]\fIport\fR,\fInetaddr\fR
|
||||
.PP
|
||||
For the first \fIipaddr\fR and
|
||||
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.
|
||||
\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
|
||||
@@ -683,6 +711,77 @@ ipset add foo 192.168.1,80,10.0.0/24
|
||||
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.
|
@@ -2,8 +2,8 @@
|
||||
* 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
|
||||
* 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 */
|
||||
@@ -23,15 +23,15 @@
|
||||
#include <libipset/ui.h> /* core options, commands */
|
||||
#include <libipset/utils.h> /* STREQ */
|
||||
|
||||
static char program_name[] = PACKAGE;
|
||||
static char program_version[] = PACKAGE_VERSION;
|
||||
static char program_name[] = "ipset";
|
||||
static char program_version[] = "6.8-genl-xta";
|
||||
|
||||
static struct ipset_session *session = NULL;
|
||||
static uint32_t restore_line = 0;
|
||||
static bool interactive = false;
|
||||
static struct ipset_session *session;
|
||||
static uint32_t restore_line;
|
||||
static bool interactive;
|
||||
static char cmdline[1024];
|
||||
static char *newargv[255];
|
||||
static int newargc = 0;
|
||||
static int newargc;
|
||||
|
||||
/* The known set types: (typename, revision, family) is unique */
|
||||
extern struct ipset_type ipset_bitmap_ip0;
|
||||
@@ -39,10 +39,14 @@ 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_netport0;
|
||||
extern struct ipset_type ipset_hash_ipport0;
|
||||
extern struct ipset_type ipset_hash_ipportip0;
|
||||
extern struct ipset_type ipset_hash_ipportnet0;
|
||||
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 {
|
||||
@@ -53,12 +57,12 @@ enum exittype {
|
||||
SESSION_PROBLEM,
|
||||
};
|
||||
|
||||
static int __attribute__((format(printf,2,3)))
|
||||
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);
|
||||
bool quiet = !interactive &&
|
||||
session &&
|
||||
ipset_envopt_test(session, IPSET_ENV_QUIET);
|
||||
|
||||
if (status && msg && !quiet) {
|
||||
va_list args;
|
||||
@@ -94,8 +98,8 @@ exit_error(int status, const char *msg, ...)
|
||||
static int
|
||||
handle_error(void)
|
||||
{
|
||||
if (ipset_session_warning(session)
|
||||
&& !ipset_envopt_test(session, IPSET_ENV_QUIET))
|
||||
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))
|
||||
@@ -107,7 +111,7 @@ handle_error(void)
|
||||
exit(OTHER_PROBLEM);
|
||||
}
|
||||
|
||||
ipset_session_report_reset(session);
|
||||
ipset_session_report_reset(session);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -116,16 +120,15 @@ 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++) {
|
||||
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);
|
||||
@@ -140,14 +143,14 @@ build_argv(char *buffer)
|
||||
char *ptr;
|
||||
int i;
|
||||
|
||||
/* Reset */
|
||||
/* Reset */
|
||||
for (i = 1; i < newargc; i++)
|
||||
newargv[i] = NULL;
|
||||
newargc = 1;
|
||||
|
||||
ptr = strtok(buffer, " \t\n");
|
||||
ptr = strtok(buffer, " \t\r\n");
|
||||
newargv[newargc++] = ptr;
|
||||
while ((ptr = strtok(NULL, " \t\n")) != NULL) {
|
||||
while ((ptr = strtok(NULL, " \t\r\n")) != NULL) {
|
||||
if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *)))
|
||||
newargv[newargc++] = ptr;
|
||||
else {
|
||||
@@ -169,7 +172,7 @@ restore(char *argv0)
|
||||
{
|
||||
int ret = 0;
|
||||
char *c;
|
||||
|
||||
|
||||
/* Initialize newargv/newargc */
|
||||
newargc = 0;
|
||||
newargv[newargc++] = argv0;
|
||||
@@ -181,7 +184,7 @@ restore(char *argv0)
|
||||
c++;
|
||||
if (c[0] == '\0' || c[0] == '#')
|
||||
continue;
|
||||
else if (strcmp(c, "COMMIT\n") == 0) {
|
||||
else if (STREQ(c, "COMMIT\n") || STREQ(c, "COMMIT\r\n")) {
|
||||
ret = ipset_commit(session);
|
||||
if (ret < 0)
|
||||
handle_error();
|
||||
@@ -189,7 +192,7 @@ restore(char *argv0)
|
||||
}
|
||||
/* Build faked argv, argc */
|
||||
build_argv(c);
|
||||
|
||||
|
||||
/* Execute line */
|
||||
ret = parse_commandline(newargc, newargv);
|
||||
if (ret < 0)
|
||||
@@ -209,7 +212,7 @@ 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;
|
||||
@@ -233,7 +236,8 @@ call_parser(int *argc, char *argv[], const struct ipset_arg *args)
|
||||
/* Fall through */
|
||||
case IPSET_OPTIONAL_ARG:
|
||||
if (*argc >= 2) {
|
||||
ret = ipset_call_parser(session, arg, argv[1]);
|
||||
ret = ipset_call_parser(session,
|
||||
arg, argv[1]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ipset_shift_argv(argc, argv, 1);
|
||||
@@ -259,7 +263,7 @@ err_unknown:
|
||||
static enum ipset_adt
|
||||
cmd2cmd(int cmd)
|
||||
{
|
||||
switch(cmd) {
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_ADD:
|
||||
return IPSET_ADD;
|
||||
case IPSET_CMD_DEL:
|
||||
@@ -339,15 +343,15 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
|
||||
? 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)))
|
||||
if (!(cmdflags & IPSET_FLAG(i)) ||
|
||||
(allowed & IPSET_FLAG(i)) ||
|
||||
!(flags & IPSET_FLAG(i)))
|
||||
continue;
|
||||
/* Not allowed element-expressions */
|
||||
switch (i) {
|
||||
@@ -355,19 +359,22 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
|
||||
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());
|
||||
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());
|
||||
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());
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@@ -387,7 +394,8 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
|
||||
"%s parameter is not allowed in command %s "
|
||||
"with set type %s and family %s",
|
||||
arg->name[0],
|
||||
cmd2name(command), type->name, session_family());
|
||||
cmd2name(command), type->name,
|
||||
session_family());
|
||||
return;
|
||||
}
|
||||
exit_error(OTHER_PROBLEM,
|
||||
@@ -402,7 +410,7 @@ 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;
|
||||
@@ -473,10 +481,10 @@ parse_commandline(int argc, char *argv[])
|
||||
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))
|
||||
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.",
|
||||
@@ -561,9 +569,9 @@ parse_commandline(int argc, char *argv[])
|
||||
case IPSET_CMD_HELP:
|
||||
help();
|
||||
|
||||
if (interactive
|
||||
|| !ipset_envopt_test(session, IPSET_ENV_QUIET)) {
|
||||
if (arg0) {
|
||||
if (interactive ||
|
||||
!ipset_envopt_test(session, IPSET_ENV_QUIET)) {
|
||||
if (arg0) {
|
||||
/* Type-specific help, without kernel checking */
|
||||
type = type_find(arg0);
|
||||
if (!type)
|
||||
@@ -593,7 +601,7 @@ parse_commandline(int argc, char *argv[])
|
||||
printf(" %s\n", type->name);
|
||||
type = type->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (interactive)
|
||||
return 0;
|
||||
@@ -603,7 +611,7 @@ parse_commandline(int argc, char *argv[])
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* Forth: parse command args and issue the command */
|
||||
switch (cmd) {
|
||||
case IPSET_CMD_CREATE:
|
||||
@@ -626,11 +634,11 @@ parse_commandline(int argc, char *argv[])
|
||||
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:
|
||||
@@ -674,22 +682,22 @@ parse_commandline(int argc, char *argv[])
|
||||
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;
|
||||
@@ -715,16 +723,22 @@ parse_commandline(int argc, char *argv[])
|
||||
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_netport0);
|
||||
ipset_type_add(&ipset_hash_ipport0);
|
||||
ipset_type_add(&ipset_hash_ipportip0);
|
||||
ipset_type_add(&ipset_hash_ipportnet0);
|
||||
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 */
|
||||
@@ -733,5 +747,9 @@ main(int argc, char *argv[])
|
||||
return exit_error(OTHER_PROBLEM,
|
||||
"Cannot initialize ipset session, aborting.");
|
||||
|
||||
return parse_commandline(argc, argv);
|
||||
ret = parse_commandline(argc, argv);
|
||||
|
||||
ipset_session_fini(session);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -37,7 +37,7 @@ static const struct ipset_arg bitmap_ip_create_args[] = {
|
||||
.parse = ipset_parse_net,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg bitmap_ip_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -45,7 +45,7 @@ static const struct ipset_arg bitmap_ip_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char bitmap_ip_usage[] =
|
||||
"create SETNAME bitmap:ip range IP/CIDR|FROM-TO\n"
|
||||
@@ -62,8 +62,8 @@ struct ipset_type ipset_bitmap_ip0 = {
|
||||
.revision = 0,
|
||||
.family = AF_INET,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -33,7 +33,7 @@ static const struct ipset_arg bitmap_ipmac_create_args[] = {
|
||||
.parse = ipset_parse_net,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg bitmap_ipmac_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -41,7 +41,7 @@ static const struct ipset_arg bitmap_ipmac_add_args[] = {
|
||||
.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"
|
||||
@@ -60,13 +60,13 @@ struct ipset_type ipset_bitmap_ipmac0 = {
|
||||
.family = AF_INET,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.last_elem_optional = true,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_single_ip,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_ether,
|
||||
.print = ipset_print_ether,
|
||||
.opt = IPSET_OPT_ETHER
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -29,7 +29,7 @@ static const struct ipset_arg bitmap_port_create_args[] = {
|
||||
.parse = ipset_parse_single_tcp_port,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg bitmap_port_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -37,7 +37,7 @@ static const struct ipset_arg bitmap_port_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char bitmap_port_usage[] =
|
||||
"create SETNAME bitmap:port range FROM-TO\n"
|
||||
@@ -53,8 +53,8 @@ struct ipset_type ipset_bitmap_port0 = {
|
||||
.revision = 0,
|
||||
.family = AF_UNSPEC,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_tcp_port,
|
||||
.print = ipset_print_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -63,7 +63,7 @@ static const struct ipset_arg hash_ip_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char hash_ip_usage[] =
|
||||
"create SETNAME hash:ip\n"
|
||||
@@ -81,18 +81,17 @@ static const char hash_ip_usage[] =
|
||||
|
||||
struct ipset_type ipset_hash_ip0 = {
|
||||
.name = "hash:ip",
|
||||
.alias = { "iphash", "iptree", "iptreemap", NULL },
|
||||
.alias = { "iphash", NULL },
|
||||
.revision = 0,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
},
|
||||
.compat_parse_elem = ipset_parse_iptimeout,
|
||||
.args = {
|
||||
[IPSET_CREATE] = hash_ip_create_args,
|
||||
[IPSET_ADD] = hash_ip_add_args,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -60,7 +60,7 @@ static const struct ipset_arg hash_ipport_create_args[] = {
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_ipport_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -68,9 +68,9 @@ static const struct ipset_arg hash_ipport_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char hash_ipport_usage[] =
|
||||
static const char hash_ipport1_usage[] =
|
||||
"create SETNAME hash:ip,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -85,19 +85,19 @@ static const char hash_ipport_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipport0 = {
|
||||
struct ipset_type ipset_hash_ipport1 = {
|
||||
.name = "hash:ip,port",
|
||||
.alias = { "ipporthash", NULL },
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
@@ -139,6 +139,6 @@ struct ipset_type ipset_hash_ipport0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_PROTO),
|
||||
},
|
||||
|
||||
.usage = hash_ipport_usage,
|
||||
.usage = hash_ipport1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -60,7 +60,7 @@ static const struct ipset_arg hash_ipportip_create_args[] = {
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_ipportip_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -68,9 +68,9 @@ static const struct ipset_arg hash_ipportip_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char hash_ipportip_usage[] =
|
||||
static const char hash_ipportip1_usage[] =
|
||||
"create SETNAME hash:ip,port,ip\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -85,24 +85,24 @@ static const char hash_ipportip_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportip0 = {
|
||||
struct ipset_type ipset_hash_ipportip1 = {
|
||||
.name = "hash:ip,port,ip",
|
||||
.alias = { "ipportiphash", NULL },
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
[IPSET_DIM_THREE] = {
|
||||
[IPSET_DIM_THREE] = {
|
||||
.parse = ipset_parse_single_ip,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP2
|
||||
@@ -150,6 +150,6 @@ struct ipset_type ipset_hash_ipportip0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_IP2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportip_usage,
|
||||
.usage = hash_ipportip1_usage,
|
||||
.usagefn = ipset_port_usage,
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -60,7 +60,7 @@ static const struct ipset_arg hash_ipportnet_create_args[] = {
|
||||
.parse = ipset_parse_ignored,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_ipportnet_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -68,9 +68,9 @@ static const struct ipset_arg hash_ipportnet_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char hash_ipportnet_usage[] =
|
||||
static const char hash_ipportnet1_usage[] =
|
||||
"create SETNAME hash:ip,port,net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -86,24 +86,24 @@ static const char hash_ipportnet_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_ipportnet0 = {
|
||||
struct ipset_type ipset_hash_ipportnet1 = {
|
||||
.name = "hash:ip,port,net",
|
||||
.alias = { "ipportnethash", NULL },
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
[IPSET_DIM_THREE] = {
|
||||
[IPSET_DIM_THREE] = {
|
||||
.parse = ipset_parse_ipnet,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP2
|
||||
@@ -133,6 +133,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
|
||||
| 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)
|
||||
@@ -141,6 +142,7 @@ struct ipset_type ipset_hash_ipportnet0 = {
|
||||
| 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)
|
||||
@@ -154,6 +156,99 @@ struct ipset_type ipset_hash_ipportnet0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR2),
|
||||
},
|
||||
|
||||
.usage = hash_ipportnet_usage,
|
||||
.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 = AF_INET46,
|
||||
.dimension = IPSET_DIM_THREE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_single6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
},
|
||||
[IPSET_DIM_THREE] = {
|
||||
.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,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -47,7 +47,7 @@ static const struct ipset_arg hash_net_create_args[] = {
|
||||
.parse = ipset_parse_ignored, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_net_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -55,9 +55,9 @@ static const struct ipset_arg hash_net_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char hash_net_usage[] =
|
||||
static const char hash_net0_usage[] =
|
||||
"create SETNAME hash:net\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -75,8 +75,8 @@ struct ipset_type ipset_hash_net0 = {
|
||||
.revision = 0,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ipnet,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
@@ -105,5 +105,60 @@ struct ipset_type ipset_hash_net0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_net_usage,
|
||||
.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 = AF_INET46,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.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,
|
||||
};
|
||||
|
||||
|
120
extensions/ipset-6/src/ipset_hash_netiface.c
Normal file
120
extensions/ipset-6/src/ipset_hash_netiface.c
Normal file
@@ -0,0 +1,120 @@
|
||||
/* 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 = AF_INET46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
.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,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -39,7 +39,7 @@ static const struct ipset_arg hash_netport_create_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg hash_netport_add_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -47,9 +47,9 @@ static const struct ipset_arg hash_netport_add_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char hash_netport_usage[] =
|
||||
static const char hash_netport1_usage[] =
|
||||
"create SETNAME hash:net,port\n"
|
||||
" [family inet|inet6]\n"
|
||||
" [hashsize VALUE] [maxelem VALUE]\n"
|
||||
@@ -63,19 +63,19 @@ static const char hash_netport_usage[] =
|
||||
" Adding/deleting multiple elements with TCP/SCTP/UDP/UDPLITE\n"
|
||||
" port range is supported both for IPv4 and IPv6.\n";
|
||||
|
||||
struct ipset_type ipset_hash_netport0 = {
|
||||
struct ipset_type ipset_hash_netport1 = {
|
||||
.name = "hash:net,port",
|
||||
.alias = { "netporthash", NULL },
|
||||
.revision = 1,
|
||||
.family = AF_INET46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ipnet,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
[IPSET_DIM_TWO] = {
|
||||
.parse = ipset_parse_proto_port,
|
||||
.print = ipset_print_proto_port,
|
||||
.opt = IPSET_OPT_PORT
|
||||
@@ -118,6 +118,82 @@ struct ipset_type ipset_hash_netport0 = {
|
||||
| IPSET_FLAG(IPSET_OPT_CIDR),
|
||||
},
|
||||
|
||||
.usage = hash_netport_usage,
|
||||
.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 = AF_INET46,
|
||||
.dimension = IPSET_DIM_TWO,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_ip4_net6,
|
||||
.print = ipset_print_ip,
|
||||
.opt = IPSET_OPT_IP
|
||||
},
|
||||
[IPSET_DIM_TWO] = {
|
||||
.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,7 +1,7 @@
|
||||
/* 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
|
||||
* 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_* */
|
||||
@@ -20,7 +20,7 @@ static const struct ipset_arg list_set_create_args[] = {
|
||||
.parse = ipset_parse_uint32, .print = ipset_print_number,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const struct ipset_arg list_set_adt_args[] = {
|
||||
{ .name = { "timeout", NULL },
|
||||
@@ -36,7 +36,7 @@ static const struct ipset_arg list_set_adt_args[] = {
|
||||
.parse = ipset_parse_after,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
};
|
||||
|
||||
static const char list_set_usage[] =
|
||||
"create SETNAME list:set\n"
|
||||
@@ -52,8 +52,8 @@ struct ipset_type ipset_list_set0 = {
|
||||
.revision = 0,
|
||||
.family = AF_UNSPEC,
|
||||
.dimension = IPSET_DIM_ONE,
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.elem = {
|
||||
[IPSET_DIM_ONE] = {
|
||||
.parse = ipset_parse_setname,
|
||||
.print = ipset_print_name,
|
||||
.opt = IPSET_OPT_NAME
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/* 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
|
||||
* 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 */
|
||||
@@ -35,91 +35,91 @@ const struct ipset_commands ipset_commands[] = {
|
||||
.name = { "add", NULL },
|
||||
.has_arg = IPSET_MANDATORY_ARG2,
|
||||
.help = "SETNAME ENTRY\n"
|
||||
" Add entry to the named set",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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",
|
||||
" Print version information",
|
||||
},
|
||||
{ /* q[uit] */
|
||||
.cmd = IPSET_CMD_QUIT,
|
||||
.name = { "quit", NULL },
|
||||
.has_arg = IPSET_NO_ARG,
|
||||
.help = "\n"
|
||||
" Quit interactive mode",
|
||||
" Quit interactive mode",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
@@ -149,8 +149,9 @@ ipset_match_cmd(const char *arg, const char * const name[])
|
||||
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]);
|
||||
else
|
||||
return tolower(arg[0]) == name[0][0] ||
|
||||
(name[1] != NULL && tolower(arg[0]) == name[1][0]);
|
||||
}
|
||||
|
||||
const struct ipset_envopts ipset_envopts[] = {
|
||||
@@ -158,36 +159,49 @@ const struct ipset_envopts ipset_envopts[] = {
|
||||
.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\".",
|
||||
" 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).",
|
||||
" 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.",
|
||||
" 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!)",
|
||||
" 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"
|
||||
" 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.",
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -197,13 +211,13 @@ 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]));
|
||||
return STREQ(arg, name[0]) ||
|
||||
(name[1] != NULL && STREQ(arg, name[1]));
|
||||
}
|
||||
|
||||
/* Strict envopt matching */
|
||||
@@ -212,13 +226,13 @@ 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]));
|
||||
return STREQ(arg, name[0]) ||
|
||||
(name[1] != NULL && STREQ(arg, name[1]));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,19 +248,18 @@ void
|
||||
ipset_shift_argv(int *argc, char *argv[], int from)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
assert(*argc >= from + 1);
|
||||
|
||||
for (i = from + 1; i <= *argc; i++) {
|
||||
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
|
||||
@@ -256,9 +269,9 @@ ipset_port_usage(void)
|
||||
const char *name;
|
||||
|
||||
printf(" [PROTO:]PORT is a valid pattern of the following:\n"
|
||||
" PORTNAME port name from /etc/services\n"
|
||||
" PORTNUMBER port number identifier\n"
|
||||
" tcp|udp:PORTNAME|PORTNUMBER\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"
|
||||
|
@@ -29,52 +29,33 @@ MODULE_ALIAS("ip6t_SET");
|
||||
|
||||
static inline int
|
||||
match_set(ip_set_id_t index, const struct sk_buff *skb,
|
||||
u8 pf, u8 dim, u8 flags, int inv)
|
||||
const struct xt_action_param *par,
|
||||
const struct ip_set_adt_opt *opt, int inv)
|
||||
{
|
||||
if (ip_set_test(index, skb, pf, dim, flags))
|
||||
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 */
|
||||
|
||||
/* Backward compatibility constrains (incomplete):
|
||||
* 2.6.24: [NETLINK]: Introduce nested and byteorder flag to netlink attribute
|
||||
* 2.6.25: is_vmalloc_addr(): Check if an address is within the vmalloc
|
||||
* boundaries
|
||||
* 2.6.27: rcu: split list.h and move rcu-protected lists into rculist.h
|
||||
* 2.6.28: netfilter: ctnetlink: remove bogus module dependency between
|
||||
* ctnetlink and nf_nat (nfnl_lock/nfnl_unlock)
|
||||
* 2.6.29: generic swap(): introduce global macro swap(a, b)
|
||||
* 2.6.31: netfilter: passive OS fingerprint xtables match
|
||||
* 2.6.34: rcu: Add lockdep-enabled variants of rcu_dereference()
|
||||
*/
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
|
||||
#error "Linux kernel version too old: must be >= 2.6.34"
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
#define CHECK_OK 1
|
||||
#define CHECK_FAIL(err) 0
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
#define CHECK_OK 0
|
||||
#define CHECK_FAIL(err) (err)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match_v0(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static bool
|
||||
set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
#endif
|
||||
{
|
||||
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->family,
|
||||
info->match_set.u.compat.dim,
|
||||
info->match_set.u.compat.flags,
|
||||
return match_set(info->match_set.index, skb, par, &opt,
|
||||
info->match_set.u.compat.flags & IPSET_INV_MATCH);
|
||||
}
|
||||
|
||||
@@ -94,13 +75,8 @@ compat_flags(struct xt_set_info_v0 *info)
|
||||
}
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
#endif
|
||||
{
|
||||
struct xt_set_info_match_v0 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
@@ -110,19 +86,19 @@ set_match_v0_checkentry(const struct xt_mtchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
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 CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->match_set);
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -133,35 +109,25 @@ set_match_v0_destroy(const struct xt_mtdtor_param *par)
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static unsigned int
|
||||
set_target_v0(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static unsigned int
|
||||
set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
#endif
|
||||
{
|
||||
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->family,
|
||||
info->add_set.u.compat.dim,
|
||||
info->add_set.u.compat.flags);
|
||||
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->family,
|
||||
info->del_set.u.compat.dim,
|
||||
info->del_set.u.compat.flags);
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
#endif
|
||||
{
|
||||
struct xt_set_info_target_v0 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
@@ -171,7 +137,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +148,7 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
|
||||
@@ -193,14 +159,14 @@ set_target_v0_checkentry(const struct xt_tgchk_param *par)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/* Fill out compatibility data */
|
||||
compat_flags(&info->add_set);
|
||||
compat_flags(&info->del_set);
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -214,33 +180,23 @@ set_target_v0_destroy(const struct xt_tgdtor_param *par)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
}
|
||||
|
||||
/* Revision 1: current interface to netfilter/iptables */
|
||||
/* Revision 1 match and target */
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match(const struct sk_buff *skb, const struct xt_match_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static bool
|
||||
set_match(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
#endif
|
||||
set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_match *info = par->matchinfo;
|
||||
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->family,
|
||||
info->match_set.dim,
|
||||
info->match_set.flags,
|
||||
return match_set(info->match_set.index, skb, par, &opt,
|
||||
info->match_set.flags & IPSET_INV_MATCH);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_match_checkentry(const struct xt_mtchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_match_checkentry(const struct xt_mtchk_param *par)
|
||||
#endif
|
||||
set_match_v1_checkentry(const struct xt_mtchk_param *par)
|
||||
{
|
||||
struct xt_set_info_match *info = par->matchinfo;
|
||||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
index = ip_set_nfnl_get_byindex(info->match_set.index);
|
||||
@@ -248,59 +204,47 @@ set_match_checkentry(const struct xt_mtchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find set indentified by id %u to match\n",
|
||||
info->match_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
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 CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_match_destroy(const struct xt_mtdtor_param *par)
|
||||
set_match_v1_destroy(const struct xt_mtdtor_param *par)
|
||||
{
|
||||
struct xt_set_info_match *info = par->matchinfo;
|
||||
struct xt_set_info_match_v1 *info = par->matchinfo;
|
||||
|
||||
ip_set_nfnl_put(info->match_set.index);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static unsigned int
|
||||
set_target(struct sk_buff *skb, const struct xt_target_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static unsigned int
|
||||
set_target(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
#endif
|
||||
set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_set_info_target *info = par->targinfo;
|
||||
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->family,
|
||||
info->add_set.dim,
|
||||
info->add_set.flags);
|
||||
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->family,
|
||||
info->del_set.dim,
|
||||
info->del_set.flags);
|
||||
ip_set_del(info->del_set.index, skb, par, &del_opt);
|
||||
|
||||
return XT_CONTINUE;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
||||
static bool
|
||||
set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) */
|
||||
static int
|
||||
set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
#endif
|
||||
set_target_v1_checkentry(const struct xt_tgchk_param *par)
|
||||
{
|
||||
const struct xt_set_info_target *info = par->targinfo;
|
||||
const struct xt_set_info_target_v1 *info = par->targinfo;
|
||||
ip_set_id_t index;
|
||||
|
||||
if (info->add_set.index != IPSET_INVALID_ID) {
|
||||
@@ -308,7 +252,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
if (index == IPSET_INVALID_ID) {
|
||||
pr_warning("Cannot find add_set index %u as target\n",
|
||||
info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,7 +263,7 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
info->del_set.index);
|
||||
if (info->add_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
return CHECK_FAIL(-ENOENT); /* error */
|
||||
return -ENOENT;
|
||||
}
|
||||
}
|
||||
if (info->add_set.dim > IPSET_DIM_MAX ||
|
||||
@@ -330,16 +274,16 @@ set_target_checkentry(const struct xt_tgchk_param *par)
|
||||
ip_set_nfnl_put(info->add_set.index);
|
||||
if (info->del_set.index != IPSET_INVALID_ID)
|
||||
ip_set_nfnl_put(info->del_set.index);
|
||||
return CHECK_FAIL(-ERANGE); /* error */
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
return CHECK_OK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
set_target_destroy(const struct xt_tgdtor_param *par)
|
||||
set_target_v1_destroy(const struct xt_tgdtor_param *par)
|
||||
{
|
||||
const struct xt_set_info_target *info = par->targinfo;
|
||||
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);
|
||||
@@ -347,6 +291,28 @@ set_target_destroy(const struct xt_tgdtor_param *par)
|
||||
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",
|
||||
@@ -362,20 +328,20 @@ static struct xt_match set_matches[] __read_mostly = {
|
||||
.name = "set",
|
||||
.family = NFPROTO_IPV4,
|
||||
.revision = 1,
|
||||
.match = set_match,
|
||||
.matchsize = sizeof(struct xt_set_info_match),
|
||||
.checkentry = set_match_checkentry,
|
||||
.destroy = set_match_destroy,
|
||||
.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,
|
||||
.matchsize = sizeof(struct xt_set_info_match),
|
||||
.checkentry = set_match_checkentry,
|
||||
.destroy = set_match_destroy,
|
||||
.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
|
||||
},
|
||||
};
|
||||
@@ -395,20 +361,40 @@ static struct xt_target set_targets[] __read_mostly = {
|
||||
.name = "SET",
|
||||
.revision = 1,
|
||||
.family = NFPROTO_IPV4,
|
||||
.target = set_target,
|
||||
.targetsize = sizeof(struct xt_set_info_target),
|
||||
.checkentry = set_target_checkentry,
|
||||
.destroy = set_target_destroy,
|
||||
.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,
|
||||
.targetsize = sizeof(struct xt_set_info_target),
|
||||
.checkentry = set_target_checkentry,
|
||||
.destroy = set_target_destroy,
|
||||
.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
|
||||
},
|
||||
};
|
||||
|
@@ -35,7 +35,7 @@ struct xt_set_info_target_v0 {
|
||||
struct xt_set_info_v0 del_set;
|
||||
};
|
||||
|
||||
/* Revision 1: current interface to netfilter/iptables */
|
||||
/* Revision 1 match and target */
|
||||
|
||||
struct xt_set_info {
|
||||
ip_set_id_t index;
|
||||
@@ -44,13 +44,22 @@ struct xt_set_info {
|
||||
};
|
||||
|
||||
/* match and target infos */
|
||||
struct xt_set_info_match {
|
||||
struct xt_set_info_match_v1 {
|
||||
struct xt_set_info match_set;
|
||||
};
|
||||
|
||||
struct xt_set_info_target {
|
||||
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*/
|
||||
|
@@ -36,6 +36,8 @@ The SYSRQ password can be changed through
|
||||
.IP
|
||||
echo \-n "password" >/sys/module/xt_SYSRQ/parameters/password
|
||||
.PP
|
||||
The module will not respond to sysrq requests until a password has been set.
|
||||
.PP
|
||||
Alternatively, the password may be specified at modprobe time, but this is
|
||||
insecure as people can possible see it through ps(1). You can use an option
|
||||
line in e.g. /etc/modprobe.d/xt_sysrq if it is properly guarded, that is, only
|
||||
@@ -52,7 +54,7 @@ The xt_SYSRQ module is normally silent unless a successful request is received,
|
||||
but the \fIdebug\fP module parameter can be used to find exactly why a
|
||||
seemingly correct request is not being processed.
|
||||
.PP
|
||||
To trigger SYSRQ from a remote host, just use netcat or socat:
|
||||
To trigger SYSRQ from a remote host, just use socat:
|
||||
.PP
|
||||
.nf
|
||||
sysrq_key="s" # the SysRq key(s)
|
||||
@@ -60,12 +62,11 @@ password="password"
|
||||
seqno="$(date +%s)"
|
||||
salt="$(dd bs=12 count=1 if=/dev/urandom 2>/dev/null |
|
||||
openssl enc \-base64)"
|
||||
ipaddr=10.10.25.7
|
||||
req="$sysrq_key,$seqno,$salt"
|
||||
req="$req,$(echo \-n "$req,$password" | sha1sum | cut \-c1\-40)"
|
||||
req="$req,$(echo \-n "$req,$ipaddr,$password" | sha1sum | cut \-c1\-40)"
|
||||
|
||||
echo "$req" | socat stdin udp\-sendto:10.10.25.7:9
|
||||
# or
|
||||
echo "$req" | netcat \-uw1 10.10.25.7 9
|
||||
echo "$req" | socat stdin udp\-sendto:$ipaddr:9
|
||||
.fi
|
||||
.PP
|
||||
See the Linux docs for possible sysrq keys. Important ones are: re(b)oot,
|
||||
@@ -73,8 +74,10 @@ power(o)ff, (s)ync filesystems, (u)mount and remount readonly. More than one
|
||||
sysrq key can be used at once, but bear in mind that, for example, a sync may
|
||||
not complete before a subsequent reboot or poweroff.
|
||||
.PP
|
||||
An IPv4 address should have no leading zeros, an IPv6 address should
|
||||
be in the form recommended by RFC 5952. The debug option will log the
|
||||
correct form of the address.
|
||||
.PP
|
||||
The hashing scheme should be enough to prevent mis-use of SYSRQ in many
|
||||
environments, but it is not perfect: take reasonable precautions to
|
||||
protect your machines. Most importantly ensure that each machine has a
|
||||
different password; there is scant protection for a SYSRQ packet being
|
||||
applied to a machine that happens to have the same password.
|
||||
protect your machines.
|
||||
|
@@ -1,34 +1,120 @@
|
||||
/*
|
||||
* "TARPIT" target extension to iptables
|
||||
* this file is in the Public Domain
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License; either
|
||||
* version 2 of the License, or any later version, as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <xtables.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "xt_TARPIT.h"
|
||||
#include "compat_user.h"
|
||||
|
||||
enum {
|
||||
F_TARPIT = 1 << 0,
|
||||
F_HONEYPOT = 1 << 1,
|
||||
F_RESET = 1 << 2,
|
||||
};
|
||||
|
||||
static const struct option tarpit_tg_opts[] = {
|
||||
{.name = "tarpit", .has_arg = false, .val = 't'},
|
||||
{.name = "honeypot", .has_arg = false, .val = 'h'},
|
||||
{.name = "reset", .has_arg = false, .val = 'r'},
|
||||
{NULL},
|
||||
};
|
||||
|
||||
static void tarpit_tg_help(void)
|
||||
{
|
||||
printf("TARPIT takes no options\n\n");
|
||||
printf(
|
||||
"TARPIT target options:\n"
|
||||
" --tarpit Enable classic 0-window tarpit (default)\n"
|
||||
" --honeypot Enable honeypot option\n"
|
||||
" --reset Enable inline resets\n");
|
||||
}
|
||||
|
||||
static int tarpit_tg_parse(int c, char **argv, int invert, unsigned int *flags,
|
||||
const void *entry, struct xt_entry_target **target)
|
||||
{
|
||||
return 0;
|
||||
struct xt_tarpit_tginfo *info = (void *)(*target)->data;
|
||||
|
||||
switch (c) {
|
||||
case 't':
|
||||
info->variant = XTTARPIT_TARPIT;
|
||||
*flags |= F_TARPIT;
|
||||
return true;
|
||||
case 'h':
|
||||
info->variant = XTTARPIT_HONEYPOT;
|
||||
*flags |= F_HONEYPOT;
|
||||
return true;
|
||||
case 'r':
|
||||
info->variant = XTTARPIT_RESET;
|
||||
*flags |= F_RESET;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void tarpit_tg_check(unsigned int flags)
|
||||
{
|
||||
if (flags == (F_TARPIT | F_HONEYPOT | F_RESET))
|
||||
xtables_error(PARAMETER_PROBLEM,
|
||||
"TARPIT: only one action can be used at a time");
|
||||
}
|
||||
|
||||
static void tarpit_tg_print(const void *ip,
|
||||
const struct xt_entry_target *target, int numeric)
|
||||
{
|
||||
const struct xt_tarpit_tginfo *info = (void *)target->data;
|
||||
|
||||
switch (info->variant) {
|
||||
case XTTARPIT_HONEYPOT:
|
||||
printf(" honeypot mode ");
|
||||
break;
|
||||
case XTTARPIT_RESET:
|
||||
printf(" reset mode ");
|
||||
break;
|
||||
default:
|
||||
printf(" tarpit mode ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tarpit_tg_save(const void *ip,
|
||||
const struct xt_entry_target *target)
|
||||
{
|
||||
const struct xt_tarpit_tginfo *info = (const void *)target->data;
|
||||
|
||||
switch (info->variant) {
|
||||
case XTTARPIT_TARPIT:
|
||||
printf(" --tarpit ");
|
||||
break;
|
||||
case XTTARPIT_HONEYPOT:
|
||||
printf(" --honeypot ");
|
||||
break;
|
||||
case XTTARPIT_RESET:
|
||||
printf(" --reset ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct xtables_target tarpit_tg_reg = {
|
||||
.version = XTABLES_VERSION,
|
||||
.name = "TARPIT",
|
||||
.family = NFPROTO_IPV4,
|
||||
.size = XT_ALIGN(sizeof(struct xt_tarpit_tginfo)),
|
||||
.userspacesize = XT_ALIGN(sizeof(struct xt_tarpit_tginfo)),
|
||||
.help = tarpit_tg_help,
|
||||
.parse = tarpit_tg_parse,
|
||||
.final_check = tarpit_tg_check,
|
||||
.print = tarpit_tg_print,
|
||||
.save = tarpit_tg_save,
|
||||
.extra_opts = tarpit_tg_opts,
|
||||
};
|
||||
|
||||
static __attribute__((constructor)) void tarpit_tg_ldr(void)
|
||||
|
@@ -1,14 +1,38 @@
|
||||
Captures and holds incoming TCP connections using no local per-connection
|
||||
resources. Connections are accepted, but immediately switched to the persist
|
||||
state (0 byte window), in which the remote side stops sending data and asks to
|
||||
continue every 60-240 seconds. Attempts to close the connection are ignored,
|
||||
forcing the remote side to time out the connection in 12-24 minutes.
|
||||
|
||||
resources.
|
||||
.PP
|
||||
TARPIT only works at the TCP level, and is totally application agnostic. This
|
||||
module will answer a TCP request and play along like a listening server, but
|
||||
aside from sending an ACK or RST, no data is sent. Incoming packets are ignored
|
||||
and dropped. The attacker will terminate the session eventually. This module
|
||||
allows the initial packets of an attack to be captured by other software for
|
||||
inspection. In most cases this is sufficient to determine the nature of the
|
||||
attack.
|
||||
.PP
|
||||
This offers similar functionality to LaBrea
|
||||
<http://www.hackbusters.net/LaBrea/> but does not require dedicated hardware or
|
||||
IPs. Any TCP port that you would normally DROP or REJECT can instead become a
|
||||
tarpit.
|
||||
|
||||
.TP
|
||||
\fB\-\-tarpit\fP
|
||||
This mode completes a connection with the attacker but limits the window size
|
||||
to 0, thus keeping the attacker waiting long periods of time. While he is
|
||||
maintaining state of the connection and trying to continue every 60-240
|
||||
seconds, we keep none, so it is very lightweight. Attempts to close the
|
||||
connection are ignored, forcing the remote side to time out the connection in
|
||||
12-24 minutes. This mode is the default.
|
||||
.TP
|
||||
\fB\-\-honeypot\fP
|
||||
This mode completes a connection with the attacker, but signals a normal window
|
||||
size, so that the remote side will attempt to send data, often with some very
|
||||
nasty exploit attempts. We can capture these packets for decoding and further
|
||||
analysis. The module does not send any data, so if the remote expects an
|
||||
application level response, the game is up.
|
||||
.TP
|
||||
\fB\-\-reset\fP
|
||||
This mode is handy because we can send an inline RST (reset). It has no other
|
||||
function.
|
||||
.PP
|
||||
To tarpit connections to TCP port 80 destined for the current machine:
|
||||
.IP
|
||||
\-A INPUT \-p tcp \-m tcp \-\-dport 80 \-j TARPIT
|
||||
@@ -24,10 +48,12 @@ the Linux box, and add:
|
||||
.PP
|
||||
NOTE:
|
||||
If you use the conntrack module while you are using TARPIT, you should also use
|
||||
the NOTRACK target, or the kernel will unnecessarily allocate resources for
|
||||
each TARPITted connection. To TARPIT incoming connections to the standard IRC
|
||||
port while using conntrack, you could:
|
||||
unset tracking on the packet, or the kernel will unnecessarily allocate
|
||||
resources for each TARPITted connection. To TARPIT incoming connections to the
|
||||
standard IRC port while using conntrack, you could:
|
||||
.IP
|
||||
\-t raw \-A PREROUTING \-p tcp \-\-dport 6667 \-j NOTRACK
|
||||
\-t raw \-A PREROUTING \-p tcp \-\-dport 6667 \-j CT \-\-notrack
|
||||
.IP
|
||||
\-A INPUT \-p tcp \-\-dport 6667 \-j NFLOG
|
||||
.IP
|
||||
\-A INPUT \-p tcp \-\-dport 6667 \-j TARPIT
|
||||
|
@@ -21,7 +21,7 @@ Known symbol names (and their number):
|
||||
.PP
|
||||
4 \(em \fBtimestamp\fP \(em RFC 781, 791
|
||||
.PP
|
||||
7 \(em \fBrecord\-route\fP \em RFC 791
|
||||
7 \(em \fBrecord\-route\fP \(em RFC 791
|
||||
.PP
|
||||
9 \(em \fBssrr\fP \(em Strict Source Routing, RFC 791
|
||||
.PP
|
||||
|
@@ -881,7 +881,7 @@ update_peer(struct peer *peer, const struct xt_pknock_mtinfo *info,
|
||||
|
||||
/* If security is needed. */
|
||||
if (info->option & XT_PKNOCK_OPENSECRET ) {
|
||||
if (hdr->proto != IPPROTO_UDP)
|
||||
if (hdr->proto != IPPROTO_UDP && hdr->proto != IPPROTO_UDPLITE)
|
||||
return false;
|
||||
|
||||
if (!pass_security(peer, info, hdr->payload, hdr->payload_len))
|
||||
@@ -982,6 +982,7 @@ static bool pknock_mt(const struct sk_buff *skb,
|
||||
break;
|
||||
|
||||
case IPPROTO_UDP:
|
||||
case IPPROTO_UDPLITE:
|
||||
#ifdef PK_CRYPTO
|
||||
hdr_len = (iph->ihl * 4) + sizeof(struct udphdr);
|
||||
break;
|
||||
@@ -1013,7 +1014,7 @@ static bool pknock_mt(const struct sk_buff *skb,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (iph->protocol == IPPROTO_UDP) {
|
||||
if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_UDPLITE) {
|
||||
hdr.payload = (void *)iph + hdr_len;
|
||||
hdr.payload_len = skb->len - hdr_len;
|
||||
}
|
||||
@@ -1022,7 +1023,8 @@ static bool pknock_mt(const struct sk_buff *skb,
|
||||
if (info->option & XT_PKNOCK_KNOCKPORT) {
|
||||
if ((ret = is_allowed(peer))) {
|
||||
if (info->option & XT_PKNOCK_CLOSESECRET &&
|
||||
iph->protocol == IPPROTO_UDP)
|
||||
(iph->protocol == IPPROTO_UDP ||
|
||||
iph->protocol == IPPROTO_UDPLITE))
|
||||
{
|
||||
if (is_close_knock(peer, info, hdr.payload, hdr.payload_len))
|
||||
{
|
||||
|
@@ -12,6 +12,13 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
|
||||
# error ----------------------------------------------------------
|
||||
# error This module has been merged into, and is available in the
|
||||
# error mainline since Linux kernel v2.6.36. Please use that.
|
||||
# error ----------------------------------------------------------
|
||||
#endif
|
||||
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
#include "xt_CHECKSUM.h"
|
||||
#include "compat_xtables.h"
|
||||
|
@@ -29,6 +29,38 @@ static const char *const dir_names[] = {
|
||||
"ORIGINAL", "REPLY",
|
||||
};
|
||||
|
||||
static void logmark_ct(const struct nf_conn *ct, enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
bool prev = false;
|
||||
|
||||
printk(" ct=0x%p ctmark=0x%x ctstate=", ct, ct->mark);
|
||||
ctinfo %= IP_CT_IS_REPLY;
|
||||
if (ctinfo == IP_CT_NEW)
|
||||
printk("NEW");
|
||||
else if (ctinfo == IP_CT_ESTABLISHED)
|
||||
printk("ESTABLISHED");
|
||||
else if (ctinfo == IP_CT_RELATED)
|
||||
printk("RELATED");
|
||||
if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
|
||||
printk(",SNAT");
|
||||
if (test_bit(IPS_DST_NAT_BIT, &ct->status))
|
||||
printk(",DNAT");
|
||||
|
||||
printk(" ctstatus=");
|
||||
if (ct->status & IPS_EXPECTED) {
|
||||
printk("EXPECTED");
|
||||
prev = true;
|
||||
}
|
||||
if (ct->status & IPS_SEEN_REPLY)
|
||||
printk("%s""SEEN_REPLY", prev++ ? "," : "");
|
||||
if (ct->status & IPS_ASSURED)
|
||||
printk("%s""ASSURED", prev++ ? "," : "");
|
||||
if (ct->status & IPS_CONFIRMED)
|
||||
printk("%s""CONFIRMED", prev++ ? "," : "");
|
||||
printk(" lifetime=%lus",
|
||||
(jiffies - ct->timeout.expires) / HZ);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
logmark_tg(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
{
|
||||
@@ -36,7 +68,6 @@ logmark_tg(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
const struct xt_logmark_tginfo *info = par->targinfo;
|
||||
const struct nf_conn *ct;
|
||||
enum ip_conntrack_info ctinfo;
|
||||
bool prev = false;
|
||||
|
||||
printk("<%u>%.*s""iif=%d hook=%s nfmark=0x%x "
|
||||
"secmark=0x%x classify=0x%x",
|
||||
@@ -46,43 +77,17 @@ logmark_tg(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
printk(" ctdir=%s", dir_names[ctinfo >= IP_CT_IS_REPLY]);
|
||||
if (ct == NULL) {
|
||||
if (ct == NULL)
|
||||
printk(" ct=NULL ctmark=NULL ctstate=INVALID ctstatus=NONE");
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
|
||||
} else if (nf_ct_is_untracked(ct)) {
|
||||
else if (nf_ct_is_untracked(ct))
|
||||
printk(" ct=UNTRACKED ctmark=NULL ctstate=UNTRACKED ctstatus=NONE");
|
||||
#else
|
||||
} else if (ct == &nf_conntrack_untracked) {
|
||||
else if (ct == &nf_conntrack_untracked)
|
||||
printk(" ct=UNTRACKED ctmark=NULL ctstate=UNTRACKED ctstatus=NONE");
|
||||
#endif
|
||||
} else {
|
||||
printk(" ct=0x%p ctmark=0x%x ctstate=", ct, ct->mark);
|
||||
ctinfo %= IP_CT_IS_REPLY;
|
||||
if (ctinfo == IP_CT_NEW)
|
||||
printk("NEW");
|
||||
else if (ctinfo == IP_CT_ESTABLISHED)
|
||||
printk("ESTABLISHED");
|
||||
else if (ctinfo == IP_CT_RELATED)
|
||||
printk("RELATED");
|
||||
if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
|
||||
printk(",SNAT");
|
||||
if (test_bit(IPS_DST_NAT_BIT, &ct->status))
|
||||
printk(",DNAT");
|
||||
|
||||
printk(" ctstatus=");
|
||||
if (ct->status & IPS_EXPECTED) {
|
||||
printk("EXPECTED");
|
||||
prev = true;
|
||||
}
|
||||
if (ct->status & IPS_SEEN_REPLY)
|
||||
printk("%s""SEEN_REPLY", prev++ ? "," : "");
|
||||
if (ct->status & IPS_ASSURED)
|
||||
printk("%s""ASSURED", prev++ ? "," : "");
|
||||
if (ct->status & IPS_CONFIRMED)
|
||||
printk("%s""CONFIRMED", prev++ ? "," : "");
|
||||
printk(" lifetime=%lus",
|
||||
(jiffies - ct->timeout.expires) / HZ);
|
||||
}
|
||||
else
|
||||
logmark_ct(ct, ctinfo);
|
||||
|
||||
printk("\n");
|
||||
return XT_CONTINUE;
|
||||
|
@@ -1,9 +1,11 @@
|
||||
/*
|
||||
* "SYSRQ" target extension for Netfilter
|
||||
* "SYSRQ" target extension for Xtables
|
||||
* Copyright © Jan Engelhardt <jengelh [at] medozas de>, 2008 - 2010
|
||||
*
|
||||
* Based upon the ipt_SYSRQ idea by Marek Zalem <marek [at] terminus sk>
|
||||
*
|
||||
* Security additions John Haxby <john.haxby [at] oracle com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 or 3 as published by the Free Software Foundation.
|
||||
@@ -58,13 +60,13 @@ static char *sysrq_hexdigest;
|
||||
* is a series of sysrq requests; <seqno> is a sequence number that must be
|
||||
* greater than the last sequence number; <salt> is some random bytes; and
|
||||
* <hash> is the hash of everything up to and including the preceding ","
|
||||
* together with the password.
|
||||
* together with "<dstaddr>,<password>".
|
||||
*
|
||||
* For example
|
||||
*
|
||||
* salt=$RANDOM
|
||||
* req="s,$(date +%s),$salt"
|
||||
* echo "$req,$(echo -n $req,secret | sha1sum | cut -c1-40)"
|
||||
* echo "$req,$(echo -n $req,10.10.25.1,secret | sha1sum | cut -c1-40)"
|
||||
*
|
||||
* You will want a better salt and password than that though :-)
|
||||
*/
|
||||
@@ -121,7 +123,6 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len)
|
||||
sg_init_table(sg, 2);
|
||||
#endif
|
||||
sg_set_buf(&sg[0], data, n);
|
||||
strcpy(sysrq_digest_password, sysrq_password);
|
||||
i = strlen(sysrq_digest_password);
|
||||
sg_set_buf(&sg[1], sysrq_digest_password, i);
|
||||
ret = crypto_hash_digest(&desc, sg, n + i, sysrq_digest);
|
||||
@@ -223,6 +224,8 @@ sysrq_tg4(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
": " NIPQUAD_FMT ":%u -> :%u len=%u\n",
|
||||
NIPQUAD(iph->saddr), htons(udph->source),
|
||||
htons(udph->dest), len);
|
||||
sprintf(sysrq_digest_password, NIPQUAD_FMT ",%s",
|
||||
NIPQUAD(iph->daddr), sysrq_password);
|
||||
return sysrq_tg((void *)udph + sizeof(struct udphdr), len);
|
||||
}
|
||||
|
||||
@@ -241,7 +244,8 @@ sysrq_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
return NF_DROP;
|
||||
|
||||
iph = ipv6_hdr(skb);
|
||||
if (ipv6_find_hdr(skb, &th_off, IPPROTO_UDP, &frag_off) < 0 ||
|
||||
if ((ipv6_find_hdr(skb, &th_off, IPPROTO_UDP, &frag_off) < 0 &&
|
||||
ipv6_find_hdr(skb, &th_off, IPPROTO_UDPLITE, &frag_off) < 0) ||
|
||||
frag_off > 0)
|
||||
return NF_DROP;
|
||||
|
||||
@@ -253,7 +257,9 @@ sysrq_tg6(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
": " NIP6_FMT ":%hu -> :%hu len=%u\n",
|
||||
NIP6(iph->saddr), ntohs(udph->source),
|
||||
ntohs(udph->dest), len);
|
||||
return sysrq_tg(udph + sizeof(struct udphdr), len);
|
||||
sprintf(sysrq_digest_password, NIP6_FMT ",%s",
|
||||
NIP6(iph->daddr), sysrq_password);
|
||||
return sysrq_tg((void *)udph + sizeof(struct udphdr), len);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -340,7 +346,9 @@ static int __init sysrq_crypto_init(void)
|
||||
sysrq_hexdigest = kmalloc(2 * sysrq_digest_size + 1, GFP_KERNEL);
|
||||
if (sysrq_hexdigest == NULL)
|
||||
goto fail;
|
||||
sysrq_digest_password = kmalloc(sizeof(sysrq_password), GFP_KERNEL);
|
||||
sysrq_digest_password =
|
||||
kmalloc(sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255") +
|
||||
sizeof(sysrq_password), GFP_KERNEL);
|
||||
if (sysrq_digest_password == NULL)
|
||||
goto fail;
|
||||
do_gettimeofday(&now);
|
||||
@@ -376,6 +384,7 @@ module_init(sysrq_tg_init);
|
||||
module_exit(sysrq_tg_exit);
|
||||
MODULE_DESCRIPTION("Xtables: triggering SYSRQ remotely");
|
||||
MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
|
||||
MODULE_AUTHOR("John Haxby <john.haxby@oracle.com");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("ipt_SYSRQ");
|
||||
MODULE_ALIAS("ip6t_SYSRQ");
|
||||
|
@@ -13,4 +13,10 @@ config NETFILTER_XT_TARGET_TARPIT
|
||||
This offers similar functionality to LaBrea
|
||||
<http://www.hackbusters.net/LaBrea/>, but does not require dedicated
|
||||
hardware or IPs. Any TCP port that you would normally DROP or REJECT
|
||||
can instead become a tar pit.
|
||||
can instead become a tar pit or honeypot. All 3 modes may be used
|
||||
in iptables rules interchangably and simultaneously.
|
||||
|
||||
A honeypot option is available which will answer connections normally
|
||||
and allow the remote to send data packets that may be captured in a
|
||||
pcap for later analysis. A reset mode is also available that will only
|
||||
send an inline reset (RST).
|
||||
|
@@ -48,14 +48,17 @@
|
||||
#include <net/route.h>
|
||||
#include <net/tcp.h>
|
||||
#include "compat_xtables.h"
|
||||
#include "xt_TARPIT.h"
|
||||
|
||||
static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook,
|
||||
unsigned int mode)
|
||||
{
|
||||
struct tcphdr _otcph, *oth, *tcph;
|
||||
unsigned int addr_type = RTN_UNSPEC;
|
||||
struct sk_buff *nskb;
|
||||
const struct iphdr *oldhdr;
|
||||
struct iphdr *niph;
|
||||
u_int16_t tmp;
|
||||
uint16_t tmp, payload;
|
||||
|
||||
/* A truncated TCP header is not going to be useful */
|
||||
if (oldskb->len < ip_hdrlen(oldskb) + sizeof(struct tcphdr))
|
||||
@@ -66,17 +69,6 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
if (oth == NULL)
|
||||
return;
|
||||
|
||||
/* No replies for RST, FIN or !SYN,!ACK */
|
||||
if (oth->rst || oth->fin || (!oth->syn && !oth->ack))
|
||||
return;
|
||||
|
||||
/* Rate-limit replies to !SYN,ACKs */
|
||||
#if 0
|
||||
if (!oth->syn && oth->ack)
|
||||
if (!xrlim_allow(rt_dst(ort), HZ))
|
||||
return;
|
||||
#endif
|
||||
|
||||
/* Check checksum. */
|
||||
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
|
||||
return;
|
||||
@@ -102,6 +94,7 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
skb_shinfo(nskb)->gso_type = 0;
|
||||
#endif
|
||||
|
||||
oldhdr = ip_hdr(oldskb);
|
||||
tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));
|
||||
|
||||
/* Swap source and dest */
|
||||
@@ -111,28 +104,94 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
tcph->source = tcph->dest;
|
||||
tcph->dest = tmp;
|
||||
|
||||
/* Calculate payload size?? */
|
||||
payload = nskb->len - ip_hdrlen(nskb) - sizeof(struct tcphdr);
|
||||
|
||||
/* Truncate to length (no data) */
|
||||
tcph->doff = sizeof(struct tcphdr) / 4;
|
||||
skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
|
||||
niph->tot_len = htons(nskb->len);
|
||||
|
||||
/* Use supplied sequence number or make a new one */
|
||||
tcph->seq = oth->ack ? oth->ack_seq : 0;
|
||||
|
||||
/* Our SYN-ACKs must have a >0 window */
|
||||
tcph->window = (oth->syn && !oth->ack) ? htons(5) : 0;
|
||||
tcph->urg_ptr = 0;
|
||||
|
||||
/* Reset flags */
|
||||
((u_int8_t *)tcph)[13] = 0;
|
||||
|
||||
if (oth->syn && oth->ack) {
|
||||
if (mode == XTTARPIT_TARPIT) {
|
||||
/* No replies for RST, FIN or !SYN,!ACK */
|
||||
if (oth->rst || oth->fin || (!oth->syn && !oth->ack))
|
||||
return;
|
||||
tcph->seq = oth->ack ? oth->ack_seq : 0;
|
||||
|
||||
/* Our SYN-ACKs must have a >0 window */
|
||||
tcph->window = (oth->syn && !oth->ack) ? htons(5) : 0;
|
||||
if (oth->syn && oth->ack) {
|
||||
tcph->rst = true;
|
||||
tcph->ack_seq = false;
|
||||
} else {
|
||||
tcph->syn = oth->syn;
|
||||
tcph->ack = true;
|
||||
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
|
||||
}
|
||||
#if 0
|
||||
/* Rate-limit replies to !SYN,ACKs */
|
||||
if (!oth->syn && oth->ack)
|
||||
if (!xrlim_allow(rt_dst(ort), HZ))
|
||||
return;
|
||||
#endif
|
||||
} else if (mode == XTTARPIT_HONEYPOT) {
|
||||
/* Do not answer any resets regardless of combination */
|
||||
if (oth->rst || oth->seq == 0xDEADBEEF)
|
||||
return;
|
||||
/* Send a reset to scanners. They like that. */
|
||||
if (oth->syn && oth->ack) {
|
||||
tcph->window = 0;
|
||||
tcph->ack = false;
|
||||
tcph->psh = true;
|
||||
tcph->ack_seq = 0xdeadbeef; /* see if they ack it */
|
||||
tcph->seq = oth->ack_seq;
|
||||
tcph->rst = true;
|
||||
}
|
||||
|
||||
/* SYN > SYN-ACK */
|
||||
if (oth->syn && !oth->ack) {
|
||||
tcph->syn = true;
|
||||
tcph->ack = true;
|
||||
tcph->window = oth->window &
|
||||
((net_random() & 0x1f) - 0xf);
|
||||
tcph->seq = htonl(net_random() & ~oth->seq);
|
||||
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
|
||||
}
|
||||
|
||||
/* ACK > ACK */
|
||||
if (oth->ack && (!(oth->fin || oth->syn))) {
|
||||
tcph->syn = false;
|
||||
tcph->ack = true;
|
||||
tcph->window = oth->window &
|
||||
((net_random() & 0x1f) - 0xf);
|
||||
tcph->ack_seq = payload > 100 ?
|
||||
htonl(ntohl(oth->seq) + payload) :
|
||||
oth->seq;
|
||||
tcph->seq = oth->ack_seq;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIN > RST.
|
||||
* We cannot terminate gracefully so just be abrupt.
|
||||
*/
|
||||
if (oth->fin) {
|
||||
tcph->window = 0;
|
||||
tcph->seq = oth->ack_seq;
|
||||
tcph->ack_seq = oth->ack_seq;
|
||||
tcph->fin = false;
|
||||
tcph->ack = false;
|
||||
tcph->rst = true;
|
||||
}
|
||||
} else if (mode == XTTARPIT_RESET) {
|
||||
tcph->window = 0;
|
||||
tcph->ack = false;
|
||||
tcph->syn = false;
|
||||
tcph->rst = true;
|
||||
tcph->ack_seq = false;
|
||||
} else {
|
||||
tcph->syn = oth->syn;
|
||||
tcph->ack = 1;
|
||||
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn);
|
||||
tcph->seq = oth->ack_seq;
|
||||
tcph->ack_seq = oth->seq;
|
||||
}
|
||||
|
||||
/* Adjust TCP checksum */
|
||||
@@ -149,7 +208,10 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
|
||||
/* Set DF, id = 0 */
|
||||
niph->frag_off = htons(IP_DF);
|
||||
niph->id = 0;
|
||||
if (mode == XTTARPIT_TARPIT || mode == XTTARPIT_RESET)
|
||||
niph->id = 0;
|
||||
else if (mode == XTTARPIT_HONEYPOT)
|
||||
niph->id = ~oldhdr->id + 1;
|
||||
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
|
||||
@@ -167,7 +229,14 @@ static void tarpit_tcp(struct sk_buff *oldskb, unsigned int hook)
|
||||
nskb->ip_summed = CHECKSUM_NONE;
|
||||
|
||||
/* Adjust IP TTL */
|
||||
niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
|
||||
if (mode == XTTARPIT_HONEYPOT)
|
||||
niph->ttl = 128;
|
||||
else
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
|
||||
niph->ttl = ip4_dst_hoplimit(skb_dst(nskb));
|
||||
#else
|
||||
niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT);
|
||||
#endif
|
||||
|
||||
/* Adjust IP checksum */
|
||||
niph->check = 0;
|
||||
@@ -193,6 +262,7 @@ tarpit_tg(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
const struct sk_buff *skb = *pskb;
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
const struct rtable *rt = skb_rtable(skb);
|
||||
const struct xt_tarpit_tginfo *info = par->targinfo;
|
||||
|
||||
/* Do we have an input route cache entry? (Not in PREROUTING.) */
|
||||
if (rt == NULL)
|
||||
@@ -218,19 +288,19 @@ tarpit_tg(struct sk_buff **pskb, const struct xt_action_param *par)
|
||||
if (iph->frag_off & htons(IP_OFFSET))
|
||||
return NF_DROP;
|
||||
|
||||
tarpit_tcp(*pskb, par->hooknum);
|
||||
tarpit_tcp(*pskb, par->hooknum, info->variant);
|
||||
return NF_DROP;
|
||||
}
|
||||
|
||||
static struct xt_target tarpit_tg_reg __read_mostly = {
|
||||
.name = "TARPIT",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.table = "filter",
|
||||
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
|
||||
.proto = IPPROTO_TCP,
|
||||
.target = tarpit_tg,
|
||||
.me = THIS_MODULE,
|
||||
.name = "TARPIT",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_IPV4,
|
||||
.hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
|
||||
.proto = IPPROTO_TCP,
|
||||
.target = tarpit_tg,
|
||||
.targetsize = sizeof(struct xt_tarpit_tginfo),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init tarpit_tg_init(void)
|
||||
|
14
extensions/xt_TARPIT.h
Normal file
14
extensions/xt_TARPIT.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef _LINUX_NETFILTER_XT_TARPIT_H
|
||||
#define _LINUX_NETFILTER_XT_TARPIT_H 1
|
||||
|
||||
enum xt_tarpit_target_variant {
|
||||
XTTARPIT_TARPIT,
|
||||
XTTARPIT_HONEYPOT,
|
||||
XTTARPIT_RESET,
|
||||
};
|
||||
|
||||
struct xt_tarpit_tginfo {
|
||||
uint8_t variant;
|
||||
};
|
||||
|
||||
#endif /* _LINUX_NETFILTER_XT_TARPIT_H */
|
@@ -14,6 +14,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/route.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/checksum.h>
|
||||
#include <net/icmp.h>
|
||||
#include <net/ip.h>
|
||||
@@ -21,6 +22,13 @@
|
||||
#include <net/route.h>
|
||||
#include <linux/netfilter/x_tables.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)
|
||||
# error ----------------------------------------------------------
|
||||
# error This module has been merged into, and is available in the
|
||||
# error mainline since Linux kernel v2.6.35. Please use that.
|
||||
# error ----------------------------------------------------------
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
|
||||
# define WITH_CONNTRACK 1
|
||||
# include <net/netfilter/nf_conntrack.h>
|
||||
|
@@ -167,16 +167,20 @@ static bool geoip_bsearch6(const struct geoip_subnet6 *range,
|
||||
{
|
||||
int mid;
|
||||
|
||||
if (hi <= lo)
|
||||
return false;
|
||||
mid = (lo + hi) / 2;
|
||||
if (ipv6_cmp(&range[mid].begin, addr) <= 0 &&
|
||||
ipv6_cmp(addr, &range[mid].end) <= 0)
|
||||
return true;
|
||||
if (ipv6_cmp(&range[mid].begin, addr) > 0)
|
||||
return geoip_bsearch6(range, addr, lo, mid);
|
||||
else if (ipv6_cmp(&range[mid].end, addr) < 0)
|
||||
return geoip_bsearch6(range, addr, mid + 1, hi);
|
||||
while (true) {
|
||||
if (hi <= lo)
|
||||
return false;
|
||||
mid = (lo + hi) / 2;
|
||||
if (ipv6_cmp(&range[mid].begin, addr) <= 0 &&
|
||||
ipv6_cmp(addr, &range[mid].end) <= 0)
|
||||
return true;
|
||||
if (ipv6_cmp(&range[mid].begin, addr) > 0)
|
||||
hi = mid;
|
||||
else if (ipv6_cmp(&range[mid].end, addr) < 0)
|
||||
lo = mid + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
WARN_ON(true);
|
||||
return false;
|
||||
@@ -218,15 +222,19 @@ static bool geoip_bsearch4(const struct geoip_subnet4 *range,
|
||||
{
|
||||
int mid;
|
||||
|
||||
if (hi <= lo)
|
||||
return false;
|
||||
mid = (lo + hi) / 2;
|
||||
if (range[mid].begin <= addr && addr <= range[mid].end)
|
||||
return true;
|
||||
if (range[mid].begin > addr)
|
||||
return geoip_bsearch4(range, addr, lo, mid);
|
||||
else if (range[mid].end < addr)
|
||||
return geoip_bsearch4(range, addr, mid + 1, hi);
|
||||
while (true) {
|
||||
if (hi <= lo)
|
||||
return false;
|
||||
mid = (lo + hi) / 2;
|
||||
if (range[mid].begin <= addr && addr <= range[mid].end)
|
||||
return true;
|
||||
if (range[mid].begin > addr)
|
||||
hi = mid;
|
||||
else if (range[mid].end < addr)
|
||||
lo = mid + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
WARN_ON(true);
|
||||
return false;
|
||||
|
@@ -868,6 +868,7 @@ ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
|
||||
}
|
||||
|
||||
case IPPROTO_UDP: /* what to do with an UDP packet */
|
||||
case IPPROTO_UDPLITE:
|
||||
{
|
||||
const struct udphdr *udph = (const void *)ip + ip_hdrlen(skb);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* xt_ipv4opts - Netfilter module to match IPv4 options
|
||||
* xt_ipv4opts - Xtables module to match IPv4 options
|
||||
* Copyright © Jan Engelhardt, 2009
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* xt_length - Netfilter module to match packet length
|
||||
* xt_length - Xtables module to match packet length
|
||||
* Copyright © Jan Engelhardt <jengelh@medozas.de>, 2007 - 2009
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* LSCAN match for netfilter
|
||||
* LSCAN match for Xtables
|
||||
* Copyright © Jan Engelhardt, 2006 - 2009
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -103,8 +103,12 @@ static bool
|
||||
xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
|
||||
{
|
||||
const struct iphdr *iph;
|
||||
const struct tcphdr *tcph;
|
||||
struct tcphdr _tcph;
|
||||
const struct tcphdr *tcph = NULL;
|
||||
const struct udphdr *udph;
|
||||
union {
|
||||
struct tcphdr tcph;
|
||||
struct udphdr udph;
|
||||
} _buf;
|
||||
struct in_addr addr;
|
||||
u_int16_t src_port,dest_port;
|
||||
u_int8_t tcp_flags, proto;
|
||||
@@ -125,29 +129,9 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
|
||||
|
||||
/* TCP or UDP ? */
|
||||
proto = iph->protocol;
|
||||
|
||||
if (proto != IPPROTO_TCP && proto != IPPROTO_UDP) {
|
||||
pr_debug("protocol not supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get the source address, source & destination ports, and TCP flags */
|
||||
|
||||
addr.s_addr = iph->saddr;
|
||||
|
||||
tcph = skb_header_pointer(pskb, match->thoff, sizeof(_tcph), &_tcph);
|
||||
if (tcph == NULL)
|
||||
return false;
|
||||
|
||||
/* Yep, it's dirty */
|
||||
src_port = tcph->source;
|
||||
dest_port = tcph->dest;
|
||||
|
||||
if (proto == IPPROTO_TCP)
|
||||
tcp_flags = *((u_int8_t*)tcph + 13);
|
||||
else
|
||||
tcp_flags = 0x00;
|
||||
|
||||
/* We're using IP address 0.0.0.0 for a special purpose here, so don't let
|
||||
* them spoof us. [DHCP needs this feature - HW] */
|
||||
if (addr.s_addr == 0) {
|
||||
@@ -155,6 +139,29 @@ xt_psd_match(const struct sk_buff *pskb, struct xt_action_param *match)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (proto == IPPROTO_TCP) {
|
||||
tcph = skb_header_pointer(pskb, match->thoff,
|
||||
sizeof(_buf.tcph), &_buf.tcph);
|
||||
if (tcph == NULL)
|
||||
return false;
|
||||
|
||||
/* Yep, it's dirty */
|
||||
src_port = tcph->source;
|
||||
dest_port = tcph->dest;
|
||||
tcp_flags = *((u_int8_t*)tcph + 13);
|
||||
} else if (proto == IPPROTO_UDP || proto == IPPROTO_UDPLITE) {
|
||||
udph = skb_header_pointer(pskb, match->thoff,
|
||||
sizeof(_buf.udph), &_buf.udph);
|
||||
if (udph == NULL)
|
||||
return false;
|
||||
src_port = udph->source;
|
||||
dest_port = udph->dest;
|
||||
tcp_flags = 0;
|
||||
} else {
|
||||
pr_debug("protocol not supported\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Use jiffies here not to depend on someone setting the time while we're
|
||||
* running; we need to be careful with possible return value overflows. */
|
||||
now = jiffies;
|
||||
|
@@ -4,7 +4,7 @@
|
||||
* by Jan Engelhardt <jengelh@medozas.de>, 2008
|
||||
*
|
||||
* Originally based on xt_quota.c:
|
||||
* netfilter module to enforce network quotas
|
||||
* Xtables module to enforce network quotas
|
||||
* Sam Johnston <samj@samj.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
4
mconfig
4
mconfig
@@ -20,8 +20,8 @@ build_geoip=m
|
||||
build_gradm=m
|
||||
build_iface=m
|
||||
build_ipp2p=m
|
||||
build_ipset4=m
|
||||
build_ipset6=
|
||||
build_ipset4=
|
||||
build_ipset6=m
|
||||
build_ipv4options=m
|
||||
build_length2=m
|
||||
build_lscan=m
|
||||
|
@@ -1,12 +1,12 @@
|
||||
.TH xtables-addons 8 "v1.32 (2011-01-04)" "" "v1.32 (2011-01-04)"
|
||||
.TH xtables-addons 8 "v1.38 (2011-08-20)" "" "v1.38 (2011-08-20)"
|
||||
.SH Name
|
||||
Xtables-addons \(em additional extensions for iptables, ip6tables, etc.
|
||||
.SH Targets
|
||||
.\" @TARGET@
|
||||
.SH Matches
|
||||
.\" @MATCHES@
|
||||
.SH "SEE ALSO"
|
||||
\fBiptables\fP(8), \fBip6tables\fP(8)
|
||||
.SH "See also"
|
||||
\fBiptables\fP(8), \fBip6tables\fP(8), \fBiptaccount\fP(8)
|
||||
.PP
|
||||
For developers, the book "Writing Netfilter modules" at
|
||||
http://jengelh.medozas.de/documents/Netfilter_Modules.pdf provides detailed
|
||||
|
Reference in New Issue
Block a user