Compare commits

..

3 Commits
v3.18 ... v2.15

Author SHA1 Message Date
Jan Engelhardt
47f5391a37 Xtables-addons 2.15 2021-02-05 19:02:49 +01:00
Jan Engelhardt
16a64492ae xt_lscan: add --mirai option 2021-02-05 19:00:13 +01:00
Jan Engelhardt
cdcf874366 xt_lscan: extend info struct to support more flags (without size change) 2021-01-20 03:09:52 +01:00
54 changed files with 824 additions and 1418 deletions

2
.gitignore vendored
View File

@@ -2,9 +2,7 @@
*.la
*.lo
*.loT
*.mod
*.o
.cache.mk
.deps/
.dirstamp
.libs/

View File

@@ -12,17 +12,16 @@ in combination with the kernel's Kbuild system.
Supported configurations for this release
=========================================
* iptables >= 1.6.0
* iptables >= 1.4.5
* kernel-devel >= 4.15
* kernel-devel >= 3.7
with prepared build/output directory
- CONFIG_NF_CONNTRACK
- CONFIG_NF_CONNTRACK_MARK enabled =y or as module (=m)
- CONFIG_CONNECTOR y/m if you wish to receive userspace
notifications from pknock through netlink/connector
(Use xtables-addons-1.x if you need support for Linux < 3.7.
Use xtables-addons-2.x if you need support for Linux < 4.15.)
(Use xtables-addons-1.x if you need support for Linux < 3.7.)
Selecting extensions

View File

@@ -1,7 +1,7 @@
# -*- Makefile -*-
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = extensions extensions/ACCOUNT extensions/pknock geoip
SUBDIRS = extensions geoip
man_MANS := xtables-addons.8

View File

@@ -40,4 +40,4 @@ targets.man: .manpages.lst ${wcman_targets}
$(call man_run,${wlist_targets})
clean:
rm -f xtables-addons.8 matches.man targets.man .manpages.lst
rm -f xtables-addons.8 matches.man targets.man

54
README
View File

@@ -1,15 +1,57 @@
Xtables-addons
==============
Xtables-addons is a set of extensions that were not accepted in the
Linux kernel and/or main Xtables/iptables package.
Xtables-addons is the proclaimed successor to patch-o-matic(-ng). It
contains extensions that were not accepted in the main Xtables
package.
It superseded the earlier patch-o-matic(-ng) package in that no
patching and/or recompilation of either the kernel or
Xtables/iptables is required. However, do see the INSTALL file for
the minimum requirements of Xtables-addons.
Xtables-addons is different from patch-o-matic in that you do not
have to patch or recompile either kernel or Xtables(iptables). But
please see the INSTALL file for the minimum requirements of this
package.
All code imported from patch-o-matic has been reviewed and all
apparent bugs like binary stability across multiarches, missing
sanity checks and incorrect endianess handling have been fixed,
simplified, and sped up.
Included in this package
========================
- xt_ACCOUNT 1.16, libxt_ACCOUNT 1.3
Inclusion into a kernel tree
============================
External extensions
===================
The program "xa-download-more" can be used to download more
extensions from 3rd parties into the source tree. The URLs are listed
in the "sources" file. If the "sources" file contains an entry like
http://foobar.org/xa/
xa-download-more will inspect http://foobar.org/xa/xa-index.txt for
files to download. That file may contain
foobar.tar.bz2
and xa-download-more will then retrieve and unpack
http://foobar.org/xa/foobar.tar.bz2.
Files that should be contained in the tarball are an mconfig and
Kbuild files to control building the extension, libxt_foobar.c for
the userspace extension and xt_foobar.c for the kernel extension.
mconfig.foobar
extensions/Kbuild.foobar
extensions/Mbuild.foobar
extensions/libxt_foobar.c
extensions/libxt_foobar.man
extensions/xt_foobar.c
extensions/xt_foobar.h

View File

@@ -1,4 +1,4 @@
AC_INIT([xtables-addons], [3.18])
AC_INIT([xtables-addons], [2.15])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([m4])
@@ -26,8 +26,8 @@ fi
AC_CHECK_HEADERS([linux/netfilter/x_tables.h], [],
[AC_MSG_ERROR([You need to have linux/netfilter/x_tables.h, see INSTALL file for details])])
PKG_CHECK_MODULES([libxtables], [xtables >= 1.6.0])
xtlibdir="$($PKG_CONFIG --variable=xtlibdir xtables)"
PKG_CHECK_MODULES([libxtables], [xtables >= 1.4.5])
xtlibdir="$(pkg-config --variable=xtlibdir xtables)"
AC_ARG_WITH([xtlibdir],
AS_HELP_STRING([--with-xtlibdir=PATH],
@@ -57,12 +57,12 @@ 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 5 -o "$kmajor" -eq 5 -a "$kminor" -gt 11; then
if test "$kmajor" -gt 4 -o "$kmajor" -eq 4 -a "$kminor" -gt 12; then
echo "WARNING: That kernel version is not officially supported yet. Continue at own luck.";
elif test "$kmajor" -eq 5 -a "$kminor" -ge 0; then
:
elif test "$kmajor" -eq 4 -a "$kminor" -ge 15; then
:
elif test "$kmajor" -eq 4 -a "$kminor" -le 10; then
:;
elif test "$kmajor" -eq 3 -a "$kminor" -ge 7; then
:;
else
echo "WARNING: That kernel version is not officially supported.";
fi;

View File

@@ -1,117 +1,9 @@
v3.18 (2021-03-11)
v2.15 (2021-02-05)
==================
- xt_pknock: fix a build failure on ARM 32-bit
v3.17 (2021-02-28)
==================
- xt_pknock: cure a NULL deref
v3.16 (2021-02-24)
==================
- xt_pknock: build fix for ILP32 targets
v3.15 (2021-02-05)
==================
- xt_ECHO: support new function signature of security_skb_classify_flow
Enhancements:
- support for Linux up to 4.15
- xt_lscan: add --mirai option
- Support for Linux 5.11
v3.14 (2020-11-24)
==================
- DELUDE, ECHO, TARPIT: use actual tunnel socket (ip_route_me_harder).
- geoip: scripts for use with MaxMind DB have been brought back,
partly under new names.
- Gave xt_geoip_fetch a more fitting name, xt_geoip_query.
v3.13 (2020-11-20)
==================
- Support for Linux 4.19.158 and 5.4.78 (ip_route_me_harder)
v3.12 (2020-11-19)
==================
- Support for Linux 5.10 and 5.9.9 API
(changes to ip_route_me_harder there)
v3.11 (2020-09-06)
==================
- Support for up to Linux 5.9
v3.10 (2020-07-28)
==================
- Support for up to Linux 5.8
v3.9 (2020-02-25)
=================
- Support for Linux 5.6 procfs changes
v3.8 (2020-02-03)
=================
- Support for Linux 5.5
- xt_geoip_build now expects the DBIP format as input,
Maxmind is thrown out.
v3.7 (2019-12-01)
=================
Fixes:
- xt_geoip: fix in6_addr little-endian byte swapping
v3.6 (2019-11-20)
=================
Enhancements:
- support for up to Linux 5.4
v3.5 (2019-09-10)
=================
Enhancements:
- xt_DELUDE, xt_TARPIT: added additional code needed to work with
bridges from Linux 5.0 onwards.
v3.4 (2019-09-06)
=================
Enhancements:
- support for up to Linux 5.3
- xt_PROTO module
v3.3 (2019-03-07)
=================
Enhancements:
- support for Linux 5.0
v3.2 (2018-09-07)
=================
Changes:
- rework xt_geoip_build to scan the immediate directory for .csv,
not to scan for GeoLite2-Country-CSV_\d+.
v3.1 (2018-08-14)
=================
Enhancements:
- support for Linux 4.17, 4.18
v3.0 (2018-02-12)
=================
Enhancements:
- support for Linux 4.15, 4.16
Changes:
- remove support for Linux 3.7--4.14
v2.14 (2017-11-22)
@@ -238,5 +130,5 @@ Changes:
Enhancements:
- Support for Linux 3.7
If you want to use Xtables-addons with kernels older than 4.15,
use the addons 2.x series.
If you want to use Xtables-addons with kernels older than 3.7,
use the addons 1.x series (maintained but without new features).

View File

@@ -34,8 +34,7 @@ int ipt_ACCOUNT_init(struct ipt_ACCOUNT_context *ctx)
// 4096 bytes default buffer should save us from reallocations
// as it fits 200 concurrent active clients
ctx->data = malloc(IPT_ACCOUNT_MIN_BUFSIZE);
if (ctx->data == NULL) {
if ((ctx->data = malloc(IPT_ACCOUNT_MIN_BUFSIZE)) == NULL) {
close(ctx->sockfd);
ctx->sockfd = -1;
ctx->error_str = "Out of memory for data buffer";

View File

@@ -28,9 +28,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
#include <linux/sockptr.h>
#endif
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <net/netns/generic.h>
@@ -43,9 +40,6 @@
#error "ipt_ACCOUNT needs at least a PAGE_SIZE of 4096"
#endif
static unsigned int max_tables_limit = 128;
module_param(max_tables_limit, uint, 0);
/**
* Internal table structure, generated by check_entry()
* @name: name of the table
@@ -187,22 +181,24 @@ static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables,
{
unsigned int i;
pr_debug("ACCOUNT: ipt_acc_table_insert: %s, %pI4/%pI4\n",
name, &ip, &netmask);
pr_debug("ACCOUNT: ipt_acc_table_insert: %s, %u.%u.%u.%u/%u.%u.%u.%u\n",
name, NIPQUAD(ip), NIPQUAD(netmask));
/* Look for existing table */
for (i = 0; i < max_tables_limit; i++) {
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (strncmp(ipt_acc_tables[i].name, name,
ACCOUNT_TABLE_NAME_LEN) == 0) {
pr_debug("ACCOUNT: Found existing slot: %d - %pI4/%pI4\n",
i, &ipt_acc_tables[i].ip, &ipt_acc_tables[i].netmask);
pr_debug("ACCOUNT: Found existing slot: %d - "
"%u.%u.%u.%u/%u.%u.%u.%u\n", i,
NIPQUAD(ipt_acc_tables[i].ip),
NIPQUAD(ipt_acc_tables[i].netmask));
if (ipt_acc_tables[i].ip != ip
|| ipt_acc_tables[i].netmask != netmask) {
printk("ACCOUNT: Table %s found, but IP/netmask mismatch. "
"IP/netmask found: %pI4/%pI4\n",
name, &ipt_acc_tables[i].ip,
&ipt_acc_tables[i].netmask);
"IP/netmask found: %u.%u.%u.%u/%u.%u.%u.%u\n",
name, NIPQUAD(ipt_acc_tables[i].ip),
NIPQUAD(ipt_acc_tables[i].netmask));
return -1;
}
@@ -213,7 +209,7 @@ static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables,
}
/* Insert new table */
for (i = 0; i < max_tables_limit; i++) {
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
/* Found free slot */
if (ipt_acc_tables[i].name[0] == 0) {
unsigned int netsize = 0;
@@ -262,7 +258,7 @@ static int ipt_acc_table_insert(struct ipt_acc_table *ipt_acc_tables,
/* No free slot found */
printk("ACCOUNT: No free table slot found (max: %d). "
"Please increase the \"max_tables_limit\" module parameter.\n", max_tables_limit);
"Please increase ACCOUNT_MAX_TABLES.\n", ACCOUNT_MAX_TABLES);
return -1;
}
@@ -303,7 +299,7 @@ static void ipt_acc_destroy(const struct xt_tgdtor_param *par)
info->table_nr = -1; /* Set back to original state */
/* Look for table */
for (i = 0; i < max_tables_limit; i++) {
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (strncmp(ian->ipt_acc_tables[i].name, info->table_name,
ACCOUNT_TABLE_NAME_LEN) == 0) {
pr_debug("ACCOUNT: Found table at slot: %d\n", i);
@@ -341,8 +337,9 @@ static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
/* Check if this entry is new */
bool is_src_new_ip = false, is_dst_new_ip = false;
pr_debug("ACCOUNT: ipt_acc_depth0_insert: %pI4/%pI4 for net %pI4/%pI4,"
" size: %u\n", &src_ip, &dst_ip, &net_ip, &netmask, size);
pr_debug("ACCOUNT: ipt_acc_depth0_insert: %u.%u.%u.%u/%u.%u.%u.%u "
"for net %u.%u.%u.%u/%u.%u.%u.%u, size: %u\n", NIPQUAD(src_ip),
NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask), size);
/* Check if src/dst is inside our network. */
/* Special: net_ip = 0.0.0.0/0 gets stored as src in slot 0 */
@@ -354,8 +351,9 @@ static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
is_dst = true;
if (!is_src && !is_dst) {
pr_debug("ACCOUNT: Skipping packet %pI4/%pI4 for net %pI4/%pI4\n",
&src_ip, &dst_ip, &net_ip, &netmask);
pr_debug("ACCOUNT: Skipping packet %u.%u.%u.%u/%u.%u.%u.%u "
"for net %u.%u.%u.%u/%u.%u.%u.%u\n", NIPQUAD(src_ip),
NIPQUAD(dst_ip), NIPQUAD(net_ip), NIPQUAD(netmask));
return;
}
@@ -394,11 +392,11 @@ static void ipt_acc_depth0_insert(struct ipt_acc_mask_24 *mask_24,
}
} else {
if (is_src_new_ip) {
pr_debug("ACCOUNT: New src_ip: %pI4\n", &src_ip);
pr_debug("ACCOUNT: New src_ip: %u.%u.%u.%u\n", NIPQUAD(src_ip));
++*itemcount;
}
if (is_dst_new_ip) {
pr_debug("ACCOUNT: New dst_ip: %pI4\n", &dst_ip);
pr_debug("ACCOUNT: New dst_ip: %u.%u.%u.%u\n", NIPQUAD(dst_ip));
++*itemcount;
}
}
@@ -484,7 +482,16 @@ static void ipt_acc_depth2_insert(struct ipt_acc_mask_8 *mask_8,
static unsigned int
ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
struct ipt_acc_net *ian = net_generic(par->state->net, ipt_acc_net_id);
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,4,0)
struct ipt_acc_net *ian = net_generic(par->net, ipt_acc_net_id);
#else
struct net *net = dev_net(par->in ? par->in : par->out);
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
#endif
#endif
struct ipt_acc_table *ipt_acc_tables = ian->ipt_acc_tables;
const struct ipt_acc_info *info =
par->targinfo;
@@ -497,7 +504,8 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
if (ipt_acc_tables[info->table_nr].name[0] == 0) {
printk("ACCOUNT: ipt_acc_target: Invalid table id %u. "
"IPs %pI4/%pI4\n", info->table_nr, &src_ip, &dst_ip);
"IPs %u.%u.%u.%u/%u.%u.%u.%u\n", info->table_nr,
NIPQUAD(src_ip), NIPQUAD(dst_ip));
spin_unlock_bh(&ian->ipt_acc_lock);
return XT_CONTINUE;
}
@@ -536,8 +544,10 @@ ipt_acc_target(struct sk_buff *skb, const struct xt_action_param *par)
return XT_CONTINUE;
}
printk("ACCOUNT: ipt_acc_target: Unable to process packet. Table id "
"%u. IPs %pI4/%pI4\n", info->table_nr, &src_ip, &dst_ip);
printk("ACCOUNT: ipt_acc_target: Unable to process packet. "
"Table id %u. IPs %u.%u.%u.%u/%u.%u.%u.%u\n",
info->table_nr, NIPQUAD(src_ip), NIPQUAD(dst_ip));
spin_unlock_bh(&ian->ipt_acc_lock);
return XT_CONTINUE;
}
@@ -603,12 +613,12 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
int table_nr = -1;
uint8_t depth;
for (table_nr = 0; table_nr < max_tables_limit; table_nr++)
for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
if (strncmp(ipt_acc_tables[table_nr].name, tablename,
ACCOUNT_TABLE_NAME_LEN) == 0)
break;
if (table_nr == max_tables_limit) {
if (table_nr == ACCOUNT_MAX_TABLES) {
printk("ACCOUNT: ipt_acc_handle_prepare_read(): "
"Table %s not found\n", tablename);
return -1;
@@ -620,8 +630,7 @@ static int ipt_acc_handle_prepare_read(struct ipt_acc_table *ipt_acc_tables,
dest->itemcount = ipt_acc_tables[table_nr].itemcount;
/* allocate "root" table */
dest->data = ipt_acc_zalloc_page();
if (dest->data == NULL) {
if ((dest->data = ipt_acc_zalloc_page()) == NULL) {
printk("ACCOUNT: out of memory for root table "
"in ipt_acc_handle_prepare_read()\n");
return -1;
@@ -707,20 +716,19 @@ static int ipt_acc_handle_prepare_read_flush(struct ipt_acc_table *ipt_acc_table
int table_nr;
void *new_data_page;
for (table_nr = 0; table_nr < max_tables_limit; table_nr++)
for (table_nr = 0; table_nr < ACCOUNT_MAX_TABLES; table_nr++)
if (strncmp(ipt_acc_tables[table_nr].name, tablename,
ACCOUNT_TABLE_NAME_LEN) == 0)
break;
if (table_nr == max_tables_limit) {
if (table_nr == ACCOUNT_MAX_TABLES) {
printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
"Table %s not found\n", tablename);
return -1;
}
/* Try to allocate memory */
new_data_page = ipt_acc_zalloc_page();
if (new_data_page == NULL) {
if (!(new_data_page = ipt_acc_zalloc_page())) {
printk("ACCOUNT: ipt_acc_handle_prepare_read_flush(): "
"Out of memory!\n");
return -1;
@@ -877,12 +885,7 @@ static int ipt_acc_handle_get_data(struct ipt_acc_net *ian,
}
static int ipt_acc_set_ctl(struct sock *sk, int cmd,
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
void *user,
#else
sockptr_t arg,
#endif
unsigned int len)
void *user, unsigned int len)
{
struct net *net = sock_net(sk);
struct ipt_acc_net *ian = net_generic(net, ipt_acc_net_id);
@@ -901,12 +904,7 @@ static int ipt_acc_set_ctl(struct sock *sk, int cmd,
break;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 9, 0)
if (copy_from_user(&handle, user, len))
#else
if (copy_from_sockptr(&handle, arg, len))
#endif
{
if (copy_from_user(&handle, user, len)) {
printk("ACCOUNT: ipt_acc_set_ctl: copy_from_user failed for "
"IPT_SO_SET_HANDLE_FREE\n");
break;
@@ -974,8 +972,7 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
/* Allocate a userspace handle */
down(&ian->ipt_acc_userspace_mutex);
handle.handle_nr = ipt_acc_handle_find_slot(ian->ipt_acc_handles);
if (handle.handle_nr == -1) {
if ((handle.handle_nr = ipt_acc_handle_find_slot(ian->ipt_acc_handles)) == -1) {
ipt_acc_data_free(dest.data, dest.depth);
up(&ian->ipt_acc_userspace_mutex);
return -EINVAL;
@@ -1064,7 +1061,7 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
spin_lock_bh(&ian->ipt_acc_lock);
/* Determine size of table names */
for (i = 0; i < max_tables_limit; i++) {
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (ian->ipt_acc_tables[i].name[0] != 0)
size += strlen(ian->ipt_acc_tables[i].name) + 1;
}
@@ -1079,7 +1076,7 @@ static int ipt_acc_get_ctl(struct sock *sk, int cmd, void *user, int *len)
}
/* Copy table names to userspace */
tnames = ian->ipt_acc_tmpbuf;
for (i = 0; i < max_tables_limit; i++) {
for (i = 0; i < ACCOUNT_MAX_TABLES; i++) {
if (ian->ipt_acc_tables[i].name[0] != 0) {
name_len = strlen(ian->ipt_acc_tables[i].name) + 1;
memcpy(tnames, ian->ipt_acc_tables[i].name, name_len);
@@ -1112,7 +1109,7 @@ static int __net_init ipt_acc_net_init(struct net *net)
memset(ian, 0, sizeof(*ian));
sema_init(&ian->ipt_acc_userspace_mutex, 1);
ian->ipt_acc_tables = kcalloc(max_tables_limit,
ian->ipt_acc_tables = kcalloc(ACCOUNT_MAX_TABLES,
sizeof(struct ipt_acc_table), GFP_KERNEL);
if (ian->ipt_acc_tables == NULL) {
printk("ACCOUNT: Out of memory allocating account_tables structure");

View File

@@ -34,6 +34,7 @@
#define IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES (SO_ACCOUNT_BASE_CTL + 8)
#define IPT_SO_GET_ACCOUNT_MAX IPT_SO_GET_ACCOUNT_GET_TABLE_NAMES
#define ACCOUNT_MAX_TABLES 128
#define ACCOUNT_TABLE_NAME_LEN 32
#define ACCOUNT_MAX_HANDLES 10

View File

@@ -13,7 +13,6 @@ obj-${build_DNETMAP} += xt_DNETMAP.o
obj-${build_ECHO} += xt_ECHO.o
obj-${build_IPMARK} += xt_IPMARK.o
obj-${build_LOGMARK} += xt_LOGMARK.o
obj-${build_PROTO} += xt_PROTO.o
obj-${build_SYSRQ} += xt_SYSRQ.o
obj-${build_TARPIT} += xt_TARPIT.o
obj-${build_condition} += xt_condition.o

View File

@@ -8,7 +8,6 @@ obj-${build_DNETMAP} += libxt_DNETMAP.so
obj-${build_ECHO} += libxt_ECHO.so
obj-${build_IPMARK} += libxt_IPMARK.so
obj-${build_LOGMARK} += libxt_LOGMARK.so
obj-${build_PROTO} += libxt_PROTO.so
obj-${build_SYSRQ} += libxt_SYSRQ.so
obj-${build_TARPIT} += libxt_TARPIT.so
obj-${build_condition} += libxt_condition.so

View File

@@ -8,8 +8,12 @@
#define DEBUGP Use__pr_debug__instead
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)
# warning Kernels below 4.15 not supported.
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
# warning Kernels below 3.7 not supported.
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
# define prandom_u32() random32()
#endif
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@@ -21,31 +25,76 @@
# warning You need CONFIG_NF_CONNTRACK.
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) || \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 9) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0) || \
LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 78) && LINUX_VERSION_CODE < KERNEL_VERSION(5, 5, 0) || \
LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 158) && LINUX_VERSION_CODE < KERNEL_VERSION(4, 20, 0)
#else
# define ip_route_me_harder(xnet, xsk, xskb, xaddrtype) ip_route_me_harder((xnet), (xskb), (xaddrtype))
# define ip6_route_me_harder(xnet, xsk, xskb) ip6_route_me_harder((xnet), (xskb))
#if !defined(NIP6) && !defined(NIP6_FMT)
# define NIP6(addr) \
ntohs((addr).s6_addr16[0]), \
ntohs((addr).s6_addr16[1]), \
ntohs((addr).s6_addr16[2]), \
ntohs((addr).s6_addr16[3]), \
ntohs((addr).s6_addr16[4]), \
ntohs((addr).s6_addr16[5]), \
ntohs((addr).s6_addr16[6]), \
ntohs((addr).s6_addr16[7])
# define NIP6_FMT "%04hx:%04hx:%04hx:%04hx:%04hx:%04hx:%04hx:%04hx"
#endif
#if !defined(NIPQUAD) && !defined(NIPQUAD_FMT)
# define NIPQUAD(addr) \
((const unsigned char *)&addr)[0], \
((const unsigned char *)&addr)[1], \
((const unsigned char *)&addr)[2], \
((const unsigned char *)&addr)[3]
# define NIPQUAD_FMT "%hhu.%hhu.%hhu.%hhu"
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 9, 0)
static inline struct inode *file_inode(struct file *f)
{
return f->f_path.dentry->d_inode;
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
static inline void proc_set_user(struct proc_dir_entry *de,
typeof(de->uid) uid, typeof(de->gid) gid)
{
de->uid = uid;
de->gid = gid;
}
static inline void *PDE_DATA(struct inode *inode)
{
return PDE(inode)->data;
}
static inline void proc_remove(struct proc_dir_entry *de)
{
if (de != NULL)
remove_proc_entry(de->name, de->parent);
}
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
# define ip6_local_out(xnet, xsk, xskb) ip6_local_out(xskb)
# define ip6_route_me_harder(xnet, xskb) ip6_route_me_harder(xskb)
# define ip_local_out(xnet, xsk, xskb) ip_local_out(xskb)
# define ip_route_me_harder(xnet, xskb, xaddrtype) ip_route_me_harder((xskb), (xaddrtype))
#endif
static inline struct net *par_net(const struct xt_action_param *par)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)
return par->state->net;
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
return par->net;
#else
return dev_net((par->in != NULL) ? par->in : par->out);
#endif
#endif
}
#ifndef NF_CT_ASSERT
# define NF_CT_ASSERT(x) WARN_ON(!(x))
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)
# define proc_ops file_operations
# define proc_open open
# define proc_read read
# define proc_write write
# define proc_lseek llseek
# define proc_release release
#endif
#endif /* _XTABLES_COMPAT_H */

View File

@@ -46,7 +46,7 @@ Contains the binding table for the given \fIsubnet/mask\fP. Each line contains
\fBprenat address\fR, \fBpostnat address\fR, \fBttl\fR (seconds until the entry
times out), \fBlasthit\fR (last hit to the entry in seconds relative to system
boot time). Please note that the \fBttl\fR and \fBlasthit\fR entries contain an
\(oq\fBS\fR\(cq in case of a static binding.
'\fBS\fR' in case of a static binding.
.TP
\fB/proc/net/xt_DNETMAP/\fR\fIsubnet\fR\fB_\fR\fImask\fR\fB_stat\fR
Contains statistics for a given \fIsubnet/mask\fP. The line contains four

View File

@@ -1,105 +0,0 @@
/*
* PROTO Target module
* This program is distributed under the terms of GNU GPL
*/
#include <stdio.h>
#include <xtables.h>
#include "xt_PROTO.h"
enum {
O_PROTO_SET = 0,
O_PROTO_STOP_AT_FRAG = 1,
O_PROTO_STOP_AT_AUTH = 2,
F_PROTO_SET = 1 << O_PROTO_SET,
F_PROTO_STOP_AT_FRAG = 1 << O_PROTO_STOP_AT_FRAG,
F_PROTO_STOP_AT_AUTH = 1 << O_PROTO_STOP_AT_AUTH,
};
#define s struct xt_PROTO_info
static const struct xt_option_entry PROTO_opts[] = {
{.name = "proto-set", .type = XTTYPE_UINT8, .id = O_PROTO_SET,
.flags = XTOPT_PUT | XTOPT_MAND, XTOPT_POINTER(s, proto)},
{.name = "stop-at-frag", .type = XTTYPE_NONE, .id = O_PROTO_STOP_AT_FRAG},
{.name = "stop-at-auth", .type = XTTYPE_NONE, .id = O_PROTO_STOP_AT_AUTH},
XTOPT_TABLEEND,
};
#undef s
static void PROTO_help(void)
{
printf(
"PROTO target options\n"
" --proto-set value Set protocol to <value 0-255>\n"
);
}
static void PROTO_parse(struct xt_option_call *cb)
{
struct xt_PROTO_info *info = cb->data;
xtables_option_parse(cb);
switch (cb->entry->id) {
case O_PROTO_SET:
info->mode |= 1 << XT_PROTO_SET;
break;
case O_PROTO_STOP_AT_FRAG:
info->mode |= 1 << XT_PROTO_STOP_AT_FRAG;
break;
case O_PROTO_STOP_AT_AUTH:
info->mode |= 1 << XT_PROTO_STOP_AT_AUTH;
break;
}
}
static void PROTO_check(struct xt_fcheck_call *cb)
{
if (!(cb->xflags & F_PROTO_SET))
xtables_error(PARAMETER_PROBLEM,
"PROTO: You must specify the proto to be set");
}
static void PROTO_save(const void *ip, const struct xt_entry_target *target)
{
const struct xt_PROTO_info *info = (void *)target->data;
if (info->mode & (1 << XT_PROTO_SET))
printf(" --proto-set %u", info->proto);
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
printf(" --stop-at-frag");
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
printf(" --stop-at-auth");
}
static void PROTO_print(const void *ip, const struct xt_entry_target *target,
int numeric)
{
const struct xt_PROTO_info *info = (void *)target->data;
printf(" PROTO ");
if (info->mode & (1 << XT_PROTO_SET))
printf("set to %u", info->proto);
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
printf(" stop-at-frag");
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
printf(" stop-at-auth");
}
static struct xtables_target proto_tg_reg = {
.name = "PROTO",
.version = XTABLES_VERSION,
.family = NFPROTO_UNSPEC,
.size = XT_ALIGN(sizeof(struct xt_PROTO_info)),
.userspacesize = XT_ALIGN(sizeof(struct xt_PROTO_info)),
.help = PROTO_help,
.print = PROTO_print,
.save = PROTO_save,
.x6_parse = PROTO_parse,
.x6_fcheck = PROTO_check,
.x6_options = PROTO_opts,
};
static __attribute__((constructor)) void _init(void)
{
xtables_register_target(&proto_tg_reg);
}

View File

@@ -1,30 +0,0 @@
.PP
The PROTO target modifies the protocol number in IP packet header.
.TP
\fB\-\-proto-set\fP \fIproto_num\fP
This option is mandatory. \fIproto_num\fP is the protocol number to which you want to
modify the packets.
.TP
\fB\-\-stop-at-frag\fP
This option is only valid for IPv6 rules. When specifying this option, the
fragment extension header will be seen as a non-extension header.
.TP
\fB\-\-stop-at-auth\fP
This option is only valid for IPv6 rules. When specifying this option, the
authentication extension header will be seen as a non-extension header.
.PP
For IPv4 packets, the \fBProtocol\fP field is modified and the checksum is
re-calculated.
.PP
For IPv6 packets, the scenario can be more complex due to the introduction of
the extension headers mechanism. By default, the PROTO target will scan the IPv6
packet, finding the last extension header and modify its \fBNext-header\fP field.
Normally, the following headers will be seen as an extension header:
\fINEXTHDR_HOP\fP,
\fINEXTHDR_ROUTING\fP,
\fINEXTHDR_FRAGMENT\fP,
\fINEXTHDR_AUTH\fP,
\fINEXTHDR_DEST\fP.
.PP
For fragmented packets, only the first fragment is processed and other fragments
are not touched.

View File

@@ -49,44 +49,30 @@ static struct option geoip_opts[] = {
{NULL},
};
#if __BYTE_ORDER == __LITTLE_ENDIAN
static void geoip_swap_le32(uint32_t *buf)
{
unsigned char *p = (void *)buf;
uint32_t n = p[0] + (p[1] << 8) + (p[2] << 16) + (p[3] << 24);
p[0] = (n >> 24) & 0xff;
p[1] = (n >> 16) & 0xff;
p[2] = (n >> 8) & 0xff;
p[3] = n & 0xff;
}
static void geoip_swap_in6(struct in6_addr *in6)
{
geoip_swap_le32(&in6->s6_addr32[0]);
geoip_swap_le32(&in6->s6_addr32[1]);
geoip_swap_le32(&in6->s6_addr32[2]);
geoip_swap_le32(&in6->s6_addr32[3]);
}
#endif
static void *
geoip_get_subnets(const char *code, uint32_t *count, uint8_t nfproto)
{
void *subnets;
struct stat sb;
char buf[256];
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int n;
#endif
int fd;
/* Use simple integer vector files */
if (nfproto == NFPROTO_IPV6)
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/%s.iv6", code);
else
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/%s.iv4", code);
if (nfproto == NFPROTO_IPV6) {
#if __BYTE_ORDER == _BIG_ENDIAN
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv6", code);
#else
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv6", code);
#endif
} else {
#if __BYTE_ORDER == _BIG_ENDIAN
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/BE/%s.iv4", code);
#else
snprintf(buf, sizeof(buf), GEOIP_DB_DIR "/LE/%s.iv4", code);
#endif
}
int fd = open(buf, O_RDONLY);
if (fd < 0) {
if ((fd = open(buf, O_RDONLY)) < 0) {
fprintf(stderr, "Could not open %s: %s\n", buf, strerror(errno));
xtables_error(OTHER_PROBLEM, "Could not read geoip database");
}
@@ -112,25 +98,6 @@ geoip_get_subnets(const char *code, uint32_t *count, uint8_t nfproto)
xtables_error(OTHER_PROBLEM, "geoip: insufficient memory");
read(fd, subnets, sb.st_size);
close(fd);
#if __BYTE_ORDER == __LITTLE_ENDIAN
for (n = 0; n < *count; ++n) {
switch (nfproto) {
case NFPROTO_IPV6: {
struct geoip_subnet6 *gs6 = &(((struct geoip_subnet6 *)subnets)[n]);
geoip_swap_in6(&gs6->begin);
geoip_swap_in6(&gs6->end);
break;
}
case NFPROTO_IPV4: {
struct geoip_subnet4 *gs4 = &(((struct geoip_subnet4 *)subnets)[n]);
geoip_swap_le32(&gs4->begin);
geoip_swap_le32(&gs4->end);
break;
}
}
}
#endif
return subnets;
}
@@ -168,7 +135,7 @@ check_geoip_cc(char *cc, u_int16_t cc_used[], u_int8_t count)
cc[i] = toupper(cc[i]);
else
xtables_error(PARAMETER_PROBLEM,
"geoip: invalid country code '%s'", cc);
"geoip: invalid country code '%s'", cc);
/* Convert chars into a single 16 bit integer.
* FIXME: This assumes that a country code is
@@ -203,8 +170,7 @@ static unsigned int parse_geoip_cc(const char *ccstr, uint16_t *cc,
next = strchr(cp, ',');
if (next) *next++ = '\0';
cctmp = check_geoip_cc(cp, cc, count);
if (cctmp != 0) {
if ((cctmp = check_geoip_cc(cp, cc, count)) != 0) {
if ((mem[count++].user =
(unsigned long)geoip_load_cc(cp, cctmp, nfproto)) == 0)
xtables_error(OTHER_PROBLEM,

View File

@@ -70,7 +70,7 @@ quota_mt2_parse(int c, char **argv, int invert, unsigned int *flags,
/* zero termination done on behalf of the kernel module */
xtables_param_act(XTF_ONLY_ONCE, "quota", "--name", *flags & FL_NAME);
xtables_param_act(XTF_NO_INVERT, "quota", "--name", invert);
snprintf(info->name, sizeof(info->name), "%s", optarg);
strncpy(info->name, optarg, sizeof(info->name));
*flags |= FL_NAME;
return true;
case 'p':

View File

@@ -5,5 +5,4 @@ AM_CFLAGS = ${regular_CFLAGS} ${libxtables_CFLAGS}
include ../../Makefile.extra
sbin_PROGRAMS = pknlusr
dist_man_MANS = pknlusr.8
noinst_PROGRAMS = pknlusr

View File

@@ -11,6 +11,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <xtables.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
@@ -69,6 +70,7 @@ parse_ports(const char *portstring, uint16_t *ports, const char *proto)
if (cp != NULL)
xtables_error(PARAMETER_PROBLEM, "too many ports specified");
free(buffer);
return i;
}
@@ -89,11 +91,12 @@ proto_to_name(uint8_t proto)
static const char *
check_proto(uint16_t pnum, uint8_t invflags)
{
char *proto;
if (invflags & XT_INV_PROTO)
xtables_error(PARAMETER_PROBLEM, PKNOCK "only works with TCP and UDP.");
const char *proto = proto_to_name(pnum);
if (proto != NULL)
if ((proto = proto_to_name(pnum)) != NULL)
return proto;
else if (pnum == 0)
xtables_error(PARAMETER_PROBLEM, PKNOCK "needs `-p tcp' or `-p udp'");
@@ -120,7 +123,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
info->ports_count = parse_ports(optarg, info->port, proto);
info->option |= XT_PKNOCK_KNOCKPORT;
*flags |= XT_PKNOCK_KNOCKPORT;
#ifdef DEBUG
#if DEBUG
printf("ports_count: %d\n", info->ports_count);
#endif
break;
@@ -159,7 +162,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
info->rule_name_len = strlen(info->rule_name);
info->option |= XT_PKNOCK_NAME;
*flags |= XT_PKNOCK_NAME;
#ifdef DEBUG
#if DEBUG
printf("info->rule_name: %s\n", info->rule_name);
#endif
break;
@@ -210,6 +213,7 @@ __pknock_parse(int c, char **argv, int invert, unsigned int *flags,
if (invert)
xtables_error(PARAMETER_PROBLEM, PKNOCK "does not support invert.");
return 1;
}
@@ -263,7 +267,7 @@ static void pknock_mt_check(unsigned int flags)
}
static void pknock_mt_print(const void *ip,
const struct xt_entry_match *match, int numeric)
const struct xt_entry_match *match, int numeric)
{
const struct xt_pknock_mtinfo *info = (void *)match->data;
int i;

View File

@@ -1,18 +0,0 @@
.TH pknlusr 8 "2020-10-22" "xtables-addons" "xtables-addons"
.SH NAME
.PP
pknlusr \(em userspace monitor for successful xt_pknock matches
.SH Synopsis
.PP
\fBpknlusr\fP [\fIgroup-id\fP]
.SH Description
\fIxt_pknock\fP is an xtables match extension that implements so-called \fIport
knocking\fP. It can be configured to send information about each successful
match via a netlink socket to userspace. \fBpknluser\fP listens for these
notifications.
.PP
By default, \fBpknlusr\fP listens for messages sent to netlink multicast group
1. Another group ID may be passed as a command-line argument.
.SH See also
.PP
xtables-addons(8)

View File

@@ -7,94 +7,85 @@
#include <arpa/inet.h>
#include <linux/netlink.h>
#include <linux/connector.h>
#include <errno.h>
#include <libgen.h>
#include <limits.h>
#include "xt_pknock.h"
#define DEFAULT_GROUP_ID 1
#define MIN_GROUP_ID DEFAULT_GROUP_ID
#define MAX_GROUP_ID \
(sizeof((struct sockaddr_nl){0}.nl_groups) * CHAR_BIT)
#define GROUP 1
int main(int argc, char **argv)
static struct sockaddr_nl src_addr, dest_addr;
static int sock_fd;
static unsigned char *buf;
static struct xt_pknock_nl_msg *nlmsg;
int main(void)
{
socklen_t addrlen;
int status;
unsigned int group_id = DEFAULT_GROUP_ID;
struct sockaddr_nl local_addr = {.nl_family = AF_NETLINK};
int sock_fd;
size_t nlmsg_size;
struct nlmgrhdr *nlmsg;
struct cn_msg *cn_msg;
struct xt_pknock_nl_msg *pknock_msg;
int group = GROUP;
if (argc > 2) {
char *prog = strdup(argv[0]);
if (prog == NULL) {
perror("strdup()");
} else {
fprintf(stderr, "%s [ group-id ]\n", basename(prog));
free(prog);
}
exit(EXIT_FAILURE);
}
int buf_size;
if (argc == 2) {
long n;
char *end;
errno = 0;
n = strtol(argv[1], &end, 10);
if (*end || (errno && (n == LONG_MIN || n == LONG_MAX)) ||
n < MIN_GROUP_ID || n > MAX_GROUP_ID) {
fputs("Group ID invalid.\n", stderr);
exit(EXIT_FAILURE);
}
group_id = n;
}
const char *ip;
char ipbuf[48];
sock_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
if (sock_fd == -1) {
perror("socket()");
exit(EXIT_FAILURE);
return 1;
}
local_addr.nl_groups = 1U << (group_id - 1);
status = bind(sock_fd, (struct sockaddr *)&local_addr, sizeof(local_addr));
memset(&src_addr, 0, sizeof(src_addr));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups = group;
status = bind(sock_fd, (struct sockaddr*)&src_addr, sizeof(src_addr));
if (status == -1) {
close(sock_fd);
perror("bind()");
goto err_close_sock;
return 1;
}
nlmsg_size = NLMSG_SPACE(sizeof(*cn_msg) + sizeof(*pknock_msg));
nlmsg = malloc(nlmsg_size);
if (!nlmsg) {
memset(&dest_addr, 0, sizeof(dest_addr));
dest_addr.nl_family = AF_NETLINK;
dest_addr.nl_pid = 0;
dest_addr.nl_groups = group;
buf_size = sizeof(struct xt_pknock_nl_msg) + sizeof(struct cn_msg) + sizeof(struct nlmsghdr);
buf = malloc(buf_size);
if (!buf) {
perror("malloc()");
goto err_close_sock;
return 1;
}
addrlen = sizeof(dest_addr);
while(1) {
const char *ip;
char ipbuf[INET_ADDRSTRLEN];
memset(nlmsg, 0, nlmsg_size);
status = recv(sock_fd, nlmsg, nlmsg_size, 0);
if (status < 0) {
perror("recv()");
goto err_free_msg;
memset(buf, 0, buf_size);
status = recvfrom(sock_fd, buf, buf_size, 0, (struct sockaddr *)&dest_addr, &addrlen);
if (status <= 0) {
perror("recvfrom()");
return 1;
}
if (status == 0)
break;
cn_msg = NLMSG_DATA(nlmsg);
pknock_msg = (struct xt_pknock_nl_msg *)(cn_msg->data);
ip = inet_ntop(AF_INET, &pknock_msg->peer_ip, ipbuf, sizeof(ipbuf));
printf("rule_name: %s - ip %s\n", pknock_msg->rule_name, ip);
nlmsg = (struct xt_pknock_nl_msg *) (buf + sizeof(struct cn_msg) + sizeof(struct nlmsghdr));
ip = inet_ntop(AF_INET, &nlmsg->peer_ip, ipbuf, sizeof(ipbuf));
printf("rule_name: %s - ip %s\n", nlmsg->rule_name, ip);
}
err_free_msg:
free(nlmsg);
err_close_sock:
close(sock_fd);
exit(status == -1 ? EXIT_FAILURE : EXIT_SUCCESS);
free(buf);
return 0;
}

View File

@@ -90,15 +90,21 @@ enum {
#define hashtable_for_each_safe(pos, n, head, size, i) \
for ((i) = 0; (i) < (size); ++(i)) \
list_for_each_safe((pos), (n), (&head[(i)]))
#define pk_debug(msg, peer) pr_debug("(S) peer: %pI4 - %s.\n", &((peer)->ip), msg)
#define pk_debug(msg, peer) pr_debug( \
"(S) peer: " NIPQUAD_FMT " - %s.\n", \
NIPQUAD((peer)->ip), msg)
static uint32_t ipt_pknock_hash_rnd;
static unsigned int rule_hashsize = DEFAULT_RULE_HASH_SIZE;
static unsigned int peer_hashsize = DEFAULT_PEER_HASH_SIZE;
static unsigned int gc_expir_time = DEFAULT_GC_EXPIRATION_TIME;
static int nl_multicast_group = -1;
static struct list_head *rule_hashtable;
static struct proc_dir_entry *pde;
static DEFINE_SPINLOCK(list_lock);
static struct {
@@ -153,6 +159,7 @@ alloc_hashtable(unsigned int size)
return NULL;
for (i = 0; i < size; ++i)
INIT_LIST_HEAD(&hash[i]);
return hash;
}
@@ -184,8 +191,10 @@ pknock_seq_start(struct seq_file *s, loff_t *pos)
const struct xt_pknock_rule *rule = s->private;
spin_lock_bh(&list_lock);
if (*pos >= peer_hashsize)
return NULL;
return rule->peer_head + *pos;
}
@@ -203,6 +212,7 @@ pknock_seq_next(struct seq_file *s, void *v, loff_t *pos)
++*pos;
if (*pos >= peer_hashsize)
return NULL;
return rule->peer_head + *pos;
}
@@ -228,11 +238,13 @@ pknock_seq_show(struct seq_file *s, void *v)
const struct peer *peer;
unsigned long time;
const struct list_head *peer_head = v;
const struct xt_pknock_rule *rule = s->private;
list_for_each_safe(pos, n, peer_head) {
peer = list_entry(pos, struct peer, head);
seq_printf(s, "src=%pI4 ", &peer->ip);
seq_printf(s, "src=" NIPQUAD_FMT " ", NIPQUAD(peer->ip));
seq_printf(s, "proto=%s ", (peer->proto == IPPROTO_TCP) ?
"TCP" : "UDP");
seq_printf(s, "status=%s ", status_itoa(peer->status));
@@ -247,11 +259,12 @@ pknock_seq_show(struct seq_file *s, void *v)
seq_printf(s, "expir_time=%lu [secs] ", time);
}
if (peer->status == ST_ALLOWED && rule->autoclose_time != 0) {
unsigned long x = ktime_get_seconds();
unsigned long y = peer->login_sec + rule->autoclose_time * 60;
time = 0;
if (time_before(x, y))
time = y - x;
if (time_before(get_seconds(), peer->login_sec +
rule->autoclose_time * 60))
time = peer->login_sec +
rule->autoclose_time * 60 -
get_seconds();
seq_printf(s, "autoclose_time=%lu [secs] ", time);
}
seq_printf(s, "\n");
@@ -282,11 +295,12 @@ pknock_proc_open(struct inode *inode, struct file *file)
return ret;
}
static const struct proc_ops pknock_proc_ops = {
.proc_open = pknock_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = seq_release,
static const struct file_operations pknock_proc_ops = {
.owner = THIS_MODULE,
.open = pknock_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
/**
@@ -298,6 +312,7 @@ static void update_rule_gc_timer(struct xt_pknock_rule *rule)
{
if (timer_pending(&rule->timer))
del_timer(&rule->timer);
rule->timer.expires = jiffies + msecs_to_jiffies(gc_expir_time);
add_timer(&rule->timer);
}
@@ -311,12 +326,8 @@ static void update_rule_gc_timer(struct xt_pknock_rule *rule)
static inline bool
autoclose_time_passed(const struct peer *peer, unsigned int autoclose_time)
{
unsigned long x, y;
if (peer == NULL || autoclose_time == 0)
return false;
x = ktime_get_seconds();
y = peer->login_sec + autoclose_time * 60;
return time_after(x, y);
return peer != NULL && autoclose_time != 0 && time_after(get_seconds(),
peer->login_sec + autoclose_time * 60);
}
/**
@@ -338,12 +349,7 @@ is_interknock_time_exceeded(const struct peer *peer, unsigned int max_time)
static inline bool
has_logged_during_this_minute(const struct peer *peer)
{
uint64_t x, y;
if (peer == NULL)
return 0;
x = ktime_get_seconds();
y = peer->login_sec;
return do_div(y, 60) == do_div(x, 60);
return peer != NULL && peer->login_sec / 60 == get_seconds() / 60;
}
/**
@@ -351,10 +357,18 @@ has_logged_during_this_minute(const struct peer *peer)
*
* @r: rule
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
static void peer_gc(struct timer_list *tl)
#else
static void peer_gc(unsigned long r)
#endif
{
unsigned int i;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
struct xt_pknock_rule *rule = from_timer(rule, tl, timer);
#else
struct xt_pknock_rule *rule = (struct xt_pknock_rule *)r;
#endif
struct peer *peer;
struct list_head *pos, *n;
@@ -428,6 +442,7 @@ add_rule(struct xt_pknock_mtinfo *info)
list_for_each_safe(pos, n, &rule_hashtable[hash]) {
rule = list_entry(pos, struct xt_pknock_rule, head);
if (!rulecmp(info, rule))
continue;
++rule->ref_count;
@@ -436,6 +451,7 @@ add_rule(struct xt_pknock_mtinfo *info)
rule->max_time = info->max_time;
rule->autoclose_time = info->autoclose_time;
}
if (info->option & XT_PKNOCK_CHECKIP)
pr_debug("add_rule() (AC) rule found: %s - "
"ref_count: %d\n",
@@ -443,20 +459,31 @@ add_rule(struct xt_pknock_mtinfo *info)
return true;
}
rule = kzalloc(sizeof(*rule), GFP_KERNEL);
rule = kmalloc(sizeof(*rule), GFP_KERNEL);
if (rule == NULL)
return false;
INIT_LIST_HEAD(&rule->head);
memset(rule->rule_name, 0, sizeof(rule->rule_name));
strncpy(rule->rule_name, info->rule_name, info->rule_name_len);
rule->rule_name_len = info->rule_name_len;
rule->ref_count = 1;
rule->max_time = info->max_time;
rule->autoclose_time = info->autoclose_time;
rule->peer_head = alloc_hashtable(peer_hashsize);
if (rule->peer_head == NULL)
goto out;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)
timer_setup(&rule->timer, peer_gc, 0);
#else
init_timer(&rule->timer);
rule->timer.function = peer_gc;
rule->timer.data = (unsigned long)rule;
#endif
rule->status_proc = proc_create_data(info->rule_name, 0, pde,
&pknock_proc_ops, rule);
if (rule->status_proc == NULL)
@@ -492,6 +519,7 @@ remove_rule(struct xt_pknock_mtinfo *info)
list_for_each_safe(pos, n, &rule_hashtable[hash]) {
rule = list_entry(pos, struct xt_pknock_rule, head);
if (rulecmp(info, rule)) {
found = 1;
rule->ref_count--;
@@ -517,6 +545,7 @@ remove_rule(struct xt_pknock_mtinfo *info)
pr_debug("(D) rule deleted: %s.\n", rule->rule_name);
if (timer_pending(&rule->timer))
del_timer(&rule->timer);
list_del(&rule->head);
kfree(rule->peer_head);
kfree(rule);
@@ -536,6 +565,7 @@ static struct peer *get_peer(struct xt_pknock_rule *rule, __be32 ip)
unsigned int hash;
hash = pknock_hash(&ip, sizeof(ip), ipt_pknock_hash_rnd, peer_hashsize);
list_for_each_safe(pos, n, &rule->peer_head[hash]) {
peer = list_entry(pos, struct peer, head);
if (peer->ip == ip)
@@ -569,12 +599,14 @@ static struct peer *new_peer(__be32 ip, uint8_t proto)
if (peer == NULL)
return NULL;
INIT_LIST_HEAD(&peer->head);
peer->ip = ip;
peer->proto = proto;
peer->timestamp = jiffies/HZ;
peer->login_sec = 0;
reset_knock_status(peer);
return peer;
}
@@ -662,19 +694,29 @@ static bool
msg_to_userspace_nl(const struct xt_pknock_mtinfo *info,
const struct peer *peer, int multicast_group)
{
#if IS_ENABLED(CONFIG_CONNECTOR)
#if defined(CONFIG_CONNECTOR) || defined(CONFIG_CONNECTOR_MODULE)
struct cn_msg *m;
struct xt_pknock_nl_msg msg;
m = kzalloc(sizeof(*m) + sizeof(msg), GFP_ATOMIC);
m = kmalloc(sizeof(*m) + sizeof(msg), GFP_ATOMIC);
if (m == NULL)
return false;
memset(m, 0, sizeof(*m) + sizeof(msg));
m->seq = 0;
m->len = sizeof(msg);
msg.peer_ip = peer->ip;
scnprintf(msg.rule_name, info->rule_name_len + 1, info->rule_name);
memcpy(m + 1, &msg, m->len);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
cn_netlink_send(m, 0, multicast_group, GFP_ATOMIC);
#else
cn_netlink_send(m, multicast_group, GFP_ATOMIC);
#endif
kfree(m);
#endif
return true;
@@ -712,12 +754,11 @@ static bool
has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc,
const unsigned char *payload, unsigned int payload_len)
{
char result[64] = ""; // 64 bytes * 8 = 512 bits
char result[64]; // 64 bytes * 8 = 512 bits
char *hexresult;
unsigned int hexa_size;
int ret;
bool fret = false;
uint64_t x;
unsigned int epoch_min;
if (payload_len == 0)
@@ -733,11 +774,15 @@ has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc,
/* + 1 cause we MUST add NULL in the payload */
if (payload_len != hexa_size + 1)
return false;
hexresult = kzalloc(hexa_size, GFP_ATOMIC);
hexresult = kmalloc(hexa_size, GFP_ATOMIC);
if (hexresult == NULL)
return false;
x = ktime_get_seconds();
epoch_min = do_div(x, 60);
memset(result, 0, sizeof(result));
memset(hexresult, 0, hexa_size);
epoch_min = get_seconds() / 60;
ret = crypto_shash_setkey(crypto.tfm, secret, secret_len);
if (ret != 0) {
@@ -756,11 +801,14 @@ has_secret(const unsigned char *secret, unsigned int secret_len, uint32_t ipsrc,
printk("crypto_shash_update/final() failed ret=%d\n", ret);
goto out;
}
crypt_to_hex(hexresult, result, crypto.size);
if (memcmp(hexresult, payload, hexa_size) != 0)
pr_debug("secret match failed\n");
else
fret = true;
out:
kfree(hexresult);
return fret;
@@ -792,6 +840,7 @@ pass_security(struct peer *peer, const struct xt_pknock_mtinfo *info,
info->open_secret_len, peer->ip,
payload, payload_len))
return true;
return false;
}
@@ -818,6 +867,7 @@ update_peer(struct peer *peer, const struct xt_pknock_mtinfo *info,
/* Peer must start the sequence from scratch. */
if (info->option & XT_PKNOCK_STRICT)
remove_peer(peer);
return false;
}
@@ -825,20 +875,25 @@ update_peer(struct peer *peer, const struct xt_pknock_mtinfo *info,
if (info->option & XT_PKNOCK_OPENSECRET ) {
if (hdr->proto != IPPROTO_UDP && hdr->proto != IPPROTO_UDPLITE)
return false;
if (!pass_security(peer, info, hdr->payload, hdr->payload_len))
return false;
}
/* Update the gc timer when there is a state change. */
update_rule_gc_timer(rule);
++peer->accepted_knock_count;
if (is_last_knock(peer, info)) {
peer->status = ST_ALLOWED;
pk_debug("ALLOWED", peer);
peer->login_sec = ktime_get_seconds();
peer->login_sec = get_seconds();
if (nl_multicast_group > 0)
msg_to_userspace_nl(info, peer, nl_multicast_group);
return true;
}
@@ -915,6 +970,7 @@ static bool pknock_mt(const struct sk_buff *skb,
switch (hdr.proto) {
case IPPROTO_TCP:
break;
case IPPROTO_UDP:
case IPPROTO_UDPLITE:
hdr_len = (iph->ihl * 4) + sizeof(struct udphdr);
@@ -936,10 +992,12 @@ static bool pknock_mt(const struct sk_buff *skb,
/* Gives the peer matching status added to rule depending on ip src. */
peer = get_peer(rule, iph->saddr);
if (info->option & XT_PKNOCK_CHECKIP) {
ret = is_allowed(peer);
goto out;
}
if (iph->protocol == IPPROTO_UDP || iph->protocol == IPPROTO_UDPLITE) {
hdr.payload = (void *)iph + hdr_len;
hdr.payload_len = skb->len - hdr_len;
@@ -947,8 +1005,7 @@ static bool pknock_mt(const struct sk_buff *skb,
/* Sets, updates, removes or checks the peer matching status. */
if (info->option & XT_PKNOCK_KNOCKPORT) {
ret = is_allowed(peer);
if (ret != 0) {
if ((ret = is_allowed(peer))) {
if (info->option & XT_PKNOCK_CLOSESECRET &&
(iph->protocol == IPPROTO_UDP ||
iph->protocol == IPPROTO_UDPLITE))
@@ -966,8 +1023,10 @@ static bool pknock_mt(const struct sk_buff *skb,
peer = new_peer(iph->saddr, iph->protocol);
add_peer(peer, rule);
}
if (peer == NULL)
goto out;
update_peer(peer, info, rule, &hdr);
}
@@ -987,7 +1046,7 @@ out:
return ret;
}
#define RETURN_ERR(err) do { pr_err(err); return -EINVAL; } while (false)
#define RETURN_ERR(err) do { printk(KERN_ERR PKNOCK err); return -EINVAL; } while (false)
static int pknock_mt_check(const struct xt_mtchk_param *par)
{
@@ -1037,9 +1096,11 @@ static int pknock_mt_check(const struct xt_mtchk_param *par)
memcmp(info->open_secret, info->close_secret,
info->open_secret_len) == 0)
RETURN_ERR("opensecret & closesecret cannot be equal.\n");
if (!add_rule(info))
/* should ENOMEM here */
RETURN_ERR("add_rule() error in checkentry() function.\n");
return 0;
}
@@ -1063,7 +1124,7 @@ static struct xt_match xt_pknock_mt_reg __read_mostly = {
static int __init xt_pknock_mt_init(void)
{
#if !IS_ENABLED(CONFIG_CONNECTOR)
#if !defined(CONFIG_CONNECTOR) && !defined(CONFIG_CONNECTOR_MODULE)
if (nl_multicast_group != -1)
pr_info("CONFIG_CONNECTOR not present; "
"netlink messages disabled\n");
@@ -1072,24 +1133,25 @@ static int __init xt_pknock_mt_init(void)
if (gc_expir_time < DEFAULT_GC_EXPIRATION_TIME)
gc_expir_time = DEFAULT_GC_EXPIRATION_TIME;
if (request_module(crypto.algo) < 0) {
pr_err("request_module('%s') error.\n",
printk(KERN_ERR PKNOCK "request_module('%s') error.\n",
crypto.algo);
return -ENXIO;
}
crypto.tfm = crypto_alloc_shash(crypto.algo, 0, 0);
if (IS_ERR(crypto.tfm)) {
pr_err("failed to load transform for %s\n",
printk(KERN_ERR PKNOCK "failed to load transform for %s\n",
crypto.algo);
return PTR_ERR(crypto.tfm);
}
crypto.size = crypto_shash_digestsize(crypto.tfm);
crypto.desc.tfm = crypto.tfm;
crypto.desc.flags = 0;
pde = proc_mkdir("xt_pknock", init_net.proc_net);
if (pde == NULL) {
pr_err("proc_mkdir() error in _init().\n");
printk(KERN_ERR PKNOCK "proc_mkdir() error in _init().\n");
return -ENXIO;
}
return xt_register_match(&xt_pknock_mt_reg);

View File

@@ -29,6 +29,8 @@ enum {
XT_PKNOCK_MAX_PASSWD_LEN = 31,
};
#define DEBUG 1
struct xt_pknock_mtinfo {
char rule_name[XT_PKNOCK_MAX_BUF_LEN+1];
uint32_t rule_name_len;

View File

@@ -58,7 +58,12 @@ xt_chaos_total(struct sk_buff *skb, const struct xt_action_param *par)
{
struct xt_action_param local_par;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
local_par.state = par->state;
#else
local_par.in = par->in,
local_par.out = par->out,
#endif
local_par.match = xm_tcp;
local_par.matchinfo = &tcp_params;
local_par.fragoff = fragoff;
@@ -73,7 +78,14 @@ xt_chaos_total(struct sk_buff *skb, const struct xt_action_param *par)
destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude;
{
struct xt_action_param local_par;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
local_par.state = par->state;
#else
local_par.in = par->in;
local_par.out = par->out;
local_par.hooknum = par->hooknum;
local_par.family = par->family;
#endif
local_par.target = destiny;
local_par.targinfo = par->targinfo;
destiny->target(skb, &local_par);
@@ -96,15 +108,27 @@ chaos_tg(struct sk_buff *skb, const struct xt_action_param *par)
if ((unsigned int)prandom_u32() <= reject_percentage) {
struct xt_action_param local_par;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
local_par.state = par->state;
#else
local_par.in = par->in;
local_par.out = par->out;
local_par.hooknum = par->hooknum;
#endif
local_par.target = xt_reject;
local_par.targinfo = &reject_params;
return xt_reject->target(skb, &local_par);
}
/* TARPIT/DELUDE may not be called from the OUTPUT chain */
if (iph->protocol == IPPROTO_TCP && info->variant != XTCHAOS_NORMAL &&
par->state->hook != NF_INET_LOCAL_OUT)
if (iph->protocol == IPPROTO_TCP &&
info->variant != XTCHAOS_NORMAL &&
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
par->state->hook
#else
par->hooknum
#endif
!= NF_INET_LOCAL_OUT)
xt_chaos_total(skb, par);
return NF_DROP;
@@ -171,8 +195,7 @@ static int __init chaos_tg_init(void)
printk(KERN_WARNING PFX "Warning: Could not find or load "
"\"DELUDE\" target\n");
ret = xt_register_target(&chaos_tg_reg);
if (ret != 0) {
if ((ret = xt_register_target(&chaos_tg_reg)) != 0) {
printk(KERN_WARNING PFX "xt_register_target returned "
"error %d\n", ret);
goto out3;

View File

@@ -25,8 +25,8 @@
#include "compat_xtables.h"
#define PFX KBUILD_MODNAME ": "
static void delude_send_reset(struct sk_buff *oldskb,
const struct xt_action_param *par)
static void delude_send_reset(struct net *net, struct sk_buff *oldskb,
unsigned int hook)
{
struct tcphdr _otcph, *tcph;
const struct tcphdr *oth;
@@ -51,8 +51,7 @@ static void delude_send_reset(struct sk_buff *oldskb,
return;
/* Check checksum */
if (nf_ip_checksum(oldskb, par->state->hook, ip_hdrlen(oldskb),
IPPROTO_TCP))
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
return;
nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
@@ -108,22 +107,22 @@ static void delude_send_reset(struct sk_buff *oldskb,
addr_type = RTN_UNSPEC;
#ifdef CONFIG_BRIDGE_NETFILTER
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
if (par->state->hook != NF_INET_FORWARD ||
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF) != NULL &&
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF))->physoutdev))
#else
if (par->state->hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
nskb->nf_bridge->physoutdev))
#else
if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
nskb->nf_bridge->mask & BRNF_BRIDGED))
#endif
#else
if (par->state->hook != NF_INET_FORWARD)
if (hook != NF_INET_FORWARD)
#endif
addr_type = RTN_LOCAL;
/* ip_route_me_harder expects skb->dst to be set */
skb_dst_set(nskb, dst_clone(skb_dst(oldskb)));
if (ip_route_me_harder(par_net(par), par->state->sk, nskb, addr_type))
if (ip_route_me_harder(net, nskb, addr_type))
goto free_nskb;
else
niph = ip_hdr(nskb);
@@ -136,7 +135,8 @@ static void delude_send_reset(struct sk_buff *oldskb,
goto free_nskb;
nf_ct_attach(nskb, oldskb);
ip_local_out(par_net(par), nskb->sk, nskb);
ip_local_out(net, nskb->sk, nskb);
return;
free_nskb:
@@ -151,7 +151,13 @@ delude_tg(struct sk_buff *skb, const struct xt_action_param *par)
* a problem, as that is supported since Linux 2.6.35. But since we do not
* actually want to have a connection open, we are still going to drop it.
*/
delude_send_reset(skb, par);
delude_send_reset(par_net(par), skb,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
par->state->hook
#else
par->hooknum
#endif
);
return NF_DROP;
}

View File

@@ -96,8 +96,7 @@ dhcpmac_tg(struct sk_buff *skb, const struct xt_action_param *par)
struct udphdr udpbuf, *udph;
unsigned int i;
if (skb_ensure_writable(skb, ip_hdrlen(skb) + sizeof(udpbuf) +
sizeof(dhcpbuf)))
if (!skb_make_writable(skb, 0))
return NF_DROP;
udph = skb_header_pointer(skb, ip_hdrlen(skb),

View File

@@ -19,10 +19,9 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#ifdef CONFIG_NF_NAT
#include <linux/inet.h>
#include <linux/ip.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
@@ -37,6 +36,12 @@
#include "compat_xtables.h"
#include "xt_DNETMAP.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Kierdelewicz <marek@piasta.pl>");
MODULE_DESCRIPTION(
"Xtables: dynamic two-way 1:1 NAT mapping of IPv4 addresses");
MODULE_ALIAS("ipt_DNETMAP");
static unsigned int default_ttl = 600;
static unsigned int proc_perms = S_IRUGO | S_IWUSR;
static unsigned int proc_uid;
@@ -61,8 +66,14 @@ MODULE_PARM_DESC(whole_prefix,
static unsigned int jtimeout;
struct dnetmap_entry {
struct list_head list, glist, grlist, lru_list;
__be32 prenat_addr, postnat_addr;
struct list_head list;
/* priv2entry */
struct list_head glist;
/* pub2entry */
struct list_head grlist;
struct list_head lru_list;
__be32 prenat_addr;
__be32 postnat_addr;
__u8 flags;
unsigned long stamp;
struct dnetmap_prefix *prefix;
@@ -72,7 +83,8 @@ struct dnetmap_prefix {
struct nf_nat_range prefix;
char prefix_str[20];
#ifdef CONFIG_PROC_FS
char proc_str_data[20], proc_str_stat[25];
char proc_str_data[20];
char proc_str_stat[25];
#endif
struct list_head elist; // element list head
struct list_head list; // prefix list
@@ -103,7 +115,7 @@ static DEFINE_SPINLOCK(dnetmap_lock);
static DEFINE_MUTEX(dnetmap_mutex);
#ifdef CONFIG_PROC_FS
static const struct proc_ops dnetmap_tg_fops, dnetmap_stat_proc_fops;
static const struct file_operations dnetmap_tg_fops, dnetmap_stat_proc_fops;
#endif
static inline unsigned int dnetmap_entry_hash(const __be32 addr)
@@ -115,7 +127,9 @@ static struct dnetmap_entry *
dnetmap_entry_lookup(struct dnetmap_net *dnetmap_net, const __be32 addr)
{
struct dnetmap_entry *e;
unsigned int h = dnetmap_entry_hash(addr);
unsigned int h;
h = dnetmap_entry_hash(addr);
list_for_each_entry(e, &dnetmap_net->dnetmap_iphash[h], glist)
if (memcmp(&e->prenat_addr, &addr, sizeof(addr)) == 0)
@@ -127,7 +141,9 @@ static struct dnetmap_entry *
dnetmap_entry_rlookup(struct dnetmap_net *dnetmap_net, const __be32 addr)
{
struct dnetmap_entry *e;
unsigned int h = dnetmap_entry_hash(addr);
unsigned int h;
h = dnetmap_entry_hash(addr);
list_for_each_entry(e, &dnetmap_net->dnetmap_iphash[hash_size + h],
grlist)
@@ -277,12 +293,12 @@ static int dnetmap_tg_check(const struct xt_tgchk_param *par)
ip_min = ntohl(mr->min_addr.ip) + (whole_prefix == 0);
ip_max = ntohl(mr->max_addr.ip) - (whole_prefix == 0);
sprintf(p->prefix_str, "%pI4/%u", &mr->min_addr.ip,
sprintf(p->prefix_str, NIPQUAD_FMT "/%u", NIPQUAD(mr->min_addr.ip),
33 - ffs(~(ip_min ^ ip_max)));
#ifdef CONFIG_PROC_FS
sprintf(p->proc_str_data, "%pI4_%u", &mr->min_addr.ip,
sprintf(p->proc_str_data, NIPQUAD_FMT "_%u", NIPQUAD(mr->min_addr.ip),
33 - ffs(~(ip_min ^ ip_max)));
sprintf(p->proc_str_stat, "%pI4_%u_stat", &mr->min_addr.ip,
sprintf(p->proc_str_stat, NIPQUAD_FMT "_%u_stat", NIPQUAD(mr->min_addr.ip),
33 - ffs(~(ip_min ^ ip_max)));
#endif
printk(KERN_INFO KBUILD_MODNAME ": new prefix %s\n", p->prefix_str);
@@ -340,22 +356,29 @@ out:
static unsigned int
dnetmap_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
struct net *net = dev_net(par->state->in ? par->state->in : par->state->out);
#else
struct net *net = dev_net(par->in ? par->in : par->out);
#endif
struct dnetmap_net *dnetmap_net = dnetmap_pernet(net);
struct nf_conn *ct;
enum ip_conntrack_info ctinfo;
__be32 prenat_ip, postnat_ip, prenat_ip_prev;
const struct xt_DNETMAP_tginfo *tginfo = par->targinfo;
const struct nf_nat_range *mr = &tginfo->prefix;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
struct nf_nat_range2 newrange;
#else
struct nf_nat_range newrange;
#endif
struct dnetmap_entry *e;
struct dnetmap_prefix *p;
__s32 jttl;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
unsigned int hooknum = par->state->hook;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
__s32 jttl = tginfo->flags & XT_DNETMAP_TTL ? tginfo->ttl * HZ : jtimeout;
#else
unsigned int hooknum = par->hooknum;
#endif
ct = nf_ct_get(skb, &ctinfo);
jttl = tginfo->flags & XT_DNETMAP_TTL ? tginfo->ttl * HZ : jtimeout;
/* in prerouting we try to map postnat-ip to prenat-ip */
if (hooknum == NF_INET_PRE_ROUTING) {
@@ -410,8 +433,8 @@ bind_new_prefix:
if (e->prenat_addr != 0 && time_before(jiffies, e->stamp)) {
if (!disable_log && ! (p->flags & XT_DNETMAP_FULL) ){
printk(KERN_INFO KBUILD_MODNAME
": ip %pI4 - no free adresses in prefix %s\n",
&prenat_ip, p->prefix_str);
": ip " NIPQUAD_FMT " - no free adresses in prefix %s\n",
NIPQUAD(prenat_ip), p->prefix_str);
p->flags |= XT_DNETMAP_FULL;
}
goto no_free_ip;
@@ -424,8 +447,8 @@ bind_new_prefix:
prenat_ip_prev = e->prenat_addr;
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": timeout binding %pI4 -> %pI4\n",
&prenat_ip_prev, &postnat_ip);
": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(prenat_ip_prev), NIPQUAD(postnat_ip) );
list_del(&e->glist);
list_del(&e->grlist);
}
@@ -442,16 +465,18 @@ bind_new_prefix:
(postnat_ip)]);
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": add binding %pI4 -> %pI4\n",
&prenat_ip, &postnat_ip);
": add binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(prenat_ip),NIPQUAD(postnat_ip));
} else {
if (!(tginfo->flags & XT_DNETMAP_REUSE) && !(e->flags & XT_DNETMAP_STATIC))
if (time_before(e->stamp, jiffies) && p != e->prefix) {
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": timeout binding %pI4 -> %pI4\n",
&e->prenat_addr, &e->postnat_addr);
": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(e->prenat_addr),
NIPQUAD(e->postnat_addr));
list_del(&e->glist);
list_del(&e->grlist);
e->prenat_addr = 0;
@@ -475,7 +500,12 @@ bind_new_prefix:
newrange.max_addr.ip = postnat_ip;
newrange.min_proto = mr->min_proto;
newrange.max_proto = mr->max_proto;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->state->hook));
#else
return nf_nat_setup_info(ct, &newrange, HOOK2MANIP(par->hooknum));
#endif
no_rev_map:
no_free_ip:
spin_unlock_bh(&dnetmap_lock);
@@ -550,13 +580,12 @@ static int dnetmap_seq_show(struct seq_file *seq, void *v)
const struct dnetmap_entry *e = v;
if((e->flags & XT_DNETMAP_STATIC) == 0){
seq_printf(seq, "%pI4 -> %pI4 --- ttl: %d lasthit: %lu\n",
&e->prenat_addr, &e->postnat_addr,
(int)(e->stamp - jiffies) / HZ,
(e->stamp - jtimeout) / HZ);
seq_printf(seq, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: %d lasthit: %lu\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr),
(int)(e->stamp - jiffies) / HZ, (e->stamp - jtimeout) / HZ);
}else{
seq_printf(seq, "%pI4 -> %pI4 --- ttl: S lasthit: S\n",
&e->prenat_addr, &e->postnat_addr);
seq_printf(seq, NIPQUAD_FMT " -> " NIPQUAD_FMT " --- ttl: S lasthit: S\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr));
}
return 0;
}
@@ -678,8 +707,8 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
if(e != NULL){
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": timeout binding %pI4 -> %pI4\n",
&e->prenat_addr, &e->postnat_addr);
": timeout binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) );
list_del(&e->glist);
list_del(&e->grlist);
}else{
@@ -701,7 +730,7 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
(e->postnat_addr)]);
list_del(&e->lru_list);
sprintf(str, "%pI4:%pI4", &addr1, &addr2);
sprintf(str, NIPQUAD_FMT ":" NIPQUAD_FMT, NIPQUAD(addr1),NIPQUAD(addr2));
printk(KERN_INFO KBUILD_MODNAME ": adding static binding %s\n", str);
// case of removing binding
@@ -717,8 +746,8 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
if(e != NULL){
if (!disable_log)
printk(KERN_INFO KBUILD_MODNAME
": remove binding %pI4 -> %pI4\n",
&e->prenat_addr, &e->postnat_addr);
": remove binding " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n",
NIPQUAD(e->prenat_addr), NIPQUAD(e->postnat_addr) );
list_del(&e->glist);
list_del(&e->grlist);
if(e->flags & XT_DNETMAP_STATIC){
@@ -748,11 +777,12 @@ dnetmap_tg_proc_write(struct file *file, const char __user *input,size_t size, l
}
static const struct proc_ops dnetmap_tg_fops = {
.proc_open = dnetmap_seq_open,
.proc_read = seq_read,
.proc_write = dnetmap_tg_proc_write,
.proc_release = seq_release_private,
static const struct file_operations dnetmap_tg_fops = {
.open = dnetmap_seq_open,
.read = seq_read,
.write = dnetmap_tg_proc_write,
.release = seq_release_private,
.owner = THIS_MODULE,
};
/* for statistics */
@@ -796,11 +826,11 @@ static int dnetmap_stat_proc_open(struct inode *inode, struct file *file)
return single_open(file, dnetmap_stat_proc_show, PDE_DATA(inode));
}
static const struct proc_ops dnetmap_stat_proc_fops = {
.proc_open = dnetmap_stat_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
static const struct file_operations dnetmap_stat_proc_fops = {
.open = dnetmap_stat_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int __net_init dnetmap_proc_net_init(struct net *net)
@@ -916,18 +946,6 @@ static void __exit dnetmap_tg_exit(void)
xt_unregister_target(&dnetmap_tg_reg);
unregister_pernet_subsys(&dnetmap_net_ops);
}
#else /* CONFIG_NF_NAT */
static int __init dnetmap_tg_init(void)
{
pr_err("CONFIG_NF_NAT is not available in your kernel, hence this module cannot function.");
return -EINVAL;
}
static void __exit dnetmap_tg_exit(void) {}
#endif
module_init(dnetmap_tg_init);
module_exit(dnetmap_tg_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marek Kierdelewicz <marek@piasta.pl>");
MODULE_DESCRIPTION("Xtables: dynamic two-way 1:1 NAT mapping of IPv4 addresses");
MODULE_ALIAS("ipt_DNETMAP");

View File

@@ -35,7 +35,11 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
void *payload;
struct flowi6 fl;
struct dst_entry *dst = NULL;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
struct net *net = dev_net((par->state->in != NULL) ? par->state->in : par->state->out);
#else
struct net *net = dev_net((par->in != NULL) ? par->in : par->out);
#endif
/* This allows us to do the copy operation in fewer lines of code. */
if (skb_linearize(oldskb) < 0)
@@ -97,11 +101,7 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
memcpy(&fl.daddr, &newip->daddr, sizeof(fl.daddr));
fl.fl6_sport = newudp->source;
fl.fl6_dport = newudp->dest;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 11, 0)
security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi_common(&fl));
#else
security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi(&fl));
#endif
dst = ip6_route_output(net, NULL, &fl);
if (dst == NULL || dst->error != 0) {
dst_release(dst);
@@ -117,7 +117,7 @@ echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par)
goto free_nskb;
nf_ct_attach(newskb, oldskb);
ip6_local_out(par_net(par), par->state->sk, newskb);
ip6_local_out(par_net(par), newskb->sk, newskb);
return NF_DROP;
free_nskb:
@@ -195,8 +195,8 @@ echo_tg4(struct sk_buff *oldskb, const struct xt_action_param *par)
/* ip_route_me_harder expects the skb's dst to be set */
skb_dst_set(newskb, dst_clone(skb_dst(oldskb)));
if (ip_route_me_harder(par_net(par), par->state->sk, newskb,
RTN_UNSPEC) != 0)
if (ip_route_me_harder(par_net(par), newskb, RTN_UNSPEC) != 0)
goto free_nskb;
newip->ttl = ip4_dst_hoplimit(skb_dst(newskb));

View File

@@ -64,7 +64,12 @@ static void logmark_ct(const struct nf_conn *ct, enum ip_conntrack_info ctinfo)
printk("%s""CONFIRMED", prev ? "," : "");
prev = true;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0)
printk(" lifetime=%lus", nf_ct_expires(ct) / HZ);
#else
printk(" lifetime=%lus",
(jiffies - ct->timeout.expires) / HZ);
#endif
}
static unsigned int
@@ -77,13 +82,21 @@ logmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
printk("<%u>%.*s""iif=%d hook=%s nfmark=0x%x "
"secmark=0x%x classify=0x%x",
info->level, (unsigned int)sizeof(info->prefix), info->prefix,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
skb_ifindex(skb), hook_names[par->state->hook],
#else
skb_ifindex(skb), hook_names[par->hooknum],
#endif
skb_nfmark(skb), skb_secmark(skb), skb->priority);
ct = nf_ct_get(skb, &ctinfo);
printk(" ctdir=%s", dir_names[ctinfo >= IP_CT_IS_REPLY]);
if (ct == NULL)
printk(" ct=NULL ctmark=NULL ctstate=INVALID ctstatus=NONE");
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0)
else if (nf_ct_is_untracked(ct))
printk(" ct=UNTRACKED ctmark=NULL ctstate=UNTRACKED ctstatus=NONE");
#endif
else
logmark_ct(ct, ctinfo);

View File

@@ -1,156 +0,0 @@
/*
* Protocol modification target for IP tables
*
* 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ipv6.h>
#include <net/checksum.h>
#include <linux/netfilter/x_tables.h>
#include "xt_PROTO.h"
MODULE_AUTHOR("Shanker Wang <i@innull.com>");
MODULE_DESCRIPTION("Xtables: Protocol field modification target");
MODULE_LICENSE("GPL");
static unsigned int
proto_tg(struct sk_buff *skb, const struct xt_action_param *par)
{
struct iphdr *iph;
const struct xt_PROTO_info *info = par->targinfo;
int new_proto;
if (skb_ensure_writable(skb, skb->len))
return NF_DROP;
iph = ip_hdr(skb);
new_proto = iph->protocol;
if (info->mode & (1 << XT_PROTO_SET))
new_proto = info->proto;
if (new_proto != iph->protocol) {
csum_replace2(&iph->check, htons(iph->protocol & 0xff),
htons(new_proto & 0xff));
iph->protocol = new_proto;
}
return XT_CONTINUE;
}
static unsigned int
proto_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
struct ipv6hdr *ip6h;
const struct xt_PROTO_info *info = par->targinfo;
u8 *nexthdr;
unsigned int hdr_offset;
__be16 *fp;
if (skb_ensure_writable(skb, skb->len))
return NF_DROP;
ip6h = ipv6_hdr(skb);
nexthdr = &ip6h->nexthdr;
hdr_offset = sizeof(struct ipv6hdr);
for (;;) {
struct ipv6_opt_hdr _opthdr, *opthp;
unsigned int hdrlen;
unsigned short _frag_off;
if (!ipv6_ext_hdr(*nexthdr) || *nexthdr == NEXTHDR_NONE)
break;
opthp = skb_header_pointer(skb, skb_network_offset(skb) + hdr_offset, sizeof(_opthdr), &_opthdr);
if (!opthp)
return NF_DROP;
if (*nexthdr == NEXTHDR_FRAGMENT) {
if (info->mode & (1 << XT_PROTO_STOP_AT_FRAG))
break;
fp = skb_header_pointer(skb, skb_network_offset(skb) +
hdr_offset + offsetof(struct frag_hdr, frag_off),
sizeof(_frag_off), &_frag_off);
if (!fp)
return NF_DROP;
_frag_off = ntohs(*fp) & ~0x7;
if (_frag_off) { // if the packet is not the first fragment
if (!ipv6_ext_hdr(opthp->nexthdr) || opthp->nexthdr == NEXTHDR_NONE ||
(info->mode & (1 << XT_PROTO_STOP_AT_AUTH) && opthp->nexthdr == NEXTHDR_AUTH)) {
nexthdr = &((struct ipv6_opt_hdr *)(skb_network_header(skb) + hdr_offset))->nexthdr;
break;
} else {
return XT_CONTINUE;
}
}
hdrlen = 8;
} else if(*nexthdr == NEXTHDR_AUTH) {
if (info->mode & (1 << XT_PROTO_STOP_AT_AUTH))
break;
hdrlen = (opthp->hdrlen + 2) << 2;
} else {
hdrlen = ipv6_optlen(opthp);
}
nexthdr = &((struct ipv6_opt_hdr *)(skb_network_header(skb) + hdr_offset))->nexthdr;
hdr_offset += hdrlen;
}
if (info->mode & (1 << XT_PROTO_SET))
*nexthdr = info->proto;
return XT_CONTINUE;
}
static int proto_tg_check(const struct xt_tgchk_param *par)
{
const struct xt_PROTO_info *info = par->targinfo;
if ((info->mode & (1 << XT_PROTO_SET)) == 0) {
pr_info_ratelimited("Did not specify any proto to set\n");
return -EINVAL;
}
if (par->family != NFPROTO_IPV6 && (info->mode & ((1 << XT_PROTO_STOP_AT_FRAG) | (1 << XT_PROTO_STOP_AT_AUTH))) != 0) {
pr_info_ratelimited("Must not specify stop-at-frag and stop-at-auth on non-ipv6 targets\n");
return -EPROTOTYPE;
}
return 0;
}
static struct xt_target proto_tg_reg[] __read_mostly = {
{
.name = "PROTO",
.revision = 0,
.family = NFPROTO_IPV4,
.target = proto_tg,
.targetsize = sizeof(struct xt_PROTO_info),
.table = "mangle",
.checkentry = proto_tg_check,
.me = THIS_MODULE,
},
{
.name = "PROTO",
.revision = 0,
.family = NFPROTO_IPV6,
.target = proto_tg6,
.targetsize = sizeof(struct xt_PROTO_info),
.table = "mangle",
.checkentry = proto_tg_check,
.me = THIS_MODULE,
},
};
static int __init proto_tg_init(void)
{
return xt_register_targets(proto_tg_reg, ARRAY_SIZE(proto_tg_reg));
}
static void __exit proto_tg_exit(void)
{
xt_unregister_targets(proto_tg_reg, ARRAY_SIZE(proto_tg_reg));
}
module_init(proto_tg_init);
module_exit(proto_tg_exit);
MODULE_ALIAS("ipt_PROTO");
MODULE_ALIAS("ip6t_PROTO");

View File

@@ -1,20 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/* Protocol modification module for IP tables */
#ifndef _XT_PROTO_H
#define _XT_PROTO_H
#include <linux/types.h>
enum {
XT_PROTO_SET = 0,
XT_PROTO_STOP_AT_FRAG = 1,
XT_PROTO_STOP_AT_AUTH = 2
};
struct xt_PROTO_info {
__u8 mode;
__u8 proto;
};
#endif

View File

@@ -114,6 +114,7 @@ static unsigned int sysrq_tg(const void *pdata, uint16_t len)
}
desc.tfm = sysrq_tfm;
desc.flags = 0;
ret = crypto_shash_init(&desc);
if (ret != 0)
goto hash_fail;
@@ -204,11 +205,12 @@ sysrq_tg4(struct sk_buff *skb, const struct xt_action_param *par)
if (sysrq_debug)
printk(KERN_INFO KBUILD_MODNAME
": %pI4:%hu -> :%hu len=%u\n",
&iph->saddr, htons(udph->source),
": " NIPQUAD_FMT ":%u -> :%u len=%u\n",
NIPQUAD(iph->saddr), htons(udph->source),
htons(udph->dest), len);
#ifdef WITH_CRYPTO
sprintf(sysrq_digest_password, "%pI4,%s", &iph->daddr, sysrq_password);
sprintf(sysrq_digest_password, NIPQUAD_FMT ",%s",
NIPQUAD(iph->daddr), sysrq_password);
#endif
return sysrq_tg((void *)udph + sizeof(struct udphdr), len);
}
@@ -237,11 +239,13 @@ sysrq_tg6(struct sk_buff *skb, const struct xt_action_param *par)
len = ntohs(udph->len) - sizeof(struct udphdr);
if (sysrq_debug)
printk(KERN_INFO KBUILD_MODNAME ": %pI6:%hu -> :%hu len=%u\n",
&iph->saddr, ntohs(udph->source),
printk(KERN_INFO KBUILD_MODNAME
": " NIP6_FMT ":%hu -> :%hu len=%u\n",
NIP6(iph->saddr), ntohs(udph->source),
ntohs(udph->dest), len);
#ifdef WITH_CRYPTO
sprintf(sysrq_digest_password, "%pI6,%s", &iph->daddr, sysrq_password);
sprintf(sysrq_digest_password, NIP6_FMT ",%s",
NIP6(iph->daddr), sysrq_password);
#endif
return sysrq_tg((void *)udph + sizeof(struct udphdr), len);
}
@@ -310,7 +314,7 @@ static void sysrq_crypto_exit(void)
static int __init sysrq_crypto_init(void)
{
#if defined(WITH_CRYPTO)
struct timespec64 now;
struct timeval now;
int ret;
sysrq_tfm = crypto_alloc_shash(sysrq_hash, 0, 0);
@@ -335,7 +339,7 @@ static int __init sysrq_crypto_init(void)
sizeof(sysrq_password), GFP_KERNEL);
if (sysrq_digest_password == NULL)
goto fail;
ktime_get_real_ts64(&now);
do_gettimeofday(&now);
sysrq_seqno = now.tv_sec;
return 0;

View File

@@ -170,8 +170,8 @@ static bool tarpit_generic(struct tcphdr *tcph, const struct tcphdr *oth,
return true;
}
static void tarpit_tcp4(const struct xt_action_param *par,
struct sk_buff *oldskb, unsigned int mode)
static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb,
unsigned int hook, unsigned int mode)
{
struct tcphdr _otcph, *tcph;
const struct tcphdr *oth;
@@ -191,8 +191,7 @@ static void tarpit_tcp4(const struct xt_action_param *par,
return;
/* Check checksum. */
if (nf_ip_checksum(oldskb, par->state->hook, ip_hdrlen(oldskb),
IPPROTO_TCP))
if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
return;
/*
@@ -206,11 +205,7 @@ static void tarpit_tcp4(const struct xt_action_param *par,
return;
/* This packet will not be the same as the other: clear nf fields */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
nf_reset_ct(nskb);
#else
nf_reset(nskb);
#endif
skb_nfmark(nskb) = 0;
skb_init_secmark(nskb);
skb_shinfo(nskb)->gso_size = 0;
@@ -254,20 +249,19 @@ static void tarpit_tcp4(const struct xt_action_param *par,
niph->id = ~oldhdr->id + 1;
#ifdef CONFIG_BRIDGE_NETFILTER
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
if (par->state->hook != NF_INET_FORWARD ||
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF) != NULL &&
((struct nf_bridge_info *)skb_ext_find(nskb, SKB_EXT_BRIDGE_NF))->physoutdev))
#else
if (par->state->hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
nskb->nf_bridge->physoutdev != NULL))
#else
if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
nskb->nf_bridge->mask & BRNF_BRIDGED))
#endif
#else
if (par->state->hook != NF_INET_FORWARD)
if (hook != NF_INET_FORWARD)
#endif
addr_type = RTN_LOCAL;
if (ip_route_me_harder(par_net(par), par->state->sk, nskb, addr_type) != 0)
if (ip_route_me_harder(net, nskb, addr_type))
goto free_nskb;
else
niph = ip_hdr(nskb);
@@ -289,8 +283,17 @@ static void tarpit_tcp4(const struct xt_action_param *par,
goto free_nskb;
nf_ct_attach(nskb, oldskb);
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, par_net(par), nskb->sk, nskb,
NULL, skb_dst(nskb)->dev, dst_output);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output_sk);
#else
NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#endif
return;
free_nskb:
@@ -298,8 +301,8 @@ static void tarpit_tcp4(const struct xt_action_param *par,
}
#ifdef WITH_IPV6
static void tarpit_tcp6(const struct xt_action_param *par,
struct sk_buff *oldskb, unsigned int mode)
static void tarpit_tcp6(struct net *net, struct sk_buff *oldskb,
unsigned int hook, unsigned int mode)
{
struct sk_buff *nskb;
struct tcphdr *tcph, oth;
@@ -352,11 +355,7 @@ static void tarpit_tcp6(const struct xt_action_param *par,
}
/* This packet will not be the same as the other: clear nf fields */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
nf_reset_ct(nskb);
#else
nf_reset(nskb);
#endif
skb_nfmark(nskb) = 0;
skb_init_secmark(nskb);
skb_shinfo(nskb)->gso_size = 0;
@@ -400,14 +399,24 @@ static void tarpit_tcp6(const struct xt_action_param *par,
&ipv6_hdr(nskb)->daddr, sizeof(struct tcphdr),
IPPROTO_TCP,
csum_partial(tcph, sizeof(struct tcphdr), 0));
if (ip6_route_me_harder(par_net(par), nskb->sk, nskb))
if (ip6_route_me_harder(net, nskb))
goto free_nskb;
nskb->ip_summed = CHECKSUM_NONE;
nf_ct_attach(nskb, oldskb);
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, par_net(par), nskb->sk, nskb,
NULL, skb_dst(nskb)->dev, dst_output);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, nskb->sk, nskb, NULL,
skb_dst(nskb)->dev, dst_output_sk);
#else
NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, nskb, NULL,
skb_dst(nskb)->dev, dst_output);
#endif
return;
free_nskb:
@@ -445,7 +454,12 @@ tarpit_tg4(struct sk_buff *skb, const struct xt_action_param *par)
/* We are not interested in fragments */
if (iph->frag_off & htons(IP_OFFSET))
return NF_DROP;
tarpit_tcp4(par, skb, info->variant);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
tarpit_tcp4(par_net(par), skb, par->state->hook, info->variant);
#else
tarpit_tcp4(par_net(par), skb, par->hooknum, info->variant);
#endif
return NF_DROP;
}
@@ -486,7 +500,12 @@ tarpit_tg6(struct sk_buff *skb, const struct xt_action_param *par)
pr_debug("addr is not unicast.\n");
return NF_DROP;
}
tarpit_tcp6(par, skb, info->variant);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
tarpit_tcp6(par_net(par), skb, par->state->hook, info->variant);
#else
tarpit_tcp6(par_net(par), skb, par->hooknum, info->variant);
#endif
return NF_DROP;
}
#endif

View File

@@ -111,12 +111,12 @@ condition_proc_write(struct file *file, const char __user *buffer,
return length;
}
static const struct proc_ops condition_proc_fops = {
.proc_open = condition_proc_open,
.proc_read = seq_read,
.proc_write = condition_proc_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
static const struct file_operations condition_proc_fops = {
.open = condition_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.write = condition_proc_write,
.release = single_release,
};
static bool

View File

@@ -45,9 +45,17 @@ static const struct net_device *iface_get(const struct xt_iface_mtinfo *info,
const struct xt_action_param *par, struct net_device **put)
{
if (info->flags & XT_IFACE_DEV_IN)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
return par->state->in;
#else
return par->in;
#endif
else if (info->flags & XT_IFACE_DEV_OUT)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
return par->state->out;
#else
return par->out;
#endif
return *put = dev_get_by_name(&init_net, info->ifname);
}

View File

@@ -857,11 +857,8 @@ ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
p2p_result = matchlist[i].function_name(haystack, hlen);
if (p2p_result) {
if (info->debug)
printk("IPP2P.debug:TCP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %d\n",
p2p_result, &ip->saddr,
ntohs(tcph->source),
&ip->daddr,
ntohs(tcph->dest), hlen);
printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
return p2p_result;
}
}
@@ -891,11 +888,8 @@ ipp2p_mt(const struct sk_buff *skb, struct xt_action_param *par)
p2p_result = udp_list[i].function_name(haystack, hlen);
if (p2p_result) {
if (info->debug)
printk("IPP2P.debug:UDP-match: %d from: %pI4:%hu to: %pI4:%hu Length: %d\n",
p2p_result, &ip->saddr,
ntohs(udph->source),
&ip->daddr,
ntohs(udph->dest), hlen);
printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
p2p_result, NIPQUAD(ip->saddr), ntohs(udph->source), NIPQUAD(ip->daddr), ntohs(udph->dest), hlen);
return p2p_result;
}
}

View File

@@ -188,8 +188,7 @@ lscan_mt(const struct sk_buff *skb, struct xt_action_param *par)
return true;
/* Check for invalid packets: -m conntrack --ctstate INVALID */
ctdata = nf_ct_get(skb, &ctstate);
if (ctdata == NULL) {
if ((ctdata = nf_ct_get(skb, &ctstate)) == NULL) {
if (info->match_fl1 & LSCAN_FL1_STEALTH)
return lscan_mt_stealth(tcph);
/*
@@ -209,7 +208,11 @@ lscan_mt(const struct sk_buff *skb, struct xt_action_param *par)
unsigned int n;
n = lscan_mt_full(ctdata->mark & connmark_mask, ctstate,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,10,0)
par->state->in == init_net.loopback_dev, tcph,
#else
par->in == init_net.loopback_dev, tcph,
#endif
skb->len - par->thoff - 4 * tcph->doff);
ctdata->mark = (ctdata->mark & ~connmark_mask) | n;

View File

@@ -117,12 +117,12 @@ quota_proc_write(struct file *file, const char __user *input,
return size;
}
static const struct proc_ops quota_proc_fops = {
.proc_open = quota_proc_open,
.proc_read = seq_read,
.proc_write = quota_proc_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
static const struct file_operations quota_proc_fops = {
.open = quota_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.write = quota_proc_write,
.release = single_release,
};
static struct xt_quota_counter *

View File

@@ -1,9 +1,5 @@
# -*- Makefile -*-
bin_SCRIPTS = xt_geoip_query
pkglibexec_SCRIPTS = xt_geoip_build xt_geoip_dl
pkglibexec_SCRIPTS = xt_geoip_build xt_geoip_build_maxmind xt_geoip_dl xt_geoip_dl_maxmind
man1_MANS = xt_geoip_build.1 xt_geoip_dl.1 \
xt_geoip_build_maxmind.1 xt_geoip_dl_maxmind.1 \
xt_geoip_query.1
man1_MANS = xt_geoip_build.1 xt_geoip_dl.1

View File

@@ -1,78 +1,86 @@
#!/usr/bin/perl
#
# Converter for DBIP (Country Lite) CSV database to binary, for xt_geoip
# Copyright Jan Engelhardt, 2008-2011
# Copyright Philip Prindeville, 2018
# Copyright Arjen de Korte, 2020
# Converter for MaxMind CSV database to binary, for xt_geoip
# Copyright © Jan Engelhardt, 2008-2011
#
use Getopt::Long;
use Net::CIDR::Lite;
use Socket qw(AF_INET AF_INET6 inet_pton);
use warnings;
use IO::Handle;
use Text::CSV_XS; # or trade for Text::CSV
use strict;
my $le32 = pack("V", 0x10000000);
my $be32 = pack("N", 0x10000000);
my $u32 = undef;
sub wantBE { return !$u32 || $u32 eq $be32; }
sub wantLE { return !$u32 || $u32 eq $le32; }
my $csv = Text::CSV_XS->new({
allow_whitespace => 1,
binary => 1,
eol => $/,
}); # or Text::CSV
my $quiet = 0;
my $input_file = "dbip-country-lite.csv";
my $target_dir = ".";
my $native_only = 0;
&Getopt::Long::Configure(qw(bundling));
&GetOptions(
"D=s" => \$target_dir,
"i=s" => \$input_file,
"q" => \$quiet,
"s" => sub { $target_dir = "/usr/share/xt_geoip"; },
"n" => \$native_only,
);
if (!-d $target_dir) {
print STDERR "Target directory \"$target_dir\" does not exist.\n";
print STDERR "Target directory $target_dir does not exist.\n";
exit 1;
}
my @dbs = qw(LE BE);
if ($native_only) {
$u32 = pack("L", 0x10000000);
if ($u32 eq $le32) {
@dbs = qw(LE);
} elsif ($u32 eq $be32) {
@dbs = qw(BE);
} else {
print STDERRR "Cannot determine endianness.\n";
exit 1;
}
}
foreach (@dbs) {
my $dir = "$target_dir/$_";
if (!-e $dir && !mkdir($dir)) {
print STDERR "Could not mkdir $dir: $!\n";
exit 1;
}
}
&dump(&collect());
sub collect
{
my ($file, $fh, $row);
my (%country);
if ($input_file eq "-") {
open($fh, "<&STDIN");
} else {
open($fh, "<", $input_file) || die "Cannot open $input_file: $!\n";
}
my %country;
while ($row = $csv->getline($fh)) {
my ($cc, $range);
$cc = $row->[2];
$range = $row->[0] . "-" . $row->[1];
if (!exists($country{$cc})) {
$country{$cc} = { pool_v4 => Net::CIDR::Lite->new(), pool_v6 => Net::CIDR::Lite->new() };
while (my $row = $csv->getline(*ARGV)) {
if (!defined($country{$row->[4]})) {
$country{$row->[4]} = {
name => $row->[5],
pool_v4 => [],
pool_v6 => [],
};
}
if (index($range, '.') > 0) {
$country{$cc}->{pool_v4}->add_range($range);
my $c = $country{$row->[4]};
if ($row->[0] =~ /:/) {
push(@{$c->{pool_v6}},
[&ip6_pack($row->[0]), &ip6_pack($row->[1])]);
} else {
push(@{$c->{pool_v4}}, [$row->[2], $row->[3]]);
}
if (index($range, ':') > 0) {
$country{$cc}->{pool_v6}->add_range($range);
}
if (!$quiet && $. % 4096 == 0) {
if ($. % 4096 == 0) {
print STDERR "\r\e[2K$. entries";
}
}
print STDERR "\r\e[2K$. entries total\n" unless ($quiet);
close($fh);
print STDERR "\r\e[2K$. entries total\n";
return \%country;
}
@@ -80,7 +88,7 @@ sub dump
{
my $country = shift @_;
foreach my $iso_code (sort keys %{$country}) {
foreach my $iso_code (sort keys %$country) {
&dump_one($iso_code, $country->{$iso_code});
}
}
@@ -88,40 +96,80 @@ sub dump
sub dump_one
{
my($iso_code, $country) = @_;
my @ranges;
my($file, $fh_le, $fh_be);
@ranges = $country->{pool_v4}->list_range();
printf "%5u IPv6 ranges for %s %s\n",
scalar(@{$country->{pool_v6}}),
$iso_code, $country->{name};
writeCountry($iso_code, AF_INET, @ranges);
if (wantLE) {
$file = "$target_dir/LE/".uc($iso_code).".iv6";
if (!open($fh_le, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
foreach my $range (@{$country->{pool_v6}}) {
print $fh_le &ip6_swap($range->[0]), &ip6_swap($range->[1]);
}
close $fh_le;
}
if (wantBE) {
$file = "$target_dir/BE/".uc($iso_code).".iv6";
if (!open($fh_be, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
foreach my $range (@{$country->{pool_v6}}) {
print $fh_be $range->[0], $range->[1];
}
close $fh_be;
}
@ranges = $country->{pool_v6}->list_range();
printf "%5u IPv4 ranges for %s %s\n",
scalar(@{$country->{pool_v4}}),
$iso_code, $country->{name};
writeCountry($iso_code, AF_INET6, @ranges);
if (wantLE) {
$file = "$target_dir/LE/".uc($iso_code).".iv4";
if (!open($fh_le, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
foreach my $range (@{$country->{pool_v4}}) {
print $fh_le pack("VV", $range->[0], $range->[1]);
}
close $fh_le;
}
if (wantBE) {
$file = "$target_dir/BE/".uc($iso_code).".iv4";
if (!open($fh_be, "> $file")) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
foreach my $range (@{$country->{pool_v4}}) {
print $fh_be pack("NN", $range->[0], $range->[1]);
}
close $fh_be;
}
}
sub writeCountry
sub ip6_pack
{
my ($iso_code, $family, @ranges) = @_;
my $fh;
printf "%5u IPv%s ranges for %s\n",
scalar(@ranges),
($family == AF_INET ? '4' : '6'),
$iso_code unless ($quiet);
my $file = "$target_dir/".uc($iso_code).".iv".($family == AF_INET ? '4' : '6');
if (!open($fh, '>', $file)) {
print STDERR "Error opening $file: $!\n";
exit 1;
my $addr = shift @_;
$addr =~ s{::}{:!:};
my @addr = split(/:/, $addr);
my @e = (0) x 8;
foreach (@addr) {
if ($_ eq "!") {
$_ = join(':', @e[0..(8-scalar(@addr))]);
}
}
binmode($fh);
foreach my $range (@ranges) {
my ($start, $end) = split('-', $range);
$start = inet_pton($family, $start);
$end = inet_pton($family, $end);
print $fh $start, $end;
}
close $fh;
@addr = split(/:/, join(':', @addr));
$_ = hex($_) foreach @addr;
return pack("n*", @addr);
}
sub ip6_swap
{
return pack("V*", unpack("N*", shift @_));
}

View File

@@ -5,7 +5,7 @@ xt_geoip_build \(em convert GeoIP.csv to packed format for xt_geoip
.SH Syntax
.PP
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build\fP [\fB\-D\fP
\fItarget_dir\fP] [\fB\-i\fP \fIinput_file\fP]
\fItarget_dir\fP] [\fIfile\fP...]
.SH Description
.PP
xt_geoip_build is used to build packed raw representations of the range
@@ -16,26 +16,20 @@ required to be loaded into memory. The ranges in the packed database files are
also ordered, as xt_geoip relies on this property for its bisection approach to
work.
.PP
Input is processed from the listed files, or if none is given, from stdin.
.PP
Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the
script requires it to be called with a path.
.PP Options
.TP
\fB\-D\fP \fItarget_dir\fP
Specifies the target directory into which the files are to be put. Defaults to ".".
.TP
\fB\-i\fP \fIinput_file\fP
Specifies the source location of the DBIP CSV file. Defaults to
"dbip-country-lite.csv". Use "-" to read from stdin.
.TP
\fB\-s\fP
"System mode". Equivalent to \fB\-D /usr/share/xt_geoip\fP.
Specify a target directory into which the files are to be put.
.SH Application
.PP
Shell commands to build the databases and put them to where they are expected
(usually run as root):
Shell commands to build the databases and put them to where they are expected:
.PP
xt_geoip_build \-s
xt_geoip_build \-D /usr/share/xt_geoip
.SH See also
.PP
xt_geoip_dl(1)

View File

@@ -1,268 +0,0 @@
#!/usr/bin/perl
#
# Converter for MaxMind (GeoLite2) CSV database to binary, for xt_geoip
# Copyright Jan Engelhardt, 2008-2011
# Copyright Philip Prindeville, 2018
#
use Getopt::Long;
use Net::CIDR::Lite;
use Socket qw(AF_INET AF_INET6 inet_pton);
use warnings;
use Text::CSV_XS; # or trade for Text::CSV
use strict;
my $csv = Text::CSV_XS->new({
allow_whitespace => 1,
binary => 1,
eol => $/,
}); # or Text::CSV
my $source_dir = ".";
my $quiet = 0;
my $target_dir = ".";
&Getopt::Long::Configure(qw(bundling));
&GetOptions(
"D=s" => \$target_dir,
"S=s" => \$source_dir,
"q" => \$quiet,
"s" => sub { $target_dir = "/usr/share/xt_geoip"; },
);
if (!-d $source_dir) {
print STDERR "Source directory \"$source_dir\" does not exist.\n";
exit 1;
}
if (!-d $target_dir) {
print STDERR "Target directory \"$target_dir\" does not exist.\n";
exit 1;
}
my %countryId;
my %countryName;
&loadCountries();
&dump(&collect());
sub loadCountries
{
sub id; sub cc; sub long; sub ct; sub cn;
%countryId = ();
%countryName = ();
my $file = "$source_dir/GeoLite2-Country-Locations-en.csv";
open(my $fh, '<', $file) || die "Couldn't open list country names\n";
# first line is headers
my $row = $csv->getline($fh);
my %header = map { ($row->[$_], $_); } (0..$#{$row});
my %pairs = (
country_iso_code => 'ISO Country Code',
geoname_id => 'ID',
country_name => 'Country Name',
continent_code => 'Continent Code',
continent_name => 'Continent Name',
);
# verify that the columns we need are present
map { die "Table has no $pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;
my %remapping = (
id => 'geoname_id',
cc => 'country_iso_code',
long => 'country_name',
ct => 'continent_code',
cn => 'continent_name',
);
# now create a function which returns the value of that column #
map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;
while (my $row = $csv->getline($fh)) {
if ($row->[cc] eq '' && $row->[long] eq '') {
$countryId{$row->[id]} = $row->[ct];
$countryName{$row->[ct]} = $row->[cn];
} else {
$countryId{$row->[id]} = $row->[cc];
$countryName{$row->[cc]} = $row->[long];
}
}
$countryName{A1} = 'Anonymous Proxy';
$countryName{A2} = 'Satellite Provider';
$countryName{O1} = 'Other Country';
close($fh);
# clean up the namespace
undef &id; undef &cc; undef &long; undef &ct; undef &cn;
}
sub lookupCountry
{
my ($id, $rid, $proxy, $sat) = @_;
if ($proxy) {
return 'A1';
} elsif ($sat) {
return 'A2';
}
$id ||= $rid;
if ($id eq '') {
return 'O1';
}
die "Unknown id: $id line $.\n" unless (exists $countryId{$id});
return $countryId{$id};
}
sub collect
{
my ($file, $fh, $row);
my (%country, %header);
sub net; sub id; sub rid; sub proxy; sub sat;
my %pairs = (
network => 'Network',
registered_country_geoname_id => 'Registered Country ID',
geoname_id => 'Country ID',
is_anonymous_proxy => 'Anonymous Proxy',
is_satellite_provider => 'Satellite',
);
foreach (sort keys %countryName) {
$country{$_} = {
name => $countryName{$_},
pool_v4 => Net::CIDR::Lite->new(),
pool_v6 => Net::CIDR::Lite->new(),
};
}
$file = "$source_dir/GeoLite2-Country-Blocks-IPv4.csv";
open($fh, '<', $file) || die "Can't open IPv4 database\n";
# first line is headers
$row = $csv->getline($fh);
%header = map { ($row->[$_], $_); } (0..$#{$row});
# verify that the columns we need are present
map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;
my %remapping = (
net => 'network',
id => 'geoname_id',
rid => 'registered_country_geoname_id',
proxy => 'is_anonymous_proxy',
sat => 'is_satellite_provider',
);
# now create a function which returns the value of that column #
map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;
while ($row = $csv->getline($fh)) {
my ($cc, $cidr);
$cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]);
$cidr = $row->[net];
$country{$cc}->{pool_v4}->add($cidr);
if ($. % 4096 == 0) {
print STDERR "\r\e[2K$. entries";
}
}
print STDERR "\r\e[2K$. entries total\n";
close($fh);
# clean up the namespace
undef &net; undef &id; undef &rid; undef &proxy; undef &sat;
$file = "$source_dir/GeoLite2-Country-Blocks-IPv6.csv";
open($fh, '<', $file) || die "Can't open IPv6 database\n";
# first line is headers
$row = $csv->getline($fh);
%header = map { ($row->[$_], $_); } (0..$#{$row});
# verify that the columns we need are present
map { die "Table has no %pairs{$_} column\n" unless (exists $header{$_}); } keys %pairs;
# unlikely the IPv6 table has different columns, but just to be sure
# create a function which returns the value of that column #
map { eval "sub $_ () { \$header{\$remapping{$_}}; }" ; } keys %remapping;
while ($row = $csv->getline($fh)) {
my ($cc, $cidr);
$cc = lookupCountry($row->[id], $row->[rid], $row->[proxy], $row->[sat]);
$cidr = $row->[net];
$country{$cc}->{pool_v6}->add($cidr);
if (!$quiet && $. % 4096 == 0) {
print STDERR "\r\e[2K$. entries";
}
}
print STDERR "\r\e[2K$. entries total\n" unless ($quiet);
close($fh);
# clean up the namespace
undef &net; undef &id; undef &rid; undef &proxy; undef &sat;
return \%country;
}
sub dump
{
my $country = shift @_;
foreach my $iso_code (sort keys %{$country}) {
&dump_one($iso_code, $country->{$iso_code});
}
}
sub dump_one
{
my($iso_code, $country) = @_;
my @ranges;
@ranges = $country->{pool_v4}->list_range();
writeCountry($iso_code, $country->{name}, AF_INET, @ranges);
@ranges = $country->{pool_v6}->list_range();
writeCountry($iso_code, $country->{name}, AF_INET6, @ranges);
}
sub writeCountry
{
my ($iso_code, $name, $family, @ranges) = @_;
my $fh;
printf "%5u IPv%s ranges for %s %s\n",
scalar(@ranges),
($family == AF_INET ? '4' : '6'),
$iso_code, $name unless ($quiet);
my $file = "$target_dir/".uc($iso_code).".iv".($family == AF_INET ? '4' : '6');
if (!open($fh, '>', $file)) {
print STDERR "Error opening $file: $!\n";
exit 1;
}
binmode($fh);
foreach my $range (@ranges) {
my ($start, $end) = split('-', $range);
$start = inet_pton($family, $start);
$end = inet_pton($family, $end);
print $fh $start, $end;
}
close $fh;
}

View File

@@ -1,40 +0,0 @@
.TH xt_geoip_build_maxmind 1 "2010-12-17" "xtables-addons" "xtables-addons"
.SH Name
.PP
xt_geoip_build_maxmind \(em convert GeoIP.csv to packed format for xt_geoip
.SH Syntax
.PP
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_build_maxmind\fP [\fB\-D\fP
\fItarget_dir\fP] [\fB\-S\fP \fIsource_dir\fP]
.SH Description
.PP
xt_geoip_build_maxmind is used to build packed raw representations of the range
database that the xt_geoip module relies on. Since kernel memory is precious,
much of the preprocessing is done in userspace by this very building tool. One
file is produced for each country, so that no more addresses than needed are
required to be loaded into memory. The ranges in the packed database files are
also ordered, as xt_geoip relies on this property for its bisection approach to
work.
.PP
Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the
script requires it to be called with a path.
.PP Options
.TP
\fB\-D\fP \fItarget_dir\fP
Specifies the target directory into which the files are to be put. Defaults to ".".
.TP
\fB\-S\fP \fIsource_dir\fP
Specifies the source directory of the MaxMind CSV files. Defaults to ".".
.TP
\fB\-s\fP
"System mode". Equivalent to \fB\-D /usr/share/xt_geoip\fP.
.SH Application
.PP
Shell commands to build the databases and put them to where they are expected
(usually run as root):
.PP
xt_geoip_build_maxmind \-s
.SH See also
.PP
xt_geoip_dl_maxmind(1)

View File

@@ -1,5 +1,8 @@
#!/bin/sh
timestamp=$(date "+%Y-%m")
wget -q "https://download.db-ip.com/free/dbip-country-lite-$timestamp.csv.gz" -O- | \
gzip -cd >dbip-country-lite.csv
rm -f GeoIPv6.csv GeoIPv6.csv.gz GeoIPCountryCSV.zip GeoIPCountryWhois.csv;
wget \
http://geolite.maxmind.com/download/geoip/database/GeoIPv6.csv.gz \
http://geolite.maxmind.com/download/geoip/database/GeoIPCountryCSV.zip;
gzip -d GeoIPv6.csv.gz;
unzip GeoIPCountryCSV.zip;

View File

@@ -7,9 +7,8 @@ xt_geoip_dl \(em download GeoIP database files
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_dl\fP
.SH Description
.PP
Downloads the DB-IP Country Lite databases for IPv4 and IPv6 and unpacks them
to the current directory. The alternate \fBxt_geoip_dl_maxmind\fP script can be
used for MaxMind formatted CSV databases.
Downloads and unpacks the MaxMind GeoIP Country Lite databases for IPv4 and
IPv6 and unpacks them to the current directory.
.PP
Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the

View File

@@ -1,16 +0,0 @@
#!/bin/sh
if [ $# -eq 1 ]; then
exec <$1
elif [ $# -ne 0 ]; then
echo $(basename $0) [ licence_key_file ] 1>&2
exit 1
fi
read licence_key
rm -rf GeoLite2-Country-CSV_*
wget -q -OGeoLite2-Country-CSV.zip "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV&license_key=${licence_key}&suffix=zip"
unzip -q GeoLite2-Country-CSV.zip
rm -f GeoLite2-Country-CSV.zip

View File

@@ -1,22 +0,0 @@
.TH xt_geoip_dl_maxmind 1 "2010-12-17" "xtables-addons" "xtables-addons"
.SH Name
.PP
xt_geoip_dl_maxmind \(em download MaxMind GeoIP database files
.SH Syntax
.PP
\fI/usr/libexec/xt_geoip/\fP\fBxt_geoip_dl_maxmind\fP [\fI licence-key file\fP]
.SH Description
.PP
Downloads the MaxMind GeoLite2 databases for IPv4 and IPv6 and unpacks them to
the current directory. The alternate \fBxt_geoip_dl\fP script can be
used for the DB-IP Country Lite databases.
.PP
Since the script is usually installed to the libexec directory of the
xtables-addons package and this is outside $PATH (on purpose), invoking the
script requires it to be called with a path.
.SH Options
.PP
None.
.SH See also
.PP
xt_geoip_build_maxmind(1)

View File

@@ -1,95 +0,0 @@
#!/usr/bin/perl
#
# Utility to query GeoIP database (.iv4/.iv6 files)
# Copyright Philip Prindeville, 2018
#
use Getopt::Long;
use Socket qw(AF_INET AF_INET6 inet_ntop);
use warnings;
use strict;
sub AF_INET_SIZE() { 4 }
sub AF_INET6_SIZE() { 16 }
my $target_dir = ".";
my $ipv4 = 0;
my $ipv6 = 0;
&Getopt::Long::Configure(qw(bundling));
&GetOptions(
"D=s" => \$target_dir,
"4" => \$ipv4,
"6" => \$ipv6,
);
if (!-d $target_dir) {
print STDERR "Target directory $target_dir does not exit.\n";
exit 1;
}
# if neither specified, assume both
if (! $ipv4 && ! $ipv6) {
$ipv4 = $ipv6 = 1;
}
foreach my $cc (@ARGV) {
if ($cc !~ m/^([a-z]{2}|a[12]|o1)$/i) {
print STDERR "Invalid country code '$cc'\n";
exit 1;
}
my $file = $target_dir . '/' . uc($cc) . '.iv4';
if (! -f $file) {
printf STDERR "Can't find data for country '$cc'\n";
exit 1;
}
my ($contents, $buffer, $bytes, $fh);
if ($ipv4) {
open($fh, '<', $file) || die "Couldn't open file for '$cc'\n";
binmode($fh);
while (($bytes = read($fh, $buffer, AF_INET_SIZE * 2)) == AF_INET_SIZE * 2) {
my ($start, $end) = unpack('a4a4', $buffer);
$start = inet_ntop(AF_INET, $start);
$end = inet_ntop(AF_INET, $end);
print $start, '-', $end, "\n";
}
close($fh);
if (! defined $bytes) {
printf STDERR "Error reading file for '$cc'\n";
exit 1;
} elsif ($bytes != 0) {
printf STDERR "Short read on file for '$cc'\n";
exit 1;
}
}
substr($file, -1) = '6';
if ($ipv6) {
open($fh, '<', $file) || die "Couldn't open file for '$cc'\n";
binmode($fh);
while (($bytes = read($fh, $buffer, AF_INET6_SIZE * 2)) == AF_INET6_SIZE * 2) {
my ($start, $end) = unpack('a16a16', $buffer);
$start = inet_ntop(AF_INET6, $start);
$end = inet_ntop(AF_INET6, $end);
print $start, '-', $end, "\n";
}
close($fh);
if (! defined $bytes) {
printf STDERR "Error reading file for '$cc'\n";
exit 1;
} elsif ($bytes != 0) {
printf STDERR "Short read on file for '$cc'\n";
exit 1;
}
}
}
exit 0;

View File

@@ -1,35 +0,0 @@
.TH xt_geoip_query 1 "2020-04-30" "xtables-addons" "xtables-addons"
.SH Name
.PP
xt_geoip_query \(em dump a country database to stdout
.SH Syntax
.PP
\fBxt_geoip_query\fP [\fB\-D\fP
\fIdatabase_dir\fP] [\fB-4\fP] [\fB-6\fP] \fIcc\fP [ \fIcc\fP ... ]
.SH Description
.PP
xt_geoip_query reads a country's IPv4 or IPv6 databases and dumps
them to standard output as a sorted, non-overlapping list of ranges (which
is how they are represented in the database), suitable for browsing or
further processing.
.PP Options
.TP
\fB\-D\fP \fIdatabase_dir\fP
Specifies the directory into which the files have been put. Defaults to ".".
.TP
\fB-4\fP
Specifies IPv4 data only.
.TP
\fB-6\fP
Specifies IPv6 data only.
.TP
\fIcc\fP [ \fIcc\fP ... ]
The ISO-3166 country code names of the desired countries' databases.
.SH Application
.PP
Shell command to dump the list of Swiss IPv6 address ranges:
.PP
xt_geoip_query \-D /usr/share/xt_geoip \-6 ch
.SH See also
.PP
xt_geoip_build(1)

View File

@@ -8,7 +8,6 @@ build_DNETMAP=m
build_ECHO=m
build_IPMARK=m
build_LOGMARK=m
build_PROTO=m
build_SYSRQ=m
build_TARPIT=m
build_condition=m

3
sources Normal file
View File

@@ -0,0 +1,3 @@
#
# Source URLs for external patchlets
#

83
xa-download-more Executable file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/perl -w
use HTTP::Request;
use LWP::UserAgent;
use strict;
&main(\@ARGV);
sub main
{
local *FH;
if (!-d "downloads") {
if (!mkdir("downloads")) {
die "Could not create downloads/ directory";
}
}
open(FH, "<sources");
while (defined($_ = <FH>)) {
chomp $_;
$_ =~ s/#.*//gs;
$_ =~ s/^\s+|\s+$//gs;
if (length($_) == 0) {
next;
}
&process_index($_);
}
close FH;
}
sub process_index
{
my $top = shift @_;
my($agent, $res, $url);
local *FH;
$agent = LWP::UserAgent->new();
$agent->env_proxy();
$url = &slash_remove("$top/xa-index.txt");
print " GET $url\n";
$res = $agent->get($url);
if (!$res->is_success()) {
print STDERR " `-> ", $res->status_line(), "\n";
return;
}
foreach my $ext (split(/\s+/, $res->content())) {
my($ex_url, $ex_res);
$ex_url = &slash_remove("$top/$ext");
print " GET $ex_url\n";
$ex_res = $agent->mirror($ex_url, "downloads/$ext");
if ($ex_res->code() == 304) {
# "Not modified" = up to date
next;
}
if (!$ex_res->is_success()) {
print STDERR " `-> ", $ex_res->status_line(), "\n";
next;
}
print " UNPACK downloads/$ext\n";
system "tar", "-xjf", "downloads/$ext";
}
}
sub slash_remove
{
my $s = shift @_;
$s =~ s{(\w+://)(.*)}{$1.&slash_remove2($2)}eg;
return $s;
}
sub slash_remove2
{
my $s = shift @_;
$s =~ s{/+}{/}g;
return $s;
}

View File

@@ -1,4 +1,4 @@
.TH xtables-addons 8 "" "" "v3.18 (2021-03-11)"
.TH xtables-addons 8 "" "" "v2.15 (2021-02-05)"
.SH Name
Xtables-addons \(em additional extensions for iptables, ip6tables, etc.
.SH Targets