From 0278351a9b9208272449ce4d875e265f6a54aee5 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Thu, 22 Apr 2010 16:42:58 +0200 Subject: First staget to ipset-5 Create src/ and move ipset source there. Get rid of unnecessary and outdated files. --- Makefile | 139 --- TODO | 2 - ipset.8 | 537 ------------ ipset.c | 2054 --------------------------------------------- ipset.h | 200 ----- ipset_iphash.c | 279 ------ ipset_ipmap.c | 376 --------- ipset_ipporthash.c | 350 -------- ipset_ipportiphash.c | 361 -------- ipset_ipportnethash.c | 426 ---------- ipset_iptree.c | 224 ----- ipset_iptreemap.c | 208 ----- ipset_macipmap.c | 382 --------- ipset_nethash.c | 308 ------- ipset_portmap.c | 272 ------ ipset_setlist.c | 229 ----- libipt_set.h | 45 - src/ipset.8 | 537 ++++++++++++ src/ipset.c | 2054 +++++++++++++++++++++++++++++++++++++++++++++ src/ipset.h | 200 +++++ src/ipset_iphash.c | 279 ++++++ src/ipset_ipmap.c | 376 +++++++++ src/ipset_ipporthash.c | 350 ++++++++ src/ipset_ipportiphash.c | 361 ++++++++ src/ipset_ipportnethash.c | 426 ++++++++++ src/ipset_iptree.c | 224 +++++ src/ipset_iptreemap.c | 208 +++++ src/ipset_macipmap.c | 382 +++++++++ src/ipset_nethash.c | 308 +++++++ src/ipset_portmap.c | 272 ++++++ src/ipset_setlist.c | 229 +++++ 31 files changed, 6206 insertions(+), 6392 deletions(-) delete mode 100644 Makefile delete mode 100644 TODO delete mode 100644 ipset.8 delete mode 100644 ipset.c delete mode 100644 ipset.h delete mode 100644 ipset_iphash.c delete mode 100644 ipset_ipmap.c delete mode 100644 ipset_ipporthash.c delete mode 100644 ipset_ipportiphash.c delete mode 100644 ipset_ipportnethash.c delete mode 100644 ipset_iptree.c delete mode 100644 ipset_iptreemap.c delete mode 100644 ipset_macipmap.c delete mode 100644 ipset_nethash.c delete mode 100644 ipset_portmap.c delete mode 100644 ipset_setlist.c delete mode 100644 libipt_set.h create mode 100644 src/ipset.8 create mode 100644 src/ipset.c create mode 100644 src/ipset.h create mode 100644 src/ipset_iphash.c create mode 100644 src/ipset_ipmap.c create mode 100644 src/ipset_ipporthash.c create mode 100644 src/ipset_ipportiphash.c create mode 100644 src/ipset_ipportnethash.c create mode 100644 src/ipset_iptree.c create mode 100644 src/ipset_iptreemap.c create mode 100644 src/ipset_macipmap.c create mode 100644 src/ipset_nethash.c create mode 100644 src/ipset_portmap.c create mode 100644 src/ipset_setlist.c diff --git a/Makefile b/Makefile deleted file mode 100644 index bbec449..0000000 --- a/Makefile +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/make - -###################################################################### -# YOU SHOULD NOT NEED TO TOUCH ANYTHING BELOW THIS LINE -###################################################################### - -ifndef KERNEL_DIR -KERNEL_DIR=/lib/modules/`uname -r`/build -endif -ifndef KBUILD_OUTPUT -KBUILD_OUTPUT=$(KERNEL_DIR) -endif -ifndef IP_NF_SET_MAX -IP_NF_SET_MAX=256 -endif -ifndef IP_NF_SET_HASHSIZE -IP_NF_SET_HASHSIZE=1024 -endif -ifndef V -V=0 -endif - -IPSET_VERSION:=4.2 - -PREFIX:=/usr/local -LIBDIR:=$(PREFIX)/lib -BINDIR:=$(PREFIX)/sbin -MANDIR:=$(PREFIX)/man -INCDIR:=$(PREFIX)/include -IPSET_LIB_DIR:=$(LIBDIR)/ipset - -# directory for new iptables releases -RELEASE_DIR:=/tmp - -COPT_FLAGS:=-O2 -WARN_FLAGS:=-Wall -EXTRA_WARN_FLAGS:=\ - -Wextra \ - -Waggregate-return \ - -Wbad-function-cast \ - -Wcast-align \ - -Wformat=2 \ - -Wfloat-equal \ - -Winit-self \ - -Winline \ - -Wmissing-declarations \ - -Wmissing-prototypes \ - -Wnested-externs \ - -Wold-style-definition \ - -Wpacked \ - -Wredundant-decls \ - -Wshadow \ - -Wsign-compare \ - -Wstrict-prototypes \ - -Wswitch-default \ - -Wswitch-enum \ - -Wundef \ - -Wwrite-strings \ - -Wno-missing-field-initializers \ - -Werror - -ifndef NO_EXTRA_WARN_FLAGS - WARN_FLAGS+=$(EXTRA_WARN_FLAGS) -endif - -ABI_FLAGS:= -CFLAGS:=$(ABI_FLAGS) $(COPT_FLAGS) $(WARN_FLAGS) -Ikernel/include -I. # -g -DIPSET_DEBUG -SH_CFLAGS:=$(CFLAGS) -fPIC -LDFLAGS:=$(ABI_FLAGS) -SETTYPES:=ipmap portmap macipmap -SETTYPES+=iptree iptreemap -SETTYPES+=iphash nethash ipporthash ipportiphash ipportnethash -SETTYPES+=setlist - -PROGRAMS=ipset -SHARED_LIBS=$(foreach T, $(SETTYPES),libipset_$(T).so) -INSTALL=$(DESTDIR)$(BINDIR)/ipset $(DESTDIR)$(MANDIR)/man8/ipset.8 -INSTALL+=$(foreach T, $(SETTYPES), $(DESTDIR)$(LIBDIR)/ipset/libipset_$(T).so) - -all: binaries modules - -.PHONY: tests - -tests: - cd tests; ./runtest.sh - -binaries: $(PROGRAMS) $(SHARED_LIBS) - -binaries_install: binaries $(INSTALL) - -patch_kernel: - cd kernel; ./patch_kernel $(KERNEL_DIR) - -modules: - @[ ! -f $(KERNEL_DIR)/net/ipv4/netfilter/Config.in ] || (echo "Error: The directory '$(KERNEL_DIR)' looks like a Linux 2.4.x kernel source tree, you have to patch it by 'make patch_kernel'." && exit 1) - @[ -f $(KERNEL_DIR)/net/ipv4/netfilter/Kconfig ] || (echo "Error: The directory '$(KERNEL_DIR)' doesn't look like a Linux 2.6.x kernel source tree." && exit 1) - @[ -f $(KBUILD_OUTPUT)/.config ] || (echo "Error: The kernel source in '$(KERNEL_DIR)' must be configured" && exit 1) - @[ -f $(KBUILD_OUTPUT)/Module.symvers ] || echo "Warning: You should run 'make modules' in '$(KERNEL_DIR)' beforehand" - cd kernel; make -C $(KBUILD_OUTPUT) M=`pwd` V=$V IP_NF_SET_MAX=$(IP_NF_SET_MAX) IP_NF_SET_HASHSIZE=$(IP_NF_SET_HASHSIZE) modules - -modules_install: modules - cd kernel; make -C $(KBUILD_OUTPUT) M=`pwd` modules_install - -install: binaries_install modules_install - -clean: $(EXTRA_CLEANS) - rm -rf $(PROGRAMS) $(SHARED_LIBS) *.o *~ tests/*~ - [ -f $(KERNEL_DIR)/net/ipv4/netfilter/Config.in ] || (cd kernel; make -C $(KERNEL_DIR) M=`pwd` clean) - -release: clean - cp -a . /tmp/ipset-$(IPSET_VERSION) - tar cjf ../ipset-$(IPSET_VERSION).tar.bz2 -C /tmp --exclude=.git ipset-$(IPSET_VERSION) - rm -rf /tmp/ipset-$(IPSET_VERSION) - -#The ipset(8) self -ipset.o: ipset.c ipset.h - $(CC) $(CFLAGS) -DIPSET_VERSION=\"$(IPSET_VERSION)\" -DIPSET_LIB_DIR=\"$(IPSET_LIB_DIR)\" -c -o $@ $< - -ipset: ipset.o - $(CC) $(CFLAGS) $(LDFLAGS) -rdynamic -o $@ $^ -ldl - -#Pooltypes -ipset_%.o: ipset_%.c ipset.h - $(CC) $(SH_CFLAGS) -o $@ -c $< - -libipset_%.so: ipset_%.o - $(CC) -shared $(LDFLAGS) -o $@ $< - -$(DESTDIR)$(LIBDIR)/ipset/libipset_%.so: libipset_%.so - @[ -d $(DESTDIR)$(LIBDIR)/ipset ] || mkdir -p $(DESTDIR)$(LIBDIR)/ipset - cp $< $@ - -$(DESTDIR)$(BINDIR)/ipset: ipset - @[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR) - cp $< $@ - -$(DESTDIR)$(MANDIR)/man8/ipset.8: ipset.8 - @[ -d $(DESTDIR)$(MANDIR)/man8 ] || mkdir -p $(DESTDIR)$(MANDIR)/man8 - cp $< $@ diff --git a/TODO b/TODO deleted file mode 100644 index 9d46233..0000000 --- a/TODO +++ /dev/null @@ -1,2 +0,0 @@ -- rewrite kernel-userspace communication from sockopt to netlink -- IPv6 support diff --git a/ipset.8 b/ipset.8 deleted file mode 100644 index fa73298..0000000 --- a/ipset.8 +++ /dev/null @@ -1,537 +0,0 @@ -.TH IPSET 8 "Feb 05, 2004" "" "" -.\" -.\" Man page written by Jozsef Kadlecsik -.\" -.\" 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 \(em administration tool for IP sets -.SH SYNOPSIS -.PP -\fBipset \-N\fP \fIset\fP \fItype-specification\fP [\fIoptions\fP...] -.PP -\fBipset\fP {\fB\-F\fP|\fB\-H\fP|\fB\-L\fP|\fB\-S\fP|\fB\-X\fP} [\fIset\fP] -[\fIoptions\fP...] -.PP -\fBipset\fP {\fB\-E\fP|\fB\-W\fP} \fIfrom-set\fP \fIto-set\fP -.PP -\fBipset\fP {\fB\-A\fP|\fB\-D\fP|\fB\-T\fP} \fIset\fP \fIentry\fP -.PP -\fBipset \-R\fP -.PP -\fBipset\fP {\fB-V\fP|\fB\-v\fP} -.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 -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 -\fB\-N\fP, \fB\-\-create\fP \fIsetname\fP \fItype\fP \fItype-specific-options\fP -Create a set identified with setname and specified type. -Type-specific options must be supplied. -.TP -\fB\-X\fP, \fB\-\-destroy\fP [\fIsetname\fP] -Destroy the specified set or all the sets if none is given. - -If the set has got references, nothing is done. -.TP -\fB\-F\fP, \fB\-\-flush\fP [\fIsetname\fP] -Delete all entries from the specified set or flush -all sets if none is given. -.TP -\fB\-E\fP, \fB\-\-rename\fP \fIfrom-setname\fP \fIto-setname\fP -Rename a set. Set identified by to-setname must not exist. -.TP -\fB\-W\fP, \fB\-\-swap\fP \fIfrom-setname\fP \fIto-setname\fP -Swap the content of two sets, or in another words, -exchange the name of two sets. The referred sets must exist and -identical type of sets can be swapped only. -.TP -\fB\-L\fP, \fB\-\-list\fP [\fIsetname\fP] -List the entries for the specified set, or for -all sets if none is given. The -\fB\-r\fP/\fB\-\-resolve\fP -option can be used to force name lookups (which may be slow). When the -\fB\-s\fP/\fB\-\-sorted\fP -option is given, the entries are listed sorted (if the given set -type supports the operation). -.TP -\fB\-S\fP, \fB\-\-save\fP [\fIsetname\fP] -Save the given set, or all sets if none is given -to stdout in a format that \fB\-\-restore\fP can read. -.TP -\fB\-R\fP, \fB\-\-restore\fP -Restore a saved session generated by \fB\-\-save\fP. The saved session -can be fed from stdin. - -When generating a session file please note that the supported commands -(create set and add element) 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. Also, it is a restore operation, so the sets being restored must -not exist. -.TP -\fB\-A\fP, \fB\-\-add\fP \fIsetname\fP \fIentry\fP -Add an entry to a set. -.TP -\fB\-D\fP, \fB\-\-del\fP \fIsetname\fP \fIentry\fP -Delete an entry from a set. -.TP -\fB-T\fP, \fB\-\-test\fP \fIsetname\fP \fIentry\fP -Test wether an entry is in a set or not. Exit status number is zero -if the tested entry is in the set and nonzero if it is missing from -the set. -.TP -\fB\-H\fP, \fB\-\-help\fP [\fIsettype\fP] -Print help and settype specific help if settype specified. -.TP -\fB\-V\fP, \fB\-v\fP, \fB\-\-version\fP -Print program version and protocol version. -.P -.SS "OTHER OPTIONS" -The following additional options can be specified: -.TP -\fB\-r\fP, \fB\-\-resolve\fP -When listing sets, enforce name lookup. The -program will try to display the IP entries resolved to -host names or services (whenever applicable), which can trigger -.B -slow -DNS -lookups. -.TP -\fB\-s\fP, \fB\-\-sorted\fP -Sorted output. When listing sets, entries are listed sorted. -.TP -\fB\-n\fP, \fB\-\-numeric\fP -Numeric output. When listing sets, IP addresses and -port numbers will be printed in numeric format. This is the default. -.TP -\fB\-q\fP, \fB\-\-quiet\fP -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. If the optional -\fB\-\-netmask\fP -parameter is specified with a CIDR netmask value between 1-31 then -network addresses are stored in the given set: i.e an -IP address will be in the set if the network address, which is 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 -\fB\-\-from\fP \fIfrom-addr\fP -.TP -\fB\-\-to\fP \fIto-addr\fP -Create an ipmap set from the specified address range. -.TP -\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP -Create an ipmap set from the specified network. -.TP -\fB\-\-netmask\fP \fIprefixlen\fP -When the optional -\fB\-\-netmask\fP -parameter specified, network addresses will be -stored in the set instead of IP addresses, and the \fIfrom-addr\fP parameter -must be a network address. The \fIprefixlen\fP value must be between 1-31. -.PP -Example: -.IP -ipset \-N test ipmap \-\-network 192.168.0.0/16 -.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 -"\fIaddress\fP\fB,\fP\fImac\fP". -When deleting or testing macipmap entries, the -"\fB,\fP\fImac\fP" -part is not mandatory. -.P -Options to use when creating an macipmap set: -.TP -\fB\-\-from\fP \fIfrom-addr\fP -.TP -\fB\-\-to\fP \fIto-addr\fP -Create a macipmap set from the specified address range. -.TP -\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP -Create a macipmap set from the specified network. -.TP -\fB\-\-matchunset\fP -When the optional -\fB\-\-matchunset\fP -parameter specified, IP addresses which could be stored -in the set but not set yet, will always match. -.P -Please note, the -"set" -and -"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 -\fB\-\-from\fP \fIfrom-port\fP -.TP -\fB\-\-to\fP \fIto-port\fP -Create a portmap set from the specified port 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. If the optional -\fB\-\-netmask\fP -parameter is specified with a CIDR prefix length value between 1-31 then -network addresses are stored in the given set: i.e an -IP address will be in the set if the network address, which is resulted -by masking the address with the specified netmask, can be found in the set. -.P -Options to use when creating an iphash set: -.TP -\fB\-\-hashsize\fP \fIhashsize\fP -The initial hash size (default 1024) -.TP -\fB\-\-probes\fP \fIprobes\fP -How many times try to resolve clashing at adding an IP to the hash -by double-hashing (default 8). -.TP -\fB\-\-resize\fP \fIpercent\fP -Increase the hash size by this many percent (default 50) when adding -an IP to the hash could not be performed after -\fIprobes\fP -number of double-hashing. -.TP -\fB\-\-netmask\fP \fIprefixlen\fP -When the optional -\fB\-\-netmask\fP -parameter specified, network addresses will be -stored in the set instead of IP addresses. The \fIprefixlen\fP value must -be between 1-31. -.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 grows approximately linearly with -the value of the -\fIprobes\fP -parameter. In general higher -\fIprobes\fP -value results better utilized hash while smaller value -produces larger, sparser hash. -.PP -Example: -.IP -ipset \-N test iphash \-\-probes 2 -.SS nethash -The nethash set type uses a hash to store different size of -network addresses. The -.I -entry -used in the ipset commands must be in the form -"\fIaddress\fP\fB/\fP\fIprefixlen\fP" -where prefixlen 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 -\fB\-\-hashsize\fP \fIhashsize\fP -The initial hash size (default 1024) -.TP -\fB\-\-probes\fP \fIprobes\fP -How many times try to resolve clashing at adding an IP to the hash -by double-hashing (default 4). -.TP -\fB\-\-resize\fP \fIpercent\fP -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 belongs to any of the -netblocks added to the set. The matching always start from the smallest -size of netblock (most specific netmask) to the largest ones (least -specific netmasks). When adding/deleting IP addresses -to a nethash set by the -"SET" -netfilter kernel module, it will be added/deleted by the smallest -netblock size which can be found in the set, or by /31 if the set is empty. -.P -The lookup time in a nethash type of set grows approximately linearly -with the times of the -\fIprobes\fP -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 -"\fIaddress\fP\fB,\fP\fIport\fP". -.P -The ipporthash types of sets evaluates two src/dst parameters of the -"set" -match and -"SET" -target. -.P -Options to use when creating an ipporthash set: -.TP -\fB\-\-from\fP \fIfrom-addr\fP -.TP -\fB\-\-to\fP \fIto-addr\fP -Create an ipporthash set from the specified address range. -.TP -\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP -Create an ipporthash set from the specified network. -.TP -\fB\-\-hashsize\fP \fIhashsize\fP -The initial hash size (default 1024) -.TP -\fB\-\-probes\fP \fIprobes\fP -How many times try to resolve clashing at adding an IP to the hash -by double-hashing (default 8). -.TP -\fB\-\-resize\fP \fIpercent\fP -Increase the hash size by this many percent (default 50) when adding -an IP to the hash could not be performed after -\fIprobes\fP -number of double-hashing. -.P -The same resizing, speed and memory efficiency comments applies here -as at the iphash type. -.SS ipportiphash -The ipportiphash set type uses a hash to store IP address,port and IP -address triples. The first IP address must come form a maximum /16 -sized network or range while the port number and the second IP address -parameters are arbitrary. When adding, deleting and testing values in an -ipportiphash type of set, the entries must be specified as -"\fIaddress\fP\fB,\fP\fIport\fP\fB,\fP\fIaddress\fP". -.P -The ipportiphash types of sets evaluates three src/dst parameters of the -"set" -match and -"SET" -target. -.P -Options to use when creating an ipportiphash set: -.TP -\fB\-\-from\fP \fIfrom-addr\fP -.TP -\fB\-\-to\fP \fIto-addr\fP -Create an ipportiphash set from the specified address range. -.TP -\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP -Create an ipportiphash set from the specified network. -.TP -\fB\-\-hashsize\fP \fIhashsize\fP -The initial hash size (default 1024) -.TP -\fB\-\-probes\fP \fIprobes\fP -How many times try to resolve clashing at adding an IP to the hash -by double-hashing (default 8). -.TP -\fB\-\-resize\fP \fIpercent\fP -Increase the hash size by this many percent (default 50) when adding -an IP to the hash could not be performed after -\fIprobes\fP -number of double-hashing. -.P -The same resizing, speed and memory efficiency comments applies here -as at the iphash type. -.SS ipportnethash -The ipportnethash set type uses a hash to store IP address, port, and -network address triples. The IP address must come form a maximum /16 -sized network or range while the port number and the network address -parameters are arbitrary, but the size of the network address must be -between /1-/31. When adding, deleting -and testing values in an ipportnethash type of set, the entries must be -specified as -"\fIaddress\fP\fB,\fP\fIport\fP\fB,\fP\fIaddress\fP\fB/\fP\fIprefixlen\fP". -.P -The ipportnethash types of sets evaluates three src/dst parameters of the -"set" -match and -"SET" -target. -.P -Options to use when creating an ipportnethash set: -.TP -\fB\-\-from\fP \fIfrom-address\fP -.TP -\fB\-\-to\fP \fIto-address\fP -Create an ipporthash set from the specified range. -.TP -\fB\-\-network\fP \fIaddress\fP\fB/\fP\fImask\fP -Create an ipporthash set from the specified network. -.TP -\fB\-\-hashsize\fP \fIhashsize\fP -The initial hash size (default 1024) -.TP -\fB\-\-probes\fP \fIprobes\fP -How many times try to resolve clashing at adding an IP to the hash -by double-hashing (default 8). -.TP -\fB\-\-resize\fP \fIpercent\fP -Increase the hash size by this many percent (default 50) when adding -an IP to the hash could not be performed after -\fIprobes\fP -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 -\fB\-\-timeout\fP \fIvalue\fP -The timeout value for the entries in seconds (default 0) -.P -If a set was created with a nonzero valued -\fB\-\-timeout\fP -parameter then one may add IP addresses to the set with a specific -timeout value using the syntax -"\fIaddress\fP\fB,\fP\fItimeout-value\fP". -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 -"\fIaddress1\fP\fB-\fP\fIaddress2\fP". -.P -Options to use when creating an iptreemap set: -.TP -\fB\-\-gc\fP \fIvalue\fP -How often the garbage collection should be called, in seconds (default 300) -.SS setlist -The setlist type uses a simple list in which you can store sets. By the -ipset -command you can add, delete and test sets in a setlist type of set. -You can specify the sets as -"\fIsetname\fP[\fB,\fP{\fBafter\fP|\fBbefore\fP},\fIsetname\fP]". -By default new sets are added after (appended to) the existing -elements. Setlist type of sets cannot be added to a setlist type of set. -.P -Options to use when creating a setlist type of set: -.TP -\fB\-\-size\fP \fIsize\fP -Create a setlist type of set with the given size (default 8). -.PP -By the -"set" -match or -"SET" -target of -\fBiptables\fP(8) -you can test, add or delete entries in the sets. The match -will try to find a matching IP address/port in the sets and -the target will try to add the IP address/port to the first set -to which it can be added. The number of src,dst options of -the match and target are important: sets which eats more src,dst -parameters than specified are skipped, while sets with equal -or less parameters are checked, elements added. For example -if -.I -a -and -.I -b -are setlist type of sets then in the command -.IP -iptables \-m set \-\-match\-set a src,dst \-j SET \-\-add-set b src,dst -.PP -the match and target will skip any set in -.I a -and -.I b -which stores -data triples, but will check all sets with single or double -data storage in -.I a -set and add src to the first single or src,dst to the first double -data storage set in -\fIb\fP. -.P -You can imagine a setlist type of set as an ordered union of -the set elements. -.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. -.P -Old separator tokens (':' and '%") are still accepted. -.P -Binding support is removed. -.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 shoulders of giants." diff --git a/ipset.c b/ipset.c deleted file mode 100644 index 3b8e248..0000000 --- a/ipset.c +++ /dev/null @@ -1,2054 +0,0 @@ -/* Copyright 2000-2002 Joakim Axelsson (gozem@linux.nu) - * Patrick Schaaf (bof@bof.de) - * Copyright 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. - */ - -#include /* *printf, perror, sscanf, fdopen */ -#include /* mem*, str* */ -#include /* errno, perror */ -#include /* time, ctime */ -#include /* gethostby*, getnetby*, getservby* */ -#include /* exit, malloc, free, strtol, getenv, mkstemp */ -#include /* read, close, fork, exec*, unlink */ -#include /* open, wait, socket, *sockopt, umask */ -#include /* open, umask */ -#include /* wait */ -#include /* socket, *sockopt, gethostby*, inet_* */ -#include /* inet_* */ -#include /* open */ -#include /* htonl, inet_* */ -#include /* va_* */ -#include /* dlopen */ - -#include "ipset.h" - -#ifndef PROC_SYS_MODPROBE -#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" -#endif - -char program_name[] = "ipset"; -char program_version[] = IPSET_VERSION; -static int protocol_version = 0; - -#define STREQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0) -#define DONT_ALIGN (protocol_version == IP_SET_PROTOCOL_UNALIGNED) -#define ALIGNED(len) IPSET_VALIGN(len, DONT_ALIGN) - -/* The list of loaded set types */ -static struct settype *all_settypes = NULL; - -/* Array of sets */ -struct set **set_list = NULL; -ip_set_id_t max_sets = 0; - -/* Suppress output to stdout and stderr? */ -static int option_quiet = 0; - -/* Data for restore mode */ -static int restore = 0; -void *restore_data = NULL; -struct ip_set_restore *restore_set = NULL; -size_t restore_offset = 0; -socklen_t restore_size; -unsigned restore_line = 0; -unsigned warn_once = 0; - -#define TEMPFILE_PATTERN "/ipsetXXXXXX" - -#ifdef IPSET_DEBUG -int option_debug = 0; -#endif - -#define OPTION_OFFSET 256 -static unsigned int global_option_offset = 0; - -/* Most of these command parsing functions are borrowed from iptables.c */ - -static const char cmdflags[] = { ' ', /* CMD_NONE */ - 'N', 'X', 'F', 'E', 'W', 'L', 'S', 'R', - 'A', 'D', 'T', 'H', 'V', -}; - -/* Options */ -#define OPT_NONE 0x0000U -#define OPT_NUMERIC 0x0001U /* -n */ -#define OPT_SORTED 0x0002U /* -s */ -#define OPT_QUIET 0x0004U /* -q */ -#define OPT_DEBUG 0x0008U /* -z */ -#define OPT_RESOLVE 0x0020U /* -r */ -#define NUMBER_OF_OPT 5 -static const char optflags[] = - { 'n', 's', 'q', 'z', 'r' }; - -static struct option opts_long[] = { - /* set operations */ - {"create", 1, 0, 'N'}, - {"destroy", 2, 0, 'X'}, - {"flush", 2, 0, 'F'}, - {"rename", 1, 0, 'E'}, - {"swap", 1, 0, 'W'}, - {"list", 2, 0, 'L'}, - - {"save", 2, 0, 'S'}, - {"restore", 0, 0, 'R'}, - - /* ip in set operations */ - {"add", 1, 0, 'A'}, - {"del", 1, 0, 'D'}, - {"test", 1, 0, 'T'}, - - /* free options */ - {"numeric", 0, 0, 'n'}, - {"sorted", 0, 0, 's'}, - {"quiet", 0, 0, 'q'}, - {"resolve", 0, 0, 'r'}, - -#ifdef IPSET_DEBUG - /* debug (if compiled with it) */ - {"debug", 0, 0, 'z'}, -#endif - - /* version and help */ - {"version", 0, 0, 'V'}, - {"help", 2, 0, 'H'}, - - /* end */ - {NULL}, -}; - -static char opts_short[] = - "-N:X::F::E:W:L::S::RA:D:T:nrsqzvVh::H::"; - -/* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal. - * Key: - * + compulsory - * x illegal - * optional - */ - -static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { - /* -n -s -q -z -r */ - /*CREATE*/ {'x', 'x', ' ', ' ', 'x'}, - /*DESTROY*/ {'x', 'x', ' ', ' ', 'x'}, - /*FLUSH*/ {'x', 'x', ' ', ' ', 'x'}, - /*RENAME*/ {'x', 'x', ' ', ' ', 'x'}, - /*SWAP*/ {'x', 'x', ' ', ' ', 'x'}, - /*LIST*/ {' ', ' ', 'x', ' ', ' '}, - /*SAVE*/ {'x', 'x', ' ', ' ', 'x'}, - /*RESTORE*/ {'x', 'x', ' ', ' ', 'x'}, - /*ADD*/ {'x', 'x', ' ', ' ', 'x'}, - /*DEL*/ {'x', 'x', ' ', ' ', 'x'}, - /*TEST*/ {'x', 'x', ' ', ' ', 'x'}, - /*HELP*/ {'x', 'x', 'x', ' ', 'x'}, - /*VERSION*/ {'x', 'x', 'x', ' ', 'x'}, -}; - -/* Main parser function */ -int parse_commandline(int argc, char *argv[]); - -static void exit_tryhelp(int status) -{ - fprintf(stderr, - "Try `%s -H' or '%s --help' for more information.\n", - program_name, program_name); - exit(status); -} - -void exit_error(int status, const char *msg, ...) -{ - if (!option_quiet) { - va_list args; - - va_start(args, msg); - fprintf(stderr, "%s v%s: ", program_name, program_version); - vfprintf(stderr, msg, args); - va_end(args); - fprintf(stderr, "\n"); - if (restore_line) - fprintf(stderr, "Restore failed at line %u:\n", restore_line); - if (status == PARAMETER_PROBLEM) - exit_tryhelp(status); - if (status == VERSION_PROBLEM) - fprintf(stderr, - "Perhaps %s or your kernel needs to be upgraded.\n", - program_name); - } - - exit(status); -} - -static void ipset_printf(const char *msg, ...) -{ - if (!option_quiet) { - va_list args; - - va_start(args, msg); - vfprintf(stdout, msg, args); - va_end(args); - fprintf(stdout, "\n"); - } -} - -static void generic_opt_check(int command, unsigned int options) -{ - int i, j, legal = 0; - - /* Check that commands are valid with options. Complicated by the - * fact that if an option is legal with *any* command given, it is - * legal overall (ie. -z and -l). - */ - for (i = 0; i < NUMBER_OF_OPT; i++) { - legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ - - for (j = 1; j <= NUMBER_OF_CMD; j++) { - if (command != j) - continue; - - if (!(options & (1 << i))) { - if (commands_v_options[j-1][i] == '+') - exit_error(PARAMETER_PROBLEM, - "You need to supply the `-%c' " - "option for this command\n", - optflags[i]); - } else { - if (commands_v_options[j-1][i] != 'x') - legal = 1; - else if (legal == 0) - legal = -1; - } - } - if (legal == -1) - exit_error(PARAMETER_PROBLEM, - "Illegal option `-%c' with this command\n", - optflags[i]); - } -} - -static char opt2char(unsigned int option) -{ - const char *ptr; - for (ptr = optflags; option > 1; option >>= 1, ptr++); - - return *ptr; -} - -static char cmd2char(int cmd) -{ - if (cmd <= CMD_NONE || cmd > NUMBER_OF_CMD) - return ' '; - - return cmdflags[cmd]; -} - -/* From iptables.c ... */ -static char *get_modprobe(void) -{ - int procfile; - char *ret; - -#define PROCFILE_BUFSIZ 1024 - procfile = open(PROC_SYS_MODPROBE, O_RDONLY); - if (procfile < 0) - return NULL; - - ret = (char *) malloc(PROCFILE_BUFSIZ); - if (ret) { - memset(ret, 0, PROCFILE_BUFSIZ); - switch (read(procfile, ret, PROCFILE_BUFSIZ)) { - case -1: goto fail; - case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */ - default: ; /* nothing */ - } - if (ret[strlen(ret)-1]=='\n') - ret[strlen(ret)-1]=0; - close(procfile); - return ret; - } - fail: - free(ret); - close(procfile); - return NULL; -} - -static int ipset_insmod(const char *modname, const char *modprobe) -{ - char *buf = NULL; - char *argv[3]; - struct stat junk; - int status; - - if (!stat(modprobe, &junk)) { - /* Try to read out of the kernel */ - buf = get_modprobe(); - if (!buf) - return -1; - modprobe = buf; - } - - switch (fork()) { - case 0: - argv[0] = (char *) modprobe; - argv[1] = (char *) modname; - argv[2] = NULL; - execv(argv[0], argv); - - /* Should not reach */ - exit(1); - case -1: - return -1; - - default: /* parent */ - wait(&status); - } - - free(buf); - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - return 0; - return -1; -} - -static int kernel_getsocket(void) -{ - int sockfd = -1; - - sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (sockfd < 0) - exit_error(OTHER_PROBLEM, - "You need to be root to perform this command."); - - return sockfd; -} - -static void kernel_error(unsigned cmd, int err) -{ - unsigned int i; - struct translate_error { - int err; - unsigned cmd; - const char *message; - } table[] = - { /* Generic error codes */ - { EPERM, 0, "Missing capability" }, - { EBADF, 0, "Invalid socket option" }, - { EINVAL, 0, "Size mismatch for expected socket data" }, - { ENOMEM, 0, "Not enough memory" }, - { EFAULT, 0, "Failed to copy data" }, - { EPROTO, 0, "ipset kernel/userspace version mismatch" }, - { EBADMSG, 0, "Unknown command" }, - /* Per command error codes */ - /* Reserved ones for add/del/test to handle internally: - * EEXIST - */ - { ENOENT, CMD_CREATE, "Unknown set type" }, - { ENOENT, 0, "Unknown set" }, - { EAGAIN, 0, "Sets are busy, try again later" }, - { ERANGE, CMD_CREATE, "No free slot remained to add a new set" }, - { ERANGE, 0, "IP/port/element is outside of the set or set is full" }, - { ENOEXEC, CMD_CREATE, "Invalid parameters to create a set" }, - { ENOEXEC, CMD_SWAP, "Sets with different types cannot be swapped" }, - { EEXIST, CMD_CREATE, "Set already exists" }, - { EEXIST, CMD_RENAME, "Set with new name already exists" }, - { EEXIST, 0, "Set specified as element does not exist" }, - { EBUSY, 0, "Set is in use, operation not permitted" }, - }; - for (i = 0; i < sizeof(table)/sizeof(struct translate_error); i++) { - if ((table[i].cmd == cmd || table[i].cmd == 0) - && table[i].err == err) - exit_error(err == EPROTO ? VERSION_PROBLEM - : OTHER_PROBLEM, - table[i].message); - } - exit_error(OTHER_PROBLEM, "Error from kernel: %s", strerror(err)); -} - -static inline int wrapped_getsockopt(void *data, socklen_t *size) -{ - int res; - int sockfd = kernel_getsocket(); - - /* Send! */ - res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); - if (res != 0 - && errno == ENOPROTOOPT - && ipset_insmod("ip_set", "/sbin/modprobe") == 0) - res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); - DP("res=%d errno=%d", res, errno); - - return res; -} - -static inline int wrapped_setsockopt(void *data, socklen_t size) -{ - int res; - int sockfd = kernel_getsocket(); - - /* Send! */ - res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); - if (res != 0 - && errno == ENOPROTOOPT - && ipset_insmod("ip_set", "/sbin/modprobe") == 0) - res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); - DP("res=%d errno=%d", res, errno); - - return res; -} - -static void kernel_getfrom(unsigned cmd, void *data, socklen_t * size) -{ - int res = wrapped_getsockopt(data, size); - - if (res != 0) - kernel_error(cmd, errno); -} - -static int kernel_sendto_handleerrno(unsigned cmd, - void *data, socklen_t size) -{ - int res = wrapped_setsockopt(data, size); - - if (res != 0) { - if (errno == EEXIST) - return -1; - else - kernel_error(cmd, errno); - } - - return 0; /* all ok */ -} - -static void kernel_sendto(unsigned cmd, void *data, size_t size) -{ - int res = wrapped_setsockopt(data, size); - - if (res != 0) - kernel_error(cmd, errno); -} - -static int kernel_getfrom_handleerrno(unsigned cmd, void *data, socklen_t *size) -{ - int res = wrapped_getsockopt(data, size); - - if (res != 0) { - if (errno == EAGAIN) - return -1; - else - kernel_error(cmd, errno); - } - - return 0; /* all ok */ -} - -static void check_protocolversion(void) -{ - struct ip_set_req_version req_version; - socklen_t size = sizeof(struct ip_set_req_version); - int res; - - if (protocol_version) - return; - - req_version.op = IP_SET_OP_VERSION; - res = wrapped_getsockopt(&req_version, &size); - - if (res != 0) - exit_error(OTHER_PROBLEM, - "Couldn't verify kernel module version!"); - - if (!(req_version.version == IP_SET_PROTOCOL_VERSION - || req_version.version == IP_SET_PROTOCOL_UNALIGNED)) - exit_error(OTHER_PROBLEM, - "Kernel ip_set module is of protocol version %u." - "I'm of protocol version %u.\n" - "Please upgrade your kernel and/or ipset(8) utillity.", - req_version.version, IP_SET_PROTOCOL_VERSION); - protocol_version = req_version.version; -} - -static void set_command(int *cmd, int newcmd) -{ - if (*cmd != CMD_NONE) - exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n", - cmd2char(*cmd), cmd2char(newcmd)); - *cmd = newcmd; -} - -static void add_option(unsigned int *options, unsigned int option) -{ - if (*options & option) - exit_error(PARAMETER_PROBLEM, - "multiple -%c flags not allowed", - opt2char(option)); - *options |= option; -} - -void *ipset_malloc(size_t size) -{ - void *p; - - if (size == 0) - return NULL; - - if ((p = malloc(size)) == NULL) { - perror("ipset: not enough memory"); - exit(1); - } - return p; -} - -char *ipset_strdup(const char *s) -{ - char *p; - - if ((p = strdup(s)) == NULL) { - perror("ipset: not enough memory"); - exit(1); - } - return p; -} - -void ipset_free(void *data) -{ - if (data == NULL) - return; - - free(data); -} - -static struct option *merge_options(struct option *oldopts, - const struct option *newopts, - int *option_offset) -{ - unsigned int num_old, num_new, i; - struct option *merge; - - for (num_old = 0; oldopts[num_old].name; num_old++); - for (num_new = 0; newopts[num_new].name; num_new++); - - global_option_offset += OPTION_OFFSET; - *option_offset = global_option_offset; - - merge = ipset_malloc(sizeof(struct option) * (num_new + num_old + 1)); - memcpy(merge, oldopts, num_old * sizeof(struct option)); - for (i = 0; i < num_new; i++) { - merge[num_old + i] = newopts[i]; - merge[num_old + i].val += *option_offset; - } - memset(merge + num_old + num_new, 0, sizeof(struct option)); - - return merge; -} - -static char *ip_tohost(const struct in_addr *addr) -{ - struct hostent *host; - - if ((host = gethostbyaddr((char *) addr, - sizeof(struct in_addr), - AF_INET)) != NULL) { - DP("%s", host->h_name); - return (char *) host->h_name; - } - - return (char *) NULL; -} - -static char *ip_tonetwork(const struct in_addr *addr) -{ - struct netent *net; - - if ((net = getnetbyaddr(ntohl(addr->s_addr), - AF_INET)) != NULL) { - DP("%s", net->n_name); - return (char *) net->n_name; - } - - return (char *) NULL; -} - -/* Return a string representation of an IP address. - * Please notice that a pointer to static char* area is returned. - */ -char *ip_tostring(ip_set_ip_t ip, unsigned options) -{ - struct in_addr addr; - addr.s_addr = htonl(ip); - - if (!(options & OPT_NUMERIC)) { - char *name; - if ((name = ip_tohost(&addr)) != NULL || - (name = ip_tonetwork(&addr)) != NULL) - return name; - } - - return inet_ntoa(addr); -} - -char *ip_tostring_numeric(ip_set_ip_t ip) -{ - return ip_tostring(ip, OPT_NUMERIC); -} - -/* Fills the 'ip' with the parsed ip or host in host byte order */ -void parse_ip(const char *str, ip_set_ip_t * ip) -{ - struct hostent *host; - struct in_addr addr; - - DP("%s", str); - - if (inet_aton(str, &addr) != 0) { - *ip = ntohl(addr.s_addr); /* We want host byte order */ - return; - } - - host = gethostbyname(str); - if (host != NULL) { - if (host->h_addrtype != AF_INET || - host->h_length != sizeof(struct in_addr)) - exit_error(PARAMETER_PROBLEM, - "host/network `%s' not an internet name", - str); - if (host->h_addr_list[1] != 0) - exit_error(PARAMETER_PROBLEM, - "host/network `%s' resolves to serveral ip-addresses. " - "Please specify one.", str); - - memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr)); - *ip = ntohl(addr.s_addr); - return; - } - - exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", str); -} - -/* Fills 'mask' with the parsed mask in host byte order */ -void parse_mask(const char *str, ip_set_ip_t * mask) -{ - struct in_addr addr; - int bits; - - DP("%s", str); - - if (str == NULL) { - /* no mask at all defaults to 32 bits */ - *mask = 0xFFFFFFFF; - return; - } - if (strchr(str, '.') && inet_aton(str, &addr) != 0) { - *mask = ntohl(addr.s_addr); /* We want host byte order */ - return; - } - if (sscanf(str, "%d", &bits) != 1 || bits < 0 || bits > 32) - exit_error(PARAMETER_PROBLEM, - "invalid mask `%s' specified", str); - - DP("bits: %d", bits); - - *mask = bits != 0 ? 0xFFFFFFFF << (32 - bits) : 0L; -} - -/* Combines parse_ip and parse_mask */ -void -parse_ipandmask(const char *str, ip_set_ip_t * ip, ip_set_ip_t * mask) -{ - char buf[256]; - char *p; - - strncpy(buf, str, sizeof(buf) - 1); - buf[255] = '\0'; - - if ((p = strrchr(buf, '/')) != NULL) { - *p = '\0'; - parse_mask(p + 1, mask); - } else - parse_mask(NULL, mask); - - /* if a null mask is given, the name is ignored, like in "any/0" */ - if (*mask == 0U) - *ip = 0U; - else - parse_ip(buf, ip); - - DP("%s ip: %08X (%s) mask: %08X", - str, *ip, ip_tostring_numeric(*ip), *mask); - - /* Apply the netmask */ - *ip &= *mask; - - DP("%s ip: %08X (%s) mask: %08X", - str, *ip, ip_tostring_numeric(*ip), *mask); -} - -/* Return a string representation of a port - * Please notice that a pointer to static char* area is returned - * and we assume TCP protocol. - */ -char *port_tostring(ip_set_ip_t port, unsigned options) -{ - struct servent *service; - static char name[] = "65535"; - - if (!(options & OPT_NUMERIC)) { - if ((service = getservbyport(htons(port), "tcp"))) - return service->s_name; - } - sprintf(name, "%u", port); - return name; -} - -int -string_to_number(const char *str, unsigned int min, unsigned int max, - ip_set_ip_t *port) -{ - unsigned long number; - char *end; - - /* Handle hex, octal, etc. */ - errno = 0; - number = strtoul(str, &end, 0); - if (*end == '\0' && end != str) { - /* we parsed a number, let's see if we want this */ - if (errno != ERANGE && min <= number && number <= max) { - *port = number; - return 0; - } - } - return -1; -} - -static int -string_to_port(const char *str, ip_set_ip_t *port) -{ - struct servent *service; - - if ((service = getservbyname(str, "tcp")) != NULL) { - *port = ntohs((uint16_t) service->s_port); - return 0; - } - return -1; -} - -/* Fills the 'ip' with the parsed port in host byte order */ -void parse_port(const char *str, ip_set_ip_t *port) -{ - if ((string_to_number(str, 0, 65535, port) != 0) - && (string_to_port(str, port) != 0)) - exit_error(PARAMETER_PROBLEM, - "Invalid TCP port `%s' specified", str); -} - -/* - * Settype functions - */ -static struct settype *settype_find(const char *typename) -{ - struct settype *runner = all_settypes; - - DP("%s", typename); - - while (runner != NULL) { - if (STREQ(runner->typename, typename)) - return runner; - - runner = runner->next; - } - - return NULL; /* not found */ -} - -static struct settype *settype_load(const char *typename) -{ - char path[sizeof(IPSET_LIB_DIR) + sizeof(IPSET_LIB_NAME) + - strlen(typename)]; - struct settype *settype; - - /* do some search in list */ - settype = settype_find(typename); - if (settype != NULL) - return settype; /* found */ - - /* Else we have to load it */ - sprintf(path, IPSET_LIB_DIR IPSET_LIB_NAME, typename); - - if (dlopen(path, RTLD_NOW)) { - /* Found library. */ - - settype = settype_find(typename); - - if (settype != NULL) - return settype; - } - - /* Can't load the settype */ - exit_error(PARAMETER_PROBLEM, - "Couldn't load settype `%s':%s\n", - typename, dlerror()); - - return NULL; /* Never executed, but keep compilers happy */ -} - -static char *check_set_name(char *setname) -{ - if (strlen(setname) > IP_SET_MAXNAMELEN - 1) - exit_error(PARAMETER_PROBLEM, - "Setname '%s' too long, max %d characters.", - setname, IP_SET_MAXNAMELEN - 1); - - return setname; -} - -static struct settype *check_set_typename(const char *typename) -{ - if (strlen(typename) > IP_SET_MAXNAMELEN - 1) - exit_error(PARAMETER_PROBLEM, - "Typename '%s' too long, max %d characters.", - typename, IP_SET_MAXNAMELEN - 1); - - return settype_load(typename); -} - -#define MAX(a,b) ((a) > (b) ? (a) : (b)) - -/* Register a new set type */ -void settype_register(struct settype *settype) -{ - struct settype *chk; - size_t size; - - DP("%s", settype->typename); - - /* Check if this typename already exists */ - chk = settype_find(settype->typename); - - if (chk != NULL) - exit_error(OTHER_PROBLEM, - "Set type '%s' already registered!\n", - settype->typename); - - /* Check version */ - if (settype->protocol_version != IP_SET_PROTOCOL_VERSION) - exit_error(OTHER_PROBLEM, - "Set type %s is of wrong protocol version %u!" - " I'm of version %u.\n", settype->typename, - settype->protocol_version, - IP_SET_PROTOCOL_VERSION); - - /* Initialize internal data */ - settype->header = ipset_malloc(settype->header_size); - size = MAX(settype->create_size, settype->adt_size); - settype->data = ipset_malloc(size); - - /* Insert first */ - settype->next = all_settypes; - all_settypes = settype; - - DP("%s registered", settype->typename); -} - -/* Find set functions */ -struct set *set_find_byid(ip_set_id_t id) -{ - struct set *set = NULL; - ip_set_id_t i; - - for (i = 0; i < max_sets; i++) - if (set_list[i] && set_list[i]->id == id) { - set = set_list[i]; - break; - } - - if (set == NULL) - exit_error(PARAMETER_PROBLEM, - "Set identified by id %u is not found", id); - return set; -} - -struct set *set_find_byname(const char *name) -{ - struct set *set = NULL; - ip_set_id_t i; - - for (i = 0; i < max_sets; i++) - if (set_list[i] != NULL && STREQ(set_list[i]->name, name)) { - set = set_list[i]; - break; - } - if (set == NULL) - exit_error(PARAMETER_PROBLEM, - "Set %s is not found", name); - return set; -} - -static ip_set_id_t set_find_free_index(const char *name) -{ - ip_set_id_t i, idx = IP_SET_INVALID_ID; - - for (i = 0; i < max_sets; i++) { - if (idx == IP_SET_INVALID_ID - && set_list[i] == NULL) - idx = i; - if (set_list[i] != NULL && STREQ(set_list[i]->name, name)) - exit_error(PARAMETER_PROBLEM, - "Set %s is already defined, cannot be restored", - name); - } - - if (idx == IP_SET_INVALID_ID) - exit_error(PARAMETER_PROBLEM, - "Set %s cannot be restored, " - "max number of set %u reached", - name, max_sets); - - return idx; -} - -/* - * Send create set order to kernel - */ -static void set_create(const char *name, struct settype *settype) -{ - struct ip_set_req_create req_create; - size_t size; - void *data; - - DP("%s %s", name, settype->typename); - - req_create.op = IP_SET_OP_CREATE; - req_create.version = protocol_version; - strcpy(req_create.name, name); - strcpy(req_create.typename, settype->typename); - - /* Final checks */ - settype->create_final(settype->data, settype->flags); - - /* Alloc memory for the data to send */ - size = sizeof(struct ip_set_req_create) + settype->create_size; - data = ipset_malloc(size); - - /* Add up ip_set_req_create and the settype data */ - memcpy(data, &req_create, sizeof(struct ip_set_req_create)); - memcpy(data + sizeof(struct ip_set_req_create), - settype->data, settype->create_size); - - kernel_sendto(CMD_CREATE, data, size); - free(data); -} - -static void set_restore_create(const char *name, struct settype *settype) -{ - struct set *set; - - DP("%s %s %zu %zu %u %u", name, settype->typename, - restore_offset, sizeof(struct ip_set_restore), - settype->create_size, restore_size); - - /* Sanity checking */ - if (restore_offset - + ALIGNED(sizeof(struct ip_set_restore)) - + ALIGNED(settype->create_size) > restore_size) - exit_error(PARAMETER_PROBLEM, - "Giving up, restore file is screwed up!"); - - /* Final checks */ - settype->create_final(settype->data, settype->flags); - - /* Fill out restore_data */ - restore_set = (struct ip_set_restore *) - (restore_data + restore_offset); - strcpy(restore_set->name, name); - strcpy(restore_set->typename, settype->typename); - restore_set->index = set_find_free_index(name); - restore_set->header_size = settype->create_size; - restore_set->members_size = 0; - - DP("name %s, restore index %u", restore_set->name, restore_set->index); - /* Add settype data */ - - restore_offset += ALIGNED(sizeof(struct ip_set_restore)); - memcpy(restore_data + restore_offset, settype->data, settype->create_size); - - restore_offset += ALIGNED(settype->create_size); - DP("restore_offset: %zu", restore_offset); - - /* Add set to set_list */ - set = ipset_malloc(sizeof(struct set)); - strcpy(set->name, name); - set->settype = settype; - set->index = restore_set->index; - set_list[restore_set->index] = set; -} - -/* - * Send destroy/flush order to kernel for one or all sets - */ -static void set_destroy(const char *name, unsigned op, unsigned cmd) -{ - struct ip_set_req_std req; - - DP("%s %s", cmd == CMD_DESTROY ? "destroy" : "flush", name); - - req.op = op; - req.version = protocol_version; - strcpy(req.name, name); - - kernel_sendto(cmd, &req, sizeof(struct ip_set_req_std)); -} - -/* - * Send rename/swap order to kernel - */ -static void set_rename(const char *name, const char *newname, - unsigned op, unsigned cmd) -{ - struct ip_set_req_create req; - - DP("%s %s %s", cmd == CMD_RENAME ? "rename" : "swap", - name, newname); - - req.op = op; - req.version = protocol_version; - strcpy(req.name, name); - strcpy(req.typename, newname); - - kernel_sendto(cmd, &req, - sizeof(struct ip_set_req_create)); -} - -/* - * Send MAX_SETS, LIST_SIZE and/or SAVE_SIZE orders to kernel - */ -static size_t load_set_list(const char name[IP_SET_MAXNAMELEN], - ip_set_id_t *idx, - unsigned op, unsigned cmd) -{ - void *data = NULL; - struct ip_set_req_max_sets req_max_sets; - struct ip_set_name_list *name_list; - struct set *set; - ip_set_id_t i; - socklen_t size, req_size; - int repeated = 0, res = 0; - - DP("%s %s", cmd == CMD_MAX_SETS ? "MAX_SETS" - : cmd == CMD_LIST_SIZE ? "LIST_SIZE" - : "SAVE_SIZE", - name); - -tryagain: - if (set_list) { - for (i = 0; i < max_sets; i++) - if (set_list[i]) - free(set_list[i]); - free(set_list); - set_list = NULL; - } - /* Get max_sets */ - req_max_sets.op = IP_SET_OP_MAX_SETS; - req_max_sets.version = protocol_version; - strcpy(req_max_sets.set.name, name); - size = sizeof(req_max_sets); - kernel_getfrom(CMD_MAX_SETS, &req_max_sets, &size); - - DP("got MAX_SETS: sets %d, max_sets %d", - req_max_sets.sets, req_max_sets.max_sets); - - max_sets = req_max_sets.max_sets; - set_list = ipset_malloc(max_sets * sizeof(struct set *)); - memset(set_list, 0, max_sets * sizeof(struct set *)); - *idx = req_max_sets.set.index; - - if (req_max_sets.sets == 0) - /* No sets in kernel */ - return 0; - - /* Get setnames */ - size = req_size = ALIGNED(sizeof(struct ip_set_req_setnames)) - + req_max_sets.sets * ALIGNED(sizeof(struct ip_set_name_list)); - data = ipset_malloc(size); - ((struct ip_set_req_setnames *) data)->op = op; - ((struct ip_set_req_setnames *) data)->index = *idx; - - res = kernel_getfrom_handleerrno(cmd, data, &size); - - if (res != 0 || size != req_size) { - free(data); - if (repeated++ < LIST_TRIES) - goto tryagain; - exit_error(OTHER_PROBLEM, - "Tried to get sets from kernel %d times" - " and failed. Please try again when the load on" - " the sets has gone down.", LIST_TRIES); - } - - /* Load in setnames */ - size = ALIGNED(sizeof(struct ip_set_req_setnames)); - while (size + ALIGNED(sizeof(struct ip_set_name_list)) <= req_size) { - name_list = (struct ip_set_name_list *) - (data + size); - set = ipset_malloc(sizeof(struct set)); - strcpy(set->name, name_list->name); - set->index = name_list->index; - set->id = name_list->id; - set->settype = settype_load(name_list->typename); - set_list[name_list->index] = set; - DP("loaded %s, type %s, index %u", - set->name, set->settype->typename, set->index); - size += ALIGNED(sizeof(struct ip_set_name_list)); - } - /* Size to get set members */ - size = ((struct ip_set_req_setnames *)data)->size; - free(data); - - return size; -} - -/* - * Save operation - */ -static size_t save_set(void *data, size_t offset, size_t len) -{ - struct ip_set_save *set_save = - (struct ip_set_save *) (data + offset); - struct set *set; - struct settype *settype; - size_t used; - - DP("offset %zu (%zu/%u/%u), len %zu", offset, - sizeof(struct ip_set_save), - set_save->header_size, set_save->members_size, - len); - if (offset + ALIGNED(sizeof(struct ip_set_save)) > len - || offset + ALIGNED(sizeof(struct ip_set_save)) - + set_save->header_size + set_save->members_size > len) - exit_error(OTHER_PROBLEM, - "Save operation failed, try again later."); - - DP("index: %u", set_save->index); - if (set_save->index == IP_SET_INVALID_ID) { - /* Marker */ - return ALIGNED(sizeof(struct ip_set_save)); - } - set = set_list[set_save->index]; - if (!set) - exit_error(OTHER_PROBLEM, - "Save set failed, try again later."); - settype = set->settype; - - /* Init set header */ - used = ALIGNED(sizeof(struct ip_set_save)); - settype->initheader(set, data + offset + used); - - /* Print create set */ - settype->saveheader(set, OPT_NUMERIC); - - /* Print add IPs */ - used += set_save->header_size; - settype->saveips(set, data + offset + used, - set_save->members_size, OPT_NUMERIC, - DONT_ALIGN); - - return (used + set_save->members_size); -} - -static int try_save_sets(const char name[IP_SET_MAXNAMELEN]) -{ - void *data = NULL; - socklen_t size, req_size = 0; - ip_set_id_t idx; - int res = 0; - time_t now = time(NULL); - - /* Load set_list from kernel */ - size = load_set_list(name, &idx, - IP_SET_OP_SAVE_SIZE, CMD_SAVE); - - if (size) { - /* Get sets and print them */ - /* Take into account marker */ - req_size = (size += ALIGNED(sizeof(struct ip_set_save))); - data = ipset_malloc(size); - ((struct ip_set_req_list *) data)->op = IP_SET_OP_SAVE; - ((struct ip_set_req_list *) data)->index = idx; - res = kernel_getfrom_handleerrno(CMD_SAVE, data, &size); - - if (res != 0 || size != req_size) { - DP("Try again: res: %i, size %u, req_size: %u", - res, size, req_size); - free(data); - return -EAGAIN; - } - } - - printf("# Generated by ipset %s on %s", IPSET_VERSION, ctime(&now)); - size = 0; - while (size < req_size) { - DP("size: %u, req_size: %u", size, req_size); - size += save_set(data, size, req_size); - } - printf("COMMIT\n"); - now = time(NULL); - printf("# Completed on %s", ctime(&now)); - ipset_free(data); - return res; -} - -/* - * Performs a save to stdout - */ -static void set_save(const char name[IP_SET_MAXNAMELEN]) -{ - int i; - - DP("%s", name); - for (i = 0; i < LIST_TRIES; i++) - if (try_save_sets(name) == 0) - return; - - if (errno == EAGAIN) - exit_error(OTHER_PROBLEM, - "Tried to save sets from kernel %d times" - " and failed. Please try again when the load on" - " the sets has gone down.", LIST_TRIES); - else - kernel_error(CMD_SAVE, errno); -} - -/* - * Restore operation - */ - -/* global new argv and argc */ -static char *newargv[255]; -static int newargc = 0; - -/* Build faked argv from parsed line */ -static void build_argv(unsigned line, char *buffer) { - char *ptr; - int i; - - /* Reset */ - for (i = 1; i < newargc; i++) - free(newargv[i]); - newargc = 1; - - ptr = strtok(buffer, " \t\n"); - newargv[newargc++] = ipset_strdup(ptr); - while ((ptr = strtok(NULL, " \t\n")) != NULL) { - if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *))) - newargv[newargc++] = ipset_strdup(ptr); - else - exit_error(PARAMETER_PROBLEM, - "Line %d is too long to restore\n", line); - } -} - -static FILE *create_tempfile(void) -{ - char buffer[1024], __tmpdir[] = "/tmp"; - char *tmpdir = NULL; - char *filename; - int fd; - FILE *file; - - if (!(tmpdir = getenv("TMPDIR")) && !(tmpdir = getenv("TMP"))) - tmpdir = __tmpdir; - filename = ipset_malloc(strlen(tmpdir) + strlen(TEMPFILE_PATTERN) + 1); - strcpy(filename, tmpdir); - strcat(filename, TEMPFILE_PATTERN); - - (void) umask(077); /* Create with restrictive permissions */ - fd = mkstemp(filename); - if (fd == -1) - exit_error(OTHER_PROBLEM, "Could not create temporary file."); - if (!(file = fdopen(fd, "r+"))) - exit_error(OTHER_PROBLEM, "Could not open temporary file."); - if (unlink(filename) == -1) - exit_error(OTHER_PROBLEM, "Could not unlink temporary file."); - free(filename); - - while (fgets(buffer, sizeof(buffer), stdin)) { - fputs(buffer, file); - } - fseek(file, 0L, SEEK_SET); - - return file; -} - -/* - * Performs a restore from a file - */ -static void set_restore(char *argv0) -{ - char buffer[1024]; - char *ptr, *name = NULL; - char cmd = ' '; - int first_pass, i; - struct settype *settype = NULL; - struct ip_set_req_setnames *header; - ip_set_id_t idx; - FILE *in; - int res; - - /* Create and store stdin in temporary file */ - in = create_tempfile(); - - /* Load existing sets from kernel */ - load_set_list(IPSET_TOKEN_ALL, &idx, - IP_SET_OP_LIST_SIZE, CMD_RESTORE); - - restore_line = 0; - restore_size = ALIGNED(sizeof(struct ip_set_req_setnames)); /* header */ - DP("restore_size: %u", restore_size); - /* First pass: calculate required amount of data */ - while (fgets(buffer, sizeof(buffer), in)) { - restore_line++; - - if (buffer[0] == '\n') - continue; - else if (buffer[0] == '#') - continue; - else if (strcmp(buffer, "COMMIT\n") == 0) { - /* Enable restore mode */ - restore = 1; - break; - } - - /* -N, -A or -B */ - ptr = strtok(buffer, " \t\n"); - DP("ptr: %s", ptr); - if (ptr == NULL - || ptr[0] != '-' - || !(ptr[1] == 'N' - || ptr[1] == 'A' - || ptr[1] == 'B') - || ptr[2] != '\0') { - exit_error(PARAMETER_PROBLEM, - "Line %u does not start as a valid restore command\n", - restore_line); - } - cmd = ptr[1]; - /* setname */ - ptr = strtok(NULL, " \t\n"); - DP("setname: %s", ptr); - if (ptr == NULL) - exit_error(PARAMETER_PROBLEM, - "Missing set name in line %u\n", - restore_line); - DP("cmd %c", cmd); - switch (cmd) { - case 'N': { - name = check_set_name(ptr); - /* settype */ - ptr = strtok(NULL, " \t\n"); - if (ptr == NULL) - exit_error(PARAMETER_PROBLEM, - "Missing settype in line %u\n", - restore_line); - settype = check_set_typename(ptr); - restore_size += ALIGNED(sizeof(struct ip_set_restore)) - + ALIGNED(settype->create_size); - DP("restore_size (N): %u", restore_size); - break; - } - case 'A': { - if (name == NULL - || strncmp(name, ptr, sizeof(name)) != 0) - exit_error(PARAMETER_PROBLEM, - "Add IP to set %s in line %u without " - "preceding corresponding create set line\n", - ptr, restore_line); - restore_size += ALIGNED(settype->adt_size); - DP("restore_size (A): %u", restore_size); - break; - } - default: { - exit_error(PARAMETER_PROBLEM, - "Unrecognized restore command in line %u\n", - restore_line); - } - } /* end of switch */ - } - /* Sanity checking */ - if (!restore) - exit_error(PARAMETER_PROBLEM, - "Missing COMMIT line\n"); - restore_size += ALIGNED(sizeof(struct ip_set_restore)); /* marker */ - DP("restore_size: %u", restore_size); - restore_data = ipset_malloc(restore_size); - header = (struct ip_set_req_setnames *) restore_data; - header->op = IP_SET_OP_RESTORE; - header->size = restore_size; - restore_offset = ALIGNED(sizeof(struct ip_set_req_setnames)); - - /* Rewind to scan the file again */ - fseek(in, 0L, SEEK_SET); - first_pass = restore_line; - restore_line = 0; - - /* Initialize newargv/newargc */ - newargv[newargc++] = ipset_strdup(argv0); - - /* Second pass: build up restore request */ - while (fgets(buffer, sizeof(buffer), in)) { - restore_line++; - - if (buffer[0] == '\n') - continue; - else if (buffer[0] == '#') - continue; - else if (strcmp(buffer, "COMMIT\n") == 0) - goto do_restore; - DP("restoring: %s", buffer); - /* Build faked argv, argc */ - build_argv(restore_line, buffer); - for (i = 0; i < newargc; i++) - DP("argv[%u]: %s", i, newargv[i]); - - /* Parse line */ - parse_commandline(newargc, newargv); - } - exit_error(PARAMETER_PROBLEM, - "Broken restore file\n"); - do_restore: - if (restore_size == (restore_offset + ALIGNED(sizeof(struct ip_set_restore)))) { - /* No bindings */ - struct ip_set_restore *marker = - (struct ip_set_restore *) (restore_data + restore_offset); - - marker->index = IP_SET_INVALID_ID; - marker->header_size = marker->members_size = 0; - restore_offset += ALIGNED(sizeof(struct ip_set_restore)); - DP("restore marker, restore_offset: %zu", restore_offset); - } - if (restore_size != restore_offset) - exit_error(PARAMETER_PROBLEM, - "Giving up, restore file is screwed up!"); - res = kernel_getfrom_handleerrno(CMD_RESTORE, restore_data, &restore_size); - - if (res != 0) { - if (restore_size != sizeof(struct ip_set_req_setnames)) - exit_error(PARAMETER_PROBLEM, - "Communication with kernel failed (%u %u)!", - restore_size, sizeof(struct ip_set_req_setnames)); - /* Check errors */ - header = (struct ip_set_req_setnames *) restore_data; - if (header->size != 0) - exit_error(PARAMETER_PROBLEM, - "Committing restoring failed at line %u!", - header->size); - } -} - -/* - * Send ADT_GET order to kernel for a set - */ -static struct set *set_adt_get(const char *name) -{ - struct ip_set_req_adt_get req_adt_get; - struct set *set; - socklen_t size; - - DP("%s", name); - - check_protocolversion(); - - req_adt_get.op = IP_SET_OP_ADT_GET; - req_adt_get.version = protocol_version; - strcpy(req_adt_get.set.name, name); - size = sizeof(struct ip_set_req_adt_get); - - kernel_getfrom(CMD_ADT_GET, (void *) &req_adt_get, &size); - - set = ipset_malloc(sizeof(struct set)); - strcpy(set->name, name); - set->index = req_adt_get.set.index; - set->settype = settype_load(req_adt_get.typename); - - return set; -} - -/* - * Send add/del/test order to kernel for a set - */ -static int set_adtip(struct set *set, const char *adt, - unsigned op, unsigned cmd) -{ - struct ip_set_req_adt *req_adt; - size_t size; - void *data; - int res = 0; - - DP("%s -> %s", set->name, adt); - - /* Alloc memory for the data to send */ - size = ALIGNED(sizeof(struct ip_set_req_adt)) + set->settype->adt_size ; - DP("alloc size %zu", size); - data = ipset_malloc(size); - - /* Fill out the request */ - req_adt = (struct ip_set_req_adt *) data; - req_adt->op = op; - req_adt->index = set->index; - memcpy(data + ALIGNED(sizeof(struct ip_set_req_adt)), - set->settype->data, set->settype->adt_size); - - if (kernel_sendto_handleerrno(cmd, data, size) == -1) - switch (op) { - case IP_SET_OP_ADD_IP: - exit_error(OTHER_PROBLEM, "%s is already in set %s.", - adt, set->name); - break; - case IP_SET_OP_DEL_IP: - exit_error(OTHER_PROBLEM, "%s is not in set %s.", - adt, set->name); - break; - case IP_SET_OP_TEST_IP: - ipset_printf("%s is in set %s.", adt, set->name); - res = 0; - break; - default: - break; - } - else - switch (op) { - case IP_SET_OP_TEST_IP: - ipset_printf("%s is NOT in set %s.", adt, set->name); - res = 1; - break; - default: - break; - } - free(data); - - return res; -} - -static void set_restore_add(struct set *set, const char *adt UNUSED) -{ - DP("%s %s", set->name, adt); - /* Sanity checking */ - if (restore_offset + ALIGNED(set->settype->adt_size) > restore_size) - exit_error(PARAMETER_PROBLEM, - "Giving up, restore file is screwed up!"); - - memcpy(restore_data + restore_offset, - set->settype->data, set->settype->adt_size); - restore_set->members_size += ALIGNED(set->settype->adt_size); - restore_offset += ALIGNED(set->settype->adt_size); - - DP("restore_offset: %zu", restore_offset); -} - -/* - * Print operation - */ - -/* Help function to set_list() */ -static size_t print_set(void *data, unsigned options) -{ - struct ip_set_list *setlist = data; - struct set *set = set_list[setlist->index]; - struct settype *settype = set->settype; - size_t offset; - - /* Pretty print the set */ - DP("header size: %u, members size: %u", - setlist->header_size, setlist->members_size); - printf("Name: %s\n", set->name); - printf("Type: %s\n", settype->typename); - printf("References: %d\n", setlist->ref); - - /* Init header */ - offset = ALIGNED(sizeof(struct ip_set_list)); - settype->initheader(set, data + offset); - - /* Pretty print the type header */ - printf("Header:"); - settype->printheader(set, options); - - /* Pretty print all IPs */ - printf("Members:\n"); - offset += setlist->header_size; - DP("Aligned: %u, offset: %zu, members_size %u\n", !DONT_ALIGN, offset, - setlist->members_size); - if (options & OPT_SORTED) - settype->printips_sorted(set, data + offset, - setlist->members_size, options, - DONT_ALIGN); - else - settype->printips(set, data + offset, - setlist->members_size, options, - DONT_ALIGN); - - printf("\n"); /* One newline between sets */ - - return (offset + setlist->members_size); -} - -static int try_list_sets(const char name[IP_SET_MAXNAMELEN], - unsigned options) -{ - void *data = NULL; - ip_set_id_t idx; - socklen_t size, req_size; - int res = 0; - - /* Default is numeric listing */ - if (!(options & (OPT_RESOLVE|OPT_NUMERIC))) - options |= OPT_NUMERIC; - - DP("%s", name); - /* Load set_list from kernel */ - size = req_size = load_set_list(name, &idx, - IP_SET_OP_LIST_SIZE, CMD_LIST); - - if (size) { - /* Get sets and print them */ - data = ipset_malloc(size); - ((struct ip_set_req_list *) data)->op = IP_SET_OP_LIST; - ((struct ip_set_req_list *) data)->index = idx; - res = kernel_getfrom_handleerrno(CMD_LIST, data, &size); - DP("get_lists getsockopt() res=%d errno=%d", res, errno); - - if (res != 0 || size != req_size) { - free(data); - return -EAGAIN; - } - size = 0; - } - while (size != req_size) - size += print_set(data + size, options); - - ipset_free(data); - return res; -} - -/* Print a set or all sets - * All sets: name = NULL - */ -static void list_sets(const char name[IP_SET_MAXNAMELEN], unsigned options) -{ - int i; - - DP("%s", name); - for (i = 0; i < LIST_TRIES; i++) - if (try_list_sets(name, options) == 0) - return; - - if (errno == EAGAIN) - exit_error(OTHER_PROBLEM, - "Tried to list sets from kernel %d times" - " and failed. Please try again when the load on" - " the sets has gone down.", LIST_TRIES); - else - kernel_error(CMD_LIST, errno); -} - -/* Prints help - * If settype is non null help for that type is printed as well - */ -static void set_help(const struct settype *settype) -{ - printf("%s v%s\n\n" - "Usage: %s -N new-set settype [options]\n" - " %s -[XFLSH] [set] [options]\n" - " %s -[EW] from-set to-set\n" - " %s -[ADT] set IP\n" - " %s -R\n" - " %s -v\n" - " %s -h (print this help information)\n\n", - program_name, program_version, - program_name, program_name, program_name, - program_name, program_name, program_name, - program_name); - - printf("Commands:\n" - "Either long or short options are allowed.\n" - " --create -N setname settype \n" - " Create a new set\n" - " --destroy -X [setname]\n" - " Destroy a set or all sets\n" - " --flush -F [setname]\n" - " Flush a set or all sets\n" - " --rename -E from-set to-set\n" - " Rename from-set to to-set\n" - " --swap -W from-set to-set\n" - " Swap the content of two existing sets\n" - " --list -L [setname] [options]\n" - " List the IPs in a set or all sets\n" - " --save -S [setname]\n" - " Save the set or all sets to stdout\n" - " --restore -R [option]\n" - " Restores a saved state\n" - " --add -A setname IP\n" - " Add an IP to a set\n" - " --del -D setname IP\n" - " Deletes an IP from a set\n" - " --test -T setname IP \n" - " Tests if an IP exists in a set.\n" - " --help -H [settype]\n" - " Prints this help, and settype specific help\n" - " --version -V\n" - " Prints version information\n\n" - "Options:\n" - " --sorted -s Numeric sort of the IPs in -L\n" - " --numeric -n Numeric output of addresses in a -L (default)\n" - " --resolve -r Try to resolve addresses in a -L\n" - " --quiet -q Suppress any output to stdout and stderr.\n"); -#ifdef IPSET_DEBUG - printf(" --debug -z Enable debugging\n\n"); -#else - printf("\n"); -#endif - - if (settype != NULL) { - printf("Type '%s' specific:\n", settype->typename); - settype->usage(); - } -} - -static int find_cmd(int option) -{ - int i; - - for (i = 1; i <= NUMBER_OF_CMD; i++) - if (cmdflags[i] == option) - return i; - - return CMD_NONE; -} - -static int parse_adt_cmdline(int command, - const char *name, - char *adt, - struct set **set, - struct settype **settype) -{ - int res = 0; - - *set = restore ? set_find_byname(name) : set_adt_get(name); - - /* Reset space for adt data */ - *settype = (*set)->settype; - memset((*settype)->data, 0, (*settype)->adt_size); - - res = (*settype)->adt_parser(command, adt, (*settype)->data); - - return res; -} - -/* Main worker function */ -int parse_commandline(int argc, char *argv[]) -{ - int res = 0; - int command = CMD_NONE; - unsigned options = 0; - int c; - - char *name = NULL; /* All except -H, -R */ - char *newname = NULL; /* -E, -W */ - char *adt = NULL; /* -A, -D, -T */ - struct set *set = NULL; /* -A, -D, -T */ - struct settype *settype = NULL; /* -N, -H */ - char all_sets[] = IPSET_TOKEN_ALL; - - struct option *opts = opts_long; - - /* Suppress error messages: we may add new options if we - demand-load a protocol. */ - opterr = 0; - /* Reset optind to 0 for restore */ - optind = 0; - - while ((c = getopt_long(argc, argv, opts_short, opts, NULL)) != -1) { - - DP("commandline parsed: opt %c (%s)", c, argv[optind]); - - switch (c) { - /* - * Command selection - */ - case 'h': - case 'H':{ /* Help: -H [typename [options]] */ - check_protocolversion(); - set_command(&command, CMD_HELP); - - if (optarg) - settype = check_set_typename(optarg); - else if (optind < argc - && argv[optind][0] != '-') - settype = check_set_typename(argv[optind++]); - - break; - } - - case 'V': - case 'v': { /* Version */ - printf("%s v%s, protocol version %u.\n", - program_name, program_version, - IP_SET_PROTOCOL_VERSION); - check_protocolversion(); - printf("Kernel module protocol version %u.\n", - protocol_version); - exit(0); - } - - case 'N':{ /* Create: -N name typename options */ - set_command(&command, CMD_CREATE); - - name = check_set_name(optarg); - - /* Protect reserved names */ - if (name[0] == ':') - exit_error(PARAMETER_PROBLEM, - "setname might not start with colon", - cmd2char(CMD_CREATE)); - - if (optind < argc - && argv[optind][0] != '-') - settype = check_set_typename(argv[optind++]); - else - exit_error(PARAMETER_PROBLEM, - "-%c requires setname and settype", - cmd2char(CMD_CREATE)); - - DP("merge options"); - /* Merge the create options */ - opts = merge_options(opts, - settype->create_opts, - &settype->option_offset); - - /* Reset space for create data */ - memset(settype->data, 0, settype->create_size); - - /* Zero the flags */ - settype->flags = 0; - - DP("call create_init"); - /* Call the settype create_init */ - settype->create_init(settype->data); - - break; - } - - case 'X': /* Destroy */ - case 'F': /* Flush */ - case 'L': /* List */ - case 'S':{ /* Save */ - set_command(&command, find_cmd(c)); - - if (optarg) - name = check_set_name(optarg); - else if (optind < argc - && argv[optind][0] != '-') - name = check_set_name(argv[optind++]); - else - name = all_sets; - - break; - } - - case 'R':{ /* Restore */ - set_command(&command, find_cmd(c)); - - break; - } - - case 'E': /* Rename */ - case 'W':{ /* Swap */ - set_command(&command, find_cmd(c)); - name = check_set_name(optarg); - - if (optind < argc - && argv[optind][0] != '-') - newname = check_set_name(argv[optind++]); - else - exit_error(PARAMETER_PROBLEM, - "-%c requires a setname " - "and the new name for that set", - cmd2char(CMD_RENAME)); - - break; - } - - case 'A': /* Add IP */ - case 'D': /* Del IP */ - case 'T':{ /* Test IP */ - set_command(&command, find_cmd(c)); - - name = check_set_name(optarg); - - /* IP */ - if (optind < argc - && argv[optind][0] != '-') - adt = argv[optind++]; - else - exit_error(PARAMETER_PROBLEM, - "-%c requires setname and IP", - c); - - res = parse_adt_cmdline(command, name, adt, - &set, &settype); - - if (!res) - exit_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", - argv[optind - 1]); - - res = 0; - break; - } - - /* options */ - - case 'n': - add_option(&options, OPT_NUMERIC); - break; - - case 'r': - if (!(options & OPT_NUMERIC)) - add_option(&options, OPT_RESOLVE); - break; - - case 's': - add_option(&options, OPT_SORTED); - break; - - case 'q': - add_option(&options, OPT_QUIET); - option_quiet = 1; - break; - -#ifdef IPSET_DEBUG - case 'z': /* debug */ - add_option(&options, OPT_DEBUG); - option_debug = 1; - break; -#endif - - case 1: /* non option */ - printf("Bad argument `%s'\n", optarg); - exit_tryhelp(PARAMETER_PROBLEM); - break; /*always good */ - - default:{ - DP("default"); - - switch (command) { - case CMD_CREATE: - res = settype->create_parse( - c - settype->option_offset, - argv, - settype->data, - &settype->flags); - break; - - default: - res = 0; /* failed */ - } /* switch (command) */ - - - if (!res) - exit_error(PARAMETER_PROBLEM, - "Unknown arg `%s'", - argv[optind - 1]); - - res = 0; - } - - DP("next arg"); - } /* switch */ - - } /* while( getopt_long() ) */ - - - if (optind < argc) - exit_error(PARAMETER_PROBLEM, - "unknown arguments found on commandline"); - if (command == CMD_NONE) - exit_error(PARAMETER_PROBLEM, "no command specified"); - - /* Check options */ - generic_opt_check(command, options); - - DP("cmd: %c", cmd2char(command)); - - check_protocolversion(); - - switch (command) { - case CMD_CREATE: - DP("CMD_CREATE"); - if (restore) - set_restore_create(name, settype); - else - set_create(name, settype); - break; - - case CMD_DESTROY: - set_destroy(name, IP_SET_OP_DESTROY, CMD_DESTROY); - break; - - case CMD_FLUSH: - set_destroy(name, IP_SET_OP_FLUSH, CMD_FLUSH); - break; - - case CMD_RENAME: - set_rename(name, newname, IP_SET_OP_RENAME, CMD_RENAME); - break; - - case CMD_SWAP: - set_rename(name, newname, IP_SET_OP_SWAP, CMD_SWAP); - break; - - case CMD_LIST: - list_sets(name, options); - break; - - case CMD_SAVE: - set_save(name); - break; - - case CMD_RESTORE: - set_restore(argv[0]); - break; - - case CMD_ADD: - if (restore) - set_restore_add(set, adt); - else - set_adtip(set, adt, IP_SET_OP_ADD_IP, CMD_ADD); - break; - - case CMD_DEL: - set_adtip(set, adt, IP_SET_OP_DEL_IP, CMD_DEL); - break; - - case CMD_TEST: - res = set_adtip(set, adt, IP_SET_OP_TEST_IP, CMD_TEST); - break; - - case CMD_HELP: - set_help(settype); - break; - - default: - /* Will never happen */ - break; /* Keep the compiler happy */ - - } /* switch( command ) */ - - return res; -} - - -int main(int argc, char *argv[]) -{ - return parse_commandline(argc, argv); - -} diff --git a/ipset.h b/ipset.h deleted file mode 100644 index c49418d..0000000 --- a/ipset.h +++ /dev/null @@ -1,200 +0,0 @@ -#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 /* struct option */ -#include -#include - -#include - -#define IPSET_LIB_NAME "/libipset_%s.so" -#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_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 */ - u_int32_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 */ - u_int32_t adt_size; - - /* Function which parses command options */ - ip_set_ip_t (*adt_parser) (int cmd, const char *optarg, void *data); - - /* - * Printing - */ - - /* Size of header. */ - u_int32_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, u_int32_t len, - unsigned options, char dont_align); - - /* Pretty print all IPs sorted */ - void (*printips_sorted) (struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align); - - /* 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, u_int32_t len, - unsigned options, char dont_align); - - /* Print usage */ - void (*usage) (void); - - /* Internal data */ - void *header; - void *data; - 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(int 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); - -extern struct set *set_find_byname(const char *name); -extern struct set *set_find_byid(ip_set_id_t id); - -extern unsigned warn_once; - -#define BITS_PER_LONG (8*sizeof(ip_set_ip_t)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) - -static inline int test_bit(int nr, const ip_set_ip_t *addr) -{ - return 1 & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); -} - -#define UNUSED __attribute__ ((unused)) -#define CONSTRUCTOR(module) \ -void __attribute__ ((constructor)) module##_init(void); \ -void module##_init(void) - -#endif /* __IPSET_H */ diff --git a/ipset_iphash.c b/ipset_iphash.c deleted file mode 100644 index 0bc5bd1..0000000 --- a/ipset_iphash.c +++ /dev/null @@ -1,279 +0,0 @@ -/* 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 /* UINT_MAX */ -#include /* *printf */ -#include /* mem* */ - -#include "ipset.h" - -#include - -#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 -iphash_create_init(void *data) -{ - struct ip_set_req_iphash_create *mydata = 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 -iphash_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *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 -iphash_create_final(void *data UNUSED, unsigned int flags UNUSED) -{ -} - -/* Create commandline options */ -static const struct option create_opts[] = { - {.name = "hashsize", .has_arg = required_argument, .val = '1'}, - {.name = "probes", .has_arg = required_argument, .val = '2'}, - {.name = "resize", .has_arg = required_argument, .val = '3'}, - {.name = "netmask", .has_arg = required_argument, .val = '4'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -iphash_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_iphash *mydata = 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 -iphash_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_iphash_create *header = data; - struct ip_set_iphash *map = 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 -iphash_printheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_iphash *mysetdata = 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 -iphash_printips(struct set *set UNUSED, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - size_t offset = 0; - ip_set_ip_t *ip; - - while (offset < len) { - ip = data + offset; - printf("%s\n", ip_tostring(*ip, options)); - offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); - } -} - -static void -iphash_saveheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_iphash *mysetdata = 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 -iphash_saveips(struct set *set UNUSED, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - size_t offset = 0; - ip_set_ip_t *ip; - - while (offset < len) { - ip = data + offset; - printf("-A %s %s\n", set->name, ip_tostring(*ip, options)); - offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); - } -} - -static void -iphash_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 = iphash_create_init, - .create_parse = iphash_create_parse, - .create_final = iphash_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_iphash), - .adt_parser = iphash_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_iphash), - .initheader = iphash_initheader, - .printheader = iphash_printheader, - .printips = iphash_printips, - .printips_sorted = iphash_printips, - .saveheader = iphash_saveheader, - .saveips = iphash_saveips, - - .usage = iphash_usage, -}; - -CONSTRUCTOR(iphash) -{ - settype_register(&settype_iphash); - -} diff --git a/ipset_ipmap.c b/ipset_ipmap.c deleted file mode 100644 index 87b8e69..0000000 --- a/ipset_ipmap.c +++ /dev/null @@ -1,376 +0,0 @@ -/* 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 /* *printf */ -#include /* mem* */ - -#include "ipset.h" - -#include - -#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 -ipmap_create_init(void *data) -{ - struct ip_set_req_ipmap_create *mydata = data; - - DP("create INIT"); - mydata->netmask = 0xFFFFFFFF; -} - -/* Function which parses command options; returns true if it ate an option */ -static int -ipmap_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) -{ - struct ip_set_req_ipmap_create *mydata = 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; -} - -/* Final check; exit if not ok. */ -static void -ipmap_create_final(void *data, unsigned int flags) -{ - struct ip_set_req_ipmap_create *mydata = data; - ip_set_ip_t range; - - 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)) { - exit_error(PARAMETER_PROBLEM, - "You have to define a full network with --from" - " and --to if you specify the --network option\n"); - } - netmask_bits = mask_to_bits(mydata->netmask); - if (netmask_bits <= mask_bits) { - exit_error(PARAMETER_PROBLEM, - "%d netmask specifies larger or equal netblock than the network itself\n"); - } - 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[] = { - {.name = "from", .has_arg = required_argument, .val = '1'}, - {.name = "to", .has_arg = required_argument, .val = '2'}, - {.name = "network", .has_arg = required_argument, .val = '3'}, - {.name = "netmask", .has_arg = required_argument, .val = '4'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -ipmap_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_ipmap *mydata = 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 -ipmap_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_ipmap_create *header = data; - struct ip_set_ipmap *map = 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: %d %d", mask_bits, netmask_bits); - map->hosts = 2 << (32 - netmask_bits - 1); - map->sizeid = 2 << (netmask_bits - mask_bits - 1); - } - - DP("%d %d", map->hosts, map->sizeid ); -} - -static void -ipmap_printheader(struct set *set, unsigned options) -{ - struct ip_set_ipmap *mysetdata = 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 inline void -__ipmap_printips_sorted(struct set *set, void *data, - u_int32_t len UNUSED, unsigned options) -{ - struct ip_set_ipmap *mysetdata = 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 -ipmap_printips_sorted(struct set *set, void *data, - u_int32_t len, unsigned options, - char dont_align) -{ - ip_set_ip_t *ip; - size_t offset = 0; - - if (dont_align) - return __ipmap_printips_sorted(set, data, len, options); - - while (offset < len) { - DP("offset: %zu, len %u\n", offset, len); - ip = data + offset; - printf("%s\n", ip_tostring(*ip, options)); - offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); - } -} - -static void -ipmap_saveheader(struct set *set, unsigned options) -{ - struct ip_set_ipmap *mysetdata = 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 inline void -__ipmap_saveips(struct set *set, void *data, u_int32_t len UNUSED, - unsigned options) -{ - struct ip_set_ipmap *mysetdata = 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 -ipmap_saveips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - ip_set_ip_t *ip; - size_t offset = 0; - - if (dont_align) - return __ipmap_saveips(set, data, len, options); - - while (offset < len) { - ip = data + offset; - printf("-A %s %s\n", set->name, ip_tostring(*ip, options)); - offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); - } -} - -static void -ipmap_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 = ipmap_create_init, - .create_parse = ipmap_create_parse, - .create_final = ipmap_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_ipmap), - .adt_parser = ipmap_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_ipmap), - .initheader = ipmap_initheader, - .printheader = ipmap_printheader, - .printips = ipmap_printips_sorted, - .printips_sorted = ipmap_printips_sorted, - .saveheader = ipmap_saveheader, - .saveips = ipmap_saveips, - - .usage = ipmap_usage, -}; - -CONSTRUCTOR(ipmap) -{ - settype_register(&settype_ipmap); - -} diff --git a/ipset_ipporthash.c b/ipset_ipporthash.c deleted file mode 100644 index 9249b2a..0000000 --- a/ipset_ipporthash.c +++ /dev/null @@ -1,350 +0,0 @@ -/* 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 /* UINT_MAX */ -#include /* *printf */ -#include /* mem*, str* */ - -#include "ipset.h" - -#include - -#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 -ipporthash_create_init(void *data) -{ - struct ip_set_req_ipporthash_create *mydata = 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 -ipporthash_create_parse(int c, char *argv[] UNUSED, void *data, - unsigned *flags) -{ - struct ip_set_req_ipporthash_create *mydata = 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 -ipporthash_create_final(void *data, unsigned int flags) -{ - struct ip_set_req_ipporthash_create *mydata = 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[] = { - {.name = "hashsize", .has_arg = required_argument, .val = '1'}, - {.name = "probes", .has_arg = required_argument, .val = '2'}, - {.name = "resize", .has_arg = required_argument, .val = '3'}, - {.name = "from", .has_arg = required_argument, .val = '4'}, - {.name = "to", .has_arg = required_argument, .val = '5'}, - {.name = "network", .has_arg = required_argument, .val = '6'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -ipporthash_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_ipporthash *mydata = data; - char *saved = ipset_strdup(arg); - char *ptr, *tmp = saved; - - DP("ipporthash: %p %p", arg, data); - - if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) - fprintf(stderr, "Warning: please use ',' separator token between ip,port.\n" - "Next release won't support old separator tokens.\n"); - - 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"); - - if (!(mydata->ip || mydata->port)) - exit_error(PARAMETER_PROBLEM, - "Zero valued IP address and port `%s' specified", arg); - ipset_free(saved); - return 1; -}; - -/* - * Print and save - */ - -static void -ipporthash_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_ipporthash_create *header = data; - struct ip_set_ipporthash *map = 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 -ipporthash_printheader(struct set *set, unsigned options) -{ - struct ip_set_ipporthash *mysetdata = 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 -ipporthash_printips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_ipporthash *mysetdata = set->settype->header; - size_t offset = 0; - ip_set_ip_t *ipptr, ip; - uint16_t port; - - while (offset < len) { - ipptr = data + offset; - ip = (*ipptr>>16) + mysetdata->first_ip; - port = (uint16_t) *ipptr; - printf("%s,%s\n", - ip_tostring(ip, options), - port_tostring(port, options)); - offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); - } -} - -static void -ipporthash_saveheader(struct set *set, unsigned options) -{ - struct ip_set_ipporthash *mysetdata = 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 -ipporthash_saveips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_ipporthash *mysetdata = set->settype->header; - size_t offset = 0; - ip_set_ip_t *ipptr, ip; - uint16_t port; - - while (offset < len) { - ipptr = data + offset; - 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 += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); - } -} - -static void -ipporthash_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 = ipporthash_create_init, - .create_parse = ipporthash_create_parse, - .create_final = ipporthash_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_ipporthash), - .adt_parser = ipporthash_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_ipporthash), - .initheader = ipporthash_initheader, - .printheader = ipporthash_printheader, - .printips = ipporthash_printips, - .printips_sorted = ipporthash_printips, - .saveheader = ipporthash_saveheader, - .saveips = ipporthash_saveips, - - .usage = ipporthash_usage, -}; - -CONSTRUCTOR(ipporthash) -{ - settype_register(&settype_ipporthash); - -} diff --git a/ipset_ipportiphash.c b/ipset_ipportiphash.c deleted file mode 100644 index 49861bf..0000000 --- a/ipset_ipportiphash.c +++ /dev/null @@ -1,361 +0,0 @@ -/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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 /* UINT_MAX */ -#include /* *printf */ -#include /* mem*, str* */ - -#include "ipset.h" - -#include - -#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 -ipportiphash_create_init(void *data) -{ - struct ip_set_req_ipportiphash_create *mydata = 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 -ipportiphash_create_parse(int c, char *argv[] UNUSED, void *data, - unsigned *flags) -{ - struct ip_set_req_ipportiphash_create *mydata = 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 -ipportiphash_create_final(void *data, unsigned int flags) -{ - struct ip_set_req_ipportiphash_create *mydata = 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[] = { - {.name = "hashsize", .has_arg = required_argument, .val = '1'}, - {.name = "probes", .has_arg = required_argument, .val = '2'}, - {.name = "resize", .has_arg = required_argument, .val = '3'}, - {.name = "from", .has_arg = required_argument, .val = '4'}, - {.name = "to", .has_arg = required_argument, .val = '5'}, - {.name = "network", .has_arg = required_argument, .val = '6'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -ipportiphash_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_ipportiphash *mydata = data; - char *saved = ipset_strdup(arg); - char *ptr, *tmp = saved; - - DP("ipportiphash: %p %p", arg, data); - - if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) - fprintf(stderr, "Warning: please use ',' separator token between ip,port,ip.\n" - "Next release won't support old separator tokens.\n"); - - ptr = strsep(&tmp, ":%,"); - parse_ip(ptr, &mydata->ip); - - if (!tmp) - exit_error(PARAMETER_PROBLEM, - "IP address, port and IP address must be specified: ip,port,ip"); - - ptr = strsep(&tmp, ":%,"); - parse_port(ptr, &mydata->port); - if (tmp) - parse_ip(tmp, &mydata->ip1); - else - exit_error(PARAMETER_PROBLEM, - "IP address, port and IP address must be specified: ip,port,ip"); - if (!(mydata->ip || mydata->port || mydata->ip1)) - exit_error(PARAMETER_PROBLEM, - "Zero valued IP address, port and IP address `%s' specified", arg); - ipset_free(saved); - return 1; -}; - -/* - * Print and save - */ - -static void -ipportiphash_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_ipportiphash_create *header = data; - struct ip_set_ipportiphash *map = set->settype->header; - - memset(map, 0, sizeof(struct ip_set_ipportiphash)); - map->hashsize = header->hashsize; - map->probes = header->probes; - map->resize = header->resize; - map->first_ip = header->from; - map->last_ip = header->to; -} - -static void -ipportiphash_printheader(struct set *set, unsigned options) -{ - struct ip_set_ipportiphash *mysetdata = 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 -ipportiphash_printips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_ipportiphash *mysetdata = set->settype->header; - size_t offset = 0; - struct ipportip *ipptr; - ip_set_ip_t ip; - uint16_t port; - - while (offset < len) { - ipptr = data + offset; - ip = (ipptr->ip>>16) + mysetdata->first_ip; - port = (uint16_t) ipptr->ip; - printf("%s,%s,", - ip_tostring(ip, options), - port_tostring(port, options)); - printf("%s\n", - ip_tostring(ipptr->ip1, options)); - offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); - } -} - -static void -ipportiphash_saveheader(struct set *set, unsigned options) -{ - struct ip_set_ipportiphash *mysetdata = 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 -ipportiphash_saveips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_ipportiphash *mysetdata = set->settype->header; - size_t offset = 0; - struct ipportip *ipptr; - ip_set_ip_t ip; - uint16_t port; - - while (offset < len) { - ipptr = data + offset; - ip = (ipptr->ip>>16) + mysetdata->first_ip; - port = (uint16_t) ipptr->ip; - printf("-A %s %s,%s,", set->name, - ip_tostring(ip, options), - port_tostring(port, options)); - printf("%s\n", - ip_tostring(ipptr->ip1, options)); - offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); - } -} - -static void -ipportiphash_usage(void) -{ - printf - ("-N set ipportiphash --from IP --to IP\n" - " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" - "-N set ipportiphash --network IP/mask\n" - " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" - "-A set IP,port,IP\n" - "-D set IP,port,IP\n" - "-T set IP,port,IP\n"); -} - -static struct settype settype_ipportiphash = { - .typename = SETTYPE_NAME, - .protocol_version = IP_SET_PROTOCOL_VERSION, - - /* Create */ - .create_size = sizeof(struct ip_set_req_ipportiphash_create), - .create_init = ipportiphash_create_init, - .create_parse = ipportiphash_create_parse, - .create_final = ipportiphash_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_ipportiphash), - .adt_parser = ipportiphash_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_ipportiphash), - .initheader = ipportiphash_initheader, - .printheader = ipportiphash_printheader, - .printips = ipportiphash_printips, - .printips_sorted = ipportiphash_printips, - .saveheader = ipportiphash_saveheader, - .saveips = ipportiphash_saveips, - - .usage = ipportiphash_usage, -}; - -CONSTRUCTOR(ipportiphash) -{ - settype_register(&settype_ipportiphash); - -} diff --git a/ipset_ipportnethash.c b/ipset_ipportnethash.c deleted file mode 100644 index 3a60bf1..0000000 --- a/ipset_ipportnethash.c +++ /dev/null @@ -1,426 +0,0 @@ -/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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 /* UINT_MAX */ -#include /* *printf */ -#include /* mem*, str* */ - -#include "ipset.h" - -#include - -#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 -ipportnethash_create_init(void *data) -{ - struct ip_set_req_ipportnethash_create *mydata = 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 -ipportnethash_create_parse(int c, char *argv[] UNUSED, void *data, - unsigned *flags) -{ - struct ip_set_req_ipportnethash_create *mydata = 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 -ipportnethash_create_final(void *data, unsigned int flags) -{ - struct ip_set_req_ipportnethash_create *mydata = 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[] = { - {.name = "hashsize", .has_arg = required_argument, .val = '1'}, - {.name = "probes", .has_arg = required_argument, .val = '2'}, - {.name = "resize", .has_arg = required_argument, .val = '3'}, - {.name = "from", .has_arg = required_argument, .val = '4'}, - {.name = "to", .has_arg = required_argument, .val = '5'}, - {.name = "network", .has_arg = required_argument, .val = '6'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -ipportnethash_adt_parser(int cmd, const char *arg, void *data) -{ - struct ip_set_req_ipportnethash *mydata = data; - char *saved = ipset_strdup(arg); - char *ptr, *tmp = saved; - ip_set_ip_t cidr; - - DP("ipportnethash: %p %p", arg, data); - - if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) - fprintf(stderr, "Warning: please use ',' separator token between ip,port,net.\n" - "Next release won't support old separator tokens.\n"); - - ptr = strsep(&tmp, ":%,"); - parse_ip(ptr, &mydata->ip); - if (!tmp) - exit_error(PARAMETER_PROBLEM, - "IP address, port and network address must be specified: ip,port,net"); - - ptr = strsep(&tmp, ":%,"); - parse_port(ptr, &mydata->port); - if (!tmp) - exit_error(PARAMETER_PROBLEM, - "IP address, port and network address must be specified: ip,port,net"); - - 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->ip1); - ipset_free(saved); - return 1; -}; - -/* - * Print and save - */ - -static void -ipportnethash_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_ipportnethash_create *header = data; - struct ip_set_ipportnethash *map = set->settype->header; - - memset(map, 0, sizeof(struct ip_set_ipportnethash)); - map->hashsize = header->hashsize; - map->probes = header->probes; - map->resize = header->resize; - map->first_ip = header->from; - map->last_ip = header->to; -} - -static void -ipportnethash_printheader(struct set *set, unsigned options) -{ - struct ip_set_ipportnethash *mysetdata = 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 char buf[20]; - -static char * -unpack_ip_tostring(ip_set_ip_t ip, unsigned options UNUSED) -{ - 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), 0), buf); - return buf; -} - -static void -ipportnethash_printips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_ipportnethash *mysetdata = set->settype->header; - size_t offset = 0; - struct ipportip *ipptr; - ip_set_ip_t ip; - uint16_t port; - - while (offset < len) { - ipptr = data + offset; - ip = (ipptr->ip>>16) + mysetdata->first_ip; - port = (uint16_t) ipptr->ip; - printf("%s,%s,", - ip_tostring(ip, options), - port_tostring(port, options)); - printf("%s\n", - unpack_ip_tostring(ipptr->ip1, options)); - offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); - } -} - -static void -ipportnethash_saveheader(struct set *set, unsigned options) -{ - struct ip_set_ipportnethash *mysetdata = 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 -ipportnethash_saveips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_ipportnethash *mysetdata = set->settype->header; - size_t offset = 0; - struct ipportip *ipptr; - ip_set_ip_t ip; - uint16_t port; - - while (offset < len) { - ipptr = data + offset; - ip = (ipptr->ip>>16) + mysetdata->first_ip; - port = (uint16_t) ipptr->ip; - printf("-A %s %s,%s,", set->name, - ip_tostring(ip, options), - port_tostring(port, options)); - printf("%s\n", - unpack_ip_tostring(ipptr->ip, options)); - offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); - } -} - -static void -ipportnethash_usage(void) -{ - printf - ("-N set ipportnethash --from IP --to IP\n" - " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" - "-N set ipportnethash --network IP/mask\n" - " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" - "-A set IP,port,IP/net\n" - "-D set IP,port,IP/net\n" - "-T set IP,port,IP[/net]\n"); -} - -static struct settype settype_ipportnethash = { - .typename = SETTYPE_NAME, - .protocol_version = IP_SET_PROTOCOL_VERSION, - - /* Create */ - .create_size = sizeof(struct ip_set_req_ipportnethash_create), - .create_init = ipportnethash_create_init, - .create_parse = ipportnethash_create_parse, - .create_final = ipportnethash_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_ipportnethash), - .adt_parser = ipportnethash_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_ipportnethash), - .initheader = ipportnethash_initheader, - .printheader = ipportnethash_printheader, - .printips = ipportnethash_printips, - .printips_sorted = ipportnethash_printips, - .saveheader = ipportnethash_saveheader, - .saveips = ipportnethash_saveips, - - .usage = ipportnethash_usage, -}; - -CONSTRUCTOR(ipportnethash) -{ - settype_register(&settype_ipportnethash); - -} diff --git a/ipset_iptree.c b/ipset_iptree.c deleted file mode 100644 index 508e67a..0000000 --- a/ipset_iptree.c +++ /dev/null @@ -1,224 +0,0 @@ -/* 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 /* UINT_MAX */ -#include /* *printf */ -#include /* mem* */ - -#include "ipset.h" - -#include - -#define BUFLEN 30; - -#define OPT_CREATE_TIMEOUT 0x01U - -/* Initialize the create. */ -static void -iptree_create_init(void *data) -{ - struct ip_set_req_iptree_create *mydata = data; - - DP("create INIT"); - mydata->timeout = 0; -} - -/* Function which parses command options; returns true if it ate an option */ -static int -iptree_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) -{ - struct ip_set_req_iptree_create *mydata = 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 -iptree_create_final(void *data UNUSED, unsigned int flags UNUSED) -{ -} - -/* Create commandline options */ -static const struct option create_opts[] = { - {.name = "timeout", .has_arg = required_argument, .val = '1'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -iptree_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_iptree *mydata = data; - char *saved = ipset_strdup(arg); - char *ptr, *tmp = saved; - - DP("iptree: %p %p", arg, data); - - if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) - fprintf(stderr, "Warning: please use ',' separator token between ip,timeout.\n" - "Next release won't support old separator tokens.\n"); - - ptr = strsep(&tmp, ":%,"); - parse_ip(ptr, &mydata->ip); - - if (tmp) - string_to_number(tmp, 0, UINT_MAX, &mydata->timeout); - else - mydata->timeout = 0; - - ipset_free(saved); - return 1; -} - -/* - * Print and save - */ - -static void -iptree_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_iptree_create *header = data; - struct ip_set_iptree *map = set->settype->header; - - map->timeout = header->timeout; -} - -static void -iptree_printheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_iptree *mysetdata = set->settype->header; - - if (mysetdata->timeout) - printf(" timeout: %u", mysetdata->timeout); - printf("\n"); -} - -static void -iptree_printips_sorted(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_iptree *mysetdata = 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 += IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align); - } -} - -static void -iptree_saveheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_iptree *mysetdata = 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 -iptree_saveips(struct set *set, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - struct ip_set_iptree *mysetdata = 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 += IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align); - } -} - -static void -iptree_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 = iptree_create_init, - .create_parse = iptree_create_parse, - .create_final = iptree_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_iptree), - .adt_parser = iptree_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_iptree), - .initheader = iptree_initheader, - .printheader = iptree_printheader, - .printips = iptree_printips_sorted, /* We only have sorted version */ - .printips_sorted = iptree_printips_sorted, - .saveheader = iptree_saveheader, - .saveips = iptree_saveips, - - .usage = iptree_usage, -}; - -CONSTRUCTOR(iptree) -{ - settype_register(&settype_iptree); - -} diff --git a/ipset_iptreemap.c b/ipset_iptreemap.c deleted file mode 100644 index 22bdcb3..0000000 --- a/ipset_iptreemap.c +++ /dev/null @@ -1,208 +0,0 @@ -/* Copyright 2007 Sven Wegener - * - * 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 /* UINT_MAX */ -#include /* *printf */ -#include /* mem* */ - -#include "ipset.h" - -#include - -#define OPT_CREATE_GC 0x1 - -static void -iptreemap_create_init(void *data) -{ - struct ip_set_req_iptreemap_create *mydata = data; - - mydata->gc_interval = 0; -} - -static int -iptreemap_create_parse(int c, char *argv[] UNUSED, 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 -iptreemap_create_final(void *data UNUSED, unsigned int flags UNUSED) -{ -} - -static const struct option create_opts[] = { - {.name = "gc", .has_arg = required_argument, .val = 'g'}, - {NULL}, -}; - -static ip_set_ip_t -iptreemap_adt_parser(int cmd UNUSED, 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->ip, &mask); - mydata->end = mydata->ip | ~mask; - } else { - if ((ptr = strchr(tmp, ':')) != NULL && ++warn_once == 1) - fprintf(stderr, "Warning: please use '-' separator token between IP range.\n" - "Next release won't support old separator token.\n"); - ptr = strsep(&tmp, "-:"); - parse_ip(ptr, &mydata->ip); - - if (tmp) { - parse_ip(tmp, &mydata->end); - } else { - mydata->end = mydata->ip; - } - } - - ipset_free(saved); - - return 1; -} - -static void -iptreemap_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 -iptreemap_printheader(struct set *set, unsigned int options UNUSED) -{ - struct ip_set_iptreemap *mysetdata = set->settype->header; - - if (mysetdata->gc_interval) - printf(" gc: %u", mysetdata->gc_interval); - - printf("\n"); -} - -static void -iptreemap_printips_sorted(struct set *set UNUSED, void *data, - u_int32_t len, unsigned int options, char dont_align) -{ - 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->ip, options)); - if (req->ip != req->end) - printf("-%s", ip_tostring(req->end, options)); - printf("\n"); - - offset += IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align); - } -} - -static void -iptreemap_saveheader(struct set *set, unsigned int options UNUSED) -{ - 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 -iptreemap_saveips(struct set *set UNUSED, void *data, - u_int32_t len, unsigned int options, char dont_align) -{ - 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->ip, options)); - - if (req->ip != req->end) - printf("-%s", ip_tostring(req->end, options)); - - printf("\n"); - - offset += IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align); - } -} - -static void -iptreemap_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 = iptreemap_create_init, - .create_parse = iptreemap_create_parse, - .create_final = iptreemap_create_final, - .create_opts = create_opts, - - .adt_size = sizeof(struct ip_set_req_iptreemap), - .adt_parser = iptreemap_adt_parser, - - .header_size = sizeof(struct ip_set_iptreemap), - .initheader = iptreemap_initheader, - .printheader = iptreemap_printheader, - .printips = iptreemap_printips_sorted, - .printips_sorted = iptreemap_printips_sorted, - .saveheader = iptreemap_saveheader, - .saveips = iptreemap_saveips, - - .usage = iptreemap_usage, -}; - -CONSTRUCTOR(iptreemap) -{ - settype_register(&settype_iptreemap); -} diff --git a/ipset_macipmap.c b/ipset_macipmap.c deleted file mode 100644 index fb97cae..0000000 --- a/ipset_macipmap.c +++ /dev/null @@ -1,382 +0,0 @@ -/* 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 /* *printf */ -#include /* mem* */ -#include /* str* */ -#include /* ETH_ALEN */ - -#include "ipset.h" - -#include - -#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 -macipmap_create_init(void *data UNUSED) -{ - DP("create INIT"); - /* Nothing */ -} - -/* Function which parses command options; returns true if it ate an option */ -static int -macipmap_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) -{ - struct ip_set_req_macipmap_create *mydata = 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 -macipmap_create_final(void *data, unsigned int flags) -{ - struct ip_set_req_macipmap_create *mydata = 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[] = { - {.name = "from", .has_arg = required_argument, .val = '1'}, - {.name = "to", .has_arg = required_argument, .val = '2'}, - {.name = "network", .has_arg = required_argument, .val = '3'}, - {.name = "matchunset", .has_arg = no_argument, .val = '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 -macipmap_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_macipmap *mydata = data; - char *saved = ipset_strdup(arg); - char *ptr, *tmp = saved; - - DP("macipmap: %p %p", arg, data); - - ptr = strsep(&tmp, ","); - if (!tmp) { - tmp = saved; - ptr = strsep(&tmp, ":%"); - if (tmp && ++warn_once == 1) - fprintf(stderr, "Warning: please use ',' separator token between ip,mac.\n" - "Next release won't support old separator tokens.\n"); - } - 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 -macipmap_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_macipmap_create *header = data; - struct ip_set_macipmap *map = 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 -macipmap_printheader(struct set *set, unsigned options) -{ - struct ip_set_macipmap *mysetdata = 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 inline void -__macipmap_printips_sorted(struct set *set, void *data, - u_int32_t len UNUSED, unsigned options) -{ - struct ip_set_macipmap *mysetdata = set->settype->header; - struct ip_set_macip *table = data; - u_int32_t addr = mysetdata->first_ip; - - while (addr <= mysetdata->last_ip) { - if (table[addr - mysetdata->first_ip].match) { - printf("%s,", ip_tostring(addr, options)); - print_mac(table[addr - mysetdata->first_ip]. - ethernet); - printf("\n"); - } - addr++; - } -} - -static void -macipmap_printips_sorted(struct set *set, void *data, - u_int32_t len, unsigned options, - char dont_align) -{ - struct ip_set_req_macipmap *d; - size_t offset = 0; - - if (dont_align) - return __macipmap_printips_sorted(set, data, len, options); - - while (offset < len) { - d = data + offset; - printf("%s,", ip_tostring(d->ip, options)); - print_mac(d->ethernet); - printf("\n"); - offset += IPSET_ALIGN(sizeof(struct ip_set_req_macipmap)); - } -} - -static void -macipmap_saveheader(struct set *set, unsigned options) -{ - struct ip_set_macipmap *mysetdata = 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 inline void -__macipmap_saveips(struct set *set, void *data, - u_int32_t len UNUSED, unsigned options) -{ - struct ip_set_macipmap *mysetdata = set->settype->header; - struct ip_set_macip *table = data; - u_int32_t addr = mysetdata->first_ip; - - while (addr <= mysetdata->last_ip) { - if (table[addr - mysetdata->first_ip].match) { - printf("-A %s %s,", - set->name, ip_tostring(addr, options)); - print_mac(table[addr - mysetdata->first_ip]. - ethernet); - printf("\n"); - } - addr++; - } -} - -static void -macipmap_saveips(struct set *set, void *data, - u_int32_t len, unsigned options, - char dont_align) -{ - struct ip_set_req_macipmap *d; - size_t offset = 0; - - if (dont_align) - return __macipmap_saveips(set, data, len, options); - - while (offset < len) { - d = data + offset; - printf("-A %s %s,", set->name, ip_tostring(d->ip, options)); - print_mac(d->ethernet); - printf("\n"); - offset += IPSET_ALIGN(sizeof(struct ip_set_req_macipmap)); - } -} - -static void -macipmap_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 = macipmap_create_init, - .create_parse = macipmap_create_parse, - .create_final = macipmap_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_macipmap), - .adt_parser = macipmap_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_macipmap), - .initheader = macipmap_initheader, - .printheader = macipmap_printheader, - .printips = macipmap_printips_sorted, - .printips_sorted = macipmap_printips_sorted, - .saveheader = macipmap_saveheader, - .saveips = macipmap_saveips, - - .usage = macipmap_usage, -}; - -CONSTRUCTOR(macipmap) -{ - settype_register(&settype_macipmap); - -} diff --git a/ipset_nethash.c b/ipset_nethash.c deleted file mode 100644 index c7891cf..0000000 --- a/ipset_nethash.c +++ /dev/null @@ -1,308 +0,0 @@ -/* 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 /* UINT_MAX */ -#include /* *printf */ -#include /* mem*, str* */ - -#include "ipset.h" - -#include - -#define BUFLEN 30; - -#define OPT_CREATE_HASHSIZE 0x01U -#define OPT_CREATE_PROBES 0x02U -#define OPT_CREATE_RESIZE 0x04U - -/* Initialize the create. */ -static void -nethash_create_init(void *data) -{ - struct ip_set_req_nethash_create *mydata = 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 -nethash_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) -{ - struct ip_set_req_nethash_create *mydata = 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 -nethash_create_final(void *data UNUSED, unsigned int flags UNUSED) -{ -} - -/* Create commandline options */ -static const struct option create_opts[] = { - {.name = "hashsize", .has_arg = required_argument, .val = '1'}, - {.name = "probes", .has_arg = required_argument, .val = '2'}, - {.name = "resize", .has_arg = required_argument, .val = '3'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -nethash_adt_parser(int cmd, const char *arg, void *data) -{ - struct ip_set_req_nethash *mydata = 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 0 - if (!mydata->ip) - exit_error(PARAMETER_PROBLEM, - "Zero valued IP address `%s' specified", ptr); -#endif - ipset_free(saved); - - return 1; -}; - -/* - * Print and save - */ - -static void -nethash_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_nethash_create *header = data; - struct ip_set_nethash *map = 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 -nethash_printheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_nethash *mysetdata = 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 UNUSED) -{ - 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), 0), buf); - return buf; -} - -static void -nethash_printips(struct set *set UNUSED, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - size_t offset = 0; - ip_set_ip_t *ip; - - while (offset < len) { - ip = data + offset; - printf("%s\n", unpack_ip_tostring(*ip, options)); - offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); - } -} - -static void -nethash_saveheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_nethash *mysetdata = 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 -nethash_saveips(struct set *set UNUSED, void *data, u_int32_t len, - unsigned options, char dont_align) -{ - size_t offset = 0; - ip_set_ip_t *ip; - - while (offset < len) { - ip = data + offset; - printf("-A %s %s\n", set->name, - unpack_ip_tostring(*ip, options)); - offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); - } -} - -static void -nethash_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 = nethash_create_init, - .create_parse = nethash_create_parse, - .create_final = nethash_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_nethash), - .adt_parser = nethash_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_nethash), - .initheader = nethash_initheader, - .printheader = nethash_printheader, - .printips = nethash_printips, - .printips_sorted = nethash_printips, - .saveheader = nethash_saveheader, - .saveips = nethash_saveips, - - .usage = nethash_usage, -}; - -CONSTRUCTOR(nethash) -{ - settype_register(&settype_nethash); - -} diff --git a/ipset_portmap.c b/ipset_portmap.c deleted file mode 100644 index a1065ae..0000000 --- a/ipset_portmap.c +++ /dev/null @@ -1,272 +0,0 @@ -/* 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 /* *printf */ -#include /* mem* */ - -#include "ipset.h" - -#include - -#define BUFLEN 30; - -#define OPT_CREATE_FROM 0x01U -#define OPT_CREATE_TO 0x02U - -#define OPT_ADDDEL_PORT 0x01U - -/* Initialize the create. */ -static void -portmap_create_init(void *data UNUSED) -{ - DP("create INIT"); - /* Nothing */ -} - -/* Function which parses command options; returns true if it ate an option */ -static int -portmap_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) -{ - struct ip_set_req_portmap_create *mydata = 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 -portmap_create_final(void *data, unsigned int flags) -{ - struct ip_set_req_portmap_create *mydata = 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[] = { - {.name = "from", .has_arg = required_argument, .val = '1'}, - {.name = "to", .has_arg = required_argument, .val = '2'}, - {NULL}, -}; - -/* Add, del, test parser */ -static ip_set_ip_t -portmap_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_portmap *mydata = data; - - parse_port(arg, &mydata->ip); - DP("%s", port_tostring(mydata->ip, 0)); - - return 1; -} - -/* - * Print and save - */ - -static void -portmap_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_portmap_create *header = data; - struct ip_set_portmap *map = set->settype->header; - - memset(map, 0, sizeof(struct ip_set_portmap)); - map->first_ip = header->from; - map->last_ip = header->to; -} - -static void -portmap_printheader(struct set *set, unsigned options) -{ - struct ip_set_portmap *mysetdata = set->settype->header; - - printf(" from: %s", port_tostring(mysetdata->first_ip, options)); - printf(" to: %s\n", port_tostring(mysetdata->last_ip, options)); -} - -static inline void -__portmap_printips_sorted(struct set *set, void *data, - u_int32_t len UNUSED, unsigned options) -{ - struct ip_set_portmap *mysetdata = set->settype->header; - ip_set_ip_t addr = mysetdata->first_ip; - - DP("%u -- %u", mysetdata->first_ip, mysetdata->last_ip); - while (addr <= mysetdata->last_ip) { - if (test_bit(addr - mysetdata->first_ip, data)) - printf("%s\n", port_tostring(addr, options)); - addr++; - } -} - -static void -portmap_printips_sorted(struct set *set, void *data, - u_int32_t len, unsigned options, - char dont_align) -{ - ip_set_ip_t *ip; - size_t offset = 0; - - if (dont_align) - return __portmap_printips_sorted(set, data, len, options); - - while (offset < len) { - ip = data + offset; - printf("%s\n", port_tostring(*ip, options)); - offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); - } -} - -static void -portmap_saveheader(struct set *set, unsigned options) -{ - struct ip_set_portmap *mysetdata = set->settype->header; - - printf("-N %s %s --from %s", - set->name, - set->settype->typename, - port_tostring(mysetdata->first_ip, options)); - printf(" --to %s\n", - port_tostring(mysetdata->last_ip, options)); -} - -static inline void -__portmap_saveips(struct set *set, void *data, - u_int32_t len UNUSED, unsigned options) -{ - struct ip_set_portmap *mysetdata = set->settype->header; - ip_set_ip_t addr = mysetdata->first_ip; - - while (addr <= mysetdata->last_ip) { - DP("addr: %lu, last_ip %lu", (long unsigned)addr, (long unsigned)mysetdata->last_ip); - if (test_bit(addr - mysetdata->first_ip, data)) - printf("-A %s %s\n", - set->name, - port_tostring(addr, options)); - addr++; - } -} - -static void -portmap_saveips(struct set *set, void *data, - u_int32_t len, unsigned options, - char dont_align) -{ - ip_set_ip_t *ip; - size_t offset = 0; - - if (dont_align) - return __portmap_saveips(set, data, len, options); - - while (offset < len) { - ip = data + offset; - printf("-A %s %s\n", set->name, port_tostring(*ip, options)); - offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); - } -} - -static void -portmap_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 = portmap_create_init, - .create_parse = portmap_create_parse, - .create_final = portmap_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_portmap), - .adt_parser = portmap_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_portmap), - .initheader = portmap_initheader, - .printheader = portmap_printheader, - .printips = portmap_printips_sorted, - .printips_sorted = portmap_printips_sorted, - .saveheader = portmap_saveheader, - .saveips = portmap_saveips, - - .usage = portmap_usage, -}; - -CONSTRUCTOR(portmap) -{ - settype_register(&settype_portmap); - -} diff --git a/ipset_setlist.c b/ipset_setlist.c deleted file mode 100644 index de16c44..0000000 --- a/ipset_setlist.c +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License 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 -#include -#include -#include -#include -#include - -#include -#include "ipset.h" - -/* Initialize the create. */ -static void -setlist_create_init(void *data) -{ - struct ip_set_req_setlist_create *mydata = data; - - mydata->size = 8; -} - -/* Function which parses command options; returns true if it ate an option */ -static int -setlist_create_parse(int c, char *argv[] UNUSED, void *data, - unsigned *flags UNUSED) -{ - struct ip_set_req_setlist_create *mydata = data; - unsigned int size; - - switch (c) { - case '1': - if (string_to_number(optarg, 1, 255, &size)) - exit_error(PARAMETER_PROBLEM, - "Invalid size '%s specified: must be " - "between 1-255", optarg); - mydata->size = size; - break; - default: - return 0; - } - return 1; -} - -/* Final check; exit if not ok. */ -static void -setlist_create_final(void *data UNUSED, unsigned int flags UNUSED) -{ -} - -/* Create commandline options */ -static const struct option create_opts[] = { - {.name = "size", .has_arg = required_argument, .val = '1'}, - {NULL}, -}; - -static void -check_setname(const char *name) -{ - if (strlen(name) > IP_SET_MAXNAMELEN - 1) - exit_error(PARAMETER_PROBLEM, - "Setname %s is longer than %d characters.", - name, IP_SET_MAXNAMELEN - 1); -} - -/* Add, del, test parser */ -static ip_set_ip_t -setlist_adt_parser(int cmd UNUSED, const char *arg, void *data) -{ - struct ip_set_req_setlist *mydata = data; - char *saved = ipset_strdup(arg); - char *ptr, *tmp = saved; - - DP("setlist: %p %p", arg, data); - - ptr = strsep(&tmp, ","); - check_setname(ptr); - strcpy(mydata->name, ptr); - - if (!tmp) { - mydata->before = 0; - mydata->ref[0] = '\0'; - return 1; - } - - ptr = strsep(&tmp, ","); - - if (tmp == NULL || !(strcmp(ptr, "before") == 0 || strcmp(ptr, "after") == 0)) - exit_error(PARAMETER_PROBLEM, - "Syntax error, you must specify elements as setname,[before|after],setname"); - - check_setname(tmp); - strcpy(mydata->ref, tmp); - mydata->before = !strcmp(ptr, "before"); - - free(saved); - - return 1; -} - -/* - * Print and save - */ - -static void -setlist_initheader(struct set *set, const void *data) -{ - const struct ip_set_req_setlist_create *header = data; - struct ip_set_setlist *map = set->settype->header; - - memset(map, 0, sizeof(struct ip_set_setlist)); - map->size = header->size; -} - -static void -setlist_printheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_setlist *mysetdata = set->settype->header; - - printf(" size: %u\n", mysetdata->size); -} - -static void -setlist_printips_sorted(struct set *set, void *data, - u_int32_t len UNUSED, unsigned options UNUSED, - char dont_align) -{ - struct ip_set_setlist *mysetdata = set->settype->header; - int i, asize; - ip_set_id_t *id; - struct set *elem; - - asize = IPSET_VALIGN(sizeof(ip_set_id_t), dont_align); - for (i = 0; i < mysetdata->size; i++ ) { - DP("Try %u", i); - id = (ip_set_id_t *)(data + i * asize); - DP("Try %u, check", i); - if (*id == IP_SET_INVALID_ID) - return; - elem = set_find_byid(*id); - printf("%s\n", elem->name); - } -} - -static void -setlist_saveheader(struct set *set, unsigned options UNUSED) -{ - struct ip_set_setlist *mysetdata = set->settype->header; - - printf("-N %s %s --size %u\n", - set->name, set->settype->typename, - mysetdata->size); -} - -static void -setlist_saveips(struct set *set, void *data, - u_int32_t len UNUSED, unsigned options UNUSED, char dont_align) -{ - struct ip_set_setlist *mysetdata = set->settype->header; - int i, asize; - ip_set_id_t *id; - struct set *elem; - - asize = IPSET_VALIGN(sizeof(ip_set_id_t), dont_align); - for (i = 0; i < mysetdata->size; i++ ) { - id = (ip_set_id_t *)(data + i * asize); - if (*id == IP_SET_INVALID_ID) - return; - elem = set_find_byid(*id); - printf("-A %s %s\n", set->name, elem->name); - } -} - -static void -setlist_usage(void) -{ - printf - ("-N set setlist --size size\n" - "-A set setname[,before|after,setname]\n" - "-D set setname\n" - "-T set setname\n"); -} - -static struct settype settype_setlist = { - .typename = SETTYPE_NAME, - .protocol_version = IP_SET_PROTOCOL_VERSION, - - /* Create */ - .create_size = sizeof(struct ip_set_req_setlist_create), - .create_init = setlist_create_init, - .create_parse = setlist_create_parse, - .create_final = setlist_create_final, - .create_opts = create_opts, - - /* Add/del/test */ - .adt_size = sizeof(struct ip_set_req_setlist), - .adt_parser = setlist_adt_parser, - - /* Printing */ - .header_size = sizeof(struct ip_set_setlist), - .initheader = setlist_initheader, - .printheader = setlist_printheader, - .printips = setlist_printips_sorted, - .printips_sorted = setlist_printips_sorted, - .saveheader = setlist_saveheader, - .saveips = setlist_saveips, - - .usage = setlist_usage, -}; - -CONSTRUCTOR(setlist) -{ - settype_register(&settype_setlist); - -} diff --git a/libipt_set.h b/libipt_set.h deleted file mode 100644 index 771a0fe..0000000 --- a/libipt_set.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _LIBIPT_SET_H -#define _LIBIPT_SET_H - -#include -#include -#include - -static int get_set_getsockopt(void *data, size_t * size) -{ - int sockfd = -1; - sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); - if (sockfd < 0) - exit_error(OTHER_PROBLEM, - "Can't open socket to ipset.\n"); - /* Send! */ - return getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); -} - -static void -parse_bindings(const char *optarg, struct ipt_set_info *info) -{ - char *saved = strdup(optarg); - char *ptr, *tmp = saved; - int i = 0; - - while (i < IP_SET_MAX_BINDINGS && tmp != NULL) { - ptr = strsep(&tmp, ","); - if (strncmp(ptr, "src", 3) == 0) - info->flags[i++] |= IPSET_SRC; - else if (strncmp(ptr, "dst", 3) == 0) - info->flags[i++] |= IPSET_DST; - else - exit_error(PARAMETER_PROBLEM, - "You must spefify (the comma separated list of) 'src' or 'dst'."); - } - - if (tmp) - exit_error(PARAMETER_PROBLEM, - "Can't follow bindings deeper than %d.", - IP_SET_MAX_BINDINGS); - - free(saved); -} - -#endif /*_LIBIPT_SET_H*/ diff --git a/src/ipset.8 b/src/ipset.8 new file mode 100644 index 0000000..fa73298 --- /dev/null +++ b/src/ipset.8 @@ -0,0 +1,537 @@ +.TH IPSET 8 "Feb 05, 2004" "" "" +.\" +.\" Man page written by Jozsef Kadlecsik +.\" +.\" 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 \(em administration tool for IP sets +.SH SYNOPSIS +.PP +\fBipset \-N\fP \fIset\fP \fItype-specification\fP [\fIoptions\fP...] +.PP +\fBipset\fP {\fB\-F\fP|\fB\-H\fP|\fB\-L\fP|\fB\-S\fP|\fB\-X\fP} [\fIset\fP] +[\fIoptions\fP...] +.PP +\fBipset\fP {\fB\-E\fP|\fB\-W\fP} \fIfrom-set\fP \fIto-set\fP +.PP +\fBipset\fP {\fB\-A\fP|\fB\-D\fP|\fB\-T\fP} \fIset\fP \fIentry\fP +.PP +\fBipset \-R\fP +.PP +\fBipset\fP {\fB-V\fP|\fB\-v\fP} +.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 +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 +\fB\-N\fP, \fB\-\-create\fP \fIsetname\fP \fItype\fP \fItype-specific-options\fP +Create a set identified with setname and specified type. +Type-specific options must be supplied. +.TP +\fB\-X\fP, \fB\-\-destroy\fP [\fIsetname\fP] +Destroy the specified set or all the sets if none is given. + +If the set has got references, nothing is done. +.TP +\fB\-F\fP, \fB\-\-flush\fP [\fIsetname\fP] +Delete all entries from the specified set or flush +all sets if none is given. +.TP +\fB\-E\fP, \fB\-\-rename\fP \fIfrom-setname\fP \fIto-setname\fP +Rename a set. Set identified by to-setname must not exist. +.TP +\fB\-W\fP, \fB\-\-swap\fP \fIfrom-setname\fP \fIto-setname\fP +Swap the content of two sets, or in another words, +exchange the name of two sets. The referred sets must exist and +identical type of sets can be swapped only. +.TP +\fB\-L\fP, \fB\-\-list\fP [\fIsetname\fP] +List the entries for the specified set, or for +all sets if none is given. The +\fB\-r\fP/\fB\-\-resolve\fP +option can be used to force name lookups (which may be slow). When the +\fB\-s\fP/\fB\-\-sorted\fP +option is given, the entries are listed sorted (if the given set +type supports the operation). +.TP +\fB\-S\fP, \fB\-\-save\fP [\fIsetname\fP] +Save the given set, or all sets if none is given +to stdout in a format that \fB\-\-restore\fP can read. +.TP +\fB\-R\fP, \fB\-\-restore\fP +Restore a saved session generated by \fB\-\-save\fP. The saved session +can be fed from stdin. + +When generating a session file please note that the supported commands +(create set and add element) 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. Also, it is a restore operation, so the sets being restored must +not exist. +.TP +\fB\-A\fP, \fB\-\-add\fP \fIsetname\fP \fIentry\fP +Add an entry to a set. +.TP +\fB\-D\fP, \fB\-\-del\fP \fIsetname\fP \fIentry\fP +Delete an entry from a set. +.TP +\fB-T\fP, \fB\-\-test\fP \fIsetname\fP \fIentry\fP +Test wether an entry is in a set or not. Exit status number is zero +if the tested entry is in the set and nonzero if it is missing from +the set. +.TP +\fB\-H\fP, \fB\-\-help\fP [\fIsettype\fP] +Print help and settype specific help if settype specified. +.TP +\fB\-V\fP, \fB\-v\fP, \fB\-\-version\fP +Print program version and protocol version. +.P +.SS "OTHER OPTIONS" +The following additional options can be specified: +.TP +\fB\-r\fP, \fB\-\-resolve\fP +When listing sets, enforce name lookup. The +program will try to display the IP entries resolved to +host names or services (whenever applicable), which can trigger +.B +slow +DNS +lookups. +.TP +\fB\-s\fP, \fB\-\-sorted\fP +Sorted output. When listing sets, entries are listed sorted. +.TP +\fB\-n\fP, \fB\-\-numeric\fP +Numeric output. When listing sets, IP addresses and +port numbers will be printed in numeric format. This is the default. +.TP +\fB\-q\fP, \fB\-\-quiet\fP +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. If the optional +\fB\-\-netmask\fP +parameter is specified with a CIDR netmask value between 1-31 then +network addresses are stored in the given set: i.e an +IP address will be in the set if the network address, which is 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 +\fB\-\-from\fP \fIfrom-addr\fP +.TP +\fB\-\-to\fP \fIto-addr\fP +Create an ipmap set from the specified address range. +.TP +\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP +Create an ipmap set from the specified network. +.TP +\fB\-\-netmask\fP \fIprefixlen\fP +When the optional +\fB\-\-netmask\fP +parameter specified, network addresses will be +stored in the set instead of IP addresses, and the \fIfrom-addr\fP parameter +must be a network address. The \fIprefixlen\fP value must be between 1-31. +.PP +Example: +.IP +ipset \-N test ipmap \-\-network 192.168.0.0/16 +.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 +"\fIaddress\fP\fB,\fP\fImac\fP". +When deleting or testing macipmap entries, the +"\fB,\fP\fImac\fP" +part is not mandatory. +.P +Options to use when creating an macipmap set: +.TP +\fB\-\-from\fP \fIfrom-addr\fP +.TP +\fB\-\-to\fP \fIto-addr\fP +Create a macipmap set from the specified address range. +.TP +\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP +Create a macipmap set from the specified network. +.TP +\fB\-\-matchunset\fP +When the optional +\fB\-\-matchunset\fP +parameter specified, IP addresses which could be stored +in the set but not set yet, will always match. +.P +Please note, the +"set" +and +"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 +\fB\-\-from\fP \fIfrom-port\fP +.TP +\fB\-\-to\fP \fIto-port\fP +Create a portmap set from the specified port 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. If the optional +\fB\-\-netmask\fP +parameter is specified with a CIDR prefix length value between 1-31 then +network addresses are stored in the given set: i.e an +IP address will be in the set if the network address, which is resulted +by masking the address with the specified netmask, can be found in the set. +.P +Options to use when creating an iphash set: +.TP +\fB\-\-hashsize\fP \fIhashsize\fP +The initial hash size (default 1024) +.TP +\fB\-\-probes\fP \fIprobes\fP +How many times try to resolve clashing at adding an IP to the hash +by double-hashing (default 8). +.TP +\fB\-\-resize\fP \fIpercent\fP +Increase the hash size by this many percent (default 50) when adding +an IP to the hash could not be performed after +\fIprobes\fP +number of double-hashing. +.TP +\fB\-\-netmask\fP \fIprefixlen\fP +When the optional +\fB\-\-netmask\fP +parameter specified, network addresses will be +stored in the set instead of IP addresses. The \fIprefixlen\fP value must +be between 1-31. +.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 grows approximately linearly with +the value of the +\fIprobes\fP +parameter. In general higher +\fIprobes\fP +value results better utilized hash while smaller value +produces larger, sparser hash. +.PP +Example: +.IP +ipset \-N test iphash \-\-probes 2 +.SS nethash +The nethash set type uses a hash to store different size of +network addresses. The +.I +entry +used in the ipset commands must be in the form +"\fIaddress\fP\fB/\fP\fIprefixlen\fP" +where prefixlen 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 +\fB\-\-hashsize\fP \fIhashsize\fP +The initial hash size (default 1024) +.TP +\fB\-\-probes\fP \fIprobes\fP +How many times try to resolve clashing at adding an IP to the hash +by double-hashing (default 4). +.TP +\fB\-\-resize\fP \fIpercent\fP +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 belongs to any of the +netblocks added to the set. The matching always start from the smallest +size of netblock (most specific netmask) to the largest ones (least +specific netmasks). When adding/deleting IP addresses +to a nethash set by the +"SET" +netfilter kernel module, it will be added/deleted by the smallest +netblock size which can be found in the set, or by /31 if the set is empty. +.P +The lookup time in a nethash type of set grows approximately linearly +with the times of the +\fIprobes\fP +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 +"\fIaddress\fP\fB,\fP\fIport\fP". +.P +The ipporthash types of sets evaluates two src/dst parameters of the +"set" +match and +"SET" +target. +.P +Options to use when creating an ipporthash set: +.TP +\fB\-\-from\fP \fIfrom-addr\fP +.TP +\fB\-\-to\fP \fIto-addr\fP +Create an ipporthash set from the specified address range. +.TP +\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP +Create an ipporthash set from the specified network. +.TP +\fB\-\-hashsize\fP \fIhashsize\fP +The initial hash size (default 1024) +.TP +\fB\-\-probes\fP \fIprobes\fP +How many times try to resolve clashing at adding an IP to the hash +by double-hashing (default 8). +.TP +\fB\-\-resize\fP \fIpercent\fP +Increase the hash size by this many percent (default 50) when adding +an IP to the hash could not be performed after +\fIprobes\fP +number of double-hashing. +.P +The same resizing, speed and memory efficiency comments applies here +as at the iphash type. +.SS ipportiphash +The ipportiphash set type uses a hash to store IP address,port and IP +address triples. The first IP address must come form a maximum /16 +sized network or range while the port number and the second IP address +parameters are arbitrary. When adding, deleting and testing values in an +ipportiphash type of set, the entries must be specified as +"\fIaddress\fP\fB,\fP\fIport\fP\fB,\fP\fIaddress\fP". +.P +The ipportiphash types of sets evaluates three src/dst parameters of the +"set" +match and +"SET" +target. +.P +Options to use when creating an ipportiphash set: +.TP +\fB\-\-from\fP \fIfrom-addr\fP +.TP +\fB\-\-to\fP \fIto-addr\fP +Create an ipportiphash set from the specified address range. +.TP +\fB\-\-network\fP \fIaddr\fP\fB/\fP\fImask\fP +Create an ipportiphash set from the specified network. +.TP +\fB\-\-hashsize\fP \fIhashsize\fP +The initial hash size (default 1024) +.TP +\fB\-\-probes\fP \fIprobes\fP +How many times try to resolve clashing at adding an IP to the hash +by double-hashing (default 8). +.TP +\fB\-\-resize\fP \fIpercent\fP +Increase the hash size by this many percent (default 50) when adding +an IP to the hash could not be performed after +\fIprobes\fP +number of double-hashing. +.P +The same resizing, speed and memory efficiency comments applies here +as at the iphash type. +.SS ipportnethash +The ipportnethash set type uses a hash to store IP address, port, and +network address triples. The IP address must come form a maximum /16 +sized network or range while the port number and the network address +parameters are arbitrary, but the size of the network address must be +between /1-/31. When adding, deleting +and testing values in an ipportnethash type of set, the entries must be +specified as +"\fIaddress\fP\fB,\fP\fIport\fP\fB,\fP\fIaddress\fP\fB/\fP\fIprefixlen\fP". +.P +The ipportnethash types of sets evaluates three src/dst parameters of the +"set" +match and +"SET" +target. +.P +Options to use when creating an ipportnethash set: +.TP +\fB\-\-from\fP \fIfrom-address\fP +.TP +\fB\-\-to\fP \fIto-address\fP +Create an ipporthash set from the specified range. +.TP +\fB\-\-network\fP \fIaddress\fP\fB/\fP\fImask\fP +Create an ipporthash set from the specified network. +.TP +\fB\-\-hashsize\fP \fIhashsize\fP +The initial hash size (default 1024) +.TP +\fB\-\-probes\fP \fIprobes\fP +How many times try to resolve clashing at adding an IP to the hash +by double-hashing (default 8). +.TP +\fB\-\-resize\fP \fIpercent\fP +Increase the hash size by this many percent (default 50) when adding +an IP to the hash could not be performed after +\fIprobes\fP +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 +\fB\-\-timeout\fP \fIvalue\fP +The timeout value for the entries in seconds (default 0) +.P +If a set was created with a nonzero valued +\fB\-\-timeout\fP +parameter then one may add IP addresses to the set with a specific +timeout value using the syntax +"\fIaddress\fP\fB,\fP\fItimeout-value\fP". +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 +"\fIaddress1\fP\fB-\fP\fIaddress2\fP". +.P +Options to use when creating an iptreemap set: +.TP +\fB\-\-gc\fP \fIvalue\fP +How often the garbage collection should be called, in seconds (default 300) +.SS setlist +The setlist type uses a simple list in which you can store sets. By the +ipset +command you can add, delete and test sets in a setlist type of set. +You can specify the sets as +"\fIsetname\fP[\fB,\fP{\fBafter\fP|\fBbefore\fP},\fIsetname\fP]". +By default new sets are added after (appended to) the existing +elements. Setlist type of sets cannot be added to a setlist type of set. +.P +Options to use when creating a setlist type of set: +.TP +\fB\-\-size\fP \fIsize\fP +Create a setlist type of set with the given size (default 8). +.PP +By the +"set" +match or +"SET" +target of +\fBiptables\fP(8) +you can test, add or delete entries in the sets. The match +will try to find a matching IP address/port in the sets and +the target will try to add the IP address/port to the first set +to which it can be added. The number of src,dst options of +the match and target are important: sets which eats more src,dst +parameters than specified are skipped, while sets with equal +or less parameters are checked, elements added. For example +if +.I +a +and +.I +b +are setlist type of sets then in the command +.IP +iptables \-m set \-\-match\-set a src,dst \-j SET \-\-add-set b src,dst +.PP +the match and target will skip any set in +.I a +and +.I b +which stores +data triples, but will check all sets with single or double +data storage in +.I a +set and add src to the first single or src,dst to the first double +data storage set in +\fIb\fP. +.P +You can imagine a setlist type of set as an ordered union of +the set elements. +.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. +.P +Old separator tokens (':' and '%") are still accepted. +.P +Binding support is removed. +.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 shoulders of giants." diff --git a/src/ipset.c b/src/ipset.c new file mode 100644 index 0000000..3b8e248 --- /dev/null +++ b/src/ipset.c @@ -0,0 +1,2054 @@ +/* Copyright 2000-2002 Joakim Axelsson (gozem@linux.nu) + * Patrick Schaaf (bof@bof.de) + * Copyright 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. + */ + +#include /* *printf, perror, sscanf, fdopen */ +#include /* mem*, str* */ +#include /* errno, perror */ +#include /* time, ctime */ +#include /* gethostby*, getnetby*, getservby* */ +#include /* exit, malloc, free, strtol, getenv, mkstemp */ +#include /* read, close, fork, exec*, unlink */ +#include /* open, wait, socket, *sockopt, umask */ +#include /* open, umask */ +#include /* wait */ +#include /* socket, *sockopt, gethostby*, inet_* */ +#include /* inet_* */ +#include /* open */ +#include /* htonl, inet_* */ +#include /* va_* */ +#include /* dlopen */ + +#include "ipset.h" + +#ifndef PROC_SYS_MODPROBE +#define PROC_SYS_MODPROBE "/proc/sys/kernel/modprobe" +#endif + +char program_name[] = "ipset"; +char program_version[] = IPSET_VERSION; +static int protocol_version = 0; + +#define STREQ(a,b) (strncmp(a,b,IP_SET_MAXNAMELEN) == 0) +#define DONT_ALIGN (protocol_version == IP_SET_PROTOCOL_UNALIGNED) +#define ALIGNED(len) IPSET_VALIGN(len, DONT_ALIGN) + +/* The list of loaded set types */ +static struct settype *all_settypes = NULL; + +/* Array of sets */ +struct set **set_list = NULL; +ip_set_id_t max_sets = 0; + +/* Suppress output to stdout and stderr? */ +static int option_quiet = 0; + +/* Data for restore mode */ +static int restore = 0; +void *restore_data = NULL; +struct ip_set_restore *restore_set = NULL; +size_t restore_offset = 0; +socklen_t restore_size; +unsigned restore_line = 0; +unsigned warn_once = 0; + +#define TEMPFILE_PATTERN "/ipsetXXXXXX" + +#ifdef IPSET_DEBUG +int option_debug = 0; +#endif + +#define OPTION_OFFSET 256 +static unsigned int global_option_offset = 0; + +/* Most of these command parsing functions are borrowed from iptables.c */ + +static const char cmdflags[] = { ' ', /* CMD_NONE */ + 'N', 'X', 'F', 'E', 'W', 'L', 'S', 'R', + 'A', 'D', 'T', 'H', 'V', +}; + +/* Options */ +#define OPT_NONE 0x0000U +#define OPT_NUMERIC 0x0001U /* -n */ +#define OPT_SORTED 0x0002U /* -s */ +#define OPT_QUIET 0x0004U /* -q */ +#define OPT_DEBUG 0x0008U /* -z */ +#define OPT_RESOLVE 0x0020U /* -r */ +#define NUMBER_OF_OPT 5 +static const char optflags[] = + { 'n', 's', 'q', 'z', 'r' }; + +static struct option opts_long[] = { + /* set operations */ + {"create", 1, 0, 'N'}, + {"destroy", 2, 0, 'X'}, + {"flush", 2, 0, 'F'}, + {"rename", 1, 0, 'E'}, + {"swap", 1, 0, 'W'}, + {"list", 2, 0, 'L'}, + + {"save", 2, 0, 'S'}, + {"restore", 0, 0, 'R'}, + + /* ip in set operations */ + {"add", 1, 0, 'A'}, + {"del", 1, 0, 'D'}, + {"test", 1, 0, 'T'}, + + /* free options */ + {"numeric", 0, 0, 'n'}, + {"sorted", 0, 0, 's'}, + {"quiet", 0, 0, 'q'}, + {"resolve", 0, 0, 'r'}, + +#ifdef IPSET_DEBUG + /* debug (if compiled with it) */ + {"debug", 0, 0, 'z'}, +#endif + + /* version and help */ + {"version", 0, 0, 'V'}, + {"help", 2, 0, 'H'}, + + /* end */ + {NULL}, +}; + +static char opts_short[] = + "-N:X::F::E:W:L::S::RA:D:T:nrsqzvVh::H::"; + +/* Table of legal combinations of commands and options. If any of the + * given commands make an option legal, that option is legal. + * Key: + * + compulsory + * x illegal + * optional + */ + +static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = { + /* -n -s -q -z -r */ + /*CREATE*/ {'x', 'x', ' ', ' ', 'x'}, + /*DESTROY*/ {'x', 'x', ' ', ' ', 'x'}, + /*FLUSH*/ {'x', 'x', ' ', ' ', 'x'}, + /*RENAME*/ {'x', 'x', ' ', ' ', 'x'}, + /*SWAP*/ {'x', 'x', ' ', ' ', 'x'}, + /*LIST*/ {' ', ' ', 'x', ' ', ' '}, + /*SAVE*/ {'x', 'x', ' ', ' ', 'x'}, + /*RESTORE*/ {'x', 'x', ' ', ' ', 'x'}, + /*ADD*/ {'x', 'x', ' ', ' ', 'x'}, + /*DEL*/ {'x', 'x', ' ', ' ', 'x'}, + /*TEST*/ {'x', 'x', ' ', ' ', 'x'}, + /*HELP*/ {'x', 'x', 'x', ' ', 'x'}, + /*VERSION*/ {'x', 'x', 'x', ' ', 'x'}, +}; + +/* Main parser function */ +int parse_commandline(int argc, char *argv[]); + +static void exit_tryhelp(int status) +{ + fprintf(stderr, + "Try `%s -H' or '%s --help' for more information.\n", + program_name, program_name); + exit(status); +} + +void exit_error(int status, const char *msg, ...) +{ + if (!option_quiet) { + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s v%s: ", program_name, program_version); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + if (restore_line) + fprintf(stderr, "Restore failed at line %u:\n", restore_line); + if (status == PARAMETER_PROBLEM) + exit_tryhelp(status); + if (status == VERSION_PROBLEM) + fprintf(stderr, + "Perhaps %s or your kernel needs to be upgraded.\n", + program_name); + } + + exit(status); +} + +static void ipset_printf(const char *msg, ...) +{ + if (!option_quiet) { + va_list args; + + va_start(args, msg); + vfprintf(stdout, msg, args); + va_end(args); + fprintf(stdout, "\n"); + } +} + +static void generic_opt_check(int command, unsigned int options) +{ + int i, j, legal = 0; + + /* Check that commands are valid with options. Complicated by the + * fact that if an option is legal with *any* command given, it is + * legal overall (ie. -z and -l). + */ + for (i = 0; i < NUMBER_OF_OPT; i++) { + legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ + + for (j = 1; j <= NUMBER_OF_CMD; j++) { + if (command != j) + continue; + + if (!(options & (1 << i))) { + if (commands_v_options[j-1][i] == '+') + exit_error(PARAMETER_PROBLEM, + "You need to supply the `-%c' " + "option for this command\n", + optflags[i]); + } else { + if (commands_v_options[j-1][i] != 'x') + legal = 1; + else if (legal == 0) + legal = -1; + } + } + if (legal == -1) + exit_error(PARAMETER_PROBLEM, + "Illegal option `-%c' with this command\n", + optflags[i]); + } +} + +static char opt2char(unsigned int option) +{ + const char *ptr; + for (ptr = optflags; option > 1; option >>= 1, ptr++); + + return *ptr; +} + +static char cmd2char(int cmd) +{ + if (cmd <= CMD_NONE || cmd > NUMBER_OF_CMD) + return ' '; + + return cmdflags[cmd]; +} + +/* From iptables.c ... */ +static char *get_modprobe(void) +{ + int procfile; + char *ret; + +#define PROCFILE_BUFSIZ 1024 + procfile = open(PROC_SYS_MODPROBE, O_RDONLY); + if (procfile < 0) + return NULL; + + ret = (char *) malloc(PROCFILE_BUFSIZ); + if (ret) { + memset(ret, 0, PROCFILE_BUFSIZ); + switch (read(procfile, ret, PROCFILE_BUFSIZ)) { + case -1: goto fail; + case PROCFILE_BUFSIZ: goto fail; /* Partial read. Wierd */ + default: ; /* nothing */ + } + if (ret[strlen(ret)-1]=='\n') + ret[strlen(ret)-1]=0; + close(procfile); + return ret; + } + fail: + free(ret); + close(procfile); + return NULL; +} + +static int ipset_insmod(const char *modname, const char *modprobe) +{ + char *buf = NULL; + char *argv[3]; + struct stat junk; + int status; + + if (!stat(modprobe, &junk)) { + /* Try to read out of the kernel */ + buf = get_modprobe(); + if (!buf) + return -1; + modprobe = buf; + } + + switch (fork()) { + case 0: + argv[0] = (char *) modprobe; + argv[1] = (char *) modname; + argv[2] = NULL; + execv(argv[0], argv); + + /* Should not reach */ + exit(1); + case -1: + return -1; + + default: /* parent */ + wait(&status); + } + + free(buf); + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + return 0; + return -1; +} + +static int kernel_getsocket(void) +{ + int sockfd = -1; + + sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + if (sockfd < 0) + exit_error(OTHER_PROBLEM, + "You need to be root to perform this command."); + + return sockfd; +} + +static void kernel_error(unsigned cmd, int err) +{ + unsigned int i; + struct translate_error { + int err; + unsigned cmd; + const char *message; + } table[] = + { /* Generic error codes */ + { EPERM, 0, "Missing capability" }, + { EBADF, 0, "Invalid socket option" }, + { EINVAL, 0, "Size mismatch for expected socket data" }, + { ENOMEM, 0, "Not enough memory" }, + { EFAULT, 0, "Failed to copy data" }, + { EPROTO, 0, "ipset kernel/userspace version mismatch" }, + { EBADMSG, 0, "Unknown command" }, + /* Per command error codes */ + /* Reserved ones for add/del/test to handle internally: + * EEXIST + */ + { ENOENT, CMD_CREATE, "Unknown set type" }, + { ENOENT, 0, "Unknown set" }, + { EAGAIN, 0, "Sets are busy, try again later" }, + { ERANGE, CMD_CREATE, "No free slot remained to add a new set" }, + { ERANGE, 0, "IP/port/element is outside of the set or set is full" }, + { ENOEXEC, CMD_CREATE, "Invalid parameters to create a set" }, + { ENOEXEC, CMD_SWAP, "Sets with different types cannot be swapped" }, + { EEXIST, CMD_CREATE, "Set already exists" }, + { EEXIST, CMD_RENAME, "Set with new name already exists" }, + { EEXIST, 0, "Set specified as element does not exist" }, + { EBUSY, 0, "Set is in use, operation not permitted" }, + }; + for (i = 0; i < sizeof(table)/sizeof(struct translate_error); i++) { + if ((table[i].cmd == cmd || table[i].cmd == 0) + && table[i].err == err) + exit_error(err == EPROTO ? VERSION_PROBLEM + : OTHER_PROBLEM, + table[i].message); + } + exit_error(OTHER_PROBLEM, "Error from kernel: %s", strerror(err)); +} + +static inline int wrapped_getsockopt(void *data, socklen_t *size) +{ + int res; + int sockfd = kernel_getsocket(); + + /* Send! */ + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); + if (res != 0 + && errno == ENOPROTOOPT + && ipset_insmod("ip_set", "/sbin/modprobe") == 0) + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); + DP("res=%d errno=%d", res, errno); + + return res; +} + +static inline int wrapped_setsockopt(void *data, socklen_t size) +{ + int res; + int sockfd = kernel_getsocket(); + + /* Send! */ + res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); + if (res != 0 + && errno == ENOPROTOOPT + && ipset_insmod("ip_set", "/sbin/modprobe") == 0) + res = setsockopt(sockfd, SOL_IP, SO_IP_SET, data, size); + DP("res=%d errno=%d", res, errno); + + return res; +} + +static void kernel_getfrom(unsigned cmd, void *data, socklen_t * size) +{ + int res = wrapped_getsockopt(data, size); + + if (res != 0) + kernel_error(cmd, errno); +} + +static int kernel_sendto_handleerrno(unsigned cmd, + void *data, socklen_t size) +{ + int res = wrapped_setsockopt(data, size); + + if (res != 0) { + if (errno == EEXIST) + return -1; + else + kernel_error(cmd, errno); + } + + return 0; /* all ok */ +} + +static void kernel_sendto(unsigned cmd, void *data, size_t size) +{ + int res = wrapped_setsockopt(data, size); + + if (res != 0) + kernel_error(cmd, errno); +} + +static int kernel_getfrom_handleerrno(unsigned cmd, void *data, socklen_t *size) +{ + int res = wrapped_getsockopt(data, size); + + if (res != 0) { + if (errno == EAGAIN) + return -1; + else + kernel_error(cmd, errno); + } + + return 0; /* all ok */ +} + +static void check_protocolversion(void) +{ + struct ip_set_req_version req_version; + socklen_t size = sizeof(struct ip_set_req_version); + int res; + + if (protocol_version) + return; + + req_version.op = IP_SET_OP_VERSION; + res = wrapped_getsockopt(&req_version, &size); + + if (res != 0) + exit_error(OTHER_PROBLEM, + "Couldn't verify kernel module version!"); + + if (!(req_version.version == IP_SET_PROTOCOL_VERSION + || req_version.version == IP_SET_PROTOCOL_UNALIGNED)) + exit_error(OTHER_PROBLEM, + "Kernel ip_set module is of protocol version %u." + "I'm of protocol version %u.\n" + "Please upgrade your kernel and/or ipset(8) utillity.", + req_version.version, IP_SET_PROTOCOL_VERSION); + protocol_version = req_version.version; +} + +static void set_command(int *cmd, int newcmd) +{ + if (*cmd != CMD_NONE) + exit_error(PARAMETER_PROBLEM, "Can't use -%c with -%c\n", + cmd2char(*cmd), cmd2char(newcmd)); + *cmd = newcmd; +} + +static void add_option(unsigned int *options, unsigned int option) +{ + if (*options & option) + exit_error(PARAMETER_PROBLEM, + "multiple -%c flags not allowed", + opt2char(option)); + *options |= option; +} + +void *ipset_malloc(size_t size) +{ + void *p; + + if (size == 0) + return NULL; + + if ((p = malloc(size)) == NULL) { + perror("ipset: not enough memory"); + exit(1); + } + return p; +} + +char *ipset_strdup(const char *s) +{ + char *p; + + if ((p = strdup(s)) == NULL) { + perror("ipset: not enough memory"); + exit(1); + } + return p; +} + +void ipset_free(void *data) +{ + if (data == NULL) + return; + + free(data); +} + +static struct option *merge_options(struct option *oldopts, + const struct option *newopts, + int *option_offset) +{ + unsigned int num_old, num_new, i; + struct option *merge; + + for (num_old = 0; oldopts[num_old].name; num_old++); + for (num_new = 0; newopts[num_new].name; num_new++); + + global_option_offset += OPTION_OFFSET; + *option_offset = global_option_offset; + + merge = ipset_malloc(sizeof(struct option) * (num_new + num_old + 1)); + memcpy(merge, oldopts, num_old * sizeof(struct option)); + for (i = 0; i < num_new; i++) { + merge[num_old + i] = newopts[i]; + merge[num_old + i].val += *option_offset; + } + memset(merge + num_old + num_new, 0, sizeof(struct option)); + + return merge; +} + +static char *ip_tohost(const struct in_addr *addr) +{ + struct hostent *host; + + if ((host = gethostbyaddr((char *) addr, + sizeof(struct in_addr), + AF_INET)) != NULL) { + DP("%s", host->h_name); + return (char *) host->h_name; + } + + return (char *) NULL; +} + +static char *ip_tonetwork(const struct in_addr *addr) +{ + struct netent *net; + + if ((net = getnetbyaddr(ntohl(addr->s_addr), + AF_INET)) != NULL) { + DP("%s", net->n_name); + return (char *) net->n_name; + } + + return (char *) NULL; +} + +/* Return a string representation of an IP address. + * Please notice that a pointer to static char* area is returned. + */ +char *ip_tostring(ip_set_ip_t ip, unsigned options) +{ + struct in_addr addr; + addr.s_addr = htonl(ip); + + if (!(options & OPT_NUMERIC)) { + char *name; + if ((name = ip_tohost(&addr)) != NULL || + (name = ip_tonetwork(&addr)) != NULL) + return name; + } + + return inet_ntoa(addr); +} + +char *ip_tostring_numeric(ip_set_ip_t ip) +{ + return ip_tostring(ip, OPT_NUMERIC); +} + +/* Fills the 'ip' with the parsed ip or host in host byte order */ +void parse_ip(const char *str, ip_set_ip_t * ip) +{ + struct hostent *host; + struct in_addr addr; + + DP("%s", str); + + if (inet_aton(str, &addr) != 0) { + *ip = ntohl(addr.s_addr); /* We want host byte order */ + return; + } + + host = gethostbyname(str); + if (host != NULL) { + if (host->h_addrtype != AF_INET || + host->h_length != sizeof(struct in_addr)) + exit_error(PARAMETER_PROBLEM, + "host/network `%s' not an internet name", + str); + if (host->h_addr_list[1] != 0) + exit_error(PARAMETER_PROBLEM, + "host/network `%s' resolves to serveral ip-addresses. " + "Please specify one.", str); + + memcpy(&addr, host->h_addr_list[0], sizeof(struct in_addr)); + *ip = ntohl(addr.s_addr); + return; + } + + exit_error(PARAMETER_PROBLEM, "host/network `%s' not found", str); +} + +/* Fills 'mask' with the parsed mask in host byte order */ +void parse_mask(const char *str, ip_set_ip_t * mask) +{ + struct in_addr addr; + int bits; + + DP("%s", str); + + if (str == NULL) { + /* no mask at all defaults to 32 bits */ + *mask = 0xFFFFFFFF; + return; + } + if (strchr(str, '.') && inet_aton(str, &addr) != 0) { + *mask = ntohl(addr.s_addr); /* We want host byte order */ + return; + } + if (sscanf(str, "%d", &bits) != 1 || bits < 0 || bits > 32) + exit_error(PARAMETER_PROBLEM, + "invalid mask `%s' specified", str); + + DP("bits: %d", bits); + + *mask = bits != 0 ? 0xFFFFFFFF << (32 - bits) : 0L; +} + +/* Combines parse_ip and parse_mask */ +void +parse_ipandmask(const char *str, ip_set_ip_t * ip, ip_set_ip_t * mask) +{ + char buf[256]; + char *p; + + strncpy(buf, str, sizeof(buf) - 1); + buf[255] = '\0'; + + if ((p = strrchr(buf, '/')) != NULL) { + *p = '\0'; + parse_mask(p + 1, mask); + } else + parse_mask(NULL, mask); + + /* if a null mask is given, the name is ignored, like in "any/0" */ + if (*mask == 0U) + *ip = 0U; + else + parse_ip(buf, ip); + + DP("%s ip: %08X (%s) mask: %08X", + str, *ip, ip_tostring_numeric(*ip), *mask); + + /* Apply the netmask */ + *ip &= *mask; + + DP("%s ip: %08X (%s) mask: %08X", + str, *ip, ip_tostring_numeric(*ip), *mask); +} + +/* Return a string representation of a port + * Please notice that a pointer to static char* area is returned + * and we assume TCP protocol. + */ +char *port_tostring(ip_set_ip_t port, unsigned options) +{ + struct servent *service; + static char name[] = "65535"; + + if (!(options & OPT_NUMERIC)) { + if ((service = getservbyport(htons(port), "tcp"))) + return service->s_name; + } + sprintf(name, "%u", port); + return name; +} + +int +string_to_number(const char *str, unsigned int min, unsigned int max, + ip_set_ip_t *port) +{ + unsigned long number; + char *end; + + /* Handle hex, octal, etc. */ + errno = 0; + number = strtoul(str, &end, 0); + if (*end == '\0' && end != str) { + /* we parsed a number, let's see if we want this */ + if (errno != ERANGE && min <= number && number <= max) { + *port = number; + return 0; + } + } + return -1; +} + +static int +string_to_port(const char *str, ip_set_ip_t *port) +{ + struct servent *service; + + if ((service = getservbyname(str, "tcp")) != NULL) { + *port = ntohs((uint16_t) service->s_port); + return 0; + } + return -1; +} + +/* Fills the 'ip' with the parsed port in host byte order */ +void parse_port(const char *str, ip_set_ip_t *port) +{ + if ((string_to_number(str, 0, 65535, port) != 0) + && (string_to_port(str, port) != 0)) + exit_error(PARAMETER_PROBLEM, + "Invalid TCP port `%s' specified", str); +} + +/* + * Settype functions + */ +static struct settype *settype_find(const char *typename) +{ + struct settype *runner = all_settypes; + + DP("%s", typename); + + while (runner != NULL) { + if (STREQ(runner->typename, typename)) + return runner; + + runner = runner->next; + } + + return NULL; /* not found */ +} + +static struct settype *settype_load(const char *typename) +{ + char path[sizeof(IPSET_LIB_DIR) + sizeof(IPSET_LIB_NAME) + + strlen(typename)]; + struct settype *settype; + + /* do some search in list */ + settype = settype_find(typename); + if (settype != NULL) + return settype; /* found */ + + /* Else we have to load it */ + sprintf(path, IPSET_LIB_DIR IPSET_LIB_NAME, typename); + + if (dlopen(path, RTLD_NOW)) { + /* Found library. */ + + settype = settype_find(typename); + + if (settype != NULL) + return settype; + } + + /* Can't load the settype */ + exit_error(PARAMETER_PROBLEM, + "Couldn't load settype `%s':%s\n", + typename, dlerror()); + + return NULL; /* Never executed, but keep compilers happy */ +} + +static char *check_set_name(char *setname) +{ + if (strlen(setname) > IP_SET_MAXNAMELEN - 1) + exit_error(PARAMETER_PROBLEM, + "Setname '%s' too long, max %d characters.", + setname, IP_SET_MAXNAMELEN - 1); + + return setname; +} + +static struct settype *check_set_typename(const char *typename) +{ + if (strlen(typename) > IP_SET_MAXNAMELEN - 1) + exit_error(PARAMETER_PROBLEM, + "Typename '%s' too long, max %d characters.", + typename, IP_SET_MAXNAMELEN - 1); + + return settype_load(typename); +} + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +/* Register a new set type */ +void settype_register(struct settype *settype) +{ + struct settype *chk; + size_t size; + + DP("%s", settype->typename); + + /* Check if this typename already exists */ + chk = settype_find(settype->typename); + + if (chk != NULL) + exit_error(OTHER_PROBLEM, + "Set type '%s' already registered!\n", + settype->typename); + + /* Check version */ + if (settype->protocol_version != IP_SET_PROTOCOL_VERSION) + exit_error(OTHER_PROBLEM, + "Set type %s is of wrong protocol version %u!" + " I'm of version %u.\n", settype->typename, + settype->protocol_version, + IP_SET_PROTOCOL_VERSION); + + /* Initialize internal data */ + settype->header = ipset_malloc(settype->header_size); + size = MAX(settype->create_size, settype->adt_size); + settype->data = ipset_malloc(size); + + /* Insert first */ + settype->next = all_settypes; + all_settypes = settype; + + DP("%s registered", settype->typename); +} + +/* Find set functions */ +struct set *set_find_byid(ip_set_id_t id) +{ + struct set *set = NULL; + ip_set_id_t i; + + for (i = 0; i < max_sets; i++) + if (set_list[i] && set_list[i]->id == id) { + set = set_list[i]; + break; + } + + if (set == NULL) + exit_error(PARAMETER_PROBLEM, + "Set identified by id %u is not found", id); + return set; +} + +struct set *set_find_byname(const char *name) +{ + struct set *set = NULL; + ip_set_id_t i; + + for (i = 0; i < max_sets; i++) + if (set_list[i] != NULL && STREQ(set_list[i]->name, name)) { + set = set_list[i]; + break; + } + if (set == NULL) + exit_error(PARAMETER_PROBLEM, + "Set %s is not found", name); + return set; +} + +static ip_set_id_t set_find_free_index(const char *name) +{ + ip_set_id_t i, idx = IP_SET_INVALID_ID; + + for (i = 0; i < max_sets; i++) { + if (idx == IP_SET_INVALID_ID + && set_list[i] == NULL) + idx = i; + if (set_list[i] != NULL && STREQ(set_list[i]->name, name)) + exit_error(PARAMETER_PROBLEM, + "Set %s is already defined, cannot be restored", + name); + } + + if (idx == IP_SET_INVALID_ID) + exit_error(PARAMETER_PROBLEM, + "Set %s cannot be restored, " + "max number of set %u reached", + name, max_sets); + + return idx; +} + +/* + * Send create set order to kernel + */ +static void set_create(const char *name, struct settype *settype) +{ + struct ip_set_req_create req_create; + size_t size; + void *data; + + DP("%s %s", name, settype->typename); + + req_create.op = IP_SET_OP_CREATE; + req_create.version = protocol_version; + strcpy(req_create.name, name); + strcpy(req_create.typename, settype->typename); + + /* Final checks */ + settype->create_final(settype->data, settype->flags); + + /* Alloc memory for the data to send */ + size = sizeof(struct ip_set_req_create) + settype->create_size; + data = ipset_malloc(size); + + /* Add up ip_set_req_create and the settype data */ + memcpy(data, &req_create, sizeof(struct ip_set_req_create)); + memcpy(data + sizeof(struct ip_set_req_create), + settype->data, settype->create_size); + + kernel_sendto(CMD_CREATE, data, size); + free(data); +} + +static void set_restore_create(const char *name, struct settype *settype) +{ + struct set *set; + + DP("%s %s %zu %zu %u %u", name, settype->typename, + restore_offset, sizeof(struct ip_set_restore), + settype->create_size, restore_size); + + /* Sanity checking */ + if (restore_offset + + ALIGNED(sizeof(struct ip_set_restore)) + + ALIGNED(settype->create_size) > restore_size) + exit_error(PARAMETER_PROBLEM, + "Giving up, restore file is screwed up!"); + + /* Final checks */ + settype->create_final(settype->data, settype->flags); + + /* Fill out restore_data */ + restore_set = (struct ip_set_restore *) + (restore_data + restore_offset); + strcpy(restore_set->name, name); + strcpy(restore_set->typename, settype->typename); + restore_set->index = set_find_free_index(name); + restore_set->header_size = settype->create_size; + restore_set->members_size = 0; + + DP("name %s, restore index %u", restore_set->name, restore_set->index); + /* Add settype data */ + + restore_offset += ALIGNED(sizeof(struct ip_set_restore)); + memcpy(restore_data + restore_offset, settype->data, settype->create_size); + + restore_offset += ALIGNED(settype->create_size); + DP("restore_offset: %zu", restore_offset); + + /* Add set to set_list */ + set = ipset_malloc(sizeof(struct set)); + strcpy(set->name, name); + set->settype = settype; + set->index = restore_set->index; + set_list[restore_set->index] = set; +} + +/* + * Send destroy/flush order to kernel for one or all sets + */ +static void set_destroy(const char *name, unsigned op, unsigned cmd) +{ + struct ip_set_req_std req; + + DP("%s %s", cmd == CMD_DESTROY ? "destroy" : "flush", name); + + req.op = op; + req.version = protocol_version; + strcpy(req.name, name); + + kernel_sendto(cmd, &req, sizeof(struct ip_set_req_std)); +} + +/* + * Send rename/swap order to kernel + */ +static void set_rename(const char *name, const char *newname, + unsigned op, unsigned cmd) +{ + struct ip_set_req_create req; + + DP("%s %s %s", cmd == CMD_RENAME ? "rename" : "swap", + name, newname); + + req.op = op; + req.version = protocol_version; + strcpy(req.name, name); + strcpy(req.typename, newname); + + kernel_sendto(cmd, &req, + sizeof(struct ip_set_req_create)); +} + +/* + * Send MAX_SETS, LIST_SIZE and/or SAVE_SIZE orders to kernel + */ +static size_t load_set_list(const char name[IP_SET_MAXNAMELEN], + ip_set_id_t *idx, + unsigned op, unsigned cmd) +{ + void *data = NULL; + struct ip_set_req_max_sets req_max_sets; + struct ip_set_name_list *name_list; + struct set *set; + ip_set_id_t i; + socklen_t size, req_size; + int repeated = 0, res = 0; + + DP("%s %s", cmd == CMD_MAX_SETS ? "MAX_SETS" + : cmd == CMD_LIST_SIZE ? "LIST_SIZE" + : "SAVE_SIZE", + name); + +tryagain: + if (set_list) { + for (i = 0; i < max_sets; i++) + if (set_list[i]) + free(set_list[i]); + free(set_list); + set_list = NULL; + } + /* Get max_sets */ + req_max_sets.op = IP_SET_OP_MAX_SETS; + req_max_sets.version = protocol_version; + strcpy(req_max_sets.set.name, name); + size = sizeof(req_max_sets); + kernel_getfrom(CMD_MAX_SETS, &req_max_sets, &size); + + DP("got MAX_SETS: sets %d, max_sets %d", + req_max_sets.sets, req_max_sets.max_sets); + + max_sets = req_max_sets.max_sets; + set_list = ipset_malloc(max_sets * sizeof(struct set *)); + memset(set_list, 0, max_sets * sizeof(struct set *)); + *idx = req_max_sets.set.index; + + if (req_max_sets.sets == 0) + /* No sets in kernel */ + return 0; + + /* Get setnames */ + size = req_size = ALIGNED(sizeof(struct ip_set_req_setnames)) + + req_max_sets.sets * ALIGNED(sizeof(struct ip_set_name_list)); + data = ipset_malloc(size); + ((struct ip_set_req_setnames *) data)->op = op; + ((struct ip_set_req_setnames *) data)->index = *idx; + + res = kernel_getfrom_handleerrno(cmd, data, &size); + + if (res != 0 || size != req_size) { + free(data); + if (repeated++ < LIST_TRIES) + goto tryagain; + exit_error(OTHER_PROBLEM, + "Tried to get sets from kernel %d times" + " and failed. Please try again when the load on" + " the sets has gone down.", LIST_TRIES); + } + + /* Load in setnames */ + size = ALIGNED(sizeof(struct ip_set_req_setnames)); + while (size + ALIGNED(sizeof(struct ip_set_name_list)) <= req_size) { + name_list = (struct ip_set_name_list *) + (data + size); + set = ipset_malloc(sizeof(struct set)); + strcpy(set->name, name_list->name); + set->index = name_list->index; + set->id = name_list->id; + set->settype = settype_load(name_list->typename); + set_list[name_list->index] = set; + DP("loaded %s, type %s, index %u", + set->name, set->settype->typename, set->index); + size += ALIGNED(sizeof(struct ip_set_name_list)); + } + /* Size to get set members */ + size = ((struct ip_set_req_setnames *)data)->size; + free(data); + + return size; +} + +/* + * Save operation + */ +static size_t save_set(void *data, size_t offset, size_t len) +{ + struct ip_set_save *set_save = + (struct ip_set_save *) (data + offset); + struct set *set; + struct settype *settype; + size_t used; + + DP("offset %zu (%zu/%u/%u), len %zu", offset, + sizeof(struct ip_set_save), + set_save->header_size, set_save->members_size, + len); + if (offset + ALIGNED(sizeof(struct ip_set_save)) > len + || offset + ALIGNED(sizeof(struct ip_set_save)) + + set_save->header_size + set_save->members_size > len) + exit_error(OTHER_PROBLEM, + "Save operation failed, try again later."); + + DP("index: %u", set_save->index); + if (set_save->index == IP_SET_INVALID_ID) { + /* Marker */ + return ALIGNED(sizeof(struct ip_set_save)); + } + set = set_list[set_save->index]; + if (!set) + exit_error(OTHER_PROBLEM, + "Save set failed, try again later."); + settype = set->settype; + + /* Init set header */ + used = ALIGNED(sizeof(struct ip_set_save)); + settype->initheader(set, data + offset + used); + + /* Print create set */ + settype->saveheader(set, OPT_NUMERIC); + + /* Print add IPs */ + used += set_save->header_size; + settype->saveips(set, data + offset + used, + set_save->members_size, OPT_NUMERIC, + DONT_ALIGN); + + return (used + set_save->members_size); +} + +static int try_save_sets(const char name[IP_SET_MAXNAMELEN]) +{ + void *data = NULL; + socklen_t size, req_size = 0; + ip_set_id_t idx; + int res = 0; + time_t now = time(NULL); + + /* Load set_list from kernel */ + size = load_set_list(name, &idx, + IP_SET_OP_SAVE_SIZE, CMD_SAVE); + + if (size) { + /* Get sets and print them */ + /* Take into account marker */ + req_size = (size += ALIGNED(sizeof(struct ip_set_save))); + data = ipset_malloc(size); + ((struct ip_set_req_list *) data)->op = IP_SET_OP_SAVE; + ((struct ip_set_req_list *) data)->index = idx; + res = kernel_getfrom_handleerrno(CMD_SAVE, data, &size); + + if (res != 0 || size != req_size) { + DP("Try again: res: %i, size %u, req_size: %u", + res, size, req_size); + free(data); + return -EAGAIN; + } + } + + printf("# Generated by ipset %s on %s", IPSET_VERSION, ctime(&now)); + size = 0; + while (size < req_size) { + DP("size: %u, req_size: %u", size, req_size); + size += save_set(data, size, req_size); + } + printf("COMMIT\n"); + now = time(NULL); + printf("# Completed on %s", ctime(&now)); + ipset_free(data); + return res; +} + +/* + * Performs a save to stdout + */ +static void set_save(const char name[IP_SET_MAXNAMELEN]) +{ + int i; + + DP("%s", name); + for (i = 0; i < LIST_TRIES; i++) + if (try_save_sets(name) == 0) + return; + + if (errno == EAGAIN) + exit_error(OTHER_PROBLEM, + "Tried to save sets from kernel %d times" + " and failed. Please try again when the load on" + " the sets has gone down.", LIST_TRIES); + else + kernel_error(CMD_SAVE, errno); +} + +/* + * Restore operation + */ + +/* global new argv and argc */ +static char *newargv[255]; +static int newargc = 0; + +/* Build faked argv from parsed line */ +static void build_argv(unsigned line, char *buffer) { + char *ptr; + int i; + + /* Reset */ + for (i = 1; i < newargc; i++) + free(newargv[i]); + newargc = 1; + + ptr = strtok(buffer, " \t\n"); + newargv[newargc++] = ipset_strdup(ptr); + while ((ptr = strtok(NULL, " \t\n")) != NULL) { + if ((newargc + 1) < (int)(sizeof(newargv)/sizeof(char *))) + newargv[newargc++] = ipset_strdup(ptr); + else + exit_error(PARAMETER_PROBLEM, + "Line %d is too long to restore\n", line); + } +} + +static FILE *create_tempfile(void) +{ + char buffer[1024], __tmpdir[] = "/tmp"; + char *tmpdir = NULL; + char *filename; + int fd; + FILE *file; + + if (!(tmpdir = getenv("TMPDIR")) && !(tmpdir = getenv("TMP"))) + tmpdir = __tmpdir; + filename = ipset_malloc(strlen(tmpdir) + strlen(TEMPFILE_PATTERN) + 1); + strcpy(filename, tmpdir); + strcat(filename, TEMPFILE_PATTERN); + + (void) umask(077); /* Create with restrictive permissions */ + fd = mkstemp(filename); + if (fd == -1) + exit_error(OTHER_PROBLEM, "Could not create temporary file."); + if (!(file = fdopen(fd, "r+"))) + exit_error(OTHER_PROBLEM, "Could not open temporary file."); + if (unlink(filename) == -1) + exit_error(OTHER_PROBLEM, "Could not unlink temporary file."); + free(filename); + + while (fgets(buffer, sizeof(buffer), stdin)) { + fputs(buffer, file); + } + fseek(file, 0L, SEEK_SET); + + return file; +} + +/* + * Performs a restore from a file + */ +static void set_restore(char *argv0) +{ + char buffer[1024]; + char *ptr, *name = NULL; + char cmd = ' '; + int first_pass, i; + struct settype *settype = NULL; + struct ip_set_req_setnames *header; + ip_set_id_t idx; + FILE *in; + int res; + + /* Create and store stdin in temporary file */ + in = create_tempfile(); + + /* Load existing sets from kernel */ + load_set_list(IPSET_TOKEN_ALL, &idx, + IP_SET_OP_LIST_SIZE, CMD_RESTORE); + + restore_line = 0; + restore_size = ALIGNED(sizeof(struct ip_set_req_setnames)); /* header */ + DP("restore_size: %u", restore_size); + /* First pass: calculate required amount of data */ + while (fgets(buffer, sizeof(buffer), in)) { + restore_line++; + + if (buffer[0] == '\n') + continue; + else if (buffer[0] == '#') + continue; + else if (strcmp(buffer, "COMMIT\n") == 0) { + /* Enable restore mode */ + restore = 1; + break; + } + + /* -N, -A or -B */ + ptr = strtok(buffer, " \t\n"); + DP("ptr: %s", ptr); + if (ptr == NULL + || ptr[0] != '-' + || !(ptr[1] == 'N' + || ptr[1] == 'A' + || ptr[1] == 'B') + || ptr[2] != '\0') { + exit_error(PARAMETER_PROBLEM, + "Line %u does not start as a valid restore command\n", + restore_line); + } + cmd = ptr[1]; + /* setname */ + ptr = strtok(NULL, " \t\n"); + DP("setname: %s", ptr); + if (ptr == NULL) + exit_error(PARAMETER_PROBLEM, + "Missing set name in line %u\n", + restore_line); + DP("cmd %c", cmd); + switch (cmd) { + case 'N': { + name = check_set_name(ptr); + /* settype */ + ptr = strtok(NULL, " \t\n"); + if (ptr == NULL) + exit_error(PARAMETER_PROBLEM, + "Missing settype in line %u\n", + restore_line); + settype = check_set_typename(ptr); + restore_size += ALIGNED(sizeof(struct ip_set_restore)) + + ALIGNED(settype->create_size); + DP("restore_size (N): %u", restore_size); + break; + } + case 'A': { + if (name == NULL + || strncmp(name, ptr, sizeof(name)) != 0) + exit_error(PARAMETER_PROBLEM, + "Add IP to set %s in line %u without " + "preceding corresponding create set line\n", + ptr, restore_line); + restore_size += ALIGNED(settype->adt_size); + DP("restore_size (A): %u", restore_size); + break; + } + default: { + exit_error(PARAMETER_PROBLEM, + "Unrecognized restore command in line %u\n", + restore_line); + } + } /* end of switch */ + } + /* Sanity checking */ + if (!restore) + exit_error(PARAMETER_PROBLEM, + "Missing COMMIT line\n"); + restore_size += ALIGNED(sizeof(struct ip_set_restore)); /* marker */ + DP("restore_size: %u", restore_size); + restore_data = ipset_malloc(restore_size); + header = (struct ip_set_req_setnames *) restore_data; + header->op = IP_SET_OP_RESTORE; + header->size = restore_size; + restore_offset = ALIGNED(sizeof(struct ip_set_req_setnames)); + + /* Rewind to scan the file again */ + fseek(in, 0L, SEEK_SET); + first_pass = restore_line; + restore_line = 0; + + /* Initialize newargv/newargc */ + newargv[newargc++] = ipset_strdup(argv0); + + /* Second pass: build up restore request */ + while (fgets(buffer, sizeof(buffer), in)) { + restore_line++; + + if (buffer[0] == '\n') + continue; + else if (buffer[0] == '#') + continue; + else if (strcmp(buffer, "COMMIT\n") == 0) + goto do_restore; + DP("restoring: %s", buffer); + /* Build faked argv, argc */ + build_argv(restore_line, buffer); + for (i = 0; i < newargc; i++) + DP("argv[%u]: %s", i, newargv[i]); + + /* Parse line */ + parse_commandline(newargc, newargv); + } + exit_error(PARAMETER_PROBLEM, + "Broken restore file\n"); + do_restore: + if (restore_size == (restore_offset + ALIGNED(sizeof(struct ip_set_restore)))) { + /* No bindings */ + struct ip_set_restore *marker = + (struct ip_set_restore *) (restore_data + restore_offset); + + marker->index = IP_SET_INVALID_ID; + marker->header_size = marker->members_size = 0; + restore_offset += ALIGNED(sizeof(struct ip_set_restore)); + DP("restore marker, restore_offset: %zu", restore_offset); + } + if (restore_size != restore_offset) + exit_error(PARAMETER_PROBLEM, + "Giving up, restore file is screwed up!"); + res = kernel_getfrom_handleerrno(CMD_RESTORE, restore_data, &restore_size); + + if (res != 0) { + if (restore_size != sizeof(struct ip_set_req_setnames)) + exit_error(PARAMETER_PROBLEM, + "Communication with kernel failed (%u %u)!", + restore_size, sizeof(struct ip_set_req_setnames)); + /* Check errors */ + header = (struct ip_set_req_setnames *) restore_data; + if (header->size != 0) + exit_error(PARAMETER_PROBLEM, + "Committing restoring failed at line %u!", + header->size); + } +} + +/* + * Send ADT_GET order to kernel for a set + */ +static struct set *set_adt_get(const char *name) +{ + struct ip_set_req_adt_get req_adt_get; + struct set *set; + socklen_t size; + + DP("%s", name); + + check_protocolversion(); + + req_adt_get.op = IP_SET_OP_ADT_GET; + req_adt_get.version = protocol_version; + strcpy(req_adt_get.set.name, name); + size = sizeof(struct ip_set_req_adt_get); + + kernel_getfrom(CMD_ADT_GET, (void *) &req_adt_get, &size); + + set = ipset_malloc(sizeof(struct set)); + strcpy(set->name, name); + set->index = req_adt_get.set.index; + set->settype = settype_load(req_adt_get.typename); + + return set; +} + +/* + * Send add/del/test order to kernel for a set + */ +static int set_adtip(struct set *set, const char *adt, + unsigned op, unsigned cmd) +{ + struct ip_set_req_adt *req_adt; + size_t size; + void *data; + int res = 0; + + DP("%s -> %s", set->name, adt); + + /* Alloc memory for the data to send */ + size = ALIGNED(sizeof(struct ip_set_req_adt)) + set->settype->adt_size ; + DP("alloc size %zu", size); + data = ipset_malloc(size); + + /* Fill out the request */ + req_adt = (struct ip_set_req_adt *) data; + req_adt->op = op; + req_adt->index = set->index; + memcpy(data + ALIGNED(sizeof(struct ip_set_req_adt)), + set->settype->data, set->settype->adt_size); + + if (kernel_sendto_handleerrno(cmd, data, size) == -1) + switch (op) { + case IP_SET_OP_ADD_IP: + exit_error(OTHER_PROBLEM, "%s is already in set %s.", + adt, set->name); + break; + case IP_SET_OP_DEL_IP: + exit_error(OTHER_PROBLEM, "%s is not in set %s.", + adt, set->name); + break; + case IP_SET_OP_TEST_IP: + ipset_printf("%s is in set %s.", adt, set->name); + res = 0; + break; + default: + break; + } + else + switch (op) { + case IP_SET_OP_TEST_IP: + ipset_printf("%s is NOT in set %s.", adt, set->name); + res = 1; + break; + default: + break; + } + free(data); + + return res; +} + +static void set_restore_add(struct set *set, const char *adt UNUSED) +{ + DP("%s %s", set->name, adt); + /* Sanity checking */ + if (restore_offset + ALIGNED(set->settype->adt_size) > restore_size) + exit_error(PARAMETER_PROBLEM, + "Giving up, restore file is screwed up!"); + + memcpy(restore_data + restore_offset, + set->settype->data, set->settype->adt_size); + restore_set->members_size += ALIGNED(set->settype->adt_size); + restore_offset += ALIGNED(set->settype->adt_size); + + DP("restore_offset: %zu", restore_offset); +} + +/* + * Print operation + */ + +/* Help function to set_list() */ +static size_t print_set(void *data, unsigned options) +{ + struct ip_set_list *setlist = data; + struct set *set = set_list[setlist->index]; + struct settype *settype = set->settype; + size_t offset; + + /* Pretty print the set */ + DP("header size: %u, members size: %u", + setlist->header_size, setlist->members_size); + printf("Name: %s\n", set->name); + printf("Type: %s\n", settype->typename); + printf("References: %d\n", setlist->ref); + + /* Init header */ + offset = ALIGNED(sizeof(struct ip_set_list)); + settype->initheader(set, data + offset); + + /* Pretty print the type header */ + printf("Header:"); + settype->printheader(set, options); + + /* Pretty print all IPs */ + printf("Members:\n"); + offset += setlist->header_size; + DP("Aligned: %u, offset: %zu, members_size %u\n", !DONT_ALIGN, offset, + setlist->members_size); + if (options & OPT_SORTED) + settype->printips_sorted(set, data + offset, + setlist->members_size, options, + DONT_ALIGN); + else + settype->printips(set, data + offset, + setlist->members_size, options, + DONT_ALIGN); + + printf("\n"); /* One newline between sets */ + + return (offset + setlist->members_size); +} + +static int try_list_sets(const char name[IP_SET_MAXNAMELEN], + unsigned options) +{ + void *data = NULL; + ip_set_id_t idx; + socklen_t size, req_size; + int res = 0; + + /* Default is numeric listing */ + if (!(options & (OPT_RESOLVE|OPT_NUMERIC))) + options |= OPT_NUMERIC; + + DP("%s", name); + /* Load set_list from kernel */ + size = req_size = load_set_list(name, &idx, + IP_SET_OP_LIST_SIZE, CMD_LIST); + + if (size) { + /* Get sets and print them */ + data = ipset_malloc(size); + ((struct ip_set_req_list *) data)->op = IP_SET_OP_LIST; + ((struct ip_set_req_list *) data)->index = idx; + res = kernel_getfrom_handleerrno(CMD_LIST, data, &size); + DP("get_lists getsockopt() res=%d errno=%d", res, errno); + + if (res != 0 || size != req_size) { + free(data); + return -EAGAIN; + } + size = 0; + } + while (size != req_size) + size += print_set(data + size, options); + + ipset_free(data); + return res; +} + +/* Print a set or all sets + * All sets: name = NULL + */ +static void list_sets(const char name[IP_SET_MAXNAMELEN], unsigned options) +{ + int i; + + DP("%s", name); + for (i = 0; i < LIST_TRIES; i++) + if (try_list_sets(name, options) == 0) + return; + + if (errno == EAGAIN) + exit_error(OTHER_PROBLEM, + "Tried to list sets from kernel %d times" + " and failed. Please try again when the load on" + " the sets has gone down.", LIST_TRIES); + else + kernel_error(CMD_LIST, errno); +} + +/* Prints help + * If settype is non null help for that type is printed as well + */ +static void set_help(const struct settype *settype) +{ + printf("%s v%s\n\n" + "Usage: %s -N new-set settype [options]\n" + " %s -[XFLSH] [set] [options]\n" + " %s -[EW] from-set to-set\n" + " %s -[ADT] set IP\n" + " %s -R\n" + " %s -v\n" + " %s -h (print this help information)\n\n", + program_name, program_version, + program_name, program_name, program_name, + program_name, program_name, program_name, + program_name); + + printf("Commands:\n" + "Either long or short options are allowed.\n" + " --create -N setname settype \n" + " Create a new set\n" + " --destroy -X [setname]\n" + " Destroy a set or all sets\n" + " --flush -F [setname]\n" + " Flush a set or all sets\n" + " --rename -E from-set to-set\n" + " Rename from-set to to-set\n" + " --swap -W from-set to-set\n" + " Swap the content of two existing sets\n" + " --list -L [setname] [options]\n" + " List the IPs in a set or all sets\n" + " --save -S [setname]\n" + " Save the set or all sets to stdout\n" + " --restore -R [option]\n" + " Restores a saved state\n" + " --add -A setname IP\n" + " Add an IP to a set\n" + " --del -D setname IP\n" + " Deletes an IP from a set\n" + " --test -T setname IP \n" + " Tests if an IP exists in a set.\n" + " --help -H [settype]\n" + " Prints this help, and settype specific help\n" + " --version -V\n" + " Prints version information\n\n" + "Options:\n" + " --sorted -s Numeric sort of the IPs in -L\n" + " --numeric -n Numeric output of addresses in a -L (default)\n" + " --resolve -r Try to resolve addresses in a -L\n" + " --quiet -q Suppress any output to stdout and stderr.\n"); +#ifdef IPSET_DEBUG + printf(" --debug -z Enable debugging\n\n"); +#else + printf("\n"); +#endif + + if (settype != NULL) { + printf("Type '%s' specific:\n", settype->typename); + settype->usage(); + } +} + +static int find_cmd(int option) +{ + int i; + + for (i = 1; i <= NUMBER_OF_CMD; i++) + if (cmdflags[i] == option) + return i; + + return CMD_NONE; +} + +static int parse_adt_cmdline(int command, + const char *name, + char *adt, + struct set **set, + struct settype **settype) +{ + int res = 0; + + *set = restore ? set_find_byname(name) : set_adt_get(name); + + /* Reset space for adt data */ + *settype = (*set)->settype; + memset((*settype)->data, 0, (*settype)->adt_size); + + res = (*settype)->adt_parser(command, adt, (*settype)->data); + + return res; +} + +/* Main worker function */ +int parse_commandline(int argc, char *argv[]) +{ + int res = 0; + int command = CMD_NONE; + unsigned options = 0; + int c; + + char *name = NULL; /* All except -H, -R */ + char *newname = NULL; /* -E, -W */ + char *adt = NULL; /* -A, -D, -T */ + struct set *set = NULL; /* -A, -D, -T */ + struct settype *settype = NULL; /* -N, -H */ + char all_sets[] = IPSET_TOKEN_ALL; + + struct option *opts = opts_long; + + /* Suppress error messages: we may add new options if we + demand-load a protocol. */ + opterr = 0; + /* Reset optind to 0 for restore */ + optind = 0; + + while ((c = getopt_long(argc, argv, opts_short, opts, NULL)) != -1) { + + DP("commandline parsed: opt %c (%s)", c, argv[optind]); + + switch (c) { + /* + * Command selection + */ + case 'h': + case 'H':{ /* Help: -H [typename [options]] */ + check_protocolversion(); + set_command(&command, CMD_HELP); + + if (optarg) + settype = check_set_typename(optarg); + else if (optind < argc + && argv[optind][0] != '-') + settype = check_set_typename(argv[optind++]); + + break; + } + + case 'V': + case 'v': { /* Version */ + printf("%s v%s, protocol version %u.\n", + program_name, program_version, + IP_SET_PROTOCOL_VERSION); + check_protocolversion(); + printf("Kernel module protocol version %u.\n", + protocol_version); + exit(0); + } + + case 'N':{ /* Create: -N name typename options */ + set_command(&command, CMD_CREATE); + + name = check_set_name(optarg); + + /* Protect reserved names */ + if (name[0] == ':') + exit_error(PARAMETER_PROBLEM, + "setname might not start with colon", + cmd2char(CMD_CREATE)); + + if (optind < argc + && argv[optind][0] != '-') + settype = check_set_typename(argv[optind++]); + else + exit_error(PARAMETER_PROBLEM, + "-%c requires setname and settype", + cmd2char(CMD_CREATE)); + + DP("merge options"); + /* Merge the create options */ + opts = merge_options(opts, + settype->create_opts, + &settype->option_offset); + + /* Reset space for create data */ + memset(settype->data, 0, settype->create_size); + + /* Zero the flags */ + settype->flags = 0; + + DP("call create_init"); + /* Call the settype create_init */ + settype->create_init(settype->data); + + break; + } + + case 'X': /* Destroy */ + case 'F': /* Flush */ + case 'L': /* List */ + case 'S':{ /* Save */ + set_command(&command, find_cmd(c)); + + if (optarg) + name = check_set_name(optarg); + else if (optind < argc + && argv[optind][0] != '-') + name = check_set_name(argv[optind++]); + else + name = all_sets; + + break; + } + + case 'R':{ /* Restore */ + set_command(&command, find_cmd(c)); + + break; + } + + case 'E': /* Rename */ + case 'W':{ /* Swap */ + set_command(&command, find_cmd(c)); + name = check_set_name(optarg); + + if (optind < argc + && argv[optind][0] != '-') + newname = check_set_name(argv[optind++]); + else + exit_error(PARAMETER_PROBLEM, + "-%c requires a setname " + "and the new name for that set", + cmd2char(CMD_RENAME)); + + break; + } + + case 'A': /* Add IP */ + case 'D': /* Del IP */ + case 'T':{ /* Test IP */ + set_command(&command, find_cmd(c)); + + name = check_set_name(optarg); + + /* IP */ + if (optind < argc + && argv[optind][0] != '-') + adt = argv[optind++]; + else + exit_error(PARAMETER_PROBLEM, + "-%c requires setname and IP", + c); + + res = parse_adt_cmdline(command, name, adt, + &set, &settype); + + if (!res) + exit_error(PARAMETER_PROBLEM, + "Unknown arg `%s'", + argv[optind - 1]); + + res = 0; + break; + } + + /* options */ + + case 'n': + add_option(&options, OPT_NUMERIC); + break; + + case 'r': + if (!(options & OPT_NUMERIC)) + add_option(&options, OPT_RESOLVE); + break; + + case 's': + add_option(&options, OPT_SORTED); + break; + + case 'q': + add_option(&options, OPT_QUIET); + option_quiet = 1; + break; + +#ifdef IPSET_DEBUG + case 'z': /* debug */ + add_option(&options, OPT_DEBUG); + option_debug = 1; + break; +#endif + + case 1: /* non option */ + printf("Bad argument `%s'\n", optarg); + exit_tryhelp(PARAMETER_PROBLEM); + break; /*always good */ + + default:{ + DP("default"); + + switch (command) { + case CMD_CREATE: + res = settype->create_parse( + c - settype->option_offset, + argv, + settype->data, + &settype->flags); + break; + + default: + res = 0; /* failed */ + } /* switch (command) */ + + + if (!res) + exit_error(PARAMETER_PROBLEM, + "Unknown arg `%s'", + argv[optind - 1]); + + res = 0; + } + + DP("next arg"); + } /* switch */ + + } /* while( getopt_long() ) */ + + + if (optind < argc) + exit_error(PARAMETER_PROBLEM, + "unknown arguments found on commandline"); + if (command == CMD_NONE) + exit_error(PARAMETER_PROBLEM, "no command specified"); + + /* Check options */ + generic_opt_check(command, options); + + DP("cmd: %c", cmd2char(command)); + + check_protocolversion(); + + switch (command) { + case CMD_CREATE: + DP("CMD_CREATE"); + if (restore) + set_restore_create(name, settype); + else + set_create(name, settype); + break; + + case CMD_DESTROY: + set_destroy(name, IP_SET_OP_DESTROY, CMD_DESTROY); + break; + + case CMD_FLUSH: + set_destroy(name, IP_SET_OP_FLUSH, CMD_FLUSH); + break; + + case CMD_RENAME: + set_rename(name, newname, IP_SET_OP_RENAME, CMD_RENAME); + break; + + case CMD_SWAP: + set_rename(name, newname, IP_SET_OP_SWAP, CMD_SWAP); + break; + + case CMD_LIST: + list_sets(name, options); + break; + + case CMD_SAVE: + set_save(name); + break; + + case CMD_RESTORE: + set_restore(argv[0]); + break; + + case CMD_ADD: + if (restore) + set_restore_add(set, adt); + else + set_adtip(set, adt, IP_SET_OP_ADD_IP, CMD_ADD); + break; + + case CMD_DEL: + set_adtip(set, adt, IP_SET_OP_DEL_IP, CMD_DEL); + break; + + case CMD_TEST: + res = set_adtip(set, adt, IP_SET_OP_TEST_IP, CMD_TEST); + break; + + case CMD_HELP: + set_help(settype); + break; + + default: + /* Will never happen */ + break; /* Keep the compiler happy */ + + } /* switch( command ) */ + + return res; +} + + +int main(int argc, char *argv[]) +{ + return parse_commandline(argc, argv); + +} diff --git a/src/ipset.h b/src/ipset.h new file mode 100644 index 0000000..c49418d --- /dev/null +++ b/src/ipset.h @@ -0,0 +1,200 @@ +#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 /* struct option */ +#include +#include + +#include + +#define IPSET_LIB_NAME "/libipset_%s.so" +#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_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 */ + u_int32_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 */ + u_int32_t adt_size; + + /* Function which parses command options */ + ip_set_ip_t (*adt_parser) (int cmd, const char *optarg, void *data); + + /* + * Printing + */ + + /* Size of header. */ + u_int32_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, u_int32_t len, + unsigned options, char dont_align); + + /* Pretty print all IPs sorted */ + void (*printips_sorted) (struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align); + + /* 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, u_int32_t len, + unsigned options, char dont_align); + + /* Print usage */ + void (*usage) (void); + + /* Internal data */ + void *header; + void *data; + 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(int 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); + +extern struct set *set_find_byname(const char *name); +extern struct set *set_find_byid(ip_set_id_t id); + +extern unsigned warn_once; + +#define BITS_PER_LONG (8*sizeof(ip_set_ip_t)) +#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) + +static inline int test_bit(int nr, const ip_set_ip_t *addr) +{ + return 1 & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); +} + +#define UNUSED __attribute__ ((unused)) +#define CONSTRUCTOR(module) \ +void __attribute__ ((constructor)) module##_init(void); \ +void module##_init(void) + +#endif /* __IPSET_H */ diff --git a/src/ipset_iphash.c b/src/ipset_iphash.c new file mode 100644 index 0000000..0bc5bd1 --- /dev/null +++ b/src/ipset_iphash.c @@ -0,0 +1,279 @@ +/* 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 /* UINT_MAX */ +#include /* *printf */ +#include /* mem* */ + +#include "ipset.h" + +#include + +#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 +iphash_create_init(void *data) +{ + struct ip_set_req_iphash_create *mydata = 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 +iphash_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *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 +iphash_create_final(void *data UNUSED, unsigned int flags UNUSED) +{ +} + +/* Create commandline options */ +static const struct option create_opts[] = { + {.name = "hashsize", .has_arg = required_argument, .val = '1'}, + {.name = "probes", .has_arg = required_argument, .val = '2'}, + {.name = "resize", .has_arg = required_argument, .val = '3'}, + {.name = "netmask", .has_arg = required_argument, .val = '4'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +iphash_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_iphash *mydata = 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 +iphash_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_iphash_create *header = data; + struct ip_set_iphash *map = 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 +iphash_printheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_iphash *mysetdata = 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 +iphash_printips(struct set *set UNUSED, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + size_t offset = 0; + ip_set_ip_t *ip; + + while (offset < len) { + ip = data + offset; + printf("%s\n", ip_tostring(*ip, options)); + offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); + } +} + +static void +iphash_saveheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_iphash *mysetdata = 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 +iphash_saveips(struct set *set UNUSED, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + size_t offset = 0; + ip_set_ip_t *ip; + + while (offset < len) { + ip = data + offset; + printf("-A %s %s\n", set->name, ip_tostring(*ip, options)); + offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); + } +} + +static void +iphash_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 = iphash_create_init, + .create_parse = iphash_create_parse, + .create_final = iphash_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_iphash), + .adt_parser = iphash_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_iphash), + .initheader = iphash_initheader, + .printheader = iphash_printheader, + .printips = iphash_printips, + .printips_sorted = iphash_printips, + .saveheader = iphash_saveheader, + .saveips = iphash_saveips, + + .usage = iphash_usage, +}; + +CONSTRUCTOR(iphash) +{ + settype_register(&settype_iphash); + +} diff --git a/src/ipset_ipmap.c b/src/ipset_ipmap.c new file mode 100644 index 0000000..87b8e69 --- /dev/null +++ b/src/ipset_ipmap.c @@ -0,0 +1,376 @@ +/* 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 /* *printf */ +#include /* mem* */ + +#include "ipset.h" + +#include + +#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 +ipmap_create_init(void *data) +{ + struct ip_set_req_ipmap_create *mydata = data; + + DP("create INIT"); + mydata->netmask = 0xFFFFFFFF; +} + +/* Function which parses command options; returns true if it ate an option */ +static int +ipmap_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) +{ + struct ip_set_req_ipmap_create *mydata = 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; +} + +/* Final check; exit if not ok. */ +static void +ipmap_create_final(void *data, unsigned int flags) +{ + struct ip_set_req_ipmap_create *mydata = data; + ip_set_ip_t range; + + 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)) { + exit_error(PARAMETER_PROBLEM, + "You have to define a full network with --from" + " and --to if you specify the --network option\n"); + } + netmask_bits = mask_to_bits(mydata->netmask); + if (netmask_bits <= mask_bits) { + exit_error(PARAMETER_PROBLEM, + "%d netmask specifies larger or equal netblock than the network itself\n"); + } + 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[] = { + {.name = "from", .has_arg = required_argument, .val = '1'}, + {.name = "to", .has_arg = required_argument, .val = '2'}, + {.name = "network", .has_arg = required_argument, .val = '3'}, + {.name = "netmask", .has_arg = required_argument, .val = '4'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +ipmap_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_ipmap *mydata = 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 +ipmap_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_ipmap_create *header = data; + struct ip_set_ipmap *map = 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: %d %d", mask_bits, netmask_bits); + map->hosts = 2 << (32 - netmask_bits - 1); + map->sizeid = 2 << (netmask_bits - mask_bits - 1); + } + + DP("%d %d", map->hosts, map->sizeid ); +} + +static void +ipmap_printheader(struct set *set, unsigned options) +{ + struct ip_set_ipmap *mysetdata = 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 inline void +__ipmap_printips_sorted(struct set *set, void *data, + u_int32_t len UNUSED, unsigned options) +{ + struct ip_set_ipmap *mysetdata = 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 +ipmap_printips_sorted(struct set *set, void *data, + u_int32_t len, unsigned options, + char dont_align) +{ + ip_set_ip_t *ip; + size_t offset = 0; + + if (dont_align) + return __ipmap_printips_sorted(set, data, len, options); + + while (offset < len) { + DP("offset: %zu, len %u\n", offset, len); + ip = data + offset; + printf("%s\n", ip_tostring(*ip, options)); + offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); + } +} + +static void +ipmap_saveheader(struct set *set, unsigned options) +{ + struct ip_set_ipmap *mysetdata = 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 inline void +__ipmap_saveips(struct set *set, void *data, u_int32_t len UNUSED, + unsigned options) +{ + struct ip_set_ipmap *mysetdata = 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 +ipmap_saveips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + ip_set_ip_t *ip; + size_t offset = 0; + + if (dont_align) + return __ipmap_saveips(set, data, len, options); + + while (offset < len) { + ip = data + offset; + printf("-A %s %s\n", set->name, ip_tostring(*ip, options)); + offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); + } +} + +static void +ipmap_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 = ipmap_create_init, + .create_parse = ipmap_create_parse, + .create_final = ipmap_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_ipmap), + .adt_parser = ipmap_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_ipmap), + .initheader = ipmap_initheader, + .printheader = ipmap_printheader, + .printips = ipmap_printips_sorted, + .printips_sorted = ipmap_printips_sorted, + .saveheader = ipmap_saveheader, + .saveips = ipmap_saveips, + + .usage = ipmap_usage, +}; + +CONSTRUCTOR(ipmap) +{ + settype_register(&settype_ipmap); + +} diff --git a/src/ipset_ipporthash.c b/src/ipset_ipporthash.c new file mode 100644 index 0000000..9249b2a --- /dev/null +++ b/src/ipset_ipporthash.c @@ -0,0 +1,350 @@ +/* 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 /* UINT_MAX */ +#include /* *printf */ +#include /* mem*, str* */ + +#include "ipset.h" + +#include + +#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 +ipporthash_create_init(void *data) +{ + struct ip_set_req_ipporthash_create *mydata = 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 +ipporthash_create_parse(int c, char *argv[] UNUSED, void *data, + unsigned *flags) +{ + struct ip_set_req_ipporthash_create *mydata = 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 +ipporthash_create_final(void *data, unsigned int flags) +{ + struct ip_set_req_ipporthash_create *mydata = 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[] = { + {.name = "hashsize", .has_arg = required_argument, .val = '1'}, + {.name = "probes", .has_arg = required_argument, .val = '2'}, + {.name = "resize", .has_arg = required_argument, .val = '3'}, + {.name = "from", .has_arg = required_argument, .val = '4'}, + {.name = "to", .has_arg = required_argument, .val = '5'}, + {.name = "network", .has_arg = required_argument, .val = '6'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +ipporthash_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_ipporthash *mydata = data; + char *saved = ipset_strdup(arg); + char *ptr, *tmp = saved; + + DP("ipporthash: %p %p", arg, data); + + if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) + fprintf(stderr, "Warning: please use ',' separator token between ip,port.\n" + "Next release won't support old separator tokens.\n"); + + 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"); + + if (!(mydata->ip || mydata->port)) + exit_error(PARAMETER_PROBLEM, + "Zero valued IP address and port `%s' specified", arg); + ipset_free(saved); + return 1; +}; + +/* + * Print and save + */ + +static void +ipporthash_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_ipporthash_create *header = data; + struct ip_set_ipporthash *map = 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 +ipporthash_printheader(struct set *set, unsigned options) +{ + struct ip_set_ipporthash *mysetdata = 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 +ipporthash_printips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_ipporthash *mysetdata = set->settype->header; + size_t offset = 0; + ip_set_ip_t *ipptr, ip; + uint16_t port; + + while (offset < len) { + ipptr = data + offset; + ip = (*ipptr>>16) + mysetdata->first_ip; + port = (uint16_t) *ipptr; + printf("%s,%s\n", + ip_tostring(ip, options), + port_tostring(port, options)); + offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); + } +} + +static void +ipporthash_saveheader(struct set *set, unsigned options) +{ + struct ip_set_ipporthash *mysetdata = 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 +ipporthash_saveips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_ipporthash *mysetdata = set->settype->header; + size_t offset = 0; + ip_set_ip_t *ipptr, ip; + uint16_t port; + + while (offset < len) { + ipptr = data + offset; + 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 += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); + } +} + +static void +ipporthash_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 = ipporthash_create_init, + .create_parse = ipporthash_create_parse, + .create_final = ipporthash_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_ipporthash), + .adt_parser = ipporthash_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_ipporthash), + .initheader = ipporthash_initheader, + .printheader = ipporthash_printheader, + .printips = ipporthash_printips, + .printips_sorted = ipporthash_printips, + .saveheader = ipporthash_saveheader, + .saveips = ipporthash_saveips, + + .usage = ipporthash_usage, +}; + +CONSTRUCTOR(ipporthash) +{ + settype_register(&settype_ipporthash); + +} diff --git a/src/ipset_ipportiphash.c b/src/ipset_ipportiphash.c new file mode 100644 index 0000000..49861bf --- /dev/null +++ b/src/ipset_ipportiphash.c @@ -0,0 +1,361 @@ +/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 /* UINT_MAX */ +#include /* *printf */ +#include /* mem*, str* */ + +#include "ipset.h" + +#include + +#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 +ipportiphash_create_init(void *data) +{ + struct ip_set_req_ipportiphash_create *mydata = 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 +ipportiphash_create_parse(int c, char *argv[] UNUSED, void *data, + unsigned *flags) +{ + struct ip_set_req_ipportiphash_create *mydata = 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 +ipportiphash_create_final(void *data, unsigned int flags) +{ + struct ip_set_req_ipportiphash_create *mydata = 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[] = { + {.name = "hashsize", .has_arg = required_argument, .val = '1'}, + {.name = "probes", .has_arg = required_argument, .val = '2'}, + {.name = "resize", .has_arg = required_argument, .val = '3'}, + {.name = "from", .has_arg = required_argument, .val = '4'}, + {.name = "to", .has_arg = required_argument, .val = '5'}, + {.name = "network", .has_arg = required_argument, .val = '6'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +ipportiphash_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_ipportiphash *mydata = data; + char *saved = ipset_strdup(arg); + char *ptr, *tmp = saved; + + DP("ipportiphash: %p %p", arg, data); + + if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) + fprintf(stderr, "Warning: please use ',' separator token between ip,port,ip.\n" + "Next release won't support old separator tokens.\n"); + + ptr = strsep(&tmp, ":%,"); + parse_ip(ptr, &mydata->ip); + + if (!tmp) + exit_error(PARAMETER_PROBLEM, + "IP address, port and IP address must be specified: ip,port,ip"); + + ptr = strsep(&tmp, ":%,"); + parse_port(ptr, &mydata->port); + if (tmp) + parse_ip(tmp, &mydata->ip1); + else + exit_error(PARAMETER_PROBLEM, + "IP address, port and IP address must be specified: ip,port,ip"); + if (!(mydata->ip || mydata->port || mydata->ip1)) + exit_error(PARAMETER_PROBLEM, + "Zero valued IP address, port and IP address `%s' specified", arg); + ipset_free(saved); + return 1; +}; + +/* + * Print and save + */ + +static void +ipportiphash_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_ipportiphash_create *header = data; + struct ip_set_ipportiphash *map = set->settype->header; + + memset(map, 0, sizeof(struct ip_set_ipportiphash)); + map->hashsize = header->hashsize; + map->probes = header->probes; + map->resize = header->resize; + map->first_ip = header->from; + map->last_ip = header->to; +} + +static void +ipportiphash_printheader(struct set *set, unsigned options) +{ + struct ip_set_ipportiphash *mysetdata = 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 +ipportiphash_printips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_ipportiphash *mysetdata = set->settype->header; + size_t offset = 0; + struct ipportip *ipptr; + ip_set_ip_t ip; + uint16_t port; + + while (offset < len) { + ipptr = data + offset; + ip = (ipptr->ip>>16) + mysetdata->first_ip; + port = (uint16_t) ipptr->ip; + printf("%s,%s,", + ip_tostring(ip, options), + port_tostring(port, options)); + printf("%s\n", + ip_tostring(ipptr->ip1, options)); + offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); + } +} + +static void +ipportiphash_saveheader(struct set *set, unsigned options) +{ + struct ip_set_ipportiphash *mysetdata = 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 +ipportiphash_saveips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_ipportiphash *mysetdata = set->settype->header; + size_t offset = 0; + struct ipportip *ipptr; + ip_set_ip_t ip; + uint16_t port; + + while (offset < len) { + ipptr = data + offset; + ip = (ipptr->ip>>16) + mysetdata->first_ip; + port = (uint16_t) ipptr->ip; + printf("-A %s %s,%s,", set->name, + ip_tostring(ip, options), + port_tostring(port, options)); + printf("%s\n", + ip_tostring(ipptr->ip1, options)); + offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); + } +} + +static void +ipportiphash_usage(void) +{ + printf + ("-N set ipportiphash --from IP --to IP\n" + " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" + "-N set ipportiphash --network IP/mask\n" + " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" + "-A set IP,port,IP\n" + "-D set IP,port,IP\n" + "-T set IP,port,IP\n"); +} + +static struct settype settype_ipportiphash = { + .typename = SETTYPE_NAME, + .protocol_version = IP_SET_PROTOCOL_VERSION, + + /* Create */ + .create_size = sizeof(struct ip_set_req_ipportiphash_create), + .create_init = ipportiphash_create_init, + .create_parse = ipportiphash_create_parse, + .create_final = ipportiphash_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_ipportiphash), + .adt_parser = ipportiphash_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_ipportiphash), + .initheader = ipportiphash_initheader, + .printheader = ipportiphash_printheader, + .printips = ipportiphash_printips, + .printips_sorted = ipportiphash_printips, + .saveheader = ipportiphash_saveheader, + .saveips = ipportiphash_saveips, + + .usage = ipportiphash_usage, +}; + +CONSTRUCTOR(ipportiphash) +{ + settype_register(&settype_ipportiphash); + +} diff --git a/src/ipset_ipportnethash.c b/src/ipset_ipportnethash.c new file mode 100644 index 0000000..3a60bf1 --- /dev/null +++ b/src/ipset_ipportnethash.c @@ -0,0 +1,426 @@ +/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 /* UINT_MAX */ +#include /* *printf */ +#include /* mem*, str* */ + +#include "ipset.h" + +#include + +#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 +ipportnethash_create_init(void *data) +{ + struct ip_set_req_ipportnethash_create *mydata = 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 +ipportnethash_create_parse(int c, char *argv[] UNUSED, void *data, + unsigned *flags) +{ + struct ip_set_req_ipportnethash_create *mydata = 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 +ipportnethash_create_final(void *data, unsigned int flags) +{ + struct ip_set_req_ipportnethash_create *mydata = 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[] = { + {.name = "hashsize", .has_arg = required_argument, .val = '1'}, + {.name = "probes", .has_arg = required_argument, .val = '2'}, + {.name = "resize", .has_arg = required_argument, .val = '3'}, + {.name = "from", .has_arg = required_argument, .val = '4'}, + {.name = "to", .has_arg = required_argument, .val = '5'}, + {.name = "network", .has_arg = required_argument, .val = '6'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +ipportnethash_adt_parser(int cmd, const char *arg, void *data) +{ + struct ip_set_req_ipportnethash *mydata = data; + char *saved = ipset_strdup(arg); + char *ptr, *tmp = saved; + ip_set_ip_t cidr; + + DP("ipportnethash: %p %p", arg, data); + + if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) + fprintf(stderr, "Warning: please use ',' separator token between ip,port,net.\n" + "Next release won't support old separator tokens.\n"); + + ptr = strsep(&tmp, ":%,"); + parse_ip(ptr, &mydata->ip); + if (!tmp) + exit_error(PARAMETER_PROBLEM, + "IP address, port and network address must be specified: ip,port,net"); + + ptr = strsep(&tmp, ":%,"); + parse_port(ptr, &mydata->port); + if (!tmp) + exit_error(PARAMETER_PROBLEM, + "IP address, port and network address must be specified: ip,port,net"); + + 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->ip1); + ipset_free(saved); + return 1; +}; + +/* + * Print and save + */ + +static void +ipportnethash_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_ipportnethash_create *header = data; + struct ip_set_ipportnethash *map = set->settype->header; + + memset(map, 0, sizeof(struct ip_set_ipportnethash)); + map->hashsize = header->hashsize; + map->probes = header->probes; + map->resize = header->resize; + map->first_ip = header->from; + map->last_ip = header->to; +} + +static void +ipportnethash_printheader(struct set *set, unsigned options) +{ + struct ip_set_ipportnethash *mysetdata = 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 char buf[20]; + +static char * +unpack_ip_tostring(ip_set_ip_t ip, unsigned options UNUSED) +{ + 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), 0), buf); + return buf; +} + +static void +ipportnethash_printips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_ipportnethash *mysetdata = set->settype->header; + size_t offset = 0; + struct ipportip *ipptr; + ip_set_ip_t ip; + uint16_t port; + + while (offset < len) { + ipptr = data + offset; + ip = (ipptr->ip>>16) + mysetdata->first_ip; + port = (uint16_t) ipptr->ip; + printf("%s,%s,", + ip_tostring(ip, options), + port_tostring(port, options)); + printf("%s\n", + unpack_ip_tostring(ipptr->ip1, options)); + offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); + } +} + +static void +ipportnethash_saveheader(struct set *set, unsigned options) +{ + struct ip_set_ipportnethash *mysetdata = 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 +ipportnethash_saveips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_ipportnethash *mysetdata = set->settype->header; + size_t offset = 0; + struct ipportip *ipptr; + ip_set_ip_t ip; + uint16_t port; + + while (offset < len) { + ipptr = data + offset; + ip = (ipptr->ip>>16) + mysetdata->first_ip; + port = (uint16_t) ipptr->ip; + printf("-A %s %s,%s,", set->name, + ip_tostring(ip, options), + port_tostring(port, options)); + printf("%s\n", + unpack_ip_tostring(ipptr->ip, options)); + offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align); + } +} + +static void +ipportnethash_usage(void) +{ + printf + ("-N set ipportnethash --from IP --to IP\n" + " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" + "-N set ipportnethash --network IP/mask\n" + " [--hashsize hashsize] [--probes probes ] [--resize resize]\n" + "-A set IP,port,IP/net\n" + "-D set IP,port,IP/net\n" + "-T set IP,port,IP[/net]\n"); +} + +static struct settype settype_ipportnethash = { + .typename = SETTYPE_NAME, + .protocol_version = IP_SET_PROTOCOL_VERSION, + + /* Create */ + .create_size = sizeof(struct ip_set_req_ipportnethash_create), + .create_init = ipportnethash_create_init, + .create_parse = ipportnethash_create_parse, + .create_final = ipportnethash_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_ipportnethash), + .adt_parser = ipportnethash_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_ipportnethash), + .initheader = ipportnethash_initheader, + .printheader = ipportnethash_printheader, + .printips = ipportnethash_printips, + .printips_sorted = ipportnethash_printips, + .saveheader = ipportnethash_saveheader, + .saveips = ipportnethash_saveips, + + .usage = ipportnethash_usage, +}; + +CONSTRUCTOR(ipportnethash) +{ + settype_register(&settype_ipportnethash); + +} diff --git a/src/ipset_iptree.c b/src/ipset_iptree.c new file mode 100644 index 0000000..508e67a --- /dev/null +++ b/src/ipset_iptree.c @@ -0,0 +1,224 @@ +/* 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 /* UINT_MAX */ +#include /* *printf */ +#include /* mem* */ + +#include "ipset.h" + +#include + +#define BUFLEN 30; + +#define OPT_CREATE_TIMEOUT 0x01U + +/* Initialize the create. */ +static void +iptree_create_init(void *data) +{ + struct ip_set_req_iptree_create *mydata = data; + + DP("create INIT"); + mydata->timeout = 0; +} + +/* Function which parses command options; returns true if it ate an option */ +static int +iptree_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) +{ + struct ip_set_req_iptree_create *mydata = 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 +iptree_create_final(void *data UNUSED, unsigned int flags UNUSED) +{ +} + +/* Create commandline options */ +static const struct option create_opts[] = { + {.name = "timeout", .has_arg = required_argument, .val = '1'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +iptree_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_iptree *mydata = data; + char *saved = ipset_strdup(arg); + char *ptr, *tmp = saved; + + DP("iptree: %p %p", arg, data); + + if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1) + fprintf(stderr, "Warning: please use ',' separator token between ip,timeout.\n" + "Next release won't support old separator tokens.\n"); + + ptr = strsep(&tmp, ":%,"); + parse_ip(ptr, &mydata->ip); + + if (tmp) + string_to_number(tmp, 0, UINT_MAX, &mydata->timeout); + else + mydata->timeout = 0; + + ipset_free(saved); + return 1; +} + +/* + * Print and save + */ + +static void +iptree_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_iptree_create *header = data; + struct ip_set_iptree *map = set->settype->header; + + map->timeout = header->timeout; +} + +static void +iptree_printheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_iptree *mysetdata = set->settype->header; + + if (mysetdata->timeout) + printf(" timeout: %u", mysetdata->timeout); + printf("\n"); +} + +static void +iptree_printips_sorted(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_iptree *mysetdata = 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 += IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align); + } +} + +static void +iptree_saveheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_iptree *mysetdata = 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 +iptree_saveips(struct set *set, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + struct ip_set_iptree *mysetdata = 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 += IPSET_VALIGN(sizeof(struct ip_set_req_iptree), dont_align); + } +} + +static void +iptree_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 = iptree_create_init, + .create_parse = iptree_create_parse, + .create_final = iptree_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_iptree), + .adt_parser = iptree_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_iptree), + .initheader = iptree_initheader, + .printheader = iptree_printheader, + .printips = iptree_printips_sorted, /* We only have sorted version */ + .printips_sorted = iptree_printips_sorted, + .saveheader = iptree_saveheader, + .saveips = iptree_saveips, + + .usage = iptree_usage, +}; + +CONSTRUCTOR(iptree) +{ + settype_register(&settype_iptree); + +} diff --git a/src/ipset_iptreemap.c b/src/ipset_iptreemap.c new file mode 100644 index 0000000..22bdcb3 --- /dev/null +++ b/src/ipset_iptreemap.c @@ -0,0 +1,208 @@ +/* Copyright 2007 Sven Wegener + * + * 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 /* UINT_MAX */ +#include /* *printf */ +#include /* mem* */ + +#include "ipset.h" + +#include + +#define OPT_CREATE_GC 0x1 + +static void +iptreemap_create_init(void *data) +{ + struct ip_set_req_iptreemap_create *mydata = data; + + mydata->gc_interval = 0; +} + +static int +iptreemap_create_parse(int c, char *argv[] UNUSED, 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 +iptreemap_create_final(void *data UNUSED, unsigned int flags UNUSED) +{ +} + +static const struct option create_opts[] = { + {.name = "gc", .has_arg = required_argument, .val = 'g'}, + {NULL}, +}; + +static ip_set_ip_t +iptreemap_adt_parser(int cmd UNUSED, 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->ip, &mask); + mydata->end = mydata->ip | ~mask; + } else { + if ((ptr = strchr(tmp, ':')) != NULL && ++warn_once == 1) + fprintf(stderr, "Warning: please use '-' separator token between IP range.\n" + "Next release won't support old separator token.\n"); + ptr = strsep(&tmp, "-:"); + parse_ip(ptr, &mydata->ip); + + if (tmp) { + parse_ip(tmp, &mydata->end); + } else { + mydata->end = mydata->ip; + } + } + + ipset_free(saved); + + return 1; +} + +static void +iptreemap_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 +iptreemap_printheader(struct set *set, unsigned int options UNUSED) +{ + struct ip_set_iptreemap *mysetdata = set->settype->header; + + if (mysetdata->gc_interval) + printf(" gc: %u", mysetdata->gc_interval); + + printf("\n"); +} + +static void +iptreemap_printips_sorted(struct set *set UNUSED, void *data, + u_int32_t len, unsigned int options, char dont_align) +{ + 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->ip, options)); + if (req->ip != req->end) + printf("-%s", ip_tostring(req->end, options)); + printf("\n"); + + offset += IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align); + } +} + +static void +iptreemap_saveheader(struct set *set, unsigned int options UNUSED) +{ + 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 +iptreemap_saveips(struct set *set UNUSED, void *data, + u_int32_t len, unsigned int options, char dont_align) +{ + 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->ip, options)); + + if (req->ip != req->end) + printf("-%s", ip_tostring(req->end, options)); + + printf("\n"); + + offset += IPSET_VALIGN(sizeof(struct ip_set_req_iptreemap), dont_align); + } +} + +static void +iptreemap_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 = iptreemap_create_init, + .create_parse = iptreemap_create_parse, + .create_final = iptreemap_create_final, + .create_opts = create_opts, + + .adt_size = sizeof(struct ip_set_req_iptreemap), + .adt_parser = iptreemap_adt_parser, + + .header_size = sizeof(struct ip_set_iptreemap), + .initheader = iptreemap_initheader, + .printheader = iptreemap_printheader, + .printips = iptreemap_printips_sorted, + .printips_sorted = iptreemap_printips_sorted, + .saveheader = iptreemap_saveheader, + .saveips = iptreemap_saveips, + + .usage = iptreemap_usage, +}; + +CONSTRUCTOR(iptreemap) +{ + settype_register(&settype_iptreemap); +} diff --git a/src/ipset_macipmap.c b/src/ipset_macipmap.c new file mode 100644 index 0000000..fb97cae --- /dev/null +++ b/src/ipset_macipmap.c @@ -0,0 +1,382 @@ +/* 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 /* *printf */ +#include /* mem* */ +#include /* str* */ +#include /* ETH_ALEN */ + +#include "ipset.h" + +#include + +#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 +macipmap_create_init(void *data UNUSED) +{ + DP("create INIT"); + /* Nothing */ +} + +/* Function which parses command options; returns true if it ate an option */ +static int +macipmap_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) +{ + struct ip_set_req_macipmap_create *mydata = 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 +macipmap_create_final(void *data, unsigned int flags) +{ + struct ip_set_req_macipmap_create *mydata = 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[] = { + {.name = "from", .has_arg = required_argument, .val = '1'}, + {.name = "to", .has_arg = required_argument, .val = '2'}, + {.name = "network", .has_arg = required_argument, .val = '3'}, + {.name = "matchunset", .has_arg = no_argument, .val = '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 +macipmap_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_macipmap *mydata = data; + char *saved = ipset_strdup(arg); + char *ptr, *tmp = saved; + + DP("macipmap: %p %p", arg, data); + + ptr = strsep(&tmp, ","); + if (!tmp) { + tmp = saved; + ptr = strsep(&tmp, ":%"); + if (tmp && ++warn_once == 1) + fprintf(stderr, "Warning: please use ',' separator token between ip,mac.\n" + "Next release won't support old separator tokens.\n"); + } + 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 +macipmap_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_macipmap_create *header = data; + struct ip_set_macipmap *map = 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 +macipmap_printheader(struct set *set, unsigned options) +{ + struct ip_set_macipmap *mysetdata = 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 inline void +__macipmap_printips_sorted(struct set *set, void *data, + u_int32_t len UNUSED, unsigned options) +{ + struct ip_set_macipmap *mysetdata = set->settype->header; + struct ip_set_macip *table = data; + u_int32_t addr = mysetdata->first_ip; + + while (addr <= mysetdata->last_ip) { + if (table[addr - mysetdata->first_ip].match) { + printf("%s,", ip_tostring(addr, options)); + print_mac(table[addr - mysetdata->first_ip]. + ethernet); + printf("\n"); + } + addr++; + } +} + +static void +macipmap_printips_sorted(struct set *set, void *data, + u_int32_t len, unsigned options, + char dont_align) +{ + struct ip_set_req_macipmap *d; + size_t offset = 0; + + if (dont_align) + return __macipmap_printips_sorted(set, data, len, options); + + while (offset < len) { + d = data + offset; + printf("%s,", ip_tostring(d->ip, options)); + print_mac(d->ethernet); + printf("\n"); + offset += IPSET_ALIGN(sizeof(struct ip_set_req_macipmap)); + } +} + +static void +macipmap_saveheader(struct set *set, unsigned options) +{ + struct ip_set_macipmap *mysetdata = 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 inline void +__macipmap_saveips(struct set *set, void *data, + u_int32_t len UNUSED, unsigned options) +{ + struct ip_set_macipmap *mysetdata = set->settype->header; + struct ip_set_macip *table = data; + u_int32_t addr = mysetdata->first_ip; + + while (addr <= mysetdata->last_ip) { + if (table[addr - mysetdata->first_ip].match) { + printf("-A %s %s,", + set->name, ip_tostring(addr, options)); + print_mac(table[addr - mysetdata->first_ip]. + ethernet); + printf("\n"); + } + addr++; + } +} + +static void +macipmap_saveips(struct set *set, void *data, + u_int32_t len, unsigned options, + char dont_align) +{ + struct ip_set_req_macipmap *d; + size_t offset = 0; + + if (dont_align) + return __macipmap_saveips(set, data, len, options); + + while (offset < len) { + d = data + offset; + printf("-A %s %s,", set->name, ip_tostring(d->ip, options)); + print_mac(d->ethernet); + printf("\n"); + offset += IPSET_ALIGN(sizeof(struct ip_set_req_macipmap)); + } +} + +static void +macipmap_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 = macipmap_create_init, + .create_parse = macipmap_create_parse, + .create_final = macipmap_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_macipmap), + .adt_parser = macipmap_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_macipmap), + .initheader = macipmap_initheader, + .printheader = macipmap_printheader, + .printips = macipmap_printips_sorted, + .printips_sorted = macipmap_printips_sorted, + .saveheader = macipmap_saveheader, + .saveips = macipmap_saveips, + + .usage = macipmap_usage, +}; + +CONSTRUCTOR(macipmap) +{ + settype_register(&settype_macipmap); + +} diff --git a/src/ipset_nethash.c b/src/ipset_nethash.c new file mode 100644 index 0000000..c7891cf --- /dev/null +++ b/src/ipset_nethash.c @@ -0,0 +1,308 @@ +/* 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 /* UINT_MAX */ +#include /* *printf */ +#include /* mem*, str* */ + +#include "ipset.h" + +#include + +#define BUFLEN 30; + +#define OPT_CREATE_HASHSIZE 0x01U +#define OPT_CREATE_PROBES 0x02U +#define OPT_CREATE_RESIZE 0x04U + +/* Initialize the create. */ +static void +nethash_create_init(void *data) +{ + struct ip_set_req_nethash_create *mydata = 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 +nethash_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) +{ + struct ip_set_req_nethash_create *mydata = 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 +nethash_create_final(void *data UNUSED, unsigned int flags UNUSED) +{ +} + +/* Create commandline options */ +static const struct option create_opts[] = { + {.name = "hashsize", .has_arg = required_argument, .val = '1'}, + {.name = "probes", .has_arg = required_argument, .val = '2'}, + {.name = "resize", .has_arg = required_argument, .val = '3'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +nethash_adt_parser(int cmd, const char *arg, void *data) +{ + struct ip_set_req_nethash *mydata = 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 0 + if (!mydata->ip) + exit_error(PARAMETER_PROBLEM, + "Zero valued IP address `%s' specified", ptr); +#endif + ipset_free(saved); + + return 1; +}; + +/* + * Print and save + */ + +static void +nethash_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_nethash_create *header = data; + struct ip_set_nethash *map = 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 +nethash_printheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_nethash *mysetdata = 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 UNUSED) +{ + 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), 0), buf); + return buf; +} + +static void +nethash_printips(struct set *set UNUSED, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + size_t offset = 0; + ip_set_ip_t *ip; + + while (offset < len) { + ip = data + offset; + printf("%s\n", unpack_ip_tostring(*ip, options)); + offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); + } +} + +static void +nethash_saveheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_nethash *mysetdata = 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 +nethash_saveips(struct set *set UNUSED, void *data, u_int32_t len, + unsigned options, char dont_align) +{ + size_t offset = 0; + ip_set_ip_t *ip; + + while (offset < len) { + ip = data + offset; + printf("-A %s %s\n", set->name, + unpack_ip_tostring(*ip, options)); + offset += IPSET_VALIGN(sizeof(ip_set_ip_t), dont_align); + } +} + +static void +nethash_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 = nethash_create_init, + .create_parse = nethash_create_parse, + .create_final = nethash_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_nethash), + .adt_parser = nethash_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_nethash), + .initheader = nethash_initheader, + .printheader = nethash_printheader, + .printips = nethash_printips, + .printips_sorted = nethash_printips, + .saveheader = nethash_saveheader, + .saveips = nethash_saveips, + + .usage = nethash_usage, +}; + +CONSTRUCTOR(nethash) +{ + settype_register(&settype_nethash); + +} diff --git a/src/ipset_portmap.c b/src/ipset_portmap.c new file mode 100644 index 0000000..a1065ae --- /dev/null +++ b/src/ipset_portmap.c @@ -0,0 +1,272 @@ +/* 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 /* *printf */ +#include /* mem* */ + +#include "ipset.h" + +#include + +#define BUFLEN 30; + +#define OPT_CREATE_FROM 0x01U +#define OPT_CREATE_TO 0x02U + +#define OPT_ADDDEL_PORT 0x01U + +/* Initialize the create. */ +static void +portmap_create_init(void *data UNUSED) +{ + DP("create INIT"); + /* Nothing */ +} + +/* Function which parses command options; returns true if it ate an option */ +static int +portmap_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags) +{ + struct ip_set_req_portmap_create *mydata = 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 +portmap_create_final(void *data, unsigned int flags) +{ + struct ip_set_req_portmap_create *mydata = 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[] = { + {.name = "from", .has_arg = required_argument, .val = '1'}, + {.name = "to", .has_arg = required_argument, .val = '2'}, + {NULL}, +}; + +/* Add, del, test parser */ +static ip_set_ip_t +portmap_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_portmap *mydata = data; + + parse_port(arg, &mydata->ip); + DP("%s", port_tostring(mydata->ip, 0)); + + return 1; +} + +/* + * Print and save + */ + +static void +portmap_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_portmap_create *header = data; + struct ip_set_portmap *map = set->settype->header; + + memset(map, 0, sizeof(struct ip_set_portmap)); + map->first_ip = header->from; + map->last_ip = header->to; +} + +static void +portmap_printheader(struct set *set, unsigned options) +{ + struct ip_set_portmap *mysetdata = set->settype->header; + + printf(" from: %s", port_tostring(mysetdata->first_ip, options)); + printf(" to: %s\n", port_tostring(mysetdata->last_ip, options)); +} + +static inline void +__portmap_printips_sorted(struct set *set, void *data, + u_int32_t len UNUSED, unsigned options) +{ + struct ip_set_portmap *mysetdata = set->settype->header; + ip_set_ip_t addr = mysetdata->first_ip; + + DP("%u -- %u", mysetdata->first_ip, mysetdata->last_ip); + while (addr <= mysetdata->last_ip) { + if (test_bit(addr - mysetdata->first_ip, data)) + printf("%s\n", port_tostring(addr, options)); + addr++; + } +} + +static void +portmap_printips_sorted(struct set *set, void *data, + u_int32_t len, unsigned options, + char dont_align) +{ + ip_set_ip_t *ip; + size_t offset = 0; + + if (dont_align) + return __portmap_printips_sorted(set, data, len, options); + + while (offset < len) { + ip = data + offset; + printf("%s\n", port_tostring(*ip, options)); + offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); + } +} + +static void +portmap_saveheader(struct set *set, unsigned options) +{ + struct ip_set_portmap *mysetdata = set->settype->header; + + printf("-N %s %s --from %s", + set->name, + set->settype->typename, + port_tostring(mysetdata->first_ip, options)); + printf(" --to %s\n", + port_tostring(mysetdata->last_ip, options)); +} + +static inline void +__portmap_saveips(struct set *set, void *data, + u_int32_t len UNUSED, unsigned options) +{ + struct ip_set_portmap *mysetdata = set->settype->header; + ip_set_ip_t addr = mysetdata->first_ip; + + while (addr <= mysetdata->last_ip) { + DP("addr: %lu, last_ip %lu", (long unsigned)addr, (long unsigned)mysetdata->last_ip); + if (test_bit(addr - mysetdata->first_ip, data)) + printf("-A %s %s\n", + set->name, + port_tostring(addr, options)); + addr++; + } +} + +static void +portmap_saveips(struct set *set, void *data, + u_int32_t len, unsigned options, + char dont_align) +{ + ip_set_ip_t *ip; + size_t offset = 0; + + if (dont_align) + return __portmap_saveips(set, data, len, options); + + while (offset < len) { + ip = data + offset; + printf("-A %s %s\n", set->name, port_tostring(*ip, options)); + offset += IPSET_ALIGN(sizeof(ip_set_ip_t)); + } +} + +static void +portmap_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 = portmap_create_init, + .create_parse = portmap_create_parse, + .create_final = portmap_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_portmap), + .adt_parser = portmap_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_portmap), + .initheader = portmap_initheader, + .printheader = portmap_printheader, + .printips = portmap_printips_sorted, + .printips_sorted = portmap_printips_sorted, + .saveheader = portmap_saveheader, + .saveips = portmap_saveips, + + .usage = portmap_usage, +}; + +CONSTRUCTOR(portmap) +{ + settype_register(&settype_portmap); + +} diff --git a/src/ipset_setlist.c b/src/ipset_setlist.c new file mode 100644 index 0000000..de16c44 --- /dev/null +++ b/src/ipset_setlist.c @@ -0,0 +1,229 @@ +/* Copyright 2008 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 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 +#include +#include +#include +#include +#include + +#include +#include "ipset.h" + +/* Initialize the create. */ +static void +setlist_create_init(void *data) +{ + struct ip_set_req_setlist_create *mydata = data; + + mydata->size = 8; +} + +/* Function which parses command options; returns true if it ate an option */ +static int +setlist_create_parse(int c, char *argv[] UNUSED, void *data, + unsigned *flags UNUSED) +{ + struct ip_set_req_setlist_create *mydata = data; + unsigned int size; + + switch (c) { + case '1': + if (string_to_number(optarg, 1, 255, &size)) + exit_error(PARAMETER_PROBLEM, + "Invalid size '%s specified: must be " + "between 1-255", optarg); + mydata->size = size; + break; + default: + return 0; + } + return 1; +} + +/* Final check; exit if not ok. */ +static void +setlist_create_final(void *data UNUSED, unsigned int flags UNUSED) +{ +} + +/* Create commandline options */ +static const struct option create_opts[] = { + {.name = "size", .has_arg = required_argument, .val = '1'}, + {NULL}, +}; + +static void +check_setname(const char *name) +{ + if (strlen(name) > IP_SET_MAXNAMELEN - 1) + exit_error(PARAMETER_PROBLEM, + "Setname %s is longer than %d characters.", + name, IP_SET_MAXNAMELEN - 1); +} + +/* Add, del, test parser */ +static ip_set_ip_t +setlist_adt_parser(int cmd UNUSED, const char *arg, void *data) +{ + struct ip_set_req_setlist *mydata = data; + char *saved = ipset_strdup(arg); + char *ptr, *tmp = saved; + + DP("setlist: %p %p", arg, data); + + ptr = strsep(&tmp, ","); + check_setname(ptr); + strcpy(mydata->name, ptr); + + if (!tmp) { + mydata->before = 0; + mydata->ref[0] = '\0'; + return 1; + } + + ptr = strsep(&tmp, ","); + + if (tmp == NULL || !(strcmp(ptr, "before") == 0 || strcmp(ptr, "after") == 0)) + exit_error(PARAMETER_PROBLEM, + "Syntax error, you must specify elements as setname,[before|after],setname"); + + check_setname(tmp); + strcpy(mydata->ref, tmp); + mydata->before = !strcmp(ptr, "before"); + + free(saved); + + return 1; +} + +/* + * Print and save + */ + +static void +setlist_initheader(struct set *set, const void *data) +{ + const struct ip_set_req_setlist_create *header = data; + struct ip_set_setlist *map = set->settype->header; + + memset(map, 0, sizeof(struct ip_set_setlist)); + map->size = header->size; +} + +static void +setlist_printheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_setlist *mysetdata = set->settype->header; + + printf(" size: %u\n", mysetdata->size); +} + +static void +setlist_printips_sorted(struct set *set, void *data, + u_int32_t len UNUSED, unsigned options UNUSED, + char dont_align) +{ + struct ip_set_setlist *mysetdata = set->settype->header; + int i, asize; + ip_set_id_t *id; + struct set *elem; + + asize = IPSET_VALIGN(sizeof(ip_set_id_t), dont_align); + for (i = 0; i < mysetdata->size; i++ ) { + DP("Try %u", i); + id = (ip_set_id_t *)(data + i * asize); + DP("Try %u, check", i); + if (*id == IP_SET_INVALID_ID) + return; + elem = set_find_byid(*id); + printf("%s\n", elem->name); + } +} + +static void +setlist_saveheader(struct set *set, unsigned options UNUSED) +{ + struct ip_set_setlist *mysetdata = set->settype->header; + + printf("-N %s %s --size %u\n", + set->name, set->settype->typename, + mysetdata->size); +} + +static void +setlist_saveips(struct set *set, void *data, + u_int32_t len UNUSED, unsigned options UNUSED, char dont_align) +{ + struct ip_set_setlist *mysetdata = set->settype->header; + int i, asize; + ip_set_id_t *id; + struct set *elem; + + asize = IPSET_VALIGN(sizeof(ip_set_id_t), dont_align); + for (i = 0; i < mysetdata->size; i++ ) { + id = (ip_set_id_t *)(data + i * asize); + if (*id == IP_SET_INVALID_ID) + return; + elem = set_find_byid(*id); + printf("-A %s %s\n", set->name, elem->name); + } +} + +static void +setlist_usage(void) +{ + printf + ("-N set setlist --size size\n" + "-A set setname[,before|after,setname]\n" + "-D set setname\n" + "-T set setname\n"); +} + +static struct settype settype_setlist = { + .typename = SETTYPE_NAME, + .protocol_version = IP_SET_PROTOCOL_VERSION, + + /* Create */ + .create_size = sizeof(struct ip_set_req_setlist_create), + .create_init = setlist_create_init, + .create_parse = setlist_create_parse, + .create_final = setlist_create_final, + .create_opts = create_opts, + + /* Add/del/test */ + .adt_size = sizeof(struct ip_set_req_setlist), + .adt_parser = setlist_adt_parser, + + /* Printing */ + .header_size = sizeof(struct ip_set_setlist), + .initheader = setlist_initheader, + .printheader = setlist_printheader, + .printips = setlist_printips_sorted, + .printips_sorted = setlist_printips_sorted, + .saveheader = setlist_saveheader, + .saveips = setlist_saveips, + + .usage = setlist_usage, +}; + +CONSTRUCTOR(setlist) +{ + settype_register(&settype_setlist); + +} -- cgit v1.2.3