mirror of
git://git.code.sf.net/p/xtables-addons/xtables-addons
synced 2025-09-06 12:45:13 +02:00
Merge branch 'ipset'
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
|||||||
.libs
|
.libs
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
|
GNUmakefile
|
||||||
|
|
||||||
/downloads
|
/downloads
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
# -*- Makefile -*-
|
# -*- Makefile -*-
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = foreign subdir-objects
|
AUTOMAKE_OPTIONS = foreign subdir-objects
|
||||||
SUBDIRS = extensions
|
SUBDIRS = extensions extensions/ipset
|
||||||
|
|
||||||
man_MANS := xtables-addons.8
|
man_MANS := xtables-addons.8
|
||||||
|
|
||||||
|
@@ -65,4 +65,4 @@ AC_SUBST([kinclude_CFLAGS])
|
|||||||
AC_SUBST([kbuilddir])
|
AC_SUBST([kbuilddir])
|
||||||
AC_SUBST([ksourcedir])
|
AC_SUBST([ksourcedir])
|
||||||
AC_SUBST([xtlibdir])
|
AC_SUBST([xtlibdir])
|
||||||
AC_OUTPUT([Makefile extensions/GNUmakefile])
|
AC_OUTPUT([Makefile extensions/GNUmakefile extensions/ipset/GNUmakefile])
|
||||||
|
1
extensions/.gitignore
vendored
1
extensions/.gitignore
vendored
@@ -8,7 +8,6 @@ modules.order
|
|||||||
|
|
||||||
/*.so
|
/*.so
|
||||||
/*.oo
|
/*.oo
|
||||||
/GNUmakefile
|
|
||||||
/matches.man
|
/matches.man
|
||||||
/targets.man
|
/targets.man
|
||||||
/.manpages.lst
|
/.manpages.lst
|
||||||
|
@@ -15,6 +15,7 @@ obj-${build_TEE} += xt_TEE.o
|
|||||||
obj-${build_condition} += xt_condition.o
|
obj-${build_condition} += xt_condition.o
|
||||||
obj-${build_geoip} += xt_geoip.o
|
obj-${build_geoip} += xt_geoip.o
|
||||||
obj-${build_ipp2p} += xt_ipp2p.o
|
obj-${build_ipp2p} += xt_ipp2p.o
|
||||||
|
obj-${build_ipset} += ipset/
|
||||||
obj-${build_portscan} += xt_portscan.o
|
obj-${build_portscan} += xt_portscan.o
|
||||||
obj-${build_quota2} += xt_quota2.o
|
obj-${build_quota2} += xt_quota2.o
|
||||||
|
|
||||||
|
3
extensions/ipset/.gitignore
vendored
Normal file
3
extensions/ipset/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
*.oo
|
||||||
|
*.so
|
||||||
|
/ipset
|
84
extensions/ipset/GNUmakefile.in
Normal file
84
extensions/ipset/GNUmakefile.in
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# -*- Makefile -*-
|
||||||
|
|
||||||
|
top_srcdir := @top_srcdir@
|
||||||
|
srcdir := @srcdir@
|
||||||
|
abstop_srcdir := $(shell readlink -e ${top_srcdir})
|
||||||
|
abssrcdir := $(shell readlink -e ${srcdir})
|
||||||
|
|
||||||
|
ifeq (${abstop_srcdir},)
|
||||||
|
$(error Path resolution of ${top_srcdir} failed)
|
||||||
|
endif
|
||||||
|
ifeq (${abssrcdir},)
|
||||||
|
$(error Path resolution of ${srcdir} failed)
|
||||||
|
endif
|
||||||
|
|
||||||
|
prefix := @prefix@
|
||||||
|
exec_prefix := @exec_prefix@
|
||||||
|
sbindir := @sbindir@
|
||||||
|
libdir := @libdir@
|
||||||
|
libexecdir := @libexecdir@
|
||||||
|
xtlibdir := @xtlibdir@
|
||||||
|
kbuilddir := @kbuilddir@
|
||||||
|
man8dir := @mandir@/man8
|
||||||
|
|
||||||
|
CC := @CC@
|
||||||
|
CCLD := ${CC}
|
||||||
|
CFLAGS := @CFLAGS@
|
||||||
|
LDFLAGS := @LDFLAGS@
|
||||||
|
regular_CFLAGS := @regular_CFLAGS@
|
||||||
|
kinclude_CFLAGS := @kinclude_CFLAGS@
|
||||||
|
xtables_CFLAGS := @xtables_CFLAGS@
|
||||||
|
|
||||||
|
AM_CFLAGS := ${regular_CFLAGS} -I${top_srcdir}/include ${xtables_CFLAGS} ${kinclude_CFLAGS} -DXTABLES_LIBDIR=\"${xtlibdir}\"
|
||||||
|
AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@
|
||||||
|
|
||||||
|
ifeq (${V},)
|
||||||
|
AM_LIBTOOL_SILENT = --silent
|
||||||
|
AM_VERBOSE_CC = @echo " CC " $@;
|
||||||
|
AM_VERBOSE_CCLD = @echo " CCLD " $@;
|
||||||
|
AM_VERBOSE_CXX = @echo " CXX " $@;
|
||||||
|
AM_VERBOSE_CXXLD = @echo " CXXLD " $@;
|
||||||
|
AM_VERBOSE_AR = @echo " AR " $@;
|
||||||
|
AM_VERBOSE_GEN = @echo " GEN " $@;
|
||||||
|
endif
|
||||||
|
|
||||||
|
#
|
||||||
|
# Building blocks
|
||||||
|
#
|
||||||
|
targets := $(addsuffix .so,$(addprefix libipset_,iphash ipmap ipporthash iptree iptreemap macipmap nethash portmap))
|
||||||
|
|
||||||
|
.SECONDARY:
|
||||||
|
|
||||||
|
.PHONY: all install clean distclean FORCE
|
||||||
|
|
||||||
|
all: ipset ${targets}
|
||||||
|
|
||||||
|
install: all
|
||||||
|
@mkdir -p "${DESTDIR}${sbindir}" "${DESTDIR}${xtlibdir}" "${DESTDIR}${man8dir}";
|
||||||
|
install -pm0755 ipset "${DESTDIR}${sbindir}/";
|
||||||
|
install -pm0755 ${targets} "${DESTDIR}${xtlibdir}/";
|
||||||
|
install -pm0644 ipset.8 "${DESTDIR}${man8dir}/";
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.oo *.so *.o ipset;
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f .*.d;
|
||||||
|
|
||||||
|
-include .*.d
|
||||||
|
|
||||||
|
|
||||||
|
ipset: ipset.o
|
||||||
|
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} ${LDFLAGS} -o $@ $< -ldl -rdynamic;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Shared libraries
|
||||||
|
#
|
||||||
|
lib%.so: lib%.oo
|
||||||
|
${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<;
|
||||||
|
|
||||||
|
libipset_%.oo: ${srcdir}/ipset_%.c
|
||||||
|
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -DPIC -fPIC ${CFLAGS} -o $@ -c $<;
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} ${CFLAGS} -o $@ -c $<;
|
6
extensions/ipset/Kbuild
Normal file
6
extensions/ipset/Kbuild
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
# -*- Makefile -*-
|
||||||
|
|
||||||
|
obj-m += ipt_set.o ipt_SET.o
|
||||||
|
obj-m += ip_set.o ip_set_ipmap.o ip_set_portmap.o ip_set_macipmap.o
|
||||||
|
obj-m += ip_set_iphash.o ip_set_nethash.o ip_set_ipporthash.o
|
||||||
|
obj-m += ip_set_iptree.o ip_set_iptreemap.o
|
1981
extensions/ipset/ip_set.c
Normal file
1981
extensions/ipset/ip_set.c
Normal file
File diff suppressed because it is too large
Load Diff
506
extensions/ipset/ip_set.h
Normal file
506
extensions/ipset/ip_set.h
Normal file
@@ -0,0 +1,506 @@
|
|||||||
|
#ifndef _IP_SET_H
|
||||||
|
#define _IP_SET_H
|
||||||
|
|
||||||
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
|
* Patrick Schaaf <bof@bof.de>
|
||||||
|
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||||
|
* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CONFIG_IP_NF_SET_MAX
|
||||||
|
/* from 2 to 65534 */
|
||||||
|
# define CONFIG_IP_NF_SET_MAX 256
|
||||||
|
#endif
|
||||||
|
#ifndef CONFIG_IP_NF_SET_HASHSIZE
|
||||||
|
# define CONFIG_IP_NF_SET_HASHSIZE 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define IP_SET_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A sockopt of such quality has hardly ever been seen before on the open
|
||||||
|
* market! This little beauty, hardly ever used: above 64, so it's
|
||||||
|
* traditionally used for firewalling, not touched (even once!) by the
|
||||||
|
* 2.0, 2.2 and 2.4 kernels!
|
||||||
|
*
|
||||||
|
* Comes with its own certificate of authenticity, valid anywhere in the
|
||||||
|
* Free world!
|
||||||
|
*
|
||||||
|
* Rusty, 19.4.2000
|
||||||
|
*/
|
||||||
|
#define SO_IP_SET 83
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Heavily modify by Joakim Axelsson 08.03.2002
|
||||||
|
* - Made it more modulebased
|
||||||
|
*
|
||||||
|
* Additional heavy modifications by Jozsef Kadlecsik 22.02.2004
|
||||||
|
* - bindings added
|
||||||
|
* - in order to "deal with" backward compatibility, renamed to ipset
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used so that the kernel module and ipset-binary can match their versions
|
||||||
|
*/
|
||||||
|
#define IP_SET_PROTOCOL_VERSION 2
|
||||||
|
|
||||||
|
#define IP_SET_MAXNAMELEN 32 /* set names and set typenames */
|
||||||
|
|
||||||
|
/* Lets work with our own typedef for representing an IP address.
|
||||||
|
* We hope to make the code more portable, possibly to IPv6...
|
||||||
|
*
|
||||||
|
* The representation works in HOST byte order, because most set types
|
||||||
|
* will perform arithmetic operations and compare operations.
|
||||||
|
*
|
||||||
|
* For now the type is an uint32_t.
|
||||||
|
*
|
||||||
|
* Make sure to ONLY use the functions when translating and parsing
|
||||||
|
* in order to keep the host byte order and make it more portable:
|
||||||
|
* parse_ip()
|
||||||
|
* parse_mask()
|
||||||
|
* parse_ipandmask()
|
||||||
|
* ip_tostring()
|
||||||
|
* (Joakim: where are they???)
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef uint32_t ip_set_ip_t;
|
||||||
|
|
||||||
|
/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t
|
||||||
|
* and IP_SET_INVALID_ID if you want to increase the max number of sets.
|
||||||
|
*/
|
||||||
|
typedef uint16_t ip_set_id_t;
|
||||||
|
|
||||||
|
#define IP_SET_INVALID_ID 65535
|
||||||
|
|
||||||
|
/* How deep we follow bindings */
|
||||||
|
#define IP_SET_MAX_BINDINGS 6
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Option flags for kernel operations (ipt_set_info)
|
||||||
|
*/
|
||||||
|
#define IPSET_SRC 0x01 /* Source match/add */
|
||||||
|
#define IPSET_DST 0x02 /* Destination match/add */
|
||||||
|
#define IPSET_MATCH_INV 0x04 /* Inverse matching */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set features
|
||||||
|
*/
|
||||||
|
#define IPSET_TYPE_IP 0x01 /* IP address type of set */
|
||||||
|
#define IPSET_TYPE_PORT 0x02 /* Port type of set */
|
||||||
|
#define IPSET_DATA_SINGLE 0x04 /* Single data storage */
|
||||||
|
#define IPSET_DATA_DOUBLE 0x08 /* Double data storage */
|
||||||
|
|
||||||
|
/* Reserved keywords */
|
||||||
|
#define IPSET_TOKEN_DEFAULT ":default:"
|
||||||
|
#define IPSET_TOKEN_ALL ":all:"
|
||||||
|
|
||||||
|
/* SO_IP_SET operation constants, and their request struct types.
|
||||||
|
*
|
||||||
|
* Operation ids:
|
||||||
|
* 0-99: commands with version checking
|
||||||
|
* 100-199: add/del/test/bind/unbind
|
||||||
|
* 200-299: list, save, restore
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Single shot operations:
|
||||||
|
* version, create, destroy, flush, rename and swap
|
||||||
|
*
|
||||||
|
* Sets are identified by name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define IP_SET_REQ_STD \
|
||||||
|
unsigned op; \
|
||||||
|
unsigned version; \
|
||||||
|
char name[IP_SET_MAXNAMELEN]
|
||||||
|
|
||||||
|
#define IP_SET_OP_CREATE 0x00000001 /* Create a new (empty) set */
|
||||||
|
struct ip_set_req_create {
|
||||||
|
IP_SET_REQ_STD;
|
||||||
|
char typename[IP_SET_MAXNAMELEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_SET_OP_DESTROY 0x00000002 /* Remove a (empty) set */
|
||||||
|
struct ip_set_req_std {
|
||||||
|
IP_SET_REQ_STD;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_SET_OP_FLUSH 0x00000003 /* Remove all IPs in a set */
|
||||||
|
/* Uses ip_set_req_std */
|
||||||
|
|
||||||
|
#define IP_SET_OP_RENAME 0x00000004 /* Rename a set */
|
||||||
|
/* Uses ip_set_req_create */
|
||||||
|
|
||||||
|
#define IP_SET_OP_SWAP 0x00000005 /* Swap two sets */
|
||||||
|
/* Uses ip_set_req_create */
|
||||||
|
|
||||||
|
union ip_set_name_index {
|
||||||
|
char name[IP_SET_MAXNAMELEN];
|
||||||
|
ip_set_id_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_SET_OP_GET_BYNAME 0x00000006 /* Get set index by name */
|
||||||
|
struct ip_set_req_get_set {
|
||||||
|
unsigned op;
|
||||||
|
unsigned version;
|
||||||
|
union ip_set_name_index set;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_SET_OP_GET_BYINDEX 0x00000007 /* Get set name by index */
|
||||||
|
/* Uses ip_set_req_get_set */
|
||||||
|
|
||||||
|
#define IP_SET_OP_VERSION 0x00000100 /* Ask kernel version */
|
||||||
|
struct ip_set_req_version {
|
||||||
|
unsigned op;
|
||||||
|
unsigned version;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Double shots operations:
|
||||||
|
* add, del, test, bind and unbind.
|
||||||
|
*
|
||||||
|
* First we query the kernel to get the index and type of the target set,
|
||||||
|
* then issue the command. Validity of IP is checked in kernel in order
|
||||||
|
* to minimalize sockopt operations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Get minimal set data for add/del/test/bind/unbind IP */
|
||||||
|
#define IP_SET_OP_ADT_GET 0x00000010 /* Get set and type */
|
||||||
|
struct ip_set_req_adt_get {
|
||||||
|
unsigned op;
|
||||||
|
unsigned version;
|
||||||
|
union ip_set_name_index set;
|
||||||
|
char typename[IP_SET_MAXNAMELEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_SET_REQ_BYINDEX \
|
||||||
|
unsigned op; \
|
||||||
|
ip_set_id_t index;
|
||||||
|
|
||||||
|
struct ip_set_req_adt {
|
||||||
|
IP_SET_REQ_BYINDEX;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_SET_OP_ADD_IP 0x00000101 /* Add an IP to a set */
|
||||||
|
/* Uses ip_set_req_adt, with type specific addage */
|
||||||
|
|
||||||
|
#define IP_SET_OP_DEL_IP 0x00000102 /* Remove an IP from a set */
|
||||||
|
/* Uses ip_set_req_adt, with type specific addage */
|
||||||
|
|
||||||
|
#define IP_SET_OP_TEST_IP 0x00000103 /* Test an IP in a set */
|
||||||
|
/* Uses ip_set_req_adt, with type specific addage */
|
||||||
|
|
||||||
|
#define IP_SET_OP_BIND_SET 0x00000104 /* Bind an IP to a set */
|
||||||
|
/* Uses ip_set_req_bind, with type specific addage */
|
||||||
|
struct ip_set_req_bind {
|
||||||
|
IP_SET_REQ_BYINDEX;
|
||||||
|
char binding[IP_SET_MAXNAMELEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IP_SET_OP_UNBIND_SET 0x00000105 /* Unbind an IP from a set */
|
||||||
|
/* Uses ip_set_req_bind, with type speficic addage
|
||||||
|
* index = 0 means unbinding for all sets */
|
||||||
|
|
||||||
|
#define IP_SET_OP_TEST_BIND_SET 0x00000106 /* Test binding an IP to a set */
|
||||||
|
/* Uses ip_set_req_bind, with type specific addage */
|
||||||
|
|
||||||
|
/* Multiple shots operations: list, save, restore.
|
||||||
|
*
|
||||||
|
* - check kernel version and query the max number of sets
|
||||||
|
* - get the basic information on all sets
|
||||||
|
* and size required for the next step
|
||||||
|
* - get actual set data: header, data, bindings
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Get max_sets and the index of a queried set
|
||||||
|
*/
|
||||||
|
#define IP_SET_OP_MAX_SETS 0x00000020
|
||||||
|
struct ip_set_req_max_sets {
|
||||||
|
unsigned op;
|
||||||
|
unsigned version;
|
||||||
|
ip_set_id_t max_sets; /* max_sets */
|
||||||
|
ip_set_id_t sets; /* real number of sets */
|
||||||
|
union ip_set_name_index set; /* index of set if name used */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Get the id and name of the sets plus size for next step */
|
||||||
|
#define IP_SET_OP_LIST_SIZE 0x00000201
|
||||||
|
#define IP_SET_OP_SAVE_SIZE 0x00000202
|
||||||
|
struct ip_set_req_setnames {
|
||||||
|
unsigned op;
|
||||||
|
ip_set_id_t index; /* set to list/save */
|
||||||
|
size_t size; /* size to get setdata/bindings */
|
||||||
|
/* followed by sets number of struct ip_set_name_list */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_name_list {
|
||||||
|
char name[IP_SET_MAXNAMELEN];
|
||||||
|
char typename[IP_SET_MAXNAMELEN];
|
||||||
|
ip_set_id_t index;
|
||||||
|
ip_set_id_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The actual list operation */
|
||||||
|
#define IP_SET_OP_LIST 0x00000203
|
||||||
|
struct ip_set_req_list {
|
||||||
|
IP_SET_REQ_BYINDEX;
|
||||||
|
/* sets number of struct ip_set_list in reply */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_list {
|
||||||
|
ip_set_id_t index;
|
||||||
|
ip_set_id_t binding;
|
||||||
|
u_int32_t ref;
|
||||||
|
size_t header_size; /* Set header data of header_size */
|
||||||
|
size_t members_size; /* Set members data of members_size */
|
||||||
|
size_t bindings_size; /* Set bindings data of bindings_size */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_hash_list {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
ip_set_id_t binding;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The save operation */
|
||||||
|
#define IP_SET_OP_SAVE 0x00000204
|
||||||
|
/* Uses ip_set_req_list, in the reply replaced by
|
||||||
|
* sets number of struct ip_set_save plus a marker
|
||||||
|
* ip_set_save followed by ip_set_hash_save structures.
|
||||||
|
*/
|
||||||
|
struct ip_set_save {
|
||||||
|
ip_set_id_t index;
|
||||||
|
ip_set_id_t binding;
|
||||||
|
size_t header_size; /* Set header data of header_size */
|
||||||
|
size_t members_size; /* Set members data of members_size */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* At restoring, ip == 0 means default binding for the given set: */
|
||||||
|
struct ip_set_hash_save {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
ip_set_id_t id;
|
||||||
|
ip_set_id_t binding;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The restore operation */
|
||||||
|
#define IP_SET_OP_RESTORE 0x00000205
|
||||||
|
/* Uses ip_set_req_setnames followed by ip_set_restore structures
|
||||||
|
* plus a marker ip_set_restore, followed by ip_set_hash_save
|
||||||
|
* structures.
|
||||||
|
*/
|
||||||
|
struct ip_set_restore {
|
||||||
|
char name[IP_SET_MAXNAMELEN];
|
||||||
|
char typename[IP_SET_MAXNAMELEN];
|
||||||
|
ip_set_id_t index;
|
||||||
|
size_t header_size; /* Create data of header_size */
|
||||||
|
size_t members_size; /* Set members data of members_size */
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
|
||||||
|
{
|
||||||
|
return 4 * ((((b - a + 8) / 8) + 3) / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
#define ip_set_printk(format, args...) \
|
||||||
|
do { \
|
||||||
|
printk("%s: %s: ", __FILE__, __FUNCTION__); \
|
||||||
|
printk(format "\n" , ## args); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#if defined(IP_SET_DEBUG)
|
||||||
|
#define DP(format, args...) \
|
||||||
|
do { \
|
||||||
|
printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
|
||||||
|
printk(format "\n" , ## args); \
|
||||||
|
} while (0)
|
||||||
|
#define IP_SET_ASSERT(x) \
|
||||||
|
do { \
|
||||||
|
if (!(x)) \
|
||||||
|
printk("IP_SET_ASSERT: %s:%i(%s)\n", \
|
||||||
|
__FILE__, __LINE__, __FUNCTION__); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define DP(format, args...)
|
||||||
|
#define IP_SET_ASSERT(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ip_set;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ip_set_type definition - one per set type, e.g. "ipmap".
|
||||||
|
*
|
||||||
|
* Each individual set has a pointer, set->type, going to one
|
||||||
|
* of these structures. Function pointers inside the structure implement
|
||||||
|
* the real behaviour of the sets.
|
||||||
|
*
|
||||||
|
* If not mentioned differently, the implementation behind the function
|
||||||
|
* pointers of a set_type, is expected to return 0 if ok, and a negative
|
||||||
|
* errno (e.g. -EINVAL) on error.
|
||||||
|
*/
|
||||||
|
struct ip_set_type {
|
||||||
|
struct list_head list; /* next in list of set types */
|
||||||
|
|
||||||
|
/* test for IP in set (kernel: iptables -m set src|dst)
|
||||||
|
* return 0 if not in set, 1 if in set.
|
||||||
|
*/
|
||||||
|
int (*testip_kernel) (struct ip_set *set,
|
||||||
|
const struct sk_buff * skb,
|
||||||
|
ip_set_ip_t *ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index);
|
||||||
|
|
||||||
|
/* test for IP in set (userspace: ipset -T set IP)
|
||||||
|
* return 0 if not in set, 1 if in set.
|
||||||
|
*/
|
||||||
|
int (*testip) (struct ip_set *set,
|
||||||
|
const void *data, size_t size,
|
||||||
|
ip_set_ip_t *ip);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Size of the data structure passed by when
|
||||||
|
* adding/deletin/testing an entry.
|
||||||
|
*/
|
||||||
|
size_t reqsize;
|
||||||
|
|
||||||
|
/* Add IP into set (userspace: ipset -A set IP)
|
||||||
|
* Return -EEXIST if the address is already in the set,
|
||||||
|
* and -ERANGE if the address lies outside the set bounds.
|
||||||
|
* If the address was not already in the set, 0 is returned.
|
||||||
|
*/
|
||||||
|
int (*addip) (struct ip_set *set,
|
||||||
|
const void *data, size_t size,
|
||||||
|
ip_set_ip_t *ip);
|
||||||
|
|
||||||
|
/* Add IP into set (kernel: iptables ... -j SET set src|dst)
|
||||||
|
* Return -EEXIST if the address is already in the set,
|
||||||
|
* and -ERANGE if the address lies outside the set bounds.
|
||||||
|
* If the address was not already in the set, 0 is returned.
|
||||||
|
*/
|
||||||
|
int (*addip_kernel) (struct ip_set *set,
|
||||||
|
const struct sk_buff * skb,
|
||||||
|
ip_set_ip_t *ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index);
|
||||||
|
|
||||||
|
/* remove IP from set (userspace: ipset -D set --entry x)
|
||||||
|
* Return -EEXIST if the address is NOT in the set,
|
||||||
|
* and -ERANGE if the address lies outside the set bounds.
|
||||||
|
* If the address really was in the set, 0 is returned.
|
||||||
|
*/
|
||||||
|
int (*delip) (struct ip_set *set,
|
||||||
|
const void *data, size_t size,
|
||||||
|
ip_set_ip_t *ip);
|
||||||
|
|
||||||
|
/* remove IP from set (kernel: iptables ... -j SET --entry x)
|
||||||
|
* Return -EEXIST if the address is NOT in the set,
|
||||||
|
* and -ERANGE if the address lies outside the set bounds.
|
||||||
|
* If the address really was in the set, 0 is returned.
|
||||||
|
*/
|
||||||
|
int (*delip_kernel) (struct ip_set *set,
|
||||||
|
const struct sk_buff * skb,
|
||||||
|
ip_set_ip_t *ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index);
|
||||||
|
|
||||||
|
/* new set creation - allocated type specific items
|
||||||
|
*/
|
||||||
|
int (*create) (struct ip_set *set,
|
||||||
|
const void *data, size_t size);
|
||||||
|
|
||||||
|
/* retry the operation after successfully tweaking the set
|
||||||
|
*/
|
||||||
|
int (*retry) (struct ip_set *set);
|
||||||
|
|
||||||
|
/* set destruction - free type specific items
|
||||||
|
* There is no return value.
|
||||||
|
* Can be called only when child sets are destroyed.
|
||||||
|
*/
|
||||||
|
void (*destroy) (struct ip_set *set);
|
||||||
|
|
||||||
|
/* set flushing - reset all bits in the set, or something similar.
|
||||||
|
* There is no return value.
|
||||||
|
*/
|
||||||
|
void (*flush) (struct ip_set *set);
|
||||||
|
|
||||||
|
/* Listing: size needed for header
|
||||||
|
*/
|
||||||
|
size_t header_size;
|
||||||
|
|
||||||
|
/* Listing: Get the header
|
||||||
|
*
|
||||||
|
* Fill in the information in "data".
|
||||||
|
* This function is always run after list_header_size() under a
|
||||||
|
* writelock on the set. Therefor is the length of "data" always
|
||||||
|
* correct.
|
||||||
|
*/
|
||||||
|
void (*list_header) (const struct ip_set *set,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
/* Listing: Get the size for the set members
|
||||||
|
*/
|
||||||
|
int (*list_members_size) (const struct ip_set *set);
|
||||||
|
|
||||||
|
/* Listing: Get the set members
|
||||||
|
*
|
||||||
|
* Fill in the information in "data".
|
||||||
|
* This function is always run after list_member_size() under a
|
||||||
|
* writelock on the set. Therefor is the length of "data" always
|
||||||
|
* correct.
|
||||||
|
*/
|
||||||
|
void (*list_members) (const struct ip_set *set,
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
char typename[IP_SET_MAXNAMELEN];
|
||||||
|
unsigned char features;
|
||||||
|
int protocol_version;
|
||||||
|
|
||||||
|
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
|
||||||
|
struct module *me;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int ip_set_register_set_type(struct ip_set_type *set_type);
|
||||||
|
extern void ip_set_unregister_set_type(struct ip_set_type *set_type);
|
||||||
|
|
||||||
|
/* A generic ipset */
|
||||||
|
struct ip_set {
|
||||||
|
char name[IP_SET_MAXNAMELEN]; /* the name of the set */
|
||||||
|
rwlock_t lock; /* lock for concurrency control */
|
||||||
|
ip_set_id_t id; /* set id for swapping */
|
||||||
|
ip_set_id_t binding; /* default binding for the set */
|
||||||
|
atomic_t ref; /* in kernel and in hash references */
|
||||||
|
struct ip_set_type *type; /* the set types */
|
||||||
|
void *data; /* pooltype specific data */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure to bind set elements to sets */
|
||||||
|
struct ip_set_hash {
|
||||||
|
struct list_head list; /* list of clashing entries in hash */
|
||||||
|
ip_set_ip_t ip; /* ip from set */
|
||||||
|
ip_set_id_t id; /* set id */
|
||||||
|
ip_set_id_t binding; /* set we bind the element to */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* register and unregister set references */
|
||||||
|
extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]);
|
||||||
|
extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id);
|
||||||
|
extern void ip_set_put(ip_set_id_t id);
|
||||||
|
|
||||||
|
/* API for iptables set match, and SET target */
|
||||||
|
extern void ip_set_addip_kernel(ip_set_id_t id,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
const u_int32_t *flags);
|
||||||
|
extern void ip_set_delip_kernel(ip_set_id_t id,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
const u_int32_t *flags);
|
||||||
|
extern int ip_set_testip_kernel(ip_set_id_t id,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
const u_int32_t *flags);
|
||||||
|
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
#endif /*_IP_SET_H*/
|
425
extensions/ipset/ip_set_iphash.c
Normal file
425
extensions/ipset/ip_set_iphash.c
Normal file
@@ -0,0 +1,425 @@
|
|||||||
|
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module implementing an ip hash set */
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/jhash.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
|
||||||
|
#include <net/ip.h>
|
||||||
|
|
||||||
|
#include "ip_set_malloc.h"
|
||||||
|
#include "ip_set_iphash.h"
|
||||||
|
|
||||||
|
static int limit = MAX_RANGE;
|
||||||
|
|
||||||
|
static inline __u32
|
||||||
|
jhash_ip(const struct ip_set_iphash *map, uint16_t i, ip_set_ip_t ip)
|
||||||
|
{
|
||||||
|
return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u32
|
||||||
|
hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *map = set->data;
|
||||||
|
__u32 id;
|
||||||
|
u_int16_t i;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
|
||||||
|
*hash_ip = ip & map->netmask;
|
||||||
|
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u, %u.%u.%u.%u",
|
||||||
|
set->name, HIPQUAD(ip), HIPQUAD(*hash_ip), HIPQUAD(map->netmask));
|
||||||
|
|
||||||
|
for (i = 0; i < map->probes; i++) {
|
||||||
|
id = jhash_ip(map, i, *hash_ip) % map->hashsize;
|
||||||
|
DP("hash key: %u", id);
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||||
|
if (*elem == *hash_ip)
|
||||||
|
return id;
|
||||||
|
/* No shortcut at testing - there can be deleted
|
||||||
|
* entries. */
|
||||||
|
}
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iphash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iphash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iphash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __testip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __testip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip(struct ip_set_iphash *map, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
__u32 probe;
|
||||||
|
u_int16_t i;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
|
||||||
|
if (!ip || map->elements >= limit)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = ip & map->netmask;
|
||||||
|
|
||||||
|
for (i = 0; i < map->probes; i++) {
|
||||||
|
probe = jhash_ip(map, i, *hash_ip) % map->hashsize;
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
|
||||||
|
if (*elem == *hash_ip)
|
||||||
|
return -EEXIST;
|
||||||
|
if (!*elem) {
|
||||||
|
*elem = *hash_ip;
|
||||||
|
map->elements++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Trigger rehashing */
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iphash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iphash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iphash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __addip(set->data, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __addip((struct ip_set_iphash *) set->data,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int retry(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *map = set->data;
|
||||||
|
ip_set_ip_t hash_ip, *elem;
|
||||||
|
void *members;
|
||||||
|
u_int32_t i, hashsize = map->hashsize;
|
||||||
|
int res;
|
||||||
|
struct ip_set_iphash *tmp;
|
||||||
|
|
||||||
|
if (map->resize == 0)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
again:
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
/* Calculate new hash size */
|
||||||
|
hashsize += (hashsize * map->resize)/100;
|
||||||
|
if (hashsize == map->hashsize)
|
||||||
|
hashsize++;
|
||||||
|
|
||||||
|
ip_set_printk("rehashing of set %s triggered: "
|
||||||
|
"hashsize grows from %u to %u",
|
||||||
|
set->name, map->hashsize, hashsize);
|
||||||
|
|
||||||
|
tmp = kmalloc(sizeof(struct ip_set_iphash)
|
||||||
|
+ map->probes * sizeof(uint32_t), GFP_ATOMIC);
|
||||||
|
if (!tmp) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_iphash)
|
||||||
|
+ map->probes * sizeof(uint32_t));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
|
||||||
|
if (!tmp->members) {
|
||||||
|
DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
|
||||||
|
kfree(tmp);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
tmp->hashsize = hashsize;
|
||||||
|
tmp->elements = 0;
|
||||||
|
tmp->probes = map->probes;
|
||||||
|
tmp->resize = map->resize;
|
||||||
|
tmp->netmask = map->netmask;
|
||||||
|
memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
|
||||||
|
|
||||||
|
write_lock_bh(&set->lock);
|
||||||
|
map = set->data; /* Play safe */
|
||||||
|
for (i = 0; i < map->hashsize && res == 0; i++) {
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
|
||||||
|
if (*elem)
|
||||||
|
res = __addip(tmp, *elem, &hash_ip);
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
/* Failure, try again */
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
harray_free(tmp->members);
|
||||||
|
kfree(tmp);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success at resizing! */
|
||||||
|
members = map->members;
|
||||||
|
|
||||||
|
map->hashsize = tmp->hashsize;
|
||||||
|
map->members = tmp->members;
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
|
||||||
|
harray_free(members);
|
||||||
|
kfree(tmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *map = set->data;
|
||||||
|
ip_set_ip_t id, *elem;
|
||||||
|
|
||||||
|
if (!ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
id = hash_id(set, ip, hash_ip);
|
||||||
|
if (id == UINT_MAX)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||||
|
*elem = 0;
|
||||||
|
map->elements--;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iphash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iphash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iphash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __delip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __delip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iphash_create *req = data;
|
||||||
|
struct ip_set_iphash *map;
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iphash_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iphash_create),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->hashsize < 1) {
|
||||||
|
ip_set_printk("hashsize too small");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->probes < 1) {
|
||||||
|
ip_set_printk("probes too small");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kmalloc(sizeof(struct ip_set_iphash)
|
||||||
|
+ req->probes * sizeof(uint32_t), GFP_KERNEL);
|
||||||
|
if (!map) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_iphash)
|
||||||
|
+ req->probes * sizeof(uint32_t));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
for (i = 0; i < req->probes; i++)
|
||||||
|
get_random_bytes(((uint32_t *) map->initval)+i, 4);
|
||||||
|
map->elements = 0;
|
||||||
|
map->hashsize = req->hashsize;
|
||||||
|
map->probes = req->probes;
|
||||||
|
map->resize = req->resize;
|
||||||
|
map->netmask = req->netmask;
|
||||||
|
map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
|
||||||
|
if (!map->members) {
|
||||||
|
DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
|
||||||
|
kfree(map);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
set->data = map;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *map = set->data;
|
||||||
|
|
||||||
|
harray_free(map->members);
|
||||||
|
kfree(map);
|
||||||
|
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *map = set->data;
|
||||||
|
harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
|
||||||
|
map->elements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *map = set->data;
|
||||||
|
struct ip_set_req_iphash_create *header = data;
|
||||||
|
|
||||||
|
header->hashsize = map->hashsize;
|
||||||
|
header->probes = map->probes;
|
||||||
|
header->resize = map->resize;
|
||||||
|
header->netmask = map->netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
const struct ip_set_iphash *map = set->data;
|
||||||
|
|
||||||
|
return (map->hashsize * sizeof(ip_set_ip_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_iphash *map = set->data;
|
||||||
|
ip_set_ip_t i, *elem;
|
||||||
|
|
||||||
|
for (i = 0; i < map->hashsize; i++) {
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
|
||||||
|
((ip_set_ip_t *)data)[i] = *elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_iphash = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = &create,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.flush = &flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_iphash),
|
||||||
|
.addip = &addip,
|
||||||
|
.addip_kernel = &addip_kernel,
|
||||||
|
.retry = &retry,
|
||||||
|
.delip = &delip,
|
||||||
|
.delip_kernel = &delip_kernel,
|
||||||
|
.testip = &testip,
|
||||||
|
.testip_kernel = &testip_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_iphash_create),
|
||||||
|
.list_header = &list_header,
|
||||||
|
.list_members_size = &list_members_size,
|
||||||
|
.list_members = &list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("iphash type of IP sets");
|
||||||
|
module_param(limit, int, 0600);
|
||||||
|
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||||
|
|
||||||
|
static int __init ip_set_iphash_init(void)
|
||||||
|
{
|
||||||
|
init_max_page_size();
|
||||||
|
return ip_set_register_set_type(&ip_set_iphash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_iphash_fini(void)
|
||||||
|
{
|
||||||
|
/* FIXME: possible race with ip_set_create() */
|
||||||
|
ip_set_unregister_set_type(&ip_set_iphash);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_iphash_init);
|
||||||
|
module_exit(ip_set_iphash_fini);
|
30
extensions/ipset/ip_set_iphash.h
Normal file
30
extensions/ipset/ip_set_iphash.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef __IP_SET_IPHASH_H
|
||||||
|
#define __IP_SET_IPHASH_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "iphash"
|
||||||
|
#define MAX_RANGE 0x0000FFFF
|
||||||
|
|
||||||
|
struct ip_set_iphash {
|
||||||
|
ip_set_ip_t *members; /* the iphash proper */
|
||||||
|
uint32_t elements; /* number of elements */
|
||||||
|
uint32_t hashsize; /* hash size */
|
||||||
|
uint16_t probes; /* max number of probes */
|
||||||
|
uint16_t resize; /* resize factor in percent */
|
||||||
|
ip_set_ip_t netmask; /* netmask */
|
||||||
|
void *initval[0]; /* initvals for jhash_1word */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_iphash_create {
|
||||||
|
uint32_t hashsize;
|
||||||
|
uint16_t probes;
|
||||||
|
uint16_t resize;
|
||||||
|
ip_set_ip_t netmask;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_iphash {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __IP_SET_IPHASH_H */
|
331
extensions/ipset/ip_set_ipmap.c
Normal file
331
extensions/ipset/ip_set_ipmap.c
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
|
* Patrick Schaaf <bof@bof.de>
|
||||||
|
* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module implementing an IP set type: the single bitmap type */
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#include "ip_set_ipmap.h"
|
||||||
|
|
||||||
|
static inline ip_set_ip_t
|
||||||
|
ip_to_id(const struct ip_set_ipmap *map, ip_set_ip_t ip)
|
||||||
|
{
|
||||||
|
return (ip - map->first_ip)/map->hosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *map = set->data;
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = ip & map->netmask;
|
||||||
|
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
|
||||||
|
set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||||
|
return !!test_bit(ip_to_id(map, *hash_ip), map->members);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_ipmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __testip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
int res = __testip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
return (res < 0 ? 0 : res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *map = set->data;
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = ip & map->netmask;
|
||||||
|
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||||
|
if (test_and_set_bit(ip_to_id(map, *hash_ip), map->members))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_ipmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
DP("%u.%u.%u.%u", HIPQUAD(req->ip));
|
||||||
|
return __addip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __addip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *map = set->data;
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = ip & map->netmask;
|
||||||
|
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||||
|
if (!test_and_clear_bit(ip_to_id(map, *hash_ip), map->members))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_ipmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __delip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __delip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
int newbytes;
|
||||||
|
const struct ip_set_req_ipmap_create *req = data;
|
||||||
|
struct ip_set_ipmap *map;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipmap_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipmap_create),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DP("from %u.%u.%u.%u to %u.%u.%u.%u",
|
||||||
|
HIPQUAD(req->from), HIPQUAD(req->to));
|
||||||
|
|
||||||
|
if (req->from > req->to) {
|
||||||
|
DP("bad ip range");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kmalloc(sizeof(struct ip_set_ipmap), GFP_KERNEL);
|
||||||
|
if (!map) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_ipmap));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
map->first_ip = req->from;
|
||||||
|
map->last_ip = req->to;
|
||||||
|
map->netmask = req->netmask;
|
||||||
|
|
||||||
|
if (req->netmask == 0xFFFFFFFF) {
|
||||||
|
map->hosts = 1;
|
||||||
|
map->sizeid = map->last_ip - map->first_ip + 1;
|
||||||
|
} else {
|
||||||
|
unsigned int mask_bits, netmask_bits;
|
||||||
|
ip_set_ip_t mask;
|
||||||
|
|
||||||
|
map->first_ip &= map->netmask; /* Should we better bark? */
|
||||||
|
|
||||||
|
mask = range_to_mask(map->first_ip, map->last_ip, &mask_bits);
|
||||||
|
netmask_bits = mask_to_bits(map->netmask);
|
||||||
|
|
||||||
|
if ((!mask && (map->first_ip || map->last_ip != 0xFFFFFFFF))
|
||||||
|
|| netmask_bits <= mask_bits)
|
||||||
|
return -ENOEXEC;
|
||||||
|
|
||||||
|
DP("mask_bits %u, netmask_bits %u",
|
||||||
|
mask_bits, netmask_bits);
|
||||||
|
map->hosts = 2 << (32 - netmask_bits - 1);
|
||||||
|
map->sizeid = 2 << (netmask_bits - mask_bits - 1);
|
||||||
|
}
|
||||||
|
if (map->sizeid > MAX_RANGE + 1) {
|
||||||
|
ip_set_printk("range too big (max %d addresses)",
|
||||||
|
MAX_RANGE+1);
|
||||||
|
kfree(map);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
DP("hosts %u, sizeid %u", map->hosts, map->sizeid);
|
||||||
|
newbytes = bitmap_bytes(0, map->sizeid - 1);
|
||||||
|
map->members = kmalloc(newbytes, GFP_KERNEL);
|
||||||
|
if (!map->members) {
|
||||||
|
DP("out of memory for %d bytes", newbytes);
|
||||||
|
kfree(map);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memset(map->members, 0, newbytes);
|
||||||
|
|
||||||
|
set->data = map;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *map = set->data;
|
||||||
|
|
||||||
|
kfree(map->members);
|
||||||
|
kfree(map);
|
||||||
|
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *map = set->data;
|
||||||
|
memset(map->members, 0, bitmap_bytes(0, map->sizeid - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_ipmap *map = set->data;
|
||||||
|
struct ip_set_req_ipmap_create *header = data;
|
||||||
|
|
||||||
|
header->from = map->first_ip;
|
||||||
|
header->to = map->last_ip;
|
||||||
|
header->netmask = map->netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
const struct ip_set_ipmap *map = set->data;
|
||||||
|
|
||||||
|
return bitmap_bytes(0, map->sizeid - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_ipmap *map = set->data;
|
||||||
|
int bytes = bitmap_bytes(0, map->sizeid - 1);
|
||||||
|
|
||||||
|
memcpy(data, map->members, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_ipmap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = &create,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.flush = &flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_ipmap),
|
||||||
|
.addip = &addip,
|
||||||
|
.addip_kernel = &addip_kernel,
|
||||||
|
.delip = &delip,
|
||||||
|
.delip_kernel = &delip_kernel,
|
||||||
|
.testip = &testip,
|
||||||
|
.testip_kernel = &testip_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_ipmap_create),
|
||||||
|
.list_header = &list_header,
|
||||||
|
.list_members_size = &list_members_size,
|
||||||
|
.list_members = &list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("ipmap type of IP sets");
|
||||||
|
|
||||||
|
static int __init ip_set_ipmap_init(void)
|
||||||
|
{
|
||||||
|
return ip_set_register_set_type(&ip_set_ipmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_ipmap_fini(void)
|
||||||
|
{
|
||||||
|
/* FIXME: possible race with ip_set_create() */
|
||||||
|
ip_set_unregister_set_type(&ip_set_ipmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_ipmap_init);
|
||||||
|
module_exit(ip_set_ipmap_fini);
|
56
extensions/ipset/ip_set_ipmap.h
Normal file
56
extensions/ipset/ip_set_ipmap.h
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#ifndef __IP_SET_IPMAP_H
|
||||||
|
#define __IP_SET_IPMAP_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "ipmap"
|
||||||
|
#define MAX_RANGE 0x0000FFFF
|
||||||
|
|
||||||
|
struct ip_set_ipmap {
|
||||||
|
void *members; /* the ipmap proper */
|
||||||
|
ip_set_ip_t first_ip; /* host byte order, included in range */
|
||||||
|
ip_set_ip_t last_ip; /* host byte order, included in range */
|
||||||
|
ip_set_ip_t netmask; /* subnet netmask */
|
||||||
|
ip_set_ip_t sizeid; /* size of set in IPs */
|
||||||
|
ip_set_ip_t hosts; /* number of hosts in a subnet */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_ipmap_create {
|
||||||
|
ip_set_ip_t from;
|
||||||
|
ip_set_ip_t to;
|
||||||
|
ip_set_ip_t netmask;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_ipmap {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
mask_to_bits(ip_set_ip_t mask)
|
||||||
|
{
|
||||||
|
unsigned int bits = 32;
|
||||||
|
ip_set_ip_t maskaddr;
|
||||||
|
|
||||||
|
if (mask == 0xFFFFFFFF)
|
||||||
|
return bits;
|
||||||
|
|
||||||
|
maskaddr = 0xFFFFFFFE;
|
||||||
|
while (--bits >= 0 && maskaddr != mask)
|
||||||
|
maskaddr <<= 1;
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ip_set_ip_t
|
||||||
|
range_to_mask(ip_set_ip_t from, ip_set_ip_t to, unsigned int *bits)
|
||||||
|
{
|
||||||
|
ip_set_ip_t mask = 0xFFFFFFFE;
|
||||||
|
|
||||||
|
*bits = 32;
|
||||||
|
while (--(*bits) >= 0 && mask && (to & mask) != from)
|
||||||
|
mask <<= 1;
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __IP_SET_IPMAP_H */
|
575
extensions/ipset/ip_set_ipporthash.c
Normal file
575
extensions/ipset/ip_set_ipporthash.c
Normal file
@@ -0,0 +1,575 @@
|
|||||||
|
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module implementing an ip+port hash set */
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/tcp.h>
|
||||||
|
#include <linux/udp.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/jhash.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
|
||||||
|
#include <net/ip.h>
|
||||||
|
|
||||||
|
#include "ip_set_malloc.h"
|
||||||
|
#include "ip_set_ipporthash.h"
|
||||||
|
|
||||||
|
static int limit = MAX_RANGE;
|
||||||
|
|
||||||
|
/* We must handle non-linear skbs */
|
||||||
|
static inline ip_set_ip_t
|
||||||
|
get_port(const struct sk_buff *skb, u_int32_t flags)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
struct iphdr *iph = ip_hdr(skb);
|
||||||
|
#else
|
||||||
|
struct iphdr *iph = skb->nh.iph;
|
||||||
|
#endif
|
||||||
|
u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
|
||||||
|
|
||||||
|
switch (iph->protocol) {
|
||||||
|
case IPPROTO_TCP: {
|
||||||
|
struct tcphdr tcph;
|
||||||
|
|
||||||
|
/* See comments at tcp_match in ip_tables.c */
|
||||||
|
if (offset)
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
|
||||||
|
#else
|
||||||
|
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
|
||||||
|
#endif
|
||||||
|
/* No choice either */
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
return ntohs(flags & IPSET_SRC ?
|
||||||
|
tcph.source : tcph.dest);
|
||||||
|
}
|
||||||
|
case IPPROTO_UDP: {
|
||||||
|
struct udphdr udph;
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
|
||||||
|
#else
|
||||||
|
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
|
||||||
|
#endif
|
||||||
|
/* No choice either */
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
return ntohs(flags & IPSET_SRC ?
|
||||||
|
udph.source : udph.dest);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return INVALID_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u32
|
||||||
|
jhash_ip(const struct ip_set_ipporthash *map, uint16_t i, ip_set_ip_t ip)
|
||||||
|
{
|
||||||
|
return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HASH_IP(map, ip, port) (port + ((ip - ((map)->first_ip)) << 16))
|
||||||
|
|
||||||
|
static inline __u32
|
||||||
|
hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *map = set->data;
|
||||||
|
__u32 id;
|
||||||
|
u_int16_t i;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
|
||||||
|
*hash_ip = HASH_IP(map, ip, port);
|
||||||
|
DP("set: %s, ipport:%u.%u.%u.%u:%u, %u.%u.%u.%u",
|
||||||
|
set->name, HIPQUAD(ip), port, HIPQUAD(*hash_ip));
|
||||||
|
|
||||||
|
for (i = 0; i < map->probes; i++) {
|
||||||
|
id = jhash_ip(map, i, *hash_ip) % map->hashsize;
|
||||||
|
DP("hash key: %u", id);
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||||
|
if (*elem == *hash_ip)
|
||||||
|
return id;
|
||||||
|
/* No shortcut at testing - there can be deleted
|
||||||
|
* entries. */
|
||||||
|
}
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *map = set->data;
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
return (hash_id(set, ip, port, hash_ip) != UINT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_ipporthash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipporthash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipporthash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __testip(set, req->ip, req->port, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
ip_set_ip_t port;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (flags[index+1] == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
port = get_port(skb, flags[index+1]);
|
||||||
|
|
||||||
|
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
|
||||||
|
flags[index] & IPSET_SRC ? "SRC" : "DST",
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
NIPQUAD(ip_hdr(skb)->saddr),
|
||||||
|
NIPQUAD(ip_hdr(skb)->daddr));
|
||||||
|
#else
|
||||||
|
NIPQUAD(skb->nh.iph->saddr),
|
||||||
|
NIPQUAD(skb->nh.iph->daddr));
|
||||||
|
#endif
|
||||||
|
DP("flag %s port %u",
|
||||||
|
flags[index+1] & IPSET_SRC ? "SRC" : "DST",
|
||||||
|
port);
|
||||||
|
if (port == INVALID_PORT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
res = __testip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
port,
|
||||||
|
hash_ip);
|
||||||
|
return (res < 0 ? 0 : res);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__add_haship(struct ip_set_ipporthash *map, ip_set_ip_t hash_ip)
|
||||||
|
{
|
||||||
|
__u32 probe;
|
||||||
|
u_int16_t i;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
|
||||||
|
for (i = 0; i < map->probes; i++) {
|
||||||
|
probe = jhash_ip(map, i, hash_ip) % map->hashsize;
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
|
||||||
|
if (*elem == hash_ip)
|
||||||
|
return -EEXIST;
|
||||||
|
if (!*elem) {
|
||||||
|
*elem = hash_ip;
|
||||||
|
map->elements++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Trigger rehashing */
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip(struct ip_set_ipporthash *map, ip_set_ip_t ip, ip_set_ip_t port,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
if (map->elements > limit)
|
||||||
|
return -ERANGE;
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = HASH_IP(map, ip, port);
|
||||||
|
|
||||||
|
return __add_haship(map, *hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_ipporthash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipporthash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipporthash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __addip(set->data, req->ip, req->port, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
ip_set_ip_t port;
|
||||||
|
|
||||||
|
if (flags[index+1] == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
port = get_port(skb, flags[index+1]);
|
||||||
|
|
||||||
|
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
|
||||||
|
flags[index] & IPSET_SRC ? "SRC" : "DST",
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
NIPQUAD(ip_hdr(skb)->saddr),
|
||||||
|
NIPQUAD(ip_hdr(skb)->daddr));
|
||||||
|
#else
|
||||||
|
NIPQUAD(skb->nh.iph->saddr),
|
||||||
|
NIPQUAD(skb->nh.iph->daddr));
|
||||||
|
#endif
|
||||||
|
DP("flag %s port %u",
|
||||||
|
flags[index+1] & IPSET_SRC ? "SRC" : "DST",
|
||||||
|
port);
|
||||||
|
if (port == INVALID_PORT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return __addip(set->data,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
port,
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int retry(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *map = set->data;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
void *members;
|
||||||
|
u_int32_t i, hashsize = map->hashsize;
|
||||||
|
int res;
|
||||||
|
struct ip_set_ipporthash *tmp;
|
||||||
|
|
||||||
|
if (map->resize == 0)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
again:
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
/* Calculate new hash size */
|
||||||
|
hashsize += (hashsize * map->resize)/100;
|
||||||
|
if (hashsize == map->hashsize)
|
||||||
|
hashsize++;
|
||||||
|
|
||||||
|
ip_set_printk("rehashing of set %s triggered: "
|
||||||
|
"hashsize grows from %u to %u",
|
||||||
|
set->name, map->hashsize, hashsize);
|
||||||
|
|
||||||
|
tmp = kmalloc(sizeof(struct ip_set_ipporthash)
|
||||||
|
+ map->probes * sizeof(uint32_t), GFP_ATOMIC);
|
||||||
|
if (!tmp) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_ipporthash)
|
||||||
|
+ map->probes * sizeof(uint32_t));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
|
||||||
|
if (!tmp->members) {
|
||||||
|
DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
|
||||||
|
kfree(tmp);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
tmp->hashsize = hashsize;
|
||||||
|
tmp->elements = 0;
|
||||||
|
tmp->probes = map->probes;
|
||||||
|
tmp->resize = map->resize;
|
||||||
|
tmp->first_ip = map->first_ip;
|
||||||
|
tmp->last_ip = map->last_ip;
|
||||||
|
memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
|
||||||
|
|
||||||
|
write_lock_bh(&set->lock);
|
||||||
|
map = set->data; /* Play safe */
|
||||||
|
for (i = 0; i < map->hashsize && res == 0; i++) {
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
|
||||||
|
if (*elem)
|
||||||
|
res = __add_haship(tmp, *elem);
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
/* Failure, try again */
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
harray_free(tmp->members);
|
||||||
|
kfree(tmp);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success at resizing! */
|
||||||
|
members = map->members;
|
||||||
|
|
||||||
|
map->hashsize = tmp->hashsize;
|
||||||
|
map->members = tmp->members;
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
|
||||||
|
harray_free(members);
|
||||||
|
kfree(tmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t port,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *map = set->data;
|
||||||
|
ip_set_ip_t id;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
id = hash_id(set, ip, port, hash_ip);
|
||||||
|
|
||||||
|
if (id == UINT_MAX)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||||
|
*elem = 0;
|
||||||
|
map->elements--;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_ipporthash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipporthash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipporthash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __delip(set, req->ip, req->port, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
ip_set_ip_t port;
|
||||||
|
|
||||||
|
if (flags[index+1] == 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
port = get_port(skb, flags[index+1]);
|
||||||
|
|
||||||
|
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
|
||||||
|
flags[index] & IPSET_SRC ? "SRC" : "DST",
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
NIPQUAD(ip_hdr(skb)->saddr),
|
||||||
|
NIPQUAD(ip_hdr(skb)->daddr));
|
||||||
|
#else
|
||||||
|
NIPQUAD(skb->nh.iph->saddr),
|
||||||
|
NIPQUAD(skb->nh.iph->daddr));
|
||||||
|
#endif
|
||||||
|
DP("flag %s port %u",
|
||||||
|
flags[index+1] & IPSET_SRC ? "SRC" : "DST",
|
||||||
|
port);
|
||||||
|
if (port == INVALID_PORT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return __delip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
port,
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_ipporthash_create *req = data;
|
||||||
|
struct ip_set_ipporthash *map;
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_ipporthash_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_ipporthash_create),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->hashsize < 1) {
|
||||||
|
ip_set_printk("hashsize too small");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->probes < 1) {
|
||||||
|
ip_set_printk("probes too small");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kmalloc(sizeof(struct ip_set_ipporthash)
|
||||||
|
+ req->probes * sizeof(uint32_t), GFP_KERNEL);
|
||||||
|
if (!map) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_ipporthash)
|
||||||
|
+ req->probes * sizeof(uint32_t));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
for (i = 0; i < req->probes; i++)
|
||||||
|
get_random_bytes(((uint32_t *) map->initval)+i, 4);
|
||||||
|
map->elements = 0;
|
||||||
|
map->hashsize = req->hashsize;
|
||||||
|
map->probes = req->probes;
|
||||||
|
map->resize = req->resize;
|
||||||
|
map->first_ip = req->from;
|
||||||
|
map->last_ip = req->to;
|
||||||
|
map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
|
||||||
|
if (!map->members) {
|
||||||
|
DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
|
||||||
|
kfree(map);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
set->data = map;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *map = set->data;
|
||||||
|
|
||||||
|
harray_free(map->members);
|
||||||
|
kfree(map);
|
||||||
|
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *map = set->data;
|
||||||
|
harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
|
||||||
|
map->elements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_ipporthash *map = set->data;
|
||||||
|
struct ip_set_req_ipporthash_create *header = data;
|
||||||
|
|
||||||
|
header->hashsize = map->hashsize;
|
||||||
|
header->probes = map->probes;
|
||||||
|
header->resize = map->resize;
|
||||||
|
header->from = map->first_ip;
|
||||||
|
header->to = map->last_ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
const struct ip_set_ipporthash *map = set->data;
|
||||||
|
|
||||||
|
return (map->hashsize * sizeof(ip_set_ip_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_ipporthash *map = set->data;
|
||||||
|
ip_set_ip_t i, *elem;
|
||||||
|
|
||||||
|
for (i = 0; i < map->hashsize; i++) {
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
|
||||||
|
((ip_set_ip_t *)data)[i] = *elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_ipporthash = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_IP | IPSET_TYPE_PORT | IPSET_DATA_DOUBLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = &create,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.flush = &flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_ipporthash),
|
||||||
|
.addip = &addip,
|
||||||
|
.addip_kernel = &addip_kernel,
|
||||||
|
.retry = &retry,
|
||||||
|
.delip = &delip,
|
||||||
|
.delip_kernel = &delip_kernel,
|
||||||
|
.testip = &testip,
|
||||||
|
.testip_kernel = &testip_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_ipporthash_create),
|
||||||
|
.list_header = &list_header,
|
||||||
|
.list_members_size = &list_members_size,
|
||||||
|
.list_members = &list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("ipporthash type of IP sets");
|
||||||
|
module_param(limit, int, 0600);
|
||||||
|
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||||
|
|
||||||
|
static int __init ip_set_ipporthash_init(void)
|
||||||
|
{
|
||||||
|
init_max_page_size();
|
||||||
|
return ip_set_register_set_type(&ip_set_ipporthash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_ipporthash_fini(void)
|
||||||
|
{
|
||||||
|
/* FIXME: possible race with ip_set_create() */
|
||||||
|
ip_set_unregister_set_type(&ip_set_ipporthash);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_ipporthash_init);
|
||||||
|
module_exit(ip_set_ipporthash_fini);
|
34
extensions/ipset/ip_set_ipporthash.h
Normal file
34
extensions/ipset/ip_set_ipporthash.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef __IP_SET_IPPORTHASH_H
|
||||||
|
#define __IP_SET_IPPORTHASH_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "ipporthash"
|
||||||
|
#define MAX_RANGE 0x0000FFFF
|
||||||
|
#define INVALID_PORT (MAX_RANGE + 1)
|
||||||
|
|
||||||
|
struct ip_set_ipporthash {
|
||||||
|
ip_set_ip_t *members; /* the ipporthash proper */
|
||||||
|
uint32_t elements; /* number of elements */
|
||||||
|
uint32_t hashsize; /* hash size */
|
||||||
|
uint16_t probes; /* max number of probes */
|
||||||
|
uint16_t resize; /* resize factor in percent */
|
||||||
|
ip_set_ip_t first_ip; /* host byte order, included in range */
|
||||||
|
ip_set_ip_t last_ip; /* host byte order, included in range */
|
||||||
|
void *initval[0]; /* initvals for jhash_1word */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_ipporthash_create {
|
||||||
|
uint32_t hashsize;
|
||||||
|
uint16_t probes;
|
||||||
|
uint16_t resize;
|
||||||
|
ip_set_ip_t from;
|
||||||
|
ip_set_ip_t to;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_ipporthash {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
ip_set_ip_t port;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __IP_SET_IPPORTHASH_H */
|
607
extensions/ipset/ip_set_iptree.c
Normal file
607
extensions/ipset/ip_set_iptree.c
Normal file
@@ -0,0 +1,607 @@
|
|||||||
|
/* Copyright (C) 2005 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module implementing an IP set type: the iptree type */
|
||||||
|
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
/* Backward compatibility */
|
||||||
|
#ifndef __nocast
|
||||||
|
#define __nocast
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ip_set_iptree.h"
|
||||||
|
|
||||||
|
static int limit = MAX_RANGE;
|
||||||
|
|
||||||
|
/* Garbage collection interval in seconds: */
|
||||||
|
#define IPTREE_GC_TIME 5*60
|
||||||
|
/* Sleep so many milliseconds before trying again
|
||||||
|
* to delete the gc timer at destroying/flushing a set */
|
||||||
|
#define IPTREE_DESTROY_SLEEP 100
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
|
||||||
|
static struct kmem_cache *branch_cachep;
|
||||||
|
static struct kmem_cache *leaf_cachep;
|
||||||
|
#else
|
||||||
|
static kmem_cache_t *branch_cachep;
|
||||||
|
static kmem_cache_t *leaf_cachep;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__LITTLE_ENDIAN)
|
||||||
|
#define ABCD(a,b,c,d,addrp) do { \
|
||||||
|
a = ((unsigned char *)addrp)[3]; \
|
||||||
|
b = ((unsigned char *)addrp)[2]; \
|
||||||
|
c = ((unsigned char *)addrp)[1]; \
|
||||||
|
d = ((unsigned char *)addrp)[0]; \
|
||||||
|
} while (0)
|
||||||
|
#elif defined(__BIG_ENDIAN)
|
||||||
|
#define ABCD(a,b,c,d,addrp) do { \
|
||||||
|
a = ((unsigned char *)addrp)[0]; \
|
||||||
|
b = ((unsigned char *)addrp)[1]; \
|
||||||
|
c = ((unsigned char *)addrp)[2]; \
|
||||||
|
d = ((unsigned char *)addrp)[3]; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#error "Please fix asm/byteorder.h"
|
||||||
|
#endif /* __LITTLE_ENDIAN */
|
||||||
|
|
||||||
|
#define TESTIP_WALK(map, elem, branch) do { \
|
||||||
|
if ((map)->tree[elem]) { \
|
||||||
|
branch = (map)->tree[elem]; \
|
||||||
|
} else \
|
||||||
|
return 0; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
struct ip_set_iptreeb *btree;
|
||||||
|
struct ip_set_iptreec *ctree;
|
||||||
|
struct ip_set_iptreed *dtree;
|
||||||
|
unsigned char a,b,c,d;
|
||||||
|
|
||||||
|
if (!ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
ABCD(a, b, c, d, hash_ip);
|
||||||
|
DP("%u %u %u %u timeout %u", a, b, c, d, map->timeout);
|
||||||
|
TESTIP_WALK(map, a, btree);
|
||||||
|
TESTIP_WALK(btree, b, ctree);
|
||||||
|
TESTIP_WALK(ctree, c, dtree);
|
||||||
|
DP("%lu %lu", dtree->expires[d], jiffies);
|
||||||
|
return dtree->expires[d]
|
||||||
|
&& (!map->timeout
|
||||||
|
|| time_after(dtree->expires[d], jiffies));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptree *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptree)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iptree),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __testip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
DP("flag: %s src: %u.%u.%u.%u dst: %u.%u.%u.%u",
|
||||||
|
flags[index] & IPSET_SRC ? "SRC" : "DST",
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
NIPQUAD(ip_hdr(skb)->saddr),
|
||||||
|
NIPQUAD(ip_hdr(skb)->daddr));
|
||||||
|
#else
|
||||||
|
NIPQUAD(skb->nh.iph->saddr),
|
||||||
|
NIPQUAD(skb->nh.iph->daddr));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
res = __testip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
return (res < 0 ? 0 : res);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADDIP_WALK(map, elem, branch, type, cachep) do { \
|
||||||
|
if ((map)->tree[elem]) { \
|
||||||
|
DP("found %u", elem); \
|
||||||
|
branch = (map)->tree[elem]; \
|
||||||
|
} else { \
|
||||||
|
branch = (type *) \
|
||||||
|
kmem_cache_alloc(cachep, GFP_ATOMIC); \
|
||||||
|
if (branch == NULL) \
|
||||||
|
return -ENOMEM; \
|
||||||
|
memset(branch, 0, sizeof(*branch)); \
|
||||||
|
(map)->tree[elem] = branch; \
|
||||||
|
DP("alloc %u", elem); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip(struct ip_set *set, ip_set_ip_t ip, unsigned int timeout,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
struct ip_set_iptreeb *btree;
|
||||||
|
struct ip_set_iptreec *ctree;
|
||||||
|
struct ip_set_iptreed *dtree;
|
||||||
|
unsigned char a,b,c,d;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (!ip || map->elements >= limit)
|
||||||
|
/* We could call the garbage collector
|
||||||
|
* but it's probably overkill */
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
ABCD(a, b, c, d, hash_ip);
|
||||||
|
DP("%u %u %u %u timeout %u", a, b, c, d, timeout);
|
||||||
|
ADDIP_WALK(map, a, btree, struct ip_set_iptreeb, branch_cachep);
|
||||||
|
ADDIP_WALK(btree, b, ctree, struct ip_set_iptreec, branch_cachep);
|
||||||
|
ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreed, leaf_cachep);
|
||||||
|
if (dtree->expires[d]
|
||||||
|
&& (!map->timeout || time_after(dtree->expires[d], jiffies)))
|
||||||
|
ret = -EEXIST;
|
||||||
|
dtree->expires[d] = map->timeout ? (timeout * HZ + jiffies) : 1;
|
||||||
|
/* Lottery: I won! */
|
||||||
|
if (dtree->expires[d] == 0)
|
||||||
|
dtree->expires[d] = 1;
|
||||||
|
DP("%u %lu", d, dtree->expires[d]);
|
||||||
|
if (ret == 0)
|
||||||
|
map->elements++;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
const struct ip_set_req_iptree *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptree)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iptree),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
DP("%u.%u.%u.%u %u", HIPQUAD(req->ip), req->timeout);
|
||||||
|
return __addip(set, req->ip,
|
||||||
|
req->timeout ? req->timeout : map->timeout,
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
|
||||||
|
return __addip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
map->timeout,
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DELIP_WALK(map, elem, branch) do { \
|
||||||
|
if ((map)->tree[elem]) { \
|
||||||
|
branch = (map)->tree[elem]; \
|
||||||
|
} else \
|
||||||
|
return -EEXIST; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
struct ip_set_iptreeb *btree;
|
||||||
|
struct ip_set_iptreec *ctree;
|
||||||
|
struct ip_set_iptreed *dtree;
|
||||||
|
unsigned char a,b,c,d;
|
||||||
|
|
||||||
|
if (!ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
ABCD(a, b, c, d, hash_ip);
|
||||||
|
DELIP_WALK(map, a, btree);
|
||||||
|
DELIP_WALK(btree, b, ctree);
|
||||||
|
DELIP_WALK(ctree, c, dtree);
|
||||||
|
|
||||||
|
if (dtree->expires[d]) {
|
||||||
|
dtree->expires[d] = 0;
|
||||||
|
map->elements--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -EEXIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptree *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptree)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iptree),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __delip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __delip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOOP_WALK_BEGIN(map, i, branch) \
|
||||||
|
for (i = 0; i < 256; i++) { \
|
||||||
|
if (!(map)->tree[i]) \
|
||||||
|
continue; \
|
||||||
|
branch = (map)->tree[i]
|
||||||
|
|
||||||
|
#define LOOP_WALK_END }
|
||||||
|
|
||||||
|
static void ip_tree_gc(unsigned long ul_set)
|
||||||
|
{
|
||||||
|
struct ip_set *set = (struct ip_set *) ul_set;
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
struct ip_set_iptreeb *btree;
|
||||||
|
struct ip_set_iptreec *ctree;
|
||||||
|
struct ip_set_iptreed *dtree;
|
||||||
|
unsigned int a,b,c,d;
|
||||||
|
unsigned char i,j,k;
|
||||||
|
|
||||||
|
i = j = k = 0;
|
||||||
|
DP("gc: %s", set->name);
|
||||||
|
write_lock_bh(&set->lock);
|
||||||
|
LOOP_WALK_BEGIN(map, a, btree);
|
||||||
|
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||||
|
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||||
|
for (d = 0; d < 256; d++) {
|
||||||
|
if (dtree->expires[d]) {
|
||||||
|
DP("gc: %u %u %u %u: expires %lu jiffies %lu",
|
||||||
|
a, b, c, d,
|
||||||
|
dtree->expires[d], jiffies);
|
||||||
|
if (map->timeout
|
||||||
|
&& time_before(dtree->expires[d], jiffies)) {
|
||||||
|
dtree->expires[d] = 0;
|
||||||
|
map->elements--;
|
||||||
|
} else
|
||||||
|
k = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (k == 0) {
|
||||||
|
DP("gc: %s: leaf %u %u %u empty",
|
||||||
|
set->name, a, b, c);
|
||||||
|
kmem_cache_free(leaf_cachep, dtree);
|
||||||
|
ctree->tree[c] = NULL;
|
||||||
|
} else {
|
||||||
|
DP("gc: %s: leaf %u %u %u not empty",
|
||||||
|
set->name, a, b, c);
|
||||||
|
j = 1;
|
||||||
|
k = 0;
|
||||||
|
}
|
||||||
|
LOOP_WALK_END;
|
||||||
|
if (j == 0) {
|
||||||
|
DP("gc: %s: branch %u %u empty",
|
||||||
|
set->name, a, b);
|
||||||
|
kmem_cache_free(branch_cachep, ctree);
|
||||||
|
btree->tree[b] = NULL;
|
||||||
|
} else {
|
||||||
|
DP("gc: %s: branch %u %u not empty",
|
||||||
|
set->name, a, b);
|
||||||
|
i = 1;
|
||||||
|
j = k = 0;
|
||||||
|
}
|
||||||
|
LOOP_WALK_END;
|
||||||
|
if (i == 0) {
|
||||||
|
DP("gc: %s: branch %u empty",
|
||||||
|
set->name, a);
|
||||||
|
kmem_cache_free(branch_cachep, btree);
|
||||||
|
map->tree[a] = NULL;
|
||||||
|
} else {
|
||||||
|
DP("gc: %s: branch %u not empty",
|
||||||
|
set->name, a);
|
||||||
|
i = j = k = 0;
|
||||||
|
}
|
||||||
|
LOOP_WALK_END;
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
|
||||||
|
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||||
|
add_timer(&map->gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void init_gc_timer(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
|
||||||
|
/* Even if there is no timeout for the entries,
|
||||||
|
* we still have to call gc because delete
|
||||||
|
* do not clean up empty branches */
|
||||||
|
map->gc_interval = IPTREE_GC_TIME;
|
||||||
|
init_timer(&map->gc);
|
||||||
|
map->gc.data = (unsigned long) set;
|
||||||
|
map->gc.function = ip_tree_gc;
|
||||||
|
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||||
|
add_timer(&map->gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptree_create *req = data;
|
||||||
|
struct ip_set_iptree *map;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptree_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_iptree_create),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kmalloc(sizeof(struct ip_set_iptree), GFP_KERNEL);
|
||||||
|
if (!map) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_iptree));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memset(map, 0, sizeof(*map));
|
||||||
|
map->timeout = req->timeout;
|
||||||
|
map->elements = 0;
|
||||||
|
set->data = map;
|
||||||
|
|
||||||
|
init_gc_timer(set);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __flush(struct ip_set_iptree *map)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreeb *btree;
|
||||||
|
struct ip_set_iptreec *ctree;
|
||||||
|
struct ip_set_iptreed *dtree;
|
||||||
|
unsigned int a,b,c;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN(map, a, btree);
|
||||||
|
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||||
|
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||||
|
kmem_cache_free(leaf_cachep, dtree);
|
||||||
|
LOOP_WALK_END;
|
||||||
|
kmem_cache_free(branch_cachep, ctree);
|
||||||
|
LOOP_WALK_END;
|
||||||
|
kmem_cache_free(branch_cachep, btree);
|
||||||
|
LOOP_WALK_END;
|
||||||
|
map->elements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
|
||||||
|
/* gc might be running */
|
||||||
|
while (!del_timer(&map->gc))
|
||||||
|
msleep(IPTREE_DESTROY_SLEEP);
|
||||||
|
__flush(map);
|
||||||
|
kfree(map);
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *map = set->data;
|
||||||
|
unsigned int timeout = map->timeout;
|
||||||
|
|
||||||
|
/* gc might be running */
|
||||||
|
while (!del_timer(&map->gc))
|
||||||
|
msleep(IPTREE_DESTROY_SLEEP);
|
||||||
|
__flush(map);
|
||||||
|
memset(map, 0, sizeof(*map));
|
||||||
|
map->timeout = timeout;
|
||||||
|
|
||||||
|
init_gc_timer(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_iptree *map = set->data;
|
||||||
|
struct ip_set_req_iptree_create *header = data;
|
||||||
|
|
||||||
|
header->timeout = map->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
const struct ip_set_iptree *map = set->data;
|
||||||
|
struct ip_set_iptreeb *btree;
|
||||||
|
struct ip_set_iptreec *ctree;
|
||||||
|
struct ip_set_iptreed *dtree;
|
||||||
|
unsigned int a,b,c,d;
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN(map, a, btree);
|
||||||
|
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||||
|
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||||
|
for (d = 0; d < 256; d++) {
|
||||||
|
if (dtree->expires[d]
|
||||||
|
&& (!map->timeout || time_after(dtree->expires[d], jiffies)))
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
LOOP_WALK_END;
|
||||||
|
LOOP_WALK_END;
|
||||||
|
LOOP_WALK_END;
|
||||||
|
|
||||||
|
DP("members %u", count);
|
||||||
|
return (count * sizeof(struct ip_set_req_iptree));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_iptree *map = set->data;
|
||||||
|
struct ip_set_iptreeb *btree;
|
||||||
|
struct ip_set_iptreec *ctree;
|
||||||
|
struct ip_set_iptreed *dtree;
|
||||||
|
unsigned int a,b,c,d;
|
||||||
|
size_t offset = 0;
|
||||||
|
struct ip_set_req_iptree *entry;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN(map, a, btree);
|
||||||
|
LOOP_WALK_BEGIN(btree, b, ctree);
|
||||||
|
LOOP_WALK_BEGIN(ctree, c, dtree);
|
||||||
|
for (d = 0; d < 256; d++) {
|
||||||
|
if (dtree->expires[d]
|
||||||
|
&& (!map->timeout || time_after(dtree->expires[d], jiffies))) {
|
||||||
|
entry = data + offset;
|
||||||
|
entry->ip = ((a << 24) | (b << 16) | (c << 8) | d);
|
||||||
|
entry->timeout = !map->timeout ? 0
|
||||||
|
: (dtree->expires[d] - jiffies)/HZ;
|
||||||
|
offset += sizeof(struct ip_set_req_iptree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOOP_WALK_END;
|
||||||
|
LOOP_WALK_END;
|
||||||
|
LOOP_WALK_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_iptree = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = &create,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.flush = &flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_iptree),
|
||||||
|
.addip = &addip,
|
||||||
|
.addip_kernel = &addip_kernel,
|
||||||
|
.delip = &delip,
|
||||||
|
.delip_kernel = &delip_kernel,
|
||||||
|
.testip = &testip,
|
||||||
|
.testip_kernel = &testip_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_iptree_create),
|
||||||
|
.list_header = &list_header,
|
||||||
|
.list_members_size = &list_members_size,
|
||||||
|
.list_members = &list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("iptree type of IP sets");
|
||||||
|
module_param(limit, int, 0600);
|
||||||
|
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||||
|
|
||||||
|
static int __init ip_set_iptree_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
branch_cachep = kmem_cache_create("ip_set_iptreeb",
|
||||||
|
sizeof(struct ip_set_iptreeb),
|
||||||
|
0, 0, NULL);
|
||||||
|
#else
|
||||||
|
branch_cachep = kmem_cache_create("ip_set_iptreeb",
|
||||||
|
sizeof(struct ip_set_iptreeb),
|
||||||
|
0, 0, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
if (!branch_cachep) {
|
||||||
|
printk(KERN_ERR "Unable to create ip_set_iptreeb slab cache\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
leaf_cachep = kmem_cache_create("ip_set_iptreed",
|
||||||
|
sizeof(struct ip_set_iptreed),
|
||||||
|
0, 0, NULL);
|
||||||
|
#else
|
||||||
|
leaf_cachep = kmem_cache_create("ip_set_iptreed",
|
||||||
|
sizeof(struct ip_set_iptreed),
|
||||||
|
0, 0, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
if (!leaf_cachep) {
|
||||||
|
printk(KERN_ERR "Unable to create ip_set_iptreed slab cache\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free_branch;
|
||||||
|
}
|
||||||
|
ret = ip_set_register_set_type(&ip_set_iptree);
|
||||||
|
if (ret == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
kmem_cache_destroy(leaf_cachep);
|
||||||
|
free_branch:
|
||||||
|
kmem_cache_destroy(branch_cachep);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_iptree_fini(void)
|
||||||
|
{
|
||||||
|
/* FIXME: possible race with ip_set_create() */
|
||||||
|
ip_set_unregister_set_type(&ip_set_iptree);
|
||||||
|
kmem_cache_destroy(leaf_cachep);
|
||||||
|
kmem_cache_destroy(branch_cachep);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_iptree_init);
|
||||||
|
module_exit(ip_set_iptree_fini);
|
40
extensions/ipset/ip_set_iptree.h
Normal file
40
extensions/ipset/ip_set_iptree.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef __IP_SET_IPTREE_H
|
||||||
|
#define __IP_SET_IPTREE_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "iptree"
|
||||||
|
#define MAX_RANGE 0x0000FFFF
|
||||||
|
|
||||||
|
struct ip_set_iptreed {
|
||||||
|
unsigned long expires[256]; /* x.x.x.ADDR */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_iptreec {
|
||||||
|
struct ip_set_iptreed *tree[256]; /* x.x.ADDR.* */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_iptreeb {
|
||||||
|
struct ip_set_iptreec *tree[256]; /* x.ADDR.*.* */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_iptree {
|
||||||
|
unsigned int timeout;
|
||||||
|
unsigned int gc_interval;
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
uint32_t elements; /* number of elements */
|
||||||
|
struct timer_list gc;
|
||||||
|
struct ip_set_iptreeb *tree[256]; /* ADDR.*.*.* */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_iptree_create {
|
||||||
|
unsigned int timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_iptree {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
unsigned int timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __IP_SET_IPTREE_H */
|
827
extensions/ipset/ip_set_iptreemap.c
Normal file
827
extensions/ipset/ip_set_iptreemap.c
Normal file
@@ -0,0 +1,827 @@
|
|||||||
|
/* Copyright (C) 2007 Sven Wegener <sven.wegener@stealer.net>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This modules implements the iptreemap ipset type. It uses bitmaps to
|
||||||
|
* represent every single IPv4 address as a bit. The bitmaps are managed in a
|
||||||
|
* tree structure, where the first three octets of an address are used as an
|
||||||
|
* index to find the bitmap and the last octet is used as the bit number.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#include "ip_set_iptreemap.h"
|
||||||
|
|
||||||
|
#define IPTREEMAP_DEFAULT_GC_TIME (5 * 60)
|
||||||
|
#define IPTREEMAP_DESTROY_SLEEP (100)
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
|
||||||
|
static struct kmem_cache *cachep_b;
|
||||||
|
static struct kmem_cache *cachep_c;
|
||||||
|
static struct kmem_cache *cachep_d;
|
||||||
|
#else
|
||||||
|
static kmem_cache_t *cachep_b;
|
||||||
|
static kmem_cache_t *cachep_c;
|
||||||
|
static kmem_cache_t *cachep_d;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct ip_set_iptreemap_d *fullbitmap_d;
|
||||||
|
static struct ip_set_iptreemap_c *fullbitmap_c;
|
||||||
|
static struct ip_set_iptreemap_b *fullbitmap_b;
|
||||||
|
|
||||||
|
#if defined(__LITTLE_ENDIAN)
|
||||||
|
#define ABCD(a, b, c, d, addr) \
|
||||||
|
do { \
|
||||||
|
a = ((unsigned char *)addr)[3]; \
|
||||||
|
b = ((unsigned char *)addr)[2]; \
|
||||||
|
c = ((unsigned char *)addr)[1]; \
|
||||||
|
d = ((unsigned char *)addr)[0]; \
|
||||||
|
} while (0)
|
||||||
|
#elif defined(__BIG_ENDIAN)
|
||||||
|
#define ABCD(a,b,c,d,addrp) do { \
|
||||||
|
a = ((unsigned char *)addrp)[0]; \
|
||||||
|
b = ((unsigned char *)addrp)[1]; \
|
||||||
|
c = ((unsigned char *)addrp)[2]; \
|
||||||
|
d = ((unsigned char *)addrp)[3]; \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#error "Please fix asm/byteorder.h"
|
||||||
|
#endif /* __LITTLE_ENDIAN */
|
||||||
|
|
||||||
|
#define TESTIP_WALK(map, elem, branch, full) \
|
||||||
|
do { \
|
||||||
|
branch = (map)->tree[elem]; \
|
||||||
|
if (!branch) \
|
||||||
|
return 0; \
|
||||||
|
else if (branch == full) \
|
||||||
|
return 1; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ADDIP_WALK(map, elem, branch, type, cachep, full) \
|
||||||
|
do { \
|
||||||
|
branch = (map)->tree[elem]; \
|
||||||
|
if (!branch) { \
|
||||||
|
branch = (type *) kmem_cache_alloc(cachep, GFP_ATOMIC); \
|
||||||
|
if (!branch) \
|
||||||
|
return -ENOMEM; \
|
||||||
|
memset(branch, 0, sizeof(*branch)); \
|
||||||
|
(map)->tree[elem] = branch; \
|
||||||
|
} else if (branch == full) { \
|
||||||
|
return -EEXIST; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ADDIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free) \
|
||||||
|
for (a = a1; a <= a2; a++) { \
|
||||||
|
branch = (map)->tree[a]; \
|
||||||
|
if (branch != full) { \
|
||||||
|
if ((a > a1 && a < a2) || (hint)) { \
|
||||||
|
if (branch) \
|
||||||
|
free(branch); \
|
||||||
|
(map)->tree[a] = full; \
|
||||||
|
continue; \
|
||||||
|
} else if (!branch) { \
|
||||||
|
branch = kmem_cache_alloc(cachep, GFP_ATOMIC); \
|
||||||
|
if (!branch) \
|
||||||
|
return -ENOMEM; \
|
||||||
|
memset(branch, 0, sizeof(*branch)); \
|
||||||
|
(map)->tree[a] = branch; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADDIP_RANGE_LOOP_END() \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DELIP_WALK(map, elem, branch, cachep, full, flags) \
|
||||||
|
do { \
|
||||||
|
branch = (map)->tree[elem]; \
|
||||||
|
if (!branch) { \
|
||||||
|
return -EEXIST; \
|
||||||
|
} else if (branch == full) { \
|
||||||
|
branch = kmem_cache_alloc(cachep, flags); \
|
||||||
|
if (!branch) \
|
||||||
|
return -ENOMEM; \
|
||||||
|
memcpy(branch, full, sizeof(*full)); \
|
||||||
|
(map)->tree[elem] = branch; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define DELIP_RANGE_LOOP(map, a, a1, a2, hint, branch, full, cachep, free, flags) \
|
||||||
|
for (a = a1; a <= a2; a++) { \
|
||||||
|
branch = (map)->tree[a]; \
|
||||||
|
if (branch) { \
|
||||||
|
if ((a > a1 && a < a2) || (hint)) { \
|
||||||
|
if (branch != full) \
|
||||||
|
free(branch); \
|
||||||
|
(map)->tree[a] = NULL; \
|
||||||
|
continue; \
|
||||||
|
} else if (branch == full) { \
|
||||||
|
branch = kmem_cache_alloc(cachep, flags); \
|
||||||
|
if (!branch) \
|
||||||
|
return -ENOMEM; \
|
||||||
|
memcpy(branch, full, sizeof(*branch)); \
|
||||||
|
(map)->tree[a] = branch; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DELIP_RANGE_LOOP_END() \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOOP_WALK_BEGIN(map, i, branch) \
|
||||||
|
for (i = 0; i < 256; i++) { \
|
||||||
|
branch = (map)->tree[i]; \
|
||||||
|
if (likely(!branch)) \
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#define LOOP_WALK_END() \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOOP_WALK_BEGIN_GC(map, i, branch, full, cachep, count) \
|
||||||
|
count = -256; \
|
||||||
|
for (i = 0; i < 256; i++) { \
|
||||||
|
branch = (map)->tree[i]; \
|
||||||
|
if (likely(!branch)) \
|
||||||
|
continue; \
|
||||||
|
count++; \
|
||||||
|
if (branch == full) { \
|
||||||
|
count++; \
|
||||||
|
continue; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOOP_WALK_END_GC(map, i, branch, full, cachep, count) \
|
||||||
|
if (-256 == count) { \
|
||||||
|
kmem_cache_free(cachep, branch); \
|
||||||
|
(map)->tree[i] = NULL; \
|
||||||
|
} else if (256 == count) { \
|
||||||
|
kmem_cache_free(cachep, branch); \
|
||||||
|
(map)->tree[i] = full; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOOP_WALK_BEGIN_COUNT(map, i, branch, inrange, count) \
|
||||||
|
for (i = 0; i < 256; i++) { \
|
||||||
|
if (!(map)->tree[i]) { \
|
||||||
|
if (inrange) { \
|
||||||
|
count++; \
|
||||||
|
inrange = 0; \
|
||||||
|
} \
|
||||||
|
continue; \
|
||||||
|
} \
|
||||||
|
branch = (map)->tree[i];
|
||||||
|
|
||||||
|
#define LOOP_WALK_END_COUNT() \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GETVALUE1(a, a1, b1, r) \
|
||||||
|
(a == a1 ? b1 : r)
|
||||||
|
|
||||||
|
#define GETVALUE2(a, b, a1, b1, c1, r) \
|
||||||
|
(a == a1 && b == b1 ? c1 : r)
|
||||||
|
|
||||||
|
#define GETVALUE3(a, b, c, a1, b1, c1, d1, r) \
|
||||||
|
(a == a1 && b == b1 && c == c1 ? d1 : r)
|
||||||
|
|
||||||
|
#define CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2) \
|
||||||
|
( \
|
||||||
|
GETVALUE1(a, a1, b1, 0) == 0 \
|
||||||
|
&& GETVALUE1(a, a2, b2, 255) == 255 \
|
||||||
|
&& c1 == 0 \
|
||||||
|
&& c2 == 255 \
|
||||||
|
&& d1 == 0 \
|
||||||
|
&& d2 == 255 \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2) \
|
||||||
|
( \
|
||||||
|
GETVALUE2(a, b, a1, b1, c1, 0) == 0 \
|
||||||
|
&& GETVALUE2(a, b, a2, b2, c2, 255) == 255 \
|
||||||
|
&& d1 == 0 \
|
||||||
|
&& d2 == 255 \
|
||||||
|
)
|
||||||
|
|
||||||
|
#define CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2) \
|
||||||
|
( \
|
||||||
|
GETVALUE3(a, b, c, a1, b1, c1, d1, 0) == 0 \
|
||||||
|
&& GETVALUE3(a, b, c, a2, b2, c2, d2, 255) == 255 \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
free_d(struct ip_set_iptreemap_d *map)
|
||||||
|
{
|
||||||
|
kmem_cache_free(cachep_d, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
free_c(struct ip_set_iptreemap_c *map)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN(map, i, dtree) {
|
||||||
|
if (dtree != fullbitmap_d)
|
||||||
|
free_d(dtree);
|
||||||
|
} LOOP_WALK_END();
|
||||||
|
|
||||||
|
kmem_cache_free(cachep_c, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
free_b(struct ip_set_iptreemap_b *map)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN(map, i, ctree) {
|
||||||
|
if (ctree != fullbitmap_c)
|
||||||
|
free_c(ctree);
|
||||||
|
} LOOP_WALK_END();
|
||||||
|
|
||||||
|
kmem_cache_free(cachep_b, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned char a, b, c, d;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
|
||||||
|
ABCD(a, b, c, d, hash_ip);
|
||||||
|
|
||||||
|
TESTIP_WALK(map, a, btree, fullbitmap_b);
|
||||||
|
TESTIP_WALK(btree, b, ctree, fullbitmap_c);
|
||||||
|
TESTIP_WALK(ctree, c, dtree, fullbitmap_d);
|
||||||
|
|
||||||
|
return !!test_bit(d, (void *) dtree->bitmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptreemap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptreemap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __testip(set, req->start, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
res = __testip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
|
||||||
|
return (res < 0 ? 0 : res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = (struct ip_set_iptreemap *) set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned char a, b, c, d;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
|
||||||
|
ABCD(a, b, c, d, hash_ip);
|
||||||
|
|
||||||
|
ADDIP_WALK(map, a, btree, struct ip_set_iptreemap_b, cachep_b, fullbitmap_b);
|
||||||
|
ADDIP_WALK(btree, b, ctree, struct ip_set_iptreemap_c, cachep_c, fullbitmap_c);
|
||||||
|
ADDIP_WALK(ctree, c, dtree, struct ip_set_iptreemap_d, cachep_d, fullbitmap_d);
|
||||||
|
|
||||||
|
if (__test_and_set_bit(d, (void *) dtree->bitmap))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
__set_bit(b, (void *) btree->dirty);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned int a, b, c, d;
|
||||||
|
unsigned char a1, b1, c1, d1;
|
||||||
|
unsigned char a2, b2, c2, d2;
|
||||||
|
|
||||||
|
if (start == end)
|
||||||
|
return __addip_single(set, start, hash_ip);
|
||||||
|
|
||||||
|
*hash_ip = start;
|
||||||
|
|
||||||
|
ABCD(a1, b1, c1, d1, &start);
|
||||||
|
ABCD(a2, b2, c2, d2, &end);
|
||||||
|
|
||||||
|
/* This is sooo ugly... */
|
||||||
|
ADDIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b) {
|
||||||
|
ADDIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c) {
|
||||||
|
ADDIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d) {
|
||||||
|
for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
|
||||||
|
__set_bit(d, (void *) dtree->bitmap);
|
||||||
|
__set_bit(b, (void *) btree->dirty);
|
||||||
|
} ADDIP_RANGE_LOOP_END();
|
||||||
|
} ADDIP_RANGE_LOOP_END();
|
||||||
|
} ADDIP_RANGE_LOOP_END();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptreemap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptreemap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __addip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
|
||||||
|
{
|
||||||
|
|
||||||
|
return __addip_single(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip_single(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip, unsigned int __nocast flags)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned char a,b,c,d;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
|
||||||
|
ABCD(a, b, c, d, hash_ip);
|
||||||
|
|
||||||
|
DELIP_WALK(map, a, btree, cachep_b, fullbitmap_b, flags);
|
||||||
|
DELIP_WALK(btree, b, ctree, cachep_c, fullbitmap_c, flags);
|
||||||
|
DELIP_WALK(ctree, c, dtree, cachep_d, fullbitmap_d, flags);
|
||||||
|
|
||||||
|
if (!__test_and_clear_bit(d, (void *) dtree->bitmap))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
__set_bit(b, (void *) btree->dirty);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip_range(struct ip_set *set, ip_set_ip_t start, ip_set_ip_t end, ip_set_ip_t *hash_ip, unsigned int __nocast flags)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned int a, b, c, d;
|
||||||
|
unsigned char a1, b1, c1, d1;
|
||||||
|
unsigned char a2, b2, c2, d2;
|
||||||
|
|
||||||
|
if (start == end)
|
||||||
|
return __delip_single(set, start, hash_ip, flags);
|
||||||
|
|
||||||
|
*hash_ip = start;
|
||||||
|
|
||||||
|
ABCD(a1, b1, c1, d1, &start);
|
||||||
|
ABCD(a2, b2, c2, d2, &end);
|
||||||
|
|
||||||
|
/* This is sooo ugly... */
|
||||||
|
DELIP_RANGE_LOOP(map, a, a1, a2, CHECK1(a, a1, a2, b1, b2, c1, c2, d1, d2), btree, fullbitmap_b, cachep_b, free_b, flags) {
|
||||||
|
DELIP_RANGE_LOOP(btree, b, GETVALUE1(a, a1, b1, 0), GETVALUE1(a, a2, b2, 255), CHECK2(a, b, a1, a2, b1, b2, c1, c2, d1, d2), ctree, fullbitmap_c, cachep_c, free_c, flags) {
|
||||||
|
DELIP_RANGE_LOOP(ctree, c, GETVALUE2(a, b, a1, b1, c1, 0), GETVALUE2(a, b, a2, b2, c2, 255), CHECK3(a, b, c, a1, a2, b1, b2, c1, c2, d1, d2), dtree, fullbitmap_d, cachep_d, free_d, flags) {
|
||||||
|
for (d = GETVALUE3(a, b, c, a1, b1, c1, d1, 0); d <= GETVALUE3(a, b, c, a2, b2, c2, d2, 255); d++)
|
||||||
|
__clear_bit(d, (void *) dtree->bitmap);
|
||||||
|
__set_bit(b, (void *) btree->dirty);
|
||||||
|
} DELIP_RANGE_LOOP_END();
|
||||||
|
} DELIP_RANGE_LOOP_END();
|
||||||
|
} DELIP_RANGE_LOOP_END();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptreemap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptreemap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap), size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __delip_range(set, min(req->start, req->end), max(req->start, req->end), hash_ip, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip_kernel(struct ip_set *set, const struct sk_buff *skb, ip_set_ip_t *hash_ip, const u_int32_t *flags, unsigned char index)
|
||||||
|
{
|
||||||
|
return __delip_single(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip,
|
||||||
|
GFP_ATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the status of the bitmap
|
||||||
|
* -1 == all bits cleared
|
||||||
|
* 1 == all bits set
|
||||||
|
* 0 == anything else
|
||||||
|
*/
|
||||||
|
static inline int
|
||||||
|
bitmap_status(struct ip_set_iptreemap_d *dtree)
|
||||||
|
{
|
||||||
|
unsigned char first = dtree->bitmap[0];
|
||||||
|
int a;
|
||||||
|
|
||||||
|
for (a = 1; a < 32; a++)
|
||||||
|
if (dtree->bitmap[a] != first)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (first == 0 ? -1 : (first == 255 ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gc(unsigned long addr)
|
||||||
|
{
|
||||||
|
struct ip_set *set = (struct ip_set *) addr;
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned int a, b, c;
|
||||||
|
int i, j, k;
|
||||||
|
|
||||||
|
write_lock_bh(&set->lock);
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN_GC(map, a, btree, fullbitmap_b, cachep_b, i) {
|
||||||
|
LOOP_WALK_BEGIN_GC(btree, b, ctree, fullbitmap_c, cachep_c, j) {
|
||||||
|
if (!__test_and_clear_bit(b, (void *) btree->dirty))
|
||||||
|
continue;
|
||||||
|
LOOP_WALK_BEGIN_GC(ctree, c, dtree, fullbitmap_d, cachep_d, k) {
|
||||||
|
switch (bitmap_status(dtree)) {
|
||||||
|
case -1:
|
||||||
|
kmem_cache_free(cachep_d, dtree);
|
||||||
|
ctree->tree[c] = NULL;
|
||||||
|
k--;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
kmem_cache_free(cachep_d, dtree);
|
||||||
|
ctree->tree[c] = fullbitmap_d;
|
||||||
|
k++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} LOOP_WALK_END();
|
||||||
|
} LOOP_WALK_END_GC(btree, b, ctree, fullbitmap_c, cachep_c, k);
|
||||||
|
} LOOP_WALK_END_GC(map, a, btree, fullbitmap_b, cachep_b, j);
|
||||||
|
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
|
||||||
|
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||||
|
add_timer(&map->gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
init_gc_timer(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
|
||||||
|
init_timer(&map->gc);
|
||||||
|
map->gc.data = (unsigned long) set;
|
||||||
|
map->gc.function = gc;
|
||||||
|
map->gc.expires = jiffies + map->gc_interval * HZ;
|
||||||
|
add_timer(&map->gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptreemap_create *req = data;
|
||||||
|
struct ip_set_iptreemap *map;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_iptreemap_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)", sizeof(struct ip_set_req_iptreemap_create), size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||||
|
if (!map)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
map->gc_interval = req->gc_interval ? req->gc_interval : IPTREEMAP_DEFAULT_GC_TIME;
|
||||||
|
set->data = map;
|
||||||
|
|
||||||
|
init_gc_timer(set);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __flush(struct ip_set_iptreemap *map)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
unsigned int a;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN(map, a, btree);
|
||||||
|
if (btree != fullbitmap_b)
|
||||||
|
free_b(btree);
|
||||||
|
LOOP_WALK_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
|
||||||
|
while (!del_timer(&map->gc))
|
||||||
|
msleep(IPTREEMAP_DESTROY_SLEEP);
|
||||||
|
|
||||||
|
__flush(map);
|
||||||
|
kfree(map);
|
||||||
|
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
|
||||||
|
while (!del_timer(&map->gc))
|
||||||
|
msleep(IPTREEMAP_DESTROY_SLEEP);
|
||||||
|
|
||||||
|
__flush(map);
|
||||||
|
|
||||||
|
memset(map, 0, sizeof(*map));
|
||||||
|
|
||||||
|
init_gc_timer(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_req_iptreemap_create *header = data;
|
||||||
|
|
||||||
|
header->gc_interval = map->gc_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned int a, b, c, d, inrange = 0, count = 0;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN_COUNT(map, a, btree, inrange, count) {
|
||||||
|
LOOP_WALK_BEGIN_COUNT(btree, b, ctree, inrange, count) {
|
||||||
|
LOOP_WALK_BEGIN_COUNT(ctree, c, dtree, inrange, count) {
|
||||||
|
for (d = 0; d < 256; d++) {
|
||||||
|
if (test_bit(d, (void *) dtree->bitmap)) {
|
||||||
|
inrange = 1;
|
||||||
|
} else if (inrange) {
|
||||||
|
count++;
|
||||||
|
inrange = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} LOOP_WALK_END_COUNT();
|
||||||
|
} LOOP_WALK_END_COUNT();
|
||||||
|
} LOOP_WALK_END_COUNT();
|
||||||
|
|
||||||
|
if (inrange)
|
||||||
|
count++;
|
||||||
|
|
||||||
|
return (count * sizeof(struct ip_set_req_iptreemap));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t add_member(void *data, size_t offset, ip_set_ip_t start, ip_set_ip_t end)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptreemap *entry = data + offset;
|
||||||
|
|
||||||
|
entry->start = start;
|
||||||
|
entry->end = end;
|
||||||
|
|
||||||
|
return sizeof(*entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *map = set->data;
|
||||||
|
struct ip_set_iptreemap_b *btree;
|
||||||
|
struct ip_set_iptreemap_c *ctree;
|
||||||
|
struct ip_set_iptreemap_d *dtree;
|
||||||
|
unsigned int a, b, c, d, inrange = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
ip_set_ip_t start = 0, end = 0, ip;
|
||||||
|
|
||||||
|
LOOP_WALK_BEGIN(map, a, btree) {
|
||||||
|
LOOP_WALK_BEGIN(btree, b, ctree) {
|
||||||
|
LOOP_WALK_BEGIN(ctree, c, dtree) {
|
||||||
|
for (d = 0; d < 256; d++) {
|
||||||
|
if (test_bit(d, (void *) dtree->bitmap)) {
|
||||||
|
ip = ((a << 24) | (b << 16) | (c << 8) | d);
|
||||||
|
if (!inrange) {
|
||||||
|
inrange = 1;
|
||||||
|
start = ip;
|
||||||
|
} else if (end < ip - 1) {
|
||||||
|
offset += add_member(data, offset, start, end);
|
||||||
|
start = ip;
|
||||||
|
}
|
||||||
|
end = ip;
|
||||||
|
} else if (inrange) {
|
||||||
|
offset += add_member(data, offset, start, end);
|
||||||
|
inrange = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} LOOP_WALK_END();
|
||||||
|
} LOOP_WALK_END();
|
||||||
|
} LOOP_WALK_END();
|
||||||
|
|
||||||
|
if (inrange)
|
||||||
|
add_member(data, offset, start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_iptreemap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = create,
|
||||||
|
.destroy = destroy,
|
||||||
|
.flush = flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_iptreemap),
|
||||||
|
.addip = addip,
|
||||||
|
.addip_kernel = addip_kernel,
|
||||||
|
.delip = delip,
|
||||||
|
.delip_kernel = delip_kernel,
|
||||||
|
.testip = testip,
|
||||||
|
.testip_kernel = testip_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_iptreemap_create),
|
||||||
|
.list_header = list_header,
|
||||||
|
.list_members_size = list_members_size,
|
||||||
|
.list_members = list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Sven Wegener <sven.wegener@stealer.net>");
|
||||||
|
MODULE_DESCRIPTION("iptreemap type of IP sets");
|
||||||
|
|
||||||
|
static int __init ip_set_iptreemap_init(void)
|
||||||
|
{
|
||||||
|
int ret = -ENOMEM;
|
||||||
|
int a;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
cachep_b = kmem_cache_create("ip_set_iptreemap_b",
|
||||||
|
sizeof(struct ip_set_iptreemap_b),
|
||||||
|
0, 0, NULL);
|
||||||
|
#else
|
||||||
|
cachep_b = kmem_cache_create("ip_set_iptreemap_b",
|
||||||
|
sizeof(struct ip_set_iptreemap_b),
|
||||||
|
0, 0, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
if (!cachep_b) {
|
||||||
|
ip_set_printk("Unable to create ip_set_iptreemap_b slab cache");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
cachep_c = kmem_cache_create("ip_set_iptreemap_c",
|
||||||
|
sizeof(struct ip_set_iptreemap_c),
|
||||||
|
0, 0, NULL);
|
||||||
|
#else
|
||||||
|
cachep_c = kmem_cache_create("ip_set_iptreemap_c",
|
||||||
|
sizeof(struct ip_set_iptreemap_c),
|
||||||
|
0, 0, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
if (!cachep_c) {
|
||||||
|
ip_set_printk("Unable to create ip_set_iptreemap_c slab cache");
|
||||||
|
goto outb;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
cachep_d = kmem_cache_create("ip_set_iptreemap_d",
|
||||||
|
sizeof(struct ip_set_iptreemap_d),
|
||||||
|
0, 0, NULL);
|
||||||
|
#else
|
||||||
|
cachep_d = kmem_cache_create("ip_set_iptreemap_d",
|
||||||
|
sizeof(struct ip_set_iptreemap_d),
|
||||||
|
0, 0, NULL, NULL);
|
||||||
|
#endif
|
||||||
|
if (!cachep_d) {
|
||||||
|
ip_set_printk("Unable to create ip_set_iptreemap_d slab cache");
|
||||||
|
goto outc;
|
||||||
|
}
|
||||||
|
|
||||||
|
fullbitmap_d = kmem_cache_alloc(cachep_d, GFP_KERNEL);
|
||||||
|
if (!fullbitmap_d)
|
||||||
|
goto outd;
|
||||||
|
|
||||||
|
fullbitmap_c = kmem_cache_alloc(cachep_c, GFP_KERNEL);
|
||||||
|
if (!fullbitmap_c)
|
||||||
|
goto outbitmapd;
|
||||||
|
|
||||||
|
fullbitmap_b = kmem_cache_alloc(cachep_b, GFP_KERNEL);
|
||||||
|
if (!fullbitmap_b)
|
||||||
|
goto outbitmapc;
|
||||||
|
|
||||||
|
ret = ip_set_register_set_type(&ip_set_iptreemap);
|
||||||
|
if (0 > ret)
|
||||||
|
goto outbitmapb;
|
||||||
|
|
||||||
|
/* Now init our global bitmaps */
|
||||||
|
memset(fullbitmap_d->bitmap, 0xff, sizeof(fullbitmap_d->bitmap));
|
||||||
|
|
||||||
|
for (a = 0; a < 256; a++)
|
||||||
|
fullbitmap_c->tree[a] = fullbitmap_d;
|
||||||
|
|
||||||
|
for (a = 0; a < 256; a++)
|
||||||
|
fullbitmap_b->tree[a] = fullbitmap_c;
|
||||||
|
memset(fullbitmap_b->dirty, 0, sizeof(fullbitmap_b->dirty));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
outbitmapb:
|
||||||
|
kmem_cache_free(cachep_b, fullbitmap_b);
|
||||||
|
outbitmapc:
|
||||||
|
kmem_cache_free(cachep_c, fullbitmap_c);
|
||||||
|
outbitmapd:
|
||||||
|
kmem_cache_free(cachep_d, fullbitmap_d);
|
||||||
|
outd:
|
||||||
|
kmem_cache_destroy(cachep_d);
|
||||||
|
outc:
|
||||||
|
kmem_cache_destroy(cachep_c);
|
||||||
|
outb:
|
||||||
|
kmem_cache_destroy(cachep_b);
|
||||||
|
out:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_iptreemap_fini(void)
|
||||||
|
{
|
||||||
|
ip_set_unregister_set_type(&ip_set_iptreemap);
|
||||||
|
kmem_cache_free(cachep_d, fullbitmap_d);
|
||||||
|
kmem_cache_free(cachep_c, fullbitmap_c);
|
||||||
|
kmem_cache_free(cachep_b, fullbitmap_b);
|
||||||
|
kmem_cache_destroy(cachep_d);
|
||||||
|
kmem_cache_destroy(cachep_c);
|
||||||
|
kmem_cache_destroy(cachep_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_iptreemap_init);
|
||||||
|
module_exit(ip_set_iptreemap_fini);
|
40
extensions/ipset/ip_set_iptreemap.h
Normal file
40
extensions/ipset/ip_set_iptreemap.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#ifndef __IP_SET_IPTREEMAP_H
|
||||||
|
#define __IP_SET_IPTREEMAP_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "iptreemap"
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
struct ip_set_iptreemap_d {
|
||||||
|
unsigned char bitmap[32]; /* x.x.x.y */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_iptreemap_c {
|
||||||
|
struct ip_set_iptreemap_d *tree[256]; /* x.x.y.x */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_iptreemap_b {
|
||||||
|
struct ip_set_iptreemap_c *tree[256]; /* x.y.x.x */
|
||||||
|
unsigned char dirty[32];
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct ip_set_iptreemap {
|
||||||
|
unsigned int gc_interval;
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
struct timer_list gc;
|
||||||
|
struct ip_set_iptreemap_b *tree[256]; /* y.x.x.x */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_iptreemap_create {
|
||||||
|
unsigned int gc_interval;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_iptreemap {
|
||||||
|
ip_set_ip_t start;
|
||||||
|
ip_set_ip_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __IP_SET_IPTREEMAP_H */
|
148
extensions/ipset/ip_set_jhash.h
Normal file
148
extensions/ipset/ip_set_jhash.h
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
#ifndef _LINUX_IPSET_JHASH_H
|
||||||
|
#define _LINUX_IPSET_JHASH_H
|
||||||
|
|
||||||
|
/* This is a copy of linux/jhash.h but the types u32/u8 are changed
|
||||||
|
* to __u32/__u8 so that the header file can be included into
|
||||||
|
* userspace code as well. Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* jhash.h: Jenkins hash support.
|
||||||
|
*
|
||||||
|
* Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
|
||||||
|
*
|
||||||
|
* http://burtleburtle.net/bob/hash/
|
||||||
|
*
|
||||||
|
* These are the credits from Bob's sources:
|
||||||
|
*
|
||||||
|
* lookup2.c, by Bob Jenkins, December 1996, Public Domain.
|
||||||
|
* hash(), hash2(), hash3, and mix() are externally useful functions.
|
||||||
|
* Routines to test the hash are included if SELF_TEST is defined.
|
||||||
|
* You can use this free for any purpose. It has no warranty.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
|
||||||
|
*
|
||||||
|
* I've modified Bob's hash to be useful in the Linux kernel, and
|
||||||
|
* any bugs present are surely my fault. -DaveM
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* NOTE: Arguments are modified. */
|
||||||
|
#define __jhash_mix(a, b, c) \
|
||||||
|
{ \
|
||||||
|
a -= b; a -= c; a ^= (c>>13); \
|
||||||
|
b -= c; b -= a; b ^= (a<<8); \
|
||||||
|
c -= a; c -= b; c ^= (b>>13); \
|
||||||
|
a -= b; a -= c; a ^= (c>>12); \
|
||||||
|
b -= c; b -= a; b ^= (a<<16); \
|
||||||
|
c -= a; c -= b; c ^= (b>>5); \
|
||||||
|
a -= b; a -= c; a ^= (c>>3); \
|
||||||
|
b -= c; b -= a; b ^= (a<<10); \
|
||||||
|
c -= a; c -= b; c ^= (b>>15); \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The golden ration: an arbitrary value */
|
||||||
|
#define JHASH_GOLDEN_RATIO 0x9e3779b9
|
||||||
|
|
||||||
|
/* The most generic version, hashes an arbitrary sequence
|
||||||
|
* of bytes. No alignment or length assumptions are made about
|
||||||
|
* the input key.
|
||||||
|
*/
|
||||||
|
static inline __u32 jhash(void *key, __u32 length, __u32 initval)
|
||||||
|
{
|
||||||
|
__u32 a, b, c, len;
|
||||||
|
__u8 *k = key;
|
||||||
|
|
||||||
|
len = length;
|
||||||
|
a = b = JHASH_GOLDEN_RATIO;
|
||||||
|
c = initval;
|
||||||
|
|
||||||
|
while (len >= 12) {
|
||||||
|
a += (k[0] +((__u32)k[1]<<8) +((__u32)k[2]<<16) +((__u32)k[3]<<24));
|
||||||
|
b += (k[4] +((__u32)k[5]<<8) +((__u32)k[6]<<16) +((__u32)k[7]<<24));
|
||||||
|
c += (k[8] +((__u32)k[9]<<8) +((__u32)k[10]<<16)+((__u32)k[11]<<24));
|
||||||
|
|
||||||
|
__jhash_mix(a,b,c);
|
||||||
|
|
||||||
|
k += 12;
|
||||||
|
len -= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
c += length;
|
||||||
|
switch (len) {
|
||||||
|
case 11: c += ((__u32)k[10]<<24);
|
||||||
|
case 10: c += ((__u32)k[9]<<16);
|
||||||
|
case 9 : c += ((__u32)k[8]<<8);
|
||||||
|
case 8 : b += ((__u32)k[7]<<24);
|
||||||
|
case 7 : b += ((__u32)k[6]<<16);
|
||||||
|
case 6 : b += ((__u32)k[5]<<8);
|
||||||
|
case 5 : b += k[4];
|
||||||
|
case 4 : a += ((__u32)k[3]<<24);
|
||||||
|
case 3 : a += ((__u32)k[2]<<16);
|
||||||
|
case 2 : a += ((__u32)k[1]<<8);
|
||||||
|
case 1 : a += k[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
__jhash_mix(a,b,c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A special optimized version that handles 1 or more of __u32s.
|
||||||
|
* The length parameter here is the number of __u32s in the key.
|
||||||
|
*/
|
||||||
|
static inline __u32 jhash2(__u32 *k, __u32 length, __u32 initval)
|
||||||
|
{
|
||||||
|
__u32 a, b, c, len;
|
||||||
|
|
||||||
|
a = b = JHASH_GOLDEN_RATIO;
|
||||||
|
c = initval;
|
||||||
|
len = length;
|
||||||
|
|
||||||
|
while (len >= 3) {
|
||||||
|
a += k[0];
|
||||||
|
b += k[1];
|
||||||
|
c += k[2];
|
||||||
|
__jhash_mix(a, b, c);
|
||||||
|
k += 3; len -= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
c += length * 4;
|
||||||
|
|
||||||
|
switch (len) {
|
||||||
|
case 2 : b += k[1];
|
||||||
|
case 1 : a += k[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
__jhash_mix(a,b,c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* A special ultra-optimized versions that knows they are hashing exactly
|
||||||
|
* 3, 2 or 1 word(s).
|
||||||
|
*
|
||||||
|
* NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
|
||||||
|
* done at the end is not done here.
|
||||||
|
*/
|
||||||
|
static inline __u32 jhash_3words(__u32 a, __u32 b, __u32 c, __u32 initval)
|
||||||
|
{
|
||||||
|
a += JHASH_GOLDEN_RATIO;
|
||||||
|
b += JHASH_GOLDEN_RATIO;
|
||||||
|
c += initval;
|
||||||
|
|
||||||
|
__jhash_mix(a, b, c);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u32 jhash_2words(__u32 a, __u32 b, __u32 initval)
|
||||||
|
{
|
||||||
|
return jhash_3words(a, b, 0, initval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u32 jhash_1word(__u32 a, __u32 initval)
|
||||||
|
{
|
||||||
|
return jhash_3words(a, 0, 0, initval);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _LINUX_IPSET_JHASH_H */
|
360
extensions/ipset/ip_set_macipmap.c
Normal file
360
extensions/ipset/ip_set_macipmap.c
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
|
* Patrick Schaaf <bof@bof.de>
|
||||||
|
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||||
|
* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module implementing an IP set type: the macipmap type */
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
|
#include "ip_set_malloc.h"
|
||||||
|
#include "ip_set_macipmap.h"
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip(struct ip_set *set, const void *data, size_t size, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *map = set->data;
|
||||||
|
struct ip_set_macip *table = map->members;
|
||||||
|
const struct ip_set_req_macipmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_macipmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_macipmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->ip < map->first_ip || req->ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = req->ip;
|
||||||
|
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
|
||||||
|
set->name, HIPQUAD(req->ip), HIPQUAD(*hash_ip));
|
||||||
|
if (test_bit(IPSET_MACIP_ISSET,
|
||||||
|
(void *) &table[req->ip - map->first_ip].flags)) {
|
||||||
|
return (memcmp(req->ethernet,
|
||||||
|
&table[req->ip - map->first_ip].ethernet,
|
||||||
|
ETH_ALEN) == 0);
|
||||||
|
} else {
|
||||||
|
return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *map = set->data;
|
||||||
|
struct ip_set_macip *table = map->members;
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
|
||||||
|
ip = ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr);
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
DP("set: %s, ip:%u.%u.%u.%u, %u.%u.%u.%u",
|
||||||
|
set->name, HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||||
|
if (test_bit(IPSET_MACIP_ISSET,
|
||||||
|
(void *) &table[ip - map->first_ip].flags)) {
|
||||||
|
/* Is mac pointer valid?
|
||||||
|
* If so, compare... */
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
return (skb_mac_header(skb) >= skb->head
|
||||||
|
&& (skb_mac_header(skb) + ETH_HLEN) <= skb->data
|
||||||
|
#else
|
||||||
|
return (skb->mac.raw >= skb->head
|
||||||
|
&& (skb->mac.raw + ETH_HLEN) <= skb->data
|
||||||
|
#endif
|
||||||
|
&& (memcmp(eth_hdr(skb)->h_source,
|
||||||
|
&table[ip - map->first_ip].ethernet,
|
||||||
|
ETH_ALEN) == 0));
|
||||||
|
} else {
|
||||||
|
return (map->flags & IPSET_MACIP_MATCHUNSET ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns 0 on success */
|
||||||
|
static inline int
|
||||||
|
__addip(struct ip_set *set,
|
||||||
|
ip_set_ip_t ip, const unsigned char *ethernet, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *map = set->data;
|
||||||
|
struct ip_set_macip *table = map->members;
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
if (test_and_set_bit(IPSET_MACIP_ISSET,
|
||||||
|
(void *) &table[ip - map->first_ip].flags))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||||
|
memcpy(&table[ip - map->first_ip].ethernet, ethernet, ETH_ALEN);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_macipmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_macipmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_macipmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __addip(set, req->ip, req->ethernet, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
|
||||||
|
ip = ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr);
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
if (!(skb_mac_header(skb) >= skb->head
|
||||||
|
&& (skb_mac_header(skb) + ETH_HLEN) <= skb->data))
|
||||||
|
#else
|
||||||
|
if (!(skb->mac.raw >= skb->head
|
||||||
|
&& (skb->mac.raw + ETH_HLEN) <= skb->data))
|
||||||
|
#endif
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return __addip(set, ip, eth_hdr(skb)->h_source, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *map = set->data;
|
||||||
|
struct ip_set_macip *table = map->members;
|
||||||
|
|
||||||
|
if (ip < map->first_ip || ip > map->last_ip)
|
||||||
|
return -ERANGE;
|
||||||
|
if (!test_and_clear_bit(IPSET_MACIP_ISSET,
|
||||||
|
(void *)&table[ip - map->first_ip].flags))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
*hash_ip = ip;
|
||||||
|
DP("%u.%u.%u.%u, %u.%u.%u.%u", HIPQUAD(ip), HIPQUAD(*hash_ip));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_macipmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_macipmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_macipmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __delip(set, req->ip, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __delip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline size_t members_size(ip_set_ip_t from, ip_set_ip_t to)
|
||||||
|
{
|
||||||
|
return (size_t)((to - from + 1) * sizeof(struct ip_set_macip));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
size_t newbytes;
|
||||||
|
const struct ip_set_req_macipmap_create *req = data;
|
||||||
|
struct ip_set_macipmap *map;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_macipmap_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_macipmap_create),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DP("from %u.%u.%u.%u to %u.%u.%u.%u",
|
||||||
|
HIPQUAD(req->from), HIPQUAD(req->to));
|
||||||
|
|
||||||
|
if (req->from > req->to) {
|
||||||
|
DP("bad ip range");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->to - req->from > MAX_RANGE) {
|
||||||
|
ip_set_printk("range too big (max %d addresses)",
|
||||||
|
MAX_RANGE+1);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kmalloc(sizeof(struct ip_set_macipmap), GFP_KERNEL);
|
||||||
|
if (!map) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_macipmap));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
map->flags = req->flags;
|
||||||
|
map->first_ip = req->from;
|
||||||
|
map->last_ip = req->to;
|
||||||
|
newbytes = members_size(map->first_ip, map->last_ip);
|
||||||
|
map->members = ip_set_malloc(newbytes);
|
||||||
|
DP("members: %u %p", newbytes, map->members);
|
||||||
|
if (!map->members) {
|
||||||
|
DP("out of memory for %d bytes", newbytes);
|
||||||
|
kfree(map);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memset(map->members, 0, newbytes);
|
||||||
|
|
||||||
|
set->data = map;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *map = set->data;
|
||||||
|
|
||||||
|
ip_set_free(map->members, members_size(map->first_ip, map->last_ip));
|
||||||
|
kfree(map);
|
||||||
|
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *map = set->data;
|
||||||
|
memset(map->members, 0, members_size(map->first_ip, map->last_ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_macipmap *map = set->data;
|
||||||
|
struct ip_set_req_macipmap_create *header = data;
|
||||||
|
|
||||||
|
DP("list_header %x %x %u", map->first_ip, map->last_ip,
|
||||||
|
map->flags);
|
||||||
|
|
||||||
|
header->from = map->first_ip;
|
||||||
|
header->to = map->last_ip;
|
||||||
|
header->flags = map->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
const struct ip_set_macipmap *map = set->data;
|
||||||
|
|
||||||
|
DP("%u", members_size(map->first_ip, map->last_ip));
|
||||||
|
return members_size(map->first_ip, map->last_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_macipmap *map = set->data;
|
||||||
|
|
||||||
|
int bytes = members_size(map->first_ip, map->last_ip);
|
||||||
|
|
||||||
|
DP("members: %u %p", bytes, map->members);
|
||||||
|
memcpy(data, map->members, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_macipmap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = &create,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.flush = &flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_macipmap),
|
||||||
|
.addip = &addip,
|
||||||
|
.addip_kernel = &addip_kernel,
|
||||||
|
.delip = &delip,
|
||||||
|
.delip_kernel = &delip_kernel,
|
||||||
|
.testip = &testip,
|
||||||
|
.testip_kernel = &testip_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_macipmap_create),
|
||||||
|
.list_header = &list_header,
|
||||||
|
.list_members_size = &list_members_size,
|
||||||
|
.list_members = &list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("macipmap type of IP sets");
|
||||||
|
|
||||||
|
static int __init ip_set_macipmap_init(void)
|
||||||
|
{
|
||||||
|
init_max_page_size();
|
||||||
|
return ip_set_register_set_type(&ip_set_macipmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_macipmap_fini(void)
|
||||||
|
{
|
||||||
|
/* FIXME: possible race with ip_set_create() */
|
||||||
|
ip_set_unregister_set_type(&ip_set_macipmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_macipmap_init);
|
||||||
|
module_exit(ip_set_macipmap_fini);
|
38
extensions/ipset/ip_set_macipmap.h
Normal file
38
extensions/ipset/ip_set_macipmap.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#ifndef __IP_SET_MACIPMAP_H
|
||||||
|
#define __IP_SET_MACIPMAP_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "macipmap"
|
||||||
|
#define MAX_RANGE 0x0000FFFF
|
||||||
|
|
||||||
|
/* general flags */
|
||||||
|
#define IPSET_MACIP_MATCHUNSET 1
|
||||||
|
|
||||||
|
/* per ip flags */
|
||||||
|
#define IPSET_MACIP_ISSET 1
|
||||||
|
|
||||||
|
struct ip_set_macipmap {
|
||||||
|
void *members; /* the macipmap proper */
|
||||||
|
ip_set_ip_t first_ip; /* host byte order, included in range */
|
||||||
|
ip_set_ip_t last_ip; /* host byte order, included in range */
|
||||||
|
u_int32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_macipmap_create {
|
||||||
|
ip_set_ip_t from;
|
||||||
|
ip_set_ip_t to;
|
||||||
|
u_int32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_macipmap {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
unsigned char ethernet[ETH_ALEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_macip {
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned char ethernet[ETH_ALEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __IP_SET_MACIPMAP_H */
|
143
extensions/ipset/ip_set_malloc.h
Normal file
143
extensions/ipset/ip_set_malloc.h
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
#ifndef _IP_SET_MALLOC_H
|
||||||
|
#define _IP_SET_MALLOC_H
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
static size_t max_malloc_size = 0, max_page_size = 0;
|
||||||
|
|
||||||
|
static inline unsigned int init_max_page_size(void)
|
||||||
|
{
|
||||||
|
size_t page_size = 0;
|
||||||
|
|
||||||
|
#define CACHE(x) if (max_page_size == 0 || x < max_page_size) \
|
||||||
|
page_size = x;
|
||||||
|
#include <linux/kmalloc_sizes.h>
|
||||||
|
#undef CACHE
|
||||||
|
if (page_size) {
|
||||||
|
if (max_malloc_size == 0)
|
||||||
|
max_malloc_size = page_size;
|
||||||
|
|
||||||
|
max_page_size = page_size;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct harray {
|
||||||
|
size_t max_elements;
|
||||||
|
void *arrays[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
__harray_malloc(size_t hashsize, size_t typesize, int flags)
|
||||||
|
{
|
||||||
|
struct harray *harray;
|
||||||
|
size_t max_elements, size, i, j;
|
||||||
|
|
||||||
|
BUG_ON(max_page_size == 0);
|
||||||
|
|
||||||
|
if (typesize > max_page_size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
max_elements = max_page_size/typesize;
|
||||||
|
size = hashsize/max_elements;
|
||||||
|
if (hashsize % max_elements)
|
||||||
|
size++;
|
||||||
|
|
||||||
|
/* Last pointer signals end of arrays */
|
||||||
|
harray = kmalloc(sizeof(struct harray) + (size + 1) * sizeof(void *),
|
||||||
|
flags);
|
||||||
|
|
||||||
|
if (!harray)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < size - 1; i++) {
|
||||||
|
harray->arrays[i] = kmalloc(max_elements * typesize, flags);
|
||||||
|
if (!harray->arrays[i])
|
||||||
|
goto undo;
|
||||||
|
memset(harray->arrays[i], 0, max_elements * typesize);
|
||||||
|
}
|
||||||
|
harray->arrays[i] = kmalloc((hashsize - i * max_elements) * typesize,
|
||||||
|
flags);
|
||||||
|
if (!harray->arrays[i])
|
||||||
|
goto undo;
|
||||||
|
memset(harray->arrays[i], 0, (hashsize - i * max_elements) * typesize);
|
||||||
|
|
||||||
|
harray->max_elements = max_elements;
|
||||||
|
harray->arrays[size] = NULL;
|
||||||
|
|
||||||
|
return (void *)harray;
|
||||||
|
|
||||||
|
undo:
|
||||||
|
for (j = 0; j < i; j++) {
|
||||||
|
kfree(harray->arrays[j]);
|
||||||
|
}
|
||||||
|
kfree(harray);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
harray_malloc(size_t hashsize, size_t typesize, int flags)
|
||||||
|
{
|
||||||
|
void *harray;
|
||||||
|
|
||||||
|
do {
|
||||||
|
harray = __harray_malloc(hashsize, typesize, flags|__GFP_NOWARN);
|
||||||
|
} while (harray == NULL && init_max_page_size());
|
||||||
|
|
||||||
|
return harray;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void harray_free(void *h)
|
||||||
|
{
|
||||||
|
struct harray *harray = (struct harray *) h;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; harray->arrays[i] != NULL; i++)
|
||||||
|
kfree(harray->arrays[i]);
|
||||||
|
kfree(harray);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void harray_flush(void *h, size_t hashsize, size_t typesize)
|
||||||
|
{
|
||||||
|
struct harray *harray = (struct harray *) h;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; harray->arrays[i+1] != NULL; i++)
|
||||||
|
memset(harray->arrays[i], 0, harray->max_elements * typesize);
|
||||||
|
memset(harray->arrays[i], 0,
|
||||||
|
(hashsize - i * harray->max_elements) * typesize);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HARRAY_ELEM(h, type, which) \
|
||||||
|
({ \
|
||||||
|
struct harray *__h = (struct harray *)(h); \
|
||||||
|
((type)((__h)->arrays[(which)/(__h)->max_elements]) \
|
||||||
|
+ (which)%(__h)->max_elements); \
|
||||||
|
})
|
||||||
|
|
||||||
|
/* General memory allocation and deallocation */
|
||||||
|
static inline void * ip_set_malloc(size_t bytes)
|
||||||
|
{
|
||||||
|
BUG_ON(max_malloc_size == 0);
|
||||||
|
|
||||||
|
if (bytes > max_malloc_size)
|
||||||
|
return vmalloc(bytes);
|
||||||
|
else
|
||||||
|
return kmalloc(bytes, GFP_KERNEL | __GFP_NOWARN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ip_set_free(void * data, size_t bytes)
|
||||||
|
{
|
||||||
|
BUG_ON(max_malloc_size == 0);
|
||||||
|
|
||||||
|
if (bytes > max_malloc_size)
|
||||||
|
vfree(data);
|
||||||
|
else
|
||||||
|
kfree(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
#endif /*_IP_SET_MALLOC_H*/
|
490
extensions/ipset/ip_set_nethash.c
Normal file
490
extensions/ipset/ip_set_nethash.c
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module implementing a cidr nethash set */
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/jhash.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
|
||||||
|
#include <net/ip.h>
|
||||||
|
|
||||||
|
#include "ip_set_malloc.h"
|
||||||
|
#include "ip_set_nethash.h"
|
||||||
|
|
||||||
|
static int limit = MAX_RANGE;
|
||||||
|
|
||||||
|
static inline __u32
|
||||||
|
jhash_ip(const struct ip_set_nethash *map, uint16_t i, ip_set_ip_t ip)
|
||||||
|
{
|
||||||
|
return jhash_1word(ip, *(((uint32_t *) map->initval) + i));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u32
|
||||||
|
hash_id_cidr(struct ip_set_nethash *map,
|
||||||
|
ip_set_ip_t ip,
|
||||||
|
unsigned char cidr,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
__u32 id;
|
||||||
|
u_int16_t i;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
|
||||||
|
*hash_ip = pack(ip, cidr);
|
||||||
|
|
||||||
|
for (i = 0; i < map->probes; i++) {
|
||||||
|
id = jhash_ip(map, i, *hash_ip) % map->hashsize;
|
||||||
|
DP("hash key: %u", id);
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||||
|
if (*elem == *hash_ip)
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline __u32
|
||||||
|
hash_id(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
__u32 id = UINT_MAX;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 30 && map->cidr[i]; i++) {
|
||||||
|
id = hash_id_cidr(map, ip, map->cidr[i], hash_ip);
|
||||||
|
if (id != UINT_MAX)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testip_cidr(struct ip_set *set, ip_set_ip_t ip, unsigned char cidr,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
|
||||||
|
return (ip && hash_id_cidr(map, ip, cidr, hash_ip) != UINT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testip(struct ip_set *set, ip_set_ip_t ip, ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
return (ip && hash_id(set, ip, hash_ip) != UINT_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_nethash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_nethash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_nethash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return (req->cidr == 32 ? __testip(set, req->ip, hash_ip)
|
||||||
|
: __testip_cidr(set, req->ip, req->cidr, hash_ip));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
return __testip(set,
|
||||||
|
ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr),
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr),
|
||||||
|
#endif
|
||||||
|
hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip_base(struct ip_set_nethash *map, ip_set_ip_t ip)
|
||||||
|
{
|
||||||
|
__u32 probe;
|
||||||
|
u_int16_t i;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
|
||||||
|
for (i = 0; i < map->probes; i++) {
|
||||||
|
probe = jhash_ip(map, i, ip) % map->hashsize;
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, probe);
|
||||||
|
if (*elem == ip)
|
||||||
|
return -EEXIST;
|
||||||
|
if (!*elem) {
|
||||||
|
*elem = ip;
|
||||||
|
map->elements++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Trigger rehashing */
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
if (!ip || map->elements >= limit)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_ip = pack(ip, cidr);
|
||||||
|
DP("%u.%u.%u.%u/%u, %u.%u.%u.%u", HIPQUAD(ip), cidr, HIPQUAD(*hash_ip));
|
||||||
|
|
||||||
|
return __addip_base(map, *hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_cidr_sizes(struct ip_set_nethash *map, unsigned char cidr)
|
||||||
|
{
|
||||||
|
unsigned char next;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 30 && map->cidr[i]; i++) {
|
||||||
|
if (map->cidr[i] == cidr) {
|
||||||
|
return;
|
||||||
|
} else if (map->cidr[i] < cidr) {
|
||||||
|
next = map->cidr[i];
|
||||||
|
map->cidr[i] = cidr;
|
||||||
|
cidr = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < 30)
|
||||||
|
map->cidr[i] = cidr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_nethash *req = data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_nethash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_nethash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
ret = __addip(set->data, req->ip, req->cidr, hash_ip);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
update_cidr_sizes(set->data, req->cidr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
int ret = -ERANGE;
|
||||||
|
ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr);
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (map->cidr[0])
|
||||||
|
ret = __addip(map, ip, map->cidr[0], hash_ip);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int retry(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
ip_set_ip_t *elem;
|
||||||
|
void *members;
|
||||||
|
u_int32_t i, hashsize = map->hashsize;
|
||||||
|
int res;
|
||||||
|
struct ip_set_nethash *tmp;
|
||||||
|
|
||||||
|
if (map->resize == 0)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
again:
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
/* Calculate new parameters */
|
||||||
|
hashsize += (hashsize * map->resize)/100;
|
||||||
|
if (hashsize == map->hashsize)
|
||||||
|
hashsize++;
|
||||||
|
|
||||||
|
ip_set_printk("rehashing of set %s triggered: "
|
||||||
|
"hashsize grows from %u to %u",
|
||||||
|
set->name, map->hashsize, hashsize);
|
||||||
|
|
||||||
|
tmp = kmalloc(sizeof(struct ip_set_nethash)
|
||||||
|
+ map->probes * sizeof(uint32_t), GFP_ATOMIC);
|
||||||
|
if (!tmp) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_nethash)
|
||||||
|
+ map->probes * sizeof(uint32_t));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
tmp->members = harray_malloc(hashsize, sizeof(ip_set_ip_t), GFP_ATOMIC);
|
||||||
|
if (!tmp->members) {
|
||||||
|
DP("out of memory for %d bytes", hashsize * sizeof(ip_set_ip_t));
|
||||||
|
kfree(tmp);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
tmp->hashsize = hashsize;
|
||||||
|
tmp->elements = 0;
|
||||||
|
tmp->probes = map->probes;
|
||||||
|
tmp->resize = map->resize;
|
||||||
|
memcpy(tmp->initval, map->initval, map->probes * sizeof(uint32_t));
|
||||||
|
memcpy(tmp->cidr, map->cidr, 30 * sizeof(unsigned char));
|
||||||
|
|
||||||
|
write_lock_bh(&set->lock);
|
||||||
|
map = set->data; /* Play safe */
|
||||||
|
for (i = 0; i < map->hashsize && res == 0; i++) {
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
|
||||||
|
if (*elem)
|
||||||
|
res = __addip_base(tmp, *elem);
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
/* Failure, try again */
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
harray_free(tmp->members);
|
||||||
|
kfree(tmp);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success at resizing! */
|
||||||
|
members = map->members;
|
||||||
|
|
||||||
|
map->hashsize = tmp->hashsize;
|
||||||
|
map->members = tmp->members;
|
||||||
|
write_unlock_bh(&set->lock);
|
||||||
|
|
||||||
|
harray_free(members);
|
||||||
|
kfree(tmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delip(struct ip_set_nethash *map, ip_set_ip_t ip, unsigned char cidr,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
ip_set_ip_t id, *elem;
|
||||||
|
|
||||||
|
if (!ip)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
id = hash_id_cidr(map, ip, cidr, hash_ip);
|
||||||
|
if (id == UINT_MAX)
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, id);
|
||||||
|
*elem = 0;
|
||||||
|
map->elements--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_ip)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_nethash *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_nethash)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_nethash),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
/* TODO: no garbage collection in map->cidr */
|
||||||
|
return __delip(set->data, req->ip, req->cidr, hash_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delip_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_ip,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
int ret = -ERANGE;
|
||||||
|
ip_set_ip_t ip = ntohl(flags[index] & IPSET_SRC
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
? ip_hdr(skb)->saddr
|
||||||
|
: ip_hdr(skb)->daddr);
|
||||||
|
#else
|
||||||
|
? skb->nh.iph->saddr
|
||||||
|
: skb->nh.iph->daddr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (map->cidr[0])
|
||||||
|
ret = __delip(map, ip, map->cidr[0], hash_ip);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_nethash_create *req = data;
|
||||||
|
struct ip_set_nethash *map;
|
||||||
|
uint16_t i;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_nethash_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_nethash_create),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->hashsize < 1) {
|
||||||
|
ip_set_printk("hashsize too small");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
if (req->probes < 1) {
|
||||||
|
ip_set_printk("probes too small");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kmalloc(sizeof(struct ip_set_nethash)
|
||||||
|
+ req->probes * sizeof(uint32_t), GFP_KERNEL);
|
||||||
|
if (!map) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_nethash)
|
||||||
|
+ req->probes * sizeof(uint32_t));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
for (i = 0; i < req->probes; i++)
|
||||||
|
get_random_bytes(((uint32_t *) map->initval)+i, 4);
|
||||||
|
map->elements = 0;
|
||||||
|
map->hashsize = req->hashsize;
|
||||||
|
map->probes = req->probes;
|
||||||
|
map->resize = req->resize;
|
||||||
|
memset(map->cidr, 0, 30 * sizeof(unsigned char));
|
||||||
|
map->members = harray_malloc(map->hashsize, sizeof(ip_set_ip_t), GFP_KERNEL);
|
||||||
|
if (!map->members) {
|
||||||
|
DP("out of memory for %d bytes", map->hashsize * sizeof(ip_set_ip_t));
|
||||||
|
kfree(map);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
set->data = map;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
|
||||||
|
harray_free(map->members);
|
||||||
|
kfree(map);
|
||||||
|
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
harray_flush(map->members, map->hashsize, sizeof(ip_set_ip_t));
|
||||||
|
memset(map->cidr, 0, 30 * sizeof(unsigned char));
|
||||||
|
map->elements = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_nethash *map = set->data;
|
||||||
|
struct ip_set_req_nethash_create *header = data;
|
||||||
|
|
||||||
|
header->hashsize = map->hashsize;
|
||||||
|
header->probes = map->probes;
|
||||||
|
header->resize = map->resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *map = set->data;
|
||||||
|
|
||||||
|
return (map->hashsize * sizeof(ip_set_ip_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_nethash *map = set->data;
|
||||||
|
ip_set_ip_t i, *elem;
|
||||||
|
|
||||||
|
for (i = 0; i < map->hashsize; i++) {
|
||||||
|
elem = HARRAY_ELEM(map->members, ip_set_ip_t *, i);
|
||||||
|
((ip_set_ip_t *)data)[i] = *elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_nethash = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_IP | IPSET_DATA_SINGLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = &create,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.flush = &flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_nethash),
|
||||||
|
.addip = &addip,
|
||||||
|
.addip_kernel = &addip_kernel,
|
||||||
|
.retry = &retry,
|
||||||
|
.delip = &delip,
|
||||||
|
.delip_kernel = &delip_kernel,
|
||||||
|
.testip = &testip,
|
||||||
|
.testip_kernel = &testip_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_nethash_create),
|
||||||
|
.list_header = &list_header,
|
||||||
|
.list_members_size = &list_members_size,
|
||||||
|
.list_members = &list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("nethash type of IP sets");
|
||||||
|
module_param(limit, int, 0600);
|
||||||
|
MODULE_PARM_DESC(limit, "maximal number of elements stored in the sets");
|
||||||
|
|
||||||
|
static int __init ip_set_nethash_init(void)
|
||||||
|
{
|
||||||
|
init_max_page_size();
|
||||||
|
return ip_set_register_set_type(&ip_set_nethash);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_nethash_fini(void)
|
||||||
|
{
|
||||||
|
/* FIXME: possible race with ip_set_create() */
|
||||||
|
ip_set_unregister_set_type(&ip_set_nethash);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_nethash_init);
|
||||||
|
module_exit(ip_set_nethash_fini);
|
55
extensions/ipset/ip_set_nethash.h
Normal file
55
extensions/ipset/ip_set_nethash.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
#ifndef __IP_SET_NETHASH_H
|
||||||
|
#define __IP_SET_NETHASH_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "nethash"
|
||||||
|
#define MAX_RANGE 0x0000FFFF
|
||||||
|
|
||||||
|
struct ip_set_nethash {
|
||||||
|
ip_set_ip_t *members; /* the nethash proper */
|
||||||
|
uint32_t elements; /* number of elements */
|
||||||
|
uint32_t hashsize; /* hash size */
|
||||||
|
uint16_t probes; /* max number of probes */
|
||||||
|
uint16_t resize; /* resize factor in percent */
|
||||||
|
unsigned char cidr[30]; /* CIDR sizes */
|
||||||
|
void *initval[0]; /* initvals for jhash_1word */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_nethash_create {
|
||||||
|
uint32_t hashsize;
|
||||||
|
uint16_t probes;
|
||||||
|
uint16_t resize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_nethash {
|
||||||
|
ip_set_ip_t ip;
|
||||||
|
unsigned char cidr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
|
||||||
|
|
||||||
|
static inline ip_set_ip_t
|
||||||
|
pack(ip_set_ip_t ip, unsigned char cidr)
|
||||||
|
{
|
||||||
|
ip_set_ip_t addr, *paddr = &addr;
|
||||||
|
unsigned char n, t, *a;
|
||||||
|
|
||||||
|
addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
|
||||||
|
#endif
|
||||||
|
n = cidr / 8;
|
||||||
|
t = cidr % 8;
|
||||||
|
a = &((unsigned char *)paddr)[n];
|
||||||
|
*a = *a /(1 << (8 - t)) + shifts[t];
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
DP("n: %u, t: %u, a: %u", n, t, *a);
|
||||||
|
DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
|
||||||
|
HIPQUAD(ip), cidr, NIPQUAD(addr));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ntohl(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __IP_SET_NETHASH_H */
|
341
extensions/ipset/ip_set_portmap.c
Normal file
341
extensions/ipset/ip_set_portmap.c
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
/* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module implementing a port set type as a bitmap */
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/tcp.h>
|
||||||
|
#include <linux/udp.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
#include <asm/bitops.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#include <net/ip.h>
|
||||||
|
|
||||||
|
#include "ip_set_portmap.h"
|
||||||
|
|
||||||
|
/* We must handle non-linear skbs */
|
||||||
|
static inline ip_set_ip_t
|
||||||
|
get_port(const struct sk_buff *skb, u_int32_t flags)
|
||||||
|
{
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
struct iphdr *iph = ip_hdr(skb);
|
||||||
|
#else
|
||||||
|
struct iphdr *iph = skb->nh.iph;
|
||||||
|
#endif
|
||||||
|
u_int16_t offset = ntohs(iph->frag_off) & IP_OFFSET;
|
||||||
|
switch (iph->protocol) {
|
||||||
|
case IPPROTO_TCP: {
|
||||||
|
struct tcphdr tcph;
|
||||||
|
|
||||||
|
/* See comments at tcp_match in ip_tables.c */
|
||||||
|
if (offset)
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &tcph, sizeof(tcph)) < 0)
|
||||||
|
#else
|
||||||
|
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
|
||||||
|
#endif
|
||||||
|
/* No choice either */
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
return ntohs(flags & IPSET_SRC ?
|
||||||
|
tcph.source : tcph.dest);
|
||||||
|
}
|
||||||
|
case IPPROTO_UDP: {
|
||||||
|
struct udphdr udph;
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
|
||||||
|
if (skb_copy_bits(skb, ip_hdr(skb)->ihl*4, &udph, sizeof(udph)) < 0)
|
||||||
|
#else
|
||||||
|
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0)
|
||||||
|
#endif
|
||||||
|
/* No choice either */
|
||||||
|
return INVALID_PORT;
|
||||||
|
|
||||||
|
return ntohs(flags & IPSET_SRC ?
|
||||||
|
udph.source : udph.dest);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return INVALID_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__testport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *map = set->data;
|
||||||
|
|
||||||
|
if (port < map->first_port || port > map->last_port)
|
||||||
|
return -ERANGE;
|
||||||
|
|
||||||
|
*hash_port = port;
|
||||||
|
DP("set: %s, port:%u, %u", set->name, port, *hash_port);
|
||||||
|
return !!test_bit(port - map->first_port, map->members);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testport(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_port)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_portmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_portmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_portmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __testport(set, req->port, hash_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
testport_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_port,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
ip_set_ip_t port = get_port(skb, flags[index]);
|
||||||
|
|
||||||
|
DP("flag %s port %u", flags[index] & IPSET_SRC ? "SRC" : "DST", port);
|
||||||
|
if (port == INVALID_PORT)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
res = __testport(set, port, hash_port);
|
||||||
|
|
||||||
|
return (res < 0 ? 0 : res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__addport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *map = set->data;
|
||||||
|
|
||||||
|
if (port < map->first_port || port > map->last_port)
|
||||||
|
return -ERANGE;
|
||||||
|
if (test_and_set_bit(port - map->first_port, map->members))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
*hash_port = port;
|
||||||
|
DP("port %u", port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addport(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_port)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_portmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_portmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_portmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __addport(set, req->port, hash_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addport_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_port,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
ip_set_ip_t port = get_port(skb, flags[index]);
|
||||||
|
|
||||||
|
if (port == INVALID_PORT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return __addport(set, port, hash_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
__delport(struct ip_set *set, ip_set_ip_t port, ip_set_ip_t *hash_port)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *map = set->data;
|
||||||
|
|
||||||
|
if (port < map->first_port || port > map->last_port)
|
||||||
|
return -ERANGE;
|
||||||
|
if (!test_and_clear_bit(port - map->first_port, map->members))
|
||||||
|
return -EEXIST;
|
||||||
|
|
||||||
|
*hash_port = port;
|
||||||
|
DP("port %u", port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delport(struct ip_set *set, const void *data, size_t size,
|
||||||
|
ip_set_ip_t *hash_port)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_portmap *req = data;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_portmap)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_portmap),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return __delport(set, req->port, hash_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
delport_kernel(struct ip_set *set,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
ip_set_ip_t *hash_port,
|
||||||
|
const u_int32_t *flags,
|
||||||
|
unsigned char index)
|
||||||
|
{
|
||||||
|
ip_set_ip_t port = get_port(skb, flags[index]);
|
||||||
|
|
||||||
|
if (port == INVALID_PORT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return __delport(set, port, hash_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int create(struct ip_set *set, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
int newbytes;
|
||||||
|
const struct ip_set_req_portmap_create *req = data;
|
||||||
|
struct ip_set_portmap *map;
|
||||||
|
|
||||||
|
if (size != sizeof(struct ip_set_req_portmap_create)) {
|
||||||
|
ip_set_printk("data length wrong (want %zu, have %zu)",
|
||||||
|
sizeof(struct ip_set_req_portmap_create),
|
||||||
|
size);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DP("from %u to %u", req->from, req->to);
|
||||||
|
|
||||||
|
if (req->from > req->to) {
|
||||||
|
DP("bad port range");
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req->to - req->from > MAX_RANGE) {
|
||||||
|
ip_set_printk("range too big (max %d ports)",
|
||||||
|
MAX_RANGE+1);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
map = kmalloc(sizeof(struct ip_set_portmap), GFP_KERNEL);
|
||||||
|
if (!map) {
|
||||||
|
DP("out of memory for %d bytes",
|
||||||
|
sizeof(struct ip_set_portmap));
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
map->first_port = req->from;
|
||||||
|
map->last_port = req->to;
|
||||||
|
newbytes = bitmap_bytes(req->from, req->to);
|
||||||
|
map->members = kmalloc(newbytes, GFP_KERNEL);
|
||||||
|
if (!map->members) {
|
||||||
|
DP("out of memory for %d bytes", newbytes);
|
||||||
|
kfree(map);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
memset(map->members, 0, newbytes);
|
||||||
|
|
||||||
|
set->data = map;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *map = set->data;
|
||||||
|
|
||||||
|
kfree(map->members);
|
||||||
|
kfree(map);
|
||||||
|
|
||||||
|
set->data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void flush(struct ip_set *set)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *map = set->data;
|
||||||
|
memset(map->members, 0, bitmap_bytes(map->first_port, map->last_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_header(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_portmap *map = set->data;
|
||||||
|
struct ip_set_req_portmap_create *header = data;
|
||||||
|
|
||||||
|
DP("list_header %u %u", map->first_port, map->last_port);
|
||||||
|
|
||||||
|
header->from = map->first_port;
|
||||||
|
header->to = map->last_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int list_members_size(const struct ip_set *set)
|
||||||
|
{
|
||||||
|
const struct ip_set_portmap *map = set->data;
|
||||||
|
|
||||||
|
return bitmap_bytes(map->first_port, map->last_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void list_members(const struct ip_set *set, void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_portmap *map = set->data;
|
||||||
|
int bytes = bitmap_bytes(map->first_port, map->last_port);
|
||||||
|
|
||||||
|
memcpy(data, map->members, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ip_set_type ip_set_portmap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.features = IPSET_TYPE_PORT | IPSET_DATA_SINGLE,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
.create = &create,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.flush = &flush,
|
||||||
|
.reqsize = sizeof(struct ip_set_req_portmap),
|
||||||
|
.addip = &addport,
|
||||||
|
.addip_kernel = &addport_kernel,
|
||||||
|
.delip = &delport,
|
||||||
|
.delip_kernel = &delport_kernel,
|
||||||
|
.testip = &testport,
|
||||||
|
.testip_kernel = &testport_kernel,
|
||||||
|
.header_size = sizeof(struct ip_set_req_portmap_create),
|
||||||
|
.list_header = &list_header,
|
||||||
|
.list_members_size = &list_members_size,
|
||||||
|
.list_members = &list_members,
|
||||||
|
.me = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("portmap type of IP sets");
|
||||||
|
|
||||||
|
static int __init ip_set_portmap_init(void)
|
||||||
|
{
|
||||||
|
return ip_set_register_set_type(&ip_set_portmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ip_set_portmap_fini(void)
|
||||||
|
{
|
||||||
|
/* FIXME: possible race with ip_set_create() */
|
||||||
|
ip_set_unregister_set_type(&ip_set_portmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ip_set_portmap_init);
|
||||||
|
module_exit(ip_set_portmap_fini);
|
25
extensions/ipset/ip_set_portmap.h
Normal file
25
extensions/ipset/ip_set_portmap.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef __IP_SET_PORTMAP_H
|
||||||
|
#define __IP_SET_PORTMAP_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define SETTYPE_NAME "portmap"
|
||||||
|
#define MAX_RANGE 0x0000FFFF
|
||||||
|
#define INVALID_PORT (MAX_RANGE + 1)
|
||||||
|
|
||||||
|
struct ip_set_portmap {
|
||||||
|
void *members; /* the portmap proper */
|
||||||
|
ip_set_ip_t first_port; /* host byte order, included in range */
|
||||||
|
ip_set_ip_t last_port; /* host byte order, included in range */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_portmap_create {
|
||||||
|
ip_set_ip_t from;
|
||||||
|
ip_set_ip_t to;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ip_set_req_portmap {
|
||||||
|
ip_set_ip_t port;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __IP_SET_PORTMAP_H */
|
470
extensions/ipset/ipset.8
Normal file
470
extensions/ipset/ipset.8
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
.TH IPSET 8 "Feb 05, 2004" "" ""
|
||||||
|
.\"
|
||||||
|
.\" Man page written by Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
.\"
|
||||||
|
.\" This program is free software; you can redistribute it and/or modify
|
||||||
|
.\" it under the terms of the GNU General Public License as published by
|
||||||
|
.\" the Free Software Foundation; either version 2 of the License, or
|
||||||
|
.\" (at your option) any later version.
|
||||||
|
.\"
|
||||||
|
.\" This program is distributed in the hope that it will be useful,
|
||||||
|
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
.\" GNU General Public License for more details.
|
||||||
|
.\"
|
||||||
|
.\" You should have received a copy of the GNU General Public License
|
||||||
|
.\" along with this program; if not, write to the Free Software
|
||||||
|
.\" Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.SH NAME
|
||||||
|
ipset \- administration tool for IP sets
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.BR "ipset -N " "set type-specification [options]"
|
||||||
|
.br
|
||||||
|
.BR "ipset -[XFLSHh] " "[set] [options]"
|
||||||
|
.br
|
||||||
|
.BR "ipset -[EW] " "from-set to-set"
|
||||||
|
.br
|
||||||
|
.BR "ipset -[ADU] " "set entry"
|
||||||
|
.br
|
||||||
|
.BR "ipset -B " "set entry -b binding"
|
||||||
|
.br
|
||||||
|
.BR "ipset -T " "set entry [-b binding]"
|
||||||
|
.br
|
||||||
|
.BR "ipset -R "
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B ipset
|
||||||
|
is used to set up, maintain and inspect so called IP sets in the Linux
|
||||||
|
kernel. Depending on the type, an IP set may store IP addresses, (TCP/UDP)
|
||||||
|
port numbers or additional informations besides IP addresses: the word IP
|
||||||
|
means a general term here. See the set type definitions below.
|
||||||
|
.P
|
||||||
|
Any entry in a set can be bound to another set, which forms a relationship
|
||||||
|
between a set element and the set it is bound to. In order to define a
|
||||||
|
binding it is not required that the entry be already added to the set.
|
||||||
|
The sets may have a default binding, which is valid for every set element
|
||||||
|
for which there is no binding defined at all.
|
||||||
|
.P
|
||||||
|
IP set bindings pointing to sets and iptables matches and targets
|
||||||
|
referring to sets creates references, which protects the given sets in
|
||||||
|
the kernel. A set cannot be removed (destroyed) while there is a single
|
||||||
|
reference pointing to it.
|
||||||
|
.SH OPTIONS
|
||||||
|
The options that are recognized by
|
||||||
|
.B ipset
|
||||||
|
can be divided into several different groups.
|
||||||
|
.SS COMMANDS
|
||||||
|
These options specify the specific action to perform. Only one of them
|
||||||
|
can be specified on the command line unless otherwise specified
|
||||||
|
below. For all the long versions of the command and option names, you
|
||||||
|
need to use only enough letters to ensure that
|
||||||
|
.B ipset
|
||||||
|
can differentiate it from all other options.
|
||||||
|
.TP
|
||||||
|
.BI "-N, --create " "\fIsetname\fP type type-specific-options"
|
||||||
|
Create a set identified with setname and specified type.
|
||||||
|
Type-specific options must be supplied.
|
||||||
|
.TP
|
||||||
|
.BI "-X, --destroy " "[\fIsetname\fP]"
|
||||||
|
Destroy the specified set, or all sets if none or the keyword
|
||||||
|
.B
|
||||||
|
:all:
|
||||||
|
is specified.
|
||||||
|
Before destroying the set, all bindings belonging to the
|
||||||
|
set elements and the default binding of the set are removed.
|
||||||
|
|
||||||
|
If the set has got references, nothing is done.
|
||||||
|
.TP
|
||||||
|
.BI "-F, --flush " "[\fIsetname\fP]"
|
||||||
|
Delete all entries from the specified set, or flush
|
||||||
|
all sets if none or the keyword
|
||||||
|
.B
|
||||||
|
:all:
|
||||||
|
is given. Bindings are not affected by the flush operation.
|
||||||
|
.TP
|
||||||
|
.BI "-E, --rename " "\fIfrom-setname\fP \fIto-setname\fP"
|
||||||
|
Rename a set. Set identified by to-setname must not exist.
|
||||||
|
.TP
|
||||||
|
.BI "-W, --swap " "\fIfrom-setname\fP \fIto-setname\fP"
|
||||||
|
Swap two sets as they referenced in the Linux kernel.
|
||||||
|
.B
|
||||||
|
iptables
|
||||||
|
rules or
|
||||||
|
.B
|
||||||
|
ipset
|
||||||
|
bindings pointing to the content of from-setname will point to
|
||||||
|
the content of to-setname and vice versa. Both sets must exist.
|
||||||
|
.TP
|
||||||
|
.BI "-L, --list " "[\fIsetname\fP]"
|
||||||
|
List the entries and bindings for the specified set, or for
|
||||||
|
all sets if none or the keyword
|
||||||
|
.B
|
||||||
|
:all:
|
||||||
|
is given. The
|
||||||
|
.B "-n, --numeric"
|
||||||
|
option can be used to suppress name lookups and generate numeric
|
||||||
|
output. When the
|
||||||
|
.B "-s, --sorted"
|
||||||
|
option is given, the entries are listed sorted (if the given set
|
||||||
|
type supports the operation).
|
||||||
|
.TP
|
||||||
|
.BI "-S, --save " "[\fIsetname\fP]"
|
||||||
|
Save the given set, or all sets if none or the keyword
|
||||||
|
.B
|
||||||
|
:all:
|
||||||
|
is specified to stdout in a format that --restore can read.
|
||||||
|
.TP
|
||||||
|
.BI "-R, --restore "
|
||||||
|
Restore a saved session generated by --save. The saved session
|
||||||
|
can be fed from stdin.
|
||||||
|
|
||||||
|
When generating a session file please note that the supported commands
|
||||||
|
(create set, add element, bind) must appear in a strict order: first create
|
||||||
|
the set, then add all elements. Then create the next set, add all its elements
|
||||||
|
and so on. Finally you can list all binding commands. Also, it is a restore
|
||||||
|
operation, so the sets being restored must not exist.
|
||||||
|
.TP
|
||||||
|
.BI "-A, --add " "\fIsetname\fP \fIIP\fP"
|
||||||
|
Add an IP to a set.
|
||||||
|
.TP
|
||||||
|
.BI "-D, --del " "\fIsetname\fP \fIIP\fP"
|
||||||
|
Delete an IP from a set.
|
||||||
|
.TP
|
||||||
|
.BI "-T, --test " "\fIsetname\fP \fIIP
|
||||||
|
Test wether an IP is in a set or not. Exit status number is zero
|
||||||
|
if the tested IP is in the set and nonzero if it is missing from
|
||||||
|
the set.
|
||||||
|
.TP
|
||||||
|
.BI "-T, --test " "\fIsetname\fP \fIIP\fP \fI--binding\fP \fIto-setname\fP"
|
||||||
|
Test wether the IP belonging to the set points to the specified binding.
|
||||||
|
Exit status number is zero if the binding points to the specified set,
|
||||||
|
otherwise it is nonzero. The keyword
|
||||||
|
.B
|
||||||
|
:default:
|
||||||
|
can be used to test the default binding of the set.
|
||||||
|
.TP
|
||||||
|
.BI "-B, --bind " "\fIsetname\fP \fIIP\fP \fI--binding\fP \fIto-setname\fP"
|
||||||
|
Bind the IP in setname to to-setname.
|
||||||
|
.TP
|
||||||
|
.BI "-U, --unbind " "\fIsetname\fP \fIIP\fP"
|
||||||
|
Delete the binding belonging to IP in set setname.
|
||||||
|
.TP
|
||||||
|
.BI "-H, --help " "[settype]"
|
||||||
|
Print help and settype specific help if settype specified.
|
||||||
|
.P
|
||||||
|
At the
|
||||||
|
.B
|
||||||
|
-B, -U
|
||||||
|
and
|
||||||
|
.B
|
||||||
|
-T
|
||||||
|
commands you can use the token
|
||||||
|
.B
|
||||||
|
:default:
|
||||||
|
to bind, unbind or test the default binding of a set instead
|
||||||
|
of an IP. At the
|
||||||
|
.B
|
||||||
|
-U
|
||||||
|
command you can use the token
|
||||||
|
.B
|
||||||
|
:all:
|
||||||
|
to destroy the bindings of all elements of a set.
|
||||||
|
.SS "OTHER OPTIONS"
|
||||||
|
The following additional options can be specified:
|
||||||
|
.TP
|
||||||
|
.B "-b, --binding setname"
|
||||||
|
The option specifies the value of the binding for the
|
||||||
|
.B "-B"
|
||||||
|
binding command, for which it is a mandatory option.
|
||||||
|
You can use it in the
|
||||||
|
.B "-T"
|
||||||
|
test command as well to test bindings.
|
||||||
|
.TP
|
||||||
|
.B "-s, --sorted"
|
||||||
|
Sorted output. When listing sets, entries are listed sorted.
|
||||||
|
.TP
|
||||||
|
.B "-n, --numeric"
|
||||||
|
Numeric output. When listing sets, bindings, IP addresses and
|
||||||
|
port numbers will be printed in numeric format. By default the
|
||||||
|
program will try to display them as host names, network names
|
||||||
|
or services (whenever applicable), which can trigger
|
||||||
|
.B
|
||||||
|
slow
|
||||||
|
DNS
|
||||||
|
lookups.
|
||||||
|
.TP
|
||||||
|
.B "-q, --quiet"
|
||||||
|
Suppress any output to stdout and stderr. ipset will still return
|
||||||
|
possible errors.
|
||||||
|
.SH SET TYPES
|
||||||
|
ipset supports the following set types:
|
||||||
|
.SS ipmap
|
||||||
|
The ipmap set type uses a memory range, where each bit represents
|
||||||
|
one IP address. An ipmap set can store up to 65536 (B-class network)
|
||||||
|
IP addresses. The ipmap set type is very fast and memory cheap, great
|
||||||
|
for use when one want to match certain IPs in a range. Using the
|
||||||
|
.B "--netmask"
|
||||||
|
option with a CIDR netmask value between 0-32 when creating an ipmap
|
||||||
|
set, you will be able to store and match network addresses: i.e an
|
||||||
|
IP address will be in the set if the value resulted by masking the address
|
||||||
|
with the specified netmask can be found in the set.
|
||||||
|
.P
|
||||||
|
Options to use when creating an ipmap set:
|
||||||
|
.TP
|
||||||
|
.BR "--from " from-IP
|
||||||
|
.TP
|
||||||
|
.BR "--to " to-IP
|
||||||
|
Create an ipmap set from the specified range.
|
||||||
|
.TP
|
||||||
|
.BR "--network " IP/mask
|
||||||
|
Create an ipmap set from the specified network.
|
||||||
|
.TP
|
||||||
|
.BR "--netmask " CIDR-netmask
|
||||||
|
When the optional
|
||||||
|
.B "--netmask"
|
||||||
|
parameter specified, network addresses will be
|
||||||
|
stored in the set instead of IP addresses, and the from-IP parameter
|
||||||
|
must be a network address.
|
||||||
|
.SS macipmap
|
||||||
|
The macipmap set type uses a memory range, where each 8 bytes
|
||||||
|
represents one IP and a MAC addresses. A macipmap set type can store
|
||||||
|
up to 65536 (B-class network) IP addresses with MAC.
|
||||||
|
When adding an entry to a macipmap set, you must specify the entry as
|
||||||
|
.I IP:MAC.
|
||||||
|
When deleting or testing macipmap entries, the
|
||||||
|
.I :MAC
|
||||||
|
part is not mandatory. (The old "%" separation token instead of ":", i.e
|
||||||
|
IP%MAC is accepted as well.)
|
||||||
|
.P
|
||||||
|
Options to use when creating an macipmap set:
|
||||||
|
.TP
|
||||||
|
.BR "--from " from-IP
|
||||||
|
.TP
|
||||||
|
.BR "--to " to-IP
|
||||||
|
Create a macipmap set from the specified range.
|
||||||
|
.TP
|
||||||
|
.BR "--network " IP/mask
|
||||||
|
Create a macipmap set from the specified network.
|
||||||
|
.TP
|
||||||
|
.BR "--matchunset"
|
||||||
|
When the optional
|
||||||
|
.B "--matchunset"
|
||||||
|
parameter specified, IP addresses which could be stored
|
||||||
|
in the set but not set yet, will always match.
|
||||||
|
.P
|
||||||
|
Please note, the
|
||||||
|
.I
|
||||||
|
set
|
||||||
|
and
|
||||||
|
.I
|
||||||
|
SET
|
||||||
|
netfilter kernel modules
|
||||||
|
.B
|
||||||
|
always
|
||||||
|
use the source MAC address from the packet to match, add or delete
|
||||||
|
entries from a macipmap type of set.
|
||||||
|
.SS portmap
|
||||||
|
The portmap set type uses a memory range, where each bit represents
|
||||||
|
one port. A portmap set type can store up to 65536 ports.
|
||||||
|
The portmap set type is very fast and memory cheap.
|
||||||
|
.P
|
||||||
|
Options to use when creating an portmap set:
|
||||||
|
.TP
|
||||||
|
.BR "--from " from-port
|
||||||
|
.TP
|
||||||
|
.BR "--to " to-port
|
||||||
|
Create a portmap set from the specified range.
|
||||||
|
.SS iphash
|
||||||
|
The iphash set type uses a hash to store IP addresses.
|
||||||
|
In order to avoid clashes in the hash double-hashing, and as a last
|
||||||
|
resort, dynamic growing of the hash performed. The iphash set type is
|
||||||
|
great to store random addresses. By supplyig the
|
||||||
|
.B "--netmask"
|
||||||
|
option with a CIDR netmask value between 0-32 at creating the set,
|
||||||
|
you will be able to store and match network addresses instead: i.e
|
||||||
|
an IP address will be in the set if the value of the address
|
||||||
|
masked with the specified netmask can be found in the set.
|
||||||
|
.P
|
||||||
|
Options to use when creating an iphash set:
|
||||||
|
.TP
|
||||||
|
.BR "--hashsize " hashsize
|
||||||
|
The initial hash size (default 1024)
|
||||||
|
.TP
|
||||||
|
.BR "--probes " probes
|
||||||
|
How many times try to resolve clashing at adding an IP to the hash
|
||||||
|
by double-hashing (default 8).
|
||||||
|
.TP
|
||||||
|
.BR "--resize " percent
|
||||||
|
Increase the hash size by this many percent (default 50) when adding
|
||||||
|
an IP to the hash could not be performed after
|
||||||
|
.B
|
||||||
|
probes
|
||||||
|
number of double-hashing.
|
||||||
|
.TP
|
||||||
|
.BR "--netmask " CIDR-netmask
|
||||||
|
When the optional
|
||||||
|
.B "--netmask"
|
||||||
|
parameter specified, network addresses will be
|
||||||
|
stored in the set instead of IP addresses.
|
||||||
|
.P
|
||||||
|
The iphash type of sets can store up to 65536 entries. If a set is full,
|
||||||
|
no new entries can be added to it.
|
||||||
|
.P
|
||||||
|
Sets created by zero valued resize parameter won't be resized at all.
|
||||||
|
The lookup time in an iphash type of set approximately linearly grows with
|
||||||
|
the value of the
|
||||||
|
.B
|
||||||
|
probes
|
||||||
|
parameter. At the same time higher
|
||||||
|
.B
|
||||||
|
probes
|
||||||
|
values result a better utilized hash while smaller values
|
||||||
|
produce a larger, sparse hash.
|
||||||
|
.SS nethash
|
||||||
|
The nethash set type uses a hash to store different size of
|
||||||
|
network addresses. The
|
||||||
|
.I
|
||||||
|
IP
|
||||||
|
"address" used in the ipset commands must be in the form
|
||||||
|
.I
|
||||||
|
IP-address/cidr-size
|
||||||
|
where the CIDR block size must be in the inclusive range of 1-31.
|
||||||
|
In order to avoid clashes in the hash
|
||||||
|
double-hashing, and as a last resort, dynamic growing of the hash performed.
|
||||||
|
.P
|
||||||
|
Options to use when creating an nethash set:
|
||||||
|
.TP
|
||||||
|
.BR "--hashsize " hashsize
|
||||||
|
The initial hash size (default 1024)
|
||||||
|
.TP
|
||||||
|
.BR "--probes " probes
|
||||||
|
How many times try to resolve clashing at adding an IP to the hash
|
||||||
|
by double-hashing (default 4).
|
||||||
|
.TP
|
||||||
|
.BR "--resize " percent
|
||||||
|
Increase the hash size by this many percent (default 50) when adding
|
||||||
|
an IP to the hash could not be performed after
|
||||||
|
.P
|
||||||
|
The nethash type of sets can store up to 65536 entries. If a set is full,
|
||||||
|
no new entries can be added to it.
|
||||||
|
.P
|
||||||
|
An IP address will be in a nethash type of set if it is in any of the
|
||||||
|
netblocks added to the set and the matching always start from the smallest
|
||||||
|
size of netblock (most specific netmask) to the biggest ones (least
|
||||||
|
specific netmasks). When adding/deleting IP addresses
|
||||||
|
to a nethash set by the
|
||||||
|
.I
|
||||||
|
SET
|
||||||
|
netfilter kernel module, it will be added/deleted by the smallest
|
||||||
|
netblock size which can be found in the set.
|
||||||
|
.P
|
||||||
|
The lookup time in a nethash type of set is approximately linearly
|
||||||
|
grows with the times of the
|
||||||
|
.B
|
||||||
|
probes
|
||||||
|
parameter and the number of different mask parameters in the hash.
|
||||||
|
Otherwise the same speed and memory efficiency comments applies here
|
||||||
|
as at the iphash type.
|
||||||
|
.SS ipporthash
|
||||||
|
The ipporthash set type uses a hash to store IP address and port pairs.
|
||||||
|
In order to avoid clashes in the hash double-hashing, and as a last
|
||||||
|
resort, dynamic growing of the hash performed. An ipporthash set can
|
||||||
|
store up to 65536 (B-class network) IP addresses with all possible port
|
||||||
|
values. When adding, deleting and testing values in an ipporthash type of
|
||||||
|
set, the entries must be specified as
|
||||||
|
.B
|
||||||
|
"IP:port".
|
||||||
|
(Old "IP%port" format accepted as well.)
|
||||||
|
.P
|
||||||
|
The ipporthash types of sets evaluates two src/dst parameters of the
|
||||||
|
.I
|
||||||
|
set
|
||||||
|
match and
|
||||||
|
.I
|
||||||
|
SET
|
||||||
|
target.
|
||||||
|
.P
|
||||||
|
Options to use when creating an ipporthash set:
|
||||||
|
.TP
|
||||||
|
.BR "--from " from-IP
|
||||||
|
.TP
|
||||||
|
.BR "--to " to-IP
|
||||||
|
Create an ipporthash set from the specified range.
|
||||||
|
.TP
|
||||||
|
.BR "--network " IP/mask
|
||||||
|
Create an ipporthash set from the specified network.
|
||||||
|
.TP
|
||||||
|
.BR "--hashsize " hashsize
|
||||||
|
The initial hash size (default 1024)
|
||||||
|
.TP
|
||||||
|
.BR "--probes " probes
|
||||||
|
How many times try to resolve clashing at adding an IP to the hash
|
||||||
|
by double-hashing (default 8).
|
||||||
|
.TP
|
||||||
|
.BR "--resize " percent
|
||||||
|
Increase the hash size by this many percent (default 50) when adding
|
||||||
|
an IP to the hash could not be performed after
|
||||||
|
.B
|
||||||
|
probes
|
||||||
|
number of double-hashing.
|
||||||
|
.P
|
||||||
|
The same resizing, speed and memory efficiency comments applies here
|
||||||
|
as at the iphash type.
|
||||||
|
.SS iptree
|
||||||
|
The iptree set type uses a tree to store IP addresses, optionally
|
||||||
|
with timeout values.
|
||||||
|
.P
|
||||||
|
Options to use when creating an iptree set:
|
||||||
|
.TP
|
||||||
|
.BR "--timeout " value
|
||||||
|
The timeout value for the entries in seconds (default 0)
|
||||||
|
.P
|
||||||
|
If a set was created with a nonzero valued
|
||||||
|
.B "--timeout"
|
||||||
|
parameter then one may add IP addresses to the set with a specific
|
||||||
|
timeout value using the syntax
|
||||||
|
.I IP:timeout-value.
|
||||||
|
Similarly to the hash types, the iptree type of sets can store up to 65536
|
||||||
|
entries.
|
||||||
|
.SS iptreemap
|
||||||
|
The iptreemap set type uses a tree to store IP addresses or networks,
|
||||||
|
where the last octet of an IP address are stored in a bitmap.
|
||||||
|
As input entry, you can add IP addresses, CIDR blocks or network ranges
|
||||||
|
to the set. Network ranges can be specified in the format
|
||||||
|
.I IP1:IP2
|
||||||
|
.P
|
||||||
|
Options to use when creating an iptreemap set:
|
||||||
|
.TP
|
||||||
|
.BR "--gc " value
|
||||||
|
How often the garbage collection should be called, in seconds (default 300)
|
||||||
|
.SH GENERAL RESTRICTIONS
|
||||||
|
Setnames starting with colon (:) cannot be defined. Zero valued set
|
||||||
|
entries cannot be used with hash type of sets.
|
||||||
|
.SH COMMENTS
|
||||||
|
If you want to store same size subnets from a given network
|
||||||
|
(say /24 blocks from a /8 network), use the ipmap set type.
|
||||||
|
If you want to store random same size networks (say random /24 blocks),
|
||||||
|
use the iphash set type. If you have got random size of netblocks,
|
||||||
|
use nethash.
|
||||||
|
.SH DIAGNOSTICS
|
||||||
|
Various error messages are printed to standard error. The exit code
|
||||||
|
is 0 for correct functioning. Errors which appear to be caused by
|
||||||
|
invalid or abused command line parameters cause an exit code of 2, and
|
||||||
|
other errors cause an exit code of 1.
|
||||||
|
.SH BUGS
|
||||||
|
Bugs? No, just funny features. :-)
|
||||||
|
OK, just kidding...
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR iptables (8),
|
||||||
|
.SH AUTHORS
|
||||||
|
Jozsef Kadlecsik wrote ipset, which is based on ippool by
|
||||||
|
Joakim Axelsson, Patrick Schaaf and Martin Josefsson.
|
||||||
|
.P
|
||||||
|
Sven Wegener wrote the iptreemap type.
|
||||||
|
.SH LAST REMARK
|
||||||
|
.BR "I stand on the shoulder of giants."
|
||||||
|
.\" .. and did I mention that we are incredibly cool people?
|
||||||
|
.\" .. sexy, too ..
|
||||||
|
.\" .. witty, charming, powerful ..
|
||||||
|
.\" .. and most of all, modest ..
|
2309
extensions/ipset/ipset.c
Normal file
2309
extensions/ipset/ipset.c
Normal file
File diff suppressed because it is too large
Load Diff
191
extensions/ipset/ipset.h
Normal file
191
extensions/ipset/ipset.h
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
#ifndef __IPSET_H
|
||||||
|
#define __IPSET_H
|
||||||
|
|
||||||
|
/* Copyright 2000-2004 Joakim Axelsson (gozem@linux.nu)
|
||||||
|
* Patrick Schaaf (bof@bof.de)
|
||||||
|
* Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe"
|
||||||
|
|
||||||
|
#define LIST_TRIES 5
|
||||||
|
|
||||||
|
#ifdef IPSET_DEBUG
|
||||||
|
extern int option_debug;
|
||||||
|
#define DP(format, args...) if (option_debug) \
|
||||||
|
do { \
|
||||||
|
fprintf(stderr, "%s: %s (DBG): ", __FILE__, __FUNCTION__);\
|
||||||
|
fprintf(stderr, format "\n" , ## args); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define DP(format, args...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Commands */
|
||||||
|
enum set_commands {
|
||||||
|
CMD_NONE,
|
||||||
|
CMD_CREATE, /* -N */
|
||||||
|
CMD_DESTROY, /* -X */
|
||||||
|
CMD_FLUSH, /* -F */
|
||||||
|
CMD_RENAME, /* -E */
|
||||||
|
CMD_SWAP, /* -W */
|
||||||
|
CMD_LIST, /* -L */
|
||||||
|
CMD_SAVE, /* -S */
|
||||||
|
CMD_RESTORE, /* -R */
|
||||||
|
CMD_ADD, /* -A */
|
||||||
|
CMD_DEL, /* -D */
|
||||||
|
CMD_TEST, /* -T */
|
||||||
|
CMD_BIND, /* -B */
|
||||||
|
CMD_UNBIND, /* -U */
|
||||||
|
CMD_HELP, /* -H */
|
||||||
|
CMD_VERSION, /* -V */
|
||||||
|
NUMBER_OF_CMD = CMD_VERSION,
|
||||||
|
/* Internal commands */
|
||||||
|
CMD_MAX_SETS,
|
||||||
|
CMD_LIST_SIZE,
|
||||||
|
CMD_SAVE_SIZE,
|
||||||
|
CMD_ADT_GET,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum exittype {
|
||||||
|
OTHER_PROBLEM = 1,
|
||||||
|
PARAMETER_PROBLEM,
|
||||||
|
VERSION_PROBLEM
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The view of an ipset in userspace */
|
||||||
|
struct set {
|
||||||
|
char name[IP_SET_MAXNAMELEN]; /* Name of the set */
|
||||||
|
ip_set_id_t id; /* Unique set id */
|
||||||
|
ip_set_id_t index; /* Array index */
|
||||||
|
unsigned ref; /* References in kernel */
|
||||||
|
struct settype *settype; /* Pointer to set type functions */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct settype {
|
||||||
|
struct settype *next;
|
||||||
|
|
||||||
|
char typename[IP_SET_MAXNAMELEN];
|
||||||
|
|
||||||
|
int protocol_version;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create set
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Size of create data. Will be sent to kernel */
|
||||||
|
size_t create_size;
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
void (*create_init) (void *data);
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
int (*create_parse) (int c, char *argv[], void *data,
|
||||||
|
unsigned *flags);
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
void (*create_final) (void *data, unsigned int flags);
|
||||||
|
|
||||||
|
/* Pointer to list of extra command-line options for create */
|
||||||
|
const struct option *create_opts;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add/del/test IP
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Size of data. Will be sent to kernel */
|
||||||
|
size_t adt_size;
|
||||||
|
|
||||||
|
/* Function which parses command options */
|
||||||
|
ip_set_ip_t (*adt_parser) (unsigned cmd, const char *optarg, void *data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Printing
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Size of header. */
|
||||||
|
size_t header_size;
|
||||||
|
|
||||||
|
/* Initialize the type-header */
|
||||||
|
void (*initheader) (struct set *set, const void *data);
|
||||||
|
|
||||||
|
/* Pretty print the type-header */
|
||||||
|
void (*printheader) (struct set *set, unsigned options);
|
||||||
|
|
||||||
|
/* Pretty print all IPs */
|
||||||
|
void (*printips) (struct set *set, void *data, size_t len, unsigned options);
|
||||||
|
|
||||||
|
/* Pretty print all IPs sorted */
|
||||||
|
void (*printips_sorted) (struct set *set, void *data, size_t len, unsigned options);
|
||||||
|
|
||||||
|
/* Print save arguments for creating the set */
|
||||||
|
void (*saveheader) (struct set *set, unsigned options);
|
||||||
|
|
||||||
|
/* Print save for all IPs */
|
||||||
|
void (*saveips) (struct set *set, void *data, size_t len, unsigned options);
|
||||||
|
|
||||||
|
/* Conver a single IP (binding) to string */
|
||||||
|
char * (*bindip_tostring)(struct set *set, ip_set_ip_t ip, unsigned options);
|
||||||
|
|
||||||
|
/* Parse an IP at restoring bindings. FIXME */
|
||||||
|
void (*bindip_parse) (const char *str, ip_set_ip_t * ip);
|
||||||
|
|
||||||
|
/* Print usage */
|
||||||
|
void (*usage) (void);
|
||||||
|
|
||||||
|
/* Internal data */
|
||||||
|
void *header;
|
||||||
|
void *data;
|
||||||
|
unsigned int option_offset;
|
||||||
|
unsigned int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void settype_register(struct settype *settype);
|
||||||
|
|
||||||
|
/* extern void unregister_settype(set_type_t *set_type); */
|
||||||
|
|
||||||
|
extern void exit_error(enum exittype status, const char *msg, ...);
|
||||||
|
|
||||||
|
extern char *binding_ip_tostring(struct set *set,
|
||||||
|
ip_set_ip_t ip, unsigned options);
|
||||||
|
extern char *ip_tostring(ip_set_ip_t ip, unsigned options);
|
||||||
|
extern char *ip_tostring_numeric(ip_set_ip_t ip);
|
||||||
|
extern void parse_ip(const char *str, ip_set_ip_t * ip);
|
||||||
|
extern void parse_mask(const char *str, ip_set_ip_t * mask);
|
||||||
|
extern void parse_ipandmask(const char *str, ip_set_ip_t * ip,
|
||||||
|
ip_set_ip_t * mask);
|
||||||
|
extern char *port_tostring(ip_set_ip_t port, unsigned options);
|
||||||
|
extern void parse_port(const char *str, ip_set_ip_t * port);
|
||||||
|
extern int string_to_number(const char *str, unsigned int min, unsigned int max,
|
||||||
|
ip_set_ip_t *port);
|
||||||
|
|
||||||
|
extern void *ipset_malloc(size_t size);
|
||||||
|
extern char *ipset_strdup(const char *);
|
||||||
|
extern void ipset_free(void **data);
|
||||||
|
|
||||||
|
#define BITSPERBYTE (8*sizeof(char))
|
||||||
|
#define ID2BYTE(id) ((id)/BITSPERBYTE)
|
||||||
|
#define ID2MASK(id) (1 << ((id)%BITSPERBYTE))
|
||||||
|
#define test_bit(id, heap) ((((char *)(heap))[ID2BYTE(id)] & ID2MASK(id)) != 0)
|
||||||
|
|
||||||
|
#endif /* __IPSET_H */
|
299
extensions/ipset/ipset_iphash.c
Normal file
299
extensions/ipset/ipset_iphash.c
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
/* Copyright 2004 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <asm/types.h>
|
||||||
|
|
||||||
|
#include "ip_set_iphash.h"
|
||||||
|
#include "ip_set_jhash.h"
|
||||||
|
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
#define BUFLEN 30;
|
||||||
|
|
||||||
|
#define OPT_CREATE_HASHSIZE 0x01U
|
||||||
|
#define OPT_CREATE_PROBES 0x02U
|
||||||
|
#define OPT_CREATE_RESIZE 0x04U
|
||||||
|
#define OPT_CREATE_NETMASK 0x08U
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
static void create_init(void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iphash_create *mydata =
|
||||||
|
(struct ip_set_req_iphash_create *) data;
|
||||||
|
|
||||||
|
DP("create INIT");
|
||||||
|
|
||||||
|
/* Default create parameters */
|
||||||
|
mydata->hashsize = 1024;
|
||||||
|
mydata->probes = 8;
|
||||||
|
mydata->resize = 50;
|
||||||
|
|
||||||
|
mydata->netmask = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iphash_create *mydata =
|
||||||
|
(struct ip_set_req_iphash_create *) data;
|
||||||
|
unsigned int bits;
|
||||||
|
ip_set_ip_t value;
|
||||||
|
|
||||||
|
DP("create_parse");
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '1':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 1, UINT_MAX - 1, &mydata->hashsize))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid hashsize `%s' specified", optarg);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_HASHSIZE;
|
||||||
|
|
||||||
|
DP("--hashsize %u", mydata->hashsize);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 1, 65535, &value))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid probes `%s' specified", optarg);
|
||||||
|
|
||||||
|
mydata->probes = value;
|
||||||
|
*flags |= OPT_CREATE_PROBES;
|
||||||
|
|
||||||
|
DP("--probes %u", mydata->probes);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '3':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 0, 65535, &value))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid resize `%s' specified", optarg);
|
||||||
|
|
||||||
|
mydata->resize = value;
|
||||||
|
*flags |= OPT_CREATE_RESIZE;
|
||||||
|
|
||||||
|
DP("--resize %u", mydata->resize);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '4':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 0, 32, &bits))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Invalid netmask `%s' specified", optarg);
|
||||||
|
|
||||||
|
if (bits != 0)
|
||||||
|
mydata->netmask = 0xFFFFFFFF << (32 - bits);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_NETMASK;
|
||||||
|
|
||||||
|
DP("--netmask %x", mydata->netmask);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
static void create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
#ifdef IPSET_DEBUG
|
||||||
|
struct ip_set_req_iphash_create *mydata =
|
||||||
|
(struct ip_set_req_iphash_create *) data;
|
||||||
|
|
||||||
|
DP("hashsize %u probes %u resize %u",
|
||||||
|
mydata->hashsize, mydata->probes, mydata->resize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create commandline options */
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"hashsize", 1, 0, '1'},
|
||||||
|
{"probes", 1, 0, '2'},
|
||||||
|
{"resize", 1, 0, '3'},
|
||||||
|
{"netmask", 1, 0, '4'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add, del, test parser */
|
||||||
|
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iphash *mydata =
|
||||||
|
(struct ip_set_req_iphash *) data;
|
||||||
|
|
||||||
|
parse_ip(arg, &mydata->ip);
|
||||||
|
if (!mydata->ip)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Zero valued IP address `%s' specified", arg);
|
||||||
|
|
||||||
|
return mydata->ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print and save
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iphash_create *header =
|
||||||
|
(struct ip_set_req_iphash_create *) data;
|
||||||
|
struct ip_set_iphash *map =
|
||||||
|
(struct ip_set_iphash *) set->settype->header;
|
||||||
|
|
||||||
|
memset(map, 0, sizeof(struct ip_set_iphash));
|
||||||
|
map->hashsize = header->hashsize;
|
||||||
|
map->probes = header->probes;
|
||||||
|
map->resize = header->resize;
|
||||||
|
map->netmask = header->netmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
mask_to_bits(ip_set_ip_t mask)
|
||||||
|
{
|
||||||
|
unsigned int bits = 32;
|
||||||
|
ip_set_ip_t maskaddr;
|
||||||
|
|
||||||
|
if (mask == 0xFFFFFFFF)
|
||||||
|
return bits;
|
||||||
|
|
||||||
|
maskaddr = 0xFFFFFFFE;
|
||||||
|
while (--bits >= 0 && maskaddr != mask)
|
||||||
|
maskaddr <<= 1;
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *mysetdata =
|
||||||
|
(struct ip_set_iphash *) set->settype->header;
|
||||||
|
|
||||||
|
printf(" hashsize: %u", mysetdata->hashsize);
|
||||||
|
printf(" probes: %u", mysetdata->probes);
|
||||||
|
printf(" resize: %u", mysetdata->resize);
|
||||||
|
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||||
|
printf("\n");
|
||||||
|
else
|
||||||
|
printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
ip_set_ip_t *ip;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
ip = data + offset;
|
||||||
|
if (*ip)
|
||||||
|
printf("%s\n", ip_tostring(*ip, options));
|
||||||
|
offset += sizeof(ip_set_ip_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iphash *mysetdata =
|
||||||
|
(struct ip_set_iphash *) set->settype->header;
|
||||||
|
|
||||||
|
printf("-N %s %s --hashsize %u --probes %u --resize %u",
|
||||||
|
set->name, set->settype->typename,
|
||||||
|
mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
|
||||||
|
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||||
|
printf("\n");
|
||||||
|
else
|
||||||
|
printf(" --netmask %d\n", mask_to_bits(mysetdata->netmask));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print save for an IP */
|
||||||
|
static void saveips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
ip_set_ip_t *ip;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
ip = data + offset;
|
||||||
|
if (*ip)
|
||||||
|
printf("-A %s %s\n", set->name,
|
||||||
|
ip_tostring(*ip, options));
|
||||||
|
offset += sizeof(ip_set_ip_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf
|
||||||
|
("-N set iphash [--hashsize hashsize] [--probes probes ]\n"
|
||||||
|
" [--resize resize] [--netmask CIDR-netmask]\n"
|
||||||
|
"-A set IP\n"
|
||||||
|
"-D set IP\n"
|
||||||
|
"-T set IP\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_iphash = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
.create_size = sizeof(struct ip_set_req_iphash_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
/* Add/del/test */
|
||||||
|
.adt_size = sizeof(struct ip_set_req_iphash),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
/* Printing */
|
||||||
|
.header_size = sizeof(struct ip_set_iphash),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printips, /* We only have the unsorted version */
|
||||||
|
.printips_sorted = &printips,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveips,
|
||||||
|
|
||||||
|
/* Bindings */
|
||||||
|
.bindip_tostring = &binding_ip_tostring,
|
||||||
|
.bindip_parse = &parse_ip,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void iphash_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_iphash);
|
||||||
|
|
||||||
|
}
|
362
extensions/ipset/ipset_ipmap.c
Normal file
362
extensions/ipset/ipset_ipmap.c
Normal file
@@ -0,0 +1,362 @@
|
|||||||
|
/* Copyright 2000-2004 Joakim Axelsson (gozem@linux.nu)
|
||||||
|
* Patrick Schaaf (bof@bof.de)
|
||||||
|
* Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
/* #include <asm/bitops.h> */
|
||||||
|
|
||||||
|
#include "ip_set_ipmap.h"
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
#define BUFLEN 30;
|
||||||
|
|
||||||
|
#define OPT_CREATE_FROM 0x01U
|
||||||
|
#define OPT_CREATE_TO 0x02U
|
||||||
|
#define OPT_CREATE_NETWORK 0x04U
|
||||||
|
#define OPT_CREATE_NETMASK 0x08U
|
||||||
|
|
||||||
|
#define OPT_ADDDEL_IP 0x01U
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
static void create_init(void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipmap_create *mydata =
|
||||||
|
(struct ip_set_req_ipmap_create *) data;
|
||||||
|
|
||||||
|
DP("create INIT");
|
||||||
|
mydata->netmask = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipmap_create *mydata =
|
||||||
|
(struct ip_set_req_ipmap_create *) data;
|
||||||
|
unsigned int bits;
|
||||||
|
|
||||||
|
DP("create_parse");
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '1':
|
||||||
|
parse_ip(optarg, &mydata->from);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_FROM;
|
||||||
|
|
||||||
|
DP("--from %x (%s)", mydata->from,
|
||||||
|
ip_tostring_numeric(mydata->from));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2':
|
||||||
|
parse_ip(optarg, &mydata->to);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_TO;
|
||||||
|
|
||||||
|
DP("--to %x (%s)", mydata->to,
|
||||||
|
ip_tostring_numeric(mydata->to));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '3':
|
||||||
|
parse_ipandmask(optarg, &mydata->from, &mydata->to);
|
||||||
|
|
||||||
|
/* Make to the last of from + mask */
|
||||||
|
if (mydata->to)
|
||||||
|
mydata->to = mydata->from | ~(mydata->to);
|
||||||
|
else {
|
||||||
|
mydata->from = 0x00000000;
|
||||||
|
mydata->to = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
*flags |= OPT_CREATE_NETWORK;
|
||||||
|
|
||||||
|
DP("--network from %x (%s)",
|
||||||
|
mydata->from, ip_tostring_numeric(mydata->from));
|
||||||
|
DP("--network to %x (%s)",
|
||||||
|
mydata->to, ip_tostring_numeric(mydata->to));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '4':
|
||||||
|
if (string_to_number(optarg, 0, 32, &bits))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Invalid netmask `%s' specified", optarg);
|
||||||
|
|
||||||
|
if (bits != 0)
|
||||||
|
mydata->netmask = 0xFFFFFFFF << (32 - bits);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_NETMASK;
|
||||||
|
|
||||||
|
DP("--netmask %x", mydata->netmask);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ERRSTRLEN 256
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
static void create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipmap_create *mydata =
|
||||||
|
(struct ip_set_req_ipmap_create *) data;
|
||||||
|
ip_set_ip_t range;
|
||||||
|
char errstr[ERRSTRLEN];
|
||||||
|
|
||||||
|
if (flags == 0)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify --from and --to, or --network\n");
|
||||||
|
|
||||||
|
if (flags & OPT_CREATE_NETWORK) {
|
||||||
|
/* --network */
|
||||||
|
if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Can't specify --from or --to with --network\n");
|
||||||
|
} else {
|
||||||
|
/* --from --to */
|
||||||
|
if ((flags & OPT_CREATE_FROM) == 0
|
||||||
|
|| (flags & OPT_CREATE_TO) == 0)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify both --from and --to\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
DP("from : %x to: %x diff: %x",
|
||||||
|
mydata->from, mydata->to,
|
||||||
|
mydata->to - mydata->from);
|
||||||
|
|
||||||
|
if (mydata->from > mydata->to)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"From can't be lower than to.\n");
|
||||||
|
|
||||||
|
if (flags & OPT_CREATE_NETMASK) {
|
||||||
|
unsigned int mask_bits, netmask_bits;
|
||||||
|
ip_set_ip_t mask;
|
||||||
|
|
||||||
|
if ((mydata->from & mydata->netmask) != mydata->from)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"%s is not a network address according to netmask %d\n",
|
||||||
|
ip_tostring_numeric(mydata->from),
|
||||||
|
mask_to_bits(mydata->netmask));
|
||||||
|
|
||||||
|
mask = range_to_mask(mydata->from, mydata->to, &mask_bits);
|
||||||
|
if (!mask
|
||||||
|
&& (mydata->from || mydata->to != 0xFFFFFFFF)) {
|
||||||
|
strncpy(errstr, ip_tostring_numeric(mydata->from),
|
||||||
|
ERRSTRLEN-2);
|
||||||
|
errstr[ERRSTRLEN-1] = '\0';
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"%s-%s is not a full network (%x)\n",
|
||||||
|
errstr,
|
||||||
|
ip_tostring_numeric(mydata->to), mask);
|
||||||
|
}
|
||||||
|
netmask_bits = mask_to_bits(mydata->netmask);
|
||||||
|
|
||||||
|
if (netmask_bits <= mask_bits) {
|
||||||
|
strncpy(errstr, ip_tostring_numeric(mydata->from),
|
||||||
|
ERRSTRLEN-2);
|
||||||
|
errstr[ERRSTRLEN-1] = '\0';
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"%d netmask specifies larger or equal netblock than %s-%s (%d)\n",
|
||||||
|
netmask_bits,
|
||||||
|
errstr,
|
||||||
|
ip_tostring_numeric(mydata->to),
|
||||||
|
mask_bits);
|
||||||
|
}
|
||||||
|
range = (1<<(netmask_bits - mask_bits)) - 1;
|
||||||
|
} else {
|
||||||
|
range = mydata->to - mydata->from;
|
||||||
|
}
|
||||||
|
if (range > MAX_RANGE)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Range too large. Max is %d IPs in range\n",
|
||||||
|
MAX_RANGE+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create commandline options */
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"from", 1, 0, '1'},
|
||||||
|
{"to", 1, 0, '2'},
|
||||||
|
{"network", 1, 0, '3'},
|
||||||
|
{"netmask", 1, 0, '4'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add, del, test parser */
|
||||||
|
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipmap *mydata =
|
||||||
|
(struct ip_set_req_ipmap *) data;
|
||||||
|
|
||||||
|
DP("ipmap: %p %p", arg, data);
|
||||||
|
|
||||||
|
parse_ip(arg, &mydata->ip);
|
||||||
|
DP("%s", ip_tostring_numeric(mydata->ip));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print and save
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipmap_create *header =
|
||||||
|
(struct ip_set_req_ipmap_create *) data;
|
||||||
|
struct ip_set_ipmap *map =
|
||||||
|
(struct ip_set_ipmap *) set->settype->header;
|
||||||
|
|
||||||
|
memset(map, 0, sizeof(struct ip_set_ipmap));
|
||||||
|
map->first_ip = header->from;
|
||||||
|
map->last_ip = header->to;
|
||||||
|
map->netmask = header->netmask;
|
||||||
|
|
||||||
|
if (map->netmask == 0xFFFFFFFF) {
|
||||||
|
map->hosts = 1;
|
||||||
|
map->sizeid = map->last_ip - map->first_ip + 1;
|
||||||
|
} else {
|
||||||
|
unsigned int mask_bits, netmask_bits;
|
||||||
|
ip_set_ip_t mask;
|
||||||
|
|
||||||
|
mask = range_to_mask(header->from, header->to, &mask_bits);
|
||||||
|
netmask_bits = mask_to_bits(header->netmask);
|
||||||
|
|
||||||
|
DP("bits: %i %i", mask_bits, netmask_bits);
|
||||||
|
map->hosts = 2 << (32 - netmask_bits - 1);
|
||||||
|
map->sizeid = 2 << (netmask_bits - mask_bits - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
DP("%i %i", map->hosts, map->sizeid );
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *mysetdata =
|
||||||
|
(struct ip_set_ipmap *) set->settype->header;
|
||||||
|
|
||||||
|
printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
|
||||||
|
printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
|
||||||
|
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||||
|
printf("\n");
|
||||||
|
else
|
||||||
|
printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printips_sorted(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *mysetdata =
|
||||||
|
(struct ip_set_ipmap *) set->settype->header;
|
||||||
|
ip_set_ip_t id;
|
||||||
|
|
||||||
|
for (id = 0; id < mysetdata->sizeid; id++)
|
||||||
|
if (test_bit(id, data))
|
||||||
|
printf("%s\n",
|
||||||
|
ip_tostring(mysetdata->first_ip
|
||||||
|
+ id * mysetdata->hosts,
|
||||||
|
options));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *mysetdata =
|
||||||
|
(struct ip_set_ipmap *) set->settype->header;
|
||||||
|
|
||||||
|
printf("-N %s %s --from %s",
|
||||||
|
set->name, set->settype->typename,
|
||||||
|
ip_tostring(mysetdata->first_ip, options));
|
||||||
|
printf(" --to %s",
|
||||||
|
ip_tostring(mysetdata->last_ip, options));
|
||||||
|
if (mysetdata->netmask == 0xFFFFFFFF)
|
||||||
|
printf("\n");
|
||||||
|
else
|
||||||
|
printf(" --netmask %d\n",
|
||||||
|
mask_to_bits(mysetdata->netmask));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipmap *mysetdata =
|
||||||
|
(struct ip_set_ipmap *) set->settype->header;
|
||||||
|
ip_set_ip_t id;
|
||||||
|
|
||||||
|
DP("%s", set->name);
|
||||||
|
for (id = 0; id < mysetdata->sizeid; id++)
|
||||||
|
if (test_bit(id, data))
|
||||||
|
printf("-A %s %s\n",
|
||||||
|
set->name,
|
||||||
|
ip_tostring(mysetdata->first_ip
|
||||||
|
+ id * mysetdata->hosts,
|
||||||
|
options));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf
|
||||||
|
("-N set ipmap --from IP --to IP [--netmask CIDR-netmask]\n"
|
||||||
|
"-N set ipmap --network IP/mask [--netmask CIDR-netmask]\n"
|
||||||
|
"-A set IP\n"
|
||||||
|
"-D set IP\n"
|
||||||
|
"-T set IP\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_ipmap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
.create_size = sizeof(struct ip_set_req_ipmap_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
/* Add/del/test */
|
||||||
|
.adt_size = sizeof(struct ip_set_req_ipmap),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
/* Printing */
|
||||||
|
.header_size = sizeof(struct ip_set_ipmap),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printips_sorted, /* We only have sorted version */
|
||||||
|
.printips_sorted = &printips_sorted,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveips,
|
||||||
|
|
||||||
|
/* Bindings */
|
||||||
|
.bindip_tostring = &binding_ip_tostring,
|
||||||
|
.bindip_parse = &parse_ip,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void ipmap_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_ipmap);
|
||||||
|
|
||||||
|
}
|
375
extensions/ipset/ipset_ipporthash.c
Normal file
375
extensions/ipset/ipset_ipporthash.c
Normal file
@@ -0,0 +1,375 @@
|
|||||||
|
/* Copyright 2004 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <asm/types.h>
|
||||||
|
|
||||||
|
#include "ip_set_ipporthash.h"
|
||||||
|
#include "ip_set_jhash.h"
|
||||||
|
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
#define OPT_CREATE_HASHSIZE 0x01U
|
||||||
|
#define OPT_CREATE_PROBES 0x02U
|
||||||
|
#define OPT_CREATE_RESIZE 0x04U
|
||||||
|
#define OPT_CREATE_NETWORK 0x08U
|
||||||
|
#define OPT_CREATE_FROM 0x10U
|
||||||
|
#define OPT_CREATE_TO 0x20U
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
static void create_init(void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipporthash_create *mydata =
|
||||||
|
(struct ip_set_req_ipporthash_create *) data;
|
||||||
|
|
||||||
|
DP("create INIT");
|
||||||
|
|
||||||
|
/* Default create parameters */
|
||||||
|
mydata->hashsize = 1024;
|
||||||
|
mydata->probes = 8;
|
||||||
|
mydata->resize = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipporthash_create *mydata =
|
||||||
|
(struct ip_set_req_ipporthash_create *) data;
|
||||||
|
ip_set_ip_t value;
|
||||||
|
|
||||||
|
DP("create_parse");
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '1':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 1, UINT_MAX - 1, &mydata->hashsize))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid hashsize `%s' specified", optarg);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_HASHSIZE;
|
||||||
|
|
||||||
|
DP("--hashsize %u", mydata->hashsize);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 1, 65535, &value))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid probes `%s' specified", optarg);
|
||||||
|
|
||||||
|
mydata->probes = value;
|
||||||
|
*flags |= OPT_CREATE_PROBES;
|
||||||
|
|
||||||
|
DP("--probes %u", mydata->probes);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '3':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 0, 65535, &value))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid resize `%s' specified", optarg);
|
||||||
|
|
||||||
|
mydata->resize = value;
|
||||||
|
*flags |= OPT_CREATE_RESIZE;
|
||||||
|
|
||||||
|
DP("--resize %u", mydata->resize);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '4':
|
||||||
|
parse_ip(optarg, &mydata->from);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_FROM;
|
||||||
|
|
||||||
|
DP("--from %x (%s)", mydata->from,
|
||||||
|
ip_tostring_numeric(mydata->from));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '5':
|
||||||
|
parse_ip(optarg, &mydata->to);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_TO;
|
||||||
|
|
||||||
|
DP("--to %x (%s)", mydata->to,
|
||||||
|
ip_tostring_numeric(mydata->to));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '6':
|
||||||
|
parse_ipandmask(optarg, &mydata->from, &mydata->to);
|
||||||
|
|
||||||
|
/* Make to the last of from + mask */
|
||||||
|
if (mydata->to)
|
||||||
|
mydata->to = mydata->from | ~(mydata->to);
|
||||||
|
else {
|
||||||
|
mydata->from = 0x00000000;
|
||||||
|
mydata->to = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
*flags |= OPT_CREATE_NETWORK;
|
||||||
|
|
||||||
|
DP("--network from %x (%s)",
|
||||||
|
mydata->from, ip_tostring_numeric(mydata->from));
|
||||||
|
DP("--network to %x (%s)",
|
||||||
|
mydata->to, ip_tostring_numeric(mydata->to));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
static void create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipporthash_create *mydata =
|
||||||
|
(struct ip_set_req_ipporthash_create *) data;
|
||||||
|
|
||||||
|
#ifdef IPSET_DEBUG
|
||||||
|
DP("hashsize %u probes %u resize %u",
|
||||||
|
mydata->hashsize, mydata->probes, mydata->resize);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (flags & OPT_CREATE_NETWORK) {
|
||||||
|
/* --network */
|
||||||
|
if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Can't specify --from or --to with --network\n");
|
||||||
|
} else if (flags & (OPT_CREATE_FROM | OPT_CREATE_TO)) {
|
||||||
|
/* --from --to */
|
||||||
|
if (!(flags & OPT_CREATE_FROM) || !(flags & OPT_CREATE_TO))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify both --from and --to\n");
|
||||||
|
} else {
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify --from and --to, or --network\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DP("from : %x to: %x diff: %x",
|
||||||
|
mydata->from, mydata->to,
|
||||||
|
mydata->to - mydata->from);
|
||||||
|
|
||||||
|
if (mydata->from > mydata->to)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"From can't be higher than to.\n");
|
||||||
|
|
||||||
|
if (mydata->to - mydata->from > MAX_RANGE)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Range too large. Max is %d IPs in range\n",
|
||||||
|
MAX_RANGE+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create commandline options */
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"hashsize", 1, 0, '1'},
|
||||||
|
{"probes", 1, 0, '2'},
|
||||||
|
{"resize", 1, 0, '3'},
|
||||||
|
{"from", 1, 0, '4'},
|
||||||
|
{"to", 1, 0, '5'},
|
||||||
|
{"network", 1, 0, '6'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add, del, test parser */
|
||||||
|
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipporthash *mydata =
|
||||||
|
(struct ip_set_req_ipporthash *) data;
|
||||||
|
char *saved = ipset_strdup(arg);
|
||||||
|
char *ptr, *tmp = saved;
|
||||||
|
|
||||||
|
DP("ipporthash: %p %p", arg, data);
|
||||||
|
|
||||||
|
ptr = strsep(&tmp, ":%");
|
||||||
|
parse_ip(ptr, &mydata->ip);
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
parse_port(tmp, &mydata->port);
|
||||||
|
else
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"IP address and port must be specified: ip%%port");
|
||||||
|
free(saved);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print and save
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_ipporthash_create *header =
|
||||||
|
(struct ip_set_req_ipporthash_create *) data;
|
||||||
|
struct ip_set_ipporthash *map =
|
||||||
|
(struct ip_set_ipporthash *) set->settype->header;
|
||||||
|
|
||||||
|
memset(map, 0, sizeof(struct ip_set_ipporthash));
|
||||||
|
map->hashsize = header->hashsize;
|
||||||
|
map->probes = header->probes;
|
||||||
|
map->resize = header->resize;
|
||||||
|
map->first_ip = header->from;
|
||||||
|
map->last_ip = header->to;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *mysetdata =
|
||||||
|
(struct ip_set_ipporthash *) set->settype->header;
|
||||||
|
|
||||||
|
printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
|
||||||
|
printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
|
||||||
|
printf(" hashsize: %u", mysetdata->hashsize);
|
||||||
|
printf(" probes: %u", mysetdata->probes);
|
||||||
|
printf(" resize: %u\n", mysetdata->resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *mysetdata =
|
||||||
|
(struct ip_set_ipporthash *) set->settype->header;
|
||||||
|
size_t offset = 0;
|
||||||
|
ip_set_ip_t *ipptr, ip;
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
ipptr = data + offset;
|
||||||
|
if (*ipptr) {
|
||||||
|
ip = (*ipptr>>16) + mysetdata->first_ip;
|
||||||
|
port = (uint16_t) *ipptr;
|
||||||
|
printf("%s:%s\n",
|
||||||
|
ip_tostring(ip, options),
|
||||||
|
port_tostring(port, options));
|
||||||
|
}
|
||||||
|
offset += sizeof(ip_set_ip_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *mysetdata =
|
||||||
|
(struct ip_set_ipporthash *) set->settype->header;
|
||||||
|
|
||||||
|
printf("-N %s %s --from %s",
|
||||||
|
set->name, set->settype->typename,
|
||||||
|
ip_tostring(mysetdata->first_ip, options));
|
||||||
|
printf(" --to %s",
|
||||||
|
ip_tostring(mysetdata->last_ip, options));
|
||||||
|
printf(" --hashsize %u --probes %u --resize %u\n",
|
||||||
|
mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print save for an IP */
|
||||||
|
static void saveips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *mysetdata =
|
||||||
|
(struct ip_set_ipporthash *) set->settype->header;
|
||||||
|
size_t offset = 0;
|
||||||
|
ip_set_ip_t *ipptr, ip;
|
||||||
|
uint16_t port;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
ipptr = data + offset;
|
||||||
|
if (*ipptr) {
|
||||||
|
ip = (*ipptr>>16) + mysetdata->first_ip;
|
||||||
|
port = (uint16_t) *ipptr;
|
||||||
|
printf("-A %s %s:%s\n", set->name,
|
||||||
|
ip_tostring(ip, options),
|
||||||
|
port_tostring(port, options));
|
||||||
|
}
|
||||||
|
offset += sizeof(ip_set_ip_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char buffer[22];
|
||||||
|
|
||||||
|
static char * unpack_ipport_tostring(struct set *set, ip_set_ip_t bip, unsigned options)
|
||||||
|
{
|
||||||
|
struct ip_set_ipporthash *mysetdata =
|
||||||
|
(struct ip_set_ipporthash *) set->settype->header;
|
||||||
|
ip_set_ip_t ip, port;
|
||||||
|
|
||||||
|
ip = (bip>>16) + mysetdata->first_ip;
|
||||||
|
port = (uint16_t) bip;
|
||||||
|
sprintf(buffer, "%s:%s",
|
||||||
|
ip_tostring(ip, options), port_tostring(port, options));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf
|
||||||
|
("-N set ipporthash --from IP --to IP\n"
|
||||||
|
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
|
||||||
|
"-N set ipporthash --network IP/mask\n"
|
||||||
|
" [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
|
||||||
|
"-A set IP:port\n"
|
||||||
|
"-D set IP:port\n"
|
||||||
|
"-T set IP:port\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_ipporthash = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
.create_size = sizeof(struct ip_set_req_ipporthash_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
/* Add/del/test */
|
||||||
|
.adt_size = sizeof(struct ip_set_req_ipporthash),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
/* Printing */
|
||||||
|
.header_size = sizeof(struct ip_set_ipporthash),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printips, /* We only have the unsorted version */
|
||||||
|
.printips_sorted = &printips,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveips,
|
||||||
|
|
||||||
|
/* Bindings */
|
||||||
|
.bindip_tostring = &unpack_ipport_tostring,
|
||||||
|
.bindip_parse = &parse_ip,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void ipporthash_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_ipporthash);
|
||||||
|
|
||||||
|
}
|
226
extensions/ipset/ipset_iptree.c
Normal file
226
extensions/ipset/ipset_iptree.c
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
/* Copyright 2005 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ip_set_iptree.h"
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
#define BUFLEN 30;
|
||||||
|
|
||||||
|
#define OPT_CREATE_TIMEOUT 0x01U
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
static void create_init(void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptree_create *mydata =
|
||||||
|
(struct ip_set_req_iptree_create *) data;
|
||||||
|
|
||||||
|
DP("create INIT");
|
||||||
|
mydata->timeout = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptree_create *mydata =
|
||||||
|
(struct ip_set_req_iptree_create *) data;
|
||||||
|
|
||||||
|
DP("create_parse");
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '1':
|
||||||
|
string_to_number(optarg, 0, UINT_MAX, &mydata->timeout);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_TIMEOUT;
|
||||||
|
|
||||||
|
DP("--timeout %u", mydata->timeout);
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
static void create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create commandline options */
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"timeout", 1, 0, '1'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add, del, test parser */
|
||||||
|
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptree *mydata =
|
||||||
|
(struct ip_set_req_iptree *) data;
|
||||||
|
char *saved = ipset_strdup(arg);
|
||||||
|
char *ptr, *tmp = saved;
|
||||||
|
|
||||||
|
DP("iptree: %p %p", arg, data);
|
||||||
|
|
||||||
|
ptr = strsep(&tmp, ":%");
|
||||||
|
parse_ip(ptr, &mydata->ip);
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
string_to_number(tmp, 0, UINT_MAX, &mydata->timeout);
|
||||||
|
else
|
||||||
|
mydata->timeout = 0;
|
||||||
|
|
||||||
|
free(saved);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print and save
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptree_create *header =
|
||||||
|
(struct ip_set_req_iptree_create *) data;
|
||||||
|
struct ip_set_iptree *map =
|
||||||
|
(struct ip_set_iptree *) set->settype->header;
|
||||||
|
|
||||||
|
map->timeout = header->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *mysetdata =
|
||||||
|
(struct ip_set_iptree *) set->settype->header;
|
||||||
|
|
||||||
|
if (mysetdata->timeout)
|
||||||
|
printf(" timeout: %u", mysetdata->timeout);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printips_sorted(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *mysetdata =
|
||||||
|
(struct ip_set_iptree *) set->settype->header;
|
||||||
|
struct ip_set_req_iptree *req;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
while (len >= offset + sizeof(struct ip_set_req_iptree)) {
|
||||||
|
req = (struct ip_set_req_iptree *)(data + offset);
|
||||||
|
if (mysetdata->timeout)
|
||||||
|
printf("%s:%u\n", ip_tostring(req->ip, options),
|
||||||
|
req->timeout);
|
||||||
|
else
|
||||||
|
printf("%s\n", ip_tostring(req->ip, options));
|
||||||
|
offset += sizeof(struct ip_set_req_iptree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *mysetdata =
|
||||||
|
(struct ip_set_iptree *) set->settype->header;
|
||||||
|
|
||||||
|
if (mysetdata->timeout)
|
||||||
|
printf("-N %s %s --timeout %u\n",
|
||||||
|
set->name, set->settype->typename,
|
||||||
|
mysetdata->timeout);
|
||||||
|
else
|
||||||
|
printf("-N %s %s\n",
|
||||||
|
set->name, set->settype->typename);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iptree *mysetdata =
|
||||||
|
(struct ip_set_iptree *) set->settype->header;
|
||||||
|
struct ip_set_req_iptree *req;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
DP("%s", set->name);
|
||||||
|
|
||||||
|
while (len >= offset + sizeof(struct ip_set_req_iptree)) {
|
||||||
|
req = (struct ip_set_req_iptree *)(data + offset);
|
||||||
|
if (mysetdata->timeout)
|
||||||
|
printf("-A %s %s:%u\n",
|
||||||
|
set->name,
|
||||||
|
ip_tostring(req->ip, options),
|
||||||
|
req->timeout);
|
||||||
|
else
|
||||||
|
printf("-A %s %s\n",
|
||||||
|
set->name,
|
||||||
|
ip_tostring(req->ip, options));
|
||||||
|
offset += sizeof(struct ip_set_req_iptree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf
|
||||||
|
("-N set iptree [--timeout value]\n"
|
||||||
|
"-A set IP[:timeout]\n"
|
||||||
|
"-D set IP\n"
|
||||||
|
"-T set IP\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_iptree = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
.create_size = sizeof(struct ip_set_req_iptree_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
/* Add/del/test */
|
||||||
|
.adt_size = sizeof(struct ip_set_req_iptree),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
/* Printing */
|
||||||
|
.header_size = sizeof(struct ip_set_iptree),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printips_sorted, /* We only have sorted version */
|
||||||
|
.printips_sorted = &printips_sorted,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveips,
|
||||||
|
|
||||||
|
/* Bindings */
|
||||||
|
.bindip_tostring = &binding_ip_tostring,
|
||||||
|
.bindip_parse = &parse_ip,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void iptree_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_iptree);
|
||||||
|
|
||||||
|
}
|
206
extensions/ipset/ipset_iptreemap.c
Normal file
206
extensions/ipset/ipset_iptreemap.c
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
/* Copyright 2007 Sven Wegener <sven.wegener@stealer.net>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the Free
|
||||||
|
* Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
* Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ip_set_iptreemap.h"
|
||||||
|
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
#define OPT_CREATE_GC 0x1
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_init(void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptreemap_create *mydata = data;
|
||||||
|
|
||||||
|
mydata->gc_interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptreemap_create *mydata = data;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'g':
|
||||||
|
string_to_number(optarg, 0, UINT_MAX, &mydata->gc_interval);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_GC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"gc", 1, 0, 'g'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static ip_set_ip_t
|
||||||
|
adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptreemap *mydata = data;
|
||||||
|
ip_set_ip_t mask;
|
||||||
|
|
||||||
|
char *saved = ipset_strdup(arg);
|
||||||
|
char *ptr, *tmp = saved;
|
||||||
|
|
||||||
|
if (strchr(tmp, '/')) {
|
||||||
|
parse_ipandmask(tmp, &mydata->start, &mask);
|
||||||
|
mydata->end = mydata->start | ~mask;
|
||||||
|
} else {
|
||||||
|
ptr = strsep(&tmp, ":");
|
||||||
|
parse_ip(ptr, &mydata->start);
|
||||||
|
|
||||||
|
if (tmp) {
|
||||||
|
parse_ip(tmp, &mydata->end);
|
||||||
|
} else {
|
||||||
|
mydata->end = mydata->start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
const struct ip_set_req_iptreemap_create *header = data;
|
||||||
|
struct ip_set_iptreemap *map = set->settype->header;
|
||||||
|
|
||||||
|
map->gc_interval = header->gc_interval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *mysetdata = set->settype->header;
|
||||||
|
|
||||||
|
if (mysetdata->gc_interval)
|
||||||
|
printf(" gc: %u", mysetdata->gc_interval);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
printips_sorted(struct set *set, void *data, size_t len, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptreemap *req;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
|
||||||
|
req = data + offset;
|
||||||
|
|
||||||
|
printf("%s", ip_tostring(req->start, options));
|
||||||
|
if (req->start != req->end)
|
||||||
|
printf(":%s", ip_tostring(req->end, options));
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
offset += sizeof(struct ip_set_req_iptreemap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_iptreemap *mysetdata = set->settype->header;
|
||||||
|
|
||||||
|
printf("-N %s %s", set->name, set->settype->typename);
|
||||||
|
|
||||||
|
if (mysetdata->gc_interval)
|
||||||
|
printf(" --gc %u", mysetdata->gc_interval);
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
saveips(struct set *set, void *data, size_t len, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_req_iptreemap *req;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
while (len >= offset + sizeof(struct ip_set_req_iptreemap)) {
|
||||||
|
req = data + offset;
|
||||||
|
|
||||||
|
printf("-A %s %s", set->name, ip_tostring(req->start, options));
|
||||||
|
|
||||||
|
if (req->start != req->end)
|
||||||
|
printf(":%s", ip_tostring(req->end, options));
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
offset += sizeof(struct ip_set_req_iptreemap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
printf(
|
||||||
|
"-N set iptreemap --gc interval\n"
|
||||||
|
"-A set IP\n"
|
||||||
|
"-D set IP\n"
|
||||||
|
"-T set IP\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_iptreemap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
.create_size = sizeof(struct ip_set_req_iptreemap_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
.adt_size = sizeof(struct ip_set_req_iptreemap),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
.header_size = sizeof(struct ip_set_iptreemap),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printips_sorted,
|
||||||
|
.printips_sorted = &printips_sorted,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveips,
|
||||||
|
|
||||||
|
.bindip_tostring = &binding_ip_tostring,
|
||||||
|
.bindip_parse = &parse_ip,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void iptreemap_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_iptreemap);
|
||||||
|
}
|
341
extensions/ipset/ipset_macipmap.c
Normal file
341
extensions/ipset/ipset_macipmap.c
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
/* Copyright 2000, 2001, 2002 Joakim Axelsson (gozem@linux.nu)
|
||||||
|
* Patrick Schaaf (bof@bof.de)
|
||||||
|
* Martin Josefsson (gandalf@wlug.westbo.se)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <linux/if_ether.h>
|
||||||
|
|
||||||
|
#include "ip_set_macipmap.h"
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
#define BUFLEN 30;
|
||||||
|
|
||||||
|
#define OPT_CREATE_FROM 0x01U
|
||||||
|
#define OPT_CREATE_TO 0x02U
|
||||||
|
#define OPT_CREATE_NETWORK 0x04U
|
||||||
|
#define OPT_CREATE_MATCHUNSET 0x08U
|
||||||
|
|
||||||
|
#define OPT_ADDDEL_IP 0x01U
|
||||||
|
#define OPT_ADDDEL_MAC 0x02U
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
static void create_init(void *data)
|
||||||
|
{
|
||||||
|
DP("create INIT");
|
||||||
|
/* Nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_macipmap_create *mydata =
|
||||||
|
(struct ip_set_req_macipmap_create *) data;
|
||||||
|
|
||||||
|
DP("create_parse");
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '1':
|
||||||
|
parse_ip(optarg, &mydata->from);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_FROM;
|
||||||
|
|
||||||
|
DP("--from %x (%s)", mydata->from,
|
||||||
|
ip_tostring_numeric(mydata->from));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2':
|
||||||
|
parse_ip(optarg, &mydata->to);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_TO;
|
||||||
|
|
||||||
|
DP("--to %x (%s)", mydata->to,
|
||||||
|
ip_tostring_numeric(mydata->to));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '3':
|
||||||
|
parse_ipandmask(optarg, &mydata->from, &mydata->to);
|
||||||
|
|
||||||
|
/* Make to the last of from + mask */
|
||||||
|
mydata->to = mydata->from | (~mydata->to);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_NETWORK;
|
||||||
|
|
||||||
|
DP("--network from %x (%s)",
|
||||||
|
mydata->from, ip_tostring_numeric(mydata->from));
|
||||||
|
DP("--network to %x (%s)",
|
||||||
|
mydata->to, ip_tostring_numeric(mydata->to));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '4':
|
||||||
|
mydata->flags |= IPSET_MACIP_MATCHUNSET;
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_MATCHUNSET;
|
||||||
|
|
||||||
|
DP("--matchunset");
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
static void create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_macipmap_create *mydata =
|
||||||
|
(struct ip_set_req_macipmap_create *) data;
|
||||||
|
|
||||||
|
if (flags == 0)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify --from and --to, or --network\n");
|
||||||
|
|
||||||
|
if (flags & OPT_CREATE_NETWORK) {
|
||||||
|
/* --network */
|
||||||
|
if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Can't specify --from or --to with --network\n");
|
||||||
|
} else {
|
||||||
|
/* --from --to */
|
||||||
|
if ((flags & OPT_CREATE_FROM) == 0
|
||||||
|
|| (flags & OPT_CREATE_TO) == 0)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify both --from and --to\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DP("from : %x to: %x diff: %d match unset: %d", mydata->from,
|
||||||
|
mydata->to, mydata->to - mydata->from,
|
||||||
|
flags & OPT_CREATE_MATCHUNSET);
|
||||||
|
|
||||||
|
if (mydata->from > mydata->to)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"From can't be lower than to.\n");
|
||||||
|
|
||||||
|
if (mydata->to - mydata->from > MAX_RANGE)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Range too large. Max is %d IPs in range\n",
|
||||||
|
MAX_RANGE+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create commandline options */
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"from", 1, 0, '1'},
|
||||||
|
{"to", 1, 0, '2'},
|
||||||
|
{"network", 1, 0, '3'},
|
||||||
|
{"matchunset", 0, 0, '4'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void parse_mac(const char *mac, unsigned char *ethernet)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
|
||||||
|
if (strlen(mac) != ETH_ALEN * 3 - 1)
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Bad mac address `%s'", mac);
|
||||||
|
|
||||||
|
for (i = 0; i < ETH_ALEN; i++) {
|
||||||
|
long number;
|
||||||
|
char *end;
|
||||||
|
|
||||||
|
number = strtol(mac + i * 3, &end, 16);
|
||||||
|
|
||||||
|
if (end == mac + i * 3 + 2 && number >= 0 && number <= 255)
|
||||||
|
ethernet[i] = number;
|
||||||
|
else
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Bad mac address `%s'", mac);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add, del, test parser */
|
||||||
|
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_macipmap *mydata =
|
||||||
|
(struct ip_set_req_macipmap *) data;
|
||||||
|
char *saved = ipset_strdup(arg);
|
||||||
|
char *ptr, *tmp = saved;
|
||||||
|
|
||||||
|
DP("macipmap: %p %p", arg, data);
|
||||||
|
|
||||||
|
ptr = strsep(&tmp, ":%");
|
||||||
|
parse_ip(ptr, &mydata->ip);
|
||||||
|
|
||||||
|
if (tmp)
|
||||||
|
parse_mac(tmp, mydata->ethernet);
|
||||||
|
else
|
||||||
|
memset(mydata->ethernet, 0, ETH_ALEN);
|
||||||
|
|
||||||
|
free(saved);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print and save
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_macipmap_create *header =
|
||||||
|
(struct ip_set_req_macipmap_create *) data;
|
||||||
|
struct ip_set_macipmap *map =
|
||||||
|
(struct ip_set_macipmap *) set->settype->header;
|
||||||
|
|
||||||
|
memset(map, 0, sizeof(struct ip_set_macipmap));
|
||||||
|
map->first_ip = header->from;
|
||||||
|
map->last_ip = header->to;
|
||||||
|
map->flags = header->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *mysetdata =
|
||||||
|
(struct ip_set_macipmap *) set->settype->header;
|
||||||
|
|
||||||
|
printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
|
||||||
|
printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
|
||||||
|
|
||||||
|
if (mysetdata->flags & IPSET_MACIP_MATCHUNSET)
|
||||||
|
printf(" matchunset");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_mac(unsigned char macaddress[ETH_ALEN])
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
printf("%02X", macaddress[0]);
|
||||||
|
for (i = 1; i < ETH_ALEN; i++)
|
||||||
|
printf(":%02X", macaddress[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printips_sorted(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *mysetdata =
|
||||||
|
(struct ip_set_macipmap *) set->settype->header;
|
||||||
|
struct ip_set_macip *table =
|
||||||
|
(struct ip_set_macip *) data;
|
||||||
|
u_int32_t addr = mysetdata->first_ip;
|
||||||
|
|
||||||
|
while (addr <= mysetdata->last_ip) {
|
||||||
|
if (test_bit(IPSET_MACIP_ISSET,
|
||||||
|
(void *)&table[addr - mysetdata->first_ip].flags)) {
|
||||||
|
printf("%s:", ip_tostring(addr, options));
|
||||||
|
print_mac(table[addr - mysetdata->first_ip].
|
||||||
|
ethernet);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *mysetdata =
|
||||||
|
(struct ip_set_macipmap *) set->settype->header;
|
||||||
|
|
||||||
|
printf("-N %s %s --from %s",
|
||||||
|
set->name, set->settype->typename,
|
||||||
|
ip_tostring(mysetdata->first_ip, options));
|
||||||
|
printf(" --to %s", ip_tostring(mysetdata->last_ip, options));
|
||||||
|
|
||||||
|
if (mysetdata->flags & IPSET_MACIP_MATCHUNSET)
|
||||||
|
printf(" --matchunset");
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_macipmap *mysetdata =
|
||||||
|
(struct ip_set_macipmap *) set->settype->header;
|
||||||
|
struct ip_set_macip *table =
|
||||||
|
(struct ip_set_macip *) data;
|
||||||
|
u_int32_t addr = mysetdata->first_ip;
|
||||||
|
|
||||||
|
while (addr <= mysetdata->last_ip) {
|
||||||
|
if (test_bit(IPSET_MACIP_ISSET,
|
||||||
|
(void *)&table[addr - mysetdata->first_ip].flags)) {
|
||||||
|
printf("-A %s %s:",
|
||||||
|
set->name, ip_tostring(addr, options));
|
||||||
|
print_mac(table[addr - mysetdata->first_ip].
|
||||||
|
ethernet);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf
|
||||||
|
("-N set macipmap --from IP --to IP [--matchunset]\n"
|
||||||
|
"-N set macipmap --network IP/mask [--matchunset]\n"
|
||||||
|
"-A set IP:MAC\n"
|
||||||
|
"-D set IP[:MAC]\n"
|
||||||
|
"-T set IP[:MAC]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_macipmap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
.create_size = sizeof(struct ip_set_req_macipmap_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
/* Add/del/test */
|
||||||
|
.adt_size = sizeof(struct ip_set_req_macipmap),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
/* Printing */
|
||||||
|
.header_size = sizeof(struct ip_set_macipmap),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printips_sorted, /* We only have sorted version */
|
||||||
|
.printips_sorted = &printips_sorted,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveips,
|
||||||
|
|
||||||
|
/* Bindings */
|
||||||
|
.bindip_tostring = &binding_ip_tostring,
|
||||||
|
.bindip_parse = &parse_ip,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void macipmap_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_macipmap);
|
||||||
|
|
||||||
|
}
|
352
extensions/ipset/ipset_nethash.c
Normal file
352
extensions/ipset/ipset_nethash.c
Normal file
@@ -0,0 +1,352 @@
|
|||||||
|
/* Copyright 2004 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <asm/types.h>
|
||||||
|
|
||||||
|
#include "ip_set_nethash.h"
|
||||||
|
#include "ip_set_jhash.h"
|
||||||
|
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
#define BUFLEN 30;
|
||||||
|
|
||||||
|
#define OPT_CREATE_HASHSIZE 0x01U
|
||||||
|
#define OPT_CREATE_PROBES 0x02U
|
||||||
|
#define OPT_CREATE_RESIZE 0x04U
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
static void create_init(void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_nethash_create *mydata =
|
||||||
|
(struct ip_set_req_nethash_create *) data;
|
||||||
|
|
||||||
|
DP("create INIT");
|
||||||
|
|
||||||
|
/* Default create parameters */
|
||||||
|
mydata->hashsize = 1024;
|
||||||
|
mydata->probes = 4;
|
||||||
|
mydata->resize = 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_nethash_create *mydata =
|
||||||
|
(struct ip_set_req_nethash_create *) data;
|
||||||
|
ip_set_ip_t value;
|
||||||
|
|
||||||
|
DP("create_parse");
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '1':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 1, UINT_MAX - 1, &mydata->hashsize))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid hashsize `%s' specified", optarg);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_HASHSIZE;
|
||||||
|
|
||||||
|
DP("--hashsize %u", mydata->hashsize);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 1, 65535, &value))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid probes `%s' specified", optarg);
|
||||||
|
|
||||||
|
mydata->probes = value;
|
||||||
|
*flags |= OPT_CREATE_PROBES;
|
||||||
|
|
||||||
|
DP("--probes %u", mydata->probes);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '3':
|
||||||
|
|
||||||
|
if (string_to_number(optarg, 0, 65535, &value))
|
||||||
|
exit_error(PARAMETER_PROBLEM, "Invalid resize `%s' specified", optarg);
|
||||||
|
|
||||||
|
mydata->resize = value;
|
||||||
|
*flags |= OPT_CREATE_RESIZE;
|
||||||
|
|
||||||
|
DP("--resize %u", mydata->resize);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
static void create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
#ifdef IPSET_DEBUG
|
||||||
|
struct ip_set_req_nethash_create *mydata =
|
||||||
|
(struct ip_set_req_nethash_create *) data;
|
||||||
|
|
||||||
|
DP("hashsize %u probes %u resize %u",
|
||||||
|
mydata->hashsize, mydata->probes, mydata->resize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create commandline options */
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"hashsize", 1, 0, '1'},
|
||||||
|
{"probes", 1, 0, '2'},
|
||||||
|
{"resize", 1, 0, '3'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add, del, test parser */
|
||||||
|
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_nethash *mydata =
|
||||||
|
(struct ip_set_req_nethash *) data;
|
||||||
|
char *saved = ipset_strdup(arg);
|
||||||
|
char *ptr, *tmp = saved;
|
||||||
|
ip_set_ip_t cidr;
|
||||||
|
|
||||||
|
ptr = strsep(&tmp, "/");
|
||||||
|
|
||||||
|
if (tmp == NULL) {
|
||||||
|
if (cmd == CMD_TEST)
|
||||||
|
cidr = 32;
|
||||||
|
else
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Missing cidr from `%s'", arg);
|
||||||
|
} else
|
||||||
|
if (string_to_number(tmp, 1, 31, &cidr))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Out of range cidr `%s' specified", arg);
|
||||||
|
|
||||||
|
mydata->cidr = cidr;
|
||||||
|
parse_ip(ptr, &mydata->ip);
|
||||||
|
if (!mydata->ip)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Zero valued IP address `%s' specified", ptr);
|
||||||
|
free(saved);
|
||||||
|
|
||||||
|
return mydata->ip;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print and save
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_nethash_create *header =
|
||||||
|
(struct ip_set_req_nethash_create *) data;
|
||||||
|
struct ip_set_nethash *map =
|
||||||
|
(struct ip_set_nethash *) set->settype->header;
|
||||||
|
|
||||||
|
memset(map, 0, sizeof(struct ip_set_nethash));
|
||||||
|
map->hashsize = header->hashsize;
|
||||||
|
map->probes = header->probes;
|
||||||
|
map->resize = header->resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *mysetdata =
|
||||||
|
(struct ip_set_nethash *) set->settype->header;
|
||||||
|
|
||||||
|
printf(" hashsize: %u", mysetdata->hashsize);
|
||||||
|
printf(" probes: %u", mysetdata->probes);
|
||||||
|
printf(" resize: %u\n", mysetdata->resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char buf[20];
|
||||||
|
|
||||||
|
static char * unpack_ip_tostring(ip_set_ip_t ip, unsigned options)
|
||||||
|
{
|
||||||
|
int i, j = 3;
|
||||||
|
unsigned char a, b;
|
||||||
|
|
||||||
|
ip = htonl(ip);
|
||||||
|
for (i = 3; i >= 0; i--)
|
||||||
|
if (((unsigned char *)&ip)[i] != 0) {
|
||||||
|
j = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
a = ((unsigned char *)&ip)[j];
|
||||||
|
if (a <= 128) {
|
||||||
|
a = (a - 1) * 2;
|
||||||
|
b = 7;
|
||||||
|
} else if (a <= 192) {
|
||||||
|
a = (a - 129) * 4;
|
||||||
|
b = 6;
|
||||||
|
} else if (a <= 224) {
|
||||||
|
a = (a - 193) * 8;
|
||||||
|
b = 5;
|
||||||
|
} else if (a <= 240) {
|
||||||
|
a = (a - 225) * 16;
|
||||||
|
b = 4;
|
||||||
|
} else if (a <= 248) {
|
||||||
|
a = (a - 241) * 32;
|
||||||
|
b = 3;
|
||||||
|
} else if (a <= 252) {
|
||||||
|
a = (a - 249) * 64;
|
||||||
|
b = 2;
|
||||||
|
} else if (a <= 254) {
|
||||||
|
a = (a - 253) * 128;
|
||||||
|
b = 1;
|
||||||
|
} else {
|
||||||
|
a = b = 0;
|
||||||
|
}
|
||||||
|
((unsigned char *)&ip)[j] = a;
|
||||||
|
b += j * 8;
|
||||||
|
|
||||||
|
sprintf(buf, "%u.%u.%u.%u/%u",
|
||||||
|
((unsigned char *)&ip)[0],
|
||||||
|
((unsigned char *)&ip)[1],
|
||||||
|
((unsigned char *)&ip)[2],
|
||||||
|
((unsigned char *)&ip)[3],
|
||||||
|
b);
|
||||||
|
|
||||||
|
DP("%s %s", ip_tostring(ntohl(ip), options), buf);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
ip_set_ip_t *ip;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
ip = data + offset;
|
||||||
|
if (*ip)
|
||||||
|
printf("%s\n", unpack_ip_tostring(*ip, options));
|
||||||
|
offset += sizeof(ip_set_ip_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_nethash *mysetdata =
|
||||||
|
(struct ip_set_nethash *) set->settype->header;
|
||||||
|
|
||||||
|
printf("-N %s %s --hashsize %u --probes %u --resize %u\n",
|
||||||
|
set->name, set->settype->typename,
|
||||||
|
mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print save for an IP */
|
||||||
|
static void saveips(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
size_t offset = 0;
|
||||||
|
ip_set_ip_t *ip;
|
||||||
|
|
||||||
|
while (offset < len) {
|
||||||
|
ip = data + offset;
|
||||||
|
if (*ip)
|
||||||
|
printf("-A %s %s\n", set->name,
|
||||||
|
unpack_ip_tostring(*ip, options));
|
||||||
|
offset += sizeof(ip_set_ip_t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char * net_tostring(struct set *set, ip_set_ip_t ip, unsigned options)
|
||||||
|
{
|
||||||
|
return unpack_ip_tostring(ip, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_net(const char *str, ip_set_ip_t *ip)
|
||||||
|
{
|
||||||
|
char *saved = strdup(str);
|
||||||
|
char *ptr, *tmp = saved;
|
||||||
|
ip_set_ip_t cidr;
|
||||||
|
|
||||||
|
ptr = strsep(&tmp, "/");
|
||||||
|
|
||||||
|
if (tmp == NULL)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Missing cidr from `%s'", str);
|
||||||
|
|
||||||
|
if (string_to_number(tmp, 1, 31, &cidr))
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Out of range cidr `%s' specified", str);
|
||||||
|
|
||||||
|
parse_ip(ptr, ip);
|
||||||
|
free(saved);
|
||||||
|
|
||||||
|
*ip = pack(*ip, cidr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf
|
||||||
|
("-N set nethash [--hashsize hashsize] [--probes probes ]\n"
|
||||||
|
" [--resize resize]\n"
|
||||||
|
"-A set IP/cidr\n"
|
||||||
|
"-D set IP/cidr\n"
|
||||||
|
"-T set IP/cidr\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_nethash = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
.create_size = sizeof(struct ip_set_req_nethash_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
/* Add/del/test */
|
||||||
|
.adt_size = sizeof(struct ip_set_req_nethash),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
/* Printing */
|
||||||
|
.header_size = sizeof(struct ip_set_nethash),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printips, /* We only have the unsorted version */
|
||||||
|
.printips_sorted = &printips,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveips,
|
||||||
|
|
||||||
|
/* Bindings */
|
||||||
|
.bindip_tostring = &net_tostring,
|
||||||
|
.bindip_parse = &parse_net,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void nethash_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_nethash);
|
||||||
|
|
||||||
|
}
|
247
extensions/ipset/ipset_portmap.c
Normal file
247
extensions/ipset/ipset_portmap.c
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/* Copyright 2004 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include "ip_set_portmap.h"
|
||||||
|
#include "ipset.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BUFLEN 30;
|
||||||
|
|
||||||
|
#define OPT_CREATE_FROM 0x01U
|
||||||
|
#define OPT_CREATE_TO 0x02U
|
||||||
|
|
||||||
|
#define OPT_ADDDEL_PORT 0x01U
|
||||||
|
|
||||||
|
/* Initialize the create. */
|
||||||
|
static void create_init(void *data)
|
||||||
|
{
|
||||||
|
DP("create INIT");
|
||||||
|
/* Nothing */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function which parses command options; returns true if it ate an option */
|
||||||
|
static int create_parse(int c, char *argv[], void *data, unsigned int *flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_portmap_create *mydata =
|
||||||
|
(struct ip_set_req_portmap_create *) data;
|
||||||
|
|
||||||
|
DP("create_parse");
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case '1':
|
||||||
|
parse_port(optarg, &mydata->from);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_FROM;
|
||||||
|
|
||||||
|
DP("--from %x (%s)", mydata->from,
|
||||||
|
port_tostring(mydata->from, 0));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '2':
|
||||||
|
parse_port(optarg, &mydata->to);
|
||||||
|
|
||||||
|
*flags |= OPT_CREATE_TO;
|
||||||
|
|
||||||
|
DP("--to %x (%s)", mydata->to,
|
||||||
|
port_tostring(mydata->to, 0));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Final check; exit if not ok. */
|
||||||
|
static void create_final(void *data, unsigned int flags)
|
||||||
|
{
|
||||||
|
struct ip_set_req_portmap_create *mydata =
|
||||||
|
(struct ip_set_req_portmap_create *) data;
|
||||||
|
|
||||||
|
if (flags == 0) {
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify --from and --to\n");
|
||||||
|
} else {
|
||||||
|
/* --from --to */
|
||||||
|
if ((flags & OPT_CREATE_FROM) == 0
|
||||||
|
|| (flags & OPT_CREATE_TO) == 0)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Need to specify both --from and --to\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
DP("from : %x to: %x diff: %d", mydata->from, mydata->to,
|
||||||
|
mydata->to - mydata->from);
|
||||||
|
|
||||||
|
if (mydata->from > mydata->to)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"From can't be lower than to.\n");
|
||||||
|
|
||||||
|
if (mydata->to - mydata->from > MAX_RANGE)
|
||||||
|
exit_error(PARAMETER_PROBLEM,
|
||||||
|
"Range too large. Max is %d ports in range\n",
|
||||||
|
MAX_RANGE+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create commandline options */
|
||||||
|
static const struct option create_opts[] = {
|
||||||
|
{"from", 1, 0, '1'},
|
||||||
|
{"to", 1, 0, '2'},
|
||||||
|
{NULL},
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Add, del, test parser */
|
||||||
|
static ip_set_ip_t adt_parser(unsigned int cmd, const char *arg, void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_portmap *mydata =
|
||||||
|
(struct ip_set_req_portmap *) data;
|
||||||
|
|
||||||
|
parse_port(arg, &mydata->port);
|
||||||
|
DP("%s", port_tostring(mydata->port, 0));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print and save
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void initheader(struct set *set, const void *data)
|
||||||
|
{
|
||||||
|
struct ip_set_req_portmap_create *header =
|
||||||
|
(struct ip_set_req_portmap_create *) data;
|
||||||
|
struct ip_set_portmap *map =
|
||||||
|
(struct ip_set_portmap *) set->settype->header;
|
||||||
|
|
||||||
|
memset(map, 0, sizeof(struct ip_set_portmap));
|
||||||
|
map->first_port = header->from;
|
||||||
|
map->last_port = header->to;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *mysetdata =
|
||||||
|
(struct ip_set_portmap *) set->settype->header;
|
||||||
|
|
||||||
|
printf(" from: %s", port_tostring(mysetdata->first_port, options));
|
||||||
|
printf(" to: %s\n", port_tostring(mysetdata->last_port, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printports_sorted(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *mysetdata =
|
||||||
|
(struct ip_set_portmap *) set->settype->header;
|
||||||
|
u_int32_t addr = mysetdata->first_port;
|
||||||
|
|
||||||
|
DP("%u -- %u", mysetdata->first_port, mysetdata->last_port);
|
||||||
|
while (addr <= mysetdata->last_port) {
|
||||||
|
if (test_bit(addr - mysetdata->first_port, data))
|
||||||
|
printf("%s\n", port_tostring(addr, options));
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *binding_port_tostring(struct set *set, ip_set_ip_t ip,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
return port_tostring(ip, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveheader(struct set *set, unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *mysetdata =
|
||||||
|
(struct ip_set_portmap *) set->settype->header;
|
||||||
|
|
||||||
|
printf("-N %s %s --from %s",
|
||||||
|
set->name,
|
||||||
|
set->settype->typename,
|
||||||
|
port_tostring(mysetdata->first_port, options));
|
||||||
|
printf(" --to %s\n",
|
||||||
|
port_tostring(mysetdata->last_port, options));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void saveports(struct set *set, void *data, size_t len,
|
||||||
|
unsigned int options)
|
||||||
|
{
|
||||||
|
struct ip_set_portmap *mysetdata =
|
||||||
|
(struct ip_set_portmap *) set->settype->header;
|
||||||
|
u_int32_t addr = mysetdata->first_port;
|
||||||
|
|
||||||
|
while (addr <= mysetdata->last_port) {
|
||||||
|
if (test_bit(addr - mysetdata->first_port, data))
|
||||||
|
printf("-A %s %s\n",
|
||||||
|
set->name,
|
||||||
|
port_tostring(addr, options));
|
||||||
|
addr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(void)
|
||||||
|
{
|
||||||
|
printf
|
||||||
|
("-N set portmap --from PORT --to PORT\n"
|
||||||
|
"-A set PORT\n"
|
||||||
|
"-D set PORT\n"
|
||||||
|
"-T set PORT\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct settype settype_portmap = {
|
||||||
|
.typename = SETTYPE_NAME,
|
||||||
|
.protocol_version = IP_SET_PROTOCOL_VERSION,
|
||||||
|
|
||||||
|
/* Create */
|
||||||
|
.create_size = sizeof(struct ip_set_req_portmap_create),
|
||||||
|
.create_init = &create_init,
|
||||||
|
.create_parse = &create_parse,
|
||||||
|
.create_final = &create_final,
|
||||||
|
.create_opts = create_opts,
|
||||||
|
|
||||||
|
/* Add/del/test */
|
||||||
|
.adt_size = sizeof(struct ip_set_req_portmap),
|
||||||
|
.adt_parser = &adt_parser,
|
||||||
|
|
||||||
|
/* Printing */
|
||||||
|
.header_size = sizeof(struct ip_set_portmap),
|
||||||
|
.initheader = &initheader,
|
||||||
|
.printheader = &printheader,
|
||||||
|
.printips = &printports_sorted, /* We only have sorted version */
|
||||||
|
.printips_sorted = &printports_sorted,
|
||||||
|
.saveheader = &saveheader,
|
||||||
|
.saveips = &saveports,
|
||||||
|
|
||||||
|
/* Bindings */
|
||||||
|
.bindip_tostring = &binding_port_tostring,
|
||||||
|
.bindip_parse = &parse_port,
|
||||||
|
|
||||||
|
.usage = &usage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static __attribute__((constructor)) void portmap_init(void)
|
||||||
|
{
|
||||||
|
settype_register(&settype_portmap);
|
||||||
|
|
||||||
|
}
|
179
extensions/ipset/ipt_SET.c
Normal file
179
extensions/ipset/ipt_SET.c
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
|
* Patrick Schaaf <bof@bof.de>
|
||||||
|
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||||
|
* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ipt_SET.c - netfilter target to manipulate IP sets */
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/netfilter.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <linux/inetdevice.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <net/protocol.h>
|
||||||
|
#include <net/checksum.h>
|
||||||
|
#include <linux/netfilter_ipv4.h>
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ipt_set.h"
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
|
||||||
|
target(struct sk_buff *skb,
|
||||||
|
#else
|
||||||
|
target(struct sk_buff **pskb,
|
||||||
|
#endif
|
||||||
|
const struct net_device *in,
|
||||||
|
const struct net_device *out,
|
||||||
|
unsigned int hooknum,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
const struct xt_target *target,
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
const void *targinfo,
|
||||||
|
void *userinfo)
|
||||||
|
#else
|
||||||
|
const void *targinfo)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
const struct ipt_set_info_target *info = targinfo;
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
|
||||||
|
struct sk_buff *skb = *pskb;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
if (info->add_set.index != IP_SET_INVALID_ID)
|
||||||
|
ip_set_addip_kernel(info->add_set.index,
|
||||||
|
skb,
|
||||||
|
info->add_set.flags);
|
||||||
|
if (info->del_set.index != IP_SET_INVALID_ID)
|
||||||
|
ip_set_delip_kernel(info->del_set.index,
|
||||||
|
skb,
|
||||||
|
info->del_set.flags);
|
||||||
|
|
||||||
|
return IPT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
static bool
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
#endif
|
||||||
|
checkentry(const char *tablename,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
|
||||||
|
const void *e,
|
||||||
|
#else
|
||||||
|
const struct ipt_entry *e,
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
const struct xt_target *target,
|
||||||
|
#endif
|
||||||
|
void *targinfo,
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
unsigned int targinfosize,
|
||||||
|
#endif
|
||||||
|
unsigned int hook_mask)
|
||||||
|
{
|
||||||
|
struct ipt_set_info_target *info = targinfo;
|
||||||
|
ip_set_id_t index;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
if (targinfosize != IPT_ALIGN(sizeof(*info))) {
|
||||||
|
DP("bad target info size %u", targinfosize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (info->add_set.index != IP_SET_INVALID_ID) {
|
||||||
|
index = ip_set_get_byindex(info->add_set.index);
|
||||||
|
if (index == IP_SET_INVALID_ID) {
|
||||||
|
ip_set_printk("cannot find add_set index %u as target",
|
||||||
|
info->add_set.index);
|
||||||
|
return 0; /* error */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->del_set.index != IP_SET_INVALID_ID) {
|
||||||
|
index = ip_set_get_byindex(info->del_set.index);
|
||||||
|
if (index == IP_SET_INVALID_ID) {
|
||||||
|
ip_set_printk("cannot find del_set index %u as target",
|
||||||
|
info->del_set.index);
|
||||||
|
return 0; /* error */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info->add_set.flags[IP_SET_MAX_BINDINGS] != 0
|
||||||
|
|| info->del_set.flags[IP_SET_MAX_BINDINGS] != 0) {
|
||||||
|
ip_set_printk("That's nasty!");
|
||||||
|
return 0; /* error */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
const struct xt_target *target,
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
void *targetinfo, unsigned int targetsize)
|
||||||
|
#else
|
||||||
|
void *targetinfo)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct ipt_set_info_target *info = targetinfo;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
if (targetsize != IPT_ALIGN(sizeof(struct ipt_set_info_target))) {
|
||||||
|
ip_set_printk("invalid targetsize %d", targetsize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (info->add_set.index != IP_SET_INVALID_ID)
|
||||||
|
ip_set_put(info->add_set.index);
|
||||||
|
if (info->del_set.index != IP_SET_INVALID_ID)
|
||||||
|
ip_set_put(info->del_set.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ipt_target SET_target = {
|
||||||
|
.name = "SET",
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
||||||
|
.family = AF_INET,
|
||||||
|
#endif
|
||||||
|
.target = target,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
.targetsize = sizeof(struct ipt_set_info_target),
|
||||||
|
#endif
|
||||||
|
.checkentry = checkentry,
|
||||||
|
.destroy = destroy,
|
||||||
|
.me = THIS_MODULE
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("iptables IP set target module");
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
||||||
|
#define ipt_register_target xt_register_target
|
||||||
|
#define ipt_unregister_target xt_unregister_target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int __init ipt_SET_init(void)
|
||||||
|
{
|
||||||
|
return ipt_register_target(&SET_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ipt_SET_fini(void)
|
||||||
|
{
|
||||||
|
ipt_unregister_target(&SET_target);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ipt_SET_init);
|
||||||
|
module_exit(ipt_SET_fini);
|
159
extensions/ipset/ipt_set.c
Normal file
159
extensions/ipset/ipt_set.c
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
|
||||||
|
* Patrick Schaaf <bof@bof.de>
|
||||||
|
* Martin Josefsson <gandalf@wlug.westbo.se>
|
||||||
|
* Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Kernel module to match an IP set. */
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ip.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
#include <linux/netfilter_ipv4/ip_tables.h>
|
||||||
|
#include "ip_set.h"
|
||||||
|
#include "ipt_set.h"
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
match_set(const struct ipt_set_info *info,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
int inv)
|
||||||
|
{
|
||||||
|
if (ip_set_testip_kernel(info->index, skb, info->flags))
|
||||||
|
inv = !inv;
|
||||||
|
return inv;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
static bool
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
#endif
|
||||||
|
match(const struct sk_buff *skb,
|
||||||
|
const struct net_device *in,
|
||||||
|
const struct net_device *out,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
const struct xt_match *match,
|
||||||
|
#endif
|
||||||
|
const void *matchinfo,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
int offset, unsigned int protoff, bool *hotdrop)
|
||||||
|
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
|
||||||
|
int offset, unsigned int protoff, int *hotdrop)
|
||||||
|
#else
|
||||||
|
int offset, int *hotdrop)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
const struct ipt_set_info_match *info = matchinfo;
|
||||||
|
|
||||||
|
return match_set(&info->match_set,
|
||||||
|
skb,
|
||||||
|
info->match_set.flags[0] & IPSET_MATCH_INV);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
|
||||||
|
static bool
|
||||||
|
#else
|
||||||
|
static int
|
||||||
|
#endif
|
||||||
|
checkentry(const char *tablename,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
|
||||||
|
const void *inf,
|
||||||
|
#else
|
||||||
|
const struct ipt_ip *ip,
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
const struct xt_match *match,
|
||||||
|
#endif
|
||||||
|
void *matchinfo,
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
unsigned int matchsize,
|
||||||
|
#endif
|
||||||
|
unsigned int hook_mask)
|
||||||
|
{
|
||||||
|
struct ipt_set_info_match *info = matchinfo;
|
||||||
|
ip_set_id_t index;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
|
||||||
|
ip_set_printk("invalid matchsize %d", matchsize);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
index = ip_set_get_byindex(info->match_set.index);
|
||||||
|
|
||||||
|
if (index == IP_SET_INVALID_ID) {
|
||||||
|
ip_set_printk("Cannot find set indentified by id %u to match",
|
||||||
|
info->match_set.index);
|
||||||
|
return 0; /* error */
|
||||||
|
}
|
||||||
|
if (info->match_set.flags[IP_SET_MAX_BINDINGS] != 0) {
|
||||||
|
ip_set_printk("That's nasty!");
|
||||||
|
return 0; /* error */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
const struct xt_match *match,
|
||||||
|
#endif
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
void *matchinfo, unsigned int matchsize)
|
||||||
|
#else
|
||||||
|
void *matchinfo)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct ipt_set_info_match *info = matchinfo;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
|
||||||
|
if (matchsize != IPT_ALIGN(sizeof(struct ipt_set_info_match))) {
|
||||||
|
ip_set_printk("invalid matchsize %d", matchsize);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
ip_set_put(info->match_set.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ipt_match set_match = {
|
||||||
|
.name = "set",
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
||||||
|
.family = AF_INET,
|
||||||
|
#endif
|
||||||
|
.match = &match,
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,17)
|
||||||
|
.matchsize = sizeof(struct ipt_set_info_match),
|
||||||
|
#endif
|
||||||
|
.checkentry = &checkentry,
|
||||||
|
.destroy = &destroy,
|
||||||
|
.me = THIS_MODULE
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
|
||||||
|
MODULE_DESCRIPTION("iptables IP set match module");
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
|
||||||
|
#define ipt_register_match xt_register_match
|
||||||
|
#define ipt_unregister_match xt_unregister_match
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int __init ipt_ipset_init(void)
|
||||||
|
{
|
||||||
|
return ipt_register_match(&set_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit ipt_ipset_fini(void)
|
||||||
|
{
|
||||||
|
ipt_unregister_match(&set_match);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(ipt_ipset_init);
|
||||||
|
module_exit(ipt_ipset_fini);
|
21
extensions/ipset/ipt_set.h
Normal file
21
extensions/ipset/ipt_set.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _IPT_SET_H
|
||||||
|
#define _IPT_SET_H
|
||||||
|
|
||||||
|
#include "ip_set.h"
|
||||||
|
|
||||||
|
struct ipt_set_info {
|
||||||
|
ip_set_id_t index;
|
||||||
|
u_int32_t flags[IP_SET_MAX_BINDINGS + 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* match info */
|
||||||
|
struct ipt_set_info_match {
|
||||||
|
struct ipt_set_info match_set;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipt_set_info_target {
|
||||||
|
struct ipt_set_info add_set;
|
||||||
|
struct ipt_set_info del_set;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*_IPT_SET_H*/
|
Reference in New Issue
Block a user