summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile20
-rw-r--r--Rules.make2
-rwxr-xr-xextensions/.ULOG-test2
-rwxr-xr-xextensions/.ah-esp-test3
-rwxr-xr-xextensions/.pool-test2
-rw-r--r--extensions/Makefile13
-rw-r--r--extensions/libipt_POOL.c151
-rw-r--r--extensions/libipt_ah.c191
-rw-r--r--extensions/libipt_esp.c191
-rw-r--r--extensions/libipt_pool.c143
-rw-r--r--include/libippool/ip_pool_support.h26
-rw-r--r--ippool/Makefile18
-rw-r--r--ippool/ippool.c589
-rw-r--r--ippool/libippool.c72
-rw-r--r--iptables.820
15 files changed, 1432 insertions, 11 deletions
diff --git a/Makefile b/Makefile
index 11c4d1ce..583db003 100644
--- a/Makefile
+++ b/Makefile
@@ -4,8 +4,8 @@ TOPLEVEL_INCLUDED=YES
ifndef KERNEL_DIR
KERNEL_DIR=/usr/src/linux
endif
-NETFILTER_VERSION:=1.1.1
-OLD_NETFILTER_VERSION:=1.1.0
+NETFILTER_VERSION:=1.1.2
+OLD_NETFILTER_VERSION:=1.1.1
LIBDIR:=/usr/local/lib
BINDIR:=/usr/local/bin
@@ -30,7 +30,10 @@ ifndef IPT_LIBDIR
IPT_LIBDIR:=$(LIBDIR)/iptables
endif
-default: patchcheck all
+default: print-extensions all
+
+print-extensions:
+ @echo Extensions found: $(OPTIONALS)
iptables.o: iptables.c
$(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" -c -o $@ $<
@@ -42,13 +45,6 @@ $(DESTDIR)$(BINDIR)/iptables: iptables
@[ -d $(DESTDIR)$(BINDIR) ] || mkdir -p $(DESTDIR)$(BINDIR)
cp $< $@
-# Temporary check for patches: really old patches may fail `isapplied'.
-patchcheck:
- @for f in `echo patch-*`; do \
- if ./isapplied $(KERNEL_DIR) $$f >/dev/null; then :; \
- else echo Please apply $$f to this kernel.; exit 1; \
- fi; done
-
iptables-save: iptables-save.c iptables.o libiptc/libiptc.a
$(CC) $(CFLAGS) -DIPT_LIB_DIR=\"$(IPT_LIBDIR)\" -rdynamic -o $@ $^ -ldl
@@ -99,6 +95,10 @@ iptables-standalone.d iptables.d: %.d: %.c
distclean: clean
@rm -f TAGS `find . -name '*~'` `find . -name '*.rej'` `find . -name '*.d'` .makefirst
+.PHONY: patch-o-matic
+patch-o-matic:
+ @cd $@ && KERNEL_DIR=$(KERNEL_DIR) ./runme
+
# Rusty's distro magic.
distrib: check nowhitespace distclean delrelease /home/public/netfilter/iptables-$(NETFILTER_VERSION).tar.bz2 diff md5sums
diff --git a/Rules.make b/Rules.make
index 02bd086d..d76ac630 100644
--- a/Rules.make
+++ b/Rules.make
@@ -2,8 +2,10 @@
all: $(SHARED_LIBS) $(EXTRAS)
+# Have to handle extensions which no longer exist.
clean: $(EXTRA_CLEANS)
rm -f $(SHARED_LIBS) $(EXTRAS) $(SHARED_LIBS:%.so=%_sh.o)
+ @find . -name '*.[ao]' | xargs rm -f
install: all $(EXTRA_INSTALLS)
diff --git a/extensions/.ULOG-test b/extensions/.ULOG-test
new file mode 100755
index 00000000..7ca85237
--- /dev/null
+++ b/extensions/.ULOG-test
@@ -0,0 +1,2 @@
+#! /bin/sh
+[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_ULOG.h ] && echo ULOG
diff --git a/extensions/.ah-esp-test b/extensions/.ah-esp-test
new file mode 100755
index 00000000..f8b779c9
--- /dev/null
+++ b/extensions/.ah-esp-test
@@ -0,0 +1,3 @@
+#! /bin/sh
+# True if ah is applied.
+[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_ah.h ] && echo ah esp
diff --git a/extensions/.pool-test b/extensions/.pool-test
new file mode 100755
index 00000000..54d04bfb
--- /dev/null
+++ b/extensions/.pool-test
@@ -0,0 +1,2 @@
+#! /bin/sh
+[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ip_pool.h ] && echo pool POOL
diff --git a/extensions/Makefile b/extensions/Makefile
index 2110df54..2817ce24 100644
--- a/extensions/Makefile
+++ b/extensions/Makefile
@@ -1,7 +1,18 @@
#! /usr/bin/make
-PF_EXT_SLIB:=tcp udp icmp mac limit standard REJECT LOG unclean state multiport tos TOS mark MARK owner SNAT DNAT MASQUERADE REDIRECT #ULOG
+PF_EXT_SLIB:=tcp udp icmp mac limit standard REJECT LOG unclean state multiport tos TOS mark MARK owner SNAT DNAT MASQUERADE REDIRECT MIRROR
PF6_EXT_SLIB:=tcp udp icmp standard
+
+# Optionals
+PF_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
+PF6_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test6),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
+
+PF_EXT_SLIB+=$(PF_EXT_SLIB_OPTS)
+PF6_EXT_SLIB+=$(PF6_EXT_SLIB_OPTS)
+
+OPTIONALS+=$(patsubst %,IPv4:%,$(PF_EXT_SLIB_OPTS))
+OPTIONALS+=$(patsubst %,IPv6:%,$(PF6_EXT_SLIB_OPTS))
+
SHARED_LIBS+=$(foreach T,$(PF_EXT_SLIB),extensions/libipt_$(T).so)
SHARED_LIBS+=$(foreach T,$(PF6_EXT_SLIB),extensions/libip6t_$(T).so)
EXTRA_INSTALLS+=$(foreach T, $(PF_EXT_SLIB), $(DESTDIR)$(LIBDIR)/iptables/libipt_$(T).so)
diff --git a/extensions/libipt_POOL.c b/extensions/libipt_POOL.c
new file mode 100644
index 00000000..12d9572d
--- /dev/null
+++ b/extensions/libipt_POOL.c
@@ -0,0 +1,151 @@
+/* Shared library add-on to iptables to add IP pool mangling target. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_pool.h>
+#include <linux/netfilter_ipv4/ipt_pool.h>
+
+#include <libippool/ip_pool_support.h>
+
+/* FIXME --RR */
+#include "../ippool/libippool.c"
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"POOL v%s options:\n"
+" --add-srcip <pool>\n"
+" --del-srcip <pool>\n"
+" --add-dstip <pool>\n"
+" --del-dstip <pool>\n"
+" add/del src/dst IP from pool.\n\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "add-srcip", 1, 0, '1' },
+ { "del-srcip", 1, 0, '2' },
+ { "add-dstip", 1, 0, '3' },
+ { "del-dstip", 1, 0, '4' },
+ { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ipt_entry_target *target, unsigned int *nfcache)
+{
+ struct ipt_pool_info *ipi = (struct ipt_pool_info *) target->data;
+
+ ipi->src = ipi->dst = IP_POOL_NONE;
+ ipi->flags = 0;
+
+ /* Can't cache this */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ struct ipt_entry_target **target)
+{
+ struct ipt_pool_info *ipi = (struct ipt_pool_info *) (*target)->data;
+ switch (c) {
+ case '1': /* --add-srcip <pool> */
+ ipi->src = ip_pool_get_index(optarg);
+ ipi->flags &= ~IPT_POOL_DEL_SRC;
+ break;
+ case '2': /* --del-srcip <pool> */
+ ipi->src = ip_pool_get_index(optarg);
+ ipi->flags |= IPT_POOL_DEL_SRC;
+ break;
+ case '3': /* --add-dstip <pool> */
+ ipi->dst = ip_pool_get_index(optarg);
+ ipi->flags &= ~IPT_POOL_DEL_DST;
+ break;
+ case '4': /* --del-dstip <pool> */
+ ipi->dst = ip_pool_get_index(optarg);
+ ipi->flags |= IPT_POOL_DEL_DST;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+/* Final check; don't care. */
+static void final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_target *target,
+ int numeric)
+{
+ char buf[256];
+ struct ipt_pool_info *ipi = (struct ipt_pool_info *) target->data;
+
+ printf("POOL");
+ if (ipi->src != IP_POOL_NONE) {
+ printf(" --%s-srcip %s",
+ (ipi->flags & IPT_POOL_DEL_SRC) ? "del" : "add",
+ ip_pool_get_name(buf, sizeof(buf), ipi->src, numeric));
+ }
+ if (ipi->dst != IP_POOL_NONE) {
+ printf(" --%s-dstip %s",
+ (ipi->flags & IPT_POOL_DEL_DST) ? "del" : "add",
+ ip_pool_get_name(buf, sizeof(buf), ipi->dst, numeric));
+ }
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+ char buf[256];
+ struct ipt_pool_info *ipi = (struct ipt_pool_info *) target->data;
+
+ printf("-j POOL");
+ if (ipi->src != IP_POOL_NONE) {
+ printf(" --%s-srcip %s",
+ (ipi->flags & IPT_POOL_DEL_SRC) ? "del" : "add",
+ ip_pool_get_name(buf, sizeof(buf), ipi->src, 0));
+ }
+ if (ipi->dst != IP_POOL_NONE) {
+ printf(" --%s-dstip %s",
+ (ipi->flags & IPT_POOL_DEL_DST) ? "del" : "add",
+ ip_pool_get_name(buf, sizeof(buf), ipi->dst, 0));
+ }
+}
+
+struct iptables_target ipt_pool_target
+= { NULL,
+ "POOL",
+ NETFILTER_VERSION,
+ IPT_ALIGN(sizeof(struct ipt_pool_info)),
+ IPT_ALIGN(sizeof(struct ipt_pool_info)),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_target(&ipt_pool_target);
+}
diff --git a/extensions/libipt_ah.c b/extensions/libipt_ah.c
new file mode 100644
index 00000000..e779fa53
--- /dev/null
+++ b/extensions/libipt_ah.c
@@ -0,0 +1,191 @@
+/* Shared library add-on to iptables to add AH support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ipt_ah.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"AH v%s options:\n"
+" --ahspi [!] spi[:spi]\n"
+" match spi (range)\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "ahspi", 1, 0, '1' },
+ {0}
+};
+
+static u_int32_t
+parse_ah_spi(const char *spistr)
+{
+ unsigned long int spi;
+ char* ep;
+
+ spi = strtoul(spistr,&ep,0) ;
+
+ if ( spistr == ep ) {
+ exit_error(PARAMETER_PROBLEM,
+ "AH no valid digits in spi `%s'", spistr);
+ }
+ if ( spi == ULONG_MAX && errno == ERANGE ) {
+ exit_error(PARAMETER_PROBLEM,
+ "spi `%s' specified too big: would overflow", spistr);
+ }
+ if ( *spistr != '\0' && *ep != '\0' ) {
+ exit_error(PARAMETER_PROBLEM,
+ "AH error parsing spi `%s'", spistr);
+ }
+ return (u_int32_t) spi;
+}
+
+static void
+parse_ah_spis(const char *spistring, u_int32_t *spis)
+{
+ char *buffer;
+ char *cp;
+
+ buffer = strdup(spistring);
+ if ((cp = strchr(buffer, ':')) == NULL)
+ spis[0] = spis[1] = parse_ah_spi(buffer);
+ else {
+ *cp = '\0';
+ cp++;
+
+ spis[0] = buffer[0] ? parse_ah_spi(buffer) : 0;
+ spis[1] = cp[0] ? parse_ah_spi(cp) : 0xFFFFFFFF;
+ }
+ free(buffer);
+}
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ struct ipt_ah *ahinfo = (struct ipt_ah *)m->data;
+
+ ahinfo->spis[1] = 0xFFFFFFFF;
+}
+
+#define AH_SPI 0x01
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ unsigned int *nfcache,
+ struct ipt_entry_match **match)
+{
+ struct ipt_ah *ahinfo = (struct ipt_ah *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags & AH_SPI)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one `--spi' allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_ah_spis(argv[optind-1], ahinfo->spis);
+ if (invert)
+ ahinfo->invflags |= IPT_AH_INV_SPI;
+ *flags |= AH_SPI;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; we don't care. */
+static void
+final_check(unsigned int flags)
+{
+}
+
+static void
+print_spis(const char *name, u_int32_t min, u_int32_t max,
+ int invert)
+{
+ const char *inv = invert ? "!" : "";
+
+ if (min != 0 || max != 0xFFFFFFFF || invert) {
+ printf("%s", name);
+ if (min == max) {
+ printf(":%s", inv);
+ printf("%u", min);
+ } else {
+ printf("s:%s", inv);
+ printf("%u",min);
+ printf(":");
+ printf("%u",max);
+ }
+ printf(" ");
+ }
+}
+
+/* Prints out the union ipt_matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match, int numeric)
+{
+ const struct ipt_ah *ah = (struct ipt_ah *)match->data;
+
+ printf("ah ");
+ print_spis("spi", ah->spis[0], ah->spis[1],
+ ah->invflags & IPT_AH_INV_SPI);
+ if (ah->invflags & ~IPT_AH_INV_MASK)
+ printf("Unknown invflags: 0x%X ",
+ ah->invflags & ~IPT_AH_INV_MASK);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct ipt_ah *ahinfo = (struct ipt_ah *)match->data;
+
+ if (ahinfo->spis[0] != 0
+ && ahinfo->spis[1] != 0xFFFFFFFF) {
+ if (ahinfo->invflags & IPT_AH_INV_SPI)
+ printf("! ");
+ if (ahinfo->spis[0]
+ != ahinfo->spis[1])
+ printf("--spi %u-%u ",
+ ahinfo->spis[0],
+ ahinfo->spis[1]);
+ else
+ printf("--spi %u ",
+ ahinfo->spis[0]);
+ }
+
+}
+
+struct iptables_match ah
+= { NULL,
+ "ah",
+ NETFILTER_VERSION,
+ IPT_ALIGN(sizeof(struct ipt_ah)),
+ IPT_ALIGN(sizeof(struct ipt_ah)),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void
+_init(void)
+{
+ register_match(&ah);
+}
diff --git a/extensions/libipt_esp.c b/extensions/libipt_esp.c
new file mode 100644
index 00000000..d60c2a65
--- /dev/null
+++ b/extensions/libipt_esp.c
@@ -0,0 +1,191 @@
+/* Shared library add-on to iptables to add ESP support. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ipt_esp.h>
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"ESP v%s options:\n"
+" --espspi [!] spi[:spi]\n"
+" match spi (range)\n",
+NETFILTER_VERSION);
+}
+
+static struct option opts[] = {
+ { "espspi", 1, 0, '1' },
+ {0}
+};
+
+static u_int32_t
+parse_esp_spi(const char *spistr)
+{
+ unsigned long int spi;
+ char* ep;
+
+ spi = strtoul(spistr,&ep,0) ;
+
+ if ( spistr == ep ) {
+ exit_error(PARAMETER_PROBLEM,
+ "ESP no valid digits in spi `%s'", spistr);
+ }
+ if ( spi == ULONG_MAX && errno == ERANGE ) {
+ exit_error(PARAMETER_PROBLEM,
+ "spi `%s' specified too big: would overflow", spistr);
+ }
+ if ( *spistr != '\0' && *ep != '\0' ) {
+ exit_error(PARAMETER_PROBLEM,
+ "ESP error parsing spi `%s'", spistr);
+ }
+ return (u_int32_t) spi;
+}
+
+static void
+parse_esp_spis(const char *spistring, u_int32_t *spis)
+{
+ char *buffer;
+ char *cp;
+
+ buffer = strdup(spistring);
+ if ((cp = strchr(buffer, ':')) == NULL)
+ spis[0] = spis[1] = parse_esp_spi(buffer);
+ else {
+ *cp = '\0';
+ cp++;
+
+ spis[0] = buffer[0] ? parse_esp_spi(buffer) : 0;
+ spis[1] = cp[0] ? parse_esp_spi(cp) : 0xFFFFFFFF;
+ }
+ free(buffer);
+}
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+ struct ipt_esp *espinfo = (struct ipt_esp *)m->data;
+
+ espinfo->spis[1] = 0xFFFFFFFF;
+}
+
+#define ESP_SPI 0x01
+
+/* Function which parses command options; returns true if it
+ ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ unsigned int *nfcache,
+ struct ipt_entry_match **match)
+{
+ struct ipt_esp *espinfo = (struct ipt_esp *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (*flags & ESP_SPI)
+ exit_error(PARAMETER_PROBLEM,
+ "Only one `--spi' allowed");
+ if (check_inverse(optarg, &invert))
+ optind++;
+ parse_esp_spis(argv[optind-1], espinfo->spis);
+ if (invert)
+ espinfo->invflags |= IPT_ESP_INV_SPI;
+ *flags |= ESP_SPI;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; we don't care. */
+static void
+final_check(unsigned int flags)
+{
+}
+
+static void
+print_spis(const char *name, u_int32_t min, u_int32_t max,
+ int invert)
+{
+ const char *inv = invert ? "!" : "";
+
+ if (min != 0 || max != 0xFFFFFFFF || invert) {
+ printf("%s", name);
+ if (min == max) {
+ printf(":%s", inv);
+ printf("%u", min);
+ } else {
+ printf("s:%s", inv);
+ printf("%u",min);
+ printf(":");
+ printf("%u",max);
+ }
+ printf(" ");
+ }
+}
+
+/* Prints out the union ipt_matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match, int numeric)
+{
+ const struct ipt_esp *esp = (struct ipt_esp *)match->data;
+
+ printf("esp ");
+ print_spis("spi", esp->spis[0], esp->spis[1],
+ esp->invflags & IPT_ESP_INV_SPI);
+ if (esp->invflags & ~IPT_ESP_INV_MASK)
+ printf("Unknown invflags: 0x%X ",
+ esp->invflags & ~IPT_ESP_INV_MASK);
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ const struct ipt_esp *espinfo = (struct ipt_esp *)match->data;
+
+ if (espinfo->spis[0] != 0
+ && espinfo->spis[1] != 0xFFFFFFFF) {
+ if (espinfo->invflags & IPT_ESP_INV_SPI)
+ printf("! ");
+ if (espinfo->spis[0]
+ != espinfo->spis[1])
+ printf("--spi %u-%u ",
+ espinfo->spis[0],
+ espinfo->spis[1]);
+ else
+ printf("--spi %u ",
+ espinfo->spis[0]);
+ }
+
+}
+
+struct iptables_match esp
+= { NULL,
+ "esp",
+ NETFILTER_VERSION,
+ IPT_ALIGN(sizeof(struct ipt_esp)),
+ IPT_ALIGN(sizeof(struct ipt_esp)),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void
+_init(void)
+{
+ register_match(&esp);
+}
diff --git a/extensions/libipt_pool.c b/extensions/libipt_pool.c
new file mode 100644
index 00000000..23e2922d
--- /dev/null
+++ b/extensions/libipt_pool.c
@@ -0,0 +1,143 @@
+/* Shared library add-on to iptables to add IP address pool matching. */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ctype.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ipt_pool.h>
+
+#include <libippool/ip_pool_support.h>
+
+/* FIXME --RR */
+#include "../ippool/libippool.c"
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+ printf(
+"pool v%s options:\n"
+" [!] --srcpool NAME|INDEX\n"
+" [!] --dstpool NAME|INDEX\n"
+" Pool index (or name from %s) to match\n"
+"\n", NETFILTER_VERSION, IPPOOL_CONF);
+}
+
+static struct option opts[] = {
+ { "srcpool", 1, 0, '1' },
+ { "dstpool", 1, 0, '2' },
+ {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *match, unsigned int *nfcache)
+{
+ struct ipt_pool_info *info =
+ (struct ipt_pool_info *)match->data;
+
+ info->src = IP_POOL_NONE;
+ info->dst = IP_POOL_NONE;
+ info->flags = 0;
+ /* Can't cache this - XXX */
+ *nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+ const struct ipt_entry *entry,
+ unsigned int *nfcache,
+ struct ipt_entry_match **match)
+{
+ struct ipt_pool_info *info =
+ (struct ipt_pool_info *)(*match)->data;
+
+ switch (c) {
+ case '1':
+ if (check_inverse(optarg, &invert)) optind++;
+ info->src = ip_pool_get_index(argv[optind-1]);
+ if (invert) info->flags |= IPT_POOL_INV_SRC;
+ *flags = 1;
+ break;
+ case '2':
+ if (check_inverse(optarg, &invert)) optind++;
+ info->dst = ip_pool_get_index(argv[optind-1]);
+ if (invert) info->flags |= IPT_POOL_INV_DST;
+ *flags = 1;
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Final check; must have specified --srcpool or --dstpool. */
+static void final_check(unsigned int flags)
+{
+ if (!flags)
+ exit_error(PARAMETER_PROBLEM, "You must specify either `--srcpool or --dstpool'");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+ const struct ipt_entry_match *match,
+ int numeric)
+{
+ char buf[256];
+ struct ipt_pool_info *info =
+ (struct ipt_pool_info *)match->data;
+
+ if (info->src != IP_POOL_NONE)
+ printf("%ssrcpool %s ",
+ (info->flags & IPT_POOL_INV_SRC) ? "!" : "",
+ ip_pool_get_name(buf, sizeof(buf), info->src, 0));
+ if (info->dst != IP_POOL_NONE)
+ printf("%sdstpool %s ",
+ (info->flags & IPT_POOL_INV_DST) ? "!" : "",
+ ip_pool_get_name(buf, sizeof(buf), info->dst, 0));
+}
+
+/* Saves the matchinfo in parsable form to stdout. */
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+ char buf[256];
+ struct ipt_pool_info *info =
+ (struct ipt_pool_info *)match->data;
+
+ if (info->src != IP_POOL_NONE)
+ printf("%s--srcpool %s",
+ (info->flags & IPT_POOL_INV_SRC) ? "! " : "",
+ ip_pool_get_name(buf, sizeof(buf), info->src, 0));
+ if (info->dst != IP_POOL_NONE)
+ printf("%s--dstpool %s",
+ (info->flags & IPT_POOL_INV_DST) ? "! " : "",
+ ip_pool_get_name(buf, sizeof(buf), info->dst, 0));
+}
+
+struct iptables_match pool
+= { NULL,
+ "pool",
+ NETFILTER_VERSION,
+ IPT_ALIGN(sizeof(struct ipt_pool_info)),
+ IPT_ALIGN(sizeof(struct ipt_pool_info)),
+ &help,
+ &init,
+ &parse,
+ &final_check,
+ &print,
+ &save,
+ opts
+};
+
+void _init(void)
+{
+ register_match(&pool);
+}
diff --git a/include/libippool/ip_pool_support.h b/include/libippool/ip_pool_support.h
new file mode 100644
index 00000000..4a87f026
--- /dev/null
+++ b/include/libippool/ip_pool_support.h
@@ -0,0 +1,26 @@
+/* support function prototypes for IP pool management (config file, mostly) */
+#ifndef _IP_POOL_SUPPORT_H
+#define _IP_POOL_SUPPORT_H
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_pool.h>
+
+#ifndef IPPOOL_CONF
+#define IPPOOL_CONF "/etc/ippool.conf"
+#endif
+
+/* called just to draw in this support .o */
+void ip_pool_init(void);
+
+/* given a pool name (or number), return pool index, possibly reading .conf */
+ip_pool_t ip_pool_get_index(char *name);
+
+/* given a pool index, and a buffer to store a name, search for the index
+ * in the .conf file, and give the textual name, if present; if not, the
+ * numeric index is returned. If numeric_flag == 1, the numeric index is
+ * always returned
+ */
+char *ip_pool_get_name(char *buf, int size, ip_pool_t index, int numeric_flag);
+
+#endif /*_IP_POOL_SUPPORT_H*/
diff --git a/ippool/Makefile b/ippool/Makefile
new file mode 100644
index 00000000..100c2e43
--- /dev/null
+++ b/ippool/Makefile
@@ -0,0 +1,18 @@
+EXTRAS+=$(shell [ -f $(KERNEL_DIR)/include/linux/netfilter_ipv4/ip_pool.h ] && echo ippool/libippool.a ippool/ippool)
+
+ifndef TOPLEVEL_INCLUDED
+local:
+ cd .. && $(MAKE) $(KERN_TARGETS) $(SHARED_LIBS) $(EXTRAS)
+
+else
+EXTRA_DEPENDS+=$(shell [ -f $(KERNEL_DIR)/include/linux/netfilter_ipv4/ip_pool.h ] && echo ippool/libippool.d)
+
+ippool/libippool.a: ippool/libippool.a(ippool/libippool.o)
+
+ippool/libippool.d: %.d: %.c
+ @-$(CC) -M -MG $(CFLAGS) $< | sed -e 's@^.*\.o:@$*.d $*.a($*.o):@' > $@
+
+ippool/ippool.o: ippool/ippool.c
+ippool/ippool: ippool/ippool.o ippool/libippool.a
+ $(CC) $(CFLAGS) -o $@ $^
+endif
diff --git a/ippool/ippool.c b/ippool/ippool.c
new file mode 100644
index 00000000..3a680d32
--- /dev/null
+++ b/ippool/ippool.c
@@ -0,0 +1,589 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <linux/netfilter_ipv4/ip_pool.h>
+#include <libippool/ip_pool_support.h>
+
+/* translate errnos, as returned by our *sockopt() functions */
+static char *errno2msg(int op, int err)
+{
+ switch(err) {
+ case ERANGE:
+ return "Address out of pool range";
+ }
+ return strerror(err);
+}
+
+static void usage(char *msg)
+{
+ if (msg) fprintf(stderr, "ERROR: %s\n", msg);
+ fprintf(stderr,
+"Usage: ippool [-LADCNF] [POOL] [args]\n"
+"The POOL argument is either a number, or a name from %s\n"
+, IPPOOL_CONF);
+ fprintf(stderr,
+"ippool [-n] [-l|-L POOL] [-u] [-v]\n"
+ "\tLists all (-l), or a single (-L) pool.\n"
+ "\tWith -u, summarized usage counts are listed.\n"
+ "\tWith -v, each pool membership is shown, one per line.\n"
+"ippool [-n] [-f|-F [POOL]]\n"
+ "\tflushes POOL (or all pools.)\n"
+"ippool [-n] [-x|-X [POOL]]\n"
+ "\tremoves POOL (or all pools.)\n"
+"ippool [-n] -B\n"
+ "\tcreates all fully specified pools found in the config file.\n"
+"ippool [-n] -N POOL [-t type] [FIRST LAST]\n"
+ "\tcreates POOL of IP addresses FIRST to LAST (inclusive). If a\n"
+ "\tpool name from the config file %s is used, type and\n"
+ "\taddress information can be defined there. The -t argument\n"
+ "\tgives the type (default bitmap).\n"
+"ippool [-n] -A POOL ADDR\n"
+ "\tadds ADDR to POOL\n"
+"ippool [-n] -D POOL ADDR\n"
+ "\tremoves ADDR from POOL\n"
+"ippool [-n] -C POOL ADDR\n"
+ "\ttests ADDR against membership in POOL\n"
+, IPPOOL_CONF);
+ exit(1);
+}
+
+/* config file parsing */
+
+#define IP_POOL_T_NONE 0
+#define IP_POOL_T_BITMAP 1
+
+static int conf_type = IP_POOL_T_NONE;
+static unsigned long conf_addr = 0;
+static unsigned long conf_addr2 = 0;
+
+#define SCAN_EOF (IP_POOL_NONE-1)
+
+static ip_pool_t get_index_line(
+ FILE *fp,
+ char **namep,
+ char **typep,
+ char **argp
+) {
+ char *p;
+ ip_pool_t index;
+ static char buf[256];
+
+ if (namep) *namep = 0;
+ if (typep) *typep = 0;
+ if (argp) *argp = 0;
+
+ if (!fgets(buf, sizeof(buf), fp)) return SCAN_EOF;
+
+ p = strtok(buf, " \t\n");
+ if (!p || *p == '#') return IP_POOL_NONE;
+ index = atoi(p);
+
+ p = strtok(0, " \t\n");
+ if (!p || *p == '#') return index;
+ if (namep) *namep = p;
+
+ p = strtok(0, " \t\n");
+ if (!p || *p == '#') return index;
+ if (typep) *typep = p;
+
+ p = strtok(0, "#\n");
+ if (argp) *argp = p;
+
+ return index;
+}
+
+static ip_pool_t get_index(char *name)
+{
+ FILE *fp;
+ char *poolname, *type, *arg, *p;
+ ip_pool_t res;
+
+ if (isdigit(*name))
+ return atoi(name);
+ fp = fopen(IPPOOL_CONF, "r");
+ if (!fp) {
+ fprintf(stderr, "cannot open %s - no pool names", IPPOOL_CONF);
+ exit(1);
+ }
+ while (SCAN_EOF != (res=get_index_line(fp, &poolname, &type, &arg))) {
+ if (poolname && 0 == strcmp(poolname, name)) {
+ if (!type || (0 == strcmp(type, "bitmap"))) {
+ conf_type = IP_POOL_T_BITMAP;
+ p = strtok(arg, " \t");
+ if (p) {
+ conf_addr = inet_addr(p);
+ p = strtok(0, " \t");
+ if (p)
+ conf_addr2 = inet_addr(p);
+ else
+ conf_addr = 0;
+ }
+ }
+ break;
+ }
+ }
+ fclose(fp);
+ if (res == SCAN_EOF) {
+ fprintf(stderr, "pool '%s' not found in %s\n",
+ name, IPPOOL_CONF);
+ exit(1);
+ }
+ return res;
+}
+
+static char *get_name(ip_pool_t index)
+{
+ FILE *fp;
+ static char sbuf[256];
+ int ok = 0;
+
+ fp = fopen(IPPOOL_CONF, "r");
+ if (fp) {
+ while (fgets(sbuf, sizeof(sbuf), fp)) {
+ char *p = strtok(sbuf, " \t\n");
+
+ if (!p || *p == '#') continue;
+ if (index != atoi(p)) continue;
+ p = strtok(0, " \t\n");
+ if (!p || *p == '#') continue;
+ memmove(sbuf, p, strlen(p)+1);
+ ok = 1;
+ break;
+ }
+ fclose(fp);
+ }
+ if (!ok) sprintf(sbuf, "%d", index);
+ return sbuf;
+}
+
+/* user/kernel interaction */
+
+static int fd = -1;
+static int flag_n = 0; /* do not do anything; just brag about it */
+static int flag_v = 0; /* be verbose (list members) */
+static int flag_q = 0; /* be quiet */
+static int flag_u = 0; /* show usage counts in listings */
+static char *flag_t = "bitmap"; /* pool type */
+
+static ip_pool_t high_nr(void)
+{
+ struct ip_pool_request req;
+ int reqlen = sizeof(req);
+
+ req.op = IP_POOL_HIGH_NR;
+ if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) {
+ fprintf(stderr,
+ "IP_POOL_HIGH_NR failed: %s\n",
+ errno2msg(IP_POOL_HIGH_NR, errno));
+ exit(1);
+ }
+ return req.index;
+}
+
+static void do_list(ip_pool_t pool)
+{
+ struct ip_pool_request req;
+ int reqlen = sizeof(req);
+ u_int32_t first_ip;
+ u_int32_t last_ip;
+
+ req.op = IP_POOL_LOOKUP;
+ req.index = pool;
+ req.addr = req.addr2 = 0;
+ reqlen = sizeof(req);
+ if (0 == getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) {
+ struct in_addr ina;
+ ina.s_addr = req.addr;
+ printf("%s %s", get_name(req.index), inet_ntoa(ina));
+ ina.s_addr = req.addr2;
+ printf(" %s", inet_ntoa(ina));
+ first_ip = ntohl(req.addr);
+ last_ip = ntohl(req.addr2);
+ if (flag_u) {
+ req.op = IP_POOL_USAGE;
+ req.index = pool;
+ reqlen = sizeof(req);
+ if (0 == getsockopt(fd, SOL_IP, SO_IP_POOL,
+ &req, &reqlen)) {
+ printf(" %d %d", req.addr, req.addr2);
+ } else {
+ printf(" - -");
+ }
+ }
+ printf("\n");
+ if (flag_v) {
+ while (first_ip <= last_ip) {
+ req.op = IP_POOL_TEST_ADDR;
+ req.index = pool;
+ ina.s_addr = req.addr = htonl(first_ip);
+ reqlen = sizeof(req);
+ if (0 == getsockopt(fd, SOL_IP, SO_IP_POOL,
+ &req, &reqlen)) {
+ if (req.addr) printf("\t%s\n",
+ inet_ntoa(ina));
+ }
+ first_ip++;
+ }
+ }
+ }
+}
+
+static void do_list_all(void)
+{
+ ip_pool_t i, highest = high_nr();
+
+ for (i=0; i<=highest; i++)
+ do_list(i);
+}
+
+static void do_flush(ip_pool_t pool)
+{
+ struct ip_pool_request req;
+ int reqlen = sizeof(req);
+
+ req.op = IP_POOL_FLUSH;
+ req.index = pool;
+ if (flag_n) {
+ printf("ippool -F %d\n", req.index);
+ return;
+ }
+ if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) {
+ int err = errno;
+ fprintf(stderr,
+ "IP_POOL_FLUSH %s failed: %s\n",
+ get_name(pool), errno2msg(IP_POOL_FLUSH, err));
+ exit(1);
+ }
+}
+
+static void do_flush_all(void)
+{
+ ip_pool_t i, highest = high_nr();
+
+ for (i=0; i<=highest; i++)
+ do_flush(i);
+}
+
+static void do_destroy(ip_pool_t pool)
+{
+ struct ip_pool_request req;
+ int reqlen = sizeof(req);
+
+ req.op = IP_POOL_DESTROY;
+ req.index = pool;
+ if (flag_n) {
+ printf("ippool -X %d\n", req.index);
+ return;
+ }
+ if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) {
+ int err = errno;
+ fprintf(stderr,
+ "IP_POOL_DESTROY %s failed: %s\n",
+ get_name(pool), errno2msg(IP_POOL_DESTROY, err));
+ exit(1);
+ }
+}
+
+static void do_destroy_all(void)
+{
+ ip_pool_t i, highest = high_nr();
+
+ for (i=0; i<=highest; i++)
+ do_destroy(i);
+}
+
+static int do_adddel(ip_pool_t pool, char *straddr, int op)
+{
+ struct ip_pool_request req;
+ int res;
+ int reqlen = sizeof(req);
+
+ req.op = op;
+ req.index = pool;
+ req.addr = inet_addr(straddr);
+ req.addr2 = 0;
+ if (flag_n) {
+ printf("ippool -%c %s %s\n",
+ (op == IP_POOL_ADD_ADDR) ? 'A' : 'D',
+ get_name(req.index), straddr);
+ return 0;
+ }
+ res = getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen);
+ if (0 > res) {
+ int err = errno;
+ fprintf(stderr,
+ "IP_POOL_ADD/DEL %s in %s failed: %s\n",
+ straddr, get_name(pool), errno2msg(op, err));
+ exit(1);
+ }
+ if (!flag_q)
+ printf("%s %s %d %d\n", get_name(pool), straddr, req.addr,
+ op == IP_POOL_ADD_ADDR ? 1 : 0);
+ return req.addr;
+}
+
+static int do_check(ip_pool_t pool, char *straddr)
+{
+ struct ip_pool_request req;
+ int reqlen = sizeof(req);
+
+ req.op = IP_POOL_TEST_ADDR;
+ req.index = pool;
+ req.addr = inet_addr(straddr);
+ if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) {
+ int err = errno;
+ fprintf(stderr,
+ "IP_POOL_TEST_ADDR %s in %s failed: %s\n",
+ straddr, get_name(pool),
+ errno2msg(IP_POOL_TEST_ADDR, err));
+ exit(1);
+ }
+ if (!flag_q)
+ printf("%s %s %d\n", get_name(req.index), straddr, req.addr);
+ return !req.addr;
+}
+
+static void do_new(ip_pool_t pool, int argc, char **argv)
+{
+ struct ip_pool_request req;
+ int reqlen = sizeof(req);
+
+ req.op = IP_POOL_INIT;
+ req.index = pool;
+ if (argc >= 2) {
+ conf_type = IP_POOL_T_BITMAP;
+ conf_addr = inet_addr(argv[0]);
+ conf_addr2 = inet_addr(argv[1]);
+ }
+ if (conf_type != IP_POOL_T_BITMAP || conf_addr == 0 || conf_addr2 == 0)
+ usage("bad pool specification");
+ req.addr = conf_addr;
+ req.addr2 = conf_addr2;
+ if (flag_n) {
+ printf("ippool -N %s [-T %s] ...\n", get_name(pool),
+ conf_type == IP_POOL_T_BITMAP
+ ? "bitmap"
+ : "???");
+ return;
+ }
+ if (0 > getsockopt(fd, SOL_IP, SO_IP_POOL, &req, &reqlen)) {
+ struct in_addr ina;
+ int err = errno;
+ ina.s_addr = conf_addr;
+ fprintf(stderr,
+ "IP_POOL_INIT %s [%s-",
+ get_name(pool), inet_ntoa(ina));
+ ina.s_addr = conf_addr2;
+ fprintf(stderr,
+ "%s] failed: %s\n",
+ inet_ntoa(ina), errno2msg(IP_POOL_INIT, err));
+ exit(1);
+ }
+}
+
+static void do_new_all(void)
+{
+ FILE *fp;
+ char *poolname, *type, *arg, *p;
+ int res;
+
+ fp = fopen(IPPOOL_CONF, "r");
+ if (!fp) {
+ fprintf(stderr, "cannot open %s - no pool names", IPPOOL_CONF);
+ exit(1);
+ }
+ while (SCAN_EOF != (res=get_index_line(fp, &poolname, &type, &arg))) {
+ if (poolname && type && (0 == strcmp(type, "bitmap"))) {
+ conf_type = IP_POOL_T_BITMAP;
+ p = strtok(arg, " \t");
+ if (p) {
+ conf_addr = inet_addr(p);
+ p = strtok(0, " \t");
+ if (p)
+ conf_addr2 = inet_addr(p);
+ else
+ conf_addr = 0;
+ }
+ if (conf_addr != 0) {
+ if (flag_v)
+ printf("ippool -N %s (%s) [%s]\n",
+ poolname, type, arg);
+ do_new(res, 0, 0);
+ }
+ }
+ }
+ fclose(fp);
+}
+
+int main(int argc, char **argv)
+{
+ int opt;
+ int op;
+#define OP_NONE 0
+#define OP_LIST 1
+#define OP_LIST_ALL 2
+#define OP_FLUSH 3
+#define OP_FLUSH_ALL 4
+#define OP_DESTROY 5
+#define OP_DESTROY_ALL 6
+#define OP_ADD 7
+#define OP_DEL 8
+#define OP_CHECK 9
+#define OP_NEW 10
+#define OP_NEW_ALL 11
+#define OP_HIGHEST 12
+ char *op_pool;
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ fprintf(stderr, "cannot get DGRAM socket: %s\n",
+ strerror(errno));
+ exit(1);
+ }
+ op_pool = 0;
+ op = OP_NONE;
+ /* GRRR. I thought getopt() would allow an "L*" specifier, for an -L
+ * taking an optional argument. Does not work. Bad.
+ * Adding -l for -L without argument, also -f/-F and -x/-X.
+ */
+ while (EOF != (opt=getopt( argc, argv, "HhnvuqA:D:C:N:t:L:F:X:lfxB")))
+ switch(opt) {
+ case 'l':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_LIST_ALL;
+ break;
+ case 'L':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_LIST;
+ op_pool = optarg;
+ break;
+ case 'f':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_FLUSH_ALL;
+ break;
+ case 'F':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_FLUSH;
+ op_pool = optarg;
+ break;
+ case 'x':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_DESTROY_ALL;
+ break;
+ case 'X':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_DESTROY;
+ op_pool = optarg;
+ break;
+ case 'A':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_ADD;
+ op_pool = optarg;
+ break;
+ case 'D':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_DEL;
+ op_pool = optarg;
+ break;
+ case 'C':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_CHECK;
+ op_pool = optarg;
+ break;
+ case 'B':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_NEW_ALL;
+ break;
+ case 'N':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_NEW;
+ op_pool = optarg;
+ break;
+ case 'H':
+ if (op != OP_NONE) usage("conflicting operations");
+ op = OP_HIGHEST;
+ break;
+ case 't':
+ flag_t = optarg;
+ break;
+ case 'n':
+ flag_n = 1;
+ break;
+ case 'v':
+ flag_v = 1;
+ break;
+ case 'u':
+ flag_u = 1;
+ break;
+ case 'q':
+ flag_q = 1;
+ break;
+ case 'h':
+ usage(0);
+ default:
+ usage("bad option");
+ }
+ if (op == OP_NONE)
+ usage("no operation specified");
+ if (op == OP_LIST_ALL) {
+ do_list_all();
+ return 0;
+ }
+ if (op == OP_LIST) {
+ do_list(get_index(op_pool));
+ return 0;
+ }
+ if (op == OP_FLUSH_ALL) {
+ do_flush_all();
+ return 0;
+ }
+ if (op == OP_FLUSH) {
+ do_flush(get_index(op_pool));
+ return 0;
+ }
+ if (op == OP_DESTROY_ALL) {
+ do_destroy_all();
+ return 0;
+ }
+ if (op == OP_DESTROY) {
+ do_destroy(get_index(op_pool));
+ return 0;
+ }
+ if (op == OP_CHECK) {
+ if (optind >= argc)
+ usage("missing address to check");
+ return do_check(get_index(op_pool), argv[optind]);
+ }
+ if (op == OP_NEW_ALL) {
+ do_new_all();
+ return 0;
+ }
+ if (op == OP_NEW) {
+ do_new(get_index(op_pool), argc-optind, argv+optind);
+ return 0;
+ }
+ if (op == OP_ADD) {
+ if (optind >= argc)
+ usage("missing address to add");
+ return do_adddel(get_index(op_pool),
+ argv[optind], IP_POOL_ADD_ADDR);
+ }
+ if (op == OP_DEL) {
+ if (optind >= argc)
+ usage("missing address to delete");
+ return do_adddel(get_index(op_pool),
+ argv[optind], IP_POOL_DEL_ADDR);
+ }
+ if (op == OP_HIGHEST) {
+ printf("%d\n", high_nr());
+ return 0;
+ }
+ usage("no operation specified");
+ return 0;
+}
diff --git a/ippool/libippool.c b/ippool/libippool.c
new file mode 100644
index 00000000..7f3ac760
--- /dev/null
+++ b/ippool/libippool.c
@@ -0,0 +1,72 @@
+/* support functions for ip_pool modules */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <libippool/ip_pool_support.h>
+
+void ip_pool_init(void)
+{
+}
+
+ip_pool_t ip_pool_get_index(char *name)
+{
+ FILE *fp;
+ char buf[256];
+
+ if (isdigit(*name))
+ return atoi(name);
+ fp = fopen(IPPOOL_CONF, "r");
+ if (!fp) exit_error(PARAMETER_PROBLEM,
+ "cannot open %s - no pool names", IPPOOL_CONF);
+ while (fgets(buf, sizeof(buf), fp)) {
+ char *p = strtok(buf, " \t\n");
+ ip_pool_t index;
+
+ if (!p || *p == '#') continue;
+ index = atoi(p);
+ p = strtok(0, " \t\n");
+ if (p && 0 == strcmp(p, name)) {
+ fclose(fp);
+ return index;
+ }
+ }
+ exit_error(PARAMETER_PROBLEM,
+ "pool '%s' not found in %s\n", name, IPPOOL_CONF);
+}
+
+char *ip_pool_get_name(char *buf, int size, ip_pool_t index, int numeric)
+{
+ FILE *fp;
+ int ok = 0;
+
+ /* make sure we have enough room, at least for a %d */
+ if (size < 16)
+ exit_error(PARAMETER_PROBLEM,
+ "ip_pool_support:get_name buf too small (%d vs. 16)\n",
+ size);
+ if (numeric)
+ goto do_numeric;
+ fp = fopen(IPPOOL_CONF, "r");
+ if (fp) {
+ while (fgets(buf, size, fp)) {
+ char *p = strtok(buf, " \t\n");
+
+ if (!p || *p == '#') continue;
+ if (index != atoi(p)) continue;
+ p = strtok(0, " \t\n");
+ if (!p || *p == '#') continue;
+ memmove(buf, p, strlen(p)+1);
+ ok = 1;
+ break;
+ }
+ fclose(fp);
+ }
+ if (!ok) {
+do_numeric:
+ sprintf(buf, "%d", index);
+ }
+ return buf;
+}
diff --git a/iptables.8 b/iptables.8
index 7bf8e2dc..0d60aeea 100644
--- a/iptables.8
+++ b/iptables.8
@@ -681,6 +681,24 @@ 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.
+.SS ULOG
+Turn on userspace logging of matching packets. When this
+option is set for a rule, the Linux kernel will multicast this
+packet through a
+.IR netlink
+socket. One or more userspace processes may then subscribe to variuos
+multicast groups and receive the packets.
+.TP
+.BI "--ulog-nlgroup" "<nlgroup>"
+This specifies the netlink group (1-32) to which the packet is sent.
+.TP
+.BI "--ulog-prefix" "<prefix>"
+Prefix log messages with the specified prefix; up to 32 characters
+long, and useful fro distinguishing messages in the logs.
+.TP
+.BI "--ulog-cprange" "<size>"
+Number of bytes to be copied to userspace. A value of 0 does always copy
+the entire packet, regardless of its size.
.SH BUGS
Check is not implemented (yet).
.SH COMPATIBILITY WITH IPCHAINS
@@ -734,6 +752,8 @@ James Morris wrote the TOS target, and tos match.
.PP
Jozsef Kadlecsik wrote the REJECT target.
.PP
+Harald Welte wrote the ULOG target and libulog.
+.PP
The Netfilter Core Team is: Marc Boucher, James Morris and Rusty Russell.
.\" .. and did I mention that we are incredibly cool people?
.\" .. sexy, too ..