diff options
author | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 21:56:24 +0900 |
---|---|---|
committer | jk7744.park <jk7744.park@samsung.com> | 2015-09-08 21:56:24 +0900 |
commit | 427e21006a01f98c92434008442bba504c9d2e6c (patch) | |
tree | 8d3cdcc6e535016586023d74b9816ef339ddb31f /extensions | |
parent | f5589e19420a83ca978348cbcfbc4c83b310bd3b (diff) | |
download | iptables-tizen_2.3.1.tar.gz iptables-tizen_2.3.1.tar.bz2 iptables-tizen_2.3.1.zip |
tizen 2.3.1 releasetizen_2.3.1_releasesubmit/tizen_2.3.1/20150915.074541tizen_2.3.1
Diffstat (limited to 'extensions')
173 files changed, 10687 insertions, 9063 deletions
diff --git a/extensions/.gitignore b/extensions/.gitignore new file mode 100644 index 0000000..b1260f0 --- /dev/null +++ b/extensions/.gitignore @@ -0,0 +1,9 @@ +.*.d +.*.dd +*.oo + +/GNUmakefile +/initext.c +/initext?.c +/matches.man +/targets.man diff --git a/extensions/GNUmakefile.in b/extensions/GNUmakefile.in index 709366a..c5d8844 100644 --- a/extensions/GNUmakefile.in +++ b/extensions/GNUmakefile.in @@ -1,25 +1,29 @@ # -*- Makefile -*- -top_builddir := @top_builddir@ -builddir := @builddir@ -top_srcdir := @top_srcdir@ -srcdir := @srcdir@ -ksourcedir := @ksourcedir@ -prefix := @prefix@ -exec_prefix := @exec_prefix@ -libdir := @libdir@ -libexecdir := @libexecdir@ -xtlibdir := @xtlibdir@ - -CC := @CC@ -CCLD := ${CC} -CFLAGS := @CFLAGS@ -LDFLAGS := @LDFLAGS@ -regular_CFLAGS := @regular_CFLAGS@ -kinclude_CFLAGS := @kinclude_CFLAGS@ - -AM_CFLAGS := ${regular_CFLAGS} -I${top_builddir}/include -I${top_srcdir}/include ${kinclude_CFLAGS} +top_builddir = @top_builddir@ +builddir = @builddir@ +top_srcdir = @top_srcdir@ +srcdir = @srcdir@ +ksourcedir = @ksourcedir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +xtlibdir = @xtlibdir@ + +CC = @CC@ +CCLD = ${CC} +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +regular_CFLAGS = @regular_CFLAGS@ +regular_CPPFLAGS = @regular_CPPFLAGS@ +kinclude_CPPFLAGS = @kinclude_CPPFLAGS@ + +AM_CFLAGS = ${regular_CFLAGS} +AM_CPPFLAGS = ${regular_CPPFLAGS} -I${top_builddir}/include -I${top_builddir} -I${top_srcdir}/include ${kinclude_CPPFLAGS} ${CPPFLAGS} AM_DEPFLAGS = -Wp,-MMD,$(@D)/.$(@F).d,-MT,$@ +AM_LDFLAGS = @noundef_LDFLAGS@ ifeq (${V},) AM_LIBTOOL_SILENT = --silent @@ -34,16 +38,17 @@ endif # # Wildcard module list # -pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(wildcard ${srcdir}/libxt_*.c)) -@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(wildcard ${srcdir}/libipt_*.c)) -@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(wildcard ${srcdir}/libip6t_*.c)) +pfx_build_mod := $(patsubst ${srcdir}/libxt_%.c,%,$(sort $(wildcard ${srcdir}/libxt_*.c))) +pfx_symlinks := NOTRACK state +@ENABLE_IPV4_TRUE@ pf4_build_mod := $(patsubst ${srcdir}/libipt_%.c,%,$(sort $(wildcard ${srcdir}/libipt_*.c))) +@ENABLE_IPV6_TRUE@ pf6_build_mod := $(patsubst ${srcdir}/libip6t_%.c,%,$(sort $(wildcard ${srcdir}/libip6t_*.c))) pfx_build_mod := $(filter-out @blacklist_modules@,${pfx_build_mod}) pf4_build_mod := $(filter-out @blacklist_modules@,${pf4_build_mod}) pf6_build_mod := $(filter-out @blacklist_modules@,${pf6_build_mod}) pfx_objs := $(patsubst %,libxt_%.o,${pfx_build_mod}) pf4_objs := $(patsubst %,libipt_%.o,${pf4_build_mod}) pf6_objs := $(patsubst %,libip6t_%.o,${pf6_build_mod}) -pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod}) +pfx_solibs := $(patsubst %,libxt_%.so,${pfx_build_mod} ${pfx_symlinks}) pf4_solibs := $(patsubst %,libipt_%.so,${pf4_build_mod}) pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod}) @@ -51,11 +56,11 @@ pf6_solibs := $(patsubst %,libip6t_%.so,${pf6_build_mod}) # # Building blocks # -targets := libext4.a libext6.a matches4.man matches6.man \ - targets4.man targets6.man +targets := libext.a libext4.a libext6.a matches.man targets.man targets_install := -@ENABLE_STATIC_TRUE@ libext4_objs := ${pfx_objs} ${pf4_objs} -@ENABLE_STATIC_TRUE@ libext6_objs := ${pfx_objs} ${pf6_objs} +@ENABLE_STATIC_TRUE@ libext_objs := ${pfx_objs} +@ENABLE_STATIC_TRUE@ libext4_objs := ${pf4_objs} +@ENABLE_STATIC_TRUE@ libext6_objs := ${pf6_objs} @ENABLE_STATIC_FALSE@ targets += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs} @ENABLE_STATIC_FALSE@ targets_install += ${pfx_solibs} ${pf4_solibs} ${pf6_solibs} @@ -70,13 +75,13 @@ install: ${targets_install} if test -n "${targets_install}"; then install -pm0755 $^ "${DESTDIR}${xtlibdir}/"; fi; clean: - rm -f *.o *.oo *.so *.a {matches,targets}[46].man initext4.c initext6.c; + rm -f *.o *.oo *.so *.a {matches,targets}.man initext.c initext4.c initext6.c; + rm -f .*.d .*.dd; distclean: clean - rm -f .*.d .*.dd; init%.o: init%.c - ${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init ${CFLAGS} -o $@ -c $<; + ${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=$*_init ${CFLAGS} -o $@ -c $<; -include .*.d @@ -85,11 +90,22 @@ init%.o: init%.c # Shared libraries # lib%.so: lib%.oo - ${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $<; + ${AM_VERBOSE_CCLD} ${CCLD} ${AM_LDFLAGS} -shared ${LDFLAGS} -o $@ $< -L../libxtables/.libs -lxtables ${$*_LIBADD}; lib%.oo: ${srcdir}/lib%.c - ${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} -o $@ -c $<; + ${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -D_INIT=lib$*_init -DPIC -fPIC ${CFLAGS} ${$*_CFLAGADD} -o $@ -c $<; + +libxt_NOTRACK.so: libxt_CT.so + ln -fs $< $@ +libxt_state.so: libxt_conntrack.so + ln -fs $< $@ +# Need the LIBADDs in iptables/Makefile.am too for libxtables_la_LIBADD +xt_RATEEST_LIBADD = -lm +xt_statistic_LIBADD = -lm +@HAVE_LIBNETFILTER_CONNTRACK_TRUE@xt_connlabel_LIBADD = @libnetfilter_conntrack_LIBS@ + +@HAVE_LIBNETFILTER_CONNTRACK_TRUE@xt_connlabel_CFLAGADD = @libnetfilter_conntrack_CFLAGS@ # # Static bits @@ -99,7 +115,10 @@ lib%.oo: ${srcdir}/lib%.c # handling code in the Makefiles. # lib%.o: ${srcdir}/lib%.c - ${AM_VERBOSE_CC} ${CC} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<; + ${AM_VERBOSE_CC} ${CC} ${AM_CPPFLAGS} ${AM_DEPFLAGS} ${AM_CFLAGS} -DNO_SHARED_LIBS=1 -D_INIT=lib$*_init ${CFLAGS} -o $@ -c $<; + +libext.a: initext.o ${libext_objs} + ${AM_VERBOSE_AR} ${AR} crs $@ $^; libext4.a: initext4.o ${libext4_objs} ${AM_VERBOSE_AR} ${AR} crs $@ $^; @@ -107,20 +126,26 @@ libext4.a: initext4.o ${libext4_objs} libext6.a: initext6.o ${libext6_objs} ${AM_VERBOSE_AR} ${AR} crs $@ $^; -initext_func := $(addprefix xt_,${pfx_build_mod}) $(addprefix ipt_,${pf4_build_mod}) -initext6_func := $(addprefix xt_,${pfx_build_mod}) $(addprefix ip6t_,${pf6_build_mod}) +initext_func := $(addprefix xt_,${pfx_build_mod}) +initext4_func := $(addprefix ipt_,${pf4_build_mod}) +initext6_func := $(addprefix ip6t_,${pf6_build_mod}) -.initext4.dd: FORCE +.initext.dd: FORCE @echo "${initext_func}" >$@.tmp; \ cmp -s $@ $@.tmp || mv $@.tmp $@; \ rm -f $@.tmp; +.initext4.dd: FORCE + @echo "${initext4_func}" >$@.tmp; \ + cmp -s $@ $@.tmp || mv $@.tmp $@; \ + rm -f $@.tmp; + .initext6.dd: FORCE @echo "${initext6_func}" >$@.tmp; \ cmp -s $@ $@.tmp || mv $@.tmp $@; \ rm -f $@.tmp; -initext4.c: .initext4.dd +initext.c: .initext.dd ${AM_VERBOSE_GEN} @( \ echo "" >$@; \ @@ -136,6 +161,22 @@ initext4.c: .initext4.dd echo "}" >>$@; \ ); +initext4.c: .initext4.dd + ${AM_VERBOSE_GEN} + @( \ + echo "" >$@; \ + for i in ${initext4_func}; do \ + echo "extern void lib$${i}_init(void);" >>$@; \ + done; \ + echo "void init_extensions4(void);" >>$@; \ + echo "void init_extensions4(void)" >>$@; \ + echo "{" >>$@; \ + for i in ${initext4_func}; do \ + echo " ""lib$${i}_init();" >>$@; \ + done; \ + echo "}" >>$@; \ + ); + initext6.c: .initext6.dd ${AM_VERBOSE_GEN} @( \ @@ -143,8 +184,8 @@ initext6.c: .initext6.dd for i in ${initext6_func}; do \ echo "extern void lib$${i}_init(void);" >>$@; \ done; \ - echo "void init_extensions(void);" >>$@; \ - echo "void init_extensions(void)" >>$@; \ + echo "void init_extensions6(void);" >>$@; \ + echo "void init_extensions6(void)" >>$@; \ echo "{" >>$@; \ for i in ${initext6_func}; do \ echo " ""lib$${i}_init();" >>$@; \ @@ -155,36 +196,33 @@ initext6.c: .initext6.dd # # Manual pages # -ex_matches = $(sort $(shell echo $(1) | grep -Eo '\b[a-z0-9]+\b')) -ex_targets = $(sort $(shell echo $(1) | grep -Eo '\b[A-Z0-9]+\b')) +ex_matches = $(shell echo ${1} | LC_ALL=POSIX grep -Eo '\b[[:lower:][:digit:]_]+\b') +ex_targets = $(shell echo ${1} | LC_ALL=POSIX grep -Eo '\b[[:upper:][:digit:]_]+\b') man_run = \ ${AM_VERBOSE_GEN} \ - for ext in $(1); do \ + for ext in $(sort ${1}); do \ f="${srcdir}/libxt_$$ext.man"; \ - cf="${srcdir}/libxt_$$ext.c"; \ - if [ -f "$$f" ] && grep -Eq "$(3)|NFPROTO_UNSPEC" "$$cf"; then \ + if [ -f "$$f" ]; then \ echo -e "\t+ $$f" >&2; \ echo ".SS $$ext"; \ - cat "$$f"; \ - continue; \ + cat "$$f" || exit $$?; \ fi; \ - f="${srcdir}/lib$(2)t_$$ext.man"; \ + f="${srcdir}/libip6t_$$ext.man"; \ if [ -f "$$f" ]; then \ echo -e "\t+ $$f" >&2; \ - echo ".SS $$ext"; \ - cat "$$f"; \ - continue; \ + echo ".SS $$ext (IPv6-specific)"; \ + cat "$$f" || exit $$?; \ + fi; \ + f="${srcdir}/libipt_$$ext.man"; \ + if [ -f "$$f" ]; then \ + echo -e "\t+ $$f" >&2; \ + echo ".SS $$ext (IPv4-specific)"; \ + cat "$$f" || exit $$?; \ fi; \ done >$@; -matches4.man: .initext4.dd $(wildcard ${srcdir}/lib*.man) - $(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod}),ip,NFPROTO_IPV4) - -matches6.man: .initext6.dd $(wildcard ${srcdir}/lib*.man) - $(call man_run,$(call ex_matches,${pfx_build_mod} ${pf6_build_mod}),ip6,NFPROTO_IPV6) - -targets4.man: .initext4.dd $(wildcard ${srcdir}/lib*.man) - $(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod}),ip,NFPROTO_IPV4) +matches.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) + $(call man_run,$(call ex_matches,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) -targets6.man: .initext6.dd $(wildcard ${srcdir}/lib*.man) - $(call man_run,$(call ex_targets,${pfx_build_mod} ${pf6_build_mod}),ip6,NFPROTO_IPV6) +targets.man: .initext.dd .initext4.dd .initext6.dd $(wildcard ${srcdir}/lib*.man) + $(call man_run,$(call ex_targets,${pfx_build_mod} ${pf4_build_mod} ${pf6_build_mod} ${pfx_symlinks})) diff --git a/extensions/libip6t_DNAT.c b/extensions/libip6t_DNAT.c new file mode 100644 index 0000000..eaa6bf1 --- /dev/null +++ b/extensions/libip6t_DNAT.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> + * + * Based on Rusty Russell's IPv4 DNAT target. Development of IPv6 NAT + * funded by Astaro. + */ + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <xtables.h> +#include <iptables.h> +#include <limits.h> /* INT_MAX in ip_tables.h */ +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter/nf_nat.h> + +enum { + O_TO_DEST = 0, + O_RANDOM, + O_PERSISTENT, + O_X_TO_DEST, + F_TO_DEST = 1 << O_TO_DEST, + F_RANDOM = 1 << O_RANDOM, + F_X_TO_DEST = 1 << O_X_TO_DEST, +}; + +static void DNAT_help(void) +{ + printf( +"DNAT target options:\n" +" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n" +" Address to map destination to.\n" +"[--random] [--persistent]\n"); +} + +static const struct xt_option_entry DNAT_opts[] = { + {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_MULTI}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +/* Ranges expected in network order. */ +static void +parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) +{ + char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; + const struct in6_addr *ip; + + arg = strdup(orig_arg); + if (arg == NULL) + xtables_error(RESOURCE_PROBLEM, "strdup"); + + start = strchr(arg, '['); + if (start == NULL) { + start = arg; + /* Lets assume one colon is port information. Otherwise its an IPv6 address */ + colon = strchr(arg, ':'); + if (colon && strchr(colon+1, ':')) + colon = NULL; + } + else { + start++; + end = strchr(start, ']'); + if (end == NULL) + xtables_error(PARAMETER_PROBLEM, + "Invalid address format"); + + *end = '\0'; + colon = strchr(end + 1, ':'); + } + + if (colon) { + int port; + + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + port = atoi(colon+1); + if (port <= 0 || port > 65535) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + error = strchr(colon+1, ':'); + if (error) + xtables_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash\n"); + + dash = strchr(colon, '-'); + if (!dash) { + range->min_proto.tcp.port + = range->max_proto.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport <= 0 || maxport > 65535) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. */ + xtables_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range->min_proto.tcp.port = htons(port); + range->max_proto.tcp.port = htons(maxport); + } + /* Starts with colon or [] colon? No IP info...*/ + if (colon == arg || colon == arg+2) { + free(arg); + return; + } + *colon = '\0'; + } + + range->flags |= NF_NAT_RANGE_MAP_IPS; + dash = strchr(start, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + ip = xtables_numeric_to_ip6addr(start); + if (!ip) + xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", + start); + range->min_addr.in6 = *ip; + if (dash) { + ip = xtables_numeric_to_ip6addr(dash + 1); + if (!ip) + xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", + dash+1); + range->max_addr.in6 = *ip; + } else + range->max_addr = range->min_addr; + + free(arg); + return; +} + +static void DNAT_parse(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + struct nf_nat_range *range = cb->data; + int portok; + + if (entry->ipv6.proto == IPPROTO_TCP || + entry->ipv6.proto == IPPROTO_UDP || + entry->ipv6.proto == IPPROTO_SCTP || + entry->ipv6.proto == IPPROTO_DCCP || + entry->ipv6.proto == IPPROTO_ICMP) + portok = 1; + else + portok = 0; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_DEST: + if (cb->xflags & F_X_TO_DEST) { + if (!kernel_version) + get_kernel_version(); + if (kernel_version > LINUX_VERSION(2, 6, 10)) + xtables_error(PARAMETER_PROBLEM, + "DNAT: Multiple --to-destination not supported"); + } + parse_to(cb->arg, portok, range); + break; + case O_PERSISTENT: + range->flags |= NF_NAT_RANGE_PERSISTENT; + break; + } +} + +static void DNAT_fcheck(struct xt_fcheck_call *cb) +{ + static const unsigned int f = F_TO_DEST | F_RANDOM; + struct nf_nat_range *mr = cb->data; + + if ((cb->xflags & f) == f) + mr->flags |= NF_NAT_RANGE_PROTO_RANDOM; +} + +static void print_range(const struct nf_nat_range *range) +{ + if (range->flags & NF_NAT_RANGE_MAP_IPS) { + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) + printf("["); + printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6)); + if (memcmp(&range->min_addr, &range->max_addr, + sizeof(range->min_addr))) + printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6)); + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) + printf("]"); + } + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(":"); + printf("%hu", ntohs(range->min_proto.tcp.port)); + if (range->max_proto.tcp.port != range->min_proto.tcp.port) + printf("-%hu", ntohs(range->max_proto.tcp.port)); + } +} + +static void DNAT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct nf_nat_range *range = (const void *)target->data; + + printf(" to:"); + print_range(range); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); + if (range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" persistent"); +} + +static void DNAT_save(const void *ip, const struct xt_entry_target *target) +{ + const struct nf_nat_range *range = (const void *)target->data; + + printf(" --to-destination "); + print_range(range); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); + if (range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" --persistent"); +} + +static struct xtables_target snat_tg_reg = { + .name = "DNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 1, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = DNAT_help, + .x6_parse = DNAT_parse, + .x6_fcheck = DNAT_fcheck, + .print = DNAT_print, + .save = DNAT_save, + .x6_options = DNAT_opts, +}; + +void _init(void) +{ + xtables_register_target(&snat_tg_reg); +} diff --git a/extensions/libip6t_DNPT.c b/extensions/libip6t_DNPT.c new file mode 100644 index 0000000..a442de6 --- /dev/null +++ b/extensions/libip6t_DNPT.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012-2013 Patrick McHardy <kaber@trash.net> + */ + +#include <stdio.h> +#include <string.h> +#include <xtables.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter_ipv6/ip6t_NPT.h> + +enum { + O_SRC_PFX = 1 << 0, + O_DST_PFX = 1 << 1, +}; + +static const struct xt_option_entry DNPT_options[] = { + { .name = "src-pfx", .id = O_SRC_PFX, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MAND }, + { .name = "dst-pfx", .id = O_DST_PFX, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MAND }, + { } +}; + +static void DNPT_help(void) +{ + printf("DNPT target options:" + "\n" + " --src-pfx prefix/length\n" + " --dst-pfx prefix/length\n" + "\n"); +} + +static void DNPT_parse(struct xt_option_call *cb) +{ + struct ip6t_npt_tginfo *npt = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRC_PFX: + npt->src_pfx = cb->val.haddr; + npt->src_pfx_len = cb->val.hlen; + break; + case O_DST_PFX: + npt->dst_pfx = cb->val.haddr; + npt->dst_pfx_len = cb->val.hlen; + break; + } +} + +static void DNPT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct ip6t_npt_tginfo *npt = (const void *)target->data; + + printf("src-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->src_pfx.in6), + npt->src_pfx_len); + printf("dst-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6), + npt->dst_pfx_len); +} + +static void DNPT_save(const void *ip, const struct xt_entry_target *target) +{ + static const struct in6_addr zero_addr; + const struct ip6t_npt_tginfo *info = (const void *)target->data; + + if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 || + info->src_pfx_len != 0) + printf("--src-pfx %s/%u ", + xtables_ip6addr_to_numeric(&info->src_pfx.in6), + info->src_pfx_len); + if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 || + info->dst_pfx_len != 0) + printf("--dst-pfx %s/%u ", + xtables_ip6addr_to_numeric(&info->dst_pfx.in6), + info->dst_pfx_len); +} + +static struct xtables_target snpt_tg_reg = { + .name = "DNPT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct ip6t_npt_tginfo)), + .userspacesize = offsetof(struct ip6t_npt_tginfo, adjustment), + .help = DNPT_help, + .x6_parse = DNPT_parse, + .print = DNPT_print, + .save = DNPT_save, + .x6_options = DNPT_options, +}; + +void _init(void) +{ + xtables_register_target(&snpt_tg_reg); +} diff --git a/extensions/libip6t_DNPT.man b/extensions/libip6t_DNPT.man new file mode 100644 index 0000000..61beeee --- /dev/null +++ b/extensions/libip6t_DNPT.man @@ -0,0 +1,30 @@ +Provides stateless destination IPv6-to-IPv6 Network Prefix Translation (as +described by RFC 6296). +.PP +You have to use this target in the +.B mangle +table, not in the +.B nat +table. It takes the following options: +.TP +\fB\-\-src\-pfx\fP [\fIprefix/\fP\fIlength] +Set source prefix that you want to translate and length +.TP +\fB\-\-dst\-pfx\fP [\fIprefix/\fP\fIlength] +Set destination prefix that you want to use in the translation and length +.PP +You have to use the SNPT target to undo the translation. Example: +.IP +ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 \! \-o vboxnet0 +\-j SNPT \-\-src-pfx fd00::/64 \-\-dst-pfx 2001:e20:2000:40f::/64 +.IP +ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64 +\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst-pfx fd00::/64 +.PP +You may need to enable IPv6 neighbor proxy: +.IP +sysctl -w net.ipv6.conf.all.proxy_ndp=1 +.PP +You also have to use the +.B NOTRACK +target to disable connection tracking for translated flows. diff --git a/extensions/libip6t_HL.c b/extensions/libip6t_HL.c index bff0611..52ca5d3 100644 --- a/extensions/libip6t_HL.c +++ b/extensions/libip6t_HL.c @@ -4,16 +4,33 @@ * Based on HW's ttl target * This program is distributed under the terms of GNU GPL */ - -#include <getopt.h> #include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <xtables.h> - #include <linux/netfilter_ipv6/ip6t_HL.h> -#define IP6T_HL_USED 1 +enum { + O_HL_SET = 0, + O_HL_INC, + O_HL_DEC, + F_HL_SET = 1 << O_HL_SET, + F_HL_INC = 1 << O_HL_INC, + F_HL_DEC = 1 << O_HL_DEC, + F_ANY = F_HL_SET | F_HL_INC | F_HL_DEC, +}; + +#define s struct ip6t_HL_info +static const struct xt_option_entry HL_opts[] = { + {.name = "hl-set", .type = XTTYPE_UINT8, .id = O_HL_SET, + .excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)}, + {.name = "hl-dec", .type = XTTYPE_UINT8, .id = O_HL_DEC, + .excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit), + .min = 1}, + {.name = "hl-inc", .type = XTTYPE_UINT8, .id = O_HL_INC, + .excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit), + .min = 1}, + XTOPT_TABLEEND, +}; +#undef s static void HL_help(void) { @@ -24,67 +41,27 @@ static void HL_help(void) " --hl-inc value Increment HL by <value 1-255>\n"); } -static int HL_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void HL_parse(struct xt_option_call *cb) { - struct ip6t_HL_info *info = (struct ip6t_HL_info *) (*target)->data; - unsigned int value; - - if (*flags & IP6T_HL_USED) { - xtables_error(PARAMETER_PROBLEM, - "Can't specify HL option twice"); + struct ip6t_HL_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_HL_SET: + info->mode = IP6T_HL_SET; + break; + case O_HL_INC: + info->mode = IP6T_HL_INC; + break; + case O_HL_DEC: + info->mode = IP6T_HL_DEC; + break; } - - if (!optarg) - xtables_error(PARAMETER_PROBLEM, - "HL: You must specify a value"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "HL: unexpected `!'"); - - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "HL: Expected value between 0 and 255"); - - switch (c) { - - case '1': - info->mode = IP6T_HL_SET; - break; - - case '2': - if (value == 0) { - xtables_error(PARAMETER_PROBLEM, - "HL: decreasing by 0?"); - } - - info->mode = IP6T_HL_DEC; - break; - - case '3': - if (value == 0) { - xtables_error(PARAMETER_PROBLEM, - "HL: increasing by 0?"); - } - - info->mode = IP6T_HL_INC; - break; - - default: - return 0; - - } - - info->hop_limit = value; - *flags |= IP6T_HL_USED; - - return 1; } -static void HL_check(unsigned int flags) +static void HL_check(struct xt_fcheck_call *cb) { - if (!(flags & IP6T_HL_USED)) + if (!(cb->xflags & F_ANY)) xtables_error(PARAMETER_PROBLEM, "HL: You must specify an action"); } @@ -96,17 +73,17 @@ static void HL_save(const void *ip, const struct xt_entry_target *target) switch (info->mode) { case IP6T_HL_SET: - printf("--hl-set "); + printf(" --hl-set"); break; case IP6T_HL_DEC: - printf("--hl-dec "); + printf(" --hl-dec"); break; case IP6T_HL_INC: - printf("--hl-inc "); + printf(" --hl-inc"); break; } - printf("%u ", info->hop_limit); + printf(" %u", info->hop_limit); } static void HL_print(const void *ip, const struct xt_entry_target *target, @@ -115,28 +92,21 @@ static void HL_print(const void *ip, const struct xt_entry_target *target, const struct ip6t_HL_info *info = (struct ip6t_HL_info *) target->data; - printf("HL "); + printf(" HL "); switch (info->mode) { case IP6T_HL_SET: - printf("set to "); + printf("set to"); break; case IP6T_HL_DEC: - printf("decrement by "); + printf("decrement by"); break; case IP6T_HL_INC: - printf("increment by "); + printf("increment by"); break; } - printf("%u ", info->hop_limit); + printf(" %u", info->hop_limit); } -static const struct option HL_opts[] = { - { "hl-set", 1, NULL, '1' }, - { "hl-dec", 1, NULL, '2' }, - { "hl-inc", 1, NULL, '3' }, - { .name = NULL } -}; - static struct xtables_target hl_tg6_reg = { .name = "HL", .version = XTABLES_VERSION, @@ -144,11 +114,11 @@ static struct xtables_target hl_tg6_reg = { .size = XT_ALIGN(sizeof(struct ip6t_HL_info)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_HL_info)), .help = HL_help, - .parse = HL_parse, - .final_check = HL_check, .print = HL_print, .save = HL_save, - .extra_opts = HL_opts, + .x6_parse = HL_parse, + .x6_fcheck = HL_check, + .x6_options = HL_opts, }; void _init(void) diff --git a/extensions/libip6t_LOG.c b/extensions/libip6t_LOG.c index 423d988..4639268 100644 --- a/extensions/libip6t_LOG.c +++ b/extensions/libip6t_LOG.c @@ -1,10 +1,6 @@ -/* Shared library add-on to ip6tables to add LOG support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> #include <syslog.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter_ipv6/ip6t_LOG.h> @@ -16,6 +12,16 @@ #define LOG_DEFAULT_LEVEL LOG_WARNING +enum { + O_LOG_LEVEL = 0, + O_LOG_PREFIX, + O_LOG_TCPSEQ, + O_LOG_TCPOPTS, + O_LOG_IPOPTS, + O_LOG_UID, + O_LOG_MAC, +}; + static void LOG_help(void) { printf( @@ -25,18 +31,24 @@ static void LOG_help(void) " --log-tcp-sequence Log TCP sequence numbers.\n" " --log-tcp-options Log TCP options.\n" " --log-ip-options Log IP options.\n" -" --log-uid Log UID owning the local socket.\n"); +" --log-uid Log UID owning the local socket.\n" +" --log-macdecode Decode MAC addresses and protocol.\n"); } -static const struct option LOG_opts[] = { - { .name = "log-level", .has_arg = 1, .val = '!' }, - { .name = "log-prefix", .has_arg = 1, .val = '#' }, - { .name = "log-tcp-sequence", .has_arg = 0, .val = '1' }, - { .name = "log-tcp-options", .has_arg = 0, .val = '2' }, - { .name = "log-ip-options", .has_arg = 0, .val = '3' }, - { .name = "log-uid", .has_arg = 0, .val = '4' }, - { .name = NULL } +#define s struct ip6t_log_info +static const struct xt_option_entry LOG_opts[] = { + {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, + .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, + {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, + {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, + {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, + {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, + {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, + {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s static void LOG_init(struct xt_entry_target *t) { @@ -63,127 +75,33 @@ static const struct ip6t_log_names ip6t_log_names[] { .name = "warning", .level = LOG_WARNING } }; -static u_int8_t -parse_level(const char *level) +static void LOG_parse(struct xt_option_call *cb) { - unsigned int lev = -1; - unsigned int set = 0; - - if (!xtables_strtoui(level, NULL, &lev, 0, 7)) { - unsigned int i = 0; - - for (i = 0; i < ARRAY_SIZE(ip6t_log_names); ++i) - if (strncasecmp(level, ip6t_log_names[i].name, - strlen(level)) == 0) { - if (set++) - xtables_error(PARAMETER_PROBLEM, - "log-level `%s' ambiguous", - level); - lev = ip6t_log_names[i].level; - } - - if (!set) - xtables_error(PARAMETER_PROBLEM, - "log-level `%s' unknown", level); - } - - return lev; -} - -#define IP6T_LOG_OPT_LEVEL 0x01 -#define IP6T_LOG_OPT_PREFIX 0x02 -#define IP6T_LOG_OPT_TCPSEQ 0x04 -#define IP6T_LOG_OPT_TCPOPT 0x08 -#define IP6T_LOG_OPT_IPOPT 0x10 -#define IP6T_LOG_OPT_UID 0x20 - -static int LOG_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) -{ - struct ip6t_log_info *loginfo = (struct ip6t_log_info *)(*target)->data; - - switch (c) { - case '!': - if (*flags & IP6T_LOG_OPT_LEVEL) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-level twice"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --log-level"); - - loginfo->level = parse_level(optarg); - *flags |= IP6T_LOG_OPT_LEVEL; - break; - - case '#': - if (*flags & IP6T_LOG_OPT_PREFIX) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-prefix twice"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --log-prefix"); - - if (strlen(optarg) > sizeof(loginfo->prefix) - 1) - xtables_error(PARAMETER_PROBLEM, - "Maximum prefix length %u for --log-prefix", - (unsigned int)sizeof(loginfo->prefix) - 1); + struct ip6t_log_info *info = cb->data; - if (strlen(optarg) == 0) - xtables_error(PARAMETER_PROBLEM, - "No prefix specified for --log-prefix"); - - if (strlen(optarg) != strlen(strtok(optarg, "\n"))) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_LOG_PREFIX: + if (strchr(cb->arg, '\n') != NULL) xtables_error(PARAMETER_PROBLEM, "Newlines not allowed in --log-prefix"); - - strcpy(loginfo->prefix, optarg); - *flags |= IP6T_LOG_OPT_PREFIX; break; - - case '1': - if (*flags & IP6T_LOG_OPT_TCPSEQ) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-tcp-sequence " - "twice"); - - loginfo->logflags |= IP6T_LOG_TCPSEQ; - *flags |= IP6T_LOG_OPT_TCPSEQ; + case O_LOG_TCPSEQ: + info->logflags |= IP6T_LOG_TCPSEQ; break; - - case '2': - if (*flags & IP6T_LOG_OPT_TCPOPT) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-tcp-options twice"); - - loginfo->logflags |= IP6T_LOG_TCPOPT; - *flags |= IP6T_LOG_OPT_TCPOPT; + case O_LOG_TCPOPTS: + info->logflags |= IP6T_LOG_TCPOPT; break; - - case '3': - if (*flags & IP6T_LOG_OPT_IPOPT) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-ip-options twice"); - - loginfo->logflags |= IP6T_LOG_IPOPT; - *flags |= IP6T_LOG_OPT_IPOPT; + case O_LOG_IPOPTS: + info->logflags |= IP6T_LOG_IPOPT; break; - - case '4': - if (*flags & IP6T_LOG_OPT_UID) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-uid twice"); - - loginfo->logflags |= IP6T_LOG_UID; - *flags |= IP6T_LOG_OPT_UID; + case O_LOG_UID: + info->logflags |= IP6T_LOG_UID; + break; + case O_LOG_MAC: + info->logflags |= IP6T_LOG_MACDECODE; break; - - default: - return 0; } - - return 1; } static void LOG_print(const void *ip, const struct xt_entry_target *target, @@ -193,32 +111,34 @@ static void LOG_print(const void *ip, const struct xt_entry_target *target, = (const struct ip6t_log_info *)target->data; unsigned int i = 0; - printf("LOG "); + printf(" LOG"); if (numeric) - printf("flags %u level %u ", + printf(" flags %u level %u", loginfo->logflags, loginfo->level); else { for (i = 0; i < ARRAY_SIZE(ip6t_log_names); ++i) if (loginfo->level == ip6t_log_names[i].level) { - printf("level %s ", ip6t_log_names[i].name); + printf(" level %s", ip6t_log_names[i].name); break; } if (i == ARRAY_SIZE(ip6t_log_names)) - printf("UNKNOWN level %u ", loginfo->level); + printf(" UNKNOWN level %u", loginfo->level); if (loginfo->logflags & IP6T_LOG_TCPSEQ) - printf("tcp-sequence "); + printf(" tcp-sequence"); if (loginfo->logflags & IP6T_LOG_TCPOPT) - printf("tcp-options "); + printf(" tcp-options"); if (loginfo->logflags & IP6T_LOG_IPOPT) - printf("ip-options "); + printf(" ip-options"); if (loginfo->logflags & IP6T_LOG_UID) - printf("uid "); + printf(" uid"); + if (loginfo->logflags & IP6T_LOG_MACDECODE) + printf(" macdecode"); if (loginfo->logflags & ~(IP6T_LOG_MASK)) - printf("unknown-flags "); + printf(" unknown-flags"); } if (strcmp(loginfo->prefix, "") != 0) - printf("prefix `%s' ", loginfo->prefix); + printf(" prefix \"%s\"", loginfo->prefix); } static void LOG_save(const void *ip, const struct xt_entry_target *target) @@ -226,34 +146,38 @@ static void LOG_save(const void *ip, const struct xt_entry_target *target) const struct ip6t_log_info *loginfo = (const struct ip6t_log_info *)target->data; - if (strcmp(loginfo->prefix, "") != 0) - printf("--log-prefix \"%s\" ", loginfo->prefix); + if (strcmp(loginfo->prefix, "") != 0) { + printf(" --log-prefix"); + xtables_save_string(loginfo->prefix); + } if (loginfo->level != LOG_DEFAULT_LEVEL) - printf("--log-level %d ", loginfo->level); + printf(" --log-level %d", loginfo->level); if (loginfo->logflags & IP6T_LOG_TCPSEQ) - printf("--log-tcp-sequence "); + printf(" --log-tcp-sequence"); if (loginfo->logflags & IP6T_LOG_TCPOPT) - printf("--log-tcp-options "); + printf(" --log-tcp-options"); if (loginfo->logflags & IP6T_LOG_IPOPT) - printf("--log-ip-options "); + printf(" --log-ip-options"); if (loginfo->logflags & IP6T_LOG_UID) - printf("--log-uid "); + printf(" --log-uid"); + if (loginfo->logflags & IP6T_LOG_MACDECODE) + printf(" --log-macdecode"); } static struct xtables_target log_tg6_reg = { - .name = "LOG", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct ip6t_log_info)), - .userspacesize = XT_ALIGN(sizeof(struct ip6t_log_info)), - .help = LOG_help, - .init = LOG_init, - .parse = LOG_parse, - .print = LOG_print, - .save = LOG_save, - .extra_opts = LOG_opts, + .name = "LOG", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct ip6t_log_info)), + .userspacesize = XT_ALIGN(sizeof(struct ip6t_log_info)), + .help = LOG_help, + .init = LOG_init, + .print = LOG_print, + .save = LOG_save, + .x6_parse = LOG_parse, + .x6_options = LOG_opts, }; void _init(void) diff --git a/extensions/libip6t_MASQUERADE.c b/extensions/libip6t_MASQUERADE.c new file mode 100644 index 0000000..eb9213e --- /dev/null +++ b/extensions/libip6t_MASQUERADE.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> + * + * Based on Rusty Russell's IPv4 MASQUERADE target. Development of IPv6 NAT + * funded by Astaro. + */ + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <xtables.h> +#include <limits.h> /* INT_MAX in ip_tables.h */ +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter/nf_nat.h> + +enum { + O_TO_PORTS = 0, + O_RANDOM, +}; + +static void MASQUERADE_help(void) +{ + printf( +"MASQUERADE target options:\n" +" --to-ports <port>[-<port>]\n" +" Port (range) to map to.\n" +" --random\n" +" Randomize source port.\n"); +} + +static const struct xt_option_entry MASQUERADE_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +/* Parses ports */ +static void +parse_ports(const char *arg, struct nf_nat_range *r) +{ + char *end; + unsigned int port, maxport; + + r->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) + xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); + + switch (*end) { + case '\0': + r->min_proto.tcp.port + = r->max_proto.tcp.port + = htons(port); + return; + case '-': + if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX)) + break; + + if (maxport < port) + break; + + r->min_proto.tcp.port = htons(port); + r->max_proto.tcp.port = htons(maxport); + return; + default: + break; + } + xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); +} + +static void MASQUERADE_parse(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + struct nf_nat_range *r = cb->data; + int portok; + + if (entry->ipv6.proto == IPPROTO_TCP || + entry->ipv6.proto == IPPROTO_UDP || + entry->ipv6.proto == IPPROTO_SCTP || + entry->ipv6.proto == IPPROTO_DCCP || + entry->ipv6.proto == IPPROTO_ICMP) + portok = 1; + else + portok = 0; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_PORTS: + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + parse_ports(cb->arg, r); + break; + case O_RANDOM: + r->flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; + } +} + +static void +MASQUERADE_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct nf_nat_range *r = (const void *)target->data; + + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" masq ports: "); + printf("%hu", ntohs(r->min_proto.tcp.port)); + if (r->max_proto.tcp.port != r->min_proto.tcp.port) + printf("-%hu", ntohs(r->max_proto.tcp.port)); + } + + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); +} + +static void +MASQUERADE_save(const void *ip, const struct xt_entry_target *target) +{ + const struct nf_nat_range *r = (const void *)target->data; + + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" --to-ports %hu", ntohs(r->min_proto.tcp.port)); + if (r->max_proto.tcp.port != r->min_proto.tcp.port) + printf("-%hu", ntohs(r->max_proto.tcp.port)); + } + + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); +} + +static struct xtables_target masquerade_tg_reg = { + .name = "MASQUERADE", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = MASQUERADE_help, + .x6_parse = MASQUERADE_parse, + .print = MASQUERADE_print, + .save = MASQUERADE_save, + .x6_options = MASQUERADE_opts, +}; + +void _init(void) +{ + xtables_register_target(&masquerade_tg_reg); +} diff --git a/extensions/libip6t_NETMAP.c b/extensions/libip6t_NETMAP.c new file mode 100644 index 0000000..a4df70e --- /dev/null +++ b/extensions/libip6t_NETMAP.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> + * + * Based on Svenning Soerensen's IPv4 NETMAP target. Development of IPv6 NAT + * funded by Astaro. + */ + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> +#include <xtables.h> +#include <libiptc/libip6tc.h> +#include <linux/netfilter/nf_nat.h> + +#define MODULENAME "NETMAP" + +enum { + O_TO = 0, +}; + +static const struct xt_option_entry NETMAP_opts[] = { + {.name = "to", .id = O_TO, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MAND}, + XTOPT_TABLEEND, +}; + +static void NETMAP_help(void) +{ + printf(MODULENAME" target options:\n" + " --%s address[/mask]\n" + " Network address to map to.\n\n", + NETMAP_opts[0].name); +} + +static void NETMAP_parse(struct xt_option_call *cb) +{ + struct nf_nat_range *range = cb->data; + unsigned int i; + + xtables_option_parse(cb); + range->flags |= NF_NAT_RANGE_MAP_IPS; + for (i = 0; i < 4; i++) { + range->min_addr.ip6[i] = cb->val.haddr.ip6[i] & + cb->val.hmask.ip6[i]; + range->max_addr.ip6[i] = range->min_addr.ip6[i] | + ~cb->val.hmask.ip6[i]; + } +} + +static void NETMAP_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct nf_nat_range *r = (const void *)target->data; + struct in6_addr a; + unsigned int i; + int bits; + + a = r->min_addr.in6; + printf("%s", xtables_ip6addr_to_numeric(&a)); + for (i = 0; i < 4; i++) + a.s6_addr32[i] = ~(r->min_addr.ip6[i] ^ r->max_addr.ip6[i]); + bits = xtables_ip6mask_to_cidr(&a); + if (bits < 0) + printf("/%s", xtables_ip6addr_to_numeric(&a)); + else + printf("/%d", bits); +} + +static void NETMAP_save(const void *ip, const struct xt_entry_target *target) +{ + printf(" --%s ", NETMAP_opts[0].name); + NETMAP_print(ip, target, 0); +} + +static struct xtables_target netmap_tg_reg = { + .name = MODULENAME, + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = NETMAP_help, + .x6_parse = NETMAP_parse, + .print = NETMAP_print, + .save = NETMAP_save, + .x6_options = NETMAP_opts, +}; + +void _init(void) +{ + xtables_register_target(&netmap_tg_reg); +} diff --git a/extensions/libip6t_REDIRECT.c b/extensions/libip6t_REDIRECT.c new file mode 100644 index 0000000..1724aa6 --- /dev/null +++ b/extensions/libip6t_REDIRECT.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> + * + * Based on Rusty Russell's IPv4 REDIRECT target. Development of IPv6 NAT + * funded by Astaro. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <xtables.h> +#include <limits.h> /* INT_MAX in ip_tables.h */ +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter/nf_nat.h> + +enum { + O_TO_PORTS = 0, + O_RANDOM, + F_TO_PORTS = 1 << O_TO_PORTS, + F_RANDOM = 1 << O_RANDOM, +}; + +static void REDIRECT_help(void) +{ + printf( +"REDIRECT target options:\n" +" --to-ports <port>[-<port>]\n" +" Port (range) to map to.\n" +" [--random]\n"); +} + +static const struct xt_option_entry REDIRECT_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +/* Parses ports */ +static void +parse_ports(const char *arg, struct nf_nat_range *range) +{ + char *end = ""; + unsigned int port, maxport; + + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && + (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) + xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); + + switch (*end) { + case '\0': + range->min_proto.tcp.port + = range->max_proto.tcp.port + = htons(port); + return; + case '-': + if (!xtables_strtoui(end + 1, NULL, &maxport, 0, UINT16_MAX) && + (maxport = xtables_service_to_port(end + 1, NULL)) == (unsigned)-1) + break; + + if (maxport < port) + break; + + range->min_proto.tcp.port = htons(port); + range->max_proto.tcp.port = htons(maxport); + return; + default: + break; + } + xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); +} + +static void REDIRECT_parse(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + struct nf_nat_range *range = (void *)(*cb->target)->data; + int portok; + + if (entry->ipv6.proto == IPPROTO_TCP + || entry->ipv6.proto == IPPROTO_UDP + || entry->ipv6.proto == IPPROTO_SCTP + || entry->ipv6.proto == IPPROTO_DCCP + || entry->ipv6.proto == IPPROTO_ICMP) + portok = 1; + else + portok = 0; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_PORTS: + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + parse_ports(cb->arg, range); + if (cb->xflags & F_RANDOM) + range->flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; + case O_RANDOM: + if (cb->xflags & F_TO_PORTS) + range->flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; + } +} + +static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct nf_nat_range *range = (const void *)target->data; + + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" redir ports "); + printf("%hu", ntohs(range->min_proto.tcp.port)); + if (range->max_proto.tcp.port != range->min_proto.tcp.port) + printf("-%hu", ntohs(range->max_proto.tcp.port)); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); + } +} + +static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) +{ + const struct nf_nat_range *range = (const void *)target->data; + + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" --to-ports "); + printf("%hu", ntohs(range->min_proto.tcp.port)); + if (range->max_proto.tcp.port != range->min_proto.tcp.port) + printf("-%hu", ntohs(range->max_proto.tcp.port)); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); + } +} + +static struct xtables_target redirect_tg_reg = { + .name = "REDIRECT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = REDIRECT_help, + .x6_parse = REDIRECT_parse, + .print = REDIRECT_print, + .save = REDIRECT_save, + .x6_options = REDIRECT_opts, +}; + +void _init(void) +{ + xtables_register_target(&redirect_tg_reg); +} diff --git a/extensions/libip6t_REJECT.c b/extensions/libip6t_REJECT.c index b8195d7..8085321 100644 --- a/extensions/libip6t_REJECT.c +++ b/extensions/libip6t_REJECT.c @@ -7,8 +7,6 @@ */ #include <stdio.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter_ipv6/ip6t_REJECT.h> @@ -19,6 +17,10 @@ struct reject_names { const char *desc; }; +enum { + O_REJECT_WITH = 0, +}; + static const struct reject_names reject_table[] = { {"icmp6-no-route", "no-route", IP6T_ICMP6_NO_ROUTE, "ICMPv6 no route"}, @@ -60,9 +62,9 @@ static void REJECT_help(void) print_reject_types(); } -static const struct option REJECT_opts[] = { - { "reject-with", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry REJECT_opts[] = { + {.name = "reject-with", .id = O_REJECT_WITH, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, }; static void REJECT_init(struct xt_entry_target *t) @@ -74,30 +76,22 @@ static void REJECT_init(struct xt_entry_target *t) } -static int REJECT_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void REJECT_parse(struct xt_option_call *cb) { - struct ip6t_reject_info *reject = - (struct ip6t_reject_info *)(*target)->data; + struct ip6t_reject_info *reject = cb->data; unsigned int i; - switch(c) { - case '1': - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --reject-with"); - for (i = 0; i < ARRAY_SIZE(reject_table); ++i) - if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0) - || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) { - reject->with = reject_table[i].with; - return 1; - } - xtables_error(PARAMETER_PROBLEM, "unknown reject type \"%s\"", optarg); - default: - /* Fall through */ - break; - } - return 0; + xtables_option_parse(cb); + for (i = 0; i < ARRAY_SIZE(reject_table); ++i) + if (strncasecmp(reject_table[i].name, + cb->arg, strlen(cb->arg)) == 0 || + strncasecmp(reject_table[i].alias, + cb->arg, strlen(cb->arg)) == 0) { + reject->with = reject_table[i].with; + return; + } + xtables_error(PARAMETER_PROBLEM, + "unknown reject type \"%s\"", cb->arg); } static void REJECT_print(const void *ip, const struct xt_entry_target *target, @@ -110,7 +104,7 @@ static void REJECT_print(const void *ip, const struct xt_entry_target *target, for (i = 0; i < ARRAY_SIZE(reject_table); ++i) if (reject_table[i].with == reject->with) break; - printf("reject-with %s ", reject_table[i].name); + printf(" reject-with %s", reject_table[i].name); } static void REJECT_save(const void *ip, const struct xt_entry_target *target) @@ -123,7 +117,7 @@ static void REJECT_save(const void *ip, const struct xt_entry_target *target) if (reject_table[i].with == reject->with) break; - printf("--reject-with %s ", reject_table[i].name); + printf(" --reject-with %s", reject_table[i].name); } static struct xtables_target reject_tg6_reg = { @@ -134,10 +128,10 @@ static struct xtables_target reject_tg6_reg = { .userspacesize = XT_ALIGN(sizeof(struct ip6t_reject_info)), .help = REJECT_help, .init = REJECT_init, - .parse = REJECT_parse, .print = REJECT_print, .save = REJECT_save, - .extra_opts = REJECT_opts, + .x6_parse = REJECT_parse, + .x6_options = REJECT_opts, }; void _init(void) diff --git a/extensions/libip6t_REJECT.man b/extensions/libip6t_REJECT.man index 2d09e05..0030a51 100644 --- a/extensions/libip6t_REJECT.man +++ b/extensions/libip6t_REJECT.man @@ -18,10 +18,9 @@ The type given can be \fBicmp6\-adm\-prohibited\fP, \fBadm\-prohibited\fP, \fBicmp6\-addr\-unreachable\fP, -\fBaddr\-unreach\fP, -\fBicmp6\-port\-unreachable\fP or -\fBport\-unreach\fP -which return the appropriate ICMPv6 error message (\fBport\-unreach\fP is +\fBaddr\-unreach\fP, or +\fBicmp6\-port\-unreachable\fP, +which return the appropriate ICMPv6 error message (\fBicmp6\-port\-unreachable\fP is the default). Finally, the option \fBtcp\-reset\fP can be used on rules which only match the TCP protocol: this causes a diff --git a/extensions/libip6t_SNAT.c b/extensions/libip6t_SNAT.c new file mode 100644 index 0000000..7382ad0 --- /dev/null +++ b/extensions/libip6t_SNAT.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> + * + * Based on Rusty Russell's IPv4 SNAT target. Development of IPv6 NAT + * funded by Astaro. + */ + +#include <stdio.h> +#include <netdb.h> +#include <string.h> +#include <stdlib.h> +#include <xtables.h> +#include <iptables.h> +#include <limits.h> /* INT_MAX in ip_tables.h */ +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter/nf_nat.h> + +enum { + O_TO_SRC = 0, + O_RANDOM, + O_PERSISTENT, + O_X_TO_SRC, + F_TO_SRC = 1 << O_TO_SRC, + F_RANDOM = 1 << O_RANDOM, + F_X_TO_SRC = 1 << O_X_TO_SRC, +}; + +static void SNAT_help(void) +{ + printf( +"SNAT target options:\n" +" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n" +" Address to map source to.\n" +"[--random] [--persistent]\n"); +} + +static const struct xt_option_entry SNAT_opts[] = { + {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_MULTI}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +/* Ranges expected in network order. */ +static void +parse_to(const char *orig_arg, int portok, struct nf_nat_range *range) +{ + char *arg, *start, *end = NULL, *colon = NULL, *dash, *error; + const struct in6_addr *ip; + + arg = strdup(orig_arg); + if (arg == NULL) + xtables_error(RESOURCE_PROBLEM, "strdup"); + + start = strchr(arg, '['); + if (start == NULL) { + start = arg; + /* Lets assume one colon is port information. Otherwise its an IPv6 address */ + colon = strchr(arg, ':'); + if (colon && strchr(colon+1, ':')) + colon = NULL; + } + else { + start++; + end = strchr(start, ']'); + if (end == NULL) + xtables_error(PARAMETER_PROBLEM, + "Invalid address format"); + + *end = '\0'; + colon = strchr(end + 1, ':'); + } + + if (colon) { + int port; + + if (!portok) + xtables_error(PARAMETER_PROBLEM, + "Need TCP, UDP, SCTP or DCCP with port specification"); + + range->flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + + port = atoi(colon+1); + if (port <= 0 || port > 65535) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", colon+1); + + error = strchr(colon+1, ':'); + if (error) + xtables_error(PARAMETER_PROBLEM, + "Invalid port:port syntax - use dash\n"); + + dash = strchr(colon, '-'); + if (!dash) { + range->min_proto.tcp.port + = range->max_proto.tcp.port + = htons(port); + } else { + int maxport; + + maxport = atoi(dash + 1); + if (maxport <= 0 || maxport > 65535) + xtables_error(PARAMETER_PROBLEM, + "Port `%s' not valid\n", dash+1); + if (maxport < port) + /* People are stupid. */ + xtables_error(PARAMETER_PROBLEM, + "Port range `%s' funky\n", colon+1); + range->min_proto.tcp.port = htons(port); + range->max_proto.tcp.port = htons(maxport); + } + /* Starts with colon or [] colon? No IP info...*/ + if (colon == arg || colon == arg+2) { + free(arg); + return; + } + *colon = '\0'; + } + + range->flags |= NF_NAT_RANGE_MAP_IPS; + dash = strchr(start, '-'); + if (colon && dash && dash > colon) + dash = NULL; + + if (dash) + *dash = '\0'; + + ip = xtables_numeric_to_ip6addr(start); + if (!ip) + xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", + start); + range->min_addr.in6 = *ip; + if (dash) { + ip = xtables_numeric_to_ip6addr(dash + 1); + if (!ip) + xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", + dash+1); + range->max_addr.in6 = *ip; + } else + range->max_addr = range->min_addr; + + free(arg); + return; +} + +static void SNAT_parse(struct xt_option_call *cb) +{ + const struct ip6t_entry *entry = cb->xt_entry; + struct nf_nat_range *range = cb->data; + int portok; + + if (entry->ipv6.proto == IPPROTO_TCP || + entry->ipv6.proto == IPPROTO_UDP || + entry->ipv6.proto == IPPROTO_SCTP || + entry->ipv6.proto == IPPROTO_DCCP || + entry->ipv6.proto == IPPROTO_ICMP) + portok = 1; + else + portok = 0; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_SRC: + if (cb->xflags & F_X_TO_SRC) { + if (!kernel_version) + get_kernel_version(); + if (kernel_version > LINUX_VERSION(2, 6, 10)) + xtables_error(PARAMETER_PROBLEM, + "SNAT: Multiple --to-source not supported"); + } + parse_to(cb->arg, portok, range); + break; + case O_PERSISTENT: + range->flags |= NF_NAT_RANGE_PERSISTENT; + break; + } +} + +static void SNAT_fcheck(struct xt_fcheck_call *cb) +{ + static const unsigned int f = F_TO_SRC | F_RANDOM; + struct nf_nat_range *range = cb->data; + + if ((cb->xflags & f) == f) + range->flags |= NF_NAT_RANGE_PROTO_RANDOM; +} + +static void print_range(const struct nf_nat_range *range) +{ + if (range->flags & NF_NAT_RANGE_MAP_IPS) { + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) + printf("["); + printf("%s", xtables_ip6addr_to_numeric(&range->min_addr.in6)); + if (memcmp(&range->min_addr, &range->max_addr, + sizeof(range->min_addr))) + printf("-%s", xtables_ip6addr_to_numeric(&range->max_addr.in6)); + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) + printf("]"); + } + if (range->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(":"); + printf("%hu", ntohs(range->min_proto.tcp.port)); + if (range->max_proto.tcp.port != range->min_proto.tcp.port) + printf("-%hu", ntohs(range->max_proto.tcp.port)); + } +} + +static void SNAT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct nf_nat_range *range = (const void *)target->data; + + printf(" to:"); + print_range(range); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); + if (range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" persistent"); +} + +static void SNAT_save(const void *ip, const struct xt_entry_target *target) +{ + const struct nf_nat_range *range = (const void *)target->data; + + printf(" --to-source "); + print_range(range); + if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); + if (range->flags & NF_NAT_RANGE_PERSISTENT) + printf(" --persistent"); +} + +static struct xtables_target snat_tg_reg = { + .name = "SNAT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .revision = 1, + .size = XT_ALIGN(sizeof(struct nf_nat_range)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_range)), + .help = SNAT_help, + .x6_parse = SNAT_parse, + .x6_fcheck = SNAT_fcheck, + .print = SNAT_print, + .save = SNAT_save, + .x6_options = SNAT_opts, +}; + +void _init(void) +{ + xtables_register_target(&snat_tg_reg); +} diff --git a/extensions/libip6t_SNPT.c b/extensions/libip6t_SNPT.c new file mode 100644 index 0000000..4f10de0 --- /dev/null +++ b/extensions/libip6t_SNPT.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012-2013 Patrick McHardy <kaber@trash.net> + */ + +#include <stdio.h> +#include <string.h> +#include <xtables.h> +#include <linux/netfilter_ipv6/ip6_tables.h> +#include <linux/netfilter_ipv6/ip6t_NPT.h> + +enum { + O_SRC_PFX = 1 << 0, + O_DST_PFX = 1 << 1, +}; + +static const struct xt_option_entry SNPT_options[] = { + { .name = "src-pfx", .id = O_SRC_PFX, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MAND }, + { .name = "dst-pfx", .id = O_DST_PFX, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MAND }, + { } +}; + +static void SNPT_help(void) +{ + printf("SNPT target options:" + "\n" + " --src-pfx prefix/length\n" + " --dst-pfx prefix/length\n" + "\n"); +} + +static void SNPT_parse(struct xt_option_call *cb) +{ + struct ip6t_npt_tginfo *npt = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRC_PFX: + npt->src_pfx = cb->val.haddr; + npt->src_pfx_len = cb->val.hlen; + break; + case O_DST_PFX: + npt->dst_pfx = cb->val.haddr; + npt->dst_pfx_len = cb->val.hlen; + break; + } +} + +static void SNPT_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct ip6t_npt_tginfo *npt = (const void *)target->data; + + printf("src-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->src_pfx.in6), + npt->src_pfx_len); + printf("dst-pfx %s/%u ", xtables_ip6addr_to_numeric(&npt->dst_pfx.in6), + npt->dst_pfx_len); +} + +static void SNPT_save(const void *ip, const struct xt_entry_target *target) +{ + static const struct in6_addr zero_addr; + const struct ip6t_npt_tginfo *info = (const void *)target->data; + + if (memcmp(&info->src_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 || + info->src_pfx_len != 0) + printf("--src-pfx %s/%u ", + xtables_ip6addr_to_numeric(&info->src_pfx.in6), + info->src_pfx_len); + if (memcmp(&info->dst_pfx.in6, &zero_addr, sizeof(zero_addr)) != 0 || + info->dst_pfx_len != 0) + printf("--dst-pfx %s/%u ", + xtables_ip6addr_to_numeric(&info->dst_pfx.in6), + info->dst_pfx_len); +} + +static struct xtables_target snpt_tg_reg = { + .name = "SNPT", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct ip6t_npt_tginfo)), + .userspacesize = offsetof(struct ip6t_npt_tginfo, adjustment), + .help = SNPT_help, + .x6_parse = SNPT_parse, + .print = SNPT_print, + .save = SNPT_save, + .x6_options = SNPT_options, +}; + +void _init(void) +{ + xtables_register_target(&snpt_tg_reg); +} diff --git a/extensions/libip6t_SNPT.man b/extensions/libip6t_SNPT.man new file mode 100644 index 0000000..78d644a --- /dev/null +++ b/extensions/libip6t_SNPT.man @@ -0,0 +1,30 @@ +Provides stateless source IPv6-to-IPv6 Network Prefix Translation (as described +by RFC 6296). +.PP +You have to use this target in the +.B mangle +table, not in the +.B nat +table. It takes the following options: +.TP +\fB\-\-src\-pfx\fP [\fIprefix/\fP\fIlength] +Set source prefix that you want to translate and length +.TP +\fB\-\-dst\-pfx\fP [\fIprefix/\fP\fIlength] +Set destination prefix that you want to use in the translation and length +.PP +You have to use the DNPT target to undo the translation. Example: +.IP +ip6tables \-t mangle \-I POSTROUTING \-s fd00::/64 \! \-o vboxnet0 +\-j SNPT \-\-src-pfx fd00::/64 \-\-dst-pfx 2001:e20:2000:40f::/64 +.IP +ip6tables \-t mangle \-I PREROUTING \-i wlan0 \-d 2001:e20:2000:40f::/64 +\-j DNPT \-\-src-pfx 2001:e20:2000:40f::/64 \-\-dst-pfx fd00::/64 +.PP +You may need to enable IPv6 neighbor proxy: +.IP +sysctl -w net.ipv6.conf.all.proxy_ndp=1 +.PP +You also have to use the +.B NOTRACK +target to disable connection tracking for translated flows. diff --git a/extensions/libip6t_ah.c b/extensions/libip6t_ah.c index 285704c..26f8140 100644 --- a/extensions/libip6t_ah.c +++ b/extensions/libip6t_ah.c @@ -1,142 +1,76 @@ -/* Shared library add-on to ip6tables to add AH support. */ #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <errno.h> #include <xtables.h> #include <linux/netfilter_ipv6/ip6t_ah.h> +enum { + O_AHSPI = 0, + O_AHLEN, + O_AHRES, +}; + static void ah_help(void) { printf( "ah match options:\n" "[!] --ahspi spi[:spi] match spi (range)\n" "[!] --ahlen length total length of this header\n" -" --ahres check the reserved filed, too\n"); +" --ahres check the reserved field too\n"); } -static const struct option ah_opts[] = { - { .name = "ahspi", .has_arg = 1, .val = '1' }, - { .name = "ahlen", .has_arg = 1, .val = '2' }, - { .name = "ahres", .has_arg = 0, .val = '3' }, - { .name = NULL } +#define s struct ip6t_ah +static const struct xt_option_entry ah_opts[] = { + {.name = "ahspi", .id = O_AHSPI, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spis)}, + {.name = "ahlen", .id = O_AHLEN, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)}, + {.name = "ahres", .id = O_AHRES, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s -static u_int32_t -parse_ah_spi(const char *spistr, const char *typestr) -{ - unsigned long int spi; - char* ep; - - spi = strtoul(spistr, &ep, 0); - - if ( spistr == ep ) - xtables_error(PARAMETER_PROBLEM, - "AH no valid digits in %s `%s'", typestr, spistr); - - if ( spi == ULONG_MAX && errno == ERANGE ) - xtables_error(PARAMETER_PROBLEM, - "%s `%s' specified too big: would overflow", - typestr, spistr); - - if ( *spistr != '\0' && *ep != '\0' ) - xtables_error(PARAMETER_PROBLEM, - "AH error parsing %s `%s'", typestr, spistr); - - return 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, "spi"); - else { - *cp = '\0'; - cp++; - - spis[0] = buffer[0] ? parse_ah_spi(buffer, "spi") : 0; - spis[1] = cp[0] ? parse_ah_spi(cp, "spi") : 0xFFFFFFFF; - } - free(buffer); -} - -static void ah_init(struct xt_entry_match *m) +static void ah_parse(struct xt_option_call *cb) { - struct ip6t_ah *ahinfo = (struct ip6t_ah *)m->data; - - ahinfo->spis[1] = 0xFFFFFFFF; - ahinfo->hdrlen = 0; - ahinfo->hdrres = 0; -} - -static int ah_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ip6t_ah *ahinfo = (struct ip6t_ah *)(*match)->data; - - switch (c) { - case '1': - if (*flags & IP6T_AH_SPI) - xtables_error(PARAMETER_PROBLEM, - "Only one `--ahspi' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_ah_spis(optarg, ahinfo->spis); - if (invert) + struct ip6t_ah *ahinfo = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_AHSPI: + if (cb->nvals == 1) + ahinfo->spis[1] = ahinfo->spis[0]; + if (cb->invert) ahinfo->invflags |= IP6T_AH_INV_SPI; - *flags |= IP6T_AH_SPI; break; - case '2': - if (*flags & IP6T_AH_LEN) - xtables_error(PARAMETER_PROBLEM, - "Only one `--ahlen' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - ahinfo->hdrlen = parse_ah_spi(optarg, "length"); - if (invert) + case O_AHLEN: + if (cb->invert) ahinfo->invflags |= IP6T_AH_INV_LEN; - *flags |= IP6T_AH_LEN; break; - case '3': - if (*flags & IP6T_AH_RES) - xtables_error(PARAMETER_PROBLEM, - "Only one `--ahres' allowed"); + case O_AHRES: ahinfo->hdrres = 1; - *flags |= IP6T_AH_RES; break; - default: - return 0; } - - return 1; } static void -print_spis(const char *name, u_int32_t min, u_int32_t max, +print_spis(const char *name, uint32_t min, uint32_t max, int invert) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFFFFFFFF || invert) { if (min == max) - printf("%s:%s%u ", name, inv, min); + printf("%s:%s%u", name, inv, min); else - printf("%ss:%s%u:%u ", name, inv, min, max); + printf("%ss:%s%u:%u", name, inv, min, max); } } static void -print_len(const char *name, u_int32_t len, int invert) +print_len(const char *name, uint32_t len, int invert) { const char *inv = invert ? "!" : ""; if (len != 0 || invert) - printf("%s:%s%u ", name, inv, len); + printf("%s:%s%u", name, inv, len); } static void ah_print(const void *ip, const struct xt_entry_match *match, @@ -144,17 +78,17 @@ static void ah_print(const void *ip, const struct xt_entry_match *match, { const struct ip6t_ah *ah = (struct ip6t_ah *)match->data; - printf("ah "); + printf(" ah "); print_spis("spi", ah->spis[0], ah->spis[1], ah->invflags & IP6T_AH_INV_SPI); print_len("length", ah->hdrlen, ah->invflags & IP6T_AH_INV_LEN); if (ah->hdrres) - printf("reserved "); + printf(" reserved"); if (ah->invflags & ~IP6T_AH_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", ah->invflags & ~IP6T_AH_INV_MASK); } @@ -164,26 +98,26 @@ static void ah_save(const void *ip, const struct xt_entry_match *match) if (!(ahinfo->spis[0] == 0 && ahinfo->spis[1] == 0xFFFFFFFF)) { - printf("%s--ahspi ", - (ahinfo->invflags & IP6T_AH_INV_SPI) ? "! " : ""); + printf("%s --ahspi ", + (ahinfo->invflags & IP6T_AH_INV_SPI) ? " !" : ""); if (ahinfo->spis[0] != ahinfo->spis[1]) - printf("%u:%u ", + printf("%u:%u", ahinfo->spis[0], ahinfo->spis[1]); else - printf("%u ", + printf("%u", ahinfo->spis[0]); } if (ahinfo->hdrlen != 0 || (ahinfo->invflags & IP6T_AH_INV_LEN) ) { - printf("%s--ahlen %u ", - (ahinfo->invflags & IP6T_AH_INV_LEN) ? "! " : "", + printf("%s --ahlen %u", + (ahinfo->invflags & IP6T_AH_INV_LEN) ? " !" : "", ahinfo->hdrlen); } if (ahinfo->hdrres != 0 ) - printf("--ahres "); + printf(" --ahres"); } static struct xtables_match ah_mt6_reg = { @@ -193,11 +127,10 @@ static struct xtables_match ah_mt6_reg = { .size = XT_ALIGN(sizeof(struct ip6t_ah)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_ah)), .help = ah_help, - .init = ah_init, - .parse = ah_parse, .print = ah_print, .save = ah_save, - .extra_opts = ah_opts, + .x6_parse = ah_parse, + .x6_options = ah_opts, }; void diff --git a/extensions/libip6t_dst.c b/extensions/libip6t_dst.c index 72df6ad..3fd4c01 100644 --- a/extensions/libip6t_dst.c +++ b/extensions/libip6t_dst.c @@ -1,15 +1,14 @@ -/* Shared library add-on to ip6tables to add Dst header support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <errno.h> #include <xtables.h> #include <linux/netfilter_ipv6/ip6t_opts.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> + +enum { + O_DSTLEN = 0, + O_DSTOPTS, +}; static void dst_help(void) { @@ -21,14 +20,15 @@ static void dst_help(void) IP6T_OPTS_OPTSNR); } -static const struct option dst_opts[] = { - { .name = "dst-len", .has_arg = 1, .val = '1' }, - { .name = "dst-opts", .has_arg = 1, .val = '2' }, - { .name = "dst-not-strict", .has_arg = 1, .val = '3' }, - { .name = NULL } +static const struct xt_option_entry dst_opts[] = { + {.name = "dst-len", .id = O_DSTLEN, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ip6t_opts, hdrlen)}, + {.name = "dst-opts", .id = O_DSTOPTS, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, }; -static u_int32_t +static uint32_t parse_opts_num(const char *idstr, const char *typestr) { unsigned long int id; @@ -53,7 +53,7 @@ parse_opts_num(const char *idstr, const char *typestr) } static int -parse_options(const char *optsstr, u_int16_t *opts) +parse_options(const char *optsstr, uint16_t *opts) { char *buffer, *cp, *next, *range; unsigned int i; @@ -105,68 +105,28 @@ parse_options(const char *optsstr, u_int16_t *opts) return i; } -static void dst_init(struct xt_entry_match *m) +static void dst_parse(struct xt_option_call *cb) { - struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; + struct ip6t_opts *optinfo = cb->data; - optinfo->hdrlen = 0; - optinfo->flags = 0; - optinfo->invflags = 0; - optinfo->optsnr = 0; -} - -static int dst_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; - - switch (c) { - case '1': - if (*flags & IP6T_OPTS_LEN) - xtables_error(PARAMETER_PROBLEM, - "Only one `--dst-len' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - optinfo->hdrlen = parse_opts_num(optarg, "length"); - if (invert) - optinfo->invflags |= IP6T_OPTS_INV_LEN; + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_DSTLEN: optinfo->flags |= IP6T_OPTS_LEN; - *flags |= IP6T_OPTS_LEN; break; - case '2': - if (*flags & IP6T_OPTS_OPTS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--dst-opts' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) - xtables_error(PARAMETER_PROBLEM, - " '!' not allowed with `--dst-opts'"); - optinfo->optsnr = parse_options(optarg, optinfo->opts); + case O_DSTOPTS: + optinfo->optsnr = parse_options(cb->arg, optinfo->opts); optinfo->flags |= IP6T_OPTS_OPTS; - *flags |= IP6T_OPTS_OPTS; break; - case '3': - if (*flags & IP6T_OPTS_NSTRICT) - xtables_error(PARAMETER_PROBLEM, - "Only one `--dst-not-strict' allowed"); - if ( !(*flags & IP6T_OPTS_OPTS) ) - xtables_error(PARAMETER_PROBLEM, - "`--dst-opts ...' required before " - "`--dst-not-strict'"); - optinfo->flags |= IP6T_OPTS_NSTRICT; - *flags |= IP6T_OPTS_NSTRICT; - break; - default: - return 0; } - - return 1; } static void -print_options(unsigned int optsnr, u_int16_t *optsp) +print_options(unsigned int optsnr, uint16_t *optsp) { unsigned int i; + printf(" "); for(i = 0; i < optsnr; i++) { printf("%d", (optsp[i] & 0xFF00) >> 8); @@ -182,22 +142,19 @@ static void dst_print(const void *ip, const struct xt_entry_match *match, { const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; - printf("dst "); + printf(" dst"); if (optinfo->flags & IP6T_OPTS_LEN) - printf("length:%s%u ", + printf(" length:%s%u", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : "", optinfo->hdrlen); if (optinfo->flags & IP6T_OPTS_OPTS) - printf("opts "); + printf(" opts"); - print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); - - if (optinfo->flags & IP6T_OPTS_NSTRICT) - printf("not-strict "); + print_options(optinfo->optsnr, (uint16_t *)optinfo->opts); if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", optinfo->invflags & ~IP6T_OPTS_INV_MASK); } @@ -206,18 +163,15 @@ static void dst_save(const void *ip, const struct xt_entry_match *match) const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; if (optinfo->flags & IP6T_OPTS_LEN) { - printf("%s--dst-len %u ", - (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", + printf("%s --dst-len %u", + (optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "", optinfo->hdrlen); } if (optinfo->flags & IP6T_OPTS_OPTS) - printf("--dst-opts "); - - print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); + printf(" --dst-opts"); - if (optinfo->flags & IP6T_OPTS_NSTRICT) - printf("--dst-not-strict "); + print_options(optinfo->optsnr, (uint16_t *)optinfo->opts); } static struct xtables_match dst_mt6_reg = { @@ -227,11 +181,10 @@ static struct xtables_match dst_mt6_reg = { .size = XT_ALIGN(sizeof(struct ip6t_opts)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)), .help = dst_help, - .init = dst_init, - .parse = dst_parse, .print = dst_print, .save = dst_save, - .extra_opts = dst_opts, + .x6_parse = dst_parse, + .x6_options = dst_opts, }; void diff --git a/extensions/libip6t_frag.c b/extensions/libip6t_frag.c index 5a280cc..023df62 100644 --- a/extensions/libip6t_frag.c +++ b/extensions/libip6t_frag.c @@ -1,154 +1,96 @@ -/* Shared library add-on to ip6tables to add Fragmentation header support. */ #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <errno.h> #include <xtables.h> #include <linux/netfilter_ipv6/ip6t_frag.h> +enum { + O_FRAGID = 0, + O_FRAGLEN, + O_FRAGRES, + O_FRAGFIRST, + O_FRAGMORE, + O_FRAGLAST, + F_FRAGMORE = 1 << O_FRAGMORE, + F_FRAGLAST = 1 << O_FRAGLAST, +}; + static void frag_help(void) { printf( "frag match options:\n" "[!] --fragid id[:id] match the id (range)\n" "[!] --fraglen length total length of this header\n" -" --fragres check the reserved filed, too\n" +" --fragres check the reserved field too\n" " --fragfirst matches on the first fragment\n" " [--fragmore|--fraglast] there are more fragments or this\n" " is the last one\n"); } -static const struct option frag_opts[] = { - { .name = "fragid", .has_arg = 1, .val = '1' }, - { .name = "fraglen", .has_arg = 1, .val = '2' }, - { .name = "fragres", .has_arg = 0, .val = '3' }, - { .name = "fragfirst", .has_arg = 0, .val = '4' }, - { .name = "fragmore", .has_arg = 0, .val = '5' }, - { .name = "fraglast", .has_arg = 0, .val = '6' }, - { .name = NULL } +#define s struct ip6t_frag +static const struct xt_option_entry frag_opts[] = { + {.name = "fragid", .id = O_FRAGID, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, ids)}, + {.name = "fraglen", .id = O_FRAGLEN, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)}, + {.name = "fragres", .id = O_FRAGRES, .type = XTTYPE_NONE}, + {.name = "fragfirst", .id = O_FRAGFIRST, .type = XTTYPE_NONE}, + {.name = "fragmore", .id = O_FRAGMORE, .type = XTTYPE_NONE, + .excl = F_FRAGLAST}, + {.name = "fraglast", .id = O_FRAGLAST, .type = XTTYPE_NONE, + .excl = F_FRAGMORE}, + XTOPT_TABLEEND, }; - -static u_int32_t -parse_frag_id(const char *idstr, const char *typestr) -{ - unsigned long int id; - char* ep; - - id = strtoul(idstr, &ep, 0); - - if ( idstr == ep ) { - xtables_error(PARAMETER_PROBLEM, - "FRAG no valid digits in %s `%s'", typestr, idstr); - } - if ( id == ULONG_MAX && errno == ERANGE ) { - xtables_error(PARAMETER_PROBLEM, - "%s `%s' specified too big: would overflow", - typestr, idstr); - } - if ( *idstr != '\0' && *ep != '\0' ) { - xtables_error(PARAMETER_PROBLEM, - "FRAG error parsing %s `%s'", typestr, idstr); - } - return id; -} - -static void -parse_frag_ids(const char *idstring, u_int32_t *ids) -{ - char *buffer; - char *cp; - - buffer = strdup(idstring); - if ((cp = strchr(buffer, ':')) == NULL) - ids[0] = ids[1] = parse_frag_id(buffer,"id"); - else { - *cp = '\0'; - cp++; - - ids[0] = buffer[0] ? parse_frag_id(buffer,"id") : 0; - ids[1] = cp[0] ? parse_frag_id(cp,"id") : 0xFFFFFFFF; - } - free(buffer); -} +#undef s static void frag_init(struct xt_entry_match *m) { - struct ip6t_frag *fraginfo = (struct ip6t_frag *)m->data; + struct ip6t_frag *fraginfo = (void *)m->data; - fraginfo->ids[0] = 0x0L; - fraginfo->ids[1] = 0xFFFFFFFF; - fraginfo->hdrlen = 0; - fraginfo->flags = 0; - fraginfo->invflags = 0; + fraginfo->ids[1] = ~0U; } -static int frag_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void frag_parse(struct xt_option_call *cb) { - struct ip6t_frag *fraginfo = (struct ip6t_frag *)(*match)->data; - - switch (c) { - case '1': - if (*flags & IP6T_FRAG_IDS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--fragid' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_frag_ids(optarg, fraginfo->ids); - if (invert) + struct ip6t_frag *fraginfo = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_FRAGID: + if (cb->nvals == 1) + fraginfo->ids[1] = fraginfo->ids[0]; + if (cb->invert) fraginfo->invflags |= IP6T_FRAG_INV_IDS; + /* + * Note however that IP6T_FRAG_IDS is not tested by anything, + * so it is merely here for completeness. + */ fraginfo->flags |= IP6T_FRAG_IDS; - *flags |= IP6T_FRAG_IDS; break; - case '2': - if (*flags & IP6T_FRAG_LEN) - xtables_error(PARAMETER_PROBLEM, - "Only one `--fraglen' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - fraginfo->hdrlen = parse_frag_id(optarg, "length"); - if (invert) + case O_FRAGLEN: + /* + * As of Linux 3.0, the kernel does not check for + * fraglen at all. + */ + if (cb->invert) fraginfo->invflags |= IP6T_FRAG_INV_LEN; fraginfo->flags |= IP6T_FRAG_LEN; - *flags |= IP6T_FRAG_LEN; break; - case '3': - if (*flags & IP6T_FRAG_RES) - xtables_error(PARAMETER_PROBLEM, - "Only one `--fragres' allowed"); + case O_FRAGRES: fraginfo->flags |= IP6T_FRAG_RES; - *flags |= IP6T_FRAG_RES; break; - case '4': - if (*flags & IP6T_FRAG_FST) - xtables_error(PARAMETER_PROBLEM, - "Only one `--fragfirst' allowed"); + case O_FRAGFIRST: fraginfo->flags |= IP6T_FRAG_FST; - *flags |= IP6T_FRAG_FST; break; - case '5': - if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF)) - xtables_error(PARAMETER_PROBLEM, - "Only one `--fragmore' or `--fraglast' allowed"); + case O_FRAGMORE: fraginfo->flags |= IP6T_FRAG_MF; - *flags |= IP6T_FRAG_MF; break; - case '6': - if (*flags & (IP6T_FRAG_MF|IP6T_FRAG_NMF)) - xtables_error(PARAMETER_PROBLEM, - "Only one `--fragmore' or `--fraglast' allowed"); + case O_FRAGLAST: fraginfo->flags |= IP6T_FRAG_NMF; - *flags |= IP6T_FRAG_NMF; break; - default: - return 0; } - - return 1; } static void -print_ids(const char *name, u_int32_t min, u_int32_t max, +print_ids(const char *name, uint32_t min, uint32_t max, int invert) { const char *inv = invert ? "!" : ""; @@ -156,9 +98,9 @@ print_ids(const char *name, u_int32_t min, u_int32_t max, if (min != 0 || max != 0xFFFFFFFF || invert) { printf("%s", name); if (min == max) - printf(":%s%u ", inv, min); + printf(":%s%u", inv, min); else - printf("s:%s%u:%u ", inv, min, max); + printf("s:%s%u:%u", inv, min, max); } } @@ -167,30 +109,30 @@ static void frag_print(const void *ip, const struct xt_entry_match *match, { const struct ip6t_frag *frag = (struct ip6t_frag *)match->data; - printf("frag "); + printf(" frag "); print_ids("id", frag->ids[0], frag->ids[1], frag->invflags & IP6T_FRAG_INV_IDS); if (frag->flags & IP6T_FRAG_LEN) { - printf("length:%s%u ", + printf(" length:%s%u", frag->invflags & IP6T_FRAG_INV_LEN ? "!" : "", frag->hdrlen); } if (frag->flags & IP6T_FRAG_RES) - printf("reserved "); + printf(" reserved"); if (frag->flags & IP6T_FRAG_FST) - printf("first "); + printf(" first"); if (frag->flags & IP6T_FRAG_MF) - printf("more "); + printf(" more"); if (frag->flags & IP6T_FRAG_NMF) - printf("last "); + printf(" last"); if (frag->invflags & ~IP6T_FRAG_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", frag->invflags & ~IP6T_FRAG_INV_MASK); } @@ -200,35 +142,35 @@ static void frag_save(const void *ip, const struct xt_entry_match *match) if (!(fraginfo->ids[0] == 0 && fraginfo->ids[1] == 0xFFFFFFFF)) { - printf("%s--fragid ", - (fraginfo->invflags & IP6T_FRAG_INV_IDS) ? "! " : ""); + printf("%s --fragid ", + (fraginfo->invflags & IP6T_FRAG_INV_IDS) ? " !" : ""); if (fraginfo->ids[0] != fraginfo->ids[1]) - printf("%u:%u ", + printf("%u:%u", fraginfo->ids[0], fraginfo->ids[1]); else - printf("%u ", + printf("%u", fraginfo->ids[0]); } if (fraginfo->flags & IP6T_FRAG_LEN) { - printf("%s--fraglen %u ", - (fraginfo->invflags & IP6T_FRAG_INV_LEN) ? "! " : "", + printf("%s --fraglen %u", + (fraginfo->invflags & IP6T_FRAG_INV_LEN) ? " !" : "", fraginfo->hdrlen); } if (fraginfo->flags & IP6T_FRAG_RES) - printf("--fragres "); + printf(" --fragres"); if (fraginfo->flags & IP6T_FRAG_FST) - printf("--fragfirst "); + printf(" --fragfirst"); if (fraginfo->flags & IP6T_FRAG_MF) - printf("--fragmore "); + printf(" --fragmore"); if (fraginfo->flags & IP6T_FRAG_NMF) - printf("--fraglast "); + printf(" --fraglast"); } static struct xtables_match frag_mt6_reg = { @@ -239,10 +181,10 @@ static struct xtables_match frag_mt6_reg = { .userspacesize = XT_ALIGN(sizeof(struct ip6t_frag)), .help = frag_help, .init = frag_init, - .parse = frag_parse, .print = frag_print, .save = frag_save, - .extra_opts = frag_opts, + .x6_parse = frag_parse, + .x6_options = frag_opts, }; void diff --git a/extensions/libip6t_hbh.c b/extensions/libip6t_hbh.c index 520ec9e..c0389ed 100644 --- a/extensions/libip6t_hbh.c +++ b/extensions/libip6t_hbh.c @@ -1,19 +1,17 @@ -/* Shared library add-on to ip6tables to add Hop-by-Hop header support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <errno.h> #include <xtables.h> -/*#include <linux/in6.h>*/ #include <linux/netfilter_ipv6/ip6t_opts.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <arpa/inet.h> #define DEBUG 0 +enum { + O_HBH_LEN = 0, + O_HBH_OPTS, +}; + static void hbh_help(void) { printf( @@ -24,14 +22,15 @@ static void hbh_help(void) IP6T_OPTS_OPTSNR); } -static const struct option hbh_opts[] = { - { "hbh-len", 1, NULL, '1' }, - { "hbh-opts", 1, NULL, '2' }, - { "hbh-not-strict", 1, NULL, '3' }, - { .name = NULL } +static const struct xt_option_entry hbh_opts[] = { + {.name = "hbh-len", .id = O_HBH_LEN, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ip6t_opts, hdrlen)}, + {.name = "hbh-opts", .id = O_HBH_OPTS, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, }; -static u_int32_t +static uint32_t parse_opts_num(const char *idstr, const char *typestr) { unsigned long int id; @@ -56,7 +55,7 @@ parse_opts_num(const char *idstr, const char *typestr) } static int -parse_options(const char *optsstr, u_int16_t *opts) +parse_options(const char *optsstr, uint16_t *opts) { char *buffer, *cp, *next, *range; unsigned int i; @@ -100,73 +99,35 @@ parse_options(const char *optsstr, u_int16_t *opts) return i; } -static void hbh_init(struct xt_entry_match *m) +static void hbh_parse(struct xt_option_call *cb) { - struct ip6t_opts *optinfo = (struct ip6t_opts *)m->data; - - optinfo->hdrlen = 0; - optinfo->flags = 0; - optinfo->invflags = 0; - optinfo->optsnr = 0; -} + struct ip6t_opts *optinfo = cb->data; -static int hbh_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ip6t_opts *optinfo = (struct ip6t_opts *)(*match)->data; - - switch (c) { - case '1': - if (*flags & IP6T_OPTS_LEN) - xtables_error(PARAMETER_PROBLEM, - "Only one `--hbh-len' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - optinfo->hdrlen = parse_opts_num(optarg, "length"); - if (invert) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_HBH_LEN: + if (cb->invert) optinfo->invflags |= IP6T_OPTS_INV_LEN; optinfo->flags |= IP6T_OPTS_LEN; - *flags |= IP6T_OPTS_LEN; break; - case '2': - if (*flags & IP6T_OPTS_OPTS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--hbh-opts' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) - xtables_error(PARAMETER_PROBLEM, - " '!' not allowed with `--hbh-opts'"); - optinfo->optsnr = parse_options(optarg, optinfo->opts); + case O_HBH_OPTS: + optinfo->optsnr = parse_options(cb->arg, optinfo->opts); optinfo->flags |= IP6T_OPTS_OPTS; - *flags |= IP6T_OPTS_OPTS; - break; - case '3': - if (*flags & IP6T_OPTS_NSTRICT) - xtables_error(PARAMETER_PROBLEM, - "Only one `--hbh-not-strict' allowed"); - if ( !(*flags & IP6T_OPTS_OPTS) ) - xtables_error(PARAMETER_PROBLEM, - "`--hbh-opts ...' required before `--hbh-not-strict'"); - optinfo->flags |= IP6T_OPTS_NSTRICT; - *flags |= IP6T_OPTS_NSTRICT; break; - default: - return 0; } - - return 1; } static void -print_options(unsigned int optsnr, u_int16_t *optsp) +print_options(unsigned int optsnr, uint16_t *optsp) { unsigned int i; for(i=0; i<optsnr; i++){ + printf("%c", (i==0)?' ':','); printf("%d", (optsp[i] & 0xFF00)>>8); if ((optsp[i] & 0x00FF) != 0x00FF){ printf(":%d", (optsp[i] & 0x00FF)); } - printf("%c", (i!=optsnr-1)?',':' '); } } @@ -175,18 +136,16 @@ static void hbh_print(const void *ip, const struct xt_entry_match *match, { const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; - printf("hbh "); + printf(" hbh"); if (optinfo->flags & IP6T_OPTS_LEN) { - printf("length"); + printf(" length"); printf(":%s", optinfo->invflags & IP6T_OPTS_INV_LEN ? "!" : ""); printf("%u", optinfo->hdrlen); - printf(" "); } - if (optinfo->flags & IP6T_OPTS_OPTS) printf("opts "); - print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); - if (optinfo->flags & IP6T_OPTS_NSTRICT) printf("not-strict "); + if (optinfo->flags & IP6T_OPTS_OPTS) printf(" opts"); + print_options(optinfo->optsnr, (uint16_t *)optinfo->opts); if (optinfo->invflags & ~IP6T_OPTS_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", optinfo->invflags & ~IP6T_OPTS_INV_MASK); } @@ -195,16 +154,14 @@ static void hbh_save(const void *ip, const struct xt_entry_match *match) const struct ip6t_opts *optinfo = (struct ip6t_opts *)match->data; if (optinfo->flags & IP6T_OPTS_LEN) { - printf("%s--hbh-len %u ", - (optinfo->invflags & IP6T_OPTS_INV_LEN) ? "! " : "", + printf("%s --hbh-len %u", + (optinfo->invflags & IP6T_OPTS_INV_LEN) ? " !" : "", optinfo->hdrlen); } if (optinfo->flags & IP6T_OPTS_OPTS) - printf("--hbh-opts "); - print_options(optinfo->optsnr, (u_int16_t *)optinfo->opts); - if (optinfo->flags & IP6T_OPTS_NSTRICT) - printf("--hbh-not-strict "); + printf(" --hbh-opts"); + print_options(optinfo->optsnr, (uint16_t *)optinfo->opts); } static struct xtables_match hbh_mt6_reg = { @@ -214,11 +171,10 @@ static struct xtables_match hbh_mt6_reg = { .size = XT_ALIGN(sizeof(struct ip6t_opts)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_opts)), .help = hbh_help, - .init = hbh_init, - .parse = hbh_parse, .print = hbh_print, .save = hbh_save, - .extra_opts = hbh_opts, + .x6_parse = hbh_parse, + .x6_options = hbh_opts, }; void diff --git a/extensions/libip6t_hl.c b/extensions/libip6t_hl.c index 09589b1..3559db4 100644 --- a/extensions/libip6t_hl.c +++ b/extensions/libip6t_hl.c @@ -5,15 +5,20 @@ * This program is released under the terms of GNU GPL * Cleanups by Stephane Ouellette <ouellettes@videotron.ca> */ - #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> #include <xtables.h> - #include <linux/netfilter_ipv6/ip6t_hl.h> +enum { + O_HL_EQ = 0, + O_HL_LT, + O_HL_GT, + F_HL_EQ = 1 << O_HL_EQ, + F_HL_LT = 1 << O_HL_LT, + F_HL_GT = 1 << O_HL_GT, + F_ANY = F_HL_EQ | F_HL_LT | F_HL_GT, +}; + static void hl_help(void) { printf( @@ -23,64 +28,27 @@ static void hl_help(void) " --hl-gt value Match HL > value\n"); } -static int hl_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void hl_parse(struct xt_option_call *cb) { - struct ip6t_hl_info *info = (struct ip6t_hl_info *) (*match)->data; - u_int8_t value; - - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - value = atoi(optarg); - - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "Can't specify HL option twice"); - - if (!optarg) - xtables_error(PARAMETER_PROBLEM, - "hl: You must specify a value"); - switch (c) { - case '2': - if (invert) - info->mode = IP6T_HL_NE; - else - info->mode = IP6T_HL_EQ; - - /* is 0 allowed? */ - info->hop_limit = value; - *flags = 1; - - break; - case '3': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "hl: unexpected `!'"); - - info->mode = IP6T_HL_LT; - info->hop_limit = value; - *flags = 1; - - break; - case '4': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "hl: unexpected `!'"); - - info->mode = IP6T_HL_GT; - info->hop_limit = value; - *flags = 1; - - break; - default: - return 0; + struct ip6t_hl_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_HL_EQ: + info->mode = cb->invert ? IP6T_HL_NE : IP6T_HL_EQ; + break; + case O_HL_LT: + info->mode = IP6T_HL_LT; + break; + case O_HL_GT: + info->mode = IP6T_HL_GT; + break; } - - return 1; } -static void hl_check(unsigned int flags) +static void hl_check(struct xt_fcheck_call *cb) { - if (!flags) + if (!(cb->xflags & F_ANY)) xtables_error(PARAMETER_PROBLEM, "HL match: You must specify one of " "`--hl-eq', `--hl-lt', `--hl-gt'"); @@ -98,7 +66,7 @@ static void hl_print(const void *ip, const struct xt_entry_match *match, const struct ip6t_hl_info *info = (struct ip6t_hl_info *) match->data; - printf("HL match HL %s %u ", op[info->mode], info->hop_limit); + printf(" HL match HL %s %u", op[info->mode], info->hop_limit); } static void hl_save(const void *ip, const struct xt_entry_match *match) @@ -112,16 +80,22 @@ static void hl_save(const void *ip, const struct xt_entry_match *match) const struct ip6t_hl_info *info = (struct ip6t_hl_info *) match->data; - printf("%s %u ", op[info->mode], info->hop_limit); + printf(" %s %u", op[info->mode], info->hop_limit); } -static const struct option hl_opts[] = { - { .name = "hl", .has_arg = 1, .val = '2' }, - { .name = "hl-eq", .has_arg = 1, .val = '2' }, - { .name = "hl-lt", .has_arg = 1, .val = '3' }, - { .name = "hl-gt", .has_arg = 1, .val = '4' }, - { .name = NULL } +#define s struct ip6t_hl_info +static const struct xt_option_entry hl_opts[] = { + {.name = "hl-lt", .id = O_HL_LT, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)}, + {.name = "hl-gt", .id = O_HL_GT, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)}, + {.name = "hl-eq", .id = O_HL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hop_limit)}, + {.name = "hl", .id = O_HL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_PUT, XTOPT_POINTER(s, hop_limit)}, + XTOPT_TABLEEND, }; +#undef s static struct xtables_match hl_mt6_reg = { .name = "hl", @@ -130,11 +104,11 @@ static struct xtables_match hl_mt6_reg = { .size = XT_ALIGN(sizeof(struct ip6t_hl_info)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_hl_info)), .help = hl_help, - .parse = hl_parse, - .final_check = hl_check, .print = hl_print, .save = hl_save, - .extra_opts = hl_opts, + .x6_parse = hl_parse, + .x6_fcheck = hl_check, + .x6_options = hl_opts, }; diff --git a/extensions/libip6t_icmp6.c b/extensions/libip6t_icmp6.c index fb321b3..68b940b 100644 --- a/extensions/libip6t_icmp6.c +++ b/extensions/libip6t_icmp6.c @@ -1,17 +1,18 @@ -/* Shared library add-on to ip6tables to add ICMP support. */ +#include <stdint.h> #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <limits.h> /* INT_MAX in ip6_tables.h */ #include <linux/netfilter_ipv6/ip6_tables.h> +enum { + O_ICMPV6_TYPE = 0, +}; + struct icmpv6_names { const char *name; - u_int8_t type; - u_int8_t code_min, code_max; + uint8_t type; + uint8_t code_min, code_max; }; static const struct icmpv6_names icmpv6_codes[] = { @@ -83,13 +84,14 @@ static void icmp6_help(void) print_icmpv6types(); } -static const struct option icmp6_opts[] = { - { "icmpv6-type", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry icmp6_opts[] = { + {.name = "icmpv6-type", .id = O_ICMPV6_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; static void -parse_icmpv6(const char *icmpv6type, u_int8_t *type, u_int8_t code[]) +parse_icmpv6(const char *icmpv6type, uint8_t *type, uint8_t code[]) { static const unsigned int limit = ARRAY_SIZE(icmpv6_codes); unsigned int match = limit; @@ -148,33 +150,18 @@ static void icmp6_init(struct xt_entry_match *m) icmpv6info->code[1] = 0xFF; } -static int icmp6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void icmp6_parse(struct xt_option_call *cb) { - struct ip6t_icmp *icmpv6info = (struct ip6t_icmp *)(*match)->data; - - switch (c) { - case '1': - if (*flags == 1) - xtables_error(PARAMETER_PROBLEM, - "icmpv6 match: only use --icmpv6-type once!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_icmpv6(optarg, &icmpv6info->type, - icmpv6info->code); - if (invert) - icmpv6info->invflags |= IP6T_ICMP_INV; - *flags = 1; - break; - - default: - return 0; - } + struct ip6t_icmp *icmpv6info = cb->data; - return 1; + xtables_option_parse(cb); + parse_icmpv6(cb->arg, &icmpv6info->type, icmpv6info->code); + if (cb->invert) + icmpv6info->invflags |= IP6T_ICMP_INV; } -static void print_icmpv6type(u_int8_t type, - u_int8_t code_min, u_int8_t code_max, +static void print_icmpv6type(uint8_t type, + uint8_t code_min, uint8_t code_max, int invert, int numeric) { @@ -188,7 +175,7 @@ static void print_icmpv6type(u_int8_t type, break; if (i != ARRAY_SIZE(icmpv6_codes)) { - printf("%s%s ", + printf(" %s%s", invert ? "!" : "", icmpv6_codes[i].name); return; @@ -196,15 +183,13 @@ static void print_icmpv6type(u_int8_t type, } if (invert) - printf("!"); + printf(" !"); printf("type %u", type); - if (code_min == 0 && code_max == 0xFF) - printf(" "); - else if (code_min == code_max) - printf(" code %u ", code_min); - else - printf(" codes %u-%u ", code_min, code_max); + if (code_min == code_max) + printf(" code %u", code_min); + else if (code_min != 0 || code_max != 0xFF) + printf(" codes %u-%u", code_min, code_max); } static void icmp6_print(const void *ip, const struct xt_entry_match *match, @@ -212,13 +197,13 @@ static void icmp6_print(const void *ip, const struct xt_entry_match *match, { const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data; - printf("ipv6-icmp "); + printf(" ipv6-icmp"); print_icmpv6type(icmpv6->type, icmpv6->code[0], icmpv6->code[1], icmpv6->invflags & IP6T_ICMP_INV, numeric); if (icmpv6->invflags & ~IP6T_ICMP_INV) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", icmpv6->invflags & ~IP6T_ICMP_INV); } @@ -227,19 +212,11 @@ static void icmp6_save(const void *ip, const struct xt_entry_match *match) const struct ip6t_icmp *icmpv6 = (struct ip6t_icmp *)match->data; if (icmpv6->invflags & IP6T_ICMP_INV) - printf("! "); + printf(" !"); - printf("--icmpv6-type %u", icmpv6->type); + printf(" --icmpv6-type %u", icmpv6->type); if (icmpv6->code[0] != 0 || icmpv6->code[1] != 0xFF) printf("/%u", icmpv6->code[0]); - printf(" "); -} - -static void icmp6_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "icmpv6 match: You must specify `--icmpv6-type'"); } static struct xtables_match icmp6_mt6_reg = { @@ -250,11 +227,10 @@ static struct xtables_match icmp6_mt6_reg = { .userspacesize = XT_ALIGN(sizeof(struct ip6t_icmp)), .help = icmp6_help, .init = icmp6_init, - .parse = icmp6_parse, - .final_check = icmp6_check, .print = icmp6_print, .save = icmp6_save, - .extra_opts = icmp6_opts, + .x6_parse = icmp6_parse, + .x6_options = icmp6_opts, }; void _init(void) diff --git a/extensions/libip6t_ipv6header.c b/extensions/libip6t_ipv6header.c index af1f5ef..00d5d5b 100644 --- a/extensions/libip6t_ipv6header.c +++ b/extensions/libip6t_ipv6header.c @@ -3,34 +3,29 @@ on whether they contain certain headers */ /* Original idea: Brad Chapman * Rewritten by: Andras Kis-Szabo <kisza@sch.bme.hu> */ - -#include <getopt.h> -#include <xtables.h> -#include <stddef.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <netdb.h> -#include <sys/types.h> - +#include <xtables.h> #include <linux/netfilter_ipv6/ip6t_ipv6header.h> -/* This maybe required -#include <linux/in.h> -#include <linux/in6.h> -*/ - +enum { + O_HEADER = 0, + O_SOFT, +}; /* A few hardcoded protocols for 'all' and in case the user has no * /etc/protocols */ struct pprot { char *name; - u_int8_t num; + uint8_t num; }; struct numflag { - u_int8_t proto; - u_int8_t flag; + uint8_t proto; + uint8_t flag; }; static const struct pprot chain_protos[] = { @@ -66,13 +61,13 @@ static const struct numflag chain_flags[] = { { IPPROTO_RAW, MASK_PROTO }, }; -static char * -proto_to_name(u_int8_t proto, int nolookup) +static const char * +proto_to_name(uint8_t proto, int nolookup) { unsigned int i; if (proto && !nolookup) { - struct protoent *pent = getprotobynumber(proto); + const struct protoent *pent = getprotobynumber(proto); if (pent) return pent->p_name; } @@ -84,11 +79,11 @@ proto_to_name(u_int8_t proto, int nolookup) return NULL; } -static u_int16_t +static uint16_t name_to_proto(const char *s) { unsigned int proto=0; - struct protoent *pent; + const struct protoent *pent; if ((pent = getprotobyname(s))) proto = pent->p_proto; @@ -139,21 +134,13 @@ static void ipv6header_help(void) "--soft The header CONTAINS the specified extensions\n"); } -static const struct option ipv6header_opts[] = { - { "header", 1, NULL, '1' }, - { "soft", 0, NULL, '2' }, - { .name = NULL } +static const struct xt_option_entry ipv6header_opts[] = { + {.name = "header", .id = O_HEADER, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT}, + {.name = "soft", .id = O_SOFT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; -static void ipv6header_init(struct xt_entry_match *m) -{ - struct ip6t_ipv6header_info *info = (struct ip6t_ipv6header_info *)m->data; - - info->matchflags = 0x00; - info->invflags = 0x00; - info->modeflag = 0x00; -} - static unsigned int parse_header(const char *flags) { unsigned int ret = 0; @@ -169,54 +156,26 @@ parse_header(const char *flags) { return ret; } -#define IPV6_HDR_HEADER 0x01 -#define IPV6_HDR_SOFT 0x02 - -static int -ipv6header_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void ipv6header_parse(struct xt_option_call *cb) { - struct ip6t_ipv6header_info *info = (struct ip6t_ipv6header_info *)(*match)->data; - - switch (c) { - case '1' : - /* Parse the provided header names */ - if (*flags & IPV6_HDR_HEADER) - xtables_error(PARAMETER_PROBLEM, - "Only one `--header' allowed"); - - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if (! (info->matchflags = parse_header(optarg)) ) - xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names"); - - if (invert) - info->invflags |= 0xFF; - *flags |= IPV6_HDR_HEADER; - break; - case '2' : - /* Soft-mode requested? */ - if (*flags & IPV6_HDR_SOFT) - xtables_error(PARAMETER_PROBLEM, - "Only one `--soft' allowed"); - - info->modeflag |= 0xFF; - *flags |= IPV6_HDR_SOFT; - break; - default: - return 0; + struct ip6t_ipv6header_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_HEADER: + if (!(info->matchflags = parse_header(cb->arg))) + xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: cannot parse header names"); + if (cb->invert) + info->invflags |= 0xFF; + break; + case O_SOFT: + info->modeflag |= 0xFF; + break; } - - return 1; -} - -static void ipv6header_check(unsigned int flags) -{ - if (!flags) xtables_error(PARAMETER_PROBLEM, "ip6t_ipv6header: no options specified"); } static void -print_header(u_int8_t flags){ +print_header(uint8_t flags){ int have_flag = 0; while (flags) { @@ -241,20 +200,19 @@ static void ipv6header_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data; - printf("ipv6header "); + printf(" ipv6header"); if (info->matchflags || info->invflags) { - printf("flags:%s", info->invflags ? "!" : ""); + printf(" flags:%s", info->invflags ? "!" : ""); if (numeric) - printf("0x%02X ", info->matchflags); + printf("0x%02X", info->matchflags); else { print_header(info->matchflags); - printf(" "); } } if (info->modeflag) - printf("soft "); + printf(" soft"); } static void ipv6header_save(const void *ip, const struct xt_entry_match *match) @@ -262,11 +220,10 @@ static void ipv6header_save(const void *ip, const struct xt_entry_match *match) const struct ip6t_ipv6header_info *info = (const struct ip6t_ipv6header_info *)match->data; - printf("%s--header ", info->invflags ? "! " : ""); + printf("%s --header ", info->invflags ? " !" : ""); print_header(info->matchflags); - printf(" "); if (info->modeflag) - printf("--soft "); + printf(" --soft"); } static struct xtables_match ipv6header_mt6_reg = { @@ -276,12 +233,10 @@ static struct xtables_match ipv6header_mt6_reg = { .size = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_ipv6header_info)), .help = ipv6header_help, - .init = ipv6header_init, - .parse = ipv6header_parse, - .final_check = ipv6header_check, .print = ipv6header_print, .save = ipv6header_save, - .extra_opts = ipv6header_opts, + .x6_parse = ipv6header_parse, + .x6_options = ipv6header_opts, }; void _init(void) diff --git a/extensions/libip6t_mh.c b/extensions/libip6t_mh.c index 95cd65d..686a293 100644 --- a/extensions/libip6t_mh.c +++ b/extensions/libip6t_mh.c @@ -11,17 +11,20 @@ * * Based on libip6t_{icmpv6,udp}.c */ +#include <stdint.h> #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter_ipv6/ip6t_mh.h> +enum { + O_MH_TYPE = 0, +}; + struct mh_name { const char *name; - u_int8_t type; + uint8_t type; }; static const struct mh_name mh_names[] = { @@ -99,7 +102,7 @@ static unsigned int name_to_type(const char *name) } } -static void parse_mh_types(const char *mhtype, u_int8_t *types) +static void parse_mh_types(const char *mhtype, uint8_t *types) { char *buffer; char *cp; @@ -121,33 +124,17 @@ static void parse_mh_types(const char *mhtype, u_int8_t *types) free(buffer); } -#define MH_TYPES 0x01 - -static int mh_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void mh_parse(struct xt_option_call *cb) { - struct ip6t_mh *mhinfo = (struct ip6t_mh *)(*match)->data; - - switch (c) { - case '1': - if (*flags & MH_TYPES) - xtables_error(PARAMETER_PROBLEM, - "Only one `--mh-type' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_mh_types(optarg, mhinfo->types); - if (invert) - mhinfo->invflags |= IP6T_MH_INV_TYPE; - *flags |= MH_TYPES; - break; - - default: - return 0; - } + struct ip6t_mh *mhinfo = cb->data; - return 1; + xtables_option_parse(cb); + parse_mh_types(cb->arg, mhinfo->types); + if (cb->invert) + mhinfo->invflags |= IP6T_MH_INV_TYPE; } -static const char *type_to_name(u_int8_t type) +static const char *type_to_name(uint8_t type) { unsigned int i; @@ -158,7 +145,7 @@ static const char *type_to_name(u_int8_t type) return NULL; } -static void print_type(u_int8_t type, int numeric) +static void print_type(uint8_t type, int numeric) { const char *name; if (numeric || !(name = type_to_name(type))) @@ -167,11 +154,12 @@ static void print_type(u_int8_t type, int numeric) printf("%s", name); } -static void print_types(u_int8_t min, u_int8_t max, int invert, int numeric) +static void print_types(uint8_t min, uint8_t max, int invert, int numeric) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFF || invert) { + printf(" "); if (min == max) { printf("%s", inv); print_type(min, numeric); @@ -181,7 +169,6 @@ static void print_types(u_int8_t min, u_int8_t max, int invert, int numeric) printf(":"); print_type(max, numeric); } - printf(" "); } } @@ -190,12 +177,12 @@ static void mh_print(const void *ip, const struct xt_entry_match *match, { const struct ip6t_mh *mhinfo = (struct ip6t_mh *)match->data; - printf("mh "); + printf(" mh"); print_types(mhinfo->types[0], mhinfo->types[1], mhinfo->invflags & IP6T_MH_INV_TYPE, numeric); if (mhinfo->invflags & ~IP6T_MH_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", mhinfo->invflags & ~IP6T_MH_INV_MASK); } @@ -207,17 +194,18 @@ static void mh_save(const void *ip, const struct xt_entry_match *match) return; if (mhinfo->invflags & IP6T_MH_INV_TYPE) - printf("! "); + printf(" !"); if (mhinfo->types[0] != mhinfo->types[1]) - printf("--mh-type %u:%u ", mhinfo->types[0], mhinfo->types[1]); + printf(" --mh-type %u:%u", mhinfo->types[0], mhinfo->types[1]); else - printf("--mh-type %u ", mhinfo->types[0]); + printf(" --mh-type %u", mhinfo->types[0]); } -static const struct option mh_opts[] = { - { "mh-type", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry mh_opts[] = { + {.name = "mh-type", .id = O_MH_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, }; static struct xtables_match mh_mt6_reg = { @@ -228,10 +216,10 @@ static struct xtables_match mh_mt6_reg = { .userspacesize = XT_ALIGN(sizeof(struct ip6t_mh)), .help = mh_help, .init = mh_init, - .parse = mh_parse, + .x6_parse = mh_parse, .print = mh_print, .save = mh_save, - .extra_opts = mh_opts, + .x6_options = mh_opts, }; void _init(void) diff --git a/extensions/libip6t_mh.man b/extensions/libip6t_mh.man index 4559e78..8ec08c6 100644 --- a/extensions/libip6t_mh.man +++ b/extensions/libip6t_mh.man @@ -8,5 +8,5 @@ a numeric MH .IR type or one of the MH type names shown by the command .nf - ip6tables \-p ipv6\-mh \-h + ip6tables \-p mh \-h .fi diff --git a/extensions/libip6t_rt.c b/extensions/libip6t_rt.c index a04023d..d470488 100644 --- a/extensions/libip6t_rt.c +++ b/extensions/libip6t_rt.c @@ -1,18 +1,20 @@ -/* Shared library add-on to ip6tables to add Routing header support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> -#include <errno.h> #include <xtables.h> -/*#include <linux/in6.h>*/ #include <linux/netfilter_ipv6/ip6t_rt.h> -#include <sys/types.h> -#include <sys/socket.h> #include <arpa/inet.h> -/*#define DEBUG 1*/ +enum { + O_RT_TYPE = 0, + O_RT_SEGSLEFT, + O_RT_LEN, + O_RT0RES, + O_RT0ADDRS, + O_RT0NSTRICT, + F_RT_TYPE = 1 << O_RT_TYPE, + F_RT0ADDRS = 1 << O_RT0ADDRS, +}; static void rt_help(void) { @@ -21,70 +23,32 @@ static void rt_help(void) "[!] --rt-type type match the type\n" "[!] --rt-segsleft num[:num] match the Segments Left field (range)\n" "[!] --rt-len length total length of this header\n" -" --rt-0-res check the reserved filed, too (type 0)\n" +" --rt-0-res check the reserved field too (type 0)\n" " --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n" " --rt-0-not-strict List of Type=0 addresses not a strict list\n", IP6T_RT_HOPS); } -static const struct option rt_opts[] = { - { "rt-type", 1, NULL, '1' }, - { "rt-segsleft", 1, NULL, '2' }, - { "rt-len", 1, NULL, '3' }, - { "rt-0-res", 0, NULL, '4' }, - { "rt-0-addrs", 1, NULL, '5' }, - { "rt-0-not-strict", 0, NULL, '6' }, - { .name = NULL } +#define s struct ip6t_rt +static const struct xt_option_entry rt_opts[] = { + {.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, rt_type)}, + {.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)}, + {.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)}, + {.name = "rt-0-res", .id = O_RT0RES, .type = XTTYPE_NONE}, + {.name = "rt-0-addrs", .id = O_RT0ADDRS, .type = XTTYPE_STRING}, + {.name = "rt-0-not-strict", .id = O_RT0NSTRICT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s -static u_int32_t -parse_rt_num(const char *idstr, const char *typestr) -{ - unsigned long int id; - char* ep; - - id = strtoul(idstr,&ep,0) ; - - if ( idstr == ep ) { - xtables_error(PARAMETER_PROBLEM, - "RT no valid digits in %s `%s'", typestr, idstr); - } - if ( id == ULONG_MAX && errno == ERANGE ) { - xtables_error(PARAMETER_PROBLEM, - "%s `%s' specified too big: would overflow", - typestr, idstr); - } - if ( *idstr != '\0' && *ep != '\0' ) { - xtables_error(PARAMETER_PROBLEM, - "RT error parsing %s `%s'", typestr, idstr); - } - return id; -} - -static void -parse_rt_segsleft(const char *idstring, u_int32_t *ids) -{ - char *buffer; - char *cp; - - buffer = strdup(idstring); - if ((cp = strchr(buffer, ':')) == NULL) - ids[0] = ids[1] = parse_rt_num(buffer,"segsleft"); - else { - *cp = '\0'; - cp++; - - ids[0] = buffer[0] ? parse_rt_num(buffer,"segsleft") : 0; - ids[1] = cp[0] ? parse_rt_num(cp,"segsleft") : 0xFFFFFFFF; - } - free(buffer); -} - -static char * +static const char * addr_to_numeric(const struct in6_addr *addrp) { static char buf[50+1]; - return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); + return inet_ntop(AF_INET6, addrp, buf, sizeof(buf)); } static struct in6_addr * @@ -135,108 +99,61 @@ parse_addresses(const char *addrstr, struct in6_addr *addrp) return i; } -static void rt_init(struct xt_entry_match *m) +static void rt_parse(struct xt_option_call *cb) { - struct ip6t_rt *rtinfo = (struct ip6t_rt *)m->data; - - rtinfo->rt_type = 0x0L; - rtinfo->segsleft[0] = 0x0L; - rtinfo->segsleft[1] = 0xFFFFFFFF; - rtinfo->hdrlen = 0; - rtinfo->flags = 0; - rtinfo->invflags = 0; - rtinfo->addrnr = 0; -} + struct ip6t_rt *rtinfo = cb->data; -static int rt_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ip6t_rt *rtinfo = (struct ip6t_rt *)(*match)->data; - - switch (c) { - case '1': - if (*flags & IP6T_RT_TYP) - xtables_error(PARAMETER_PROBLEM, - "Only one `--rt-type' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - rtinfo->rt_type = parse_rt_num(optarg, "type"); - if (invert) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_RT_TYPE: + if (cb->invert) rtinfo->invflags |= IP6T_RT_INV_TYP; rtinfo->flags |= IP6T_RT_TYP; - *flags |= IP6T_RT_TYP; break; - case '2': - if (*flags & IP6T_RT_SGS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--rt-segsleft' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_rt_segsleft(optarg, rtinfo->segsleft); - if (invert) + case O_RT_SEGSLEFT: + if (cb->nvals == 1) + rtinfo->segsleft[1] = rtinfo->segsleft[0]; + if (cb->invert) rtinfo->invflags |= IP6T_RT_INV_SGS; rtinfo->flags |= IP6T_RT_SGS; - *flags |= IP6T_RT_SGS; break; - case '3': - if (*flags & IP6T_RT_LEN) - xtables_error(PARAMETER_PROBLEM, - "Only one `--rt-len' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - rtinfo->hdrlen = parse_rt_num(optarg, "length"); - if (invert) + case O_RT_LEN: + if (cb->invert) rtinfo->invflags |= IP6T_RT_INV_LEN; rtinfo->flags |= IP6T_RT_LEN; - *flags |= IP6T_RT_LEN; break; - case '4': - if (*flags & IP6T_RT_RES) - xtables_error(PARAMETER_PROBLEM, - "Only one `--rt-0-res' allowed"); - if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) ) + case O_RT0RES: + if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 || + rtinfo->invflags & IP6T_RT_INV_TYP) xtables_error(PARAMETER_PROBLEM, "`--rt-type 0' required before `--rt-0-res'"); rtinfo->flags |= IP6T_RT_RES; - *flags |= IP6T_RT_RES; break; - case '5': - if (*flags & IP6T_RT_FST) - xtables_error(PARAMETER_PROBLEM, - "Only one `--rt-0-addrs' allowed"); - if ( !(*flags & IP6T_RT_TYP) || (rtinfo->rt_type != 0) || (rtinfo->invflags & IP6T_RT_INV_TYP) ) + case O_RT0ADDRS: + if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 || + rtinfo->invflags & IP6T_RT_INV_TYP) xtables_error(PARAMETER_PROBLEM, "`--rt-type 0' required before `--rt-0-addrs'"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) - xtables_error(PARAMETER_PROBLEM, - " '!' not allowed with `--rt-0-addrs'"); - rtinfo->addrnr = parse_addresses(optarg, rtinfo->addrs); + rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs); rtinfo->flags |= IP6T_RT_FST; - *flags |= IP6T_RT_FST; break; - case '6': - if (*flags & IP6T_RT_FST_NSTRICT) - xtables_error(PARAMETER_PROBLEM, - "Only one `--rt-0-not-strict' allowed"); - if ( !(*flags & IP6T_RT_FST) ) + case O_RT0NSTRICT: + if (!(cb->xflags & F_RT0ADDRS)) xtables_error(PARAMETER_PROBLEM, "`--rt-0-addr ...' required before `--rt-0-not-strict'"); rtinfo->flags |= IP6T_RT_FST_NSTRICT; - *flags |= IP6T_RT_FST_NSTRICT; break; - default: - return 0; } - - return 1; } static void -print_nums(const char *name, u_int32_t min, u_int32_t max, +print_nums(const char *name, uint32_t min, uint32_t max, int invert) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFFFFFFFF || invert) { - printf("%s", name); + printf(" %s", name); if (min == max) { printf(":%s", inv); printf("%u", min); @@ -246,7 +163,6 @@ print_nums(const char *name, u_int32_t min, u_int32_t max, printf(":"); printf("%u",max); } - printf(" "); } } @@ -256,7 +172,7 @@ print_addresses(unsigned int addrnr, struct in6_addr *addrp) unsigned int i; for(i=0; i<addrnr; i++){ - printf("%s%c", addr_to_numeric(&(addrp[i])), (i!=addrnr-1)?',':' '); + printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i]))); } } @@ -265,24 +181,23 @@ static void rt_print(const void *ip, const struct xt_entry_match *match, { const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; - printf("rt "); + printf(" rt"); if (rtinfo->flags & IP6T_RT_TYP) - printf("type:%s%d ", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "", + printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "", rtinfo->rt_type); print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1], rtinfo->invflags & IP6T_RT_INV_SGS); if (rtinfo->flags & IP6T_RT_LEN) { - printf("length"); + printf(" length"); printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : ""); printf("%u", rtinfo->hdrlen); - printf(" "); } - if (rtinfo->flags & IP6T_RT_RES) printf("reserved "); - if (rtinfo->flags & IP6T_RT_FST) printf("0-addrs "); + if (rtinfo->flags & IP6T_RT_RES) printf(" reserved"); + if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs"); print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); - if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("0-not-strict "); + if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict"); if (rtinfo->invflags & ~IP6T_RT_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", rtinfo->invflags & ~IP6T_RT_INV_MASK); } @@ -291,35 +206,35 @@ static void rt_save(const void *ip, const struct xt_entry_match *match) const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data; if (rtinfo->flags & IP6T_RT_TYP) { - printf("%s--rt-type %u ", - (rtinfo->invflags & IP6T_RT_INV_TYP) ? "! " : "", + printf("%s --rt-type %u", + (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "", rtinfo->rt_type); } if (!(rtinfo->segsleft[0] == 0 && rtinfo->segsleft[1] == 0xFFFFFFFF)) { - printf("%s--rt-segsleft ", - (rtinfo->invflags & IP6T_RT_INV_SGS) ? "! " : ""); + printf("%s --rt-segsleft ", + (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : ""); if (rtinfo->segsleft[0] != rtinfo->segsleft[1]) - printf("%u:%u ", + printf("%u:%u", rtinfo->segsleft[0], rtinfo->segsleft[1]); else - printf("%u ", + printf("%u", rtinfo->segsleft[0]); } if (rtinfo->flags & IP6T_RT_LEN) { - printf("%s--rt-len %u ", - (rtinfo->invflags & IP6T_RT_INV_LEN) ? "! " : "", + printf("%s --rt-len %u", + (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "", rtinfo->hdrlen); } - if (rtinfo->flags & IP6T_RT_RES) printf("--rt-0-res "); - if (rtinfo->flags & IP6T_RT_FST) printf("--rt-0-addrs "); + if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res"); + if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs"); print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs); - if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf("--rt-0-not-strict "); + if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict"); } @@ -330,11 +245,10 @@ static struct xtables_match rt_mt6_reg = { .size = XT_ALIGN(sizeof(struct ip6t_rt)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)), .help = rt_help, - .init = rt_init, - .parse = rt_parse, + .x6_parse = rt_parse, .print = rt_print, .save = rt_save, - .extra_opts = rt_opts, + .x6_options = rt_opts, }; void diff --git a/extensions/libipt_CLUSTERIP.c b/extensions/libipt_CLUSTERIP.c index 279aacf..f4b638b 100644 --- a/extensions/libipt_CLUSTERIP.c +++ b/extensions/libipt_CLUSTERIP.c @@ -3,6 +3,7 @@ * * Development of this code was funded by SuSE AG, http://www.suse.com/ */ +#include <stdbool.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -18,6 +19,22 @@ #include <xtables.h> #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> +enum { + O_NEW = 0, + O_HASHMODE, + O_CLUSTERMAC, + O_TOTAL_NODES, + O_LOCAL_NODE, + O_HASH_INIT, + F_NEW = 1 << O_NEW, + F_HASHMODE = 1 << O_HASHMODE, + F_CLUSTERMAC = 1 << O_CLUSTERMAC, + F_TOTAL_NODES = 1 << O_TOTAL_NODES, + F_LOCAL_NODE = 1 << O_LOCAL_NODE, + F_FULL = F_NEW | F_HASHMODE | F_CLUSTERMAC | + F_TOTAL_NODES | F_LOCAL_NODE, +}; + static void CLUSTERIP_help(void) { printf( @@ -33,140 +50,69 @@ static void CLUSTERIP_help(void) " --hash-init <num> Set init value of the Jenkins hash\n"); } -#define PARAM_NEW 0x0001 -#define PARAM_HMODE 0x0002 -#define PARAM_MAC 0x0004 -#define PARAM_TOTALNODE 0x0008 -#define PARAM_LOCALNODE 0x0010 -#define PARAM_HASHINIT 0x0020 - -static const struct option CLUSTERIP_opts[] = { - { "new", 0, NULL, '1' }, - { "hashmode", 1, NULL, '2' }, - { "clustermac", 1, NULL, '3' }, - { "total-nodes", 1, NULL, '4' }, - { "local-node", 1, NULL, '5' }, - { "hash-init", 1, NULL, '6' }, - { .name = NULL } +#define s struct ipt_clusterip_tgt_info +static const struct xt_option_entry CLUSTERIP_opts[] = { + {.name = "new", .id = O_NEW, .type = XTTYPE_NONE}, + {.name = "hashmode", .id = O_HASHMODE, .type = XTTYPE_STRING, + .also = O_NEW}, + {.name = "clustermac", .id = O_CLUSTERMAC, .type = XTTYPE_ETHERMAC, + .also = O_NEW, .flags = XTOPT_PUT, XTOPT_POINTER(s, clustermac)}, + {.name = "total-nodes", .id = O_TOTAL_NODES, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, num_total_nodes), + .also = O_NEW, .max = CLUSTERIP_MAX_NODES}, + {.name = "local-node", .id = O_LOCAL_NODE, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, local_nodes[0]), + .also = O_NEW, .max = CLUSTERIP_MAX_NODES}, + {.name = "hash-init", .id = O_HASH_INIT, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, hash_initval), + .also = O_NEW, .max = UINT_MAX}, + XTOPT_TABLEEND, }; +#undef s -static void -parse_mac(const char *mac, char *macbuf) +static void CLUSTERIP_parse(struct xt_option_call *cb) { - unsigned int i = 0; - - if (strlen(mac) != ETH_ALEN*3-1) - xtables_error(PARAMETER_PROBLEM, "Bad mac address \"%s\"", mac); - - for (i = 0; i < ETH_ALEN; i++) { - long number; - char *end; + struct ipt_clusterip_tgt_info *cipinfo = cb->data; - number = strtol(mac + i*3, &end, 16); - - if (end == mac + i*3 + 2 - && number >= 0 - && number <= 255) - macbuf[i] = number; - else - xtables_error(PARAMETER_PROBLEM, - "Bad mac address `%s'", mac); - } -} - -static int CLUSTERIP_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) -{ - struct ipt_clusterip_tgt_info *cipinfo - = (struct ipt_clusterip_tgt_info *)(*target)->data; - - switch (c) { - unsigned int num; - case '1': + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_NEW: cipinfo->flags |= CLUSTERIP_FLAG_NEW; - if (*flags & PARAM_NEW) - xtables_error(PARAMETER_PROBLEM, "Can only specify \"--new\" once\n"); - *flags |= PARAM_NEW; break; - case '2': - if (!(*flags & PARAM_NEW)) - xtables_error(PARAMETER_PROBLEM, "Can only specify hashmode combined with \"--new\"\n"); - if (*flags & PARAM_HMODE) - xtables_error(PARAMETER_PROBLEM, "Can only specify hashmode once\n"); - if (!strcmp(optarg, "sourceip")) + case O_HASHMODE: + if (strcmp(cb->arg, "sourceip") == 0) cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP; - else if (!strcmp(optarg, "sourceip-sourceport")) + else if (strcmp(cb->arg, "sourceip-sourceport") == 0) cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT; - else if (!strcmp(optarg, "sourceip-sourceport-destport")) + else if (strcmp(cb->arg, "sourceip-sourceport-destport") == 0) cipinfo->hash_mode = CLUSTERIP_HASHMODE_SIP_SPT_DPT; else xtables_error(PARAMETER_PROBLEM, "Unknown hashmode \"%s\"\n", - optarg); - *flags |= PARAM_HMODE; + cb->arg); break; - case '3': - if (!(*flags & PARAM_NEW)) - xtables_error(PARAMETER_PROBLEM, "Can only specify MAC combined with \"--new\"\n"); - if (*flags & PARAM_MAC) - xtables_error(PARAMETER_PROBLEM, "Can only specify MAC once\n"); - parse_mac(optarg, (char *)cipinfo->clustermac); + case O_CLUSTERMAC: if (!(cipinfo->clustermac[0] & 0x01)) xtables_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n"); - *flags |= PARAM_MAC; - break; - case '4': - if (!(*flags & PARAM_NEW)) - xtables_error(PARAMETER_PROBLEM, "Can only specify node number combined with \"--new\"\n"); - if (*flags & PARAM_TOTALNODE) - xtables_error(PARAMETER_PROBLEM, "Can only specify total node number once\n"); - if (!xtables_strtoui(optarg, NULL, &num, 1, CLUSTERIP_MAX_NODES)) - xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg); - cipinfo->num_total_nodes = num; - *flags |= PARAM_TOTALNODE; break; - case '5': - if (!(*flags & PARAM_NEW)) - xtables_error(PARAMETER_PROBLEM, "Can only specify node number combined with \"--new\"\n"); - if (*flags & PARAM_LOCALNODE) - xtables_error(PARAMETER_PROBLEM, "Can only specify local node number once\n"); - if (!xtables_strtoui(optarg, NULL, &num, 1, CLUSTERIP_MAX_NODES)) - xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg); + case O_LOCAL_NODE: cipinfo->num_local_nodes = 1; - cipinfo->local_nodes[0] = num; - *flags |= PARAM_LOCALNODE; break; - case '6': - if (!(*flags & PARAM_NEW)) - xtables_error(PARAMETER_PROBLEM, "Can only specify hash init value combined with \"--new\"\n"); - if (*flags & PARAM_HASHINIT) - xtables_error(PARAMETER_PROBLEM, "Can specify hash init value only once\n"); - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT_MAX)) - xtables_error(PARAMETER_PROBLEM, "Unable to parse \"%s\"\n", optarg); - cipinfo->hash_initval = num; - *flags |= PARAM_HASHINIT; - break; - default: - return 0; } - - return 1; } -static void CLUSTERIP_check(unsigned int flags) +static void CLUSTERIP_check(struct xt_fcheck_call *cb) { - if (flags == 0) + if (cb->xflags == 0) return; - - if ((flags & (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE)) - == (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE)) + if ((cb->xflags & F_FULL) == F_FULL) return; xtables_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n"); } -static char *hashmode2str(enum clusterip_hashmode mode) +static const char *hashmode2str(enum clusterip_hashmode mode) { - char *retstr; + const char *retstr; switch (mode) { case CLUSTERIP_HASHMODE_SIP: retstr = "sourceip"; @@ -184,7 +130,7 @@ static char *hashmode2str(enum clusterip_hashmode mode) return retstr; } -static char *mac2str(const u_int8_t mac[ETH_ALEN]) +static const char *mac2str(const uint8_t mac[ETH_ALEN]) { static char buf[ETH_ALEN*3]; sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", @@ -198,12 +144,12 @@ static void CLUSTERIP_print(const void *ip, const struct ipt_clusterip_tgt_info *cipinfo = (const struct ipt_clusterip_tgt_info *)target->data; - if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) { - printf("CLUSTERIP"); + if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { + printf(" CLUSTERIP"); return; } - printf("CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u", + printf(" CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%u hash_init=%u", hashmode2str(cipinfo->hash_mode), mac2str(cipinfo->clustermac), cipinfo->num_total_nodes, @@ -218,10 +164,10 @@ static void CLUSTERIP_save(const void *ip, const struct xt_entry_target *target) /* if this is not a new entry, we don't need to save target * parameters */ - if (!cipinfo->flags & CLUSTERIP_FLAG_NEW) + if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) return; - printf("--new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u", + printf(" --new --hashmode %s --clustermac %s --total-nodes %d --local-node %d --hash-init %u", hashmode2str(cipinfo->hash_mode), mac2str(cipinfo->clustermac), cipinfo->num_total_nodes, @@ -236,11 +182,11 @@ static struct xtables_target clusterip_tg_reg = { .size = XT_ALIGN(sizeof(struct ipt_clusterip_tgt_info)), .userspacesize = offsetof(struct ipt_clusterip_tgt_info, config), .help = CLUSTERIP_help, - .parse = CLUSTERIP_parse, - .final_check = CLUSTERIP_check, + .x6_parse = CLUSTERIP_parse, + .x6_fcheck = CLUSTERIP_check, .print = CLUSTERIP_print, .save = CLUSTERIP_save, - .extra_opts = CLUSTERIP_opts, + .x6_options = CLUSTERIP_opts, }; void _init(void) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index 57c5888..ff18799 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -1,44 +1,50 @@ -/* Shared library add-on to iptables to add destination-NAT support. */ #include <stdio.h> #include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <iptables.h> /* get_kernel_version */ #include <limits.h> /* INT_MAX in ip_tables.h */ #include <linux/netfilter_ipv4/ip_tables.h> -#include <net/netfilter/nf_nat.h> - -#define IPT_DNAT_OPT_DEST 0x1 -#define IPT_DNAT_OPT_RANDOM 0x2 +#include <linux/netfilter/nf_nat.h> + +enum { + O_TO_DEST = 0, + O_RANDOM, + O_PERSISTENT, + O_X_TO_DEST, /* hidden flag */ + F_TO_DEST = 1 << O_TO_DEST, + F_RANDOM = 1 << O_RANDOM, + F_X_TO_DEST = 1 << O_X_TO_DEST, +}; /* Dest NAT data consists of a multi-range, indicating where to map to. */ struct ipt_natinfo { struct xt_entry_target t; - struct nf_nat_multi_range mr; + struct nf_nat_ipv4_multi_range_compat mr; }; static void DNAT_help(void) { printf( "DNAT target options:\n" -" --to-destination <ipaddr>[-<ipaddr>][:port-port]\n" +" --to-destination [<ipaddr>[-<ipaddr>]][:port[-port]]\n" " Address to map destination to.\n" "[--random] [--persistent]\n"); } -static const struct option DNAT_opts[] = { - { "to-destination", 1, NULL, '1' }, - { "random", 0, NULL, '2' }, - { "persistent", 0, NULL, '3' }, - { .name = NULL } +static const struct xt_option_entry DNAT_opts[] = { + {.name = "to-destination", .id = O_TO_DEST, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_MULTI}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; static struct ipt_natinfo * -append_range(struct ipt_natinfo *info, const struct nf_nat_range *range) +append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range) { unsigned int size; @@ -58,12 +64,15 @@ append_range(struct ipt_natinfo *info, const struct nf_nat_range *range) /* Ranges expected in network order. */ static struct xt_entry_target * -parse_to(char *arg, int portok, struct ipt_natinfo *info) +parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) { - struct nf_nat_range range; - char *colon, *dash, *error; + struct nf_nat_ipv4_range range; + char *arg, *colon, *dash, *error; const struct in_addr *ip; + arg = strdup(orig_arg); + if (arg == NULL) + xtables_error(RESOURCE_PROBLEM, "strdup"); memset(&range, 0, sizeof(range)); colon = strchr(arg, ':'); @@ -74,7 +83,7 @@ parse_to(char *arg, int portok, struct ipt_natinfo *info) xtables_error(PARAMETER_PROBLEM, "Need TCP, UDP, SCTP or DCCP with port specification"); - range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; port = atoi(colon+1); if (port <= 0 || port > 65535) @@ -106,12 +115,14 @@ parse_to(char *arg, int portok, struct ipt_natinfo *info) range.max.tcp.port = htons(maxport); } /* Starts with a colon? No IP info...*/ - if (colon == arg) + if (colon == arg) { + free(arg); return &(append_range(info, &range)->t); + } *colon = '\0'; } - range.flags |= IP_NAT_RANGE_MAP_IPS; + range.flags |= NF_NAT_RANGE_MAP_IPS; dash = strchr(arg, '-'); if (colon && dash && dash > colon) dash = NULL; @@ -133,14 +144,14 @@ parse_to(char *arg, int portok, struct ipt_natinfo *info) } else range.max_ip = range.min_ip; + free(arg); return &(append_range(info, &range)->t); } -static int DNAT_parse(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_target **target) +static void DNAT_parse(struct xt_option_call *cb) { - const struct ipt_entry *entry = e; - struct ipt_natinfo *info = (void *)*target; + const struct ipt_entry *entry = cb->xt_entry; + struct ipt_natinfo *info = (void *)(*cb->target); int portok; if (entry->ip.proto == IPPROTO_TCP @@ -152,53 +163,37 @@ static int DNAT_parse(int c, char **argv, int invert, unsigned int *flags, else portok = 0; - switch (c) { - case '1': - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --to-destination"); - - if (*flags & IPT_DNAT_OPT_DEST) { + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_DEST: + if (cb->xflags & F_X_TO_DEST) { if (!kernel_version) get_kernel_version(); if (kernel_version > LINUX_VERSION(2, 6, 10)) xtables_error(PARAMETER_PROBLEM, - "Multiple --to-destination not supported"); + "DNAT: Multiple --to-destination not supported"); } - *target = parse_to(optarg, portok, info); - /* WTF do we need this for?? */ - if (*flags & IPT_DNAT_OPT_RANDOM) - info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; - *flags |= IPT_DNAT_OPT_DEST; - return 1; - - case '2': - if (*flags & IPT_DNAT_OPT_DEST) { - info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; - *flags |= IPT_DNAT_OPT_RANDOM; - } else - *flags |= IPT_DNAT_OPT_RANDOM; - return 1; - - case '3': - info->mr.range[0].flags |= IP_NAT_RANGE_PERSISTENT; - return 1; - - default: - return 0; + *cb->target = parse_to(cb->arg, portok, info); + cb->xflags |= F_X_TO_DEST; + break; + case O_PERSISTENT: + info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT; + break; } } -static void DNAT_check(unsigned int flags) +static void DNAT_fcheck(struct xt_fcheck_call *cb) { - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "You must specify --to-destination"); + static const unsigned int f = F_TO_DEST | F_RANDOM; + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + + if ((cb->xflags & f) == f) + mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; } -static void print_range(const struct nf_nat_range *r) +static void print_range(const struct nf_nat_ipv4_range *r) { - if (r->flags & IP_NAT_RANGE_MAP_IPS) { + if (r->flags & NF_NAT_RANGE_MAP_IPS) { struct in_addr a; a.s_addr = r->min_ip; @@ -208,7 +203,7 @@ static void print_range(const struct nf_nat_range *r) printf("-%s", xtables_ipaddr_to_numeric(&a)); } } - if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { printf(":"); printf("%hu", ntohs(r->min.tcp.port)); if (r->max.tcp.port != r->min.tcp.port) @@ -222,14 +217,13 @@ static void DNAT_print(const void *ip, const struct xt_entry_target *target, const struct ipt_natinfo *info = (const void *)target; unsigned int i = 0; - printf("to:"); + printf(" to:"); for (i = 0; i < info->mr.rangesize; i++) { print_range(&info->mr.range[i]); - printf(" "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("random "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT) - printf("persistent "); + if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); + if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) + printf(" persistent"); } } @@ -239,13 +233,12 @@ static void DNAT_save(const void *ip, const struct xt_entry_target *target) unsigned int i = 0; for (i = 0; i < info->mr.rangesize; i++) { - printf("--to-destination "); + printf(" --to-destination "); print_range(&info->mr.range[i]); - printf(" "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("--random "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT) - printf("--persistent "); + if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); + if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) + printf(" --persistent"); } } @@ -253,14 +246,14 @@ static struct xtables_target dnat_tg_reg = { .name = "DNAT", .version = XTABLES_VERSION, .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), .help = DNAT_help, - .parse = DNAT_parse, - .final_check = DNAT_check, + .x6_parse = DNAT_parse, + .x6_fcheck = DNAT_fcheck, .print = DNAT_print, .save = DNAT_save, - .extra_opts = DNAT_opts, + .x6_options = DNAT_opts, }; void _init(void) diff --git a/extensions/libipt_ECN.c b/extensions/libipt_ECN.c index bf1f8a5..ee09f29 100644 --- a/extensions/libipt_ECN.c +++ b/extensions/libipt_ECN.c @@ -5,17 +5,21 @@ * This program is distributed under the terms of GNU GPL v2, 1991 * * libipt_ECN.c borrowed heavily from libipt_DSCP.c - * - * $Id$ */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter_ipv4/ipt_ECN.h> +enum { + O_ECN_TCP_REMOVE = 0, + O_ECN_TCP_CWR, + O_ECN_TCP_ECE, + O_ECN_IP_ECT, + F_ECN_TCP_REMOVE = 1 << O_ECN_TCP_REMOVE, + F_ECN_TCP_CWR = 1 << O_ECN_TCP_CWR, + F_ECN_TCP_ECE = 1 << O_ECN_TCP_ECE, +}; + static void ECN_help(void) { printf( @@ -30,77 +34,49 @@ static void ECN_help(void) " --ecn-tcp-ece Set the IPv4 ECE bit (0 or 1)\n", #endif - -static const struct option ECN_opts[] = { - { "ecn-tcp-remove", 0, NULL, 'F' }, - { "ecn-tcp-cwr", 1, NULL, 'G' }, - { "ecn-tcp-ece", 1, NULL, 'H' }, - { "ecn-ip-ect", 1, NULL, '9' }, - { .name = NULL } +static const struct xt_option_entry ECN_opts[] = { + {.name = "ecn-tcp-remove", .id = O_ECN_TCP_REMOVE, .type = XTTYPE_NONE, + .excl = F_ECN_TCP_CWR | F_ECN_TCP_ECE}, + {.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_UINT8, + .min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE}, + {.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_UINT8, + .min = 0, .max = 1, .excl = F_ECN_TCP_REMOVE}, + {.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8, + .min = 0, .max = 3}, + XTOPT_TABLEEND, }; -static int ECN_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void ECN_parse(struct xt_option_call *cb) { - unsigned int result; - struct ipt_ECN_info *einfo - = (struct ipt_ECN_info *)(*target)->data; - - switch (c) { - case 'F': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-tcp-remove ONCE!"); + struct ipt_ECN_info *einfo = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_ECN_TCP_REMOVE: einfo->operation = IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR; einfo->proto.tcp.ece = 0; einfo->proto.tcp.cwr = 0; - *flags = 1; break; - case 'G': - if (*flags & IPT_ECN_OP_SET_CWR) - xtables_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-tcp-cwr ONCE!"); - if (!xtables_strtoui(optarg, NULL, &result, 0, 1)) - xtables_error(PARAMETER_PROBLEM, - "ECN target: Value out of range"); + case O_ECN_TCP_CWR: einfo->operation |= IPT_ECN_OP_SET_CWR; - einfo->proto.tcp.cwr = result; - *flags |= IPT_ECN_OP_SET_CWR; + einfo->proto.tcp.cwr = cb->val.u8; break; - case 'H': - if (*flags & IPT_ECN_OP_SET_ECE) - xtables_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-tcp-ece ONCE!"); - if (!xtables_strtoui(optarg, NULL, &result, 0, 1)) - xtables_error(PARAMETER_PROBLEM, - "ECN target: Value out of range"); + case O_ECN_TCP_ECE: einfo->operation |= IPT_ECN_OP_SET_ECE; - einfo->proto.tcp.ece = result; - *flags |= IPT_ECN_OP_SET_ECE; + einfo->proto.tcp.ece = cb->val.u8; break; - case '9': - if (*flags & IPT_ECN_OP_SET_IP) - xtables_error(PARAMETER_PROBLEM, - "ECN target: Only use --ecn-ip-ect ONCE!"); - if (!xtables_strtoui(optarg, NULL, &result, 0, 3)) - xtables_error(PARAMETER_PROBLEM, - "ECN target: Value out of range"); + case O_ECN_IP_ECT: einfo->operation |= IPT_ECN_OP_SET_IP; - einfo->ip_ect = result; - *flags |= IPT_ECN_OP_SET_IP; + einfo->ip_ect = cb->val.u8; break; - default: - return 0; } - - return 1; } -static void ECN_check(unsigned int flags) +static void ECN_check(struct xt_fcheck_call *cb) { - if (!flags) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, - "ECN target: Parameter --ecn-tcp-remove is required"); + "ECN target: An operation is required"); } static void ECN_print(const void *ip, const struct xt_entry_target *target, @@ -109,21 +85,21 @@ static void ECN_print(const void *ip, const struct xt_entry_target *target, const struct ipt_ECN_info *einfo = (const struct ipt_ECN_info *)target->data; - printf("ECN "); + printf(" ECN"); if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) && einfo->proto.tcp.ece == 0 && einfo->proto.tcp.cwr == 0) - printf("TCP remove "); + printf(" TCP remove"); else { if (einfo->operation & IPT_ECN_OP_SET_ECE) - printf("ECE=%u ", einfo->proto.tcp.ece); + printf(" ECE=%u", einfo->proto.tcp.ece); if (einfo->operation & IPT_ECN_OP_SET_CWR) - printf("CWR=%u ", einfo->proto.tcp.cwr); + printf(" CWR=%u", einfo->proto.tcp.cwr); if (einfo->operation & IPT_ECN_OP_SET_IP) - printf("ECT codepoint=%u ", einfo->ip_ect); + printf(" ECT codepoint=%u", einfo->ip_ect); } } @@ -135,17 +111,17 @@ static void ECN_save(const void *ip, const struct xt_entry_target *target) if (einfo->operation == (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR) && einfo->proto.tcp.ece == 0 && einfo->proto.tcp.cwr == 0) - printf("--ecn-tcp-remove "); + printf(" --ecn-tcp-remove"); else { if (einfo->operation & IPT_ECN_OP_SET_ECE) - printf("--ecn-tcp-ece %d ", einfo->proto.tcp.ece); + printf(" --ecn-tcp-ece %d", einfo->proto.tcp.ece); if (einfo->operation & IPT_ECN_OP_SET_CWR) - printf("--ecn-tcp-cwr %d ", einfo->proto.tcp.cwr); + printf(" --ecn-tcp-cwr %d", einfo->proto.tcp.cwr); if (einfo->operation & IPT_ECN_OP_SET_IP) - printf("--ecn-ip-ect %d ", einfo->ip_ect); + printf(" --ecn-ip-ect %d", einfo->ip_ect); } } @@ -156,11 +132,11 @@ static struct xtables_target ecn_tg_reg = { .size = XT_ALIGN(sizeof(struct ipt_ECN_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_ECN_info)), .help = ECN_help, - .parse = ECN_parse, - .final_check = ECN_check, .print = ECN_print, .save = ECN_save, - .extra_opts = ECN_opts, + .x6_parse = ECN_parse, + .x6_fcheck = ECN_check, + .x6_options = ECN_opts, }; void _init(void) diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c index 9afb91d..77f16d1 100644 --- a/extensions/libipt_LOG.c +++ b/extensions/libipt_LOG.c @@ -1,10 +1,6 @@ -/* Shared library add-on to iptables to add LOG support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> #include <syslog.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter_ipv4/ipt_LOG.h> @@ -16,6 +12,16 @@ #define IPT_LOG_MASK 0x0f #endif +enum { + O_LOG_LEVEL = 0, + O_LOG_PREFIX, + O_LOG_TCPSEQ, + O_LOG_TCPOPTS, + O_LOG_IPOPTS, + O_LOG_UID, + O_LOG_MAC, +}; + static void LOG_help(void) { printf( @@ -25,18 +31,24 @@ static void LOG_help(void) " --log-tcp-sequence Log TCP sequence numbers.\n\n" " --log-tcp-options Log TCP options.\n\n" " --log-ip-options Log IP options.\n\n" -" --log-uid Log UID owning the local socket.\n\n"); +" --log-uid Log UID owning the local socket.\n\n" +" --log-macdecode Decode MAC addresses and protocol.\n\n"); } -static const struct option LOG_opts[] = { - { .name = "log-level", .has_arg = 1, .val = '!' }, - { .name = "log-prefix", .has_arg = 1, .val = '#' }, - { .name = "log-tcp-sequence", .has_arg = 0, .val = '1' }, - { .name = "log-tcp-options", .has_arg = 0, .val = '2' }, - { .name = "log-ip-options", .has_arg = 0, .val = '3' }, - { .name = "log-uid", .has_arg = 0, .val = '4' }, - { .name = NULL } +#define s struct ipt_log_info +static const struct xt_option_entry LOG_opts[] = { + {.name = "log-level", .id = O_LOG_LEVEL, .type = XTTYPE_SYSLOGLEVEL, + .flags = XTOPT_PUT, XTOPT_POINTER(s, level)}, + {.name = "log-prefix", .id = O_LOG_PREFIX, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix), .min = 1}, + {.name = "log-tcp-sequence", .id = O_LOG_TCPSEQ, .type = XTTYPE_NONE}, + {.name = "log-tcp-options", .id = O_LOG_TCPOPTS, .type = XTTYPE_NONE}, + {.name = "log-ip-options", .id = O_LOG_IPOPTS, .type = XTTYPE_NONE}, + {.name = "log-uid", .id = O_LOG_UID, .type = XTTYPE_NONE}, + {.name = "log-macdecode", .id = O_LOG_MAC, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s static void LOG_init(struct xt_entry_target *t) { @@ -63,127 +75,33 @@ static const struct ipt_log_names ipt_log_names[] { .name = "warning", .level = LOG_WARNING } }; -static u_int8_t -parse_level(const char *level) -{ - unsigned int lev = -1; - unsigned int set = 0; - - if (!xtables_strtoui(level, NULL, &lev, 0, 7)) { - unsigned int i = 0; - - for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i) - if (strncasecmp(level, ipt_log_names[i].name, - strlen(level)) == 0) { - if (set++) - xtables_error(PARAMETER_PROBLEM, - "log-level `%s' ambiguous", - level); - lev = ipt_log_names[i].level; - } - - if (!set) - xtables_error(PARAMETER_PROBLEM, - "log-level `%s' unknown", level); - } - - return lev; -} - -#define IPT_LOG_OPT_LEVEL 0x01 -#define IPT_LOG_OPT_PREFIX 0x02 -#define IPT_LOG_OPT_TCPSEQ 0x04 -#define IPT_LOG_OPT_TCPOPT 0x08 -#define IPT_LOG_OPT_IPOPT 0x10 -#define IPT_LOG_OPT_UID 0x20 - -static int LOG_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void LOG_parse(struct xt_option_call *cb) { - struct ipt_log_info *loginfo = (struct ipt_log_info *)(*target)->data; - - switch (c) { - case '!': - if (*flags & IPT_LOG_OPT_LEVEL) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-level twice"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --log-level"); - - loginfo->level = parse_level(optarg); - *flags |= IPT_LOG_OPT_LEVEL; - break; - - case '#': - if (*flags & IPT_LOG_OPT_PREFIX) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-prefix twice"); + struct ipt_log_info *info = cb->data; - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --log-prefix"); - - if (strlen(optarg) > sizeof(loginfo->prefix) - 1) - xtables_error(PARAMETER_PROBLEM, - "Maximum prefix length %u for --log-prefix", - (unsigned int)sizeof(loginfo->prefix) - 1); - - if (strlen(optarg) == 0) - xtables_error(PARAMETER_PROBLEM, - "No prefix specified for --log-prefix"); - - if (strlen(optarg) != strlen(strtok(optarg, "\n"))) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_LOG_PREFIX: + if (strchr(cb->arg, '\n') != NULL) xtables_error(PARAMETER_PROBLEM, "Newlines not allowed in --log-prefix"); - - strcpy(loginfo->prefix, optarg); - *flags |= IPT_LOG_OPT_PREFIX; break; - - case '1': - if (*flags & IPT_LOG_OPT_TCPSEQ) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-tcp-sequence " - "twice"); - - loginfo->logflags |= IPT_LOG_TCPSEQ; - *flags |= IPT_LOG_OPT_TCPSEQ; + case O_LOG_TCPSEQ: + info->logflags |= IPT_LOG_TCPSEQ; break; - - case '2': - if (*flags & IPT_LOG_OPT_TCPOPT) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-tcp-options twice"); - - loginfo->logflags |= IPT_LOG_TCPOPT; - *flags |= IPT_LOG_OPT_TCPOPT; + case O_LOG_TCPOPTS: + info->logflags |= IPT_LOG_TCPOPT; break; - - case '3': - if (*flags & IPT_LOG_OPT_IPOPT) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-ip-options twice"); - - loginfo->logflags |= IPT_LOG_IPOPT; - *flags |= IPT_LOG_OPT_IPOPT; + case O_LOG_IPOPTS: + info->logflags |= IPT_LOG_IPOPT; break; - - case '4': - if (*flags & IPT_LOG_OPT_UID) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --log-uid twice"); - - loginfo->logflags |= IPT_LOG_UID; - *flags |= IPT_LOG_OPT_UID; + case O_LOG_UID: + info->logflags |= IPT_LOG_UID; + break; + case O_LOG_MAC: + info->logflags |= IPT_LOG_MACDECODE; break; - - default: - return 0; } - - return 1; } static void LOG_print(const void *ip, const struct xt_entry_target *target, @@ -193,32 +111,34 @@ static void LOG_print(const void *ip, const struct xt_entry_target *target, = (const struct ipt_log_info *)target->data; unsigned int i = 0; - printf("LOG "); + printf(" LOG"); if (numeric) - printf("flags %u level %u ", + printf(" flags %u level %u", loginfo->logflags, loginfo->level); else { for (i = 0; i < ARRAY_SIZE(ipt_log_names); ++i) if (loginfo->level == ipt_log_names[i].level) { - printf("level %s ", ipt_log_names[i].name); + printf(" level %s", ipt_log_names[i].name); break; } if (i == ARRAY_SIZE(ipt_log_names)) - printf("UNKNOWN level %u ", loginfo->level); + printf(" UNKNOWN level %u", loginfo->level); if (loginfo->logflags & IPT_LOG_TCPSEQ) - printf("tcp-sequence "); + printf(" tcp-sequence"); if (loginfo->logflags & IPT_LOG_TCPOPT) - printf("tcp-options "); + printf(" tcp-options"); if (loginfo->logflags & IPT_LOG_IPOPT) - printf("ip-options "); + printf(" ip-options"); if (loginfo->logflags & IPT_LOG_UID) - printf("uid "); + printf(" uid"); + if (loginfo->logflags & IPT_LOG_MACDECODE) + printf(" macdecode"); if (loginfo->logflags & ~(IPT_LOG_MASK)) - printf("unknown-flags "); + printf(" unknown-flags"); } if (strcmp(loginfo->prefix, "") != 0) - printf("prefix `%s' ", loginfo->prefix); + printf(" prefix \"%s\"", loginfo->prefix); } static void LOG_save(const void *ip, const struct xt_entry_target *target) @@ -227,35 +147,37 @@ static void LOG_save(const void *ip, const struct xt_entry_target *target) = (const struct ipt_log_info *)target->data; if (strcmp(loginfo->prefix, "") != 0) { - printf("--log-prefix "); + printf(" --log-prefix"); xtables_save_string(loginfo->prefix); } if (loginfo->level != LOG_DEFAULT_LEVEL) - printf("--log-level %d ", loginfo->level); + printf(" --log-level %d", loginfo->level); if (loginfo->logflags & IPT_LOG_TCPSEQ) - printf("--log-tcp-sequence "); + printf(" --log-tcp-sequence"); if (loginfo->logflags & IPT_LOG_TCPOPT) - printf("--log-tcp-options "); + printf(" --log-tcp-options"); if (loginfo->logflags & IPT_LOG_IPOPT) - printf("--log-ip-options "); + printf(" --log-ip-options"); if (loginfo->logflags & IPT_LOG_UID) - printf("--log-uid "); + printf(" --log-uid"); + if (loginfo->logflags & IPT_LOG_MACDECODE) + printf(" --log-macdecode"); } static struct xtables_target log_tg_reg = { - .name = "LOG", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct ipt_log_info)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)), - .help = LOG_help, - .init = LOG_init, - .parse = LOG_parse, - .print = LOG_print, - .save = LOG_save, - .extra_opts = LOG_opts, + .name = "LOG", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct ipt_log_info)), + .userspacesize = XT_ALIGN(sizeof(struct ipt_log_info)), + .help = LOG_help, + .init = LOG_init, + .print = LOG_print, + .save = LOG_save, + .x6_parse = LOG_parse, + .x6_options = LOG_opts, }; void _init(void) diff --git a/extensions/libipt_LOG.man b/extensions/libipt_LOG.man deleted file mode 100644 index 47c35e0..0000000 --- a/extensions/libipt_LOG.man +++ /dev/null @@ -1,31 +0,0 @@ -Turn on kernel logging of matching packets. When this option is set -for a rule, the Linux kernel will print some information on all -matching packets (like most IP header fields) via the kernel log -(where it can be read with -.I dmesg -or -.IR syslogd (8)). -This is a "non-terminating target", i.e. rule traversal continues at -the next rule. So if you want to LOG the packets you refuse, use two -separate rules with the same matching criteria, first using target LOG -then DROP (or REJECT). -.TP -\fB\-\-log\-level\fP \fIlevel\fP -Level of logging (numeric or see \fIsyslog.conf\fP(5)). -.TP -\fB\-\-log\-prefix\fP \fIprefix\fP -Prefix log messages with the specified prefix; up to 29 letters long, -and useful for distinguishing messages in the logs. -.TP -\fB\-\-log\-tcp\-sequence\fP -Log TCP sequence numbers. This is a security risk if the log is -readable by users. -.TP -\fB\-\-log\-tcp\-options\fP -Log options from the TCP packet header. -.TP -\fB\-\-log\-ip\-options\fP -Log options from the IP packet header. -.TP -\fB\-\-log\-uid\fP -Log the userid of the process which generated the packet. diff --git a/extensions/libipt_MASQUERADE.c b/extensions/libipt_MASQUERADE.c index 3386ff3..ea07445 100644 --- a/extensions/libipt_MASQUERADE.c +++ b/extensions/libipt_MASQUERADE.c @@ -1,4 +1,3 @@ -/* Shared library add-on to iptables to add masquerade support. */ #include <stdio.h> #include <netdb.h> #include <string.h> @@ -7,7 +6,12 @@ #include <xtables.h> #include <limits.h> /* INT_MAX in ip_tables.h */ #include <linux/netfilter_ipv4/ip_tables.h> -#include <net/netfilter/nf_nat.h> +#include <linux/netfilter/nf_nat.h> + +enum { + O_TO_PORTS = 0, + O_RANDOM, +}; static void MASQUERADE_help(void) { @@ -19,29 +23,28 @@ static void MASQUERADE_help(void) " Randomize source port.\n"); } -static const struct option MASQUERADE_opts[] = { - { "to-ports", 1, NULL, '1' }, - { "random", 0, NULL, '2' }, - { .name = NULL } +static const struct xt_option_entry MASQUERADE_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; static void MASQUERADE_init(struct xt_entry_target *t) { - struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; + struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; /* Actually, it's 0, but it's ignored at the moment. */ mr->rangesize = 1; - } /* Parses ports */ static void -parse_ports(const char *arg, struct nf_nat_multi_range *mr) +parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) { char *end; unsigned int port, maxport; - mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX)) xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); @@ -68,13 +71,11 @@ parse_ports(const char *arg, struct nf_nat_multi_range *mr) xtables_param_act(XTF_BAD_VALUE, "MASQUERADE", "--to-ports", arg); } -static int MASQUERADE_parse(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_target **target) +static void MASQUERADE_parse(struct xt_option_call *cb) { - const struct ipt_entry *entry = e; + const struct ipt_entry *entry = cb->xt_entry; int portok; - struct nf_nat_multi_range *mr - = (struct nf_nat_multi_range *)(*target)->data; + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; if (entry->ip.proto == IPPROTO_TCP || entry->ip.proto == IPPROTO_UDP @@ -85,25 +86,17 @@ static int MASQUERADE_parse(int c, char **argv, int invert, unsigned int *flags, else portok = 0; - switch (c) { - case '1': + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_PORTS: if (!portok) xtables_error(PARAMETER_PROBLEM, "Need TCP, UDP, SCTP or DCCP with port specification"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --to-ports"); - - parse_ports(optarg, mr); - return 1; - - case '2': - mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; - return 1; - - default: - return 0; + parse_ports(cb->arg, mr); + break; + case O_RANDOM: + mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; } } @@ -111,50 +104,48 @@ static void MASQUERADE_print(const void *ip, const struct xt_entry_target *target, int numeric) { - const struct nf_nat_multi_range *mr = (const void *)target->data; - const struct nf_nat_range *r = &mr->range[0]; + const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; + const struct nf_nat_ipv4_range *r = &mr->range[0]; - if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { - printf("masq ports: "); + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" masq ports: "); printf("%hu", ntohs(r->min.tcp.port)); if (r->max.tcp.port != r->min.tcp.port) printf("-%hu", ntohs(r->max.tcp.port)); - printf(" "); } - if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("random "); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); } static void MASQUERADE_save(const void *ip, const struct xt_entry_target *target) { - const struct nf_nat_multi_range *mr = (const void *)target->data; - const struct nf_nat_range *r = &mr->range[0]; + const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; + const struct nf_nat_ipv4_range *r = &mr->range[0]; - if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { - printf("--to-ports %hu", ntohs(r->min.tcp.port)); + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" --to-ports %hu", ntohs(r->min.tcp.port)); if (r->max.tcp.port != r->min.tcp.port) printf("-%hu", ntohs(r->max.tcp.port)); - printf(" "); } - if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("--random "); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); } static struct xtables_target masquerade_tg_reg = { .name = "MASQUERADE", .version = XTABLES_VERSION, .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), .help = MASQUERADE_help, .init = MASQUERADE_init, - .parse = MASQUERADE_parse, + .x6_parse = MASQUERADE_parse, .print = MASQUERADE_print, .save = MASQUERADE_save, - .extra_opts = MASQUERADE_opts, + .x6_options = MASQUERADE_opts, }; void _init(void) diff --git a/extensions/libipt_NETMAP.c b/extensions/libipt_NETMAP.c index b05022b..dee7b01 100644 --- a/extensions/libipt_NETMAP.c +++ b/extensions/libipt_NETMAP.c @@ -1,20 +1,24 @@ /* Shared library add-on to iptables to add static NAT support. Author: Svenning Soerensen <svenning@post5.tele.dk> */ - #include <stdio.h> #include <netdb.h> #include <string.h> #include <stdlib.h> #include <getopt.h> #include <xtables.h> -#include <net/netfilter/nf_nat.h> +#include <linux/netfilter/nf_nat.h> #define MODULENAME "NETMAP" -static const struct option NETMAP_opts[] = { - { "to", 1, NULL, '1' }, - { .name = NULL } +enum { + O_TO = 0, +}; + +static const struct xt_option_entry NETMAP_opts[] = { + {.name = "to", .id = O_TO, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MAND}, + XTOPT_TABLEEND, }; static void NETMAP_help(void) @@ -25,22 +29,10 @@ static void NETMAP_help(void) NETMAP_opts[0].name); } -static u_int32_t -bits2netmask(int bits) -{ - u_int32_t netmask, bm; - - if (bits >= 32 || bits < 0) - return(~0); - for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1) - netmask |= bm; - return htonl(netmask); -} - static int -netmask2bits(u_int32_t netmask) +netmask2bits(uint32_t netmask) { - u_int32_t bm; + uint32_t bm; int bits; netmask = ntohl(netmask); @@ -53,95 +45,28 @@ netmask2bits(u_int32_t netmask) static void NETMAP_init(struct xt_entry_target *t) { - struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; + struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; /* Actually, it's 0, but it's ignored at the moment. */ mr->rangesize = 1; - -} - -/* Parses network address */ -static void -parse_to(char *arg, struct nf_nat_range *range) -{ - char *slash; - const struct in_addr *ip; - u_int32_t netmask; - unsigned int bits; - - range->flags |= IP_NAT_RANGE_MAP_IPS; - slash = strchr(arg, '/'); - if (slash) - *slash = '\0'; - - ip = xtables_numeric_to_ipaddr(arg); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n", - arg); - range->min_ip = ip->s_addr; - if (slash) { - if (strchr(slash+1, '.')) { - ip = xtables_numeric_to_ipmask(slash+1); - if (!ip) - xtables_error(PARAMETER_PROBLEM, "Bad netmask \"%s\"\n", - slash+1); - netmask = ip->s_addr; - } - else { - if (!xtables_strtoui(slash+1, NULL, &bits, 0, 32)) - xtables_error(PARAMETER_PROBLEM, "Bad netmask \"%s\"\n", - slash+1); - netmask = bits2netmask(bits); - } - /* Don't allow /0 (/1 is probably insane, too) */ - if (netmask == 0) - xtables_error(PARAMETER_PROBLEM, "Netmask needed\n"); - } - else - netmask = ~0; - - if (range->min_ip & ~netmask) { - if (slash) - *slash = '/'; - xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n", - arg); - } - range->max_ip = range->min_ip | ~netmask; } -static int NETMAP_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void NETMAP_parse(struct xt_option_call *cb) { - struct nf_nat_multi_range *mr - = (struct nf_nat_multi_range *)(*target)->data; + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + struct nf_nat_ipv4_range *range = &mr->range[0]; - switch (c) { - case '1': - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --%s", NETMAP_opts[0].name); - - parse_to(optarg, &mr->range[0]); - *flags = 1; - return 1; - - default: - return 0; - } -} - -static void NETMAP_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - MODULENAME" needs --%s", NETMAP_opts[0].name); + xtables_option_parse(cb); + range->flags |= NF_NAT_RANGE_MAP_IPS; + range->min_ip = cb->val.haddr.ip & cb->val.hmask.ip; + range->max_ip = range->min_ip | ~cb->val.hmask.ip; } static void NETMAP_print(const void *ip, const struct xt_entry_target *target, int numeric) { - const struct nf_nat_multi_range *mr = (const void *)target->data; - const struct nf_nat_range *r = &mr->range[0]; + const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; + const struct nf_nat_ipv4_range *r = &mr->range[0]; struct in_addr a; int bits; @@ -157,7 +82,7 @@ static void NETMAP_print(const void *ip, const struct xt_entry_target *target, static void NETMAP_save(const void *ip, const struct xt_entry_target *target) { - printf("--%s ", NETMAP_opts[0].name); + printf(" --%s ", NETMAP_opts[0].name); NETMAP_print(ip, target, 0); } @@ -165,15 +90,14 @@ static struct xtables_target netmap_tg_reg = { .name = MODULENAME, .version = XTABLES_VERSION, .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), .help = NETMAP_help, .init = NETMAP_init, - .parse = NETMAP_parse, - .final_check = NETMAP_check, + .x6_parse = NETMAP_parse, .print = NETMAP_print, .save = NETMAP_save, - .extra_opts = NETMAP_opts, + .x6_options = NETMAP_opts, }; void _init(void) diff --git a/extensions/libipt_REDIRECT.c b/extensions/libipt_REDIRECT.c index 324d0eb..610a949 100644 --- a/extensions/libipt_REDIRECT.c +++ b/extensions/libipt_REDIRECT.c @@ -1,16 +1,17 @@ -/* Shared library add-on to iptables to add redirect support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <limits.h> /* INT_MAX in ip_tables.h */ #include <linux/netfilter_ipv4/ip_tables.h> -#include <net/netfilter/nf_nat.h> +#include <linux/netfilter/nf_nat.h> -#define IPT_REDIRECT_OPT_DEST 0x01 -#define IPT_REDIRECT_OPT_RANDOM 0x02 +enum { + O_TO_PORTS = 0, + O_RANDOM, + F_TO_PORTS = 1 << O_TO_PORTS, + F_RANDOM = 1 << O_RANDOM, +}; static void REDIRECT_help(void) { @@ -21,29 +22,28 @@ static void REDIRECT_help(void) " [--random]\n"); } -static const struct option REDIRECT_opts[] = { - { "to-ports", 1, NULL, '1' }, - { "random", 0, NULL, '2' }, - { .name = NULL } +static const struct xt_option_entry REDIRECT_opts[] = { + {.name = "to-ports", .id = O_TO_PORTS, .type = XTTYPE_STRING}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; static void REDIRECT_init(struct xt_entry_target *t) { - struct nf_nat_multi_range *mr = (struct nf_nat_multi_range *)t->data; + struct nf_nat_ipv4_multi_range_compat *mr = (struct nf_nat_ipv4_multi_range_compat *)t->data; /* Actually, it's 0, but it's ignored at the moment. */ mr->rangesize = 1; - } /* Parses ports */ static void -parse_ports(const char *arg, struct nf_nat_multi_range *mr) +parse_ports(const char *arg, struct nf_nat_ipv4_multi_range_compat *mr) { - char *end; + char *end = ""; unsigned int port, maxport; - mr->range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + mr->range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; if (!xtables_strtoui(arg, &end, &port, 0, UINT16_MAX) && (port = xtables_service_to_port(arg, NULL)) == (unsigned)-1) @@ -72,12 +72,10 @@ parse_ports(const char *arg, struct nf_nat_multi_range *mr) xtables_param_act(XTF_BAD_VALUE, "REDIRECT", "--to-ports", arg); } -static int REDIRECT_parse(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_target **target) +static void REDIRECT_parse(struct xt_option_call *cb) { - const struct ipt_entry *entry = e; - struct nf_nat_multi_range *mr - = (struct nf_nat_multi_range *)(*target)->data; + const struct ipt_entry *entry = cb->xt_entry; + struct nf_nat_ipv4_multi_range_compat *mr = (void *)(*cb->target)->data; int portok; if (entry->ip.proto == IPPROTO_TCP @@ -89,65 +87,51 @@ static int REDIRECT_parse(int c, char **argv, int invert, unsigned int *flags, else portok = 0; - switch (c) { - case '1': + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_PORTS: if (!portok) xtables_error(PARAMETER_PROBLEM, "Need TCP, UDP, SCTP or DCCP with port specification"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --to-ports"); - - parse_ports(optarg, mr); - if (*flags & IPT_REDIRECT_OPT_RANDOM) - mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; - *flags |= IPT_REDIRECT_OPT_DEST; - return 1; - - case '2': - if (*flags & IPT_REDIRECT_OPT_DEST) { - mr->range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; - *flags |= IPT_REDIRECT_OPT_RANDOM; - } else - *flags |= IPT_REDIRECT_OPT_RANDOM; - return 1; - - default: - return 0; + parse_ports(cb->arg, mr); + if (cb->xflags & F_RANDOM) + mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; + case O_RANDOM: + if (cb->xflags & F_TO_PORTS) + mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; + break; } } static void REDIRECT_print(const void *ip, const struct xt_entry_target *target, int numeric) { - const struct nf_nat_multi_range *mr = (const void *)target->data; - const struct nf_nat_range *r = &mr->range[0]; + const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; + const struct nf_nat_ipv4_range *r = &mr->range[0]; - if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { - printf("redir ports "); + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" redir ports "); printf("%hu", ntohs(r->min.tcp.port)); if (r->max.tcp.port != r->min.tcp.port) printf("-%hu", ntohs(r->max.tcp.port)); - printf(" "); - if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("random "); + if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); } } static void REDIRECT_save(const void *ip, const struct xt_entry_target *target) { - const struct nf_nat_multi_range *mr = (const void *)target->data; - const struct nf_nat_range *r = &mr->range[0]; + const struct nf_nat_ipv4_multi_range_compat *mr = (const void *)target->data; + const struct nf_nat_ipv4_range *r = &mr->range[0]; - if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { - printf("--to-ports "); + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { + printf(" --to-ports "); printf("%hu", ntohs(r->min.tcp.port)); if (r->max.tcp.port != r->min.tcp.port) printf("-%hu", ntohs(r->max.tcp.port)); - printf(" "); - if (mr->range[0].flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("--random "); + if (mr->range[0].flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); } } @@ -155,14 +139,14 @@ static struct xtables_target redirect_tg_reg = { .name = "REDIRECT", .version = XTABLES_VERSION, .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), .help = REDIRECT_help, .init = REDIRECT_init, - .parse = REDIRECT_parse, + .x6_parse = REDIRECT_parse, .print = REDIRECT_print, .save = REDIRECT_save, - .extra_opts = REDIRECT_opts, + .x6_options = REDIRECT_opts, }; void _init(void) diff --git a/extensions/libipt_REJECT.c b/extensions/libipt_REJECT.c index 85d9e53..362c65e 100644 --- a/extensions/libipt_REJECT.c +++ b/extensions/libipt_REJECT.c @@ -4,8 +4,6 @@ */ #include <stdio.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter_ipv4/ipt_REJECT.h> #include <linux/version.h> @@ -26,6 +24,10 @@ struct reject_names { const char *desc; }; +enum { + O_REJECT_WITH = 0, +}; + static const struct reject_names reject_table[] = { {"icmp-net-unreachable", "net-unreach", IPT_ICMP_NET_UNREACHABLE, "ICMP network unreachable"}, @@ -75,9 +77,9 @@ static void REJECT_help(void) printf("(*) See man page or read the INCOMPATIBILITES file for compatibility issues.\n"); } -static const struct option REJECT_opts[] = { - { "reject-with", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry REJECT_opts[] = { + {.name = "reject-with", .id = O_REJECT_WITH, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, }; static void REJECT_init(struct xt_entry_target *t) @@ -89,36 +91,27 @@ static void REJECT_init(struct xt_entry_target *t) } -static int REJECT_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void REJECT_parse(struct xt_option_call *cb) { - struct ipt_reject_info *reject = (struct ipt_reject_info *)(*target)->data; - static const unsigned int limit = ARRAY_SIZE(reject_table); + struct ipt_reject_info *reject = cb->data; unsigned int i; - switch(c) { - case '1': - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --reject-with"); - for (i = 0; i < limit; i++) { - if ((strncasecmp(reject_table[i].name, optarg, strlen(optarg)) == 0) - || (strncasecmp(reject_table[i].alias, optarg, strlen(optarg)) == 0)) { - reject->with = reject_table[i].with; - return 1; - } + xtables_option_parse(cb); + for (i = 0; i < ARRAY_SIZE(reject_table); ++i) + if (strncasecmp(reject_table[i].name, + cb->arg, strlen(cb->arg)) == 0 || + strncasecmp(reject_table[i].alias, + cb->arg, strlen(cb->arg)) == 0) { + reject->with = reject_table[i].with; + return; } - /* This due to be dropped late in 2.4 pre-release cycle --RR */ - if (strncasecmp("echo-reply", optarg, strlen(optarg)) == 0 - || strncasecmp("echoreply", optarg, strlen(optarg)) == 0) - fprintf(stderr, "--reject-with echo-reply no longer" - " supported\n"); - xtables_error(PARAMETER_PROBLEM, "unknown reject type \"%s\"", optarg); - default: - /* Fall through */ - break; - } - return 0; + /* This due to be dropped late in 2.4 pre-release cycle --RR */ + if (strncasecmp("echo-reply", cb->arg, strlen(cb->arg)) == 0 || + strncasecmp("echoreply", cb->arg, strlen(cb->arg)) == 0) + fprintf(stderr, "--reject-with echo-reply no longer" + " supported\n"); + xtables_error(PARAMETER_PROBLEM, + "unknown reject type \"%s\"", cb->arg); } static void REJECT_print(const void *ip, const struct xt_entry_target *target, @@ -131,7 +124,7 @@ static void REJECT_print(const void *ip, const struct xt_entry_target *target, for (i = 0; i < ARRAY_SIZE(reject_table); ++i) if (reject_table[i].with == reject->with) break; - printf("reject-with %s ", reject_table[i].name); + printf(" reject-with %s", reject_table[i].name); } static void REJECT_save(const void *ip, const struct xt_entry_target *target) @@ -144,7 +137,7 @@ static void REJECT_save(const void *ip, const struct xt_entry_target *target) if (reject_table[i].with == reject->with) break; - printf("--reject-with %s ", reject_table[i].name); + printf(" --reject-with %s", reject_table[i].name); } static struct xtables_target reject_tg_reg = { @@ -155,10 +148,10 @@ static struct xtables_target reject_tg_reg = { .userspacesize = XT_ALIGN(sizeof(struct ipt_reject_info)), .help = REJECT_help, .init = REJECT_init, - .parse = REJECT_parse, .print = REJECT_print, .save = REJECT_save, - .extra_opts = REJECT_opts, + .x6_parse = REJECT_parse, + .x6_options = REJECT_opts, }; void _init(void) diff --git a/extensions/libipt_REJECT.man b/extensions/libipt_REJECT.man index c419a85..926da03 100644 --- a/extensions/libipt_REJECT.man +++ b/extensions/libipt_REJECT.man @@ -18,9 +18,9 @@ The type given can be \fBicmp\-port\-unreachable\fP, \fBicmp\-proto\-unreachable\fP, \fBicmp\-net\-prohibited\fP, -\fBicmp\-host\-prohibited\fP or -\fBicmp\-admin\-prohibited\fP (*) -which return the appropriate ICMP error message (\fBport\-unreachable\fP is +\fBicmp\-host\-prohibited\fP, or +\fBicmp\-admin\-prohibited\fP (*), +which return the appropriate ICMP error message (\fBicmp\-port\-unreachable\fP is the default). The option \fBtcp\-reset\fP can be used on rules which only match the TCP protocol: this causes a diff --git a/extensions/libipt_SAME.c b/extensions/libipt_SAME.c index ed02ef9..5d5bf63 100644 --- a/extensions/libipt_SAME.c +++ b/extensions/libipt_SAME.c @@ -1,14 +1,18 @@ -/* Shared library add-on to iptables to add simple non load-balancing SNAT support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <xtables.h> -#include <net/netfilter/nf_nat.h> -/* For 64bit kernel / 32bit userspace */ +#include <linux/netfilter/nf_nat.h> #include <linux/netfilter_ipv4/ipt_SAME.h> +enum { + O_TO_ADDR = 0, + O_NODST, + O_RANDOM, + F_TO_ADDR = 1 << O_TO_ADDR, + F_RANDOM = 1 << O_RANDOM, +}; + static void SAME_help(void) { printf( @@ -24,32 +28,24 @@ static void SAME_help(void) " Randomize source port\n"); } -static const struct option SAME_opts[] = { - { "to", 1, NULL, '1' }, - { "nodst", 0, NULL, '2'}, - { "random", 0, NULL, '3' }, - { .name = NULL } +static const struct xt_option_entry SAME_opts[] = { + {.name = "to", .id = O_TO_ADDR, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "nodst", .id = O_NODST, .type = XTTYPE_NONE}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; -static void SAME_init(struct xt_entry_target *t) -{ - struct ipt_same_info *mr = (struct ipt_same_info *)t->data; - - /* Set default to 0 */ - mr->rangesize = 0; - mr->info = 0; - mr->ipnum = 0; - -} - /* Parses range of IPs */ -static void -parse_to(char *arg, struct nf_nat_range *range) +static void parse_to(const char *orig_arg, struct nf_nat_ipv4_range *range) { - char *dash; + char *dash, *arg; const struct in_addr *ip; - range->flags |= IP_NAT_RANGE_MAP_IPS; + arg = strdup(orig_arg); + if (arg == NULL) + xtables_error(RESOURCE_PROBLEM, "strdup"); + range->flags |= NF_NAT_RANGE_MAP_IPS; dash = strchr(arg, '-'); if (dash) @@ -72,66 +68,44 @@ parse_to(char *arg, struct nf_nat_range *range) if (range->min_ip > range->max_ip) xtables_error(PARAMETER_PROBLEM, "Bad IP range \"%s-%s\"\n", arg, dash+1); + free(arg); } -#define IPT_SAME_OPT_TO 0x01 -#define IPT_SAME_OPT_NODST 0x02 -#define IPT_SAME_OPT_RANDOM 0x04 - -static int SAME_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void SAME_parse(struct xt_option_call *cb) { - struct ipt_same_info *mr - = (struct ipt_same_info *)(*target)->data; + struct ipt_same_info *mr = cb->data; unsigned int count; - switch (c) { - case '1': + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_ADDR: if (mr->rangesize == IPT_SAME_MAX_RANGE) xtables_error(PARAMETER_PROBLEM, "Too many ranges specified, maximum " "is %i ranges.\n", IPT_SAME_MAX_RANGE); - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --to"); - - parse_to(optarg, &mr->range[mr->rangesize]); - /* WTF do we need this for? */ - if (*flags & IPT_SAME_OPT_RANDOM) - mr->range[mr->rangesize].flags - |= IP_NAT_RANGE_PROTO_RANDOM; + parse_to(cb->arg, &mr->range[mr->rangesize]); mr->rangesize++; - *flags |= IPT_SAME_OPT_TO; break; - - case '2': - if (*flags & IPT_SAME_OPT_NODST) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --nodst twice"); - + case O_NODST: mr->info |= IPT_SAME_NODST; - *flags |= IPT_SAME_OPT_NODST; break; - - case '3': - *flags |= IPT_SAME_OPT_RANDOM; + case O_RANDOM: for (count=0; count < mr->rangesize; count++) - mr->range[count].flags |= IP_NAT_RANGE_PROTO_RANDOM; + mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM; break; - - default: - return 0; } - - return 1; } -static void SAME_check(unsigned int flags) +static void SAME_fcheck(struct xt_fcheck_call *cb) { - if (!(flags & IPT_SAME_OPT_TO)) - xtables_error(PARAMETER_PROBLEM, - "SAME needs --to"); + static const unsigned int f = F_TO_ADDR | F_RANDOM; + struct ipt_same_info *mr = cb->data; + unsigned int count; + + if ((cb->xflags & f) == f) + for (count = 0; count < mr->rangesize; ++count) + mr->range[count].flags |= NF_NAT_RANGE_PROTO_RANDOM; } static void SAME_print(const void *ip, const struct xt_entry_target *target, @@ -141,10 +115,10 @@ static void SAME_print(const void *ip, const struct xt_entry_target *target, const struct ipt_same_info *mr = (const void *)target->data; int random_selection = 0; - printf("same:"); - + printf(" same:"); + for (count = 0; count < mr->rangesize; count++) { - const struct nf_nat_range *r = &mr->range[count]; + const struct nf_nat_ipv4_range *r = &mr->range[count]; struct in_addr a; a.s_addr = r->min_ip; @@ -152,19 +126,17 @@ static void SAME_print(const void *ip, const struct xt_entry_target *target, printf("%s", xtables_ipaddr_to_numeric(&a)); a.s_addr = r->max_ip; - if (r->min_ip == r->max_ip) - printf(" "); - else - printf("-%s ", xtables_ipaddr_to_numeric(&a)); - if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) + if (r->min_ip != r->max_ip) + printf("-%s", xtables_ipaddr_to_numeric(&a)); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) random_selection = 1; } if (mr->info & IPT_SAME_NODST) - printf("nodst "); + printf(" nodst"); if (random_selection) - printf("random "); + printf(" random"); } static void SAME_save(const void *ip, const struct xt_entry_target *target) @@ -174,26 +146,24 @@ static void SAME_save(const void *ip, const struct xt_entry_target *target) int random_selection = 0; for (count = 0; count < mr->rangesize; count++) { - const struct nf_nat_range *r = &mr->range[count]; + const struct nf_nat_ipv4_range *r = &mr->range[count]; struct in_addr a; a.s_addr = r->min_ip; - printf("--to %s", xtables_ipaddr_to_numeric(&a)); + printf(" --to %s", xtables_ipaddr_to_numeric(&a)); a.s_addr = r->max_ip; - if (r->min_ip == r->max_ip) - printf(" "); - else - printf("-%s ", xtables_ipaddr_to_numeric(&a)); - if (r->flags & IP_NAT_RANGE_PROTO_RANDOM) + if (r->min_ip != r->max_ip) + printf("-%s", xtables_ipaddr_to_numeric(&a)); + if (r->flags & NF_NAT_RANGE_PROTO_RANDOM) random_selection = 1; } if (mr->info & IPT_SAME_NODST) - printf("--nodst "); + printf(" --nodst"); if (random_selection) - printf("--random "); + printf(" --random"); } static struct xtables_target same_tg_reg = { @@ -203,12 +173,11 @@ static struct xtables_target same_tg_reg = { .size = XT_ALIGN(sizeof(struct ipt_same_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_same_info)), .help = SAME_help, - .init = SAME_init, - .parse = SAME_parse, - .final_check = SAME_check, + .x6_parse = SAME_parse, + .x6_fcheck = SAME_fcheck, .print = SAME_print, .save = SAME_save, - .extra_opts = SAME_opts, + .x6_options = SAME_opts, }; void _init(void) diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c index f7c93d8..1a24f3d 100644 --- a/extensions/libipt_SNAT.c +++ b/extensions/libipt_SNAT.c @@ -1,44 +1,50 @@ -/* Shared library add-on to iptables to add source-NAT support. */ #include <stdio.h> #include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <iptables.h> #include <limits.h> /* INT_MAX in ip_tables.h */ #include <linux/netfilter_ipv4/ip_tables.h> -#include <net/netfilter/nf_nat.h> - -#define IPT_SNAT_OPT_SOURCE 0x01 -#define IPT_SNAT_OPT_RANDOM 0x02 +#include <linux/netfilter/nf_nat.h> + +enum { + O_TO_SRC = 0, + O_RANDOM, + O_PERSISTENT, + O_X_TO_SRC, + F_TO_SRC = 1 << O_TO_SRC, + F_RANDOM = 1 << O_RANDOM, + F_X_TO_SRC = 1 << O_X_TO_SRC, +}; /* Source NAT data consists of a multi-range, indicating where to map to. */ struct ipt_natinfo { struct xt_entry_target t; - struct nf_nat_multi_range mr; + struct nf_nat_ipv4_multi_range_compat mr; }; static void SNAT_help(void) { printf( "SNAT target options:\n" -" --to-source <ipaddr>[-<ipaddr>][:port-port]\n" +" --to-source [<ipaddr>[-<ipaddr>]][:port[-port]]\n" " Address to map source to.\n" "[--random] [--persistent]\n"); } -static const struct option SNAT_opts[] = { - { "to-source", 1, NULL, '1' }, - { "random", 0, NULL, '2' }, - { "persistent", 0, NULL, '3' }, - { .name = NULL } +static const struct xt_option_entry SNAT_opts[] = { + {.name = "to-source", .id = O_TO_SRC, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_MULTI}, + {.name = "random", .id = O_RANDOM, .type = XTTYPE_NONE}, + {.name = "persistent", .id = O_PERSISTENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; static struct ipt_natinfo * -append_range(struct ipt_natinfo *info, const struct nf_nat_range *range) +append_range(struct ipt_natinfo *info, const struct nf_nat_ipv4_range *range) { unsigned int size; @@ -58,12 +64,15 @@ append_range(struct ipt_natinfo *info, const struct nf_nat_range *range) /* Ranges expected in network order. */ static struct xt_entry_target * -parse_to(char *arg, int portok, struct ipt_natinfo *info) +parse_to(const char *orig_arg, int portok, struct ipt_natinfo *info) { - struct nf_nat_range range; - char *colon, *dash, *error; + struct nf_nat_ipv4_range range; + char *arg, *colon, *dash, *error; const struct in_addr *ip; + arg = strdup(orig_arg); + if (arg == NULL) + xtables_error(RESOURCE_PROBLEM, "strdup"); memset(&range, 0, sizeof(range)); colon = strchr(arg, ':'); @@ -74,7 +83,7 @@ parse_to(char *arg, int portok, struct ipt_natinfo *info) xtables_error(PARAMETER_PROBLEM, "Need TCP, UDP, SCTP or DCCP with port specification"); - range.flags |= IP_NAT_RANGE_PROTO_SPECIFIED; + range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; port = atoi(colon+1); if (port <= 0 || port > 65535) @@ -106,12 +115,14 @@ parse_to(char *arg, int portok, struct ipt_natinfo *info) range.max.tcp.port = htons(maxport); } /* Starts with a colon? No IP info...*/ - if (colon == arg) + if (colon == arg) { + free(arg); return &(append_range(info, &range)->t); + } *colon = '\0'; } - range.flags |= IP_NAT_RANGE_MAP_IPS; + range.flags |= NF_NAT_RANGE_MAP_IPS; dash = strchr(arg, '-'); if (colon && dash && dash > colon) dash = NULL; @@ -133,14 +144,14 @@ parse_to(char *arg, int portok, struct ipt_natinfo *info) } else range.max_ip = range.min_ip; + free(arg); return &(append_range(info, &range)->t); } -static int SNAT_parse(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_target **target) +static void SNAT_parse(struct xt_option_call *cb) { - const struct ipt_entry *entry = e; - struct ipt_natinfo *info = (void *)*target; + const struct ipt_entry *entry = cb->xt_entry; + struct ipt_natinfo *info = (void *)(*cb->target); int portok; if (entry->ip.proto == IPPROTO_TCP @@ -152,53 +163,37 @@ static int SNAT_parse(int c, char **argv, int invert, unsigned int *flags, else portok = 0; - switch (c) { - case '1': - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --to-source"); - - if (*flags & IPT_SNAT_OPT_SOURCE) { + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TO_SRC: + if (cb->xflags & F_X_TO_SRC) { if (!kernel_version) get_kernel_version(); if (kernel_version > LINUX_VERSION(2, 6, 10)) xtables_error(PARAMETER_PROBLEM, - "Multiple --to-source not supported"); + "SNAT: Multiple --to-source not supported"); } - *target = parse_to(optarg, portok, info); - /* WTF do we need this for?? */ - if (*flags & IPT_SNAT_OPT_RANDOM) - info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; - *flags |= IPT_SNAT_OPT_SOURCE; - return 1; - - case '2': - if (*flags & IPT_SNAT_OPT_SOURCE) { - info->mr.range[0].flags |= IP_NAT_RANGE_PROTO_RANDOM; - *flags |= IPT_SNAT_OPT_RANDOM; - } else - *flags |= IPT_SNAT_OPT_RANDOM; - return 1; - - case '3': - info->mr.range[0].flags |= IP_NAT_RANGE_PERSISTENT; - return 1; - - default: - return 0; + *cb->target = parse_to(cb->arg, portok, info); + cb->xflags |= F_X_TO_SRC; + break; + case O_PERSISTENT: + info->mr.range[0].flags |= NF_NAT_RANGE_PERSISTENT; + break; } } -static void SNAT_check(unsigned int flags) +static void SNAT_fcheck(struct xt_fcheck_call *cb) { - if (!(flags & IPT_SNAT_OPT_SOURCE)) - xtables_error(PARAMETER_PROBLEM, - "You must specify --to-source"); + static const unsigned int f = F_TO_SRC | F_RANDOM; + struct nf_nat_ipv4_multi_range_compat *mr = cb->data; + + if ((cb->xflags & f) == f) + mr->range[0].flags |= NF_NAT_RANGE_PROTO_RANDOM; } -static void print_range(const struct nf_nat_range *r) +static void print_range(const struct nf_nat_ipv4_range *r) { - if (r->flags & IP_NAT_RANGE_MAP_IPS) { + if (r->flags & NF_NAT_RANGE_MAP_IPS) { struct in_addr a; a.s_addr = r->min_ip; @@ -208,7 +203,7 @@ static void print_range(const struct nf_nat_range *r) printf("-%s", xtables_ipaddr_to_numeric(&a)); } } - if (r->flags & IP_NAT_RANGE_PROTO_SPECIFIED) { + if (r->flags & NF_NAT_RANGE_PROTO_SPECIFIED) { printf(":"); printf("%hu", ntohs(r->min.tcp.port)); if (r->max.tcp.port != r->min.tcp.port) @@ -222,14 +217,13 @@ static void SNAT_print(const void *ip, const struct xt_entry_target *target, const struct ipt_natinfo *info = (const void *)target; unsigned int i = 0; - printf("to:"); + printf(" to:"); for (i = 0; i < info->mr.rangesize; i++) { print_range(&info->mr.range[i]); - printf(" "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("random "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT) - printf("persistent "); + if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" random"); + if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) + printf(" persistent"); } } @@ -239,13 +233,12 @@ static void SNAT_save(const void *ip, const struct xt_entry_target *target) unsigned int i = 0; for (i = 0; i < info->mr.rangesize; i++) { - printf("--to-source "); + printf(" --to-source "); print_range(&info->mr.range[i]); - printf(" "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PROTO_RANDOM) - printf("--random "); - if (info->mr.range[i].flags & IP_NAT_RANGE_PERSISTENT) - printf("--persistent "); + if (info->mr.range[i].flags & NF_NAT_RANGE_PROTO_RANDOM) + printf(" --random"); + if (info->mr.range[i].flags & NF_NAT_RANGE_PERSISTENT) + printf(" --persistent"); } } @@ -253,14 +246,14 @@ static struct xtables_target snat_tg_reg = { .name = "SNAT", .version = XTABLES_VERSION, .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct nf_nat_multi_range)), - .userspacesize = XT_ALIGN(sizeof(struct nf_nat_multi_range)), + .size = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), + .userspacesize = XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)), .help = SNAT_help, - .parse = SNAT_parse, - .final_check = SNAT_check, + .x6_parse = SNAT_parse, + .x6_fcheck = SNAT_fcheck, .print = SNAT_print, .save = SNAT_save, - .extra_opts = SNAT_opts, + .x6_options = SNAT_opts, }; void _init(void) diff --git a/extensions/libipt_TTL.c b/extensions/libipt_TTL.c index 4db9bbe..0f81280 100644 --- a/extensions/libipt_TTL.c +++ b/extensions/libipt_TTL.c @@ -1,19 +1,35 @@ /* Shared library add-on to iptables for the TTL target * (C) 2000 by Harald Welte <laforge@gnumonks.org> * - * $Id$ - * * This program is distributed under the terms of GNU GPL */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> - #include <linux/netfilter_ipv4/ipt_TTL.h> -#define IPT_TTL_USED 1 +enum { + O_TTL_SET = 0, + O_TTL_INC, + O_TTL_DEC, + F_TTL_SET = 1 << O_TTL_SET, + F_TTL_INC = 1 << O_TTL_INC, + F_TTL_DEC = 1 << O_TTL_DEC, + F_ANY = F_TTL_SET | F_TTL_INC | F_TTL_DEC, +}; + +#define s struct ipt_TTL_info +static const struct xt_option_entry TTL_opts[] = { + {.name = "ttl-set", .type = XTTYPE_UINT8, .id = O_TTL_SET, + .excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl)}, + {.name = "ttl-dec", .type = XTTYPE_UINT8, .id = O_TTL_DEC, + .excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl), + .min = 1}, + {.name = "ttl-inc", .type = XTTYPE_UINT8, .id = O_TTL_INC, + .excl = F_ANY, .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl), + .min = 1}, + XTOPT_TABLEEND, +}; +#undef s static void TTL_help(void) { @@ -24,67 +40,27 @@ static void TTL_help(void) " --ttl-inc value Increment TTL by <value 1-255>\n"); } -static int TTL_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void TTL_parse(struct xt_option_call *cb) { - struct ipt_TTL_info *info = (struct ipt_TTL_info *) (*target)->data; - unsigned int value; - - if (*flags & IPT_TTL_USED) { - xtables_error(PARAMETER_PROBLEM, - "Can't specify TTL option twice"); + struct ipt_TTL_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TTL_SET: + info->mode = IPT_TTL_SET; + break; + case O_TTL_DEC: + info->mode = IPT_TTL_DEC; + break; + case O_TTL_INC: + info->mode = IPT_TTL_INC; + break; } - - if (!optarg) - xtables_error(PARAMETER_PROBLEM, - "TTL: You must specify a value"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "TTL: unexpected `!'"); - - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "TTL: Expected value between 0 and 255"); - - switch (c) { - - case '1': - info->mode = IPT_TTL_SET; - break; - - case '2': - if (value == 0) { - xtables_error(PARAMETER_PROBLEM, - "TTL: decreasing by 0?"); - } - - info->mode = IPT_TTL_DEC; - break; - - case '3': - if (value == 0) { - xtables_error(PARAMETER_PROBLEM, - "TTL: increasing by 0?"); - } - - info->mode = IPT_TTL_INC; - break; - - default: - return 0; - - } - - info->ttl = value; - *flags |= IPT_TTL_USED; - - return 1; } -static void TTL_check(unsigned int flags) +static void TTL_check(struct xt_fcheck_call *cb) { - if (!(flags & IPT_TTL_USED)) + if (!(cb->xflags & F_ANY)) xtables_error(PARAMETER_PROBLEM, "TTL: You must specify an action"); } @@ -96,17 +72,17 @@ static void TTL_save(const void *ip, const struct xt_entry_target *target) switch (info->mode) { case IPT_TTL_SET: - printf("--ttl-set "); + printf(" --ttl-set"); break; case IPT_TTL_DEC: - printf("--ttl-dec "); + printf(" --ttl-dec"); break; case IPT_TTL_INC: - printf("--ttl-inc "); + printf(" --ttl-inc"); break; } - printf("%u ", info->ttl); + printf(" %u", info->ttl); } static void TTL_print(const void *ip, const struct xt_entry_target *target, @@ -115,28 +91,21 @@ static void TTL_print(const void *ip, const struct xt_entry_target *target, const struct ipt_TTL_info *info = (struct ipt_TTL_info *) target->data; - printf("TTL "); + printf(" TTL "); switch (info->mode) { case IPT_TTL_SET: - printf("set to "); + printf("set to"); break; case IPT_TTL_DEC: - printf("decrement by "); + printf("decrement by"); break; case IPT_TTL_INC: - printf("increment by "); + printf("increment by"); break; } - printf("%u ", info->ttl); + printf(" %u", info->ttl); } -static const struct option TTL_opts[] = { - { "ttl-set", 1, NULL, '1' }, - { "ttl-dec", 1, NULL, '2' }, - { "ttl-inc", 1, NULL, '3' }, - { .name = NULL } -}; - static struct xtables_target ttl_tg_reg = { .name = "TTL", .version = XTABLES_VERSION, @@ -144,11 +113,11 @@ static struct xtables_target ttl_tg_reg = { .size = XT_ALIGN(sizeof(struct ipt_TTL_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_TTL_info)), .help = TTL_help, - .parse = TTL_parse, - .final_check = TTL_check, .print = TTL_print, .save = TTL_save, - .extra_opts = TTL_opts, + .x6_parse = TTL_parse, + .x6_fcheck = TTL_check, + .x6_options = TTL_opts, }; void _init(void) diff --git a/extensions/libipt_TTL.man b/extensions/libipt_TTL.man index 89fc18f..cf3d1a2 100644 --- a/extensions/libipt_TTL.man +++ b/extensions/libipt_TTL.man @@ -3,11 +3,11 @@ how many hops (routers) a packet can traverse until it's time to live is exceeded. .PP Setting or incrementing the TTL field can potentially be very dangerous, -so it should be avoided at any cost. -.PP -.B Don't ever set or increment the value on packets that leave your local network! +so it should be avoided at any cost. This target is only valid in .B mangle table. +.PP +.B Don't ever set or increment the value on packets that leave your local network! .TP \fB\-\-ttl\-set\fP \fIvalue\fP Set the TTL value to `value'. diff --git a/extensions/libipt_ULOG.c b/extensions/libipt_ULOG.c index 4d009b7..fafb220 100644 --- a/extensions/libipt_ULOG.c +++ b/extensions/libipt_ULOG.c @@ -10,27 +10,17 @@ * libipt_ULOG.c,v 1.7 2001/01/30 11:55:02 laforge Exp */ #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <syslog.h> -#include <getopt.h> #include <xtables.h> /* For 64bit kernel / 32bit userspace */ #include <linux/netfilter_ipv4/ipt_ULOG.h> - -static void print_groups(unsigned int gmask) -{ - int b; - unsigned int test; - - for (b = 31; b >= 0; b--) { - test = (1 << b); - if (gmask & test) - printf("%d ", b + 1); - } -} +enum { + O_ULOG_NLGROUP = 0, + O_ULOG_PREFIX, + O_ULOG_CPRANGE, + O_ULOG_QTHR, +}; static void ULOG_help(void) { @@ -41,12 +31,16 @@ static void ULOG_help(void) " --ulog-prefix prefix Prefix log messages with this prefix.\n"); } -static const struct option ULOG_opts[] = { - {"ulog-nlgroup", 1, NULL, '!'}, - {"ulog-prefix", 1, NULL, '#'}, - {"ulog-cprange", 1, NULL, 'A'}, - {"ulog-qthreshold", 1, NULL, 'B'}, - { .name = NULL } +static const struct xt_option_entry ULOG_opts[] = { + {.name = "ulog-nlgroup", .id = O_ULOG_NLGROUP, .type = XTTYPE_UINT8, + .min = 1, .max = 32}, + {.name = "ulog-prefix", .id = O_ULOG_PREFIX, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(struct ipt_ulog_info, prefix), + .min = 1}, + {.name = "ulog-cprange", .id = O_ULOG_CPRANGE, .type = XTTYPE_UINT64}, + {.name = "ulog-qthreshold", .id = O_ULOG_QTHR, .type = XTTYPE_UINT64, + .min = 1, .max = ULOG_MAX_QLEN}, + XTOPT_TABLEEND, }; static void ULOG_init(struct xt_entry_target *t) @@ -58,89 +52,27 @@ static void ULOG_init(struct xt_entry_target *t) } -#define IPT_LOG_OPT_NLGROUP 0x01 -#define IPT_LOG_OPT_PREFIX 0x02 -#define IPT_LOG_OPT_CPRANGE 0x04 -#define IPT_LOG_OPT_QTHRESHOLD 0x08 - -static int ULOG_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void ULOG_parse(struct xt_option_call *cb) { - struct ipt_ulog_info *loginfo = - (struct ipt_ulog_info *) (*target)->data; - int group_d; + struct ipt_ulog_info *loginfo = cb->data; - switch (c) { - case '!': - if (*flags & IPT_LOG_OPT_NLGROUP) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --ulog-nlgroup twice"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --ulog-nlgroup"); - group_d = atoi(optarg); - if (group_d > 32 || group_d < 1) - xtables_error(PARAMETER_PROBLEM, - "--ulog-nlgroup has to be between 1 and 32"); - - loginfo->nl_group = (1 << (group_d - 1)); - - *flags |= IPT_LOG_OPT_NLGROUP; + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_ULOG_NLGROUP: + loginfo->nl_group = 1 << (cb->val.u8 - 1); break; - - case '#': - if (*flags & IPT_LOG_OPT_PREFIX) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --ulog-prefix twice"); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --ulog-prefix"); - - if (strlen(optarg) > sizeof(loginfo->prefix) - 1) - xtables_error(PARAMETER_PROBLEM, - "Maximum prefix length %u for --ulog-prefix", - (unsigned int)sizeof(loginfo->prefix) - 1); - - if (strlen(optarg) == 0) - xtables_error(PARAMETER_PROBLEM, - "No prefix specified for --ulog-prefix"); - - if (strlen(optarg) != strlen(strtok(optarg, "\n"))) + case O_ULOG_PREFIX: + if (strchr(cb->arg, '\n') != NULL) xtables_error(PARAMETER_PROBLEM, "Newlines not allowed in --ulog-prefix"); - - strcpy(loginfo->prefix, optarg); - *flags |= IPT_LOG_OPT_PREFIX; break; - case 'A': - if (*flags & IPT_LOG_OPT_CPRANGE) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --ulog-cprange twice"); - if (atoi(optarg) < 0) - xtables_error(PARAMETER_PROBLEM, - "Negative copy range?"); - loginfo->copy_range = atoi(optarg); - *flags |= IPT_LOG_OPT_CPRANGE; + case O_ULOG_CPRANGE: + loginfo->copy_range = cb->val.u64; break; - case 'B': - if (*flags & IPT_LOG_OPT_QTHRESHOLD) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --ulog-qthreshold twice"); - if (atoi(optarg) < 1) - xtables_error(PARAMETER_PROBLEM, - "Negative or zero queue threshold ?"); - if (atoi(optarg) > ULOG_MAX_QLEN) - xtables_error(PARAMETER_PROBLEM, - "Maximum queue length exceeded"); - loginfo->qthreshold = atoi(optarg); - *flags |= IPT_LOG_OPT_QTHRESHOLD; + case O_ULOG_QTHR: + loginfo->qthreshold = cb->val.u64; break; - default: - return 0; } - return 1; } static void ULOG_save(const void *ip, const struct xt_entry_target *target) @@ -149,19 +81,17 @@ static void ULOG_save(const void *ip, const struct xt_entry_target *target) = (const struct ipt_ulog_info *) target->data; if (strcmp(loginfo->prefix, "") != 0) { - fputs("--ulog-prefix ", stdout); + fputs(" --ulog-prefix", stdout); xtables_save_string(loginfo->prefix); } - if (loginfo->nl_group != ULOG_DEFAULT_NLGROUP) { - printf("--ulog-nlgroup "); - print_groups(loginfo->nl_group); - } + if (loginfo->nl_group != ULOG_DEFAULT_NLGROUP) + printf(" --ulog-nlgroup %d", ffs(loginfo->nl_group)); if (loginfo->copy_range) - printf("--ulog-cprange %u ", (unsigned int)loginfo->copy_range); + printf(" --ulog-cprange %u", (unsigned int)loginfo->copy_range); if (loginfo->qthreshold != ULOG_DEFAULT_QTHRESHOLD) - printf("--ulog-qthreshold %u ", (unsigned int)loginfo->qthreshold); + printf(" --ulog-qthreshold %u", (unsigned int)loginfo->qthreshold); } static void ULOG_print(const void *ip, const struct xt_entry_target *target, @@ -170,12 +100,12 @@ static void ULOG_print(const void *ip, const struct xt_entry_target *target, const struct ipt_ulog_info *loginfo = (const struct ipt_ulog_info *) target->data; - printf("ULOG "); - printf("copy_range %u nlgroup ", (unsigned int)loginfo->copy_range); - print_groups(loginfo->nl_group); + printf(" ULOG "); + printf("copy_range %u nlgroup %d", (unsigned int)loginfo->copy_range, + ffs(loginfo->nl_group)); if (strcmp(loginfo->prefix, "") != 0) - printf("prefix `%s' ", loginfo->prefix); - printf("queue_threshold %u ", (unsigned int)loginfo->qthreshold); + printf(" prefix \"%s\"", loginfo->prefix); + printf(" queue_threshold %u", (unsigned int)loginfo->qthreshold); } static struct xtables_target ulog_tg_reg = { @@ -186,10 +116,10 @@ static struct xtables_target ulog_tg_reg = { .userspacesize = XT_ALIGN(sizeof(struct ipt_ulog_info)), .help = ULOG_help, .init = ULOG_init, - .parse = ULOG_parse, .print = ULOG_print, .save = ULOG_save, - .extra_opts = ULOG_opts, + .x6_parse = ULOG_parse, + .x6_options = ULOG_opts, }; void _init(void) diff --git a/extensions/libipt_ULOG.man b/extensions/libipt_ULOG.man index 649b6e3..c91f776 100644 --- a/extensions/libipt_ULOG.man +++ b/extensions/libipt_ULOG.man @@ -1,4 +1,5 @@ -This target provides userspace logging of matching packets. When this +This is the deprecated ipv4-only predecessor of the NFLOG target. +It provides userspace logging of matching packets. When this target is set for a rule, the Linux kernel will multicast this packet through a .IR netlink diff --git a/extensions/libipt_addrtype.c b/extensions/libipt_addrtype.c deleted file mode 100644 index ad63dcf..0000000 --- a/extensions/libipt_addrtype.c +++ /dev/null @@ -1,360 +0,0 @@ -/* Shared library add-on to iptables to add addrtype matching support - * - * This program is released under the terms of GNU GPL */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <xtables.h> - -#include <linux/netfilter_ipv4/ipt_addrtype.h> - -/* from linux/rtnetlink.h, must match order of enumeration */ -static const char *const rtn_names[] = { - "UNSPEC", - "UNICAST", - "LOCAL", - "BROADCAST", - "ANYCAST", - "MULTICAST", - "BLACKHOLE", - "UNREACHABLE", - "PROHIBIT", - "THROW", - "NAT", - "XRESOLVE", - NULL -}; - -static void addrtype_help_types(void) -{ - int i; - - for (i = 0; rtn_names[i]; i++) - printf(" %s\n", rtn_names[i]); -} - -static void addrtype_help_v0(void) -{ - printf( -"Address type match options:\n" -" [!] --src-type type[,...] Match source address type\n" -" [!] --dst-type type[,...] Match destination address type\n" -"\n" -"Valid types: \n"); - addrtype_help_types(); -} - -static void addrtype_help_v1(void) -{ - printf( -"Address type match options:\n" -" [!] --src-type type[,...] Match source address type\n" -" [!] --dst-type type[,...] Match destination address type\n" -" --limit-iface-in Match only on the packet's incoming device\n" -" --limit-iface-out Match only on the packet's incoming device\n" -"\n" -"Valid types: \n"); - addrtype_help_types(); -} - -static int -parse_type(const char *name, size_t len, u_int16_t *mask) -{ - int i; - - for (i = 0; rtn_names[i]; i++) - if (strncasecmp(name, rtn_names[i], len) == 0) { - /* build up bitmask for kernel module */ - *mask |= (1 << i); - return 1; - } - - return 0; -} - -static void parse_types(const char *arg, u_int16_t *mask) -{ - const char *comma; - - while ((comma = strchr(arg, ',')) != NULL) { - if (comma == arg || !parse_type(arg, comma-arg, mask)) - xtables_error(PARAMETER_PROBLEM, - "addrtype: bad type `%s'", arg); - arg = comma + 1; - } - - if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask)) - xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg); -} - -#define IPT_ADDRTYPE_OPT_SRCTYPE 0x1 -#define IPT_ADDRTYPE_OPT_DSTTYPE 0x2 -#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN 0x4 -#define IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT 0x8 - -static int -addrtype_parse_v0(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ipt_addrtype_info *info = - (struct ipt_addrtype_info *) (*match)->data; - - switch (c) { - case '1': - if (*flags&IPT_ADDRTYPE_OPT_SRCTYPE) - xtables_error(PARAMETER_PROBLEM, - "addrtype: can't specify src-type twice"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_types(optarg, &info->source); - if (invert) - info->invert_source = 1; - *flags |= IPT_ADDRTYPE_OPT_SRCTYPE; - break; - case '2': - if (*flags&IPT_ADDRTYPE_OPT_DSTTYPE) - xtables_error(PARAMETER_PROBLEM, - "addrtype: can't specify dst-type twice"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_types(optarg, &info->dest); - if (invert) - info->invert_dest = 1; - *flags |= IPT_ADDRTYPE_OPT_DSTTYPE; - break; - default: - return 0; - } - - return 1; -} - -static int -addrtype_parse_v1(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ipt_addrtype_info_v1 *info = - (struct ipt_addrtype_info_v1 *) (*match)->data; - - switch (c) { - case '1': - if (*flags & IPT_ADDRTYPE_OPT_SRCTYPE) - xtables_error(PARAMETER_PROBLEM, - "addrtype: can't specify src-type twice"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_types(optarg, &info->source); - if (invert) - info->flags |= IPT_ADDRTYPE_INVERT_SOURCE; - *flags |= IPT_ADDRTYPE_OPT_SRCTYPE; - break; - case '2': - if (*flags & IPT_ADDRTYPE_OPT_DSTTYPE) - xtables_error(PARAMETER_PROBLEM, - "addrtype: can't specify dst-type twice"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_types(optarg, &info->dest); - if (invert) - info->flags |= IPT_ADDRTYPE_INVERT_DEST; - *flags |= IPT_ADDRTYPE_OPT_DSTTYPE; - break; - case '3': - if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN) - xtables_error(PARAMETER_PROBLEM, - "addrtype: can't specify limit-iface-in twice"); - info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_IN; - *flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN; - break; - case '4': - if (*flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT) - xtables_error(PARAMETER_PROBLEM, - "addrtype: can't specify limit-iface-out twice"); - info->flags |= IPT_ADDRTYPE_LIMIT_IFACE_OUT; - *flags |= IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT; - break; - default: - return 0; - } - - return 1; -} - -static void addrtype_check_v0(unsigned int flags) -{ - if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE))) - xtables_error(PARAMETER_PROBLEM, - "addrtype: you must specify --src-type or --dst-type"); -} - -static void addrtype_check_v1(unsigned int flags) -{ - if (!(flags & (IPT_ADDRTYPE_OPT_SRCTYPE|IPT_ADDRTYPE_OPT_DSTTYPE))) - xtables_error(PARAMETER_PROBLEM, - "addrtype: you must specify --src-type or --dst-type"); - if (flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_IN && - flags & IPT_ADDRTYPE_OPT_LIMIT_IFACE_OUT) - xtables_error(PARAMETER_PROBLEM, - "addrtype: you can't specify both --limit-iface-in " - "and --limit-iface-out"); -} - -static void print_types(u_int16_t mask) -{ - const char *sep = ""; - int i; - - for (i = 0; rtn_names[i]; i++) - if (mask & (1 << i)) { - printf("%s%s", sep, rtn_names[i]); - sep = ","; - } - - printf(" "); -} - -static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match, - int numeric) -{ - const struct ipt_addrtype_info *info = - (struct ipt_addrtype_info *) match->data; - - printf("ADDRTYPE match "); - if (info->source) { - printf("src-type "); - if (info->invert_source) - printf("!"); - print_types(info->source); - } - if (info->dest) { - printf("dst-type "); - if (info->invert_dest) - printf("!"); - print_types(info->dest); - } -} - -static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match, - int numeric) -{ - const struct ipt_addrtype_info_v1 *info = - (struct ipt_addrtype_info_v1 *) match->data; - - printf("ADDRTYPE match "); - if (info->source) { - printf("src-type "); - if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE) - printf("!"); - print_types(info->source); - } - if (info->dest) { - printf("dst-type "); - if (info->flags & IPT_ADDRTYPE_INVERT_DEST) - printf("!"); - print_types(info->dest); - } - if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) { - printf("limit-in "); - } - if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) { - printf("limit-out "); - } -} - -static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match) -{ - const struct ipt_addrtype_info *info = - (struct ipt_addrtype_info *) match->data; - - if (info->source) { - if (info->invert_source) - printf("! "); - printf("--src-type "); - print_types(info->source); - } - if (info->dest) { - if (info->invert_dest) - printf("! "); - printf("--dst-type "); - print_types(info->dest); - } -} - -static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match) -{ - const struct ipt_addrtype_info_v1 *info = - (struct ipt_addrtype_info_v1 *) match->data; - - if (info->source) { - if (info->flags & IPT_ADDRTYPE_INVERT_SOURCE) - printf("! "); - printf("--src-type "); - print_types(info->source); - } - if (info->dest) { - if (info->flags & IPT_ADDRTYPE_INVERT_DEST) - printf("! "); - printf("--dst-type "); - print_types(info->dest); - } - if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_IN) { - printf("--limit-iface-in "); - } - if (info->flags & IPT_ADDRTYPE_LIMIT_IFACE_OUT) { - printf("--limit-iface-out "); - } -} - -static const struct option addrtype_opts[] = { - { "src-type", 1, NULL, '1' }, - { "dst-type", 1, NULL, '2' }, - { .name = NULL } -}; - -static const struct option addrtype_opts_v0[] = { - { "src-type", 1, NULL, '1' }, - { "dst-type", 1, NULL, '2' }, - { .name = NULL } -}; - -static const struct option addrtype_opts_v1[] = { - { "src-type", 1, NULL, '1' }, - { "dst-type", 1, NULL, '2' }, - { "limit-iface-in", 0, NULL, '3' }, - { "limit-iface-out", 0, NULL, '4' }, - { .name = NULL } -}; - -static struct xtables_match addrtype_mt_reg[] = { - { - .name = "addrtype", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct ipt_addrtype_info)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_addrtype_info)), - .help = addrtype_help_v0, - .parse = addrtype_parse_v0, - .final_check = addrtype_check_v0, - .print = addrtype_print_v0, - .save = addrtype_save_v0, - .extra_opts = addrtype_opts_v0, - }, - { - .name = "addrtype", - .revision = 1, - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_addrtype_info_v1)), - .help = addrtype_help_v1, - .parse = addrtype_parse_v1, - .final_check = addrtype_check_v1, - .print = addrtype_print_v1, - .save = addrtype_save_v1, - .extra_opts = addrtype_opts_v1, - }, -}; - - -void _init(void) -{ - xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg)); -} diff --git a/extensions/libipt_ah.c b/extensions/libipt_ah.c index 170cd8b..8cf167c 100644 --- a/extensions/libipt_ah.c +++ b/extensions/libipt_ah.c @@ -1,13 +1,11 @@ -/* 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 <xtables.h> #include <linux/netfilter_ipv4/ipt_ah.h> +enum { + O_AHSPI = 0, +}; + static void ah_help(void) { printf( @@ -16,87 +14,26 @@ static void ah_help(void) " match spi (range)\n"); } -static const struct option ah_opts[] = { - { "ahspi", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry ah_opts[] = { + {.name = "ahspi", .id = O_AHSPI, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct ipt_ah, spis)}, + XTOPT_TABLEEND, }; -static u_int32_t -parse_ah_spi(const char *spistr) -{ - unsigned long int spi; - char* ep; - - spi = strtoul(spistr,&ep,0) ; - - if ( spistr == ep ) { - xtables_error(PARAMETER_PROBLEM, - "AH no valid digits in spi `%s'", spistr); - } - if ( spi == ULONG_MAX && errno == ERANGE ) { - xtables_error(PARAMETER_PROBLEM, - "spi `%s' specified too big: would overflow", spistr); - } - if ( *spistr != '\0' && *ep != '\0' ) { - xtables_error(PARAMETER_PROBLEM, - "AH error parsing spi `%s'", spistr); - } - return spi; -} - -static void -parse_ah_spis(const char *spistring, u_int32_t *spis) +static void ah_parse(struct xt_option_call *cb) { - 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); -} - -static void ah_init(struct xt_entry_match *m) -{ - struct ipt_ah *ahinfo = (struct ipt_ah *)m->data; - - ahinfo->spis[1] = 0xFFFFFFFF; -} - -#define AH_SPI 0x01 - -static int ah_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ipt_ah *ahinfo = (struct ipt_ah *)(*match)->data; - - switch (c) { - case '1': - if (*flags & AH_SPI) - xtables_error(PARAMETER_PROBLEM, - "Only one `--ahspi' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_ah_spis(optarg, ahinfo->spis); - if (invert) - ahinfo->invflags |= IPT_AH_INV_SPI; - *flags |= AH_SPI; - break; - default: - return 0; - } + struct ipt_ah *ahinfo = cb->data; - return 1; + xtables_option_parse(cb); + if (cb->nvals == 1) + ahinfo->spis[1] = ahinfo->spis[0]; + if (cb->invert) + ahinfo->invflags |= IPT_AH_INV_SPI; } static void -print_spis(const char *name, u_int32_t min, u_int32_t max, +print_spis(const char *name, uint32_t min, uint32_t max, int invert) { const char *inv = invert ? "!" : ""; @@ -112,7 +49,6 @@ print_spis(const char *name, u_int32_t min, u_int32_t max, printf(":"); printf("%u",max); } - printf(" "); } } @@ -121,11 +57,11 @@ static void ah_print(const void *ip, const struct xt_entry_match *match, { const struct ipt_ah *ah = (struct ipt_ah *)match->data; - printf("ah "); + 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 ", + printf(" Unknown invflags: 0x%X", ah->invflags & ~IPT_AH_INV_MASK); } @@ -135,15 +71,15 @@ static void ah_save(const void *ip, const struct xt_entry_match *match) if (!(ahinfo->spis[0] == 0 && ahinfo->spis[1] == 0xFFFFFFFF)) { - printf("%s--ahspi ", - (ahinfo->invflags & IPT_AH_INV_SPI) ? "! " : ""); + printf("%s --ahspi ", + (ahinfo->invflags & IPT_AH_INV_SPI) ? " !" : ""); if (ahinfo->spis[0] != ahinfo->spis[1]) - printf("%u:%u ", + printf("%u:%u", ahinfo->spis[0], ahinfo->spis[1]); else - printf("%u ", + printf("%u", ahinfo->spis[0]); } @@ -156,11 +92,10 @@ static struct xtables_match ah_mt_reg = { .size = XT_ALIGN(sizeof(struct ipt_ah)), .userspacesize = XT_ALIGN(sizeof(struct ipt_ah)), .help = ah_help, - .init = ah_init, - .parse = ah_parse, .print = ah_print, .save = ah_save, - .extra_opts = ah_opts, + .x6_parse = ah_parse, + .x6_options = ah_opts, }; void diff --git a/extensions/libipt_ecn.c b/extensions/libipt_ecn.c deleted file mode 100644 index ec3ff2d..0000000 --- a/extensions/libipt_ecn.c +++ /dev/null @@ -1,160 +0,0 @@ -/* Shared library add-on to iptables for ECN matching - * - * (C) 2002 by Harald Welte <laforge@gnumonks.org> - * - * This program is distributed under the terms of GNU GPL v2, 1991 - * - * libipt_ecn.c borrowed heavily from libipt_dscp.c - * - */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - -#include <xtables.h> -#include <linux/netfilter_ipv4/ipt_ecn.h> - -static void ecn_help(void) -{ - printf( -"ECN match options\n" -"[!] --ecn-tcp-cwr Match CWR bit of TCP header\n" -"[!] --ecn-tcp-ece Match ECE bit of TCP header\n" -"[!] --ecn-ip-ect [0..3] Match ECN codepoint in IPv4 header\n"); -} - -static const struct option ecn_opts[] = { - { .name = "ecn-tcp-cwr", .has_arg = 0, .val = 'F' }, - { .name = "ecn-tcp-ece", .has_arg = 0, .val = 'G' }, - { .name = "ecn-ip-ect", .has_arg = 1, .val = 'H' }, - { .name = NULL } -}; - -static int ecn_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - unsigned int result; - struct ipt_ecn_info *einfo - = (struct ipt_ecn_info *)(*match)->data; - - switch (c) { - case 'F': - if (*flags & IPT_ECN_OP_MATCH_CWR) - xtables_error(PARAMETER_PROBLEM, - "ECN match: can only use parameter ONCE!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - einfo->operation |= IPT_ECN_OP_MATCH_CWR; - if (invert) - einfo->invert |= IPT_ECN_OP_MATCH_CWR; - *flags |= IPT_ECN_OP_MATCH_CWR; - break; - - case 'G': - if (*flags & IPT_ECN_OP_MATCH_ECE) - xtables_error(PARAMETER_PROBLEM, - "ECN match: can only use parameter ONCE!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - einfo->operation |= IPT_ECN_OP_MATCH_ECE; - if (invert) - einfo->invert |= IPT_ECN_OP_MATCH_ECE; - *flags |= IPT_ECN_OP_MATCH_ECE; - break; - - case 'H': - if (*flags & IPT_ECN_OP_MATCH_IP) - xtables_error(PARAMETER_PROBLEM, - "ECN match: can only use parameter ONCE!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) - einfo->invert |= IPT_ECN_OP_MATCH_IP; - *flags |= IPT_ECN_OP_MATCH_IP; - einfo->operation |= IPT_ECN_OP_MATCH_IP; - if (!xtables_strtoui(optarg, NULL, &result, 0, 3)) - xtables_error(PARAMETER_PROBLEM, - "ECN match: Value out of range"); - einfo->ip_ect = result; - break; - default: - return 0; - } - - return 1; -} - -static void ecn_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "ECN match: some option required"); -} - -static void ecn_print(const void *ip, const struct xt_entry_match *match, - int numeric) -{ - const struct ipt_ecn_info *einfo = - (const struct ipt_ecn_info *)match->data; - - printf("ECN match "); - - if (einfo->operation & IPT_ECN_OP_MATCH_ECE) { - if (einfo->invert & IPT_ECN_OP_MATCH_ECE) - fputc('!', stdout); - printf("ECE "); - } - - if (einfo->operation & IPT_ECN_OP_MATCH_CWR) { - if (einfo->invert & IPT_ECN_OP_MATCH_CWR) - fputc('!', stdout); - printf("CWR "); - } - - if (einfo->operation & IPT_ECN_OP_MATCH_IP) { - if (einfo->invert & IPT_ECN_OP_MATCH_IP) - fputc('!', stdout); - printf("ECT=%d ", einfo->ip_ect); - } -} - -static void ecn_save(const void *ip, const struct xt_entry_match *match) -{ - const struct ipt_ecn_info *einfo = - (const struct ipt_ecn_info *)match->data; - - if (einfo->operation & IPT_ECN_OP_MATCH_ECE) { - if (einfo->invert & IPT_ECN_OP_MATCH_ECE) - printf("! "); - printf("--ecn-tcp-ece "); - } - - if (einfo->operation & IPT_ECN_OP_MATCH_CWR) { - if (einfo->invert & IPT_ECN_OP_MATCH_CWR) - printf("! "); - printf("--ecn-tcp-cwr "); - } - - if (einfo->operation & IPT_ECN_OP_MATCH_IP) { - if (einfo->invert & IPT_ECN_OP_MATCH_IP) - printf("! "); - printf("--ecn-ip-ect %d", einfo->ip_ect); - } -} - -static struct xtables_match ecn_mt_reg = { - .name = "ecn", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct ipt_ecn_info)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_ecn_info)), - .help = ecn_help, - .parse = ecn_parse, - .final_check = ecn_check, - .print = ecn_print, - .save = ecn_save, - .extra_opts = ecn_opts, -}; - -void _init(void) -{ - xtables_register_match(&ecn_mt_reg); -} diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c index 37b2fdc..666e7da 100644 --- a/extensions/libipt_icmp.c +++ b/extensions/libipt_icmp.c @@ -1,11 +1,8 @@ -/* Shared library add-on to iptables to add ICMP support. */ +#include <stdint.h> #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> -#include <limits.h> /* INT_MAX in ip_tables.h */ +#include <limits.h> /* INT_MAX in ip6_tables.h */ #include <linux/netfilter_ipv4/ip_tables.h> /* special hack for icmp-type 'any': @@ -16,10 +13,14 @@ * See: https://bugzilla.netfilter.org/cgi-bin/bugzilla/show_bug.cgi?id=37 */ +enum { + O_ICMP_TYPE = 0, +}; + struct icmp_names { const char *name; - u_int8_t type; - u_int8_t code_min, code_max; + uint8_t type; + uint8_t code_min, code_max; }; static const struct icmp_names icmp_codes[] = { @@ -107,13 +108,14 @@ static void icmp_help(void) print_icmptypes(); } -static const struct option icmp_opts[] = { - { "icmp-type", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry icmp_opts[] = { + {.name = "icmp-type", .id = O_ICMP_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; static void -parse_icmp(const char *icmptype, u_int8_t *type, u_int8_t code[]) +parse_icmp(const char *icmptype, uint8_t *type, uint8_t code[]) { static const unsigned int limit = ARRAY_SIZE(icmp_codes); unsigned int match = limit; @@ -173,33 +175,18 @@ static void icmp_init(struct xt_entry_match *m) icmpinfo->code[1] = 0xFF; } -static int icmp_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void icmp_parse(struct xt_option_call *cb) { - struct ipt_icmp *icmpinfo = (struct ipt_icmp *)(*match)->data; - - switch (c) { - case '1': - if (*flags == 1) - xtables_error(PARAMETER_PROBLEM, - "icmp match: only use --icmp-type once!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_icmp(optarg, &icmpinfo->type, - icmpinfo->code); - if (invert) - icmpinfo->invflags |= IPT_ICMP_INV; - *flags = 1; - break; - - default: - return 0; - } + struct ipt_icmp *icmpinfo = cb->data; - return 1; + xtables_option_parse(cb); + parse_icmp(cb->arg, &icmpinfo->type, icmpinfo->code); + if (cb->invert) + icmpinfo->invflags |= IPT_ICMP_INV; } -static void print_icmptype(u_int8_t type, - u_int8_t code_min, u_int8_t code_max, +static void print_icmptype(uint8_t type, + uint8_t code_min, uint8_t code_max, int invert, int numeric) { @@ -213,7 +200,7 @@ static void print_icmptype(u_int8_t type, break; if (i != ARRAY_SIZE(icmp_codes)) { - printf("%s%s ", + printf(" %s%s", invert ? "!" : "", icmp_codes[i].name); return; @@ -221,15 +208,13 @@ static void print_icmptype(u_int8_t type, } if (invert) - printf("!"); + printf(" !"); printf("type %u", type); - if (code_min == 0 && code_max == 0xFF) - printf(" "); - else if (code_min == code_max) - printf(" code %u ", code_min); - else - printf(" codes %u-%u ", code_min, code_max); + if (code_min == code_max) + printf(" code %u", code_min); + else if (code_min != 0 || code_max != 0xFF) + printf(" codes %u-%u", code_min, code_max); } static void icmp_print(const void *ip, const struct xt_entry_match *match, @@ -237,13 +222,13 @@ static void icmp_print(const void *ip, const struct xt_entry_match *match, { const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; - printf("icmp "); + printf(" icmp"); print_icmptype(icmp->type, icmp->code[0], icmp->code[1], icmp->invflags & IPT_ICMP_INV, numeric); if (icmp->invflags & ~IPT_ICMP_INV) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", icmp->invflags & ~IPT_ICMP_INV); } @@ -252,16 +237,15 @@ static void icmp_save(const void *ip, const struct xt_entry_match *match) const struct ipt_icmp *icmp = (struct ipt_icmp *)match->data; if (icmp->invflags & IPT_ICMP_INV) - printf("! "); + printf(" !"); /* special hack for 'any' case */ if (icmp->type == 0xFF) { - printf("--icmp-type any "); + printf(" --icmp-type any"); } else { - printf("--icmp-type %u", icmp->type); + printf(" --icmp-type %u", icmp->type); if (icmp->code[0] != 0 || icmp->code[1] != 0xFF) printf("/%u", icmp->code[0]); - printf(" "); } } @@ -273,10 +257,10 @@ static struct xtables_match icmp_mt_reg = { .userspacesize = XT_ALIGN(sizeof(struct ipt_icmp)), .help = icmp_help, .init = icmp_init, - .parse = icmp_parse, .print = icmp_print, .save = icmp_save, - .extra_opts = icmp_opts, + .x6_parse = icmp_parse, + .x6_options = icmp_opts, }; void _init(void) diff --git a/extensions/libipt_realm.c b/extensions/libipt_realm.c index cd4b324..a8d9dda 100644 --- a/extensions/libipt_realm.c +++ b/extensions/libipt_realm.c @@ -1,11 +1,7 @@ -/* Shared library add-on to iptables to add realm matching support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> #include <errno.h> -#include <ctype.h> -#include <getopt.h> #if defined(__GLIBC__) && __GLIBC__ == 2 #include <net/ethernet.h> #else @@ -14,6 +10,10 @@ #include <xtables.h> #include <linux/netfilter_ipv4/ipt_realm.h> +enum { + O_REALM = 0, +}; + static void realm_help(void) { printf( @@ -22,168 +22,49 @@ static void realm_help(void) " Match realm\n"); } -static const struct option realm_opts[] = { - { "realm", 1, NULL, '1' }, - { .name = NULL } -}; - -struct realmname { - int id; - char* name; - int len; - struct realmname* next; +static const struct xt_option_entry realm_opts[] = { + {.name = "realm", .id = O_REALM, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; /* array of realms from /etc/iproute2/rt_realms */ -static struct realmname *realms; -/* 1 if loading failed */ -static int rdberr; +static struct xtables_lmap *realms; -static void load_realms(void) +static void realm_init(struct xt_entry_match *m) { - const char* rfnm = "/etc/iproute2/rt_realms"; - char buf[512]; - FILE *fil; - char *cur, *nxt; - int id; - struct realmname *oldnm = NULL, *newnm = NULL; - - fil = fopen(rfnm, "r"); - if (!fil) { - rdberr = 1; - return; - } - - while (fgets(buf, sizeof(buf), fil)) { - cur = buf; - while ((*cur == ' ') || (*cur == '\t')) - cur++; - if ((*cur == '#') || (*cur == '\n') || (*cur == 0)) - continue; - - /* iproute2 allows hex and dec format */ - errno = 0; - id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) ? 10 : 16); - if ((nxt == cur) || errno) - continue; - - /* same boundaries as in iproute2 */ - if (id < 0 || id > 255) - continue; - cur = nxt; - - if (!isspace(*cur)) - continue; - while ((*cur == ' ') || (*cur == '\t')) - cur++; - if ((*cur == '#') || (*cur == '\n') || (*cur == 0)) - continue; - nxt = cur; - while ((*nxt != 0) && !isspace(*nxt)) - nxt++; - if (nxt == cur) - continue; - - /* found valid data */ - newnm = malloc(sizeof(struct realmname)); - if (newnm == NULL) { - perror("libipt_realm: malloc failed"); - exit(1); - } - newnm->id = id; - newnm->len = nxt - cur; - newnm->name = malloc(newnm->len + 1); - if (newnm->name == NULL) { - perror("libipt_realm: malloc failed"); - exit(1); - } - strncpy(newnm->name, cur, newnm->len); - newnm->name[newnm->len] = 0; - newnm->next = NULL; - - if (oldnm) - oldnm->next = newnm; - else - realms = newnm; - oldnm = newnm; - } - - fclose(fil); + const char file[] = "/etc/iproute2/rt_realms"; + realms = xtables_lmap_init(file); + if (realms == NULL && errno != ENOENT) + fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno)); } -/* get realm id for name, -1 if error/not found */ -static int realm_name2id(const char* name) +static void realm_parse(struct xt_option_call *cb) { - struct realmname* cur; - - if ((realms == NULL) && (rdberr == 0)) - load_realms(); - cur = realms; - if (cur == NULL) - return -1; - while (cur) { - if (!strncmp(name, cur->name, cur->len + 1)) - return cur->id; - cur = cur->next; - } - return -1; -} - -/* get realm name for id, NULL if error/not found */ -static const char *realm_id2name(int id) -{ - struct realmname* cur; - - if ((realms == NULL) && (rdberr == 0)) - load_realms(); - cur = realms; - if (cur == NULL) - return NULL; - while (cur) { - if (id == cur->id) - return cur->name; - cur = cur->next; - } - return NULL; -} - -static int realm_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct ipt_realm_info *realminfo = (struct ipt_realm_info *)(*match)->data; + struct xt_realm_info *realminfo = cb->data; int id; + char *end; - switch (c) { - char *end; - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - end = optarg = optarg; - realminfo->id = strtoul(optarg, &end, 0); - if (end != optarg && (*end == '/' || *end == '\0')) { - if (*end == '/') - realminfo->mask = strtoul(end+1, &end, 0); - else - realminfo->mask = 0xffffffff; - if (*end != '\0' || end == optarg) - xtables_error(PARAMETER_PROBLEM, - "Bad realm value `%s'", optarg); - } else { - id = realm_name2id(optarg); - if (id == -1) - xtables_error(PARAMETER_PROBLEM, - "Realm `%s' not found", optarg); - realminfo->id = id; + xtables_option_parse(cb); + realminfo->id = strtoul(cb->arg, &end, 0); + if (end != cb->arg && (*end == '/' || *end == '\0')) { + if (*end == '/') + realminfo->mask = strtoul(end+1, &end, 0); + else realminfo->mask = 0xffffffff; - } - if (invert) - realminfo->invert = 1; - *flags = 1; - break; - - default: - return 0; + if (*end != '\0' || end == cb->arg) + xtables_error(PARAMETER_PROBLEM, + "Bad realm value \"%s\"", cb->arg); + } else { + id = xtables_lmap_name2id(realms, cb->arg); + if (id == -1) + xtables_error(PARAMETER_PROBLEM, + "Realm \"%s\" not found", cb->arg); + realminfo->id = id; + realminfo->mask = 0xffffffff; } - return 1; + if (cb->invert) + realminfo->invert = 1; } static void @@ -192,59 +73,52 @@ print_realm(unsigned long id, unsigned long mask, int numeric) const char* name = NULL; if (mask != 0xffffffff) - printf("0x%lx/0x%lx ", id, mask); + printf(" 0x%lx/0x%lx", id, mask); else { if (numeric == 0) - name = realm_id2name(id); + name = xtables_lmap_id2name(realms, id); if (name) - printf("%s ", name); + printf(" %s", name); else - printf("0x%lx ", id); + printf(" 0x%lx", id); } } static void realm_print(const void *ip, const struct xt_entry_match *match, int numeric) { - const struct ipt_realm_info *ri = (const void *)match->data; + const struct xt_realm_info *ri = (const void *)match->data; if (ri->invert) - printf("! "); + printf(" !"); - printf("realm "); + printf(" realm"); print_realm(ri->id, ri->mask, numeric); } static void realm_save(const void *ip, const struct xt_entry_match *match) { - const struct ipt_realm_info *ri = (const void *)match->data; + const struct xt_realm_info *ri = (const void *)match->data; if (ri->invert) - printf("! "); + printf(" !"); - printf("--realm "); + printf(" --realm"); print_realm(ri->id, ri->mask, 0); } -static void realm_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "realm match: You must specify `--realm'"); -} - static struct xtables_match realm_mt_reg = { .name = "realm", .version = XTABLES_VERSION, .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct ipt_realm_info)), - .userspacesize = XT_ALIGN(sizeof(struct ipt_realm_info)), + .size = XT_ALIGN(sizeof(struct xt_realm_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_realm_info)), .help = realm_help, - .parse = realm_parse, - .final_check = realm_check, + .init = realm_init, .print = realm_print, .save = realm_save, - .extra_opts = realm_opts, + .x6_parse = realm_parse, + .x6_options = realm_opts, }; void _init(void) diff --git a/extensions/libipt_ttl.c b/extensions/libipt_ttl.c index e2fbcd5..5fe08cc 100644 --- a/extensions/libipt_ttl.c +++ b/extensions/libipt_ttl.c @@ -1,89 +1,51 @@ /* Shared library add-on to iptables to add TTL matching support * (C) 2000 by Harald Welte <laforge@gnumonks.org> * - * $Id$ - * * This program is released under the terms of GNU GPL */ - #include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> #include <xtables.h> - #include <linux/netfilter_ipv4/ipt_ttl.h> +enum { + O_TTL_EQ = 0, + O_TTL_LT, + O_TTL_GT, + F_TTL_EQ = 1 << O_TTL_EQ, + F_TTL_LT = 1 << O_TTL_LT, + F_TTL_GT = 1 << O_TTL_GT, + F_ANY = F_TTL_EQ | F_TTL_LT | F_TTL_GT, +}; + static void ttl_help(void) { printf( "ttl match options:\n" -" --ttl-eq value Match time to live value\n" +"[!] --ttl-eq value Match time to live value\n" " --ttl-lt value Match TTL < value\n" " --ttl-gt value Match TTL > value\n"); } -static int ttl_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void ttl_parse(struct xt_option_call *cb) { - struct ipt_ttl_info *info = (struct ipt_ttl_info *) (*match)->data; - unsigned int value; - - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - switch (c) { - case '2': - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "ttl: Expected value between 0 and 255"); - - if (invert) - info->mode = IPT_TTL_NE; - else - info->mode = IPT_TTL_EQ; - - /* is 0 allowed? */ - info->ttl = value; - break; - case '3': - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "ttl: Expected value between 0 and 255"); - - if (invert) - xtables_error(PARAMETER_PROBLEM, - "ttl: unexpected `!'"); - - info->mode = IPT_TTL_LT; - info->ttl = value; - break; - case '4': - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "ttl: Expected value between 0 and 255"); - - if (invert) - xtables_error(PARAMETER_PROBLEM, - "ttl: unexpected `!'"); - - info->mode = IPT_TTL_GT; - info->ttl = value; - break; - default: - return 0; - + struct ipt_ttl_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TTL_EQ: + info->mode = cb->invert ? IPT_TTL_NE : IPT_TTL_EQ; + break; + case O_TTL_LT: + info->mode = IPT_TTL_LT; + break; + case O_TTL_GT: + info->mode = IPT_TTL_GT; + break; } - - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "Can't specify TTL option twice"); - *flags = 1; - - return 1; } -static void ttl_check(unsigned int flags) +static void ttl_check(struct xt_fcheck_call *cb) { - if (!flags) + if (!(cb->xflags & F_ANY)) xtables_error(PARAMETER_PROBLEM, "TTL match: You must specify one of " "`--ttl-eq', `--ttl-lt', `--ttl-gt"); @@ -95,22 +57,22 @@ static void ttl_print(const void *ip, const struct xt_entry_match *match, const struct ipt_ttl_info *info = (struct ipt_ttl_info *) match->data; - printf("TTL match "); + printf(" TTL match "); switch (info->mode) { case IPT_TTL_EQ: - printf("TTL == "); + printf("TTL =="); break; case IPT_TTL_NE: - printf("TTL != "); + printf("TTL !="); break; case IPT_TTL_LT: - printf("TTL < "); + printf("TTL <"); break; case IPT_TTL_GT: - printf("TTL > "); + printf("TTL >"); break; } - printf("%u ", info->ttl); + printf(" %u", info->ttl); } static void ttl_save(const void *ip, const struct xt_entry_match *match) @@ -120,31 +82,37 @@ static void ttl_save(const void *ip, const struct xt_entry_match *match) switch (info->mode) { case IPT_TTL_EQ: - printf("--ttl-eq "); + printf(" --ttl-eq"); break; case IPT_TTL_NE: - printf("! --ttl-eq "); + printf(" ! --ttl-eq"); break; case IPT_TTL_LT: - printf("--ttl-lt "); + printf(" --ttl-lt"); break; case IPT_TTL_GT: - printf("--ttl-gt "); + printf(" --ttl-gt"); break; default: /* error */ break; } - printf("%u ", info->ttl); + printf(" %u", info->ttl); } -static const struct option ttl_opts[] = { - { "ttl", 1, NULL, '2' }, - { "ttl-eq", 1, NULL, '2'}, - { "ttl-lt", 1, NULL, '3'}, - { "ttl-gt", 1, NULL, '4'}, - { .name = NULL } +#define s struct ipt_ttl_info +static const struct xt_option_entry ttl_opts[] = { + {.name = "ttl-lt", .id = O_TTL_LT, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl)}, + {.name = "ttl-gt", .id = O_TTL_GT, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl)}, + {.name = "ttl-eq", .id = O_TTL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, ttl)}, + {.name = "ttl", .id = O_TTL_EQ, .excl = F_ANY, .type = XTTYPE_UINT8, + .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl)}, + XTOPT_TABLEEND, }; +#undef s static struct xtables_match ttl_mt_reg = { .name = "ttl", @@ -153,11 +121,11 @@ static struct xtables_match ttl_mt_reg = { .size = XT_ALIGN(sizeof(struct ipt_ttl_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_ttl_info)), .help = ttl_help, - .parse = ttl_parse, - .final_check = ttl_check, .print = ttl_print, .save = ttl_save, - .extra_opts = ttl_opts, + .x6_parse = ttl_parse, + .x6_fcheck = ttl_check, + .x6_options = ttl_opts, }; diff --git a/extensions/libipt_ttl.man b/extensions/libipt_ttl.man index 849f704..1f32277 100644 --- a/extensions/libipt_ttl.man +++ b/extensions/libipt_ttl.man @@ -1,6 +1,6 @@ This module matches the time to live field in the IP header. .TP -\fB\-\-ttl\-eq\fP \fIttl\fP +[\fB!\fP] \fB\-\-ttl\-eq\fP \fIttl\fP Matches the given TTL value. .TP \fB\-\-ttl\-gt\fP \fIttl\fP diff --git a/extensions/libxt_AUDIT.c b/extensions/libxt_AUDIT.c new file mode 100644 index 0000000..86a61cb --- /dev/null +++ b/extensions/libxt_AUDIT.c @@ -0,0 +1,101 @@ +/* Shared library add-on to xtables for AUDIT + * + * (C) 2010-2011, Thomas Graf <tgraf@redhat.com> + * (C) 2010-2011, Red Hat, Inc. + * + * This program is distributed under the terms of GNU GPL v2, 1991 + */ +#include <stdio.h> +#include <string.h> +#include <xtables.h> +#include <linux/netfilter/xt_AUDIT.h> + +enum { + O_AUDIT_TYPE = 0, +}; + +static void audit_help(void) +{ + printf( +"AUDIT target options\n" +" --type TYPE Action type to be recorded.\n"); +} + +static const struct xt_option_entry audit_opts[] = { + {.name = "type", .id = O_AUDIT_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + XTOPT_TABLEEND, +}; + +static void audit_parse(struct xt_option_call *cb) +{ + struct xt_audit_info *einfo = cb->data; + + xtables_option_parse(cb); + if (strcasecmp(cb->arg, "accept") == 0) + einfo->type = XT_AUDIT_TYPE_ACCEPT; + else if (strcasecmp(cb->arg, "drop") == 0) + einfo->type = XT_AUDIT_TYPE_DROP; + else if (strcasecmp(cb->arg, "reject") == 0) + einfo->type = XT_AUDIT_TYPE_REJECT; + else + xtables_error(PARAMETER_PROBLEM, + "Bad action type value \"%s\"", cb->arg); +} + +static void audit_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct xt_audit_info *einfo = + (const struct xt_audit_info *)target->data; + + printf(" AUDIT "); + + switch(einfo->type) { + case XT_AUDIT_TYPE_ACCEPT: + printf("accept"); + break; + case XT_AUDIT_TYPE_DROP: + printf("drop"); + break; + case XT_AUDIT_TYPE_REJECT: + printf("reject"); + break; + } +} + +static void audit_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_audit_info *einfo = + (const struct xt_audit_info *)target->data; + + switch(einfo->type) { + case XT_AUDIT_TYPE_ACCEPT: + printf(" --type accept"); + break; + case XT_AUDIT_TYPE_DROP: + printf(" --type drop"); + break; + case XT_AUDIT_TYPE_REJECT: + printf(" --type reject"); + break; + } +} + +static struct xtables_target audit_tg_reg = { + .name = "AUDIT", + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_audit_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_audit_info)), + .help = audit_help, + .print = audit_print, + .save = audit_save, + .x6_parse = audit_parse, + .x6_options = audit_opts, +}; + +void _init(void) +{ + xtables_register_target(&audit_tg_reg); +} diff --git a/extensions/libxt_AUDIT.man b/extensions/libxt_AUDIT.man new file mode 100644 index 0000000..cd79696 --- /dev/null +++ b/extensions/libxt_AUDIT.man @@ -0,0 +1,14 @@ +This target allows to create audit records for packets hitting the target. +It can be used to record accepted, dropped, and rejected packets. See +auditd(8) for additional details. +.TP +\fB\-\-type\fP {\fBaccept\fP|\fBdrop\fP|\fBreject\fP} +Set type of audit record. +.PP +Example: +.IP +iptables \-N AUDIT_DROP +.IP +iptables \-A AUDIT_DROP \-j AUDIT \-\-type drop +.IP +iptables \-A AUDIT_DROP \-j DROP diff --git a/extensions/libxt_CHECKSUM.c b/extensions/libxt_CHECKSUM.c new file mode 100644 index 0000000..df9f9b3 --- /dev/null +++ b/extensions/libxt_CHECKSUM.c @@ -0,0 +1,77 @@ +/* Shared library add-on to xtables for CHECKSUM + * + * (C) 2002 by Harald Welte <laforge@gnumonks.org> + * (C) 2010 by Red Hat, Inc + * Author: Michael S. Tsirkin <mst@redhat.com> + * + * This program is distributed under the terms of GNU GPL v2, 1991 + * + * libxt_CHECKSUM.c borrowed some bits from libipt_ECN.c + */ +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter/xt_CHECKSUM.h> + +enum { + O_CHECKSUM_FILL = 0, +}; + +static void CHECKSUM_help(void) +{ + printf( +"CHECKSUM target options\n" +" --checksum-fill Fill in packet checksum.\n"); +} + +static const struct xt_option_entry CHECKSUM_opts[] = { + {.name = "checksum-fill", .id = O_CHECKSUM_FILL, + .flags = XTOPT_MAND, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static void CHECKSUM_parse(struct xt_option_call *cb) +{ + struct xt_CHECKSUM_info *einfo = cb->data; + + xtables_option_parse(cb); + einfo->operation = XT_CHECKSUM_OP_FILL; +} + +static void CHECKSUM_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct xt_CHECKSUM_info *einfo = + (const struct xt_CHECKSUM_info *)target->data; + + printf(" CHECKSUM"); + + if (einfo->operation & XT_CHECKSUM_OP_FILL) + printf(" fill"); +} + +static void CHECKSUM_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_CHECKSUM_info *einfo = + (const struct xt_CHECKSUM_info *)target->data; + + if (einfo->operation & XT_CHECKSUM_OP_FILL) + printf(" --checksum-fill"); +} + +static struct xtables_target checksum_tg_reg = { + .name = "CHECKSUM", + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_CHECKSUM_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_CHECKSUM_info)), + .help = CHECKSUM_help, + .print = CHECKSUM_print, + .save = CHECKSUM_save, + .x6_parse = CHECKSUM_parse, + .x6_options = CHECKSUM_opts, +}; + +void _init(void) +{ + xtables_register_target(&checksum_tg_reg); +} diff --git a/extensions/libxt_CHECKSUM.man b/extensions/libxt_CHECKSUM.man new file mode 100644 index 0000000..92ae700 --- /dev/null +++ b/extensions/libxt_CHECKSUM.man @@ -0,0 +1,8 @@ +This target allows to selectively work around broken/old applications. +It can only be used in the mangle table. +.TP +\fB\-\-checksum\-fill\fP +Compute and fill in the checksum in a packet that lacks a checksum. +This is particularly useful, if you need to work around old applications +such as dhcp clients, that do not work well with checksum offloads, +but don't want to disable checksum offload in your device. diff --git a/extensions/libxt_CLASSIFY.c b/extensions/libxt_CLASSIFY.c index 82b8f4e..e04657a 100644 --- a/extensions/libxt_CLASSIFY.c +++ b/extensions/libxt_CLASSIFY.c @@ -1,15 +1,16 @@ -/* Shared library add-on to iptables to add CLASSIFY target support. */ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> +/* + * Copyright (c) 2003-2013 Patrick McHardy <kaber@trash.net> + */ +#include <stdio.h> #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_CLASSIFY.h> -#include <linux/types.h> #include <linux/pkt_sched.h> +enum { + O_SET_CLASS = 0, +}; + static void CLASSIFY_help(void) { @@ -18,9 +19,10 @@ CLASSIFY_help(void) "--set-class MAJOR:MINOR Set skb->priority value (always hexadecimal!)\n"); } -static const struct option CLASSIFY_opts[] = { - { "set-class", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry CLASSIFY_opts[] = { + {.name = "set-class", .id = O_SET_CLASS, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + XTOPT_TABLEEND, }; static int CLASSIFY_string_to_priority(const char *s, unsigned int *p) @@ -34,44 +36,20 @@ static int CLASSIFY_string_to_priority(const char *s, unsigned int *p) return 0; } -static int -CLASSIFY_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, - struct xt_entry_target **target) +static void CLASSIFY_parse(struct xt_option_call *cb) { - struct xt_classify_target_info *clinfo - = (struct xt_classify_target_info *)(*target)->data; - - switch (c) { - case '1': - if (CLASSIFY_string_to_priority(optarg, &clinfo->priority)) - xtables_error(PARAMETER_PROBLEM, - "Bad class value `%s'", optarg); - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "CLASSIFY: Can't specify --set-class twice"); - *flags = 1; - break; + struct xt_classify_target_info *clinfo = cb->data; - default: - return 0; - } - - return 1; -} - -static void -CLASSIFY_final_check(unsigned int flags) -{ - if (!flags) + xtables_option_parse(cb); + if (CLASSIFY_string_to_priority(cb->arg, &clinfo->priority)) xtables_error(PARAMETER_PROBLEM, - "CLASSIFY: Parameter --set-class is required"); + "Bad class value \"%s\"", cb->arg); } static void CLASSIFY_print_class(unsigned int priority, int numeric) { - printf("%x:%x ", TC_H_MAJ(priority)>>16, TC_H_MIN(priority)); + printf(" %x:%x", TC_H_MAJ(priority)>>16, TC_H_MIN(priority)); } static void @@ -81,7 +59,7 @@ CLASSIFY_print(const void *ip, { const struct xt_classify_target_info *clinfo = (const struct xt_classify_target_info *)target->data; - printf("CLASSIFY set "); + printf(" CLASSIFY set"); CLASSIFY_print_class(clinfo->priority, numeric); } @@ -91,7 +69,7 @@ CLASSIFY_save(const void *ip, const struct xt_entry_target *target) const struct xt_classify_target_info *clinfo = (const struct xt_classify_target_info *)target->data; - printf("--set-class %.4x:%.4x ", + printf(" --set-class %.4x:%.4x", TC_H_MAJ(clinfo->priority)>>16, TC_H_MIN(clinfo->priority)); } @@ -102,11 +80,10 @@ static struct xtables_target classify_target = { .size = XT_ALIGN(sizeof(struct xt_classify_target_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_classify_target_info)), .help = CLASSIFY_help, - .parse = CLASSIFY_parse, - .final_check = CLASSIFY_final_check, .print = CLASSIFY_print, .save = CLASSIFY_save, - .extra_opts = CLASSIFY_opts, + .x6_parse = CLASSIFY_parse, + .x6_options = CLASSIFY_opts, }; void _init(void) diff --git a/extensions/libxt_CONNMARK.c b/extensions/libxt_CONNMARK.c index 6aba5f3..5d5351e 100644 --- a/extensions/libxt_CONNMARK.c +++ b/extensions/libxt_CONNMARK.c @@ -19,24 +19,41 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <stdbool.h> +#include <stdint.h> #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_CONNMARK.h> struct xt_connmark_target_info { unsigned long mark; unsigned long mask; - u_int8_t mode; + uint8_t mode; }; enum { - F_MARK = 1 << 0, - F_SR_MARK = 1 << 1, + O_SET_MARK = 0, + O_SAVE_MARK, + O_RESTORE_MARK, + O_AND_MARK, + O_OR_MARK, + O_XOR_MARK, + O_SET_XMARK, + O_CTMASK, + O_NFMASK, + O_MASK, + F_SET_MARK = 1 << O_SET_MARK, + F_SAVE_MARK = 1 << O_SAVE_MARK, + F_RESTORE_MARK = 1 << O_RESTORE_MARK, + F_AND_MARK = 1 << O_AND_MARK, + F_OR_MARK = 1 << O_OR_MARK, + F_XOR_MARK = 1 << O_XOR_MARK, + F_SET_XMARK = 1 << O_SET_XMARK, + F_CTMASK = 1 << O_CTMASK, + F_NFMASK = 1 << O_NFMASK, + F_MASK = 1 << O_MASK, + F_OP_ANY = F_SET_MARK | F_SAVE_MARK | F_RESTORE_MARK | + F_AND_MARK | F_OR_MARK | F_XOR_MARK | F_SET_XMARK, }; static void CONNMARK_help(void) @@ -48,27 +65,44 @@ static void CONNMARK_help(void) " --restore-mark [--mask mask] Restore saved nfmark value\n"); } -static const struct option CONNMARK_opts[] = { - { "set-mark", 1, NULL, '1' }, - { "save-mark", 0, NULL, '2' }, - { "restore-mark", 0, NULL, '3' }, - { "mask", 1, NULL, '4' }, - { .name = NULL } +#define s struct xt_connmark_target_info +static const struct xt_option_entry CONNMARK_opts[] = { + {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32, + .excl = F_OP_ANY}, + {.name = "save-mark", .id = O_SAVE_MARK, .type = XTTYPE_NONE, + .excl = F_OP_ANY}, + {.name = "restore-mark", .id = O_RESTORE_MARK, .type = XTTYPE_NONE, + .excl = F_OP_ANY}, + {.name = "mask", .id = O_MASK, .type = XTTYPE_UINT32}, + XTOPT_TABLEEND, }; - -static const struct option connmark_tg_opts[] = { - {.name = "set-xmark", .has_arg = true, .val = '='}, - {.name = "set-mark", .has_arg = true, .val = '-'}, - {.name = "and-mark", .has_arg = true, .val = '&'}, - {.name = "or-mark", .has_arg = true, .val = '|'}, - {.name = "xor-mark", .has_arg = true, .val = '^'}, - {.name = "save-mark", .has_arg = false, .val = 'S'}, - {.name = "restore-mark", .has_arg = false, .val = 'R'}, - {.name = "ctmask", .has_arg = true, .val = 'c'}, - {.name = "nfmask", .has_arg = true, .val = 'n'}, - {.name = "mask", .has_arg = true, .val = 'm'}, - {.name = NULL}, +#undef s + +#define s struct xt_connmark_tginfo1 +static const struct xt_option_entry connmark_tg_opts[] = { + {.name = "set-xmark", .id = O_SET_XMARK, .type = XTTYPE_MARKMASK32, + .excl = F_OP_ANY}, + {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32, + .excl = F_OP_ANY}, + {.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32, + .excl = F_OP_ANY}, + {.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32, + .excl = F_OP_ANY}, + {.name = "xor-mark", .id = O_XOR_MARK, .type = XTTYPE_UINT32, + .excl = F_OP_ANY}, + {.name = "save-mark", .id = O_SAVE_MARK, .type = XTTYPE_NONE, + .excl = F_OP_ANY}, + {.name = "restore-mark", .id = O_RESTORE_MARK, .type = XTTYPE_NONE, + .excl = F_OP_ANY}, + {.name = "ctmask", .id = O_CTMASK, .type = XTTYPE_UINT32, + .excl = F_MASK, .flags = XTOPT_PUT, XTOPT_POINTER(s, ctmask)}, + {.name = "nfmask", .id = O_NFMASK, .type = XTTYPE_UINT32, + .excl = F_MASK, .flags = XTOPT_PUT, XTOPT_POINTER(s, nfmask)}, + {.name = "mask", .id = O_MASK, .type = XTTYPE_UINT32, + .excl = F_CTMASK | F_NFMASK}, + XTOPT_TABLEEND, }; +#undef s static void connmark_tg_help(void) { @@ -100,165 +134,75 @@ static void connmark_tg_init(struct xt_entry_target *target) info->nfmask = UINT32_MAX; } -static int -CONNMARK_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void CONNMARK_parse(struct xt_option_call *cb) { - struct xt_connmark_target_info *markinfo - = (struct xt_connmark_target_info *)(*target)->data; + struct xt_connmark_target_info *markinfo = cb->data; - switch (c) { - char *end; - case '1': + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET_MARK: markinfo->mode = XT_CONNMARK_SET; - - markinfo->mark = strtoul(optarg, &end, 0); - if (*end == '/' && end[1] != '\0') - markinfo->mask = strtoul(end+1, &end, 0); - - if (*end != '\0' || end == optarg) - xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "CONNMARK target: Can't specify --set-mark twice"); - *flags = 1; + markinfo->mark = cb->val.mark; + markinfo->mask = cb->val.mask; break; - case '2': + case O_SAVE_MARK: markinfo->mode = XT_CONNMARK_SAVE; - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "CONNMARK target: Can't specify --save-mark twice"); - *flags = 1; break; - case '3': + case O_RESTORE_MARK: markinfo->mode = XT_CONNMARK_RESTORE; - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "CONNMARK target: Can't specify --restore-mark twice"); - *flags = 1; break; - case '4': - if (!*flags) - xtables_error(PARAMETER_PROBLEM, - "CONNMARK target: Can't specify --mask without a operation"); - markinfo->mask = strtoul(optarg, &end, 0); - - if (*end != '\0' || end == optarg) - xtables_error(PARAMETER_PROBLEM, "Bad MASK value \"%s\"", optarg); + case O_MASK: + markinfo->mask = cb->val.u32; break; - default: - return 0; } - - return 1; } -static int connmark_tg_parse(int c, char **argv, int invert, - unsigned int *flags, const void *entry, - struct xt_entry_target **target) +static void connmark_tg_parse(struct xt_option_call *cb) { - struct xt_connmark_tginfo1 *info = (void *)(*target)->data; - unsigned int value, mask = UINT32_MAX; - char *end; + struct xt_connmark_tginfo1 *info = cb->data; - switch (c) { - case '=': /* --set-xmark */ - case '-': /* --set-mark */ - xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); - if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); - if (*end == '/') - if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); - if (*end != '\0') - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--set-xmark/--set-mark", optarg); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET_XMARK: info->mode = XT_CONNMARK_SET; - info->ctmark = value; - info->ctmask = mask; - if (c == '-') - info->ctmask |= value; - *flags |= F_MARK; - return true; - - case '&': /* --and-mark */ - xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); - if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--and-mark", optarg); + info->ctmark = cb->val.mark; + info->ctmask = cb->val.mask; + break; + case O_SET_MARK: + info->mode = XT_CONNMARK_SET; + info->ctmark = cb->val.mark; + info->ctmask = cb->val.mark | cb->val.mask; + break; + case O_AND_MARK: info->mode = XT_CONNMARK_SET; info->ctmark = 0; - info->ctmask = ~mask; - *flags |= F_MARK; - return true; - - case '|': /* --or-mark */ - xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--or-mark", optarg); + info->ctmask = ~cb->val.u32; + break; + case O_OR_MARK: info->mode = XT_CONNMARK_SET; - info->ctmark = value; - info->ctmask = value; - *flags |= F_MARK; - return true; - - case '^': /* --xor-mark */ - xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--xor-mark", optarg); + info->ctmark = cb->val.u32; + info->ctmask = cb->val.u32; + break; + case O_XOR_MARK: info->mode = XT_CONNMARK_SET; - info->ctmark = value; + info->ctmark = cb->val.u32; info->ctmask = 0; - *flags |= F_MARK; - return true; - - case 'S': /* --save-mark */ - xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); + break; + case O_SAVE_MARK: info->mode = XT_CONNMARK_SAVE; - *flags |= F_MARK | F_SR_MARK; - return true; - - case 'R': /* --restore-mark */ - xtables_param_act(XTF_ONE_ACTION, "CONNMARK", *flags & F_MARK); + break; + case O_RESTORE_MARK: info->mode = XT_CONNMARK_RESTORE; - *flags |= F_MARK | F_SR_MARK; - return true; - - case 'n': /* --nfmask */ - if (!(*flags & F_SR_MARK)) - xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " - "or --restore-mark is required for " - "--nfmask"); - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--nfmask", optarg); - info->nfmask = value; - return true; - - case 'c': /* --ctmask */ - if (!(*flags & F_SR_MARK)) - xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " - "or --restore-mark is required for " - "--ctmask"); - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--ctmask", optarg); - info->ctmask = value; - return true; - - case 'm': /* --mask */ - if (!(*flags & F_SR_MARK)) - xtables_error(PARAMETER_PROBLEM, "CONNMARK: --save-mark " - "or --restore-mark is required for " - "--mask"); - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "CONNMARK", "--mask", optarg); - info->nfmask = info->ctmask = value; - return true; + break; + case O_MASK: + info->nfmask = info->ctmask = cb->val.u32; + break; } - - return false; } -static void connmark_tg_check(unsigned int flags) +static void connmark_tg_check(struct xt_fcheck_call *cb) { - if (!flags) + if (!(cb->xflags & F_OP_ANY)) xtables_error(PARAMETER_PROBLEM, "CONNMARK target: No operation specified"); } @@ -283,22 +227,20 @@ static void CONNMARK_print(const void *ip, (const struct xt_connmark_target_info *)target->data; switch (markinfo->mode) { case XT_CONNMARK_SET: - printf("CONNMARK set "); + printf(" CONNMARK set "); print_mark(markinfo->mark); print_mask("/", markinfo->mask); - printf(" "); break; case XT_CONNMARK_SAVE: - printf("CONNMARK save "); + printf(" CONNMARK save "); print_mask("mask ", markinfo->mask); - printf(" "); break; case XT_CONNMARK_RESTORE: - printf("CONNMARK restore "); + printf(" CONNMARK restore "); print_mask("mask ", markinfo->mask); break; default: - printf("ERROR: UNKNOWN CONNMARK MODE "); + printf(" ERROR: UNKNOWN CONNMARK MODE"); break; } } @@ -312,39 +254,39 @@ connmark_tg_print(const void *ip, const struct xt_entry_target *target, switch (info->mode) { case XT_CONNMARK_SET: if (info->ctmark == 0) - printf("CONNMARK and 0x%x ", - (unsigned int)(u_int32_t)~info->ctmask); + printf(" CONNMARK and 0x%x", + (unsigned int)(uint32_t)~info->ctmask); else if (info->ctmark == info->ctmask) - printf("CONNMARK or 0x%x ", info->ctmark); + printf(" CONNMARK or 0x%x", info->ctmark); else if (info->ctmask == 0) - printf("CONNMARK xor 0x%x ", info->ctmark); + printf(" CONNMARK xor 0x%x", info->ctmark); else if (info->ctmask == 0xFFFFFFFFU) - printf("CONNMARK set 0x%x ", info->ctmark); + printf(" CONNMARK set 0x%x", info->ctmark); else - printf("CONNMARK xset 0x%x/0x%x ", + printf(" CONNMARK xset 0x%x/0x%x", info->ctmark, info->ctmask); break; case XT_CONNMARK_SAVE: if (info->nfmask == UINT32_MAX && info->ctmask == UINT32_MAX) - printf("CONNMARK save "); + printf(" CONNMARK save"); else if (info->nfmask == info->ctmask) - printf("CONNMARK save mask 0x%x ", info->nfmask); + printf(" CONNMARK save mask 0x%x", info->nfmask); else - printf("CONNMARK save nfmask 0x%x ctmask ~0x%x ", + printf(" CONNMARK save nfmask 0x%x ctmask ~0x%x", info->nfmask, info->ctmask); break; case XT_CONNMARK_RESTORE: if (info->ctmask == UINT32_MAX && info->nfmask == UINT32_MAX) - printf("CONNMARK restore "); + printf(" CONNMARK restore"); else if (info->ctmask == info->nfmask) - printf("CONNMARK restore mask 0x%x ", info->ctmask); + printf(" CONNMARK restore mask 0x%x", info->ctmask); else - printf("CONNMARK restore ctmask 0x%x nfmask ~0x%x ", + printf(" CONNMARK restore ctmask 0x%x nfmask ~0x%x", info->ctmask, info->nfmask); break; default: - printf("ERROR: UNKNOWN CONNMARK MODE"); + printf(" ERROR: UNKNOWN CONNMARK MODE"); break; } } @@ -356,21 +298,20 @@ static void CONNMARK_save(const void *ip, const struct xt_entry_target *target) switch (markinfo->mode) { case XT_CONNMARK_SET: - printf("--set-mark "); + printf(" --set-mark "); print_mark(markinfo->mark); print_mask("/", markinfo->mask); - printf(" "); break; case XT_CONNMARK_SAVE: - printf("--save-mark "); + printf(" --save-mark "); print_mask("--mask ", markinfo->mask); break; case XT_CONNMARK_RESTORE: - printf("--restore-mark "); + printf(" --restore-mark "); print_mask("--mask ", markinfo->mask); break; default: - printf("ERROR: UNKNOWN CONNMARK MODE "); + printf(" ERROR: UNKNOWN CONNMARK MODE"); break; } } @@ -390,18 +331,18 @@ connmark_tg_save(const void *ip, const struct xt_entry_target *target) switch (info->mode) { case XT_CONNMARK_SET: - printf("--set-xmark 0x%x/0x%x ", info->ctmark, info->ctmask); + printf(" --set-xmark 0x%x/0x%x", info->ctmark, info->ctmask); break; case XT_CONNMARK_SAVE: - printf("--save-mark --nfmask 0x%x --ctmask 0x%x ", + printf(" --save-mark --nfmask 0x%x --ctmask 0x%x", info->nfmask, info->ctmask); break; case XT_CONNMARK_RESTORE: - printf("--restore-mark --nfmask 0x%x --ctmask 0x%x ", + printf(" --restore-mark --nfmask 0x%x --ctmask 0x%x", info->nfmask, info->ctmask); break; default: - printf("ERROR: UNKNOWN CONNMARK MODE"); + printf(" ERROR: UNKNOWN CONNMARK MODE"); break; } } @@ -416,11 +357,11 @@ static struct xtables_target connmark_tg_reg[] = { .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_target_info)), .help = CONNMARK_help, .init = CONNMARK_init, - .parse = CONNMARK_parse, - .final_check = connmark_tg_check, .print = CONNMARK_print, .save = CONNMARK_save, - .extra_opts = CONNMARK_opts, + .x6_parse = CONNMARK_parse, + .x6_fcheck = connmark_tg_check, + .x6_options = CONNMARK_opts, }, { .version = XTABLES_VERSION, @@ -431,11 +372,11 @@ static struct xtables_target connmark_tg_reg[] = { .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_tginfo1)), .help = connmark_tg_help, .init = connmark_tg_init, - .parse = connmark_tg_parse, - .final_check = connmark_tg_check, .print = connmark_tg_print, .save = connmark_tg_save, - .extra_opts = connmark_tg_opts, + .x6_parse = connmark_tg_parse, + .x6_fcheck = connmark_tg_check, + .x6_options = connmark_tg_opts, }, }; diff --git a/extensions/libxt_CONNMARK.man b/extensions/libxt_CONNMARK.man index 13c6b4b..9317923 100644 --- a/extensions/libxt_CONNMARK.man +++ b/extensions/libxt_CONNMARK.man @@ -2,7 +2,7 @@ This module sets the netfilter mark value associated with a connection. The mark is 32 bits wide. .TP \fB\-\-set\-xmark\fP \fIvalue\fP[\fB/\fP\fImask\fP] -Zero out the bits given by \fImask\fR and XOR \fIvalue\fR into the ctmark. +Zero out the bits given by \fImask\fP and XOR \fIvalue\fP into the ctmark. .TP \fB\-\-save\-mark\fP [\fB\-\-nfmask\fP \fInfmask\fP] [\fB\-\-ctmask\fP \fIctmask\fP] Copy the packet mark (nfmark) to the connection mark (ctmark) using the given @@ -10,18 +10,18 @@ masks. The new nfmark value is determined as follows: .IP ctmark = (ctmark & ~ctmask) ^ (nfmark & nfmask) .IP -i.e. \fIctmask\fR defines what bits to clear and \fInfmask\fR what bits of the -nfmark to XOR into the ctmark. \fIctmask\fR and \fInfmask\fR default to +i.e. \fIctmask\fP defines what bits to clear and \fInfmask\fP what bits of the +nfmark to XOR into the ctmark. \fIctmask\fP and \fInfmask\fP default to 0xFFFFFFFF. .TP \fB\-\-restore\-mark\fP [\fB\-\-nfmask\fP \fInfmask\fP] [\fB\-\-ctmask\fP \fIctmask\fP] Copy the connection mark (ctmark) to the packet mark (nfmark) using the given masks. The new ctmark value is determined as follows: .IP -nfmark = (nfmark & ~\fInfmask\fR) ^ (ctmark & \fIctmask\fR); +nfmark = (nfmark & ~\fInfmask\fP) ^ (ctmark & \fIctmask\fP); .IP -i.e. \fInfmask\fR defines what bits to clear and \fIctmask\fR what bits of the -ctmark to XOR into the nfmark. \fIctmask\fR and \fInfmask\fR default to +i.e. \fInfmask\fP defines what bits to clear and \fIctmask\fP what bits of the +ctmark to XOR into the nfmark. \fIctmask\fP and \fInfmask\fP default to 0xFFFFFFFF. .IP \fB\-\-restore\-mark\fP is only valid in the \fBmangle\fP table. @@ -29,16 +29,16 @@ ctmark to XOR into the nfmark. \fIctmask\fR and \fInfmask\fR default to The following mnemonics are available for \fB\-\-set\-xmark\fP: .TP \fB\-\-and\-mark\fP \fIbits\fP -Binary AND the ctmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark -0/\fR\fIinvbits\fR, where \fIinvbits\fR is the binary negation of \fIbits\fR.) +Binary AND the ctmark with \fIbits\fP. (Mnemonic for \fB\-\-set\-xmark +0/\fP\fIinvbits\fP, where \fIinvbits\fP is the binary negation of \fIbits\fP.) .TP \fB\-\-or\-mark\fP \fIbits\fP -Binary OR the ctmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP -\fIbits\fR\fB/\fR\fIbits\fR.) +Binary OR the ctmark with \fIbits\fP. (Mnemonic for \fB\-\-set\-xmark\fP +\fIbits\fP\fB/\fP\fIbits\fP.) .TP \fB\-\-xor\-mark\fP \fIbits\fP -Binary XOR the ctmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP -\fIbits\fR\fB/0\fR.) +Binary XOR the ctmark with \fIbits\fP. (Mnemonic for \fB\-\-set\-xmark\fP +\fIbits\fP\fB/0\fP.) .TP \fB\-\-set\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP] Set the connection mark. If a mask is specified then only those bits set in the @@ -50,4 +50,4 @@ copied. .TP \fB\-\-restore\-mark\fP [\fB\-\-mask\fP \fImask\fP] Copy the ctmark to the nfmark. If a mask is specified, only those bits are -copied. This is only valid in the \fBmangle\fR table. +copied. This is only valid in the \fBmangle\fP table. diff --git a/extensions/libxt_CONNSECMARK.c b/extensions/libxt_CONNSECMARK.c index d95339f..0b3cd79 100644 --- a/extensions/libxt_CONNSECMARK.c +++ b/extensions/libxt_CONNSECMARK.c @@ -6,14 +6,18 @@ * Copyright (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com> */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter/xt_CONNSECMARK.h> #define PFX "CONNSECMARK target: " +enum { + O_SAVE = 0, + O_RESTORE, + F_SAVE = 1 << O_SAVE, + F_RESTORE = 1 << O_RESTORE, +}; + static void CONNSECMARK_help(void) { printf( @@ -22,62 +26,43 @@ static void CONNSECMARK_help(void) " --restore Copy security mark from connection to packet\n"); } -static const struct option CONNSECMARK_opts[] = { - { "save", 0, NULL, '1' }, - { "restore", 0, NULL, '2' }, - { .name = NULL } +static const struct xt_option_entry CONNSECMARK_opts[] = { + {.name = "save", .id = O_SAVE, .excl = F_RESTORE, .type = XTTYPE_NONE}, + {.name = "restore", .id = O_RESTORE, .excl = F_SAVE, + .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; -static int -CONNSECMARK_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void CONNSECMARK_parse(struct xt_option_call *cb) { - struct xt_connsecmark_target_info *info = - (struct xt_connsecmark_target_info*)(*target)->data; + struct xt_connsecmark_target_info *info = cb->data; - switch (c) { - case '1': - if (*flags & CONNSECMARK_SAVE) - xtables_error(PARAMETER_PROBLEM, PFX - "Can't specify --save twice"); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SAVE: info->mode = CONNSECMARK_SAVE; - *flags |= CONNSECMARK_SAVE; break; - - case '2': - if (*flags & CONNSECMARK_RESTORE) - xtables_error(PARAMETER_PROBLEM, PFX - "Can't specify --restore twice"); + case O_RESTORE: info->mode = CONNSECMARK_RESTORE; - *flags |= CONNSECMARK_RESTORE; break; - - default: - return 0; } - - return 1; } -static void CONNSECMARK_check(unsigned int flags) +static void CONNSECMARK_check(struct xt_fcheck_call *cb) { - if (!flags) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, PFX "parameter required"); - - if (flags == (CONNSECMARK_SAVE|CONNSECMARK_RESTORE)) - xtables_error(PARAMETER_PROBLEM, PFX "only one flag of --save " - "or --restore is allowed"); } static void print_connsecmark(const struct xt_connsecmark_target_info *info) { switch (info->mode) { case CONNSECMARK_SAVE: - printf("save "); + printf("save"); break; case CONNSECMARK_RESTORE: - printf("restore "); + printf("restore"); break; default: @@ -92,7 +77,7 @@ CONNSECMARK_print(const void *ip, const struct xt_entry_target *target, const struct xt_connsecmark_target_info *info = (struct xt_connsecmark_target_info*)(target)->data; - printf("CONNSECMARK "); + printf(" CONNSECMARK "); print_connsecmark(info); } @@ -102,7 +87,7 @@ CONNSECMARK_save(const void *ip, const struct xt_entry_target *target) const struct xt_connsecmark_target_info *info = (struct xt_connsecmark_target_info*)target->data; - printf("--"); + printf(" --"); print_connsecmark(info); } @@ -113,12 +98,12 @@ static struct xtables_target connsecmark_target = { .revision = 0, .size = XT_ALIGN(sizeof(struct xt_connsecmark_target_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_connsecmark_target_info)), - .parse = CONNSECMARK_parse, .help = CONNSECMARK_help, - .final_check = CONNSECMARK_check, .print = CONNSECMARK_print, .save = CONNSECMARK_save, - .extra_opts = CONNSECMARK_opts, + .x6_parse = CONNSECMARK_parse, + .x6_fcheck = CONNSECMARK_check, + .x6_options = CONNSECMARK_opts, }; void _init(void) diff --git a/extensions/libxt_CONNSECMARK.man b/extensions/libxt_CONNSECMARK.man index a72e710..2616ab9 100644 --- a/extensions/libxt_CONNSECMARK.man +++ b/extensions/libxt_CONNSECMARK.man @@ -1,9 +1,12 @@ This module copies security markings from packets to connections (if unlabeled), and from connections back to packets (also only if unlabeled). Typically used in conjunction with SECMARK, it is -only valid in the +valid in the +.B security +table (for backwards compatibility with older kernels, it is also +valid in the .B mangle -table. +table). .TP \fB\-\-save\fP If the packet has a security marking, copy it to the connection diff --git a/extensions/libxt_CT.c b/extensions/libxt_CT.c index 6be6ea0..6b28fe1 100644 --- a/extensions/libxt_CT.c +++ b/extensions/libxt_CT.c @@ -1,8 +1,9 @@ +/* + * Copyright (c) 2010-2013 Patrick McHardy <kaber@trash.net> + */ + #include <stdio.h> #include <string.h> -#include <stdlib.h> -#include <stddef.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter/nf_conntrack_common.h> #include <linux/netfilter/xt_CT.h> @@ -19,22 +20,55 @@ static void ct_help(void) ); } -enum ct_options { - CT_OPT_NOTRACK = 0x1, - CT_OPT_HELPER = 0x2, - CT_OPT_CTEVENTS = 0x4, - CT_OPT_EXPEVENTS = 0x8, - CT_OPT_ZONE = 0x10, +static void ct_help_v1(void) +{ + printf( +"CT target options:\n" +" --notrack Don't track connection\n" +" --helper name Use conntrack helper 'name' for connection\n" +" --timeout name Use timeout policy 'name' for connection\n" +" --ctevents event[,event...] Generate specified conntrack events for connection\n" +" --expevents event[,event...] Generate specified expectation events for connection\n" +" --zone ID Assign/Lookup connection in zone ID\n" + ); +} + +enum { + O_NOTRACK = 0, + O_HELPER, + O_TIMEOUT, + O_CTEVENTS, + O_EXPEVENTS, + O_ZONE, +}; + +#define s struct xt_ct_target_info +static const struct xt_option_entry ct_opts[] = { + {.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE}, + {.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)}, + {.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING}, + {.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING}, + {.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)}, + XTOPT_TABLEEND, }; +#undef s -static const struct option ct_opts[] = { - { "notrack", 0, NULL, CT_OPT_NOTRACK }, - { "helper", 1, NULL, CT_OPT_HELPER }, - { "ctevents", 1, NULL, CT_OPT_CTEVENTS }, - { "expevents", 1, NULL, CT_OPT_EXPEVENTS }, - { "zone", 1, NULL, CT_OPT_ZONE }, - { .name = NULL }, +#define s struct xt_ct_target_info_v1 +static const struct xt_option_entry ct_opts_v1[] = { + {.name = "notrack", .id = O_NOTRACK, .type = XTTYPE_NONE}, + {.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, helper)}, + {.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, timeout)}, + {.name = "ctevents", .id = O_CTEVENTS, .type = XTTYPE_STRING}, + {.name = "expevents", .id = O_EXPEVENTS, .type = XTTYPE_STRING}, + {.name = "zone", .id = O_ZONE, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, zone)}, + XTOPT_TABLEEND, }; +#undef s struct event_tbl { const char *name; @@ -86,52 +120,53 @@ static void ct_print_events(const char *pfx, const struct event_tbl *tbl, const char *sep = ""; unsigned int i; - printf("%s ", pfx); + printf(" %s ", pfx); for (i = 0; i < size; i++) { if (mask & (1 << tbl[i].event)) { printf("%s%s", sep, tbl[i].name); sep = ","; } } - printf(" "); } -static int ct_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void ct_parse(struct xt_option_call *cb) { - struct xt_ct_target_info *info = (struct xt_ct_target_info *)(*target)->data; - unsigned int zone; + struct xt_ct_target_info *info = cb->data; - switch (c) { - case CT_OPT_NOTRACK: - xtables_param_act(XTF_ONLY_ONCE, "CT", "--notrack", *flags & CT_OPT_NOTRACK); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_NOTRACK: info->flags |= XT_CT_NOTRACK; break; - case CT_OPT_HELPER: - xtables_param_act(XTF_ONLY_ONCE, "CT", "--helper", *flags & CT_OPT_HELPER); - strncpy(info->helper, optarg, sizeof(info->helper)); - info->helper[sizeof(info->helper) - 1] = '\0'; + case O_CTEVENTS: + info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), cb->arg); break; - case CT_OPT_CTEVENTS: - xtables_param_act(XTF_ONLY_ONCE, "CT", "--ctevents", *flags & CT_OPT_CTEVENTS); - info->ct_events = ct_parse_events(ct_event_tbl, ARRAY_SIZE(ct_event_tbl), optarg); + case O_EXPEVENTS: + info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), cb->arg); break; - case CT_OPT_EXPEVENTS: - xtables_param_act(XTF_ONLY_ONCE, "CT", "--expevents", *flags & CT_OPT_EXPEVENTS); - info->exp_events = ct_parse_events(exp_event_tbl, ARRAY_SIZE(exp_event_tbl), optarg); + } +} + +static void ct_parse_v1(struct xt_option_call *cb) +{ + struct xt_ct_target_info_v1 *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_NOTRACK: + info->flags |= XT_CT_NOTRACK; + break; + case O_CTEVENTS: + info->ct_events = ct_parse_events(ct_event_tbl, + ARRAY_SIZE(ct_event_tbl), + cb->arg); break; - case CT_OPT_ZONE: - xtables_param_act(XTF_ONLY_ONCE, "CT", "--zone", *flags & CT_OPT_ZONE); - if (!xtables_strtoui(optarg, NULL, &zone, 0, UINT16_MAX)) - xtables_error(PARAMETER_PROBLEM, "Bad zone value \"%s\"", optarg); - info->zone = zone; + case O_EXPEVENTS: + info->exp_events = ct_parse_events(exp_event_tbl, + ARRAY_SIZE(exp_event_tbl), + cb->arg); break; - default: - return 0; } - - *flags |= c; - return 1; } static void ct_print(const void *ip, const struct xt_entry_target *target, int numeric) @@ -139,11 +174,38 @@ static void ct_print(const void *ip, const struct xt_entry_target *target, int n const struct xt_ct_target_info *info = (const struct xt_ct_target_info *)target->data; - printf("CT "); + printf(" CT"); + if (info->flags & XT_CT_NOTRACK) + printf(" notrack"); + if (info->helper[0]) + printf(" helper %s", info->helper); + if (info->ct_events) + ct_print_events("ctevents", ct_event_tbl, + ARRAY_SIZE(ct_event_tbl), info->ct_events); + if (info->exp_events) + ct_print_events("expevents", exp_event_tbl, + ARRAY_SIZE(exp_event_tbl), info->exp_events); + if (info->zone) + printf("zone %u ", info->zone); +} + +static void +ct_print_v1(const void *ip, const struct xt_entry_target *target, int numeric) +{ + const struct xt_ct_target_info_v1 *info = + (const struct xt_ct_target_info_v1 *)target->data; + + if (info->flags & XT_CT_NOTRACK_ALIAS) { + printf (" NOTRACK"); + return; + } + printf(" CT"); if (info->flags & XT_CT_NOTRACK) - printf("notrack "); + printf(" notrack"); if (info->helper[0]) - printf("helper %s ", info->helper); + printf(" helper %s", info->helper); + if (info->timeout[0]) + printf(" timeout %s", info->timeout); if (info->ct_events) ct_print_events("ctevents", ct_event_tbl, ARRAY_SIZE(ct_event_tbl), info->ct_events); @@ -159,10 +221,35 @@ static void ct_save(const void *ip, const struct xt_entry_target *target) const struct xt_ct_target_info *info = (const struct xt_ct_target_info *)target->data; + if (info->flags & XT_CT_NOTRACK_ALIAS) + return; + if (info->flags & XT_CT_NOTRACK) + printf(" --notrack"); + if (info->helper[0]) + printf(" --helper %s", info->helper); + if (info->ct_events) + ct_print_events("--ctevents", ct_event_tbl, + ARRAY_SIZE(ct_event_tbl), info->ct_events); + if (info->exp_events) + ct_print_events("--expevents", exp_event_tbl, + ARRAY_SIZE(exp_event_tbl), info->exp_events); + if (info->zone) + printf(" --zone %u", info->zone); +} + +static void ct_save_v1(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_ct_target_info_v1 *info = + (const struct xt_ct_target_info_v1 *)target->data; + + if (info->flags & XT_CT_NOTRACK_ALIAS) + return; if (info->flags & XT_CT_NOTRACK) - printf("--notrack "); + printf(" --notrack"); if (info->helper[0]) - printf("--helper %s ", info->helper); + printf(" --helper %s", info->helper); + if (info->timeout[0]) + printf(" --timeout %s", info->timeout); if (info->ct_events) ct_print_events("--ctevents", ct_event_tbl, ARRAY_SIZE(ct_event_tbl), info->ct_events); @@ -170,23 +257,118 @@ static void ct_save(const void *ip, const struct xt_entry_target *target) ct_print_events("--expevents", exp_event_tbl, ARRAY_SIZE(exp_event_tbl), info->exp_events); if (info->zone) - printf("--zone %u ", info->zone); + printf(" --zone %u", info->zone); +} + +static const char * +ct_print_name_alias(const struct xt_entry_target *target) +{ + struct xt_ct_target_info *info = (void *)target->data; + + return info->flags & XT_CT_NOTRACK_ALIAS ? "NOTRACK" : "CT"; +} + +static void notrack_ct0_tg_init(struct xt_entry_target *target) +{ + struct xt_ct_target_info *info = (void *)target->data; + + info->flags = XT_CT_NOTRACK; +} + +static void notrack_ct1_tg_init(struct xt_entry_target *target) +{ + struct xt_ct_target_info_v1 *info = (void *)target->data; + + info->flags = XT_CT_NOTRACK; +} + +static void notrack_ct2_tg_init(struct xt_entry_target *target) +{ + struct xt_ct_target_info_v1 *info = (void *)target->data; + + info->flags = XT_CT_NOTRACK | XT_CT_NOTRACK_ALIAS; } -static struct xtables_target ct_target = { - .family = NFPROTO_UNSPEC, - .name = "CT", - .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct xt_ct_target_info)), - .userspacesize = offsetof(struct xt_ct_target_info, ct), - .help = ct_help, - .parse = ct_parse, - .print = ct_print, - .save = ct_save, - .extra_opts = ct_opts, +static struct xtables_target ct_target_reg[] = { + { + .family = NFPROTO_UNSPEC, + .name = "CT", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_ct_target_info)), + .userspacesize = offsetof(struct xt_ct_target_info, ct), + .help = ct_help, + .print = ct_print, + .save = ct_save, + .x6_parse = ct_parse, + .x6_options = ct_opts, + }, + { + .family = NFPROTO_UNSPEC, + .name = "CT", + .revision = 1, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)), + .userspacesize = offsetof(struct xt_ct_target_info_v1, ct), + .help = ct_help_v1, + .print = ct_print_v1, + .save = ct_save_v1, + .x6_parse = ct_parse_v1, + .x6_options = ct_opts_v1, + }, + { + .family = NFPROTO_UNSPEC, + .name = "CT", + .revision = 2, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)), + .userspacesize = offsetof(struct xt_ct_target_info_v1, ct), + .help = ct_help_v1, + .print = ct_print_v1, + .save = ct_save_v1, + .alias = ct_print_name_alias, + .x6_parse = ct_parse_v1, + .x6_options = ct_opts_v1, + }, + { + .family = NFPROTO_UNSPEC, + .name = "NOTRACK", + .real_name = "CT", + .revision = 0, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_ct_target_info)), + .userspacesize = offsetof(struct xt_ct_target_info, ct), + .init = notrack_ct0_tg_init, + }, + { + .family = NFPROTO_UNSPEC, + .name = "NOTRACK", + .real_name = "CT", + .revision = 1, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)), + .userspacesize = offsetof(struct xt_ct_target_info_v1, ct), + .init = notrack_ct1_tg_init, + }, + { + .family = NFPROTO_UNSPEC, + .name = "NOTRACK", + .real_name = "CT", + .revision = 2, + .ext_flags = XTABLES_EXT_ALIAS, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_ct_target_info_v1)), + .userspacesize = offsetof(struct xt_ct_target_info_v1, ct), + .init = notrack_ct2_tg_init, + }, + { + .family = NFPROTO_UNSPEC, + .name = "NOTRACK", + .revision = 0, + .version = XTABLES_VERSION, + }, }; void _init(void) { - xtables_register_target(&ct_target); + xtables_register_targets(ct_target_reg, ARRAY_SIZE(ct_target_reg)); } diff --git a/extensions/libxt_CT.man b/extensions/libxt_CT.man index ff258b7..a93eb14 100644 --- a/extensions/libxt_CT.man +++ b/extensions/libxt_CT.man @@ -23,3 +23,8 @@ Possible event types are: \fBnew\fP. \fB\-\-zone\fP \fIid\fP Assign this packet to zone \fIid\fP and only have lookups done in that zone. By default, packets have zone 0. +.TP +\fB\-\-timeout\fP \fIname\fP +Use the timeout policy identified by \fIname\fP for the connection. This is +provides more flexible timeout policy definition than global timeout values +available at /proc/sys/net/netfilter/nf_conntrack_*_timeout_*. diff --git a/extensions/libipt_DNAT.man b/extensions/libxt_DNAT.man index d1e0a3a..225274f 100644 --- a/extensions/libipt_DNAT.man +++ b/extensions/libxt_DNAT.man @@ -7,20 +7,17 @@ and chains, and user-defined chains which are only called from those chains. It specifies that the destination address of the packet should be modified (and all future packets in this connection will -also be mangled), and rules should cease being examined. It takes one -type of option: +also be mangled), and rules should cease being examined. It takes the +following options: .TP -\fB\-\-to\-destination\fP [\fIipaddr\fP][\fB\-\fP\fIipaddr\fP][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]] +\fB\-\-to\-destination\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]] which can specify a single new destination IP address, an inclusive -range of IP addresses, and optionally, a port range (which is only -valid if the rule also specifies -\fB\-p tcp\fP -or -\fB\-p udp\fP). +range of IP addresses. Optionally a port range, +if the rule also specifies one of the following protocols: +\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. If no port range is specified, then the destination port will never be modified. If no IP address is specified then only the destination port will be modified. - In Kernels up to 2.6.10 you can add several \-\-to\-destination options. For those kernels, if you specify more than one destination address, either via an address range or multiple \-\-to\-destination options, a simple round-robin (one @@ -37,3 +34,5 @@ is used then port mapping will be randomized (kernel >= 2.6.22). Gives a client the same source-/destination-address for each connection. This supersedes the SAME target. Support for persistent mappings is available from 2.6.29-rc2. +.TP +IPv6 support available since Linux kernels >= 3.7. diff --git a/extensions/libxt_DSCP.c b/extensions/libxt_DSCP.c index 82ac10c..e16e93c 100644 --- a/extensions/libxt_DSCP.c +++ b/extensions/libxt_DSCP.c @@ -11,16 +11,19 @@ */ #include <stdio.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_DSCP.h> /* This is evil, but it's my code - HW*/ #include "dscp_helper.c" +enum { + O_SET_DSCP = 0, + O_SET_DSCP_CLASS, + F_SET_DSCP = 1 << O_SET_DSCP, + F_SET_DSCP_CLASS = 1 << O_SET_DSCP_CLASS, +}; + static void DSCP_help(void) { printf( @@ -37,79 +40,39 @@ static void DSCP_help(void) ); } -static const struct option DSCP_opts[] = { - { "set-dscp", 1, NULL, 'F' }, - { "set-dscp-class", 1, NULL, 'G' }, - { .name = NULL } +static const struct xt_option_entry DSCP_opts[] = { + {.name = "set-dscp", .id = O_SET_DSCP, .excl = F_SET_DSCP_CLASS, + .type = XTTYPE_UINT8, .min = 0, .max = XT_DSCP_MAX, + .flags = XTOPT_PUT, + XTOPT_POINTER(struct xt_DSCP_info, dscp)}, + {.name = "set-dscp-class", .id = O_SET_DSCP_CLASS, .excl = F_SET_DSCP, + .type = XTTYPE_STRING}, + XTOPT_TABLEEND, }; -static void -parse_dscp(const char *s, struct xt_DSCP_info *dinfo) +static void DSCP_parse(struct xt_option_call *cb) { - unsigned int dscp; - - if (!xtables_strtoui(s, NULL, &dscp, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid dscp `%s'\n", s); + struct xt_DSCP_info *dinfo = cb->data; - if (dscp > XT_DSCP_MAX) - xtables_error(PARAMETER_PROBLEM, - "DSCP `%d` out of range\n", dscp); - - dinfo->dscp = dscp; -} - - -static void -parse_class(const char *s, struct xt_DSCP_info *dinfo) -{ - unsigned int dscp = class_to_dscp(s); - - /* Assign the value */ - dinfo->dscp = dscp; -} - - -static int DSCP_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) -{ - struct xt_DSCP_info *dinfo - = (struct xt_DSCP_info *)(*target)->data; - - switch (c) { - case 'F': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "DSCP target: Only use --set-dscp ONCE!"); - parse_dscp(optarg, dinfo); - *flags = 1; - break; - case 'G': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "DSCP target: Only use --set-dscp-class ONCE!"); - parse_class(optarg, dinfo); - *flags = 1; + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET_DSCP_CLASS: + dinfo->dscp = class_to_dscp(cb->arg); break; - - default: - return 0; } - - return 1; } -static void DSCP_check(unsigned int flags) +static void DSCP_check(struct xt_fcheck_call *cb) { - if (!flags) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "DSCP target: Parameter --set-dscp is required"); } static void -print_dscp(u_int8_t dscp, int numeric) +print_dscp(uint8_t dscp, int numeric) { - printf("0x%02x ", dscp); + printf(" 0x%02x", dscp); } static void DSCP_print(const void *ip, const struct xt_entry_target *target, @@ -117,7 +80,7 @@ static void DSCP_print(const void *ip, const struct xt_entry_target *target, { const struct xt_DSCP_info *dinfo = (const struct xt_DSCP_info *)target->data; - printf("DSCP set "); + printf(" DSCP set"); print_dscp(dinfo->dscp, numeric); } @@ -126,7 +89,7 @@ static void DSCP_save(const void *ip, const struct xt_entry_target *target) const struct xt_DSCP_info *dinfo = (const struct xt_DSCP_info *)target->data; - printf("--set-dscp 0x%02x ", dinfo->dscp); + printf(" --set-dscp 0x%02x", dinfo->dscp); } static struct xtables_target dscp_target = { @@ -136,11 +99,11 @@ static struct xtables_target dscp_target = { .size = XT_ALIGN(sizeof(struct xt_DSCP_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_DSCP_info)), .help = DSCP_help, - .parse = DSCP_parse, - .final_check = DSCP_check, .print = DSCP_print, .save = DSCP_save, - .extra_opts = DSCP_opts, + .x6_parse = DSCP_parse, + .x6_fcheck = DSCP_check, + .x6_options = DSCP_opts, }; void _init(void) diff --git a/extensions/libxt_HMARK.c b/extensions/libxt_HMARK.c new file mode 100644 index 0000000..94aebe9 --- /dev/null +++ b/extensions/libxt_HMARK.c @@ -0,0 +1,450 @@ +/* + * (C) 2012 by Hans Schillstrom <hans.schillstrom@ericsson.com> + * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org> + * + * 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. + * + * Description: shared library add-on to iptables to add HMARK target support + * + * Initial development by Hans Schillstrom. Pablo's improvements to this piece + * of software has been sponsored by Sophos Astaro <http://www.sophos.com>. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <string.h> + +#include "xtables.h" +#include <linux/netfilter/xt_HMARK.h> + +static void HMARK_help(void) +{ + printf( +"HMARK target options, i.e. modify hash calculation by:\n" +" --hmark-tuple [src|dst|sport|dport|spi|proto|ct][,...]\n" +" --hmark-mod value nfmark modulus value\n" +" --hmark-offset value Last action add value to nfmark\n\n" +" --hmark-rnd Random see for hashing\n" +" Alternatively, fine tuning of what will be included in hash calculation\n" +" --hmark-src-prefix length Source address mask CIDR prefix\n" +" --hmark-dst-prefix length Dest address mask CIDR prefix\n" +" --hmark-sport-mask value Mask src port with value\n" +" --hmark-dport-mask value Mask dst port with value\n" +" --hmark-spi-mask value For esp and ah AND spi with value\n" +" --hmark-sport value OR src port with value\n" +" --hmark-dport value OR dst port with value\n" +" --hmark-spi value For esp and ah OR spi with value\n" +" --hmark-proto-mask value Mask Protocol with value\n"); +} + +#define hi struct xt_hmark_info + +enum { + O_HMARK_SADDR_MASK, + O_HMARK_DADDR_MASK, + O_HMARK_SPI, + O_HMARK_SPI_MASK, + O_HMARK_SPORT, + O_HMARK_DPORT, + O_HMARK_SPORT_MASK, + O_HMARK_DPORT_MASK, + O_HMARK_PROTO_MASK, + O_HMARK_RND, + O_HMARK_MODULUS, + O_HMARK_OFFSET, + O_HMARK_CT, + O_HMARK_TYPE, +}; + +#define HMARK_OPT_PKT_MASK \ + ((1 << O_HMARK_SADDR_MASK) | \ + (1 << O_HMARK_DADDR_MASK) | \ + (1 << O_HMARK_SPI_MASK) | \ + (1 << O_HMARK_SPORT_MASK) | \ + (1 << O_HMARK_DPORT_MASK) | \ + (1 << O_HMARK_PROTO_MASK) | \ + (1 << O_HMARK_SPI_MASK) | \ + (1 << O_HMARK_SPORT) | \ + (1 << O_HMARK_DPORT) | \ + (1 << O_HMARK_SPI)) + +static const struct xt_option_entry HMARK_opts[] = { + { .name = "hmark-tuple", + .type = XTTYPE_STRING, + .id = O_HMARK_TYPE, + }, + { .name = "hmark-src-prefix", + .type = XTTYPE_PLENMASK, + .id = O_HMARK_SADDR_MASK, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, src_mask) + }, + { .name = "hmark-dst-prefix", + .type = XTTYPE_PLENMASK, + .id = O_HMARK_DADDR_MASK, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, dst_mask) + }, + { .name = "hmark-sport-mask", + .type = XTTYPE_UINT16, + .id = O_HMARK_SPORT_MASK, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.p16.src) + }, + { .name = "hmark-dport-mask", + .type = XTTYPE_UINT16, + .id = O_HMARK_DPORT_MASK, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.p16.dst) + }, + { .name = "hmark-spi-mask", + .type = XTTYPE_UINT32, + .id = O_HMARK_SPI_MASK, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.v32) + }, + { .name = "hmark-sport", + .type = XTTYPE_UINT16, + .id = O_HMARK_SPORT, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.p16.src) + }, + { .name = "hmark-dport", + .type = XTTYPE_UINT16, + .id = O_HMARK_DPORT, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.p16.dst) + }, + { .name = "hmark-spi", + .type = XTTYPE_UINT32, + .id = O_HMARK_SPI, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.v32) + }, + { .name = "hmark-proto-mask", + .type = XTTYPE_UINT16, + .id = O_HMARK_PROTO_MASK, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, proto_mask) + }, + { .name = "hmark-rnd", + .type = XTTYPE_UINT32, + .id = O_HMARK_RND, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, hashrnd) + }, + { .name = "hmark-mod", + .type = XTTYPE_UINT32, + .id = O_HMARK_MODULUS, + .min = 1, + .flags = XTOPT_PUT | XTOPT_MAND, XTOPT_POINTER(hi, hmodulus) + }, + { .name = "hmark-offset", + .type = XTTYPE_UINT32, + .id = O_HMARK_OFFSET, + .flags = XTOPT_PUT, XTOPT_POINTER(hi, hoffset) + }, + XTOPT_TABLEEND, +}; + +static int +hmark_parse(const char *type, size_t len, struct xt_hmark_info *info, + unsigned int *xflags) +{ + if (strncasecmp(type, "ct", len) == 0) { + info->flags |= XT_HMARK_FLAG(XT_HMARK_CT); + *xflags |= (1 << O_HMARK_CT); + } else if (strncasecmp(type, "src", len) == 0) { + memset(&info->src_mask, 0xff, sizeof(info->src_mask)); + info->flags |= XT_HMARK_FLAG(XT_HMARK_SADDR_MASK); + *xflags |= (1 << O_HMARK_SADDR_MASK); + } else if (strncasecmp(type, "dst", len) == 0) { + memset(&info->dst_mask, 0xff, sizeof(info->dst_mask)); + info->flags |= XT_HMARK_FLAG(XT_HMARK_DADDR_MASK); + *xflags |= (1 << O_HMARK_DADDR_MASK); + } else if (strncasecmp(type, "sport", len) == 0) { + memset(&info->port_mask.p16.src, 0xff, + sizeof(info->port_mask.p16.src)); + info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT_MASK); + *xflags |= (1 << O_HMARK_SPORT_MASK); + } else if (strncasecmp(type, "dport", len) == 0) { + memset(&info->port_mask.p16.dst, 0xff, + sizeof(info->port_mask.p16.dst)); + info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT_MASK); + *xflags |= (1 << O_HMARK_DPORT_MASK); + } else if (strncasecmp(type, "proto", len) == 0) { + memset(&info->proto_mask, 0xff, sizeof(info->proto_mask)); + info->flags |= XT_HMARK_FLAG(XT_HMARK_PROTO_MASK); + *xflags |= (1 << O_HMARK_PROTO_MASK); + } else if (strncasecmp(type, "spi", len) == 0) { + memset(&info->port_mask.v32, 0xff, sizeof(info->port_mask.v32)); + info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI_MASK); + *xflags |= (1 << O_HMARK_SPI_MASK); + } else + return 0; + + return 1; +} + +static void +hmark_parse_type(struct xt_option_call *cb) +{ + const char *arg = cb->arg; + struct xt_hmark_info *info = cb->data; + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg || + !hmark_parse(arg, comma-arg, info, &cb->xflags)) + xtables_error(PARAMETER_PROBLEM, "Bad type \"%s\"", arg); + arg = comma+1; + } + if (!*arg) + xtables_error(PARAMETER_PROBLEM, "\"--hmark-tuple\" requires " + "a list of types with no " + "spaces, e.g. " + "src,dst,sport,dport,proto"); + if (strlen(arg) == 0 || + !hmark_parse(arg, strlen(arg), info, &cb->xflags)) + xtables_error(PARAMETER_PROBLEM, "Bad type \"%s\"", arg); +} + +static void HMARK_parse(struct xt_option_call *cb, int plen) +{ + struct xt_hmark_info *info = cb->data; + + xtables_option_parse(cb); + + switch (cb->entry->id) { + case O_HMARK_TYPE: + hmark_parse_type(cb); + break; + case O_HMARK_SADDR_MASK: + info->flags |= XT_HMARK_FLAG(XT_HMARK_SADDR_MASK); + break; + case O_HMARK_DADDR_MASK: + info->flags |= XT_HMARK_FLAG(XT_HMARK_DADDR_MASK); + break; + case O_HMARK_SPI: + info->port_set.v32 = htonl(cb->val.u32); + info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI); + break; + case O_HMARK_SPORT: + info->port_set.p16.src = htons(cb->val.u16); + info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT); + break; + case O_HMARK_DPORT: + info->port_set.p16.dst = htons(cb->val.u16); + info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT); + break; + case O_HMARK_SPORT_MASK: + info->port_mask.p16.src = htons(cb->val.u16); + info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT_MASK); + break; + case O_HMARK_DPORT_MASK: + info->port_mask.p16.dst = htons(cb->val.u16); + info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT_MASK); + break; + case O_HMARK_SPI_MASK: + info->port_mask.v32 = htonl(cb->val.u32); + info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI_MASK); + break; + case O_HMARK_PROTO_MASK: + info->flags |= XT_HMARK_FLAG(XT_HMARK_PROTO_MASK); + break; + case O_HMARK_RND: + info->flags |= XT_HMARK_FLAG(XT_HMARK_RND); + break; + case O_HMARK_MODULUS: + info->flags |= XT_HMARK_FLAG(XT_HMARK_MODULUS); + break; + case O_HMARK_OFFSET: + info->flags |= XT_HMARK_FLAG(XT_HMARK_OFFSET); + break; + case O_HMARK_CT: + info->flags |= XT_HMARK_FLAG(XT_HMARK_CT); + break; + } + cb->xflags |= (1 << cb->entry->id); +} + +static void HMARK_ip4_parse(struct xt_option_call *cb) +{ + HMARK_parse(cb, 32); +} +static void HMARK_ip6_parse(struct xt_option_call *cb) +{ + HMARK_parse(cb, 128); +} + +static void HMARK_check(struct xt_fcheck_call *cb) +{ + if (!(cb->xflags & (1 << O_HMARK_MODULUS))) + xtables_error(PARAMETER_PROBLEM, "--hmark-mod is mandatory"); + if (!(cb->xflags & (1 << O_HMARK_RND))) + xtables_error(PARAMETER_PROBLEM, "--hmark-rnd is mandatory"); + if (cb->xflags & (1 << O_HMARK_SPI_MASK) && + (cb->xflags & ((1 << O_HMARK_SPORT_MASK) | + (1 << O_HMARK_DPORT_MASK)))) + xtables_error(PARAMETER_PROBLEM, "you cannot use " + "--hmark-spi-mask and --hmark-?port-mask," + "at the same time"); + if (!((cb->xflags & HMARK_OPT_PKT_MASK) || + cb->xflags & (1 << O_HMARK_CT))) + xtables_error(PARAMETER_PROBLEM, "you have to specify " + "--hmark-tuple at least"); +} + +static void HMARK_print(const struct xt_hmark_info *info) +{ + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT_MASK)) + printf("sport-mask 0x%x ", htons(info->port_mask.p16.src)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT_MASK)) + printf("dport-mask 0x%x ", htons(info->port_mask.p16.dst)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK)) + printf("spi-mask 0x%x ", htonl(info->port_mask.v32)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT)) + printf("sport 0x%x ", htons(info->port_set.p16.src)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT)) + printf("dport 0x%x ", htons(info->port_set.p16.dst)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI)) + printf("spi 0x%x ", htonl(info->port_set.v32)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_PROTO_MASK)) + printf("proto-mask 0x%x ", info->proto_mask); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_RND)) + printf("rnd 0x%x ", info->hashrnd); +} + +static void HMARK_ip6_print(const void *ip, + const struct xt_entry_target *target, int numeric) +{ + const struct xt_hmark_info *info = + (const struct xt_hmark_info *)target->data; + + printf(" HMARK "); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_MODULUS)) + printf("mod %u ", info->hmodulus); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_OFFSET)) + printf("+ 0x%x ", info->hoffset); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT)) + printf("ct, "); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK)) + printf("src-prefix %s ", + xtables_ip6mask_to_numeric(&info->src_mask.in6) + 1); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK)) + printf("dst-prefix %s ", + xtables_ip6mask_to_numeric(&info->dst_mask.in6) + 1); + HMARK_print(info); +} +static void HMARK_ip4_print(const void *ip, + const struct xt_entry_target *target, int numeric) +{ + const struct xt_hmark_info *info = + (const struct xt_hmark_info *)target->data; + + printf(" HMARK "); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_MODULUS)) + printf("mod %u ", info->hmodulus); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_OFFSET)) + printf("+ 0x%x ", info->hoffset); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT)) + printf("ct, "); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK)) + printf("src-prefix %u ", + xtables_ipmask_to_cidr(&info->src_mask.in)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK)) + printf("dst-prefix %u ", + xtables_ipmask_to_cidr(&info->dst_mask.in)); + HMARK_print(info); +} + +static void HMARK_save(const struct xt_hmark_info *info) +{ + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT_MASK)) + printf(" --hmark-sport-mask 0x%04x", + htons(info->port_mask.p16.src)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT_MASK)) + printf(" --hmark-dport-mask 0x%04x", + htons(info->port_mask.p16.dst)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK)) + printf(" --hmark-spi-mask 0x%08x", + htonl(info->port_mask.v32)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT)) + printf(" --hmark-sport 0x%04x", + htons(info->port_set.p16.src)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT)) + printf(" --hmark-dport 0x%04x", + htons(info->port_set.p16.dst)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI)) + printf(" --hmark-spi 0x%08x", htonl(info->port_set.v32)); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_PROTO_MASK)) + printf(" --hmark-proto-mask 0x%02x", info->proto_mask); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_RND)) + printf(" --hmark-rnd 0x%08x", info->hashrnd); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_MODULUS)) + printf(" --hmark-mod %u", info->hmodulus); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_OFFSET)) + printf(" --hmark-offset %u", info->hoffset); + if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT)) + printf(" --hmark-tuple ct"); +} + +static void HMARK_ip6_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_hmark_info *info = + (const struct xt_hmark_info *)target->data; + int ret; + + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK)) { + ret = xtables_ip6mask_to_cidr(&info->src_mask.in6); + printf(" --hmark-src-prefix %d", ret); + } + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK)) { + ret = xtables_ip6mask_to_cidr(&info->dst_mask.in6); + printf(" --hmark-dst-prefix %d", ret); + } + HMARK_save(info); +} + +static void HMARK_ip4_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_hmark_info *info = + (const struct xt_hmark_info *)target->data; + int ret; + + if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK)) { + ret = xtables_ipmask_to_cidr(&info->src_mask.in); + printf(" --hmark-src-prefix %d", ret); + } + if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK)) { + ret = xtables_ipmask_to_cidr(&info->dst_mask.in); + printf(" --hmark-dst-prefix %d", ret); + } + HMARK_save(info); +} + +static struct xtables_target mark_tg_reg[] = { + { + .family = NFPROTO_IPV4, + .name = "HMARK", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_hmark_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_hmark_info)), + .help = HMARK_help, + .print = HMARK_ip4_print, + .save = HMARK_ip4_save, + .x6_parse = HMARK_ip4_parse, + .x6_fcheck = HMARK_check, + .x6_options = HMARK_opts, + }, + { + .family = NFPROTO_IPV6, + .name = "HMARK", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_hmark_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_hmark_info)), + .help = HMARK_help, + .print = HMARK_ip6_print, + .save = HMARK_ip6_save, + .x6_parse = HMARK_ip6_parse, + .x6_fcheck = HMARK_check, + .x6_options = HMARK_opts, + }, +}; + +void _init(void) +{ + xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg)); +} diff --git a/extensions/libxt_HMARK.man b/extensions/libxt_HMARK.man new file mode 100644 index 0000000..e7b5426 --- /dev/null +++ b/extensions/libxt_HMARK.man @@ -0,0 +1,60 @@ +Like MARK, i.e. set the fwmark, but the mark is calculated from hashing +packet selector at choice. You have also to specify the mark range and, +optionally, the offset to start from. ICMP error messages are inspected +and used to calculate the hashing. +.PP +Existing options are: +.TP +\fB\-\-hmark\-tuple\fP tuple\fI\fP +Possible tuple members are: +.B src +meaning source address (IPv4, IPv6 address), +.B dst +meaning destination address (IPv4, IPv6 address), +.B sport +meaning source port (TCP, UDP, UDPlite, SCTP, DCCP), +.B dport +meaning destination port (TCP, UDP, UDPlite, SCTP, DCCP), +.B spi +meaning Security Parameter Index (AH, ESP), and +.B ct +meaning the usage of the conntrack tuple instead of the packet selectors. +.TP +\fB\-\-hmark\-mod\fP \fIvalue (must be > 0)\fP +Modulus for hash calculation (to limit the range of possible marks) +.TP +\fB\-\-hmark\-offset\fP \fIvalue\fP +Offset to start marks from. +.TP +For advanced usage, instead of using \-\-hmark\-tuple, you can specify custom +prefixes and masks: +.TP +\fB\-\-hmark\-src\-prefix\fP \fIcidr\fP +The source address mask in CIDR notation. +.TP +\fB\-\-hmark\-dst\-prefix\fP \fIcidr\fP +The destination address mask in CIDR notation. +.TP +\fB\-\-hmark\-sport\-mask\fP \fIvalue\fP +A 16 bit source port mask in hexadecimal. +.TP +\fB\-\-hmark\-dport\-mask\fP \fIvalue\fP +A 16 bit destination port mask in hexadecimal. +.TP +\fB\-\-hmark\-spi\-mask\fP \fIvalue\fP +A 32 bit field with spi mask. +.TP +\fB\-\-hmark\-proto\-mask\fP \fIvalue\fP +An 8 bit field with layer 4 protocol number. +.TP +\fB\-\-hmark\-rnd\fP \fIvalue\fP +A 32 bit random custom value to feed hash calculation. +.PP +\fIExamples:\fP +.PP +iptables \-t mangle \-A PREROUTING \-m conntrack \-\-ctstate NEW + \-j HMARK \-\-hmark-tuple ct,src,dst,proto \-\-hmark-offset 10000 +\-\-hmark\-mod 10 \-\-hmark\-rnd 0xfeedcafe +.PP +iptables \-t mangle \-A PREROUTING -j HMARK \-\-hmark\-offset 10000 +\-\-hmark-tuple src,dst,proto \-\-hmark-mod 10 \-\-hmark\-rnd 0xdeafbeef diff --git a/extensions/libxt_IDLETIMER.c b/extensions/libxt_IDLETIMER.c new file mode 100644 index 0000000..21004a4 --- /dev/null +++ b/extensions/libxt_IDLETIMER.c @@ -0,0 +1,89 @@ +/* + * Shared library add-on for iptables to add IDLETIMER support. + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * + * Contact: Luciano Coelho <luciano.coelho@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter/xt_IDLETIMER.h> + +enum { + O_TIMEOUT = 0, + O_LABEL, +}; + +#define s struct idletimer_tg_info +static const struct xt_option_entry idletimer_tg_opts[] = { + {.name = "timeout", .id = O_TIMEOUT, .type = XTTYPE_UINT32, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, timeout)}, + {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, label)}, + XTOPT_TABLEEND, +}; +#undef s + +static void idletimer_tg_help(void) +{ + printf( +"IDLETIMER target options:\n" +" --timeout time Timeout until the notification is sent (in seconds)\n" +" --label string Unique rule identifier\n" +"\n"); +} + +static void idletimer_tg_print(const void *ip, + const struct xt_entry_target *target, + int numeric) +{ + struct idletimer_tg_info *info = + (struct idletimer_tg_info *) target->data; + + printf(" timeout:%u", info->timeout); + printf(" label:%s", info->label); +} + +static void idletimer_tg_save(const void *ip, + const struct xt_entry_target *target) +{ + struct idletimer_tg_info *info = + (struct idletimer_tg_info *) target->data; + + printf(" --timeout %u", info->timeout); + printf(" --label %s", info->label); +} + +static struct xtables_target idletimer_tg_reg = { + .family = NFPROTO_UNSPEC, + .name = "IDLETIMER", + .version = XTABLES_VERSION, + .revision = 0, + .size = XT_ALIGN(sizeof(struct idletimer_tg_info)), + .userspacesize = offsetof(struct idletimer_tg_info, timer), + .help = idletimer_tg_help, + .x6_parse = xtables_option_parse, + .print = idletimer_tg_print, + .save = idletimer_tg_save, + .x6_options = idletimer_tg_opts, +}; + +void _init(void) +{ + xtables_register_target(&idletimer_tg_reg); +} diff --git a/extensions/libxt_IDLETIMER.man b/extensions/libxt_IDLETIMER.man new file mode 100644 index 0000000..e3c91ce --- /dev/null +++ b/extensions/libxt_IDLETIMER.man @@ -0,0 +1,20 @@ +This target can be used to identify when interfaces have been idle for a +certain period of time. Timers are identified by labels and are created when +a rule is set with a new label. The rules also take a timeout value (in +seconds) as an option. If more than one rule uses the same timer label, the +timer will be restarted whenever any of the rules get a hit. One entry for +each timer is created in sysfs. This attribute contains the timer remaining +for the timer to expire. The attributes are located under the xt_idletimer +class: +.PP +/sys/class/xt_idletimer/timers/<label> +.PP +When the timer expires, the target module sends a sysfs notification to the +userspace, which can then decide what to do (eg. disconnect to save power). +.TP +\fB\-\-timeout\fP \fIamount\fP +This is the time in seconds that will trigger the notification. +.TP +\fB\-\-label\fP \fIstring\fP +This is a unique identifier for the timer. The maximum length for the +label string is 27 characters. diff --git a/extensions/libxt_LED.c b/extensions/libxt_LED.c index af0e091..8622c37 100644 --- a/extensions/libxt_LED.c +++ b/extensions/libxt_LED.c @@ -9,23 +9,30 @@ * published by the Free Software Foundation. * */ - #include <stdio.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> -#include <stddef.h> - #include <xtables.h> - #include <linux/netfilter/xt_LED.h> -static const struct option LED_opts[] = { - {.name = "led-trigger-id", .has_arg = true, .val = 'i'}, - {.name = "led-delay", .has_arg = true, .val = 'd'}, - {.name = "led-always-blink", .has_arg = false, .val = 'a'}, - {.name = NULL}, +enum { + O_LED_TRIGGER_ID = 0, + O_LED_DELAY, + O_LED_ALWAYS_BLINK, +}; + +#define s struct xt_led_info +static const struct xt_option_entry LED_opts[] = { + {.name = "led-trigger-id", .id = O_LED_TRIGGER_ID, + .flags = XTOPT_MAND, .type = XTTYPE_STRING, .min = 0, + .max = sizeof(((struct xt_led_info *)NULL)->id) - + sizeof("netfilter-")}, + {.name = "led-delay", .id = O_LED_DELAY, .type = XTTYPE_STRING}, + {.name = "led-always-blink", .id = O_LED_ALWAYS_BLINK, + .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s static void LED_help(void) { @@ -39,50 +46,28 @@ static void LED_help(void) ); } -static int LED_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void LED_parse(struct xt_option_call *cb) { - struct xt_led_info *led = (void *)(*target)->data; - - switch (c) { - case 'i': - xtables_param_act(XTF_NO_INVERT, "LED", - "--led-trigger-id", invert); - if (strlen("netfilter-") + strlen(optarg) > sizeof(led->id)) - xtables_error(PARAMETER_PROBLEM, - "--led-trigger-id must be 16 chars or less"); - if (optarg[0] == '\0') - xtables_error(PARAMETER_PROBLEM, - "--led-trigger-id cannot be blank"); + struct xt_led_info *led = cb->data; - /* "netfilter-" + 16 char id == 26 == sizeof(led->id) */ + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_LED_TRIGGER_ID: strcpy(led->id, "netfilter-"); - strcat(led->id, optarg); - *flags = 1; - return true; - - case 'd': - xtables_param_act(XTF_NO_INVERT, "LED", "--led-delay", invert); - if (strncasecmp(optarg, "inf", 3) == 0) + strcat(led->id, cb->arg); + break; + case O_LED_DELAY: + if (strncasecmp(cb->arg, "inf", 3) == 0) led->delay = -1; - else - led->delay = strtoul(optarg, NULL, 0); - - return true; - - case 'a': - if (!invert) - led->always_blink = 1; - return true; + else if (!xtables_strtoui(cb->arg, NULL, &led->delay, 0, UINT32_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Delay value must be within range 0..%u", + UINT32_MAX); + break; + case O_LED_ALWAYS_BLINK: + led->always_blink = 1; + break; } - return false; -} - -static void LED_final_check(unsigned int flags) -{ - if (flags == 0) - xtables_error(PARAMETER_PROBLEM, - "--led-trigger-id must be specified"); } static void LED_print(const void *ip, const struct xt_entry_target *target, @@ -91,22 +76,22 @@ static void LED_print(const void *ip, const struct xt_entry_target *target, const struct xt_led_info *led = (void *)target->data; const char *id = led->id + strlen("netfilter-"); /* trim off prefix */ - printf("led-trigger-id:\""); + printf(" led-trigger-id:\""); /* Escape double quotes and backslashes in the ID */ while (*id != '\0') { if (*id == '"' || *id == '\\') printf("\\"); printf("%c", *id++); } - printf("\" "); + printf("\""); if (led->delay == -1) - printf("led-delay:inf "); + printf(" led-delay:inf"); else - printf("led-delay:%dms ", led->delay); + printf(" led-delay:%dms", led->delay); if (led->always_blink) - printf("led-always-blink "); + printf(" led-always-blink"); } static void LED_save(const void *ip, const struct xt_entry_target *target) @@ -114,24 +99,24 @@ static void LED_save(const void *ip, const struct xt_entry_target *target) const struct xt_led_info *led = (void *)target->data; const char *id = led->id + strlen("netfilter-"); /* trim off prefix */ - printf("--led-trigger-id \""); + printf(" --led-trigger-id \""); /* Escape double quotes and backslashes in the ID */ while (*id != '\0') { if (*id == '"' || *id == '\\') printf("\\"); printf("%c", *id++); } - printf("\" "); + printf("\""); /* Only print the delay if it's not zero (the default) */ if (led->delay > 0) - printf("--led-delay %d ", led->delay); + printf(" --led-delay %d", led->delay); else if (led->delay == -1) - printf("--led-delay inf "); + printf(" --led-delay inf"); /* Only print always_blink if it's not set to the default */ if (led->always_blink) - printf("--led-always-blink "); + printf(" --led-always-blink"); } static struct xtables_target led_tg_reg = { @@ -142,11 +127,10 @@ static struct xtables_target led_tg_reg = { .size = XT_ALIGN(sizeof(struct xt_led_info)), .userspacesize = offsetof(struct xt_led_info, internal_data), .help = LED_help, - .parse = LED_parse, - .final_check = LED_final_check, - .extra_opts = LED_opts, .print = LED_print, .save = LED_save, + .x6_parse = LED_parse, + .x6_options = LED_opts, }; void _init(void) diff --git a/extensions/libip6t_LOG.man b/extensions/libxt_LOG.man index b7803fe..354edf4 100644 --- a/extensions/libip6t_LOG.man +++ b/extensions/libxt_LOG.man @@ -1,17 +1,18 @@ Turn on kernel logging of matching packets. When this option is set for a rule, the Linux kernel will print some information on all -matching packets (like most IPv6 IPv6-header fields) via the kernel log -(where it can be read with -.I dmesg -or -.IR syslogd (8)). +matching packets (like most IP/IPv6 header fields) via the kernel log +(where it can be read with \fIdmesg(1)\fP or read in the syslog). +.PP This is a "non-terminating target", i.e. rule traversal continues at the next rule. So if you want to LOG the packets you refuse, use two separate rules with the same matching criteria, first using target LOG then DROP (or REJECT). .TP \fB\-\-log\-level\fP \fIlevel\fP -Level of logging (numeric or see \fIsyslog.conf\fP(5)). +Level of logging, which can be (system-specific) numeric or a mnemonic. +Possible values are (in decreasing order of priority): \fBemerg\fP, +\fBalert\fP, \fBcrit\fP, \fBerror\fP, \fBwarning\fP, \fBnotice\fP, \fBinfo\fP +or \fBdebug\fP. .TP \fB\-\-log\-prefix\fP \fIprefix\fP Prefix log messages with the specified prefix; up to 29 letters long, @@ -25,7 +26,7 @@ readable by users. Log options from the TCP packet header. .TP \fB\-\-log\-ip\-options\fP -Log options from the IPv6 packet header. +Log options from the IP/IPv6 packet header. .TP \fB\-\-log\-uid\fP Log the userid of the process which generated the packet. diff --git a/extensions/libxt_MARK.c b/extensions/libxt_MARK.c index dbfc7c0..556dbde 100644 --- a/extensions/libxt_MARK.c +++ b/extensions/libxt_MARK.c @@ -1,12 +1,6 @@ -/* Shared library add-on to iptables to add MARK target support. */ #include <stdbool.h> #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_MARK.h> /* Version 0 */ @@ -23,11 +17,22 @@ enum { struct xt_mark_target_info_v1 { unsigned long mark; - u_int8_t mode; + uint8_t mode; }; enum { - F_MARK = 1 << 0, + O_SET_MARK = 0, + O_AND_MARK, + O_OR_MARK, + O_XOR_MARK, + O_SET_XMARK, + F_SET_MARK = 1 << O_SET_MARK, + F_AND_MARK = 1 << O_AND_MARK, + F_OR_MARK = 1 << O_OR_MARK, + F_XOR_MARK = 1 << O_XOR_MARK, + F_SET_XMARK = 1 << O_SET_XMARK, + F_ANY = F_SET_MARK | F_AND_MARK | F_OR_MARK | + F_XOR_MARK | F_SET_XMARK, }; static void MARK_help(void) @@ -39,20 +44,28 @@ static void MARK_help(void) " --or-mark value Binary OR the nfmark with value\n"); } -static const struct option MARK_opts[] = { - { "set-mark", 1, NULL, '1' }, - { "and-mark", 1, NULL, '2' }, - { "or-mark", 1, NULL, '3' }, - { .name = NULL } +static const struct xt_option_entry MARK_opts[] = { + {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_UINT32, + .excl = F_ANY}, + {.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32, + .excl = F_ANY}, + {.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32, + .excl = F_ANY}, + XTOPT_TABLEEND, }; -static const struct option mark_tg_opts[] = { - {.name = "set-xmark", .has_arg = true, .val = 'X'}, - {.name = "set-mark", .has_arg = true, .val = '='}, - {.name = "and-mark", .has_arg = true, .val = '&'}, - {.name = "or-mark", .has_arg = true, .val = '|'}, - {.name = "xor-mark", .has_arg = true, .val = '^'}, - { .name = NULL } +static const struct xt_option_entry mark_tg_opts[] = { + {.name = "set-xmark", .id = O_SET_XMARK, .type = XTTYPE_MARKMASK32, + .excl = F_ANY}, + {.name = "set-mark", .id = O_SET_MARK, .type = XTTYPE_MARKMASK32, + .excl = F_ANY}, + {.name = "and-mark", .id = O_AND_MARK, .type = XTTYPE_UINT32, + .excl = F_ANY}, + {.name = "or-mark", .id = O_OR_MARK, .type = XTTYPE_UINT32, + .excl = F_ANY}, + {.name = "xor-mark", .id = O_XOR_MARK, .type = XTTYPE_UINT32, + .excl = F_ANY}, + XTOPT_TABLEEND, }; static void mark_tg_help(void) @@ -67,144 +80,80 @@ static void mark_tg_help(void) "\n"); } -/* Function which parses command options; returns true if it - ate an option */ -static int -MARK_parse_v0(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void MARK_parse_v0(struct xt_option_call *cb) { - struct xt_mark_target_info *markinfo - = (struct xt_mark_target_info *)(*target)->data; - unsigned int mark = 0; + struct xt_mark_target_info *markinfo = cb->data; - switch (c) { - case '1': - if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); - markinfo->mark = mark; - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "MARK target: Can't specify --set-mark twice"); - *flags = 1; + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET_MARK: + markinfo->mark = cb->val.mark; break; - case '2': - xtables_error(PARAMETER_PROBLEM, - "MARK target: kernel too old for --and-mark"); - case '3': - xtables_error(PARAMETER_PROBLEM, - "MARK target: kernel too old for --or-mark"); default: - return 0; + xtables_error(PARAMETER_PROBLEM, + "MARK target: kernel too old for --%s", + cb->entry->name); } - - return 1; } -static void MARK_check(unsigned int flags) +static void MARK_check(struct xt_fcheck_call *cb) { - if (!flags) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "MARK target: Parameter --set/and/or-mark" " is required"); } -static int -MARK_parse_v1(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void MARK_parse_v1(struct xt_option_call *cb) { - struct xt_mark_target_info_v1 *markinfo - = (struct xt_mark_target_info_v1 *)(*target)->data; - unsigned int mark = 0; + struct xt_mark_target_info_v1 *markinfo = cb->data; - switch (c) { - case '1': + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET_MARK: markinfo->mode = XT_MARK_SET; break; - case '2': + case O_AND_MARK: markinfo->mode = XT_MARK_AND; break; - case '3': + case O_OR_MARK: markinfo->mode = XT_MARK_OR; break; - default: - return 0; } - - if (!xtables_strtoui(optarg, NULL, &mark, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); - markinfo->mark = mark; - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "MARK target: Can't specify --set-mark twice"); - - *flags = 1; - return 1; + markinfo->mark = cb->val.u32; } -static int mark_tg_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void mark_tg_parse(struct xt_option_call *cb) { - struct xt_mark_tginfo2 *info = (void *)(*target)->data; - unsigned int value, mask = UINT32_MAX; - char *end; + struct xt_mark_tginfo2 *info = cb->data; - switch (c) { - case 'X': /* --set-xmark */ - case '=': /* --set-mark */ - xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); - xtables_param_act(XTF_NO_INVERT, "MARK", "--set-xmark/--set-mark", invert); - if (!xtables_strtoui(optarg, &end, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); - if (*end == '/') - if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); - if (*end != '\0') - xtables_param_act(XTF_BAD_VALUE, "MARK", "--set-xmark/--set-mark", optarg); - info->mark = value; - info->mask = mask; - - if (c == '=') - info->mask = value | mask; + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET_XMARK: + info->mark = cb->val.mark; + info->mask = cb->val.mask; break; - - case '&': /* --and-mark */ - xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); - xtables_param_act(XTF_NO_INVERT, "MARK", "--and-mark", invert); - if (!xtables_strtoui(optarg, NULL, &mask, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MARK", "--and-mark", optarg); + case O_SET_MARK: + info->mark = cb->val.mark; + info->mask = cb->val.mark | cb->val.mask; + break; + case O_AND_MARK: info->mark = 0; - info->mask = ~mask; + info->mask = ~cb->val.u32; break; - - case '|': /* --or-mark */ - xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); - xtables_param_act(XTF_NO_INVERT, "MARK", "--or-mark", invert); - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MARK", "--or-mark", optarg); - info->mark = value; - info->mask = value; + case O_OR_MARK: + info->mark = info->mask = cb->val.u32; break; - - case '^': /* --xor-mark */ - xtables_param_act(XTF_ONE_ACTION, "MARK", *flags & F_MARK); - xtables_param_act(XTF_NO_INVERT, "MARK", "--xor-mark", invert); - if (!xtables_strtoui(optarg, NULL, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "MARK", "--xor-mark", optarg); - info->mark = value; + case O_XOR_MARK: + info->mark = cb->val.u32; info->mask = 0; break; - - default: - return false; } - - *flags |= F_MARK; - return true; } -static void mark_tg_check(unsigned int flags) +static void mark_tg_check(struct xt_fcheck_call *cb) { - if (flags == 0) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "MARK: One of the --set-xmark, " "--{and,or,xor,set}-mark options is required"); } @@ -212,7 +161,7 @@ static void mark_tg_check(unsigned int flags) static void print_mark(unsigned long mark) { - printf("0x%lx ", mark); + printf(" 0x%lx", mark); } static void MARK_print_v0(const void *ip, @@ -220,7 +169,7 @@ static void MARK_print_v0(const void *ip, { const struct xt_mark_target_info *markinfo = (const struct xt_mark_target_info *)target->data; - printf("MARK set "); + printf(" MARK set"); print_mark(markinfo->mark); } @@ -229,7 +178,7 @@ static void MARK_save_v0(const void *ip, const struct xt_entry_target *target) const struct xt_mark_target_info *markinfo = (const struct xt_mark_target_info *)target->data; - printf("--set-mark "); + printf(" --set-mark"); print_mark(markinfo->mark); } @@ -241,13 +190,13 @@ static void MARK_print_v1(const void *ip, const struct xt_entry_target *target, switch (markinfo->mode) { case XT_MARK_SET: - printf("MARK set "); + printf(" MARK set"); break; case XT_MARK_AND: - printf("MARK and "); + printf(" MARK and"); break; case XT_MARK_OR: - printf("MARK or "); + printf(" MARK or"); break; } print_mark(markinfo->mark); @@ -259,15 +208,15 @@ static void mark_tg_print(const void *ip, const struct xt_entry_target *target, const struct xt_mark_tginfo2 *info = (const void *)target->data; if (info->mark == 0) - printf("MARK and 0x%x ", (unsigned int)(u_int32_t)~info->mask); + printf(" MARK and 0x%x", (unsigned int)(uint32_t)~info->mask); else if (info->mark == info->mask) - printf("MARK or 0x%x ", info->mark); + printf(" MARK or 0x%x", info->mark); else if (info->mask == 0) - printf("MARK xor 0x%x ", info->mark); + printf(" MARK xor 0x%x", info->mark); else if (info->mask == 0xffffffffU) - printf("MARK set 0x%x ", info->mark); + printf(" MARK set 0x%x", info->mark); else - printf("MARK xset 0x%x/0x%x ", info->mark, info->mask); + printf(" MARK xset 0x%x/0x%x", info->mark, info->mask); } static void MARK_save_v1(const void *ip, const struct xt_entry_target *target) @@ -277,13 +226,13 @@ static void MARK_save_v1(const void *ip, const struct xt_entry_target *target) switch (markinfo->mode) { case XT_MARK_SET: - printf("--set-mark "); + printf(" --set-mark"); break; case XT_MARK_AND: - printf("--and-mark "); + printf(" --and-mark"); break; case XT_MARK_OR: - printf("--or-mark "); + printf(" --or-mark"); break; } print_mark(markinfo->mark); @@ -293,7 +242,7 @@ static void mark_tg_save(const void *ip, const struct xt_entry_target *target) { const struct xt_mark_tginfo2 *info = (const void *)target->data; - printf("--set-xmark 0x%x/0x%x ", info->mark, info->mask); + printf(" --set-xmark 0x%x/0x%x", info->mark, info->mask); } static struct xtables_target mark_tg_reg[] = { @@ -305,11 +254,11 @@ static struct xtables_target mark_tg_reg[] = { .size = XT_ALIGN(sizeof(struct xt_mark_target_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info)), .help = MARK_help, - .parse = MARK_parse_v0, - .final_check = MARK_check, .print = MARK_print_v0, .save = MARK_save_v0, - .extra_opts = MARK_opts, + .x6_parse = MARK_parse_v0, + .x6_fcheck = MARK_check, + .x6_options = MARK_opts, }, { .family = NFPROTO_IPV4, @@ -319,11 +268,11 @@ static struct xtables_target mark_tg_reg[] = { .size = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), .userspacesize = XT_ALIGN(sizeof(struct xt_mark_target_info_v1)), .help = MARK_help, - .parse = MARK_parse_v1, - .final_check = MARK_check, .print = MARK_print_v1, .save = MARK_save_v1, - .extra_opts = MARK_opts, + .x6_parse = MARK_parse_v1, + .x6_fcheck = MARK_check, + .x6_options = MARK_opts, }, { .version = XTABLES_VERSION, @@ -333,11 +282,11 @@ static struct xtables_target mark_tg_reg[] = { .size = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), .userspacesize = XT_ALIGN(sizeof(struct xt_mark_tginfo2)), .help = mark_tg_help, - .parse = mark_tg_parse, - .final_check = mark_tg_check, .print = mark_tg_print, .save = mark_tg_save, - .extra_opts = mark_tg_opts, + .x6_parse = mark_tg_parse, + .x6_fcheck = mark_tg_check, + .x6_options = mark_tg_opts, }, }; diff --git a/extensions/libxt_MARK.man b/extensions/libxt_MARK.man index aaeceb4..712fb76 100644 --- a/extensions/libxt_MARK.man +++ b/extensions/libxt_MARK.man @@ -5,23 +5,23 @@ PREROUTING chain of the mangle table to affect routing. The mark field is 32 bits wide. .TP \fB\-\-set\-xmark\fP \fIvalue\fP[\fB/\fP\fImask\fP] -Zeroes out the bits given by \fImask\fR and XORs \fIvalue\fR into the packet -mark ("nfmark"). If \fImask\fR is omitted, 0xFFFFFFFF is assumed. +Zeroes out the bits given by \fImask\fP and XORs \fIvalue\fP into the packet +mark ("nfmark"). If \fImask\fP is omitted, 0xFFFFFFFF is assumed. .TP \fB\-\-set\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP] -Zeroes out the bits given by \fImask\fR and ORs \fIvalue\fR into the packet -mark. If \fImask\fR is omitted, 0xFFFFFFFF is assumed. +Zeroes out the bits given by \fImask\fP and ORs \fIvalue\fP into the packet +mark. If \fImask\fP is omitted, 0xFFFFFFFF is assumed. .PP The following mnemonics are available: .TP \fB\-\-and\-mark\fP \fIbits\fP -Binary AND the nfmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark -0/\fR\fIinvbits\fR, where \fIinvbits\fR is the binary negation of \fIbits\fR.) +Binary AND the nfmark with \fIbits\fP. (Mnemonic for \fB\-\-set\-xmark +0/\fP\fIinvbits\fP, where \fIinvbits\fP is the binary negation of \fIbits\fP.) .TP \fB\-\-or\-mark\fP \fIbits\fP -Binary OR the nfmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP -\fIbits\fR\fB/\fR\fIbits\fR.) +Binary OR the nfmark with \fIbits\fP. (Mnemonic for \fB\-\-set\-xmark\fP +\fIbits\fP\fB/\fP\fIbits\fP.) .TP \fB\-\-xor\-mark\fP \fIbits\fP -Binary XOR the nfmark with \fIbits\fR. (Mnemonic for \fB\-\-set\-xmark\fP -\fIbits\fR\fB/0\fR.) +Binary XOR the nfmark with \fIbits\fP. (Mnemonic for \fB\-\-set\-xmark\fP +\fIbits\fP\fB/0\fP.) diff --git a/extensions/libipt_MASQUERADE.man b/extensions/libxt_MASQUERADE.man index 8f42993..c9e3950 100644 --- a/extensions/libipt_MASQUERADE.man +++ b/extensions/libxt_MASQUERADE.man @@ -10,21 +10,19 @@ effect that connections are .I forgotten when the interface goes down. This is the correct behavior when the next dialup is unlikely to have the same interface address (and hence -any established connections are lost anyway). It takes one option: +any established connections are lost anyway). .TP \fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP] This specifies a range of source ports to use, overriding the default .B SNAT source port-selection heuristics (see above). This is only valid -if the rule also specifies -\fB\-p tcp\fP -or -\fB\-p udp\fP. +if the rule also specifies one of the following protocols: +\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. .TP \fB\-\-random\fP Randomize source port mapping If option \fB\-\-random\fP is used then port mapping will be randomized (kernel >= 2.6.21). -.RS -.PP +.TP +IPv6 support available since Linux kernels >= 3.7. diff --git a/extensions/libipt_NETMAP.man b/extensions/libxt_NETMAP.man index a7e90b8..06507db 100644 --- a/extensions/libipt_NETMAP.man +++ b/extensions/libxt_NETMAP.man @@ -7,3 +7,5 @@ table. Network address to map to. The resulting address will be constructed in the following way: All 'one' bits in the mask are filled in from the new `address'. All bits that are zero in the mask are filled in from the original address. +.TP +IPv6 support available since Linux kernels >= 3.7. diff --git a/extensions/libxt_NFLOG.c b/extensions/libxt_NFLOG.c index e2185d5..448576a 100644 --- a/extensions/libxt_NFLOG.c +++ b/extensions/libxt_NFLOG.c @@ -1,3 +1,4 @@ +#include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -8,19 +9,25 @@ #include <linux/netfilter/xt_NFLOG.h> enum { - NFLOG_GROUP = 0x1, - NFLOG_PREFIX = 0x2, - NFLOG_RANGE = 0x4, - NFLOG_THRESHOLD = 0x8, + O_GROUP = 0, + O_PREFIX, + O_RANGE, + O_THRESHOLD, }; -static const struct option NFLOG_opts[] = { - { "nflog-group", 1, NULL, NFLOG_GROUP }, - { "nflog-prefix", 1, NULL, NFLOG_PREFIX }, - { "nflog-range", 1, NULL, NFLOG_RANGE }, - { "nflog-threshold", 1, NULL, NFLOG_THRESHOLD }, - { .name = NULL } +#define s struct xt_nflog_info +static const struct xt_option_entry NFLOG_opts[] = { + {.name = "nflog-group", .id = O_GROUP, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, group)}, + {.name = "nflog-prefix", .id = O_PREFIX, .type = XTTYPE_STRING, + .min = 1, .flags = XTOPT_PUT, XTOPT_POINTER(s, prefix)}, + {.name = "nflog-range", .id = O_RANGE, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, len)}, + {.name = "nflog-threshold", .id = O_THRESHOLD, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, threshold)}, + XTOPT_TABLEEND, }; +#undef s static void NFLOG_help(void) { @@ -35,92 +42,33 @@ static void NFLOG_init(struct xt_entry_target *t) { struct xt_nflog_info *info = (struct xt_nflog_info *)t->data; - info->group = 0; info->threshold = XT_NFLOG_DEFAULT_THRESHOLD; } -static int NFLOG_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void NFLOG_parse(struct xt_option_call *cb) { - struct xt_nflog_info *info = (struct xt_nflog_info *)(*target)->data; - int n; - size_t length; - - switch (c) { - case NFLOG_GROUP: - if (*flags & NFLOG_GROUP) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --nflog-group twice"); - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --nflog-group"); - - n = atoi(optarg); - if (n < 0) - xtables_error(PARAMETER_PROBLEM, - "--nflog-group can not be negative"); - info->group = n; - break; - case NFLOG_PREFIX: - if (*flags & NFLOG_PREFIX) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --nflog-prefix twice"); - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --nflog-prefix"); - - length = strlen(optarg); - if (length == 0) - xtables_error(PARAMETER_PROBLEM, - "No prefix specified for --nflog-prefix"); - if (length >= sizeof(info->prefix)) - xtables_error(PARAMETER_PROBLEM, - "--nflog-prefix too long, max %Zu characters", - sizeof(info->prefix) - 1); - if (length != strlen(strtok(optarg, "\n"))) - xtables_error(PARAMETER_PROBLEM, - "Newlines are not allowed in --nflog-prefix"); - strcpy(info->prefix, optarg); - break; - case NFLOG_RANGE: - if (*flags & NFLOG_RANGE) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --nflog-range twice"); - n = atoi(optarg); - if (n < 0) - xtables_error(PARAMETER_PROBLEM, - "Invalid --nflog-range, must be >= 0"); - info->len = n; - break; - case NFLOG_THRESHOLD: - if (*flags & NFLOG_THRESHOLD) - xtables_error(PARAMETER_PROBLEM, - "Can't specify --nflog-threshold twice"); - n = atoi(optarg); - if (n < 1) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_PREFIX: + if (strchr(cb->arg, '\n') != NULL) xtables_error(PARAMETER_PROBLEM, - "Invalid --nflog-threshold, must be >= 1"); - info->threshold = n; + "Newlines not allowed in --log-prefix"); break; - default: - return 0; } - *flags |= c; - return 1; } static void nflog_print(const struct xt_nflog_info *info, char *prefix) { if (info->prefix[0] != '\0') { - printf("%snflog-prefix ", prefix); + printf(" %snflog-prefix ", prefix); xtables_save_string(info->prefix); } if (info->group) - printf("%snflog-group %u ", prefix, info->group); + printf(" %snflog-group %u", prefix, info->group); if (info->len) - printf("%snflog-range %u ", prefix, info->len); + printf(" %snflog-range %u", prefix, info->len); if (info->threshold != XT_NFLOG_DEFAULT_THRESHOLD) - printf("%snflog-threshold %u ", prefix, info->threshold); + printf(" %snflog-threshold %u", prefix, info->threshold); } static void NFLOG_print(const void *ip, const struct xt_entry_target *target, @@ -146,10 +94,10 @@ static struct xtables_target nflog_target = { .userspacesize = XT_ALIGN(sizeof(struct xt_nflog_info)), .help = NFLOG_help, .init = NFLOG_init, - .parse = NFLOG_parse, + .x6_parse = NFLOG_parse, .print = NFLOG_print, .save = NFLOG_save, - .extra_opts = NFLOG_opts, + .x6_options = NFLOG_opts, }; void _init(void) diff --git a/extensions/libxt_NFLOG.man b/extensions/libxt_NFLOG.man index 66f0b97..1b6dbf1 100644 --- a/extensions/libxt_NFLOG.man +++ b/extensions/libxt_NFLOG.man @@ -9,7 +9,7 @@ may subscribe to the group to receive the packets. Like LOG, this is a non-terminating target, i.e. rule traversal continues at the next rule. .TP \fB\-\-nflog\-group\fP \fInlgroup\fP -The netlink group (1 \- 2^32\-1) to which packets are (only applicable for +The netlink group (0 - 2^16\-1) to which packets are (only applicable for nfnetlink_log). The default value is 0. .TP \fB\-\-nflog\-prefix\fP \fIprefix\fP diff --git a/extensions/libxt_NFQUEUE.c b/extensions/libxt_NFQUEUE.c index 2d9d98a..0c86918 100644 --- a/extensions/libxt_NFQUEUE.c +++ b/extensions/libxt_NFQUEUE.c @@ -6,14 +6,19 @@ * */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_NFQUEUE.h> +enum { + O_QUEUE_NUM = 0, + O_QUEUE_BALANCE, + O_QUEUE_BYPASS, + O_QUEUE_CPU_FANOUT, + F_QUEUE_NUM = 1 << O_QUEUE_NUM, + F_QUEUE_BALANCE = 1 << O_QUEUE_BALANCE, + F_QUEUE_CPU_FANOUT = 1 << O_QUEUE_CPU_FANOUT, +}; + static void NFQUEUE_help(void) { printf( @@ -30,94 +35,85 @@ static void NFQUEUE_help_v1(void) " --queue-balance first:last Balance flows between queues <value> to <value>.\n"); } -static const struct option NFQUEUE_opts[] = { - { "queue-num", 1, NULL, 'F' }, - { "queue-balance", 1, NULL, 'B' }, - { .name = NULL } -}; - -static void exit_badqueue(const char *s) +static void NFQUEUE_help_v2(void) { - xtables_error(PARAMETER_PROBLEM, "Invalid queue number `%s'\n", s); + NFQUEUE_help_v1(); + printf( +" --queue-bypass Bypass Queueing if no queue instance exists.\n" +" --queue-cpu-fanout Use current CPU (no hashing)\n"); } -static void -parse_num(const char *s, struct xt_NFQ_info *tinfo) +static void NFQUEUE_help_v3(void) { - unsigned int num; + NFQUEUE_help_v2(); + printf( +" --queue-cpu-fanout Use current CPU (no hashing)\n"); +} - if (!xtables_strtoui(s, NULL, &num, 0, UINT16_MAX)) - exit_badqueue(s); +#define s struct xt_NFQ_info +static const struct xt_option_entry NFQUEUE_opts[] = { + {.name = "queue-num", .id = O_QUEUE_NUM, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, queuenum), + .excl = F_QUEUE_BALANCE}, + {.name = "queue-balance", .id = O_QUEUE_BALANCE, + .type = XTTYPE_UINT16RC, .excl = F_QUEUE_NUM}, + {.name = "queue-bypass", .id = O_QUEUE_BYPASS, .type = XTTYPE_NONE}, + {.name = "queue-cpu-fanout", .id = O_QUEUE_CPU_FANOUT, + .type = XTTYPE_NONE, .also = F_QUEUE_BALANCE}, + XTOPT_TABLEEND, +}; +#undef s - tinfo->queuenum = num; +static void NFQUEUE_parse(struct xt_option_call *cb) +{ + xtables_option_parse(cb); + if (cb->entry->id == O_QUEUE_BALANCE) + xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: " + "--queue-balance not supported (kernel too old?)"); } -static int -NFQUEUE_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void NFQUEUE_parse_v1(struct xt_option_call *cb) { - struct xt_NFQ_info *tinfo - = (struct xt_NFQ_info *)(*target)->data; + struct xt_NFQ_info_v1 *info = cb->data; + const uint16_t *r = cb->val.u16_range; - switch (c) { - case 'F': - if (*flags) - xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: " - "Only use --queue-num ONCE!"); - parse_num(optarg, tinfo); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_QUEUE_BALANCE: + if (cb->nvals != 2) + xtables_error(PARAMETER_PROBLEM, + "Bad range \"%s\"", cb->arg); + if (r[0] >= r[1]) + xtables_error(PARAMETER_PROBLEM, "%u should be less than %u", + r[0], r[1]); + info->queuenum = r[0]; + info->queues_total = r[1] - r[0] + 1; break; - case 'B': - xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: " - "--queue-balance not supported (kernel too old?)"); - default: - return 0; } - - return 1; } -static int -NFQUEUE_parse_v1(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void NFQUEUE_parse_v2(struct xt_option_call *cb) { - struct xt_NFQ_info_v1 *info = (void *)(*target)->data; - char *colon; - unsigned int firstqueue, lastqueue; - - switch (c) { - case 'F': /* fallthrough */ - case 'B': - if (*flags) - xtables_error(PARAMETER_PROBLEM, "NFQUEUE target: " - "Only use --queue-num ONCE!"); - - if (!xtables_strtoui(optarg, &colon, &firstqueue, 0, UINT16_MAX)) - exit_badqueue(optarg); - - info->queuenum = firstqueue; + struct xt_NFQ_info_v2 *info = cb->data; - if (c == 'F') { - if (*colon) - exit_badqueue(optarg); - break; - } - - if (*colon != ':') - xtables_error(PARAMETER_PROBLEM, "Bad range \"%s\"", optarg); + NFQUEUE_parse_v1(cb); + switch (cb->entry->id) { + case O_QUEUE_BYPASS: + info->bypass = 1; + break; + } +} - if (!xtables_strtoui(colon + 1, NULL, &lastqueue, 1, UINT16_MAX)) - exit_badqueue(optarg); +static void NFQUEUE_parse_v3(struct xt_option_call *cb) +{ + struct xt_NFQ_info_v3 *info = cb->data; - if (firstqueue >= lastqueue) - xtables_error(PARAMETER_PROBLEM, "%u should be less than %u", - firstqueue, lastqueue); - info->queues_total = lastqueue - firstqueue + 1; + NFQUEUE_parse_v2(cb); + switch (cb->entry->id) { + case O_QUEUE_CPU_FANOUT: + info->flags |= NFQ_FLAG_CPU_FANOUT; break; - default: - return 0; } - - return 1; } static void NFQUEUE_print(const void *ip, @@ -125,7 +121,7 @@ static void NFQUEUE_print(const void *ip, { const struct xt_NFQ_info *tinfo = (const struct xt_NFQ_info *)target->data; - printf("NFQUEUE num %u", tinfo->queuenum); + printf(" NFQUEUE num %u", tinfo->queuenum); } static void NFQUEUE_print_v1(const void *ip, @@ -136,18 +132,38 @@ static void NFQUEUE_print_v1(const void *ip, if (last > 1) { last += tinfo->queuenum - 1; - printf("NFQUEUE balance %u:%u", tinfo->queuenum, last); + printf(" NFQUEUE balance %u:%u", tinfo->queuenum, last); } else { - printf("NFQUEUE num %u", tinfo->queuenum); + printf(" NFQUEUE num %u", tinfo->queuenum); } } +static void NFQUEUE_print_v2(const void *ip, + const struct xt_entry_target *target, int numeric) +{ + const struct xt_NFQ_info_v2 *info = (void *) target->data; + + NFQUEUE_print_v1(ip, target, numeric); + if (info->bypass & NFQ_FLAG_BYPASS) + printf(" bypass"); +} + +static void NFQUEUE_print_v3(const void *ip, + const struct xt_entry_target *target, int numeric) +{ + const struct xt_NFQ_info_v3 *info = (void *)target->data; + + NFQUEUE_print_v2(ip, target, numeric); + if (info->flags & NFQ_FLAG_CPU_FANOUT) + printf(" cpu-fanout"); +} + static void NFQUEUE_save(const void *ip, const struct xt_entry_target *target) { const struct xt_NFQ_info *tinfo = (const struct xt_NFQ_info *)target->data; - printf("--queue-num %u ", tinfo->queuenum); + printf(" --queue-num %u", tinfo->queuenum); } static void NFQUEUE_save_v1(const void *ip, const struct xt_entry_target *target) @@ -157,32 +173,51 @@ static void NFQUEUE_save_v1(const void *ip, const struct xt_entry_target *target if (last > 1) { last += tinfo->queuenum - 1; - printf("--queue-balance %u:%u ", tinfo->queuenum, last); + printf(" --queue-balance %u:%u", tinfo->queuenum, last); } else { - printf("--queue-num %u ", tinfo->queuenum); + printf(" --queue-num %u", tinfo->queuenum); } } +static void NFQUEUE_save_v2(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_NFQ_info_v2 *info = (void *) target->data; + + NFQUEUE_save_v1(ip, target); + + if (info->bypass & NFQ_FLAG_BYPASS) + printf(" --queue-bypass"); +} + +static void NFQUEUE_save_v3(const void *ip, + const struct xt_entry_target *target) +{ + const struct xt_NFQ_info_v3 *info = (void *)target->data; + + NFQUEUE_save_v2(ip, target); + if (info->flags & NFQ_FLAG_CPU_FANOUT) + printf(" --queue-cpu-fanout"); +} + static void NFQUEUE_init_v1(struct xt_entry_target *t) { struct xt_NFQ_info_v1 *tinfo = (void *)t->data; tinfo->queues_total = 1; } -static struct xtables_target nfqueue_target = { +static struct xtables_target nfqueue_targets[] = { +{ .family = NFPROTO_UNSPEC, .name = "NFQUEUE", .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_NFQ_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info)), .help = NFQUEUE_help, - .parse = NFQUEUE_parse, .print = NFQUEUE_print, .save = NFQUEUE_save, - .extra_opts = NFQUEUE_opts -}; - -static struct xtables_target nfqueue_target_v1 = { + .x6_parse = NFQUEUE_parse, + .x6_options = NFQUEUE_opts +},{ .family = NFPROTO_UNSPEC, .revision = 1, .name = "NFQUEUE", @@ -191,14 +226,40 @@ static struct xtables_target nfqueue_target_v1 = { .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v1)), .help = NFQUEUE_help_v1, .init = NFQUEUE_init_v1, - .parse = NFQUEUE_parse_v1, .print = NFQUEUE_print_v1, .save = NFQUEUE_save_v1, - .extra_opts = NFQUEUE_opts, + .x6_parse = NFQUEUE_parse_v1, + .x6_options = NFQUEUE_opts, +},{ + .family = NFPROTO_UNSPEC, + .revision = 2, + .name = "NFQUEUE", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_NFQ_info_v2)), + .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v2)), + .help = NFQUEUE_help_v2, + .init = NFQUEUE_init_v1, + .print = NFQUEUE_print_v2, + .save = NFQUEUE_save_v2, + .x6_parse = NFQUEUE_parse_v2, + .x6_options = NFQUEUE_opts, +},{ + .family = NFPROTO_UNSPEC, + .revision = 3, + .name = "NFQUEUE", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_NFQ_info_v3)), + .userspacesize = XT_ALIGN(sizeof(struct xt_NFQ_info_v3)), + .help = NFQUEUE_help_v3, + .init = NFQUEUE_init_v1, + .print = NFQUEUE_print_v3, + .save = NFQUEUE_save_v3, + .x6_parse = NFQUEUE_parse_v3, + .x6_options = NFQUEUE_opts, +} }; void _init(void) { - xtables_register_target(&nfqueue_target); - xtables_register_target(&nfqueue_target_v1); + xtables_register_targets(nfqueue_targets, ARRAY_SIZE(nfqueue_targets)); } diff --git a/extensions/libxt_NFQUEUE.man b/extensions/libxt_NFQUEUE.man index 59eddfc..1bfb7b8 100644 --- a/extensions/libxt_NFQUEUE.man +++ b/extensions/libxt_NFQUEUE.man @@ -1,11 +1,13 @@ -This target is an extension of the QUEUE target. As opposed to QUEUE, it allows -you to put a packet into any specific queue, identified by its 16-bit queue -number. -It can only be used with Kernel versions 2.6.14 or later, since it requires -the +This target passes the packet to userspace using the +\fBnfnetlink_queue\fP handler. The packet is put into the queue +identified by its 16-bit queue number. Userspace can inspect +and modify the packet if desired. Userspace must then drop or +reinject the packet into the kernel. Please see libnetfilter_queue +for details. .B nfnetlink_queue -kernel support. The \fBqueue-balance\fP option was added in Linux 2.6.31. +was added in Linux 2.6.14. The \fBqueue-balance\fP option was added in Linux 2.6.31, +\fBqueue-bypass\fP in 2.6.39. .TP \fB\-\-queue\-num\fP \fIvalue\fP This specifies the QUEUE number to use. Valid queue numbers are 0 to 65535. The default value is 0. @@ -16,3 +18,16 @@ This specifies a range of queues to use. Packets are then balanced across the gi This is useful for multicore systems: start multiple instances of the userspace program on queues x, x+1, .. x+n and use "\-\-queue\-balance \fIx\fP\fB:\fP\fIx+n\fP". Packets belonging to the same connection are put into the same nfqueue. +.PP +.TP +\fB\-\-queue\-bypass\fP +By default, if no userspace program is listening on an NFQUEUE, then all packets that are to be queued +are dropped. When this option is used, the NFQUEUE rule behaves like ACCEPT instead, and the packet +will move on to the next table. +.PP +.TP +\fB\-\-queue\-cpu-fanout\fP +Available starting Linux kernel 3.10. When used together with +\fB--queue-balance\fP this will use the CPU ID as an index to map packets to +the queues. The idea is that you can improve performance if there's a queue +per CPU. This requires \fB--queue-balance\fP to be specified. diff --git a/extensions/libxt_NOTRACK.c b/extensions/libxt_NOTRACK.c deleted file mode 100644 index ca58700..0000000 --- a/extensions/libxt_NOTRACK.c +++ /dev/null @@ -1,15 +0,0 @@ -/* Shared library add-on to iptables to add NOTRACK target support. */ -#include <xtables.h> - -static struct xtables_target notrack_target = { - .family = NFPROTO_UNSPEC, - .name = "NOTRACK", - .version = XTABLES_VERSION, - .size = XT_ALIGN(0), - .userspacesize = XT_ALIGN(0), -}; - -void _init(void) -{ - xtables_register_target(¬rack_target); -} diff --git a/extensions/libxt_NOTRACK.man b/extensions/libxt_NOTRACK.man index c2cdf5a..4302b93 100644 --- a/extensions/libxt_NOTRACK.man +++ b/extensions/libxt_NOTRACK.man @@ -1,5 +1,3 @@ -This target disables connection tracking for all packets matching that rule. -.PP -It can only be used in the -.B raw -table. +This extension disables connection tracking for all packets matching that rule. +It is equivalent with \-j CT \-\-notrack. Like CT, NOTRACK can only be used in +the \fBraw\fP table. diff --git a/extensions/libxt_RATEEST.c b/extensions/libxt_RATEEST.c index 4b7831f..449ceab 100644 --- a/extensions/libxt_RATEEST.c +++ b/extensions/libxt_RATEEST.c @@ -1,18 +1,20 @@ +/* + * Copyright (c) 2008-2013 Patrick McHardy <kaber@trash.net> + */ + #include <stdio.h> #include <string.h> #include <stdlib.h> -#include <stddef.h> -#include <getopt.h> #include <math.h> #include <xtables.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_RATEEST.h> -/* hack to pass raw values to final_check */ -static struct xt_rateest_target_info *RATEEST_info; -static unsigned int interval; -static unsigned int ewma_log; +struct rateest_tg_udata { + unsigned int interval; + unsigned int ewma_log; +}; static void RATEEST_help(void) @@ -24,18 +26,23 @@ RATEEST_help(void) " --rateest-ewmalog value Rate measurement averaging time constant\n"); } -enum RATEEST_options { - RATEEST_OPT_NAME, - RATEEST_OPT_INTERVAL, - RATEEST_OPT_EWMALOG, +enum { + O_NAME = 0, + O_INTERVAL, + O_EWMALOG, }; -static const struct option RATEEST_opts[] = { - { "rateest-name", 1, NULL, RATEEST_OPT_NAME }, - { "rateest-interval", 1, NULL, RATEEST_OPT_INTERVAL }, - { "rateest-ewmalog", 1, NULL, RATEEST_OPT_EWMALOG }, - { .name = NULL }, +#define s struct xt_rateest_target_info +static const struct xt_option_entry RATEEST_opts[] = { + {.name = "rateest-name", .id = O_NAME, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name)}, + {.name = "rateest-interval", .id = O_INTERVAL, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "rateest-ewmalog", .id = O_EWMALOG, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + XTOPT_TABLEEND, }; +#undef s /* Copied from iproute */ #define TIME_UNITS_PER_SEC 1000000 @@ -74,83 +81,41 @@ RATEEST_print_time(unsigned int time) double tmp = time; if (tmp >= TIME_UNITS_PER_SEC) - printf("%.1fs ", tmp/TIME_UNITS_PER_SEC); + printf(" %.1fs", tmp / TIME_UNITS_PER_SEC); else if (tmp >= TIME_UNITS_PER_SEC/1000) - printf("%.1fms ", tmp/(TIME_UNITS_PER_SEC/1000)); + printf(" %.1fms", tmp / (TIME_UNITS_PER_SEC / 1000)); else - printf("%uus ", time); -} - -static void -RATEEST_init(struct xt_entry_target *target) -{ - interval = 0; - ewma_log = 0; + printf(" %uus", time); } -static int -RATEEST_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void RATEEST_parse(struct xt_option_call *cb) { - struct xt_rateest_target_info *info = (void *)(*target)->data; - - RATEEST_info = info; + struct rateest_tg_udata *udata = cb->udata; - switch (c) { - case RATEEST_OPT_NAME: - if (*flags & (1 << c)) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_INTERVAL: + if (RATEEST_get_time(&udata->interval, cb->arg) < 0) xtables_error(PARAMETER_PROBLEM, - "RATEEST: can't specify --rateest-name twice"); - *flags |= 1 << c; - - strncpy(info->name, optarg, sizeof(info->name) - 1); + "RATEEST: bad interval value \"%s\"", + cb->arg); break; - - case RATEEST_OPT_INTERVAL: - if (*flags & (1 << c)) - xtables_error(PARAMETER_PROBLEM, - "RATEEST: can't specify --rateest-interval twice"); - *flags |= 1 << c; - - if (RATEEST_get_time(&interval, optarg) < 0) + case O_EWMALOG: + if (RATEEST_get_time(&udata->ewma_log, cb->arg) < 0) xtables_error(PARAMETER_PROBLEM, - "RATEEST: bad interval value `%s'", optarg); - + "RATEEST: bad ewmalog value \"%s\"", + cb->arg); break; - - case RATEEST_OPT_EWMALOG: - if (*flags & (1 << c)) - xtables_error(PARAMETER_PROBLEM, - "RATEEST: can't specify --rateest-ewmalog twice"); - *flags |= 1 << c; - - if (RATEEST_get_time(&ewma_log, optarg) < 0) - xtables_error(PARAMETER_PROBLEM, - "RATEEST: bad ewmalog value `%s'", optarg); - - break; - - default: - return 0; } - - return 1; } -static void -RATEEST_final_check(unsigned int flags) +static void RATEEST_final_check(struct xt_fcheck_call *cb) { - struct xt_rateest_target_info *info = RATEEST_info; - - if (!(flags & (1 << RATEEST_OPT_NAME))) - xtables_error(PARAMETER_PROBLEM, "RATEEST: no name specified"); - if (!(flags & (1 << RATEEST_OPT_INTERVAL))) - xtables_error(PARAMETER_PROBLEM, "RATEEST: no interval specified"); - if (!(flags & (1 << RATEEST_OPT_EWMALOG))) - xtables_error(PARAMETER_PROBLEM, "RATEEST: no ewmalog specified"); + struct xt_rateest_target_info *info = cb->data; + struct rateest_tg_udata *udata = cb->udata; for (info->interval = 0; info->interval <= 5; info->interval++) { - if (interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4)) + if (udata->interval <= (1 << info->interval) * (TIME_UNITS_PER_SEC / 4)) break; } @@ -161,7 +126,7 @@ RATEEST_final_check(unsigned int flags) for (info->ewma_log = 1; info->ewma_log < 32; info->ewma_log++) { double w = 1.0 - 1.0 / (1 << info->ewma_log); - if (interval / (-log(w)) > ewma_log) + if (udata->interval / (-log(w)) > udata->ewma_log) break; } info->ewma_log--; @@ -181,10 +146,10 @@ __RATEEST_print(const struct xt_entry_target *target, const char *prefix) local_interval = (TIME_UNITS_PER_SEC << (info->interval + 2)) / 4; local_ewma_log = local_interval * (1 << (info->ewma_log)); - printf("%sname %s ", prefix, info->name); - printf("%sinterval ", prefix); + printf(" %sname %s", prefix, info->name); + printf(" %sinterval", prefix); RATEEST_print_time(local_interval); - printf("%sewmalog ", prefix); + printf(" %sewmalog", prefix); RATEEST_print_time(local_ewma_log); } @@ -206,14 +171,14 @@ static struct xtables_target rateest_tg_reg = { .name = "RATEEST", .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_rateest_target_info)), - .userspacesize = XT_ALIGN(sizeof(struct xt_rateest_target_info)), + .userspacesize = offsetof(struct xt_rateest_target_info, est), .help = RATEEST_help, - .init = RATEEST_init, - .parse = RATEEST_parse, - .final_check = RATEEST_final_check, + .x6_parse = RATEEST_parse, + .x6_fcheck = RATEEST_final_check, .print = RATEEST_print, .save = RATEEST_save, - .extra_opts = RATEEST_opts, + .x6_options = RATEEST_opts, + .udata_size = sizeof(struct rateest_tg_udata), }; void _init(void) diff --git a/extensions/libipt_REDIRECT.man b/extensions/libxt_REDIRECT.man index 90ab19d..3400a6d 100644 --- a/extensions/libipt_REDIRECT.man +++ b/extensions/libxt_REDIRECT.man @@ -7,19 +7,18 @@ and chains, and user-defined chains which are only called from those chains. It redirects the packet to the machine itself by changing the destination IP to the primary address of the incoming interface -(locally-generated packets are mapped to the 127.0.0.1 address). +(locally-generated packets are mapped to the localhost address, +127.0.0.1 for IPv4 and ::1 for IPv6). .TP \fB\-\-to\-ports\fP \fIport\fP[\fB\-\fP\fIport\fP] This specifies a destination port or range of ports to use: without this, the destination port is never altered. This is only valid -if the rule also specifies -\fB\-p tcp\fP -or -\fB\-p udp\fP. +if the rule also specifies one of the following protocols: +\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. .TP \fB\-\-random\fP If option \fB\-\-random\fP is used then port mapping will be randomized (kernel >= 2.6.22). -.RS -.PP +.TP +IPv6 support available starting Linux kernels >= 3.7. diff --git a/extensions/libxt_SECMARK.c b/extensions/libxt_SECMARK.c index 2152b6f..6ba8606 100644 --- a/extensions/libxt_SECMARK.c +++ b/extensions/libxt_SECMARK.c @@ -6,14 +6,15 @@ * Copyright (C) 2006 Red Hat, Inc., James Morris <jmorris@redhat.com> */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter/xt_SECMARK.h> #define PFX "SECMARK target: " +enum { + O_SELCTX = 0, +}; + static void SECMARK_help(void) { printf( @@ -21,51 +22,26 @@ static void SECMARK_help(void) " --selctx value Set the SELinux security context\n"); } -static const struct option SECMARK_opts[] = { - { "selctx", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry SECMARK_opts[] = { + {.name = "selctx", .id = O_SELCTX, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, + XTOPT_POINTER(struct xt_secmark_target_info, secctx)}, + XTOPT_TABLEEND, }; -static int SECMARK_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void SECMARK_parse(struct xt_option_call *cb) { - struct xt_secmark_target_info *info = - (struct xt_secmark_target_info*)(*target)->data; - - switch (c) { - case '1': - if (*flags & SECMARK_MODE_SEL) - xtables_error(PARAMETER_PROBLEM, PFX - "Can't specify --selctx twice"); - info->mode = SECMARK_MODE_SEL; + struct xt_secmark_target_info *info = cb->data; - if (strlen(optarg) > SECMARK_SELCTX_MAX-1) - xtables_error(PARAMETER_PROBLEM, PFX - "Maximum length %u exceeded by --selctx" - " parameter (%zu)", - SECMARK_SELCTX_MAX-1, strlen(optarg)); - - strcpy(info->u.sel.selctx, optarg); - *flags |= SECMARK_MODE_SEL; - break; - default: - return 0; - } - - return 1; -} - -static void SECMARK_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, PFX "parameter required"); + xtables_option_parse(cb); + info->mode = SECMARK_MODE_SEL; } static void print_secmark(const struct xt_secmark_target_info *info) { switch (info->mode) { case SECMARK_MODE_SEL: - printf("selctx %s ", info->u.sel.selctx);\ + printf("selctx %s", info->secctx); break; default: @@ -79,7 +55,7 @@ static void SECMARK_print(const void *ip, const struct xt_entry_target *target, const struct xt_secmark_target_info *info = (struct xt_secmark_target_info*)(target)->data; - printf("SECMARK "); + printf(" SECMARK "); print_secmark(info); } @@ -88,7 +64,7 @@ static void SECMARK_save(const void *ip, const struct xt_entry_target *target) const struct xt_secmark_target_info *info = (struct xt_secmark_target_info*)target->data; - printf("--"); + printf(" --"); print_secmark(info); } @@ -100,11 +76,10 @@ static struct xtables_target secmark_target = { .size = XT_ALIGN(sizeof(struct xt_secmark_target_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_secmark_target_info)), .help = SECMARK_help, - .parse = SECMARK_parse, - .final_check = SECMARK_check, .print = SECMARK_print, .save = SECMARK_save, - .extra_opts = SECMARK_opts, + .x6_parse = SECMARK_parse, + .x6_options = SECMARK_opts, }; void _init(void) diff --git a/extensions/libxt_SECMARK.man b/extensions/libxt_SECMARK.man index e44efce..d0e6fd6 100644 --- a/extensions/libxt_SECMARK.man +++ b/extensions/libxt_SECMARK.man @@ -1,7 +1,10 @@ This is used to set the security mark value associated with the -packet for use by security subsystems such as SELinux. It is only +packet for use by security subsystems such as SELinux. It is +valid in the +.B security +table (for backwards compatibility with older kernels, it is also valid in the .B mangle -table. The mark is 32 bits wide. +table). The mark is 32 bits wide. .TP \fB\-\-selctx\fP \fIsecurity_context\fP diff --git a/extensions/libxt_SET.c b/extensions/libxt_SET.c index f6386a9..a11db39 100644 --- a/extensions/libxt_SET.c +++ b/extensions/libxt_SET.c @@ -9,6 +9,7 @@ */ /* Shared library add-on to iptables to add IP set mangling target. */ +#include <stdbool.h> #include <stdio.h> #include <netdb.h> #include <string.h> @@ -20,8 +21,10 @@ #include <linux/netfilter/xt_set.h> #include "libxt_set.h" +/* Revision 0 */ + static void -set_target_help(void) +set_target_help_v0(void) { printf("SET target options:\n" " --add-set name flags\n" @@ -31,14 +34,14 @@ set_target_help(void) " 'src' and 'dst' specifications.\n"); } -static const struct option set_target_opts[] = { - { .name = "add-set", .has_arg = true, .val = '1'}, - { .name = "del-set", .has_arg = true, .val = '2'}, - { .name = NULL } +static const struct option set_target_opts_v0[] = { + {.name = "add-set", .has_arg = true, .val = '1'}, + {.name = "del-set", .has_arg = true, .val = '2'}, + XT_GETOPT_TABLEEND, }; static void -set_target_check(unsigned int flags) +set_target_check_v0(unsigned int flags) { if (!flags) xtables_error(PARAMETER_PROBLEM, @@ -64,10 +67,6 @@ parse_target_v0(char **argv, int invert, unsigned int *flags, xtables_error(PARAMETER_PROBLEM, "--%s can be specified only once", what); - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --%s", what); - if (!argv[optind] || argv[optind][0] == '-' || argv[optind][0] == '!') xtables_error(PARAMETER_PROBLEM, @@ -101,9 +100,6 @@ set_target_parse_v0(int c, char **argv, int invert, unsigned int *flags, parse_target_v0(argv, invert, flags, &myinfo->del_set, "del-set"); break; - - default: - return 0; } return 1; } @@ -117,7 +113,7 @@ print_target_v0(const char *prefix, const struct xt_set_info_v0 *info) if (info->index == IPSET_INVALID_ID) return; get_set_byid(setname, info->index); - printf("%s %s", prefix, setname); + printf(" %s %s", prefix, setname); for (i = 0; i < IPSET_DIM_MAX; i++) { if (!info->u.flags[i]) break; @@ -125,7 +121,6 @@ print_target_v0(const char *prefix, const struct xt_set_info_v0 *info) i == 0 ? " " : ",", info->u.flags[i] & IPSET_SRC ? "src" : "dst"); } - printf(" "); } static void @@ -147,29 +142,30 @@ set_target_save_v0(const void *ip, const struct xt_entry_target *target) print_target_v0("--del-set", &info->del_set); } +/* Revision 1 */ static void -set_target_init(struct xt_entry_target *target) +set_target_init_v1(struct xt_entry_target *target) { - struct xt_set_info_target *info = - (struct xt_set_info_target *) target->data; + struct xt_set_info_target_v1 *info = + (struct xt_set_info_target_v1 *) target->data; info->add_set.index = info->del_set.index = IPSET_INVALID_ID; } +#define SET_TARGET_ADD 0x1 +#define SET_TARGET_DEL 0x2 +#define SET_TARGET_EXIST 0x4 +#define SET_TARGET_TIMEOUT 0x8 + static void -parse_target(char **argv, int invert, unsigned int *flags, - struct xt_set_info *info, const char *what) +parse_target(char **argv, int invert, struct xt_set_info *info, + const char *what) { if (info->dim) xtables_error(PARAMETER_PROBLEM, "--%s can be specified only once", what); - - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, - "Unexpected `!' after --%s", what); - if (!argv[optind] || argv[optind][0] == '-' || argv[optind][0] == '!') xtables_error(PARAMETER_PROBLEM, @@ -183,29 +179,24 @@ parse_target(char **argv, int invert, unsigned int *flags, get_set_byname(optarg, info); parse_dirs(argv[optind], info); optind++; - - *flags = 1; } static int -set_target_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +set_target_parse_v1(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) { - struct xt_set_info_target *myinfo = - (struct xt_set_info_target *) (*target)->data; + struct xt_set_info_target_v1 *myinfo = + (struct xt_set_info_target_v1 *) (*target)->data; switch (c) { case '1': /* --add-set <set> <flags> */ - parse_target(argv, invert, flags, - &myinfo->add_set, "add-set"); + parse_target(argv, invert, &myinfo->add_set, "add-set"); + *flags |= SET_TARGET_ADD; break; case '2': /* --del-set <set>[:<flags>] <flags> */ - parse_target(argv, invert, flags, - &myinfo->del_set, "del-set"); + parse_target(argv, invert, &myinfo->del_set, "del-set"); + *flags |= SET_TARGET_DEL; break; - - default: - return 0; } return 1; } @@ -219,31 +210,139 @@ print_target(const char *prefix, const struct xt_set_info *info) if (info->index == IPSET_INVALID_ID) return; get_set_byid(setname, info->index); - printf("%s %s", prefix, setname); - for (i = 1; i <= IPSET_DIM_MAX; i++) { + printf(" %s %s", prefix, setname); + for (i = 1; i <= info->dim; i++) { printf("%s%s", i == 1 ? " " : ",", info->flags & (1 << i) ? "src" : "dst"); } - printf(" "); } static void -set_target_print(const void *ip, const struct xt_entry_target *target, - int numeric) +set_target_print_v1(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct xt_set_info_target_v1 *info = (const void *)target->data; + + print_target("add-set", &info->add_set); + print_target("del-set", &info->del_set); +} + +static void +set_target_save_v1(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_set_info_target_v1 *info = (const void *)target->data; + + print_target("--add-set", &info->add_set); + print_target("--del-set", &info->del_set); +} + +/* Revision 2 */ + +static void +set_target_help_v2(void) +{ + printf("SET target options:\n" + " --add-set name flags [--exist] [--timeout n]\n" + " --del-set name flags\n" + " add/del src/dst IP/port from/to named sets,\n" + " where flags are the comma separated list of\n" + " 'src' and 'dst' specifications.\n"); +} + +static const struct option set_target_opts_v2[] = { + {.name = "add-set", .has_arg = true, .val = '1'}, + {.name = "del-set", .has_arg = true, .val = '2'}, + {.name = "exist", .has_arg = false, .val = '3'}, + {.name = "timeout", .has_arg = true, .val = '4'}, + XT_GETOPT_TABLEEND, +}; + +static void +set_target_check_v2(unsigned int flags) +{ + if (!(flags & (SET_TARGET_ADD|SET_TARGET_DEL))) + xtables_error(PARAMETER_PROBLEM, + "You must specify either `--add-set' or `--del-set'"); + if (!(flags & SET_TARGET_ADD)) { + if (flags & SET_TARGET_EXIST) + xtables_error(PARAMETER_PROBLEM, + "Flag `--exist' can be used with `--add-set' only"); + if (flags & SET_TARGET_TIMEOUT) + xtables_error(PARAMETER_PROBLEM, + "Option `--timeout' can be used with `--add-set' only"); + } +} + + +static void +set_target_init_v2(struct xt_entry_target *target) +{ + struct xt_set_info_target_v2 *info = + (struct xt_set_info_target_v2 *) target->data; + + info->add_set.index = + info->del_set.index = IPSET_INVALID_ID; + info->timeout = UINT32_MAX; +} + +static int +set_target_parse_v2(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_target **target) +{ + struct xt_set_info_target_v2 *myinfo = + (struct xt_set_info_target_v2 *) (*target)->data; + unsigned int timeout; + + switch (c) { + case '1': /* --add-set <set> <flags> */ + parse_target(argv, invert, &myinfo->add_set, "add-set"); + *flags |= SET_TARGET_ADD; + break; + case '2': /* --del-set <set>[:<flags>] <flags> */ + parse_target(argv, invert, &myinfo->del_set, "del-set"); + *flags |= SET_TARGET_DEL; + break; + case '3': + myinfo->flags |= IPSET_FLAG_EXIST; + *flags |= SET_TARGET_EXIST; + break; + case '4': + if (!xtables_strtoui(optarg, NULL, &timeout, 0, UINT32_MAX - 1)) + xtables_error(PARAMETER_PROBLEM, + "Invalid value for option --timeout " + "or out of range 0-%u", UINT32_MAX - 1); + myinfo->timeout = timeout; + *flags |= SET_TARGET_TIMEOUT; + break; + } + return 1; +} + +static void +set_target_print_v2(const void *ip, const struct xt_entry_target *target, + int numeric) { - const struct xt_set_info_target *info = (const void *)target->data; + const struct xt_set_info_target_v2 *info = (const void *)target->data; print_target("add-set", &info->add_set); + if (info->flags & IPSET_FLAG_EXIST) + printf(" exist"); + if (info->timeout != UINT32_MAX) + printf(" timeout %u", info->timeout); print_target("del-set", &info->del_set); } static void -set_target_save(const void *ip, const struct xt_entry_target *target) +set_target_save_v2(const void *ip, const struct xt_entry_target *target) { - const struct xt_set_info_target *info = (const void *)target->data; + const struct xt_set_info_target_v2 *info = (const void *)target->data; print_target("--add-set", &info->add_set); + if (info->flags & IPSET_FLAG_EXIST) + printf(" --exist"); + if (info->timeout != UINT32_MAX) + printf(" --timeout %u", info->timeout); print_target("--del-set", &info->del_set); } @@ -255,28 +354,43 @@ static struct xtables_target set_tg_reg[] = { .family = NFPROTO_IPV4, .size = XT_ALIGN(sizeof(struct xt_set_info_target_v0)), .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v0)), - .help = set_target_help, + .help = set_target_help_v0, .init = set_target_init_v0, .parse = set_target_parse_v0, - .final_check = set_target_check, + .final_check = set_target_check_v0, .print = set_target_print_v0, .save = set_target_save_v0, - .extra_opts = set_target_opts, + .extra_opts = set_target_opts_v0, }, { .name = "SET", .revision = 1, .version = XTABLES_VERSION, .family = NFPROTO_UNSPEC, - .size = XT_ALIGN(sizeof(struct xt_set_info_target)), - .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target)), - .help = set_target_help, - .init = set_target_init, - .parse = set_target_parse, - .final_check = set_target_check, - .print = set_target_print, - .save = set_target_save, - .extra_opts = set_target_opts, + .size = XT_ALIGN(sizeof(struct xt_set_info_target_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v1)), + .help = set_target_help_v0, + .init = set_target_init_v1, + .parse = set_target_parse_v1, + .final_check = set_target_check_v0, + .print = set_target_print_v1, + .save = set_target_save_v1, + .extra_opts = set_target_opts_v0, + }, + { + .name = "SET", + .revision = 2, + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_set_info_target_v2)), + .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_target_v2)), + .help = set_target_help_v2, + .init = set_target_init_v2, + .parse = set_target_parse_v2, + .final_check = set_target_check_v2, + .print = set_target_print_v2, + .save = set_target_save_v2, + .extra_opts = set_target_opts_v2, }, }; diff --git a/extensions/libxt_SET.man b/extensions/libxt_SET.man index ea80c2a..c35ba93 100644 --- a/extensions/libxt_SET.man +++ b/extensions/libxt_SET.man @@ -1,18 +1,25 @@ -This modules adds and/or deletes entries from IP sets which can be defined +This module adds and/or deletes entries from IP sets which can be defined by ipset(8). .TP \fB\-\-add\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...] -add the address(es)/port(s) of the packet to the sets +add the address(es)/port(s) of the packet to the set .TP \fB\-\-del\-set\fP \fIsetname\fP \fIflag\fP[\fB,\fP\fIflag\fP...] -delete the address(es)/port(s) of the packet from the sets +delete the address(es)/port(s) of the packet from the set .IP -where flags are +where \fIflag\fP(s) are .BR "src" and/or .BR "dst" specifications and there can be no more than six of them. +.TP +\fB\-\-timeout\fP \fIvalue\fP +when adding an entry, the timeout value to use instead of the default +one from the set definition +.TP +\fB\-\-exist\fP +when adding an entry if it already exists, reset the timeout value +to the specified one or to the default from the set definition .PP -Use of -j SET requires that ipset kernel support is provided. As standard -kernels do not ship this currently, the ipset or Xtables-addons package needs -to be installed. +Use of -j SET requires that ipset kernel support is provided, which, for +standard kernels, is the case since Linux 2.6.39. diff --git a/extensions/libipt_SNAT.man b/extensions/libxt_SNAT.man index 6b828fd..f0620a2 100644 --- a/extensions/libipt_SNAT.man +++ b/extensions/libxt_SNAT.man @@ -2,23 +2,23 @@ This target is only valid in the .B nat table, in the .B POSTROUTING -chain. It specifies that the source address of the packet should be +and +.B INPUT +chains, and user-defined chains which are only called from those +chains. It specifies that the source address of the packet should be modified (and all future packets in this connection will also be -mangled), and rules should cease being examined. It takes one type -of option: +mangled), and rules should cease being examined. It takes the +following options: .TP -\fB\-\-to\-source\fP \fIipaddr\fP[\fB\-\fP\fIipaddr\fP][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]] +\fB\-\-to\-source\fP [\fIipaddr\fP[\fB\-\fP\fIipaddr\fP]][\fB:\fP\fIport\fP[\fB\-\fP\fIport\fP]] which can specify a single new source IP address, an inclusive range -of IP addresses, and optionally, a port range (which is only valid if -the rule also specifies -\fB\-p tcp\fP -or -\fB\-p udp\fP). +of IP addresses. Optionally a port range, +if the rule also specifies one of the following protocols: +\fBtcp\fP, \fBudp\fP, \fBdccp\fP or \fBsctp\fP. If no port range is specified, then source ports below 512 will be mapped to other ports below 512: those between 512 and 1023 inclusive will be mapped to ports below 1024, and other ports will be mapped to -1024 or above. Where possible, no port alteration will - +1024 or above. Where possible, no port alteration will occur. In Kernels up to 2.6.10, you can add several \-\-to\-source options. For those kernels, if you specify more than one source address, either via an address range or multiple \-\-to\-source options, a simple round-robin (one after another @@ -35,3 +35,11 @@ is used then port mapping will be randomized (kernel >= 2.6.21). Gives a client the same source-/destination-address for each connection. This supersedes the SAME target. Support for persistent mappings is available from 2.6.29-rc2. +.PP +Kernels prior to 2.6.36-rc1 don't have the ability to +.B SNAT +in the +.B INPUT +chain. +.TP +IPv6 support available since Linux kernels >= 3.7. diff --git a/extensions/libxt_SYNPROXY.c b/extensions/libxt_SYNPROXY.c new file mode 100644 index 0000000..475590e --- /dev/null +++ b/extensions/libxt_SYNPROXY.c @@ -0,0 +1,127 @@ + +/* + * Copyright (c) 2013 Patrick McHardy <kaber@trash.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <stdbool.h> +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter/xt_SYNPROXY.h> + +enum { + O_SACK_PERM = 0, + O_TIMESTAMP, + O_WSCALE, + O_MSS, + O_ECN, +}; + +static void SYNPROXY_help(void) +{ + printf( +"SYNPROXY target options:\n" +" --sack-perm Set SACK_PERM\n" +" --timestamp Set TIMESTAMP\n" +" --wscale value Set window scaling factor\n" +" --mss value Set MSS value\n" +" --ecn Set ECN\n"); +} + +static const struct xt_option_entry SYNPROXY_opts[] = { + {.name = "sack-perm", .id = O_SACK_PERM, .type = XTTYPE_NONE, }, + {.name = "timestamp", .id = O_TIMESTAMP, .type = XTTYPE_NONE, }, + {.name = "wscale", .id = O_WSCALE, .type = XTTYPE_UINT32, }, + {.name = "mss", .id = O_MSS, .type = XTTYPE_UINT32, }, + {.name = "ecn", .id = O_ECN, .type = XTTYPE_NONE, }, + XTOPT_TABLEEND, +}; + +static void SYNPROXY_parse(struct xt_option_call *cb) +{ + struct xt_synproxy_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SACK_PERM: + info->options |= XT_SYNPROXY_OPT_SACK_PERM; + break; + case O_TIMESTAMP: + info->options |= XT_SYNPROXY_OPT_TIMESTAMP; + break; + case O_WSCALE: + info->options |= XT_SYNPROXY_OPT_WSCALE; + info->wscale = cb->val.u32; + break; + case O_MSS: + info->options |= XT_SYNPROXY_OPT_MSS; + info->mss = cb->val.u32; + break; + case O_ECN: + info->options |= XT_SYNPROXY_OPT_ECN; + break; + } +} + +static void SYNPROXY_check(struct xt_fcheck_call *cb) +{ +} + +static void SYNPROXY_print(const void *ip, const struct xt_entry_target *target, + int numeric) +{ + const struct xt_synproxy_info *info = + (const struct xt_synproxy_info *)target->data; + + printf(" SYNPROXY "); + if (info->options & XT_SYNPROXY_OPT_SACK_PERM) + printf("sack-perm "); + if (info->options & XT_SYNPROXY_OPT_TIMESTAMP) + printf("timestamp "); + if (info->options & XT_SYNPROXY_OPT_WSCALE) + printf("wscale %u ", info->wscale); + if (info->options & XT_SYNPROXY_OPT_MSS) + printf("mss %u ", info->mss); + if (info->options & XT_SYNPROXY_OPT_ECN) + printf("ecn "); +} + +static void SYNPROXY_save(const void *ip, const struct xt_entry_target *target) +{ + const struct xt_synproxy_info *info = + (const struct xt_synproxy_info *)target->data; + + if (info->options & XT_SYNPROXY_OPT_SACK_PERM) + printf(" --sack-perm"); + if (info->options & XT_SYNPROXY_OPT_TIMESTAMP) + printf(" --timestamp"); + if (info->options & XT_SYNPROXY_OPT_WSCALE) + printf(" --wscale %u", info->wscale); + if (info->options & XT_SYNPROXY_OPT_MSS) + printf(" --mss %u", info->mss); + if (info->options & XT_SYNPROXY_OPT_ECN) + printf(" --ecn"); +} + +static struct xtables_target synproxy_tg_reg = { + .family = NFPROTO_UNSPEC, + .name = "SYNPROXY", + .version = XTABLES_VERSION, + .revision = 0, + .size = XT_ALIGN(sizeof(struct xt_synproxy_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_synproxy_info)), + .help = SYNPROXY_help, + .print = SYNPROXY_print, + .save = SYNPROXY_save, + .x6_parse = SYNPROXY_parse, + .x6_fcheck = SYNPROXY_check, + .x6_options = SYNPROXY_opts, +}; + +void _init(void) +{ + xtables_register_target(&synproxy_tg_reg); +} diff --git a/extensions/libxt_TCPMSS.c b/extensions/libxt_TCPMSS.c index ac9e2d0..4b71e44 100644 --- a/extensions/libxt_TCPMSS.c +++ b/extensions/libxt_TCPMSS.c @@ -2,15 +2,17 @@ * * Copyright (c) 2000 Marc Boucher */ +#include "config.h" #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> +#include <netinet/ip.h> #include <linux/netfilter/xt_TCPMSS.h> +enum { + O_SET_MSS = 0, + O_CLAMP_MSS, +}; + struct mssinfo { struct xt_entry_target t; struct xt_tcpmss_info mss; @@ -27,72 +29,42 @@ hdrsize); static void TCPMSS_help(void) { - __TCPMSS_help(40); + __TCPMSS_help(sizeof(struct iphdr)); } static void TCPMSS_help6(void) { - __TCPMSS_help(60); + __TCPMSS_help(SIZEOF_STRUCT_IP6_HDR); } -static const struct option TCPMSS_opts[] = { - { "set-mss", 1, NULL, '1' }, - { "clamp-mss-to-pmtu", 0, NULL, '2' }, - { .name = NULL } +static const struct xt_option_entry TCPMSS4_opts[] = { + {.name = "set-mss", .id = O_SET_MSS, .type = XTTYPE_UINT16, + .min = 0, .max = UINT16_MAX - sizeof(struct iphdr), + .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_tcpmss_info, mss)}, + {.name = "clamp-mss-to-pmtu", .id = O_CLAMP_MSS, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; -static int __TCPMSS_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target, - int hdrsize) -{ - struct xt_tcpmss_info *mssinfo - = (struct xt_tcpmss_info *)(*target)->data; - - switch (c) { - unsigned int mssval; - - case '1': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "TCPMSS target: Only one option may be specified"); - if (!xtables_strtoui(optarg, NULL, &mssval, - 0, UINT16_MAX - hdrsize)) - xtables_error(PARAMETER_PROBLEM, "Bad TCPMSS value \"%s\"", optarg); - - mssinfo->mss = mssval; - *flags = 1; - break; - - case '2': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "TCPMSS target: Only one option may be specified"); - mssinfo->mss = XT_TCPMSS_CLAMP_PMTU; - *flags = 1; - break; - - default: - return 0; - } - - return 1; -} +static const struct xt_option_entry TCPMSS6_opts[] = { + {.name = "set-mss", .id = O_SET_MSS, .type = XTTYPE_UINT16, + .min = 0, .max = UINT16_MAX - SIZEOF_STRUCT_IP6_HDR, + .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_tcpmss_info, mss)}, + {.name = "clamp-mss-to-pmtu", .id = O_CLAMP_MSS, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; -static int TCPMSS_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void TCPMSS_parse(struct xt_option_call *cb) { - return __TCPMSS_parse(c, argv, invert, flags, entry, target, 40); -} + struct xt_tcpmss_info *mssinfo = cb->data; -static int TCPMSS_parse6(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) -{ - return __TCPMSS_parse(c, argv, invert, flags, entry, target, 60); + xtables_option_parse(cb); + if (cb->entry->id == O_CLAMP_MSS) + mssinfo->mss = XT_TCPMSS_CLAMP_PMTU; } -static void TCPMSS_check(unsigned int flags) +static void TCPMSS_check(struct xt_fcheck_call *cb) { - if (!flags) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "TCPMSS target: At least one parameter is required"); } @@ -103,9 +75,9 @@ static void TCPMSS_print(const void *ip, const struct xt_entry_target *target, const struct xt_tcpmss_info *mssinfo = (const struct xt_tcpmss_info *)target->data; if(mssinfo->mss == XT_TCPMSS_CLAMP_PMTU) - printf("TCPMSS clamp to PMTU "); + printf(" TCPMSS clamp to PMTU"); else - printf("TCPMSS set %u ", mssinfo->mss); + printf(" TCPMSS set %u", mssinfo->mss); } static void TCPMSS_save(const void *ip, const struct xt_entry_target *target) @@ -114,41 +86,41 @@ static void TCPMSS_save(const void *ip, const struct xt_entry_target *target) (const struct xt_tcpmss_info *)target->data; if(mssinfo->mss == XT_TCPMSS_CLAMP_PMTU) - printf("--clamp-mss-to-pmtu "); + printf(" --clamp-mss-to-pmtu"); else - printf("--set-mss %u ", mssinfo->mss); + printf(" --set-mss %u", mssinfo->mss); } -static struct xtables_target tcpmss_target = { - .family = NFPROTO_IPV4, - .name = "TCPMSS", - .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct xt_tcpmss_info)), - .userspacesize = XT_ALIGN(sizeof(struct xt_tcpmss_info)), - .help = TCPMSS_help, - .parse = TCPMSS_parse, - .final_check = TCPMSS_check, - .print = TCPMSS_print, - .save = TCPMSS_save, - .extra_opts = TCPMSS_opts, -}; - -static struct xtables_target tcpmss_target6 = { - .family = NFPROTO_IPV6, - .name = "TCPMSS", - .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct xt_tcpmss_info)), - .userspacesize = XT_ALIGN(sizeof(struct xt_tcpmss_info)), - .help = TCPMSS_help6, - .parse = TCPMSS_parse6, - .final_check = TCPMSS_check, - .print = TCPMSS_print, - .save = TCPMSS_save, - .extra_opts = TCPMSS_opts, +static struct xtables_target tcpmss_tg_reg[] = { + { + .family = NFPROTO_IPV4, + .name = "TCPMSS", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_tcpmss_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_tcpmss_info)), + .help = TCPMSS_help, + .print = TCPMSS_print, + .save = TCPMSS_save, + .x6_parse = TCPMSS_parse, + .x6_fcheck = TCPMSS_check, + .x6_options = TCPMSS4_opts, + }, + { + .family = NFPROTO_IPV6, + .name = "TCPMSS", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_tcpmss_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_tcpmss_info)), + .help = TCPMSS_help6, + .print = TCPMSS_print, + .save = TCPMSS_save, + .x6_parse = TCPMSS_parse, + .x6_fcheck = TCPMSS_check, + .x6_options = TCPMSS6_opts, + }, }; void _init(void) { - xtables_register_target(&tcpmss_target); - xtables_register_target(&tcpmss_target6); + xtables_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg)); } diff --git a/extensions/libxt_TCPMSS.man b/extensions/libxt_TCPMSS.man index ac8fb4e..8da8e76 100644 --- a/extensions/libxt_TCPMSS.man +++ b/extensions/libxt_TCPMSS.man @@ -11,19 +11,13 @@ packets. The symptoms of this problem are that everything works fine from your Linux firewall/router, but machines behind it can never exchange large packets: -.PD 0 -.RS 0.1i -.TP 0.3i -1) +.IP 1. 4 Web browsers connect, then hang with no data received. -.TP -2) +.IP 2. 4 Small mail works fine, but large emails hang. -.TP -3) +.IP 3. 4 ssh works fine, but scp hangs after initial handshaking. -.RE -.PD +.PP Workaround: activate this option and add a rule to your firewall configuration like: .IP diff --git a/extensions/libxt_TCPOPTSTRIP.c b/extensions/libxt_TCPOPTSTRIP.c index a063d0d..6897857 100644 --- a/extensions/libxt_TCPOPTSTRIP.c +++ b/extensions/libxt_TCPOPTSTRIP.c @@ -4,21 +4,17 @@ * Copyright © CC Computer Consultants GmbH, 2007 * Jan Engelhardt <jengelh@computergmbh.de> */ -#include <getopt.h> -#include <stdbool.h> #include <stdio.h> #include <string.h> -#include <stdlib.h> #include <xtables.h> #include <netinet/tcp.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_TCPOPTSTRIP.h> #ifndef TCPOPT_MD5SIG # define TCPOPT_MD5SIG 19 #endif enum { - FLAG_STRIP = 1 << 0, + O_STRIP_OPTION = 0, }; struct tcp_optionmap { @@ -26,9 +22,9 @@ struct tcp_optionmap { const unsigned int option; }; -static const struct option tcpoptstrip_tg_opts[] = { - {.name = "strip-options", .has_arg = true, .val = 's'}, - { .name = NULL } +static const struct xt_option_entry tcpoptstrip_tg_opts[] = { + {.name = "strip-options", .id = O_STRIP_OPTION, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, }; static const struct tcp_optionmap tcp_optionmap[] = { @@ -38,7 +34,7 @@ static const struct tcp_optionmap tcp_optionmap[] = { {"sack", "Selective ACK", TCPOPT_SACK}, {"timestamp", "Timestamp", TCPOPT_TIMESTAMP}, {"md5", "MD5 signature", TCPOPT_MD5SIG}, - { .name = NULL } + {NULL}, }; static void tcpoptstrip_tg_help(void) @@ -56,15 +52,8 @@ static void tcpoptstrip_tg_help(void) printf(" %-14s strip \"%s\" option\n", w->name, w->desc); } -static void tcpoptstrip_tg_init(struct xt_entry_target *t) -{ - struct xt_tcpoptstrip_target_info *info = (void *)t->data; - - /* strictly necessary? play safe for now. */ - memset(info->strip_bmap, 0, sizeof(info->strip_bmap)); -} - -static void parse_list(struct xt_tcpoptstrip_target_info *info, char *arg) +static void +parse_list(struct xt_tcpoptstrip_target_info *info, const char *arg) { unsigned int option; char *p; @@ -102,30 +91,12 @@ static void parse_list(struct xt_tcpoptstrip_target_info *info, char *arg) } } -static int tcpoptstrip_tg_parse(int c, char **argv, int invert, - unsigned int *flags, const void *entry, - struct xt_entry_target **target) +static void tcpoptstrip_tg_parse(struct xt_option_call *cb) { - struct xt_tcpoptstrip_target_info *info = (void *)(*target)->data; + struct xt_tcpoptstrip_target_info *info = cb->data; - switch (c) { - case 's': - if (*flags & FLAG_STRIP) - xtables_error(PARAMETER_PROBLEM, - "You can specify --strip-options only once"); - parse_list(info, optarg); - *flags |= FLAG_STRIP; - return true; - } - - return false; -} - -static void tcpoptstrip_tg_check(unsigned int flags) -{ - if (flags == 0) - xtables_error(PARAMETER_PROBLEM, - "TCPOPTSTRIP: --strip-options parameter required"); + xtables_option_parse(cb); + parse_list(info, cb->arg); } static void @@ -163,7 +134,7 @@ tcpoptstrip_tg_print(const void *ip, const struct xt_entry_target *target, const struct xt_tcpoptstrip_target_info *info = (const void *)target->data; - printf("TCPOPTSTRIP options "); + printf(" TCPOPTSTRIP options "); tcpoptstrip_print_list(info, numeric); } @@ -173,7 +144,7 @@ tcpoptstrip_tg_save(const void *ip, const struct xt_entry_target *target) const struct xt_tcpoptstrip_target_info *info = (const void *)target->data; - printf("--strip-options "); + printf(" --strip-options "); tcpoptstrip_print_list(info, true); } @@ -184,12 +155,10 @@ static struct xtables_target tcpoptstrip_tg_reg = { .size = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_tcpoptstrip_target_info)), .help = tcpoptstrip_tg_help, - .init = tcpoptstrip_tg_init, - .parse = tcpoptstrip_tg_parse, - .final_check = tcpoptstrip_tg_check, .print = tcpoptstrip_tg_print, .save = tcpoptstrip_tg_save, - .extra_opts = tcpoptstrip_tg_opts, + .x6_parse = tcpoptstrip_tg_parse, + .x6_options = tcpoptstrip_tg_opts, }; void _init(void) diff --git a/extensions/libxt_TEE.c b/extensions/libxt_TEE.c index e4c0607..92c7601 100644 --- a/extensions/libxt_TEE.c +++ b/extensions/libxt_TEE.c @@ -25,15 +25,19 @@ #include <linux/netfilter/xt_TEE.h> enum { - FLAG_GATEWAY = 1 << 0, - FLAG_OIF = 1 << 1, + O_GATEWAY = 0, + O_OIF, }; -static const struct option tee_tg_opts[] = { - {.name = "gateway", .has_arg = true, .val = 'g'}, - {.name = "oif", .has_arg = true, .val = 'o'}, - {NULL}, +#define s struct xt_tee_tginfo +static const struct xt_option_entry tee_tg_opts[] = { + {.name = "gateway", .id = O_GATEWAY, .type = XTTYPE_HOST, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, gw)}, + {.name = "oif", .id = O_OIF, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, oif)}, + XTOPT_TABLEEND, }; +#undef s static void tee_tg_help(void) { @@ -44,94 +48,17 @@ static void tee_tg_help(void) "\n"); } -static int tee_tg_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) -{ - struct xt_tee_tginfo *info = (void *)(*target)->data; - const struct in_addr *ia; - - switch (c) { - case 'g': - if (*flags & FLAG_GATEWAY) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --gateway more than once"); - - ia = xtables_numeric_to_ipaddr(optarg); - if (ia == NULL) - xtables_error(PARAMETER_PROBLEM, - "Invalid IP address %s", optarg); - - memcpy(&info->gw, ia, sizeof(*ia)); - *flags |= FLAG_GATEWAY; - return true; - case 'o': - if (*flags & FLAG_OIF) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --oif more than once"); - if (strlen(optarg) >= sizeof(info->oif)) - xtables_error(PARAMETER_PROBLEM, - "oif name too long"); - strcpy(info->oif, optarg); - *flags |= FLAG_OIF; - return true; - } - - return false; -} - -static int tee_tg6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) -{ - struct xt_tee_tginfo *info = (void *)(*target)->data; - const struct in6_addr *ia; - - switch (c) { - case 'g': - if (*flags & FLAG_GATEWAY) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --gateway more than once"); - - ia = xtables_numeric_to_ip6addr(optarg); - if (ia == NULL) - xtables_error(PARAMETER_PROBLEM, - "Invalid IP address %s", optarg); - - memcpy(&info->gw, ia, sizeof(*ia)); - *flags |= FLAG_GATEWAY; - return true; - case 'o': - if (*flags & FLAG_OIF) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --oif more than once"); - if (strlen(optarg) >= sizeof(info->oif)) - xtables_error(PARAMETER_PROBLEM, - "oif name too long"); - strcpy(info->oif, optarg); - *flags |= FLAG_OIF; - return true; - } - - return false; -} - -static void tee_tg_check(unsigned int flags) -{ - if (flags == 0) - xtables_error(PARAMETER_PROBLEM, "TEE target: " - "--gateway parameter required"); -} - static void tee_tg_print(const void *ip, const struct xt_entry_target *target, int numeric) { const struct xt_tee_tginfo *info = (const void *)target->data; if (numeric) - printf("TEE gw:%s ", xtables_ipaddr_to_numeric(&info->gw.in)); + printf(" TEE gw:%s", xtables_ipaddr_to_numeric(&info->gw.in)); else - printf("TEE gw:%s ", xtables_ipaddr_to_anyname(&info->gw.in)); + printf(" TEE gw:%s", xtables_ipaddr_to_anyname(&info->gw.in)); if (*info->oif != '\0') - printf("oif=%s ", info->oif); + printf(" oif=%s", info->oif); } static void tee_tg6_print(const void *ip, const struct xt_entry_target *target, @@ -140,63 +67,61 @@ static void tee_tg6_print(const void *ip, const struct xt_entry_target *target, const struct xt_tee_tginfo *info = (const void *)target->data; if (numeric) - printf("TEE gw:%s ", xtables_ip6addr_to_numeric(&info->gw.in6)); + printf(" TEE gw:%s", xtables_ip6addr_to_numeric(&info->gw.in6)); else - printf("TEE gw:%s ", xtables_ip6addr_to_anyname(&info->gw.in6)); + printf(" TEE gw:%s", xtables_ip6addr_to_anyname(&info->gw.in6)); if (*info->oif != '\0') - printf("oif=%s ", info->oif); + printf(" oif=%s", info->oif); } static void tee_tg_save(const void *ip, const struct xt_entry_target *target) { const struct xt_tee_tginfo *info = (const void *)target->data; - printf("--gateway %s ", xtables_ipaddr_to_numeric(&info->gw.in)); + printf(" --gateway %s", xtables_ipaddr_to_numeric(&info->gw.in)); if (*info->oif != '\0') - printf("--oif %s ", info->oif); + printf(" --oif %s", info->oif); } static void tee_tg6_save(const void *ip, const struct xt_entry_target *target) { const struct xt_tee_tginfo *info = (const void *)target->data; - printf("--gateway %s ", xtables_ip6addr_to_numeric(&info->gw.in6)); + printf(" --gateway %s", xtables_ip6addr_to_numeric(&info->gw.in6)); if (*info->oif != '\0') - printf("--oif %s ", info->oif); + printf(" --oif %s", info->oif); } -static struct xtables_target tee_tg_reg = { - .name = "TEE", - .version = XTABLES_VERSION, - .revision = 1, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)), - .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)), - .help = tee_tg_help, - .parse = tee_tg_parse, - .final_check = tee_tg_check, - .print = tee_tg_print, - .save = tee_tg_save, - .extra_opts = tee_tg_opts, -}; - -static struct xtables_target tee_tg6_reg = { - .name = "TEE", - .version = XTABLES_VERSION, - .revision = 1, - .family = NFPROTO_IPV6, - .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)), - .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)), - .help = tee_tg_help, - .parse = tee_tg6_parse, - .final_check = tee_tg_check, - .print = tee_tg6_print, - .save = tee_tg6_save, - .extra_opts = tee_tg_opts, +static struct xtables_target tee_tg_reg[] = { + { + .name = "TEE", + .version = XTABLES_VERSION, + .revision = 1, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)), + .help = tee_tg_help, + .print = tee_tg_print, + .save = tee_tg_save, + .x6_parse = xtables_option_parse, + .x6_options = tee_tg_opts, + }, + { + .name = "TEE", + .version = XTABLES_VERSION, + .revision = 1, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct xt_tee_tginfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_tee_tginfo)), + .help = tee_tg_help, + .print = tee_tg6_print, + .save = tee_tg6_save, + .x6_parse = xtables_option_parse, + .x6_options = tee_tg_opts, + }, }; void _init(void) { - xtables_register_target(&tee_tg_reg); - xtables_register_target(&tee_tg6_reg); + xtables_register_targets(tee_tg_reg, ARRAY_SIZE(tee_tg_reg)); } diff --git a/extensions/libxt_TOS.c b/extensions/libxt_TOS.c index dc60cc0..cef5876 100644 --- a/extensions/libxt_TOS.c +++ b/extensions/libxt_TOS.c @@ -2,9 +2,10 @@ * Shared library add-on to iptables to add TOS target support * * Copyright © CC Computer Consultants GmbH, 2007 - * Contact: Jan Engelhardt <jengelh@computergmbh.de> + * Contact: Jan Engelhardt <jengelh@medozas.de> */ #include <getopt.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -15,24 +16,37 @@ #include "tos_values.c" struct ipt_tos_target_info { - u_int8_t tos; + uint8_t tos; }; enum { - FLAG_TOS = 1 << 0, + O_SET_TOS = 0, + O_AND_TOS, + O_OR_TOS, + O_XOR_TOS, + F_SET_TOS = 1 << O_SET_TOS, + F_AND_TOS = 1 << O_AND_TOS, + F_OR_TOS = 1 << O_OR_TOS, + F_XOR_TOS = 1 << O_XOR_TOS, + F_ANY = F_SET_TOS | F_AND_TOS | F_OR_TOS | F_XOR_TOS, }; -static const struct option tos_tg_opts_v0[] = { - {.name = "set-tos", .has_arg = true, .val = '='}, - { .name = NULL } +static const struct xt_option_entry tos_tg_opts_v0[] = { + {.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK, + .excl = F_ANY, .max = 0xFF}, + XTOPT_TABLEEND, }; -static const struct option tos_tg_opts[] = { - {.name = "set-tos", .has_arg = true, .val = '='}, - {.name = "and-tos", .has_arg = true, .val = '&'}, - {.name = "or-tos", .has_arg = true, .val = '|'}, - {.name = "xor-tos", .has_arg = true, .val = '^'}, - { .name = NULL } +static const struct xt_option_entry tos_tg_opts[] = { + {.name = "set-tos", .id = O_SET_TOS, .type = XTTYPE_TOSMASK, + .excl = F_ANY, .max = 0x3F}, + {.name = "and-tos", .id = O_AND_TOS, .type = XTTYPE_UINT8, + .excl = F_ANY}, + {.name = "or-tos", .id = O_OR_TOS, .type = XTTYPE_UINT8, + .excl = F_ANY}, + {.name = "xor-tos", .id = O_XOR_TOS, .type = XTTYPE_UINT8, + .excl = F_ANY}, + XTOPT_TABLEEND, }; static void tos_tg_help_v0(void) @@ -77,87 +91,48 @@ XTABLES_VERSION); ); } -static int tos_tg_parse_v0(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void tos_tg_parse_v0(struct xt_option_call *cb) { - struct ipt_tos_target_info *info = (void *)(*target)->data; - struct tos_value_mask tvm; - - switch (c) { - case '=': - xtables_param_act(XTF_ONLY_ONCE, "TOS", "--set-tos", *flags & FLAG_TOS); - xtables_param_act(XTF_NO_INVERT, "TOS", "--set-tos", invert); - if (!tos_parse_symbolic(optarg, &tvm, 0xFF)) - xtables_param_act(XTF_BAD_VALUE, "TOS", "--set-tos", optarg); - if (tvm.mask != 0xFF) - xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel " - "is too old to support anything besides " - "/0xFF as a mask."); - info->tos = tvm.value; - *flags |= FLAG_TOS; - return true; - } - - return false; + struct ipt_tos_target_info *info = cb->data; + + xtables_option_parse(cb); + if (cb->val.tos_mask != 0xFF) + xtables_error(PARAMETER_PROBLEM, "tos match: Your kernel " + "is too old to support anything besides " + "/0xFF as a mask."); + info->tos = cb->val.tos_value; } -static int tos_tg_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void tos_tg_parse(struct xt_option_call *cb) { - struct xt_tos_target_info *info = (void *)(*target)->data; - struct tos_value_mask tvm; - unsigned int bits; - - switch (c) { - case '=': /* --set-tos */ - xtables_param_act(XTF_ONLY_ONCE, "TOS", "--set-tos", *flags & FLAG_TOS); - xtables_param_act(XTF_NO_INVERT, "TOS", "--set-tos", invert); - if (!tos_parse_symbolic(optarg, &tvm, 0x3F)) - xtables_param_act(XTF_BAD_VALUE, "TOS", "--set-tos", optarg); - info->tos_value = tvm.value; - info->tos_mask = tvm.mask; - break; + struct xt_tos_target_info *info = cb->data; - case '&': /* --and-tos */ - xtables_param_act(XTF_ONLY_ONCE, "TOS", "--and-tos", *flags & FLAG_TOS); - xtables_param_act(XTF_NO_INVERT, "TOS", "--and-tos", invert); - if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX)) - xtables_param_act(XTF_BAD_VALUE, "TOS", "--and-tos", optarg); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET_TOS: + info->tos_value = cb->val.tos_value; + info->tos_mask = cb->val.tos_mask; + break; + case O_AND_TOS: info->tos_value = 0; - info->tos_mask = ~bits; + info->tos_mask = ~cb->val.u8; break; - - case '|': /* --or-tos */ - xtables_param_act(XTF_ONLY_ONCE, "TOS", "--or-tos", *flags & FLAG_TOS); - xtables_param_act(XTF_NO_INVERT, "TOS", "--or-tos", invert); - if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX)) - xtables_param_act(XTF_BAD_VALUE, "TOS", "--or-tos", optarg); - info->tos_value = bits; - info->tos_mask = bits; + case O_OR_TOS: + info->tos_value = cb->val.u8; + info->tos_mask = cb->val.u8; break; - - case '^': /* --xor-tos */ - xtables_param_act(XTF_ONLY_ONCE, "TOS", "--xor-tos", *flags & FLAG_TOS); - xtables_param_act(XTF_NO_INVERT, "TOS", "--xor-tos", invert); - if (!xtables_strtoui(optarg, NULL, &bits, 0, UINT8_MAX)) - xtables_param_act(XTF_BAD_VALUE, "TOS", "--xor-tos", optarg); - info->tos_value = bits; + case O_XOR_TOS: + info->tos_value = cb->val.u8; info->tos_mask = 0; break; - - default: - return false; } - - *flags |= FLAG_TOS; - return true; } -static void tos_tg_check(unsigned int flags) +static void tos_tg_check(struct xt_fcheck_call *cb) { - if (flags == 0) + if (!(cb->xflags & F_ANY)) xtables_error(PARAMETER_PROBLEM, - "TOS: The --set-tos parameter is required"); + "TOS: An action is required"); } static void tos_tg_print_v0(const void *ip, @@ -165,9 +140,9 @@ static void tos_tg_print_v0(const void *ip, { const struct ipt_tos_target_info *info = (const void *)target->data; - printf("TOS set "); + printf(" TOS set "); if (numeric || !tos_try_print_symbolic("", info->tos, 0xFF)) - printf("0x%02x ", info->tos); + printf("0x%02x", info->tos); } static void tos_tg_print(const void *ip, const struct xt_entry_target *target, @@ -176,21 +151,21 @@ static void tos_tg_print(const void *ip, const struct xt_entry_target *target, const struct xt_tos_target_info *info = (const void *)target->data; if (numeric) - printf("TOS set 0x%02x/0x%02x ", + printf(" TOS set 0x%02x/0x%02x", info->tos_value, info->tos_mask); - else if (tos_try_print_symbolic("TOS set ", + else if (tos_try_print_symbolic(" TOS set", info->tos_value, info->tos_mask)) /* already printed by call */ return; else if (info->tos_value == 0) - printf("TOS and 0x%02x ", - (unsigned int)(u_int8_t)~info->tos_mask); + printf(" TOS and 0x%02x", + (unsigned int)(uint8_t)~info->tos_mask); else if (info->tos_value == info->tos_mask) - printf("TOS or 0x%02x ", info->tos_value); + printf(" TOS or 0x%02x", info->tos_value); else if (info->tos_mask == 0) - printf("TOS xor 0x%02x ", info->tos_value); + printf(" TOS xor 0x%02x", info->tos_value); else - printf("TOS set 0x%02x/0x%02x ", + printf(" TOS set 0x%02x/0x%02x", info->tos_value, info->tos_mask); } @@ -198,14 +173,14 @@ static void tos_tg_save_v0(const void *ip, const struct xt_entry_target *target) { const struct ipt_tos_target_info *info = (const void *)target->data; - printf("--set-tos 0x%02x ", info->tos); + printf(" --set-tos 0x%02x", info->tos); } static void tos_tg_save(const void *ip, const struct xt_entry_target *target) { const struct xt_tos_target_info *info = (const void *)target->data; - printf("--set-tos 0x%02x/0x%02x ", info->tos_value, info->tos_mask); + printf(" --set-tos 0x%02x/0x%02x", info->tos_value, info->tos_mask); } static struct xtables_target tos_tg_reg[] = { @@ -217,11 +192,11 @@ static struct xtables_target tos_tg_reg[] = { .size = XT_ALIGN(sizeof(struct xt_tos_target_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)), .help = tos_tg_help_v0, - .parse = tos_tg_parse_v0, - .final_check = tos_tg_check, .print = tos_tg_print_v0, .save = tos_tg_save_v0, - .extra_opts = tos_tg_opts_v0, + .x6_parse = tos_tg_parse_v0, + .x6_fcheck = tos_tg_check, + .x6_options = tos_tg_opts_v0, }, { .version = XTABLES_VERSION, @@ -231,11 +206,11 @@ static struct xtables_target tos_tg_reg[] = { .size = XT_ALIGN(sizeof(struct xt_tos_target_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_tos_target_info)), .help = tos_tg_help, - .parse = tos_tg_parse, - .final_check = tos_tg_check, .print = tos_tg_print, .save = tos_tg_save, - .extra_opts = tos_tg_opts, + .x6_parse = tos_tg_parse, + .x6_fcheck = tos_tg_check, + .x6_options = tos_tg_opts, }, }; diff --git a/extensions/libxt_TOS.man b/extensions/libxt_TOS.man index d5cbfcb..58118ec 100644 --- a/extensions/libxt_TOS.man +++ b/extensions/libxt_TOS.man @@ -1,27 +1,36 @@ This module sets the Type of Service field in the IPv4 header (including the "precedence" bits) or the Priority field in the IPv6 header. Note that TOS shares the same bits as DSCP and ECN. The TOS target is only valid in the -\fBmangle\fR table. +\fBmangle\fP table. .TP \fB\-\-set\-tos\fP \fIvalue\fP[\fB/\fP\fImask\fP] -Zeroes out the bits given by \fImask\fR and XORs \fIvalue\fR into the -TOS/Priority field. If \fImask\fR is omitted, 0xFF is assumed. +Zeroes out the bits given by \fImask\fP (see NOTE below) and XORs \fIvalue\fP +into the TOS/Priority field. If \fImask\fP is omitted, 0xFF is assumed. .TP \fB\-\-set\-tos\fP \fIsymbol\fP You can specify a symbolic name when using the TOS target for IPv4. It implies -a mask of 0xFF. The list of recognized TOS names can be obtained by calling -iptables with \fB\-j TOS \-h\fP. +a mask of 0xFF (see NOTE below). The list of recognized TOS names can be +obtained by calling iptables with \fB\-j TOS \-h\fP. .PP The following mnemonics are available: .TP \fB\-\-and\-tos\fP \fIbits\fP -Binary AND the TOS value with \fIbits\fR. (Mnemonic for \fB\-\-set\-tos -0/\fR\fIinvbits\fR, where \fIinvbits\fR is the binary negation of \fIbits\fR.) +Binary AND the TOS value with \fIbits\fP. (Mnemonic for \fB\-\-set\-tos +0/\fP\fIinvbits\fP, where \fIinvbits\fP is the binary negation of \fIbits\fP. +See NOTE below.) .TP \fB\-\-or\-tos\fP \fIbits\fP -Binary OR the TOS value with \fIbits\fR. (Mnemonic for \fB\-\-set\-tos\fP -\fIbits\fR\fB/\fR\fIbits\fR.) +Binary OR the TOS value with \fIbits\fP. (Mnemonic for \fB\-\-set\-tos\fP +\fIbits\fP\fB/\fP\fIbits\fP. See NOTE below.) .TP \fB\-\-xor\-tos\fP \fIbits\fP -Binary XOR the TOS value with \fIbits\fR. (Mnemonic for \fB\-\-set\-tos\fP -\fIbits\fR\fB/0\fR.) +Binary XOR the TOS value with \fIbits\fP. (Mnemonic for \fB\-\-set\-tos\fP +\fIbits\fP\fB/0\fP. See NOTE below.) +.PP +NOTE: In Linux kernels up to and including 2.6.38, with the exception of +longterm releases 2.6.32 (>=.42), 2.6.33 (>=.15), and 2.6.35 (>=.14), there is +a bug whereby IPv6 TOS mangling does not behave as documented and differs from +the IPv4 version. The TOS mask indicates the bits one wants to zero out, so it +needs to be inverted before applying it to the original TOS field. However, the +aformentioned kernels forgo the inversion which breaks --set-tos and its +mnemonics. diff --git a/extensions/libxt_TPROXY.c b/extensions/libxt_TPROXY.c index d410c52..d13ec85 100644 --- a/extensions/libxt_TPROXY.c +++ b/extensions/libxt_TPROXY.c @@ -1,31 +1,42 @@ /* - * Shared library add-on to iptables to add TPROXY target support. + * shared library add-on to iptables to add TPROXY target support. * * Copyright (C) 2002-2008 BalaBit IT Ltd. */ -#include <getopt.h> -#include <stdbool.h> #include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <limits.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_TPROXY.h> +#include <arpa/inet.h> -static const struct option tproxy_tg_opts[] = { - { .name = "on-port", .has_arg = 1, .val = '1'}, - { .name = "on-ip", .has_arg = 1, .val = '2'}, - { .name = "tproxy-mark", .has_arg = 1, .val = '3'}, - {NULL}, +enum { + P_PORT = 0, + P_ADDR, + P_MARK, + F_PORT = 1 << P_PORT, + F_ADDR = 1 << P_ADDR, + F_MARK = 1 << P_MARK, }; -enum { - PARAM_ONPORT = 1 << 0, - PARAM_ONIP = 1 << 1, - PARAM_MARK = 1 << 2, +#define s struct xt_tproxy_target_info +static const struct xt_option_entry tproxy_tg0_opts[] = { + {.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT, + .flags = XTOPT_MAND | XTOPT_NBO | XTOPT_PUT, XTOPT_POINTER(s, lport)}, + {.name = "on-ip", .id = P_ADDR, .type = XTTYPE_HOST}, + {.name = "tproxy-mark", .id = P_MARK, .type = XTTYPE_MARKMASK32}, + XTOPT_TABLEEND, }; +#undef s +#define s struct xt_tproxy_target_info_v1 +static const struct xt_option_entry tproxy_tg1_opts[] = { + {.name = "on-port", .id = P_PORT, .type = XTTYPE_PORT, + .flags = XTOPT_MAND | XTOPT_NBO | XTOPT_PUT, XTOPT_POINTER(s, lport)}, + {.name = "on-ip", .id = P_ADDR, .type = XTTYPE_HOST, + .flags = XTOPT_PUT, XTOPT_POINTER(s, laddr)}, + {.name = "tproxy-mark", .id = P_MARK, .type = XTTYPE_MARKMASK32}, + XTOPT_TABLEEND, +}; +#undef s static void tproxy_tg_help(void) { @@ -36,115 +47,149 @@ static void tproxy_tg_help(void) " --tproxy-mark value[/mask] Mark packets with the given value/mask\n\n"); } -static void parse_tproxy_lport(const char *s, struct xt_tproxy_target_info *info) +static void tproxy_tg_print(const void *ip, const struct xt_entry_target *target, + int numeric) { - unsigned int lport; - - if (xtables_strtoui(s, NULL, &lport, 0, UINT16_MAX)) - info->lport = htons(lport); - else - xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-port", s); + const struct xt_tproxy_target_info *info = (const void *)target->data; + printf(" TPROXY redirect %s:%u mark 0x%x/0x%x", + xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr), + ntohs(info->lport), (unsigned int)info->mark_value, + (unsigned int)info->mark_mask); } -static void parse_tproxy_laddr(const char *s, struct xt_tproxy_target_info *info) +static void +tproxy_tg_print4(const void *ip, const struct xt_entry_target *target, + int numeric) { - struct in_addr *laddr; - - if ((laddr = xtables_numeric_to_ipaddr(s)) == NULL) - xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--on-ip", s); + const struct xt_tproxy_target_info_v1 *info = + (const void *)target->data; - info->laddr = laddr->s_addr; + printf(" TPROXY redirect %s:%u mark 0x%x/0x%x", + xtables_ipaddr_to_numeric(&info->laddr.in), + ntohs(info->lport), (unsigned int)info->mark_value, + (unsigned int)info->mark_mask); } -static void parse_tproxy_mark(char *s, struct xt_tproxy_target_info *info) +static void +tproxy_tg_print6(const void *ip, const struct xt_entry_target *target, + int numeric) { - unsigned int value, mask = UINT32_MAX; - char *end; - - if (!xtables_strtoui(s, &end, &value, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s); - if (*end == '/') - if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s); - if (*end != '\0') - xtables_param_act(XTF_BAD_VALUE, "TPROXY", "--tproxy-mark", s); - - info->mark_mask = mask; - info->mark_value = value; + const struct xt_tproxy_target_info_v1 *info = + (const void *)target->data; + + printf(" TPROXY redirect %s:%u mark 0x%x/0x%x", + xtables_ip6addr_to_numeric(&info->laddr.in6), + ntohs(info->lport), (unsigned int)info->mark_value, + (unsigned int)info->mark_mask); } -static int tproxy_tg_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_target **target) +static void tproxy_tg_save(const void *ip, const struct xt_entry_target *target) { - struct xt_tproxy_target_info *tproxyinfo = (void *)(*target)->data; - - switch (c) { - case '1': - xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-port", *flags & PARAM_ONPORT); - xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-port", invert); - parse_tproxy_lport(optarg, tproxyinfo); - *flags |= PARAM_ONPORT; - return 1; - case '2': - xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--on-ip", *flags & PARAM_ONIP); - xtables_param_act(XTF_NO_INVERT, "TPROXY", "--on-ip", invert); - parse_tproxy_laddr(optarg, tproxyinfo); - *flags |= PARAM_ONIP; - return 1; - case '3': - xtables_param_act(XTF_ONLY_ONCE, "TPROXY", "--tproxy-mark", *flags & PARAM_MARK); - xtables_param_act(XTF_NO_INVERT, "TPROXY", "--tproxy-mark", invert); - parse_tproxy_mark(optarg, tproxyinfo); - *flags |= PARAM_MARK; - return 1; - } + const struct xt_tproxy_target_info *info = (const void *)target->data; - return 0; + printf(" --on-port %u", ntohs(info->lport)); + printf(" --on-ip %s", + xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr)); + printf(" --tproxy-mark 0x%x/0x%x", + (unsigned int)info->mark_value, (unsigned int)info->mark_mask); } -static void tproxy_tg_check(unsigned int flags) +static void +tproxy_tg_save4(const void *ip, const struct xt_entry_target *target) { - if (!(flags & PARAM_ONPORT)) - xtables_error(PARAMETER_PROBLEM, - "TPROXY target: Parameter --on-port is required"); + const struct xt_tproxy_target_info_v1 *info; + + info = (const void *)target->data; + printf(" --on-port %u", ntohs(info->lport)); + printf(" --on-ip %s", xtables_ipaddr_to_numeric(&info->laddr.in)); + printf(" --tproxy-mark 0x%x/0x%x", + (unsigned int)info->mark_value, (unsigned int)info->mark_mask); } -static void tproxy_tg_print(const void *ip, const struct xt_entry_target *target, - int numeric) +static void +tproxy_tg_save6(const void *ip, const struct xt_entry_target *target) { - const struct xt_tproxy_target_info *info = (const void *)target->data; - printf("TPROXY redirect %s:%u mark 0x%x/0x%x", - xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr), - ntohs(info->lport), (unsigned int)info->mark_value, - (unsigned int)info->mark_mask); + const struct xt_tproxy_target_info_v1 *info; + + info = (const void *)target->data; + printf(" --on-port %u", ntohs(info->lport)); + printf(" --on-ip %s", xtables_ip6addr_to_numeric(&info->laddr.in6)); + printf(" --tproxy-mark 0x%x/0x%x", + (unsigned int)info->mark_value, (unsigned int)info->mark_mask); } -static void tproxy_tg_save(const void *ip, const struct xt_entry_target *target) +static void tproxy_tg0_parse(struct xt_option_call *cb) { - const struct xt_tproxy_target_info *info = (const void *)target->data; + struct xt_tproxy_target_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case P_MARK: + info->mark_value = cb->val.mark; + info->mark_mask = cb->val.mask; + break; + case P_ADDR: + info->laddr = cb->val.haddr.ip; + break; + } +} - printf("--on-port %u ", ntohs(info->lport)); - printf("--on-ip %s ", - xtables_ipaddr_to_numeric((const struct in_addr *)&info->laddr)); - printf("--tproxy-mark 0x%x/0x%x ", - (unsigned int)info->mark_value, (unsigned int)info->mark_mask); +static void tproxy_tg1_parse(struct xt_option_call *cb) +{ + struct xt_tproxy_target_info_v1 *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case P_MARK: + info->mark_value = cb->val.mark; + info->mark_mask = cb->val.mask; + break; + } } -static struct xtables_target tproxy_tg_reg = { - .name = "TPROXY", - .family = NFPROTO_IPV4, - .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct xt_tproxy_target_info)), - .userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info)), - .help = tproxy_tg_help, - .parse = tproxy_tg_parse, - .final_check = tproxy_tg_check, - .print = tproxy_tg_print, - .save = tproxy_tg_save, - .extra_opts = tproxy_tg_opts, +static struct xtables_target tproxy_tg_reg[] = { + { + .name = "TPROXY", + .revision = 0, + .family = NFPROTO_IPV4, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_tproxy_target_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info)), + .help = tproxy_tg_help, + .print = tproxy_tg_print, + .save = tproxy_tg_save, + .x6_options = tproxy_tg0_opts, + .x6_parse = tproxy_tg0_parse, + }, + { + .name = "TPROXY", + .revision = 1, + .family = NFPROTO_IPV4, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), + .help = tproxy_tg_help, + .print = tproxy_tg_print4, + .save = tproxy_tg_save4, + .x6_options = tproxy_tg1_opts, + .x6_parse = tproxy_tg1_parse, + }, + { + .name = "TPROXY", + .revision = 1, + .family = NFPROTO_IPV6, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_tproxy_target_info_v1)), + .help = tproxy_tg_help, + .print = tproxy_tg_print6, + .save = tproxy_tg_save6, + .x6_options = tproxy_tg1_opts, + .x6_parse = tproxy_tg1_parse, + }, }; void _init(void) { - xtables_register_target(&tproxy_tg_reg); + xtables_register_targets(tproxy_tg_reg, ARRAY_SIZE(tproxy_tg_reg)); } diff --git a/extensions/libxt_TPROXY.man b/extensions/libxt_TPROXY.man index 0129f84..2f7d82d 100644 --- a/extensions/libxt_TPROXY.man +++ b/extensions/libxt_TPROXY.man @@ -1,4 +1,4 @@ -This target is only valid in the \fBmangle\fR table, in the \fBPREROUTING\fR +This target is only valid in the \fBmangle\fP table, in the \fBPREROUTING\fP chain and user-defined chains which are only called from this chain. It redirects the packet to a local socket without changing the packet header in any way. It can also change the mark value which can then be used in advanced diff --git a/extensions/libxt_TRACE.man b/extensions/libxt_TRACE.man index d28c3a0..8d590a5 100644 --- a/extensions/libxt_TRACE.man +++ b/extensions/libxt_TRACE.man @@ -1,7 +1,9 @@ -This target marks packes so that the kernel will log every rule which match -the packets as those traverse the tables, chains, rules. (The ipt_LOG or -ip6t_LOG module -is required for the logging.) The packets are logged with the string prefix: +This target marks packets so that the kernel will log every rule which match +the packets as those traverse the tables, chains, rules. +.PP +A logging backend, such as ip(6)t_LOG or nfnetlink_log, must be loaded for this +to be visible. +The packets are logged with the string prefix: "TRACE: tablename:chainname:type:rulenum " where type can be "rule" for plain rule, "return" for implicit rule at the end of a user defined chain and "policy" for the policy of the built in chains. diff --git a/extensions/libxt_addrtype.c b/extensions/libxt_addrtype.c new file mode 100644 index 0000000..e5d3033 --- /dev/null +++ b/extensions/libxt_addrtype.c @@ -0,0 +1,302 @@ +/* Shared library add-on to iptables to add addrtype matching support + * + * Copyright (c) 2003-2013 Patrick McHardy <kaber@trash.net> + * + * This program is released under the terms of GNU GPL */ +#include <stdio.h> +#include <string.h> +#include <xtables.h> +#include <linux/netfilter/xt_addrtype.h> + +enum { + O_SRC_TYPE = 0, + O_DST_TYPE, + O_LIMIT_IFACE_IN, + O_LIMIT_IFACE_OUT, + F_SRC_TYPE = 1 << O_SRC_TYPE, + F_DST_TYPE = 1 << O_DST_TYPE, + F_LIMIT_IFACE_IN = 1 << O_LIMIT_IFACE_IN, + F_LIMIT_IFACE_OUT = 1 << O_LIMIT_IFACE_OUT, +}; + +/* from linux/rtnetlink.h, must match order of enumeration */ +static const char *const rtn_names[] = { + "UNSPEC", + "UNICAST", + "LOCAL", + "BROADCAST", + "ANYCAST", + "MULTICAST", + "BLACKHOLE", + "UNREACHABLE", + "PROHIBIT", + "THROW", + "NAT", + "XRESOLVE", + NULL +}; + +static void addrtype_help_types(void) +{ + int i; + + for (i = 0; rtn_names[i]; i++) + printf(" %s\n", rtn_names[i]); +} + +static void addrtype_help_v0(void) +{ + printf( +"Address type match options:\n" +" [!] --src-type type[,...] Match source address type\n" +" [!] --dst-type type[,...] Match destination address type\n" +"\n" +"Valid types: \n"); + addrtype_help_types(); +} + +static void addrtype_help_v1(void) +{ + printf( +"Address type match options:\n" +" [!] --src-type type[,...] Match source address type\n" +" [!] --dst-type type[,...] Match destination address type\n" +" --limit-iface-in Match only on the packet's incoming device\n" +" --limit-iface-out Match only on the packet's outgoing device\n" +"\n" +"Valid types: \n"); + addrtype_help_types(); +} + +static int +parse_type(const char *name, size_t len, uint16_t *mask) +{ + int i; + + for (i = 0; rtn_names[i]; i++) + if (strncasecmp(name, rtn_names[i], len) == 0) { + /* build up bitmask for kernel module */ + *mask |= (1 << i); + return 1; + } + + return 0; +} + +static void parse_types(const char *arg, uint16_t *mask) +{ + const char *comma; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg || !parse_type(arg, comma-arg, mask)) + xtables_error(PARAMETER_PROBLEM, + "addrtype: bad type `%s'", arg); + arg = comma + 1; + } + + if (strlen(arg) == 0 || !parse_type(arg, strlen(arg), mask)) + xtables_error(PARAMETER_PROBLEM, "addrtype: bad type \"%s\"", arg); +} + +static void addrtype_parse_v0(struct xt_option_call *cb) +{ + struct xt_addrtype_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRC_TYPE: + parse_types(cb->arg, &info->source); + if (cb->invert) + info->invert_source = 1; + break; + case O_DST_TYPE: + parse_types(cb->arg, &info->dest); + if (cb->invert) + info->invert_dest = 1; + break; + } +} + +static void addrtype_parse_v1(struct xt_option_call *cb) +{ + struct xt_addrtype_info_v1 *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRC_TYPE: + parse_types(cb->arg, &info->source); + if (cb->invert) + info->flags |= XT_ADDRTYPE_INVERT_SOURCE; + break; + case O_DST_TYPE: + parse_types(cb->arg, &info->dest); + if (cb->invert) + info->flags |= XT_ADDRTYPE_INVERT_DEST; + break; + case O_LIMIT_IFACE_IN: + info->flags |= XT_ADDRTYPE_LIMIT_IFACE_IN; + break; + case O_LIMIT_IFACE_OUT: + info->flags |= XT_ADDRTYPE_LIMIT_IFACE_OUT; + break; + } +} + +static void addrtype_check(struct xt_fcheck_call *cb) +{ + if (!(cb->xflags & (F_SRC_TYPE | F_DST_TYPE))) + xtables_error(PARAMETER_PROBLEM, + "addrtype: you must specify --src-type or --dst-type"); +} + +static void print_types(uint16_t mask) +{ + const char *sep = ""; + int i; + + for (i = 0; rtn_names[i]; i++) + if (mask & (1 << i)) { + printf("%s%s", sep, rtn_names[i]); + sep = ","; + } +} + +static void addrtype_print_v0(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_addrtype_info *info = (const void *)match->data; + + printf(" ADDRTYPE match"); + if (info->source) { + printf(" src-type "); + if (info->invert_source) + printf("!"); + print_types(info->source); + } + if (info->dest) { + printf(" dst-type"); + if (info->invert_dest) + printf("!"); + print_types(info->dest); + } +} + +static void addrtype_print_v1(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_addrtype_info_v1 *info = (const void *)match->data; + + printf(" ADDRTYPE match"); + if (info->source) { + printf(" src-type "); + if (info->flags & XT_ADDRTYPE_INVERT_SOURCE) + printf("!"); + print_types(info->source); + } + if (info->dest) { + printf(" dst-type "); + if (info->flags & XT_ADDRTYPE_INVERT_DEST) + printf("!"); + print_types(info->dest); + } + if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) + printf(" limit-in"); + if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) + printf(" limit-out"); +} + +static void addrtype_save_v0(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_addrtype_info *info = (const void *)match->data; + + if (info->source) { + if (info->invert_source) + printf(" !"); + printf(" --src-type "); + print_types(info->source); + } + if (info->dest) { + if (info->invert_dest) + printf(" !"); + printf(" --dst-type "); + print_types(info->dest); + } +} + +static void addrtype_save_v1(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_addrtype_info_v1 *info = (const void *)match->data; + + if (info->source) { + if (info->flags & XT_ADDRTYPE_INVERT_SOURCE) + printf(" !"); + printf(" --src-type "); + print_types(info->source); + } + if (info->dest) { + if (info->flags & XT_ADDRTYPE_INVERT_DEST) + printf(" !"); + printf(" --dst-type "); + print_types(info->dest); + } + if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) + printf(" --limit-iface-in"); + if (info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) + printf(" --limit-iface-out"); +} + +static const struct xt_option_entry addrtype_opts_v0[] = { + {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry addrtype_opts_v1[] = { + {.name = "src-type", .id = O_SRC_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "dst-type", .id = O_DST_TYPE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "limit-iface-in", .id = O_LIMIT_IFACE_IN, + .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_OUT}, + {.name = "limit-iface-out", .id = O_LIMIT_IFACE_OUT, + .type = XTTYPE_NONE, .excl = F_LIMIT_IFACE_IN}, + XTOPT_TABLEEND, +}; + +static struct xtables_match addrtype_mt_reg[] = { + { + .name = "addrtype", + .version = XTABLES_VERSION, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_addrtype_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info)), + .help = addrtype_help_v0, + .print = addrtype_print_v0, + .save = addrtype_save_v0, + .x6_parse = addrtype_parse_v0, + .x6_fcheck = addrtype_check, + .x6_options = addrtype_opts_v0, + }, + { + .name = "addrtype", + .revision = 1, + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_addrtype_info_v1)), + .help = addrtype_help_v1, + .print = addrtype_print_v1, + .save = addrtype_save_v1, + .x6_parse = addrtype_parse_v1, + .x6_fcheck = addrtype_check, + .x6_options = addrtype_opts_v1, + }, +}; + + +void _init(void) +{ + xtables_register_matches(addrtype_mt_reg, ARRAY_SIZE(addrtype_mt_reg)); +} diff --git a/extensions/libipt_addrtype.man b/extensions/libxt_addrtype.man index 16fd9df..16fd9df 100644 --- a/extensions/libipt_addrtype.man +++ b/extensions/libxt_addrtype.man diff --git a/extensions/libxt_bpf.c b/extensions/libxt_bpf.c new file mode 100644 index 0000000..dca97d7 --- /dev/null +++ b/extensions/libxt_bpf.c @@ -0,0 +1,152 @@ +/* + * Xtables BPF extension + * + * Written by Willem de Bruijn (willemb@google.com) + * Copyright Google, Inc. 2013 + * Licensed under the GNU General Public License version 2 (GPLv2) +*/ + +#include <linux/netfilter/xt_bpf.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <xtables.h> + +#define BCODE_FILE_MAX_LEN_B 1024 + +enum { + O_BCODE_STDIN = 0, +}; + +static void bpf_help(void) +{ + printf( +"bpf match options:\n" +"--bytecode <program> : a bpf program as generated by\n" +" `nfbpf_compiler RAW <filter>`\n"); +} + +static const struct xt_option_entry bpf_opts[] = { + {.name = "bytecode", .id = O_BCODE_STDIN, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, +}; + +static void bpf_parse_string(struct xt_option_call *cb, const char *bpf_program, + const char separator) +{ + struct xt_bpf_info *bi = (void *) cb->data; + const char *token; + char sp; + int i; + + /* parse head: length. */ + if (sscanf(bpf_program, "%hu%c", &bi->bpf_program_num_elem, &sp) != 2 || + sp != separator) + xtables_error(PARAMETER_PROBLEM, + "bpf: error parsing program length"); + if (!bi->bpf_program_num_elem) + xtables_error(PARAMETER_PROBLEM, + "bpf: illegal zero length program"); + if (bi->bpf_program_num_elem > XT_BPF_MAX_NUM_INSTR) + xtables_error(PARAMETER_PROBLEM, + "bpf: number of instructions exceeds maximum"); + + /* parse instructions. */ + i = 0; + token = bpf_program; + while ((token = strchr(token, separator)) && (++token)[0]) { + if (i >= bi->bpf_program_num_elem) + xtables_error(PARAMETER_PROBLEM, + "bpf: real program length exceeds" + " the encoded length parameter"); + if (sscanf(token, "%hu %hhu %hhu %u,", + &bi->bpf_program[i].code, + &bi->bpf_program[i].jt, + &bi->bpf_program[i].jf, + &bi->bpf_program[i].k) != 4) + xtables_error(PARAMETER_PROBLEM, + "bpf: error at instr %d", i); + i++; + } + + if (i != bi->bpf_program_num_elem) + xtables_error(PARAMETER_PROBLEM, + "bpf: parsed program length is less than the" + " encoded length parameter"); +} + +static void bpf_parse(struct xt_option_call *cb) +{ + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_BCODE_STDIN: + bpf_parse_string(cb, cb->arg, ','); + break; + default: + xtables_error(PARAMETER_PROBLEM, "bpf: unknown option"); + } +} + +static void bpf_print_code(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_bpf_info *info = (void *) match->data; + int i; + + for (i = 0; i < info->bpf_program_num_elem-1; i++) + printf("%hu %hhu %hhu %u,", info->bpf_program[i].code, + info->bpf_program[i].jt, + info->bpf_program[i].jf, + info->bpf_program[i].k); + + printf("%hu %hhu %hhu %u", info->bpf_program[i].code, + info->bpf_program[i].jt, + info->bpf_program[i].jf, + info->bpf_program[i].k); +} + +static void bpf_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_bpf_info *info = (void *) match->data; + + printf(" --bytecode \"%hu,", info->bpf_program_num_elem); + bpf_print_code(ip, match); + printf("\""); +} + +static void bpf_fcheck(struct xt_fcheck_call *cb) +{ + if (!(cb->xflags & (1 << O_BCODE_STDIN))) + xtables_error(PARAMETER_PROBLEM, + "bpf: missing --bytecode parameter"); +} + +static void bpf_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + printf("match bpf "); + return bpf_print_code(ip, match); +} + +static struct xtables_match bpf_match = { + .family = NFPROTO_UNSPEC, + .name = "bpf", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_bpf_info)), + .userspacesize = XT_ALIGN(offsetof(struct xt_bpf_info, filter)), + .help = bpf_help, + .print = bpf_print, + .save = bpf_save, + .x6_parse = bpf_parse, + .x6_fcheck = bpf_fcheck, + .x6_options = bpf_opts, +}; + +void _init(void) +{ + xtables_register_match(&bpf_match); +} diff --git a/extensions/libxt_bpf.man b/extensions/libxt_bpf.man new file mode 100644 index 0000000..5b1d042 --- /dev/null +++ b/extensions/libxt_bpf.man @@ -0,0 +1,34 @@ +Match using Linux Socket Filter. Expects a BPF program in decimal format. This +is the format generated by the \fBnfbpf_compile\fP utility. +.TP +\fB\-\-bytecode\fP \fIcode\fP +Pass the BPF byte code format (described in the example below). +.PP +The code format is similar to the output of the tcpdump -ddd command: one line +that stores the number of instructions, followed by one line for each +instruction. Instruction lines follow the pattern 'u16 u8 u8 u32' in decimal +notation. Fields encode the operation, jump offset if true, jump offset if +false and generic multiuse field 'K'. Comments are not supported. +.PP +For example, to read only packets matching 'ip proto 6', insert the following, +without the comments or trailing whitespace: +.IP +4 # number of instructions +.br +48 0 0 9 # load byte ip->proto +.br +21 0 1 6 # jump equal IPPROTO_TCP +.br +6 0 0 1 # return pass (non-zero) +.br +6 0 0 0 # return fail (zero) +.PP +You can pass this filter to the bpf match with the following command: +.IP +iptables \-A OUTPUT \-m bpf \-\-bytecode '4,48 0 0 9,21 0 1 6,6 0 0 1,6 0 0 0' \-j ACCEPT +.PP +Or instead, you can invoke the nfbpf_compile utility. +.IP +iptables \-A OUTPUT \-m bpf \-\-bytecode "`nfbpf_compile RAW 'ip proto 6'`" \-j ACCEPT +.PP +You may want to learn more about BPF from FreeBSD's bpf(4) manpage. diff --git a/extensions/libxt_cgroup.c b/extensions/libxt_cgroup.c new file mode 100644 index 0000000..cdc4ec9 --- /dev/null +++ b/extensions/libxt_cgroup.c @@ -0,0 +1,74 @@ +#include <getopt.h> +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter/xt_cgroup.h> + +static void cgroup_help(void) +{ + printf( +"cgroup match options:\n" +"[!] --cgroup fwid Match cgroup fwid\n"); +} + +static const struct option cgroup_opts[] = { + { "cgroup", 1, NULL, 'c' }, + { .name = NULL } +}; + +static int +cgroup_parse(int c, char **argv, int invert, unsigned int *flags, + const void *entry, + struct xt_entry_match **target) +{ + struct xt_cgroup_info *cgroupinfo + = (struct xt_cgroup_info *)(*target)->data; + + switch (c) { + case 'c': /* TODO 1 or 0 */ + /* use optarg, due libopt is used */ + if (sscanf(optarg, "%u", &cgroupinfo->id) != 1) + return 1; + + cgroupinfo->invert = invert; + *flags = 1; + break; + + default: + return 0; + } + + return 1; +} + +static void +cgroup_print(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_cgroup_info *info = (void *) match->data; + + printf(" cgroup %s%u", info->invert ? "! ":"", info->id); +} + +static void cgroup_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_cgroup_info *info = (void *) match->data; + + printf("%s --cgroup %u", info->invert ? " !" : "", info->id); +} + +static struct xtables_match cgroup_match = { + .family = NFPROTO_UNSPEC, + .name = "cgroup", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_cgroup_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_cgroup_info)), + .help = cgroup_help, + .print = cgroup_print, + .save = cgroup_save, + .parse = cgroup_parse, + .extra_opts = cgroup_opts, +}; + +void _init(void) +{ + xtables_register_match(&cgroup_match); +} diff --git a/extensions/libxt_cgroup.man b/extensions/libxt_cgroup.man new file mode 100644 index 0000000..456a031 --- /dev/null +++ b/extensions/libxt_cgroup.man @@ -0,0 +1,15 @@ +.TP +[\fB!\fP] \fB\-\-cgroup\fP \fIfwid\fP +Match corresponding cgroup for this packet. + +Can be used to assign particular firewall policies for aggregated +task/jobs on the system. This allows for more fine-grained firewall +policies that only match for a subset of the system's processes. +fwid is the maker set through the net_cls cgroup's id. +.PP +Example: +.PP +iptables \-A OUTPUT \-p tcp \-\-sport 80 \-m cgroup ! \-\-cgroup 1 +\-j DROP +.PP +Available since Linux 3.14. diff --git a/extensions/libxt_cluster.c b/extensions/libxt_cluster.c index ea5d9fb..3adff12 100644 --- a/extensions/libxt_cluster.c +++ b/extensions/libxt_cluster.c @@ -6,19 +6,9 @@ * published by the Free Software Foundation. */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <stddef.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_cluster.h> -/* hack to keep for check */ -static unsigned int total_nodes; -static unsigned int node_mask; - static void cluster_help(void) { @@ -31,162 +21,80 @@ cluster_help(void) } enum { - CLUSTER_OPT_TOTAL_NODES, - CLUSTER_OPT_LOCAL_NODE, - CLUSTER_OPT_NODE_MASK, - CLUSTER_OPT_HASH_SEED, + O_CL_TOTAL_NODES = 0, + O_CL_LOCAL_NODE, + O_CL_LOCAL_NODEMASK, + O_CL_HASH_SEED, + F_CL_TOTAL_NODES = 1 << O_CL_TOTAL_NODES, + F_CL_LOCAL_NODE = 1 << O_CL_LOCAL_NODE, + F_CL_LOCAL_NODEMASK = 1 << O_CL_LOCAL_NODEMASK, + F_CL_HASH_SEED = 1 << O_CL_HASH_SEED, }; -static const struct option cluster_opts[] = { - { "cluster-total-nodes", 1, NULL, CLUSTER_OPT_TOTAL_NODES }, - { "cluster-local-node", 1, NULL, CLUSTER_OPT_LOCAL_NODE }, - { "cluster-local-nodemask", 1, NULL, CLUSTER_OPT_NODE_MASK }, - { "cluster-hash-seed", 1, NULL, CLUSTER_OPT_HASH_SEED }, - { .name = NULL } +#define s struct xt_cluster_match_info +static const struct xt_option_entry cluster_opts[] = { + {.name = "cluster-total-nodes", .id = O_CL_TOTAL_NODES, + .type = XTTYPE_UINT32, .min = 1, .max = XT_CLUSTER_NODES_MAX, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, total_nodes)}, + {.name = "cluster-local-node", .id = O_CL_LOCAL_NODE, + .excl = F_CL_LOCAL_NODEMASK, .flags = XTOPT_INVERT, + .type = XTTYPE_UINT32, .min = 1, .max = XT_CLUSTER_NODES_MAX}, + {.name = "cluster-local-nodemask", .id = O_CL_LOCAL_NODEMASK, + .excl = F_CL_LOCAL_NODE, .type = XTTYPE_UINT32, + .min = 1, .max = XT_CLUSTER_NODES_MAX, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, node_mask)}, + {.name = "cluster-hash-seed", .id = O_CL_HASH_SEED, + .type = XTTYPE_UINT32, .flags = XTOPT_MAND | XTOPT_PUT, + XTOPT_POINTER(s, hash_seed)}, + XTOPT_TABLEEND, }; -static int -cluster_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void cluster_parse(struct xt_option_call *cb) { - struct xt_cluster_match_info *info = (void *)(*match)->data; - unsigned int num; - - switch (c) { - case CLUSTER_OPT_TOTAL_NODES: - if (*flags & (1 << c)) { - xtables_error(PARAMETER_PROBLEM, - "Can only specify " - "`--cluster-total-nodes' once"); - } - if (!xtables_strtoui(optarg, NULL, &num, 1, - XT_CLUSTER_NODES_MAX)) { - xtables_error(PARAMETER_PROBLEM, - "Unable to parse `%s' in " - "`--cluster-total-nodes'", optarg); - } - total_nodes = num; - info->total_nodes = total_nodes = num; - *flags |= 1 << c; - break; - case CLUSTER_OPT_LOCAL_NODE: - if (*flags & (1 << c)) { - xtables_error(PARAMETER_PROBLEM, - "Can only specify " - "`--cluster-local-node' once"); - } - if (*flags & (1 << CLUSTER_OPT_NODE_MASK)) { - xtables_error(PARAMETER_PROBLEM, "You cannot use " - "`--cluster-local-nodemask' and " - "`--cluster-local-node'"); - } - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if (!xtables_strtoui(optarg, NULL, &num, 1, - XT_CLUSTER_NODES_MAX)) { - xtables_error(PARAMETER_PROBLEM, - "Unable to parse `%s' in " - "`--cluster-local-node'", optarg); - } - if (invert) - info->flags |= (1 << XT_CLUSTER_F_INV); - - info->node_mask = node_mask = (1 << (num - 1)); - *flags |= 1 << c; + struct xt_cluster_match_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_CL_LOCAL_NODE: + if (cb->invert) + info->flags |= XT_CLUSTER_F_INV; + info->node_mask = 1 << (cb->val.u32 - 1); break; - case CLUSTER_OPT_NODE_MASK: - if (*flags & (1 << c)) { - xtables_error(PARAMETER_PROBLEM, - "Can only specify " - "`--cluster-local-node' once"); - } - if (*flags & (1 << CLUSTER_OPT_LOCAL_NODE)) { - xtables_error(PARAMETER_PROBLEM, "You cannot use " - "`--cluster-local-nodemask' and " - "`--cluster-local-node'"); - } - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if (!xtables_strtoui(optarg, NULL, &num, 1, - XT_CLUSTER_NODES_MAX)) { - xtables_error(PARAMETER_PROBLEM, - "Unable to parse `%s' in " - "`--cluster-local-node'", optarg); - } - if (invert) - info->flags |= (1 << XT_CLUSTER_F_INV); - - info->node_mask = node_mask = num; - *flags |= 1 << c; + case O_CL_LOCAL_NODEMASK: + if (cb->invert) + info->flags |= XT_CLUSTER_F_INV; break; - - case CLUSTER_OPT_HASH_SEED: - if (*flags & (1 << c)) { - xtables_error(PARAMETER_PROBLEM, - "Can only specify " - "`--cluster-hash-seed' once"); - } - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) { - xtables_error(PARAMETER_PROBLEM, - "Unable to parse `%s'", optarg); - } - info->hash_seed = num; - *flags |= 1 << c; - break; - default: - return 0; } - - return 1; } -static void -cluster_check(unsigned int flags) +static void cluster_check(struct xt_fcheck_call *cb) { - if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) | - (1 << CLUSTER_OPT_LOCAL_NODE) | - (1 << CLUSTER_OPT_HASH_SEED))) - == ((1 << CLUSTER_OPT_TOTAL_NODES) | - (1 << CLUSTER_OPT_LOCAL_NODE) | - (1 << CLUSTER_OPT_HASH_SEED))) { - if (node_mask >= (1ULL << total_nodes)) { + const struct xt_cluster_match_info *info = cb->data; + unsigned int test; + + test = F_CL_TOTAL_NODES | F_CL_LOCAL_NODE | F_CL_HASH_SEED; + if ((cb->xflags & test) == test) { + if (info->node_mask >= (1ULL << info->total_nodes)) xtables_error(PARAMETER_PROBLEM, "cluster match: " "`--cluster-local-node' " "must be <= `--cluster-total-nodes'"); - } return; } - if ((flags & ((1 << CLUSTER_OPT_TOTAL_NODES) | - (1 << CLUSTER_OPT_NODE_MASK) | - (1 << CLUSTER_OPT_HASH_SEED))) - == ((1 << CLUSTER_OPT_TOTAL_NODES) | - (1 << CLUSTER_OPT_NODE_MASK) | - (1 << CLUSTER_OPT_HASH_SEED))) { - if (node_mask >= (1ULL << total_nodes)) { + + test = F_CL_TOTAL_NODES | F_CL_LOCAL_NODEMASK | F_CL_HASH_SEED; + if ((cb->xflags & test) == test) { + if (info->node_mask >= (1ULL << info->total_nodes)) xtables_error(PARAMETER_PROBLEM, "cluster match: " "`--cluster-local-nodemask' too big " "for `--cluster-total-nodes'"); - } return; } - if (!(flags & (1 << CLUSTER_OPT_TOTAL_NODES))) { - xtables_error(PARAMETER_PROBLEM, - "cluster match: `--cluster-total-nodes' " - "is missing"); - } - if (!(flags & (1 << CLUSTER_OPT_HASH_SEED))) { - xtables_error(PARAMETER_PROBLEM, - "cluster match: `--cluster-hash-seed' " - "is missing"); - } - if (!(flags & ((1 << (CLUSTER_OPT_LOCAL_NODE) | - (1 << (CLUSTER_OPT_NODE_MASK)))))) { + if (!(cb->xflags & (F_CL_LOCAL_NODE | F_CL_LOCAL_NODEMASK))) xtables_error(PARAMETER_PROBLEM, "cluster match: `--cluster-local-node' or" "`--cluster-local-nodemask' is missing"); - } } static void @@ -194,13 +102,13 @@ cluster_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_cluster_match_info *info = (void *)match->data; - printf("cluster "); + printf(" cluster "); if (info->flags & XT_CLUSTER_F_INV) - printf("!node_mask=0x%08x ", info->node_mask); + printf("!node_mask=0x%08x", info->node_mask); else - printf("node_mask=0x%08x ", info->node_mask); + printf("node_mask=0x%08x", info->node_mask); - printf("total_nodes=%u hash_seed=0x%08x ", + printf(" total_nodes=%u hash_seed=0x%08x", info->total_nodes, info->hash_seed); } @@ -210,11 +118,11 @@ cluster_save(const void *ip, const struct xt_entry_match *match) const struct xt_cluster_match_info *info = (void *)match->data; if (info->flags & XT_CLUSTER_F_INV) - printf("! --cluster-local-nodemask 0x%08x ", info->node_mask); + printf(" ! --cluster-local-nodemask 0x%08x", info->node_mask); else - printf("--cluster-local-nodemask 0x%08x ", info->node_mask); + printf(" --cluster-local-nodemask 0x%08x", info->node_mask); - printf("--cluster-total-nodes %u --cluster-hash-seed 0x%08x ", + printf(" --cluster-total-nodes %u --cluster-hash-seed 0x%08x", info->total_nodes, info->hash_seed); } @@ -225,11 +133,11 @@ static struct xtables_match cluster_mt_reg = { .size = XT_ALIGN(sizeof(struct xt_cluster_match_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_cluster_match_info)), .help = cluster_help, - .parse = cluster_parse, - .final_check = cluster_check, .print = cluster_print, .save = cluster_save, - .extra_opts = cluster_opts, + .x6_parse = cluster_parse, + .x6_fcheck = cluster_check, + .x6_options = cluster_opts, }; void _init(void) diff --git a/extensions/libxt_cluster.man b/extensions/libxt_cluster.man index 62ad71c..94b4b20 100644 --- a/extensions/libxt_cluster.man +++ b/extensions/libxt_cluster.man @@ -55,6 +55,11 @@ arptables \-A INPUT \-i eth2 \-\-h\-length 6 \-\-destination\-mac 01:00:5e:00:01:02 \-j mangle \-\-mangle\-mac\-d 00:zz:yy:xx:5a:27 .PP +\fBNOTE\fP: the arptables commands above use mainstream syntax. If you +are using arptables-jf included in some RedHat, CentOS and Fedora +versions, you will hit syntax errors. Therefore, you'll have to adapt +these to the arptables-jf syntax to get them working. +.PP In the case of TCP connections, pickup facility has to be disabled to avoid marking TCP ACK packets coming in the reply direction as valid. diff --git a/extensions/libxt_comment.c b/extensions/libxt_comment.c index 0068a6e..6ed2ff9 100644 --- a/extensions/libxt_comment.c +++ b/extensions/libxt_comment.c @@ -7,13 +7,13 @@ * Port to patch-o-matic-ng */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_comment.h> +enum { + O_COMMENT = 0, +}; + static void comment_help(void) { printf( @@ -21,60 +21,20 @@ static void comment_help(void) "--comment COMMENT Attach a comment to a rule\n"); } -static const struct option comment_opts[] = { - { "comment", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry comment_opts[] = { + {.name = "comment", .id = O_COMMENT, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, + XTOPT_POINTER(struct xt_comment_info, comment)}, + XTOPT_TABLEEND, }; static void -parse_comment(const char *s, struct xt_comment_info *info) -{ - int slen = strlen(s); - - if (slen >= XT_MAX_COMMENT_LEN) { - xtables_error(PARAMETER_PROBLEM, - "COMMENT must be shorter than %i characters", XT_MAX_COMMENT_LEN); - } - strcpy((char *)info->comment, s); -} - -static int -comment_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct xt_comment_info *commentinfo = (struct xt_comment_info *)(*match)->data; - - switch (c) { - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) { - xtables_error(PARAMETER_PROBLEM, - "Sorry, you can't have an inverted comment"); - } - parse_comment(optarg, commentinfo); - *flags = 1; - break; - - default: - return 0; - } - return 1; -} - -static void comment_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "COMMENT match: You must specify `--comment'"); -} - -static void comment_print(const void *ip, const struct xt_entry_match *match, int numeric) { struct xt_comment_info *commentinfo = (void *)match->data; commentinfo->comment[XT_MAX_COMMENT_LEN-1] = '\0'; - printf("/* %s */ ", commentinfo->comment); + printf(" /* %s */", commentinfo->comment); } /* Saves the union ipt_matchinfo in parsable form to stdout. */ @@ -84,8 +44,8 @@ comment_save(const void *ip, const struct xt_entry_match *match) struct xt_comment_info *commentinfo = (void *)match->data; commentinfo->comment[XT_MAX_COMMENT_LEN-1] = '\0'; - printf("--comment "); - xtables_save_string((const char *)commentinfo->comment); + printf(" --comment"); + xtables_save_string(commentinfo->comment); } static struct xtables_match comment_match = { @@ -95,11 +55,10 @@ static struct xtables_match comment_match = { .size = XT_ALIGN(sizeof(struct xt_comment_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_comment_info)), .help = comment_help, - .parse = comment_parse, - .final_check = comment_check, .print = comment_print, .save = comment_save, - .extra_opts = comment_opts, + .x6_parse = xtables_option_parse, + .x6_options = comment_opts, }; void _init(void) diff --git a/extensions/libxt_connbytes.c b/extensions/libxt_connbytes.c index 5ebdd34..ed2ad25 100644 --- a/extensions/libxt_connbytes.c +++ b/extensions/libxt_connbytes.c @@ -1,13 +1,14 @@ -/* Shared library add-on to iptables to add byte tracking support. */ #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> -#include <linux/netfilter/nf_conntrack_common.h> #include <linux/netfilter/xt_connbytes.h> +enum { + O_CONNBYTES = 0, + O_CONNBYTES_DIR, + O_CONNBYTES_MODE, +}; + static void connbytes_help(void) { printf( @@ -17,105 +18,78 @@ static void connbytes_help(void) " --connbytes-mode [packets, bytes, avgpkt]\n"); } -static const struct option connbytes_opts[] = { - { "connbytes", 1, NULL, '1' }, - { "connbytes-dir", 1, NULL, '2' }, - { "connbytes-mode", 1, NULL, '3' }, - { .name = NULL } +static const struct xt_option_entry connbytes_opts[] = { + {.name = "connbytes", .id = O_CONNBYTES, .type = XTTYPE_UINT64RC, + .flags = XTOPT_MAND | XTOPT_INVERT}, + {.name = "connbytes-dir", .id = O_CONNBYTES_DIR, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "connbytes-mode", .id = O_CONNBYTES_MODE, + .type = XTTYPE_STRING, .flags = XTOPT_MAND}, + XTOPT_TABLEEND, }; -static void -parse_range(const char *arg, struct xt_connbytes_info *si) +static void connbytes_parse(struct xt_option_call *cb) { - char *colon,*p; - - si->count.from = strtoul(arg,&colon,10); - if (*colon != ':') - xtables_error(PARAMETER_PROBLEM, "Bad range \"%s\"", arg); - si->count.to = strtoul(colon+1,&p,10); - if (p == colon+1) { - /* second number omited */ - si->count.to = 0xffffffff; - } - if (si->count.from > si->count.to) - xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu", - (unsigned long long)si->count.from, - (unsigned long long)si->count.to); -} - -static int -connbytes_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct xt_connbytes_info *sinfo = (struct xt_connbytes_info *)(*match)->data; - unsigned long i; - - switch (c) { - case '1': - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) - optind++; - - parse_range(optarg, sinfo); - if (invert) { + struct xt_connbytes_info *sinfo = cb->data; + unsigned long long i; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_CONNBYTES: + sinfo->count.from = cb->val.u64_range[0]; + sinfo->count.to = UINT64_MAX; + if (cb->nvals == 2) + sinfo->count.to = cb->val.u64_range[1]; + + if (sinfo->count.to < sinfo->count.from) + xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu", + (unsigned long long)sinfo->count.from, + (unsigned long long)sinfo->count.to); + if (cb->invert) { i = sinfo->count.from; sinfo->count.from = sinfo->count.to; sinfo->count.to = i; } - *flags |= 1; break; - case '2': - if (!strcmp(optarg, "original")) + case O_CONNBYTES_DIR: + if (strcmp(cb->arg, "original") == 0) sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL; - else if (!strcmp(optarg, "reply")) + else if (strcmp(cb->arg, "reply") == 0) sinfo->direction = XT_CONNBYTES_DIR_REPLY; - else if (!strcmp(optarg, "both")) + else if (strcmp(cb->arg, "both") == 0) sinfo->direction = XT_CONNBYTES_DIR_BOTH; else xtables_error(PARAMETER_PROBLEM, - "Unknown --connbytes-dir `%s'", optarg); - - *flags |= 2; + "Unknown --connbytes-dir `%s'", cb->arg); break; - case '3': - if (!strcmp(optarg, "packets")) + case O_CONNBYTES_MODE: + if (strcmp(cb->arg, "packets") == 0) sinfo->what = XT_CONNBYTES_PKTS; - else if (!strcmp(optarg, "bytes")) + else if (strcmp(cb->arg, "bytes") == 0) sinfo->what = XT_CONNBYTES_BYTES; - else if (!strcmp(optarg, "avgpkt")) + else if (strcmp(cb->arg, "avgpkt") == 0) sinfo->what = XT_CONNBYTES_AVGPKT; else xtables_error(PARAMETER_PROBLEM, - "Unknown --connbytes-mode `%s'", optarg); - *flags |= 4; + "Unknown --connbytes-mode `%s'", cb->arg); break; - default: - return 0; } - - return 1; -} - -static void connbytes_check(unsigned int flags) -{ - if (flags != 7) - xtables_error(PARAMETER_PROBLEM, "You must specify `--connbytes'" - "`--connbytes-dir' and `--connbytes-mode'"); } static void print_mode(const struct xt_connbytes_info *sinfo) { switch (sinfo->what) { case XT_CONNBYTES_PKTS: - fputs("packets ", stdout); + fputs(" packets", stdout); break; case XT_CONNBYTES_BYTES: - fputs("bytes ", stdout); + fputs(" bytes", stdout); break; case XT_CONNBYTES_AVGPKT: - fputs("avgpkt ", stdout); + fputs(" avgpkt", stdout); break; default: - fputs("unknown ", stdout); + fputs(" unknown", stdout); break; } } @@ -124,38 +98,48 @@ static void print_direction(const struct xt_connbytes_info *sinfo) { switch (sinfo->direction) { case XT_CONNBYTES_DIR_ORIGINAL: - fputs("original ", stdout); + fputs(" original", stdout); break; case XT_CONNBYTES_DIR_REPLY: - fputs("reply ", stdout); + fputs(" reply", stdout); break; case XT_CONNBYTES_DIR_BOTH: - fputs("both ", stdout); + fputs(" both", stdout); break; default: - fputs("unknown ", stdout); + fputs(" unknown", stdout); break; } } +static void print_from_to(const struct xt_connbytes_info *sinfo, const char *prefix) +{ + unsigned long long from, to; + + if (sinfo->count.from > sinfo->count.to) { + fputs(" !", stdout); + from = sinfo->count.to; + to = sinfo->count.from; + } else { + to = sinfo->count.to; + from = sinfo->count.from; + } + printf(" %sconnbytes %llu", prefix, from); + if (to && to < UINT64_MAX) + printf(":%llu", to); +} + static void connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_connbytes_info *sinfo = (const void *)match->data; - if (sinfo->count.from > sinfo->count.to) - printf("connbytes ! %llu:%llu ", - (unsigned long long)sinfo->count.to, - (unsigned long long)sinfo->count.from); - else - printf("connbytes %llu:%llu ", - (unsigned long long)sinfo->count.from, - (unsigned long long)sinfo->count.to); + print_from_to(sinfo, ""); - fputs("connbytes mode ", stdout); + fputs(" connbytes mode", stdout); print_mode(sinfo); - fputs("connbytes direction ", stdout); + fputs(" connbytes direction", stdout); print_direction(sinfo); } @@ -163,19 +147,12 @@ static void connbytes_save(const void *ip, const struct xt_entry_match *match) { const struct xt_connbytes_info *sinfo = (const void *)match->data; - if (sinfo->count.from > sinfo->count.to) - printf("! --connbytes %llu:%llu ", - (unsigned long long)sinfo->count.to, - (unsigned long long)sinfo->count.from); - else - printf("--connbytes %llu:%llu ", - (unsigned long long)sinfo->count.from, - (unsigned long long)sinfo->count.to); + print_from_to(sinfo, "--"); - fputs("--connbytes-mode ", stdout); + fputs(" --connbytes-mode", stdout); print_mode(sinfo); - fputs("--connbytes-dir ", stdout); + fputs(" --connbytes-dir", stdout); print_direction(sinfo); } @@ -186,11 +163,10 @@ static struct xtables_match connbytes_match = { .size = XT_ALIGN(sizeof(struct xt_connbytes_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_connbytes_info)), .help = connbytes_help, - .parse = connbytes_parse, - .final_check = connbytes_check, .print = connbytes_print, .save = connbytes_save, - .extra_opts = connbytes_opts, + .x6_parse = connbytes_parse, + .x6_options = connbytes_opts, }; void _init(void) diff --git a/extensions/libxt_connlabel.c b/extensions/libxt_connlabel.c new file mode 100644 index 0000000..c84a167 --- /dev/null +++ b/extensions/libxt_connlabel.c @@ -0,0 +1,124 @@ +#include <errno.h> +#include <stdbool.h> +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <xtables.h> +#include <linux/netfilter/xt_connlabel.h> +#include <libnetfilter_conntrack/libnetfilter_conntrack.h> + +enum { + O_LABEL = 0, + O_SET = 1, +}; + +static struct nfct_labelmap *map; + +static void connlabel_mt_help(void) +{ + puts( +"connlabel match options:\n" +"[!] --label name Match if label has been set on connection\n" +" --set Set label on connection"); +} + +static const struct xt_option_entry connlabel_mt_opts[] = { + {.name = "label", .id = O_LABEL, .type = XTTYPE_STRING, + .min = 1, .flags = XTOPT_MAND|XTOPT_INVERT}, + {.name = "set", .id = O_SET, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static void connlabel_mt_parse(struct xt_option_call *cb) +{ + struct xt_connlabel_mtinfo *info = cb->data; + int tmp; + + xtables_option_parse(cb); + + switch (cb->entry->id) { + case O_LABEL: + tmp = nfct_labelmap_get_bit(map, cb->arg); + if (tmp < 0) + xtables_error(PARAMETER_PROBLEM, "label '%s' not found", cb->arg); + info->bit = tmp; + if (cb->invert) + info->options |= XT_CONNLABEL_OP_INVERT; + break; + case O_SET: + info->options |= XT_CONNLABEL_OP_SET; + break; + } + +} + +static const char *connlabel_get_name(int b) +{ + const char *name = nfct_labelmap_get_name(map, b); + if (name && strcmp(name, "")) + return name; + return NULL; +} + +static void +connlabel_mt_print_op(const struct xt_connlabel_mtinfo *info, const char *prefix) +{ + if (info->options & XT_CONNLABEL_OP_SET) + printf(" %sset", prefix); +} + +static void +connlabel_mt_print(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_connlabel_mtinfo *info = (const void *)match->data; + const char *name = connlabel_get_name(info->bit); + + printf(" connlabel"); + if (info->options & XT_CONNLABEL_OP_INVERT) + printf(" !"); + if (numeric || name == NULL) { + printf(" %u", info->bit); + } else { + printf(" '%s'", name); + } + connlabel_mt_print_op(info, ""); +} + +static void +connlabel_mt_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_connlabel_mtinfo *info = (const void *)match->data; + const char *name = connlabel_get_name(info->bit); + + if (info->options & XT_CONNLABEL_OP_INVERT) + printf(" !"); + if (name) + printf(" --label \"%s\"", name); + else + printf(" --label \"%u\"", info->bit); + connlabel_mt_print_op(info, "--"); +} + +static struct xtables_match connlabel_mt_reg = { + .family = NFPROTO_UNSPEC, + .name = "connlabel", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_connlabel_mtinfo)), + .userspacesize = offsetof(struct xt_connlabel_mtinfo, bit), + .help = connlabel_mt_help, + .print = connlabel_mt_print, + .save = connlabel_mt_save, + .x6_parse = connlabel_mt_parse, + .x6_options = connlabel_mt_opts, +}; + +void _init(void) +{ + map = nfct_labelmap_new(NULL); + if (!map) { + fprintf(stderr, "cannot open connlabel.conf, not registering '%s' match: %s\n", + connlabel_mt_reg.name, strerror(errno)); + return; + } + xtables_register_match(&connlabel_mt_reg); +} diff --git a/extensions/libxt_connlabel.man b/extensions/libxt_connlabel.man new file mode 100644 index 0000000..bdaa51e --- /dev/null +++ b/extensions/libxt_connlabel.man @@ -0,0 +1,33 @@ +Module matches or adds connlabels to a connection. +connlabels are similar to connmarks, except labels are bit-based; i.e. +all labels may be attached to a flow at the same time. +Up to 128 unique labels are currently supported. +.TP +[\fB!\fP] \fB\-\-label\fP \fBname\fP +matches if label \fBname\fP has been set on a connection. +Instead of a name (which will be translated to a number, see EXAMPLE below), +a number may be used instead. Using a number always overrides connlabel.conf. +.TP +\fB\-\-set\fP +if the label has not been set on the connection, set it. +Note that setting a label can fail. This is because the kernel allocates the +conntrack label storage area when the connection is created, and it only +reserves the amount of memory required by the ruleset that exists at +the time the connection is created. +In this case, the match will fail (or succeed, in case \fB\-\-label\fP +option was negated). +.PP +This match depends on libnetfilter_conntrack 1.0.4 or later. +Label translation is done via the \fB/etc/xtables/connlabel.conf\fP configuration file. +.PP +Example: +.IP +.nf +0 eth0-in +1 eth0-out +2 ppp-in +3 ppp-out +4 bulk-traffic +5 interactive +.fi +.PP diff --git a/extensions/libxt_connlimit.c b/extensions/libxt_connlimit.c index a215915..a569f86 100644 --- a/extensions/libxt_connlimit.c +++ b/extensions/libxt_connlimit.c @@ -1,27 +1,50 @@ -/* Shared library add-on to iptables to add connection limit support. */ #include <stdio.h> #include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <stddef.h> -#include <getopt.h> #include <xtables.h> #include <linux/netfilter/xt_connlimit.h> +enum { + O_UPTO = 0, + O_ABOVE, + O_MASK, + O_SADDR, + O_DADDR, + F_UPTO = 1 << O_UPTO, + F_ABOVE = 1 << O_ABOVE, + F_MASK = 1 << O_MASK, + F_SADDR = 1 << O_SADDR, + F_DADDR = 1 << O_DADDR, +}; + static void connlimit_help(void) { printf( "connlimit match options:\n" -"[!] --connlimit-above n match if the number of existing " -" connections is (not) above n\n" -" --connlimit-mask n group hosts using mask\n"); +" --connlimit-upto n match if the number of existing connections is 0..n\n" +" --connlimit-above n match if the number of existing connections is >n\n" +" --connlimit-mask n group hosts using prefix length (default: max len)\n" +" --connlimit-saddr select source address for grouping\n" +" --connlimit-daddr select destination addresses for grouping\n"); } -static const struct option connlimit_opts[] = { - {"connlimit-above", 1, NULL, 'A'}, - {"connlimit-mask", 1, NULL, 'M'}, - { .name = NULL } +#define s struct xt_connlimit_info +static const struct xt_option_entry connlimit_opts[] = { + {.name = "connlimit-upto", .id = O_UPTO, .excl = F_ABOVE, + .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, limit)}, + {.name = "connlimit-above", .id = O_ABOVE, .excl = F_UPTO, + .type = XTTYPE_UINT32, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, limit)}, + {.name = "connlimit-mask", .id = O_MASK, .type = XTTYPE_PLENMASK, + .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)}, + {.name = "connlimit-saddr", .id = O_SADDR, .excl = F_DADDR, + .type = XTTYPE_NONE}, + {.name = "connlimit-daddr", .id = O_DADDR, .excl = F_SADDR, + .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s static void connlimit_init(struct xt_entry_match *match) { @@ -31,99 +54,57 @@ static void connlimit_init(struct xt_entry_match *match) memset(info->v6_mask, 0xFF, sizeof(info->v6_mask)); } -static void prefix_to_netmask(u_int32_t *mask, unsigned int prefix_len) -{ - if (prefix_len == 0) { - mask[0] = mask[1] = mask[2] = mask[3] = 0; - } else if (prefix_len <= 32) { - mask[0] <<= 32 - prefix_len; - mask[1] = mask[2] = mask[3] = 0; - } else if (prefix_len <= 64) { - mask[1] <<= 32 - (prefix_len - 32); - mask[2] = mask[3] = 0; - } else if (prefix_len <= 96) { - mask[2] <<= 32 - (prefix_len - 64); - mask[3] = 0; - } else if (prefix_len <= 128) { - mask[3] <<= 32 - (prefix_len - 96); - } - mask[0] = htonl(mask[0]); - mask[1] = htonl(mask[1]); - mask[2] = htonl(mask[2]); - mask[3] = htonl(mask[3]); -} - -static int connlimit_parse(int c, char **argv, int invert, unsigned int *flags, - struct xt_connlimit_info *info, unsigned int family) +static void connlimit_parse(struct xt_option_call *cb, uint8_t family) { - char *err; - int i; - - switch (c) { - case 'A': - if (*flags & 0x1) + struct xt_connlimit_info *info = cb->data; + const unsigned int revision = (*cb->match)->u.user.revision; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_ABOVE: + if (cb->invert) + info->flags |= XT_CONNLIMIT_INVERT; + break; + case O_UPTO: + if (!cb->invert) + info->flags |= XT_CONNLIMIT_INVERT; + break; + case O_SADDR: + if (revision < 1) xtables_error(PARAMETER_PROBLEM, - "--connlimit-above may be given only once"); - *flags |= 0x1; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - info->limit = strtoul(optarg, NULL, 0); - info->inverse = invert; + "xt_connlimit.0 does not support " + "--connlimit-daddr"); + info->flags &= ~XT_CONNLIMIT_DADDR; break; - case 'M': - if (*flags & 0x2) + case O_DADDR: + if (revision < 1) xtables_error(PARAMETER_PROBLEM, - "--connlimit-mask may be given only once"); - - *flags |= 0x2; - i = strtoul(optarg, &err, 0); - if (family == NFPROTO_IPV6) { - if (i > 128 || *err != '\0') - xtables_error(PARAMETER_PROBLEM, - "--connlimit-mask must be between " - "0 and 128"); - prefix_to_netmask(info->v6_mask, i); - } else { - if (i > 32 || *err != '\0') - xtables_error(PARAMETER_PROBLEM, - "--connlimit-mask must be between " - "0 and 32"); - if (i == 0) - info->v4_mask = 0; - else - info->v4_mask = htonl(0xFFFFFFFF << (32 - i)); - } + "xt_connlimit.0 does not support " + "--connlimit-daddr"); + info->flags |= XT_CONNLIMIT_DADDR; break; - default: - return 0; } - - return 1; } -static int connlimit_parse4(int c, char **argv, int invert, - unsigned int *flags, const void *entry, - struct xt_entry_match **match) +static void connlimit_parse4(struct xt_option_call *cb) { - return connlimit_parse(c, argv, invert, flags, - (void *)(*match)->data, NFPROTO_IPV4); + return connlimit_parse(cb, NFPROTO_IPV4); } -static int connlimit_parse6(int c, char **argv, int invert, - unsigned int *flags, const void *entry, - struct xt_entry_match **match) +static void connlimit_parse6(struct xt_option_call *cb) { - return connlimit_parse(c, argv, invert, flags, - (void *)(*match)->data, NFPROTO_IPV6); + return connlimit_parse(cb, NFPROTO_IPV6); } -static void connlimit_check(unsigned int flags) +static void connlimit_check(struct xt_fcheck_call *cb) { - if (!(flags & 0x1)) + if ((cb->xflags & (F_UPTO | F_ABOVE)) == 0) xtables_error(PARAMETER_PROBLEM, - "You must specify \"--connlimit-above\""); + "You must specify \"--connlimit-above\" or " + "\"--connlimit-upto\"."); } -static unsigned int count_bits4(u_int32_t mask) +static unsigned int count_bits4(uint32_t mask) { unsigned int bits = 0; @@ -133,10 +114,10 @@ static unsigned int count_bits4(u_int32_t mask) return 32 - bits; } -static unsigned int count_bits6(const u_int32_t *mask) +static unsigned int count_bits6(const uint32_t *mask) { unsigned int bits = 0, i; - u_int32_t tmp[4]; + uint32_t tmp[4]; for (i = 0; i < 4; ++i) for (tmp[i] = ~ntohl(mask[i]); tmp[i] != 0; tmp[i] >>= 1) @@ -149,64 +130,119 @@ static void connlimit_print4(const void *ip, { const struct xt_connlimit_info *info = (const void *)match->data; - printf("#conn/%u %s %u ", count_bits4(info->v4_mask), - info->inverse ? "<=" : ">", info->limit); + printf(" #conn %s/%u %s %u", + (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src", + count_bits4(info->v4_mask), + (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit); } static void connlimit_print6(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_connlimit_info *info = (const void *)match->data; - printf("#conn/%u %s %u ", count_bits6(info->v6_mask), - info->inverse ? "<=" : ">", info->limit); + + printf(" #conn %s/%u %s %u", + (info->flags & XT_CONNLIMIT_DADDR) ? "dst" : "src", + count_bits6(info->v6_mask), + (info->flags & XT_CONNLIMIT_INVERT) ? "<=" : ">", info->limit); } static void connlimit_save4(const void *ip, const struct xt_entry_match *match) { const struct xt_connlimit_info *info = (const void *)match->data; - - printf("%s--connlimit-above %u --connlimit-mask %u ", - info->inverse ? "! " : "", info->limit, - count_bits4(info->v4_mask)); + const int revision = match->u.user.revision; + + if (info->flags & XT_CONNLIMIT_INVERT) + printf(" --connlimit-upto %u", info->limit); + else + printf(" --connlimit-above %u", info->limit); + printf(" --connlimit-mask %u", count_bits4(info->v4_mask)); + if (revision >= 1) { + if (info->flags & XT_CONNLIMIT_DADDR) + printf(" --connlimit-daddr"); + else + printf(" --connlimit-saddr"); + } } static void connlimit_save6(const void *ip, const struct xt_entry_match *match) { const struct xt_connlimit_info *info = (const void *)match->data; - - printf("%s--connlimit-above %u --connlimit-mask %u ", - info->inverse ? "! " : "", info->limit, - count_bits6(info->v6_mask)); + const int revision = match->u.user.revision; + + if (info->flags & XT_CONNLIMIT_INVERT) + printf(" --connlimit-upto %u", info->limit); + else + printf(" --connlimit-above %u", info->limit); + printf(" --connlimit-mask %u", count_bits6(info->v6_mask)); + if (revision >= 1) { + if (info->flags & XT_CONNLIMIT_DADDR) + printf(" --connlimit-daddr"); + else + printf(" --connlimit-saddr"); + } } static struct xtables_match connlimit_mt_reg[] = { { .name = "connlimit", + .revision = 0, + .family = NFPROTO_IPV4, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), + .userspacesize = offsetof(struct xt_connlimit_info, data), + .help = connlimit_help, + .init = connlimit_init, + .x6_parse = connlimit_parse4, + .x6_fcheck = connlimit_check, + .print = connlimit_print4, + .save = connlimit_save4, + .x6_options = connlimit_opts, + }, + { + .name = "connlimit", + .revision = 0, + .family = NFPROTO_IPV6, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), + .userspacesize = offsetof(struct xt_connlimit_info, data), + .help = connlimit_help, + .init = connlimit_init, + .x6_parse = connlimit_parse6, + .x6_fcheck = connlimit_check, + .print = connlimit_print6, + .save = connlimit_save6, + .x6_options = connlimit_opts, + }, + { + .name = "connlimit", + .revision = 1, .family = NFPROTO_IPV4, .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), .userspacesize = offsetof(struct xt_connlimit_info, data), .help = connlimit_help, .init = connlimit_init, - .parse = connlimit_parse4, - .final_check = connlimit_check, + .x6_parse = connlimit_parse4, + .x6_fcheck = connlimit_check, .print = connlimit_print4, .save = connlimit_save4, - .extra_opts = connlimit_opts, + .x6_options = connlimit_opts, }, { .name = "connlimit", + .revision = 1, .family = NFPROTO_IPV6, .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_connlimit_info)), .userspacesize = offsetof(struct xt_connlimit_info, data), .help = connlimit_help, .init = connlimit_init, - .parse = connlimit_parse6, - .final_check = connlimit_check, + .x6_parse = connlimit_parse6, + .x6_fcheck = connlimit_check, .print = connlimit_print6, .save = connlimit_save6, - .extra_opts = connlimit_opts, + .x6_options = connlimit_opts, }, }; diff --git a/extensions/libxt_connlimit.man b/extensions/libxt_connlimit.man index c85d768..ad9f40f 100644 --- a/extensions/libxt_connlimit.man +++ b/extensions/libxt_connlimit.man @@ -1,23 +1,34 @@ Allows you to restrict the number of parallel connections to a server per client IP address (or client address block). .TP -[\fB!\fP] \fB\-\-connlimit\-above\fP \fIn\fP -Match if the number of existing connections is (not) above \fIn\fR. +\fB\-\-connlimit\-upto\fP \fIn\fP +Match if the number of existing connections is below or equal \fIn\fP. +.TP +\fB\-\-connlimit\-above\fP \fIn\fP +Match if the number of existing connections is above \fIn\fP. .TP \fB\-\-connlimit\-mask\fP \fIprefix_length\fP Group hosts using the prefix length. For IPv4, this must be a number between -(including) 0 and 32. For IPv6, between 0 and 128. -.P +(including) 0 and 32. For IPv6, between 0 and 128. If not specified, the +maximum prefix length for the applicable protocol is used. +.TP +\fB\-\-connlimit\-saddr\fP +Apply the limit onto the source group. This is the default if +\-\-connlimit\-daddr is not specified. +.TP +\fB\-\-connlimit\-daddr\fP +Apply the limit onto the destination group. +.PP Examples: .TP # allow 2 telnet connections per client host iptables \-A INPUT \-p tcp \-\-syn \-\-dport 23 \-m connlimit \-\-connlimit\-above 2 \-j REJECT .TP # you can also match the other way around: -iptables \-A INPUT \-p tcp \-\-syn \-\-dport 23 \-m connlimit ! \-\-connlimit\-above 2 \-j ACCEPT +iptables \-A INPUT \-p tcp \-\-syn \-\-dport 23 \-m connlimit \-\-connlimit\-upto 2 \-j ACCEPT .TP # limit the number of parallel HTTP requests to 16 per class C sized \ -network (24 bit netmask) +source network (24 bit netmask) iptables \-p tcp \-\-syn \-\-dport 80 \-m connlimit \-\-connlimit\-above 16 \-\-connlimit\-mask 24 \-j REJECT .TP @@ -25,3 +36,7 @@ iptables \-p tcp \-\-syn \-\-dport 80 \-m connlimit \-\-connlimit\-above 16 (ipv6) ip6tables \-p tcp \-\-syn \-\-dport 80 \-s fe80::/64 \-m connlimit \-\-connlimit\-above 16 \-\-connlimit\-mask 64 \-j REJECT +.TP +# Limit the number of connections to a particular host: +ip6tables \-p tcp \-\-syn \-\-dport 49152:65535 \-d 2001:db8::1 \-m connlimit +\-\-connlimit-above 100 \-j REJECT diff --git a/extensions/libxt_connmark.c b/extensions/libxt_connmark.c index 38aa563..6f1d532 100644 --- a/extensions/libxt_connmark.c +++ b/extensions/libxt_connmark.c @@ -19,22 +19,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <stdbool.h> +#include <stdint.h> #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_connmark.h> struct xt_connmark_info { unsigned long mark, mask; - u_int8_t invert; + uint8_t invert; }; enum { - F_MARK = 1 << 0, + O_MARK = 0, }; static void connmark_mt_help(void) @@ -44,83 +41,40 @@ static void connmark_mt_help(void) "[!] --mark value[/mask] Match ctmark value with optional mask\n"); } -static const struct option connmark_mt_opts[] = { - {.name = "mark", .has_arg = true, .val = '1'}, - { .name = NULL } +static const struct xt_option_entry connmark_mt_opts[] = { + {.name = "mark", .id = O_MARK, .type = XTTYPE_MARKMASK32, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; -static int -connmark_mt_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void connmark_mt_parse(struct xt_option_call *cb) { - struct xt_connmark_mtinfo1 *info = (void *)(*match)->data; - unsigned int mark, mask = UINT32_MAX; - char *end; - - switch (c) { - case '1': /* --mark */ - xtables_param_act(XTF_ONLY_ONCE, "connmark", "--mark", *flags & F_MARK); - if (!xtables_strtoui(optarg, &end, &mark, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg); - if (*end == '/') - if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg); - if (*end != '\0') - xtables_param_act(XTF_BAD_VALUE, "connmark", "--mark", optarg); - - if (invert) - info->invert = true; - info->mark = mark; - info->mask = mask; - *flags |= F_MARK; - return true; - } - return false; + struct xt_connmark_mtinfo1 *info = cb->data; + + xtables_option_parse(cb); + if (cb->invert) + info->invert = true; + info->mark = cb->val.mark; + info->mask = cb->val.mask; } -static int -connmark_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void connmark_parse(struct xt_option_call *cb) { - struct xt_connmark_info *markinfo = (struct xt_connmark_info *)(*match)->data; - - switch (c) { - char *end; - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - markinfo->mark = strtoul(optarg, &end, 0); - markinfo->mask = 0xffffffffUL; - - if (*end == '/') - markinfo->mask = strtoul(end+1, &end, 0); - - if (*end != '\0' || end == optarg) - xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); - if (invert) - markinfo->invert = 1; - *flags = 1; - break; - - default: - return 0; - } - return 1; + struct xt_connmark_info *markinfo = cb->data; + + xtables_option_parse(cb); + markinfo->mark = cb->val.mark; + markinfo->mask = cb->val.mask; + if (cb->invert) + markinfo->invert = 1; } static void print_mark(unsigned int mark, unsigned int mask) { if (mask != 0xffffffffU) - printf("0x%x/0x%x ", mark, mask); + printf(" 0x%x/0x%x", mark, mask); else - printf("0x%x ", mark); -} - -static void connmark_mt_check(unsigned int flags) -{ - if (flags == 0) - xtables_error(PARAMETER_PROBLEM, - "connmark: The --mark option is required"); + printf(" 0x%x", mark); } static void @@ -128,7 +82,7 @@ connmark_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_connmark_info *info = (const void *)match->data; - printf("CONNMARK match "); + printf(" CONNMARK match "); if (info->invert) printf("!"); print_mark(info->mark, info->mask); @@ -139,7 +93,7 @@ connmark_mt_print(const void *ip, const struct xt_entry_match *match, int numeri { const struct xt_connmark_mtinfo1 *info = (const void *)match->data; - printf("connmark match "); + printf(" connmark match "); if (info->invert) printf("!"); print_mark(info->mark, info->mask); @@ -150,9 +104,9 @@ static void connmark_save(const void *ip, const struct xt_entry_match *match) const struct xt_connmark_info *info = (const void *)match->data; if (info->invert) - printf("! "); + printf(" !"); - printf("--mark "); + printf(" --mark"); print_mark(info->mark, info->mask); } @@ -162,9 +116,9 @@ connmark_mt_save(const void *ip, const struct xt_entry_match *match) const struct xt_connmark_mtinfo1 *info = (const void *)match->data; if (info->invert) - printf("! "); + printf(" !"); - printf("--mark "); + printf(" --mark"); print_mark(info->mark, info->mask); } @@ -177,11 +131,10 @@ static struct xtables_match connmark_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_connmark_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_info)), .help = connmark_mt_help, - .parse = connmark_parse, - .final_check = connmark_mt_check, .print = connmark_print, .save = connmark_save, - .extra_opts = connmark_mt_opts, + .x6_parse = connmark_parse, + .x6_options = connmark_mt_opts, }, { .version = XTABLES_VERSION, @@ -191,11 +144,10 @@ static struct xtables_match connmark_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)), .userspacesize = XT_ALIGN(sizeof(struct xt_connmark_mtinfo1)), .help = connmark_mt_help, - .parse = connmark_mt_parse, - .final_check = connmark_mt_check, .print = connmark_mt_print, .save = connmark_mt_save, - .extra_opts = connmark_mt_opts, + .x6_parse = connmark_mt_parse, + .x6_options = connmark_mt_opts, }, }; diff --git a/extensions/libxt_connmark.man b/extensions/libxt_connmark.man index ee87d9e..4e83801 100644 --- a/extensions/libxt_connmark.man +++ b/extensions/libxt_connmark.man @@ -1,5 +1,5 @@ This module matches the netfilter mark field associated with a connection -(which can be set using the \fBCONNMARK\fR target below). +(which can be set using the \fBCONNMARK\fP target below). .TP [\fB!\fP] \fB\-\-mark\fP \fIvalue\fP[\fB/\fP\fImask\fP] Matches packets in connections with the given mark value (if a mask is diff --git a/extensions/libxt_conntrack.c b/extensions/libxt_conntrack.c index 5557d3e..128bbd2 100644 --- a/extensions/libxt_conntrack.c +++ b/extensions/libxt_conntrack.c @@ -6,21 +6,18 @@ * Copyright © CC Computer Consultants GmbH, 2007 - 2008 * Jan Engelhardt <jengelh@computergmbh.de> */ -#include <sys/socket.h> -#include <sys/types.h> -#include <ctype.h> -#include <getopt.h> -#include <netdb.h> #include <stdbool.h> -#include <stddef.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <xtables.h> -#include <linux/netfilter.h> #include <linux/netfilter/xt_conntrack.h> +#include <linux/netfilter/xt_state.h> #include <linux/netfilter/nf_conntrack_common.h> -#include <arpa/inet.h> +#ifndef XT_STATE_UNTRACKED +#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1)) +#endif struct ip_conntrack_old_tuple { struct { @@ -50,9 +47,25 @@ struct xt_conntrack_info { unsigned long expires_min, expires_max; /* Flags word */ - u_int8_t flags; + uint8_t flags; /* Inverse flags */ - u_int8_t invflags; + uint8_t invflags; +}; + +enum { + O_CTSTATE = 0, + O_CTPROTO, + O_CTORIGSRC, + O_CTORIGDST, + O_CTREPLSRC, + O_CTREPLDST, + O_CTORIGSRCPORT, + O_CTORIGDSTPORT, + O_CTREPLSRCPORT, + O_CTREPLDSTPORT, + O_CTSTATUS, + O_CTEXPIRE, + O_CTDIR, }; static void conntrack_mt_help(void) @@ -79,34 +92,98 @@ static void conntrack_mt_help(void) " --ctdir {ORIGINAL|REPLY} Flow direction of packet\n"); } -static const struct option conntrack_mt_opts_v0[] = { - {.name = "ctstate", .has_arg = true, .val = '1'}, - {.name = "ctproto", .has_arg = true, .val = '2'}, - {.name = "ctorigsrc", .has_arg = true, .val = '3'}, - {.name = "ctorigdst", .has_arg = true, .val = '4'}, - {.name = "ctreplsrc", .has_arg = true, .val = '5'}, - {.name = "ctrepldst", .has_arg = true, .val = '6'}, - {.name = "ctstatus", .has_arg = true, .val = '7'}, - {.name = "ctexpire", .has_arg = true, .val = '8'}, - { .name = NULL } +#define s struct xt_conntrack_info /* for v0 */ +static const struct xt_option_entry conntrack_mt_opts_v0[] = { + {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL, + .flags = XTOPT_INVERT}, + {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOST, + .flags = XTOPT_INVERT}, + {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOST, + .flags = XTOPT_INVERT}, + {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOST, + .flags = XTOPT_INVERT}, + {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOST, + .flags = XTOPT_INVERT}, + {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, }; - -static const struct option conntrack_mt_opts[] = { - {.name = "ctstate", .has_arg = true, .val = '1'}, - {.name = "ctproto", .has_arg = true, .val = '2'}, - {.name = "ctorigsrc", .has_arg = true, .val = '3'}, - {.name = "ctorigdst", .has_arg = true, .val = '4'}, - {.name = "ctreplsrc", .has_arg = true, .val = '5'}, - {.name = "ctrepldst", .has_arg = true, .val = '6'}, - {.name = "ctstatus", .has_arg = true, .val = '7'}, - {.name = "ctexpire", .has_arg = true, .val = '8'}, - {.name = "ctorigsrcport", .has_arg = true, .val = 'a'}, - {.name = "ctorigdstport", .has_arg = true, .val = 'b'}, - {.name = "ctreplsrcport", .has_arg = true, .val = 'c'}, - {.name = "ctrepldstport", .has_arg = true, .val = 'd'}, - {.name = "ctdir", .has_arg = true, .val = 'e'}, - {.name = NULL}, +#undef s + +#define s struct xt_conntrack_mtinfo2 +/* We exploit the fact that v1-v2 share the same xt_o_e layout */ +static const struct xt_option_entry conntrack2_mt_opts[] = { + {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL, + .flags = XTOPT_INVERT}, + {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT}, + /* + * Rev 1 and 2 only store one port, and we would normally use + * %XTTYPE_PORT (rather than %XTTYPE_PORTRC) for that. The resulting + * error message - in case a user passed a range nevertheless - + * "port 22:23 resolved to nothing" is not quite as useful as using + * %XTTYPE_PORTC and libxt_conntrack's own range test. + */ + {.name = "ctorigsrcport", .id = O_CTORIGSRCPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_NBO}, + {.name = "ctorigdstport", .id = O_CTORIGDSTPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_NBO}, + {.name = "ctreplsrcport", .id = O_CTREPLSRCPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_NBO}, + {.name = "ctrepldstport", .id = O_CTREPLDSTPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_NBO}, + {.name = "ctdir", .id = O_CTDIR, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, +}; +#undef s + +#define s struct xt_conntrack_mtinfo3 +/* Difference from v2 is the non-NBO form. */ +static const struct xt_option_entry conntrack3_mt_opts[] = { + {.name = "ctstate", .id = O_CTSTATE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "ctproto", .id = O_CTPROTO, .type = XTTYPE_PROTOCOL, + .flags = XTOPT_INVERT}, + {.name = "ctorigsrc", .id = O_CTORIGSRC, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctorigdst", .id = O_CTORIGDST, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctreplsrc", .id = O_CTREPLSRC, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctrepldst", .id = O_CTREPLDST, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "ctstatus", .id = O_CTSTATUS, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "ctexpire", .id = O_CTEXPIRE, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT}, + {.name = "ctorigsrcport", .id = O_CTORIGSRCPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT}, + {.name = "ctorigdstport", .id = O_CTORIGDSTPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT}, + {.name = "ctreplsrcport", .id = O_CTREPLSRCPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT}, + {.name = "ctrepldstport", .id = O_CTREPLDSTPORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT}, + {.name = "ctdir", .id = O_CTDIR, .type = XTTYPE_STRING}, + XTOPT_TABLEEND, }; +#undef s static int parse_state(const char *state, size_t len, struct xt_conntrack_info *sinfo) @@ -149,7 +226,7 @@ parse_states(const char *arg, struct xt_conntrack_info *sinfo) } static bool -conntrack_ps_state(struct xt_conntrack_mtinfo2 *info, const char *state, +conntrack_ps_state(struct xt_conntrack_mtinfo3 *info, const char *state, size_t z) { if (strncasecmp(state, "INVALID", z) == 0) @@ -172,7 +249,7 @@ conntrack_ps_state(struct xt_conntrack_mtinfo2 *info, const char *state, } static void -conntrack_ps_states(struct xt_conntrack_mtinfo2 *info, const char *arg) +conntrack_ps_states(struct xt_conntrack_mtinfo3 *info, const char *arg) { const char *comma; @@ -223,7 +300,7 @@ parse_statuses(const char *arg, struct xt_conntrack_info *sinfo) } static bool -conntrack_ps_status(struct xt_conntrack_mtinfo2 *info, const char *status, +conntrack_ps_status(struct xt_conntrack_mtinfo3 *info, const char *status, size_t z) { if (strncasecmp(status, "NONE", z) == 0) @@ -242,7 +319,7 @@ conntrack_ps_status(struct xt_conntrack_mtinfo2 *info, const char *status, } static void -conntrack_ps_statuses(struct xt_conntrack_mtinfo2 *info, const char *arg) +conntrack_ps_statuses(struct xt_conntrack_mtinfo3 *info, const char *arg) { const char *comma; @@ -257,103 +334,21 @@ conntrack_ps_statuses(struct xt_conntrack_mtinfo2 *info, const char *arg) xtables_error(PARAMETER_PROBLEM, "Bad ctstatus \"%s\"", arg); } -static unsigned long -parse_expire(const char *s) -{ - unsigned int len; - - if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, "expire value invalid: \"%s\"\n", s); - else - return len; -} - -/* If a single value is provided, min and max are both set to the value */ -static void -parse_expires(const char *s, struct xt_conntrack_info *sinfo) -{ - char *buffer; - char *cp; - - buffer = strdup(s); - if ((cp = strchr(buffer, ':')) == NULL) - sinfo->expires_min = sinfo->expires_max = - parse_expire(buffer); - else { - *cp = '\0'; - cp++; - - sinfo->expires_min = buffer[0] ? parse_expire(buffer) : 0; - sinfo->expires_max = cp[0] - ? parse_expire(cp) - : (unsigned long)-1; - } - free(buffer); - - if (sinfo->expires_min > sinfo->expires_max) - xtables_error(PARAMETER_PROBLEM, - "expire min. range value `%lu' greater than max. " - "range value `%lu'", sinfo->expires_min, sinfo->expires_max); -} - -static void -conntrack_ps_expires(struct xt_conntrack_mtinfo2 *info, const char *s) -{ - unsigned int min, max; - char *end; - - if (!xtables_strtoui(s, &end, &min, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); - max = min; - if (*end == ':') - if (!xtables_strtoui(end + 1, &end, &max, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); - if (*end != '\0') - xtables_param_act(XTF_BAD_VALUE, "conntrack", "--expires", s); - - if (min > max) - xtables_error(PARAMETER_PROBLEM, - "expire min. range value \"%u\" greater than max. " - "range value \"%u\"", min, max); - - info->expires_min = min; - info->expires_max = max; -} - -static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void conntrack_parse(struct xt_option_call *cb) { - struct xt_conntrack_info *sinfo = (void *)(*match)->data; - char *protocol = NULL; - unsigned int naddrs = 0; - struct in_addr *addrs = NULL; - + struct xt_conntrack_info *sinfo = cb->data; - switch (c) { - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - parse_states(optarg, sinfo); - if (invert) { + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_CTSTATE: + parse_states(cb->arg, sinfo); + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_STATE; - } - sinfo->flags |= XT_CONNTRACK_STATE; break; - - case '2': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if(invert) + case O_CTPROTO: + sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = cb->val.protocol; + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_PROTO; - - /* Canonicalize into lower case */ - for (protocol = optarg; *protocol; protocol++) - *protocol = tolower(*protocol); - - protocol = optarg; - sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum = - xtables_parse_protocol(protocol); - if (sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum == 0 && (sinfo->invflags & XT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, @@ -361,356 +356,153 @@ static int conntrack_parse(int c, char **argv, int invert, unsigned int *flags, sinfo->flags |= XT_CONNTRACK_PROTO; break; - - case '3': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if (invert) + case O_CTORIGSRC: + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_ORIGSRC; - - xtables_ipparse_any(optarg, &addrs, - &sinfo->sipmsk[IP_CT_DIR_ORIGINAL], - &naddrs); - if(naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - - if(naddrs == 1) { - sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = addrs[0].s_addr; - } - + sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip = cb->val.haddr.ip; sinfo->flags |= XT_CONNTRACK_ORIGSRC; break; - - case '4': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if (invert) + case O_CTORIGDST: + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_ORIGDST; - - xtables_ipparse_any(optarg, &addrs, - &sinfo->dipmsk[IP_CT_DIR_ORIGINAL], - &naddrs); - if(naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - - if(naddrs == 1) { - sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = addrs[0].s_addr; - } - + sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip = cb->val.haddr.ip; sinfo->flags |= XT_CONNTRACK_ORIGDST; break; - - case '5': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if (invert) + case O_CTREPLSRC: + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_REPLSRC; - - xtables_ipparse_any(optarg, &addrs, - &sinfo->sipmsk[IP_CT_DIR_REPLY], - &naddrs); - if(naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - - if(naddrs == 1) { - sinfo->tuple[IP_CT_DIR_REPLY].src.ip = addrs[0].s_addr; - } - + sinfo->tuple[IP_CT_DIR_REPLY].src.ip = cb->val.haddr.ip; sinfo->flags |= XT_CONNTRACK_REPLSRC; break; - - case '6': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - if (invert) + case O_CTREPLDST: + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_REPLDST; - - xtables_ipparse_any(optarg, &addrs, - &sinfo->dipmsk[IP_CT_DIR_REPLY], - &naddrs); - if(naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - - if(naddrs == 1) { - sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = addrs[0].s_addr; - } - + sinfo->tuple[IP_CT_DIR_REPLY].dst.ip = cb->val.haddr.ip; sinfo->flags |= XT_CONNTRACK_REPLDST; break; - - case '7': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - parse_statuses(optarg, sinfo); - if (invert) { + case O_CTSTATUS: + parse_statuses(cb->arg, sinfo); + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_STATUS; - } sinfo->flags |= XT_CONNTRACK_STATUS; break; - - case '8': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - parse_expires(optarg, sinfo); - if (invert) { + case O_CTEXPIRE: + sinfo->expires_min = cb->val.u32_range[0]; + sinfo->expires_max = cb->val.u32_range[0]; + if (cb->nvals >= 2) + sinfo->expires_max = cb->val.u32_range[1]; + if (cb->invert) sinfo->invflags |= XT_CONNTRACK_EXPIRES; - } sinfo->flags |= XT_CONNTRACK_EXPIRES; break; - - default: - return 0; } - - *flags = sinfo->flags; - return 1; } -static int -conntrack_mt_parse(int c, bool invert, unsigned int *flags, - struct xt_conntrack_mtinfo2 *info) +static void conntrack_mt_parse(struct xt_option_call *cb, uint8_t rev) { - unsigned int port; - char *p; + struct xt_conntrack_mtinfo3 *info = cb->data; - switch (c) { - case '1': /* --ctstate */ - conntrack_ps_states(info, optarg); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_CTSTATE: + conntrack_ps_states(info, cb->arg); info->match_flags |= XT_CONNTRACK_STATE; - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_STATE; break; - - case '2': /* --ctproto */ - /* Canonicalize into lower case */ - for (p = optarg; *p != '\0'; ++p) - *p = tolower(*p); - info->l4proto = xtables_parse_protocol(optarg); - + case O_CTPROTO: + info->l4proto = cb->val.protocol; if (info->l4proto == 0 && (info->invert_flags & XT_INV_PROTO)) xtables_error(PARAMETER_PROBLEM, "conntrack: rule would " "never match protocol"); info->match_flags |= XT_CONNTRACK_PROTO; - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_PROTO; break; - - case '7': /* --ctstatus */ - conntrack_ps_statuses(info, optarg); + case O_CTORIGSRC: + info->origsrc_addr = cb->val.haddr; + info->origsrc_mask = cb->val.hmask; + info->match_flags |= XT_CONNTRACK_ORIGSRC; + if (cb->invert) + info->invert_flags |= XT_CONNTRACK_ORIGSRC; + break; + case O_CTORIGDST: + info->origdst_addr = cb->val.haddr; + info->origdst_mask = cb->val.hmask; + info->match_flags |= XT_CONNTRACK_ORIGDST; + if (cb->invert) + info->invert_flags |= XT_CONNTRACK_ORIGDST; + break; + case O_CTREPLSRC: + info->replsrc_addr = cb->val.haddr; + info->replsrc_mask = cb->val.hmask; + info->match_flags |= XT_CONNTRACK_REPLSRC; + if (cb->invert) + info->invert_flags |= XT_CONNTRACK_REPLSRC; + break; + case O_CTREPLDST: + info->repldst_addr = cb->val.haddr; + info->repldst_mask = cb->val.hmask; + info->match_flags |= XT_CONNTRACK_REPLDST; + if (cb->invert) + info->invert_flags |= XT_CONNTRACK_REPLDST; + break; + case O_CTSTATUS: + conntrack_ps_statuses(info, cb->arg); info->match_flags |= XT_CONNTRACK_STATUS; - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_STATUS; break; - - case '8': /* --ctexpire */ - conntrack_ps_expires(info, optarg); + case O_CTEXPIRE: + info->expires_min = cb->val.u32_range[0]; + info->expires_max = cb->val.u32_range[0]; + if (cb->nvals >= 2) + info->expires_max = cb->val.u32_range[1]; info->match_flags |= XT_CONNTRACK_EXPIRES; - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_EXPIRES; break; - - case 'a': /* --ctorigsrcport */ - if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "conntrack", - "--ctorigsrcport", optarg); + case O_CTORIGSRCPORT: + info->origsrc_port = cb->val.port_range[0]; + info->origsrc_port_high = cb->val.port_range[cb->nvals >= 2]; info->match_flags |= XT_CONNTRACK_ORIGSRC_PORT; - info->origsrc_port = htons(port); - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_ORIGSRC_PORT; break; - - case 'b': /* --ctorigdstport */ - if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "conntrack", - "--ctorigdstport", optarg); + case O_CTORIGDSTPORT: + info->origdst_port = cb->val.port_range[0]; + info->origdst_port_high = cb->val.port_range[cb->nvals >= 2]; info->match_flags |= XT_CONNTRACK_ORIGDST_PORT; - info->origdst_port = htons(port); - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_ORIGDST_PORT; break; - - case 'c': /* --ctreplsrcport */ - if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "conntrack", - "--ctreplsrcport", optarg); + case O_CTREPLSRCPORT: + info->replsrc_port = cb->val.port_range[0]; + info->replsrc_port_high = cb->val.port_range[cb->nvals >= 2]; info->match_flags |= XT_CONNTRACK_REPLSRC_PORT; - info->replsrc_port = htons(port); - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_REPLSRC_PORT; break; - - case 'd': /* --ctrepldstport */ - if (!xtables_strtoui(optarg, NULL, &port, 0, UINT16_MAX)) - xtables_param_act(XTF_BAD_VALUE, "conntrack", - "--ctrepldstport", optarg); + case O_CTREPLDSTPORT: + info->repldst_port = cb->val.port_range[0]; + info->repldst_port_high = cb->val.port_range[cb->nvals >= 2]; info->match_flags |= XT_CONNTRACK_REPLDST_PORT; - info->repldst_port = htons(port); - if (invert) + if (cb->invert) info->invert_flags |= XT_CONNTRACK_REPLDST_PORT; break; - - case 'e': /* --ctdir */ - xtables_param_act(XTF_NO_INVERT, "conntrack", "--ctdir", invert); - if (strcasecmp(optarg, "ORIGINAL") == 0) { + case O_CTDIR: + if (strcasecmp(cb->arg, "ORIGINAL") == 0) { info->match_flags |= XT_CONNTRACK_DIRECTION; info->invert_flags &= ~XT_CONNTRACK_DIRECTION; - } else if (strcasecmp(optarg, "REPLY") == 0) { + } else if (strcasecmp(cb->arg, "REPLY") == 0) { info->match_flags |= XT_CONNTRACK_DIRECTION; info->invert_flags |= XT_CONNTRACK_DIRECTION; } else { - xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", optarg); + xtables_param_act(XTF_BAD_VALUE, "conntrack", "--ctdir", cb->arg); } break; - - default: - return false; - } - - *flags = info->match_flags; - return true; -} - -static int -conntrack_mt4_parse(int c, bool invert, unsigned int *flags, - struct xt_conntrack_mtinfo2 *info) -{ - struct in_addr *addr = NULL; - unsigned int naddrs = 0; - - switch (c) { - case '3': /* --ctorigsrc */ - xtables_ipparse_any(optarg, &addr, &info->origsrc_mask.in, - &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->origsrc_addr.in, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_ORIGSRC; - if (invert) - info->invert_flags |= XT_CONNTRACK_ORIGSRC; - break; - - case '4': /* --ctorigdst */ - xtables_ipparse_any(optarg, &addr, &info->origdst_mask.in, - &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_ORIGDST; - if (invert) - info->invert_flags |= XT_CONNTRACK_ORIGDST; - break; - - case '5': /* --ctreplsrc */ - xtables_ipparse_any(optarg, &addr, &info->replsrc_mask.in, - &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_REPLSRC; - if (invert) - info->invert_flags |= XT_CONNTRACK_REPLSRC; - break; - - case '6': /* --ctrepldst */ - xtables_ipparse_any(optarg, &addr, &info->repldst_mask.in, - &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_REPLDST; - if (invert) - info->invert_flags |= XT_CONNTRACK_REPLDST; - break; - - - default: - return conntrack_mt_parse(c, invert, flags, info); - } - - *flags = info->match_flags; - return true; -} - -static int -conntrack_mt6_parse(int c, bool invert, unsigned int *flags, - struct xt_conntrack_mtinfo2 *info) -{ - struct in6_addr *addr = NULL; - unsigned int naddrs = 0; - - switch (c) { - case '3': /* --ctorigsrc */ - xtables_ip6parse_any(optarg, &addr, - &info->origsrc_mask.in6, &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->origsrc_addr.in6, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_ORIGSRC; - if (invert) - info->invert_flags |= XT_CONNTRACK_ORIGSRC; - break; - - case '4': /* --ctorigdst */ - xtables_ip6parse_any(optarg, &addr, - &info->origdst_mask.in6, &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->origdst_addr.in, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_ORIGDST; - if (invert) - info->invert_flags |= XT_CONNTRACK_ORIGDST; - break; - - case '5': /* --ctreplsrc */ - xtables_ip6parse_any(optarg, &addr, - &info->replsrc_mask.in6, &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->replsrc_addr.in, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_REPLSRC; - if (invert) - info->invert_flags |= XT_CONNTRACK_REPLSRC; - break; - - case '6': /* --ctrepldst */ - xtables_ip6parse_any(optarg, &addr, - &info->repldst_mask.in6, &naddrs); - if (naddrs > 1) - xtables_error(PARAMETER_PROBLEM, - "multiple IP addresses not allowed"); - if (naddrs == 1) - memcpy(&info->repldst_addr.in, addr, sizeof(*addr)); - info->match_flags |= XT_CONNTRACK_REPLDST; - if (invert) - info->invert_flags |= XT_CONNTRACK_REPLDST; - break; - - - default: - return conntrack_mt_parse(c, invert, flags, info); } - - *flags = info->match_flags; - return true; } #define cinfo_transform(r, l) \ @@ -720,51 +512,64 @@ conntrack_mt6_parse(int c, bool invert, unsigned int *flags, (r)->status_mask = (l)->status_mask; \ } while (false); -static int -conntrack1_mt4_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void conntrack1_mt_parse(struct xt_option_call *cb) { - struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; - struct xt_conntrack_mtinfo2 up; + struct xt_conntrack_mtinfo1 *info = cb->data; + struct xt_conntrack_mtinfo3 up; + memset(&up, 0, sizeof(up)); cinfo_transform(&up, info); - if (!conntrack_mt4_parse(c, invert, flags, &up)) - return false; - cinfo_transform(info, &up); - return true; -} - -static int -conntrack1_mt6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct xt_conntrack_mtinfo1 *info = (void *)(*match)->data; - struct xt_conntrack_mtinfo2 up; - - cinfo_transform(&up, info); - if (!conntrack_mt6_parse(c, invert, flags, &up)) - return false; + up.origsrc_port_high = up.origsrc_port; + up.origdst_port_high = up.origdst_port; + up.replsrc_port_high = up.replsrc_port; + up.repldst_port_high = up.repldst_port; + cb->data = &up; + conntrack_mt_parse(cb, 3); + if (up.origsrc_port != up.origsrc_port_high || + up.origdst_port != up.origdst_port_high || + up.replsrc_port != up.replsrc_port_high || + up.repldst_port != up.repldst_port_high) + xtables_error(PARAMETER_PROBLEM, + "conntrack rev 1 does not support port ranges"); cinfo_transform(info, &up); - return true; + cb->data = info; } -static int -conntrack2_mt4_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void conntrack2_mt_parse(struct xt_option_call *cb) { - return conntrack_mt4_parse(c, invert, flags, (void *)(*match)->data); +#define cinfo2_transform(r, l) \ + memcpy((r), (l), offsetof(typeof(*(l)), sizeof(*info)); + + struct xt_conntrack_mtinfo2 *info = cb->data; + struct xt_conntrack_mtinfo3 up; + + memset(&up, 0, sizeof(up)); + memcpy(&up, info, sizeof(*info)); + up.origsrc_port_high = up.origsrc_port; + up.origdst_port_high = up.origdst_port; + up.replsrc_port_high = up.replsrc_port; + up.repldst_port_high = up.repldst_port; + cb->data = &up; + conntrack_mt_parse(cb, 3); + if (up.origsrc_port != up.origsrc_port_high || + up.origdst_port != up.origdst_port_high || + up.replsrc_port != up.replsrc_port_high || + up.repldst_port != up.repldst_port_high) + xtables_error(PARAMETER_PROBLEM, + "conntrack rev 2 does not support port ranges"); + memcpy(info, &up, sizeof(*info)); + cb->data = info; +#undef cinfo2_transform } -static int -conntrack2_mt6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void conntrack3_mt_parse(struct xt_option_call *cb) { - return conntrack_mt6_parse(c, invert, flags, (void *)(*match)->data); + conntrack_mt_parse(cb, 3); } -static void conntrack_mt_check(unsigned int flags) +static void conntrack_mt_check(struct xt_fcheck_call *cb) { - if (flags == 0) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "conntrack: At least one option " "is required"); } @@ -772,7 +577,7 @@ static void conntrack_mt_check(unsigned int flags) static void print_state(unsigned int statemask) { - const char *sep = ""; + const char *sep = " "; if (statemask & XT_CONNTRACK_STATE_INVALID) { printf("%sINVALID", sep); @@ -802,13 +607,12 @@ print_state(unsigned int statemask) printf("%sDNAT", sep); sep = ","; } - printf(" "); } static void print_status(unsigned int statusmask) { - const char *sep = ""; + const char *sep = " "; if (statusmask & IPS_EXPECTED) { printf("%sEXPECTED", sep); @@ -828,7 +632,6 @@ print_status(unsigned int statusmask) } if (statusmask == 0) printf("%sNONE", sep); - printf(" "); } static void @@ -838,29 +641,29 @@ conntrack_dump_addr(const union nf_inet_addr *addr, { if (family == NFPROTO_IPV4) { if (!numeric && addr->ip == 0) { - printf("anywhere "); + printf(" anywhere"); return; } if (numeric) - printf("%s%s ", + printf(" %s%s", xtables_ipaddr_to_numeric(&addr->in), xtables_ipmask_to_numeric(&mask->in)); else - printf("%s%s ", + printf(" %s%s", xtables_ipaddr_to_anyname(&addr->in), xtables_ipmask_to_numeric(&mask->in)); } else if (family == NFPROTO_IPV6) { if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 && addr->ip6[2] == 0 && addr->ip6[3] == 0) { - printf("anywhere "); + printf(" anywhere"); return; } if (numeric) - printf("%s%s ", + printf(" %s%s", xtables_ip6addr_to_numeric(&addr->in6), xtables_ip6mask_to_numeric(&mask->in6)); else - printf("%s%s ", + printf(" %s%s", xtables_ip6addr_to_anyname(&addr->in6), xtables_ip6mask_to_numeric(&mask->in6)); } @@ -873,17 +676,17 @@ print_addr(const struct in_addr *addr, const struct in_addr *mask, char buf[BUFSIZ]; if (inv) - printf("! "); + printf(" !"); if (mask->s_addr == 0L && !numeric) - printf("%s ", "anywhere"); + printf(" %s", "anywhere"); else { if (numeric) strcpy(buf, xtables_ipaddr_to_numeric(addr)); else strcpy(buf, xtables_ipaddr_to_anyname(addr)); strcat(buf, xtables_ipmask_to_numeric(mask)); - printf("%s ", buf); + printf(" %s", buf); } } @@ -894,22 +697,22 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, if(sinfo->flags & XT_CONNTRACK_STATE) { if (sinfo->invflags & XT_CONNTRACK_STATE) - printf("! "); - printf("%sctstate ", optpfx); + printf(" !"); + printf(" %sctstate", optpfx); print_state(sinfo->statemask); } if(sinfo->flags & XT_CONNTRACK_PROTO) { if (sinfo->invflags & XT_CONNTRACK_PROTO) - printf("! "); - printf("%sctproto ", optpfx); - printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum); + printf(" !"); + printf(" %sctproto", optpfx); + printf(" %u", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum); } if(sinfo->flags & XT_CONNTRACK_ORIGSRC) { if (sinfo->invflags & XT_CONNTRACK_ORIGSRC) - printf("! "); - printf("%sctorigsrc ", optpfx); + printf(" !"); + printf(" %sctorigsrc", optpfx); print_addr( (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, @@ -920,8 +723,8 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, if(sinfo->flags & XT_CONNTRACK_ORIGDST) { if (sinfo->invflags & XT_CONNTRACK_ORIGDST) - printf("! "); - printf("%sctorigdst ", optpfx); + printf(" !"); + printf(" %sctorigdst", optpfx); print_addr( (struct in_addr *)&sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, @@ -932,8 +735,8 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, if(sinfo->flags & XT_CONNTRACK_REPLSRC) { if (sinfo->invflags & XT_CONNTRACK_REPLSRC) - printf("! "); - printf("%sctreplsrc ", optpfx); + printf(" !"); + printf(" %sctreplsrc", optpfx); print_addr( (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].src.ip, @@ -944,8 +747,8 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, if(sinfo->flags & XT_CONNTRACK_REPLDST) { if (sinfo->invflags & XT_CONNTRACK_REPLDST) - printf("! "); - printf("%sctrepldst ", optpfx); + printf(" !"); + printf(" %sctrepldst", optpfx); print_addr( (struct in_addr *)&sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, @@ -956,135 +759,160 @@ matchinfo_print(const void *ip, const struct xt_entry_match *match, int numeric, if(sinfo->flags & XT_CONNTRACK_STATUS) { if (sinfo->invflags & XT_CONNTRACK_STATUS) - printf("! "); - printf("%sctstatus ", optpfx); + printf(" !"); + printf(" %sctstatus", optpfx); print_status(sinfo->statusmask); } if(sinfo->flags & XT_CONNTRACK_EXPIRES) { if (sinfo->invflags & XT_CONNTRACK_EXPIRES) - printf("! "); - printf("%sctexpire ", optpfx); + printf(" !"); + printf(" %sctexpire ", optpfx); if (sinfo->expires_max == sinfo->expires_min) - printf("%lu ", sinfo->expires_min); + printf("%lu", sinfo->expires_min); else - printf("%lu:%lu ", sinfo->expires_min, sinfo->expires_max); + printf("%lu:%lu", sinfo->expires_min, sinfo->expires_max); } if (sinfo->flags & XT_CONNTRACK_DIRECTION) { if (sinfo->invflags & XT_CONNTRACK_DIRECTION) - printf("%sctdir REPLY", optpfx); + printf(" %sctdir REPLY", optpfx); else - printf("%sctdir ORIGINAL", optpfx); + printf(" %sctdir ORIGINAL", optpfx); } } static void -conntrack_dump(const struct xt_conntrack_mtinfo2 *info, const char *prefix, - unsigned int family, bool numeric) +conntrack_dump_ports(const char *prefix, const char *opt, + u_int16_t port_low, u_int16_t port_high) +{ + if (port_high == 0 || port_low == port_high) + printf(" %s%s %u", prefix, opt, port_low); + else + printf(" %s%s %u:%u", prefix, opt, port_low, port_high); +} + +static void +conntrack_dump(const struct xt_conntrack_mtinfo3 *info, const char *prefix, + unsigned int family, bool numeric, bool v3) { if (info->match_flags & XT_CONNTRACK_STATE) { if (info->invert_flags & XT_CONNTRACK_STATE) - printf("! "); - printf("%sctstate ", prefix); + printf(" !"); + printf(" %s%s", prefix, + info->match_flags & XT_CONNTRACK_STATE_ALIAS + ? "state" : "ctstate"); print_state(info->state_mask); } if (info->match_flags & XT_CONNTRACK_PROTO) { if (info->invert_flags & XT_CONNTRACK_PROTO) - printf("! "); - printf("%sctproto %u ", prefix, info->l4proto); + printf(" !"); + printf(" %sctproto %u", prefix, info->l4proto); } if (info->match_flags & XT_CONNTRACK_ORIGSRC) { if (info->invert_flags & XT_CONNTRACK_ORIGSRC) - printf("! "); - printf("%sctorigsrc ", prefix); + printf(" !"); + printf(" %sctorigsrc", prefix); conntrack_dump_addr(&info->origsrc_addr, &info->origsrc_mask, family, numeric); } if (info->match_flags & XT_CONNTRACK_ORIGDST) { if (info->invert_flags & XT_CONNTRACK_ORIGDST) - printf("! "); - printf("%sctorigdst ", prefix); + printf(" !"); + printf(" %sctorigdst", prefix); conntrack_dump_addr(&info->origdst_addr, &info->origdst_mask, family, numeric); } if (info->match_flags & XT_CONNTRACK_REPLSRC) { if (info->invert_flags & XT_CONNTRACK_REPLSRC) - printf("! "); - printf("%sctreplsrc ", prefix); + printf(" !"); + printf(" %sctreplsrc", prefix); conntrack_dump_addr(&info->replsrc_addr, &info->replsrc_mask, family, numeric); } if (info->match_flags & XT_CONNTRACK_REPLDST) { if (info->invert_flags & XT_CONNTRACK_REPLDST) - printf("! "); - printf("%sctrepldst ", prefix); + printf(" !"); + printf(" %sctrepldst", prefix); conntrack_dump_addr(&info->repldst_addr, &info->repldst_mask, family, numeric); } if (info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) { if (info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT) - printf("! "); - printf("%sctorigsrcport %u ", prefix, - ntohs(info->origsrc_port)); + printf(" !"); + conntrack_dump_ports(prefix, "ctorigsrcport", + v3 ? info->origsrc_port : ntohs(info->origsrc_port), + v3 ? info->origsrc_port_high : 0); } if (info->match_flags & XT_CONNTRACK_ORIGDST_PORT) { if (info->invert_flags & XT_CONNTRACK_ORIGDST_PORT) - printf("! "); - printf("%sctorigdstport %u ", prefix, - ntohs(info->origdst_port)); + printf(" !"); + conntrack_dump_ports(prefix, "ctorigdstport", + v3 ? info->origdst_port : ntohs(info->origdst_port), + v3 ? info->origdst_port_high : 0); } if (info->match_flags & XT_CONNTRACK_REPLSRC_PORT) { if (info->invert_flags & XT_CONNTRACK_REPLSRC_PORT) - printf("! "); - printf("%sctreplsrcport %u ", prefix, - ntohs(info->replsrc_port)); + printf(" !"); + conntrack_dump_ports(prefix, "ctreplsrcport", + v3 ? info->replsrc_port : ntohs(info->replsrc_port), + v3 ? info->replsrc_port_high : 0); } if (info->match_flags & XT_CONNTRACK_REPLDST_PORT) { if (info->invert_flags & XT_CONNTRACK_REPLDST_PORT) - printf("! "); - printf("%sctrepldstport %u ", prefix, - ntohs(info->repldst_port)); + printf(" !"); + conntrack_dump_ports(prefix, "ctrepldstport", + v3 ? info->repldst_port : ntohs(info->repldst_port), + v3 ? info->repldst_port_high : 0); } if (info->match_flags & XT_CONNTRACK_STATUS) { if (info->invert_flags & XT_CONNTRACK_STATUS) - printf("! "); - printf("%sctstatus ", prefix); + printf(" !"); + printf(" %sctstatus", prefix); print_status(info->status_mask); } if (info->match_flags & XT_CONNTRACK_EXPIRES) { if (info->invert_flags & XT_CONNTRACK_EXPIRES) - printf("! "); - printf("%sctexpire ", prefix); + printf(" !"); + printf(" %sctexpire ", prefix); if (info->expires_max == info->expires_min) - printf("%u ", (unsigned int)info->expires_min); + printf("%u", (unsigned int)info->expires_min); else - printf("%u:%u ", (unsigned int)info->expires_min, + printf("%u:%u", (unsigned int)info->expires_min, (unsigned int)info->expires_max); } if (info->match_flags & XT_CONNTRACK_DIRECTION) { if (info->invert_flags & XT_CONNTRACK_DIRECTION) - printf("%sctdir REPLY", prefix); + printf(" %sctdir REPLY", prefix); else - printf("%sctdir ORIGINAL", prefix); + printf(" %sctdir ORIGINAL", prefix); } } +static const char * +conntrack_print_name_alias(const struct xt_entry_match *match) +{ + struct xt_conntrack_mtinfo1 *info = (void *)match->data; + + return info->match_flags & XT_CONNTRACK_STATE_ALIAS + ? "state" : "conntrack"; +} + static void conntrack_print(const void *ip, const struct xt_entry_match *match, int numeric) { @@ -1096,10 +924,10 @@ conntrack1_mt4_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_conntrack_mtinfo1 *info = (void *)match->data; - struct xt_conntrack_mtinfo2 up; + struct xt_conntrack_mtinfo3 up; cinfo_transform(&up, info); - conntrack_dump(&up, "", NFPROTO_IPV4, numeric); + conntrack_dump(&up, "", NFPROTO_IPV4, numeric, false); } static void @@ -1107,24 +935,38 @@ conntrack1_mt6_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_conntrack_mtinfo1 *info = (void *)match->data; - struct xt_conntrack_mtinfo2 up; + struct xt_conntrack_mtinfo3 up; cinfo_transform(&up, info); - conntrack_dump(&up, "", NFPROTO_IPV6, numeric); + conntrack_dump(&up, "", NFPROTO_IPV6, numeric, false); } static void -conntrack_mt_print(const void *ip, const struct xt_entry_match *match, - int numeric) +conntrack2_mt_print(const void *ip, const struct xt_entry_match *match, + int numeric) { - conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric); + conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric, false); } static void -conntrack_mt6_print(const void *ip, const struct xt_entry_match *match, +conntrack2_mt6_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric, false); +} + +static void +conntrack3_mt_print(const void *ip, const struct xt_entry_match *match, int numeric) { - conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric); + conntrack_dump((const void *)match->data, "", NFPROTO_IPV4, numeric, true); +} + +static void +conntrack3_mt6_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + conntrack_dump((const void *)match->data, "", NFPROTO_IPV6, numeric, true); } static void conntrack_save(const void *ip, const struct xt_entry_match *match) @@ -1132,36 +974,186 @@ static void conntrack_save(const void *ip, const struct xt_entry_match *match) matchinfo_print(ip, match, 1, "--"); } -static void conntrack_mt_save(const void *ip, - const struct xt_entry_match *match) +static void conntrack3_mt_save(const void *ip, + const struct xt_entry_match *match) +{ + conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true, true); +} + +static void conntrack3_mt6_save(const void *ip, + const struct xt_entry_match *match) { - conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true); + conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true, true); } -static void conntrack_mt6_save(const void *ip, +static void conntrack2_mt_save(const void *ip, const struct xt_entry_match *match) { - conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true); + conntrack_dump((const void *)match->data, "--", NFPROTO_IPV4, true, false); +} + +static void conntrack2_mt6_save(const void *ip, + const struct xt_entry_match *match) +{ + conntrack_dump((const void *)match->data, "--", NFPROTO_IPV6, true, false); } static void conntrack1_mt4_save(const void *ip, const struct xt_entry_match *match) { const struct xt_conntrack_mtinfo1 *info = (void *)match->data; - struct xt_conntrack_mtinfo2 up; + struct xt_conntrack_mtinfo3 up; cinfo_transform(&up, info); - conntrack_dump(&up, "--", NFPROTO_IPV4, true); + conntrack_dump(&up, "--", NFPROTO_IPV4, true, false); } static void conntrack1_mt6_save(const void *ip, const struct xt_entry_match *match) { const struct xt_conntrack_mtinfo1 *info = (void *)match->data; - struct xt_conntrack_mtinfo2 up; + struct xt_conntrack_mtinfo3 up; cinfo_transform(&up, info); - conntrack_dump(&up, "--", NFPROTO_IPV6, true); + conntrack_dump(&up, "--", NFPROTO_IPV6, true, false); +} + +static void +state_help(void) +{ + printf( +"state match options:\n" +" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n" +" State(s) to match\n"); +} + +static const struct xt_option_entry state_opts[] = { + {.name = "state", .id = O_CTSTATE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, +}; + +static unsigned int +state_parse_state(const char *state, size_t len) +{ + if (strncasecmp(state, "INVALID", len) == 0) + return XT_CONNTRACK_STATE_INVALID; + else if (strncasecmp(state, "NEW", len) == 0) + return XT_CONNTRACK_STATE_BIT(IP_CT_NEW); + else if (strncasecmp(state, "ESTABLISHED", len) == 0) + return XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED); + else if (strncasecmp(state, "RELATED", len) == 0) + return XT_CONNTRACK_STATE_BIT(IP_CT_RELATED); + else if (strncasecmp(state, "UNTRACKED", len) == 0) + return XT_CONNTRACK_STATE_UNTRACKED; + return 0; +} + +static unsigned int +state_parse_states(const char *arg) +{ + const char *comma; + unsigned int mask = 0, flag; + + while ((comma = strchr(arg, ',')) != NULL) { + if (comma == arg) + goto badstate; + flag = state_parse_state(arg, comma-arg); + if (flag == 0) + goto badstate; + mask |= flag; + arg = comma+1; + } + if (!*arg) + xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of " + "states with no spaces, e.g. " + "ESTABLISHED,RELATED"); + if (strlen(arg) == 0) + goto badstate; + flag = state_parse_state(arg, strlen(arg)); + if (flag == 0) + goto badstate; + mask |= flag; + return mask; + badstate: + xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg); +} + +static void state_parse(struct xt_option_call *cb) +{ + struct xt_state_info *sinfo = cb->data; + + xtables_option_parse(cb); + sinfo->statemask = state_parse_states(cb->arg); + if (cb->invert) + sinfo->statemask = ~sinfo->statemask; +} + +static void state_ct1_parse(struct xt_option_call *cb) +{ + struct xt_conntrack_mtinfo1 *sinfo = cb->data; + + xtables_option_parse(cb); + sinfo->match_flags = XT_CONNTRACK_STATE | XT_CONNTRACK_STATE_ALIAS; + sinfo->state_mask = state_parse_states(cb->arg); + if (cb->invert) + sinfo->invert_flags |= XT_CONNTRACK_STATE; +} + +static void state_ct23_parse(struct xt_option_call *cb) +{ + struct xt_conntrack_mtinfo3 *sinfo = cb->data; + + xtables_option_parse(cb); + sinfo->match_flags = XT_CONNTRACK_STATE | XT_CONNTRACK_STATE_ALIAS; + sinfo->state_mask = state_parse_states(cb->arg); + if (cb->invert) + sinfo->invert_flags |= XT_CONNTRACK_STATE; +} + +static void state_print_state(unsigned int statemask) +{ + const char *sep = ""; + + if (statemask & XT_CONNTRACK_STATE_INVALID) { + printf("%sINVALID", sep); + sep = ","; + } + if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_NEW)) { + printf("%sNEW", sep); + sep = ","; + } + if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_RELATED)) { + printf("%sRELATED", sep); + sep = ","; + } + if (statemask & XT_CONNTRACK_STATE_BIT(IP_CT_ESTABLISHED)) { + printf("%sESTABLISHED", sep); + sep = ","; + } + if (statemask & XT_CONNTRACK_STATE_UNTRACKED) { + printf("%sUNTRACKED", sep); + sep = ","; + } +} + +static void +state_print(const void *ip, + const struct xt_entry_match *match, + int numeric) +{ + const struct xt_state_info *sinfo = (const void *)match->data; + + printf(" state "); + state_print_state(sinfo->statemask); +} + +static void state_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_state_info *sinfo = (const void *)match->data; + + printf(" --state "); + state_print_state(sinfo->statemask); } static struct xtables_match conntrack_mt_reg[] = { @@ -1173,11 +1165,12 @@ static struct xtables_match conntrack_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_conntrack_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_info)), .help = conntrack_mt_help, - .parse = conntrack_parse, - .final_check = conntrack_mt_check, + .x6_parse = conntrack_parse, + .x6_fcheck = conntrack_mt_check, .print = conntrack_print, .save = conntrack_save, - .extra_opts = conntrack_mt_opts_v0, + .alias = conntrack_print_name_alias, + .x6_options = conntrack_mt_opts_v0, }, { .version = XTABLES_VERSION, @@ -1187,11 +1180,12 @@ static struct xtables_match conntrack_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), .help = conntrack_mt_help, - .parse = conntrack1_mt4_parse, - .final_check = conntrack_mt_check, + .x6_parse = conntrack1_mt_parse, + .x6_fcheck = conntrack_mt_check, .print = conntrack1_mt4_print, .save = conntrack1_mt4_save, - .extra_opts = conntrack_mt_opts, + .alias = conntrack_print_name_alias, + .x6_options = conntrack2_mt_opts, }, { .version = XTABLES_VERSION, @@ -1201,11 +1195,12 @@ static struct xtables_match conntrack_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), .help = conntrack_mt_help, - .parse = conntrack1_mt6_parse, - .final_check = conntrack_mt_check, + .x6_parse = conntrack1_mt_parse, + .x6_fcheck = conntrack_mt_check, .print = conntrack1_mt6_print, .save = conntrack1_mt6_save, - .extra_opts = conntrack_mt_opts, + .alias = conntrack_print_name_alias, + .x6_options = conntrack2_mt_opts, }, { .version = XTABLES_VERSION, @@ -1215,11 +1210,12 @@ static struct xtables_match conntrack_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), .help = conntrack_mt_help, - .parse = conntrack2_mt4_parse, - .final_check = conntrack_mt_check, - .print = conntrack_mt_print, - .save = conntrack_mt_save, - .extra_opts = conntrack_mt_opts, + .x6_parse = conntrack2_mt_parse, + .x6_fcheck = conntrack_mt_check, + .print = conntrack2_mt_print, + .save = conntrack2_mt_save, + .alias = conntrack_print_name_alias, + .x6_options = conntrack2_mt_opts, }, { .version = XTABLES_VERSION, @@ -1229,11 +1225,100 @@ static struct xtables_match conntrack_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), .help = conntrack_mt_help, - .parse = conntrack2_mt6_parse, - .final_check = conntrack_mt_check, - .print = conntrack_mt6_print, - .save = conntrack_mt6_save, - .extra_opts = conntrack_mt_opts, + .x6_parse = conntrack2_mt_parse, + .x6_fcheck = conntrack_mt_check, + .print = conntrack2_mt6_print, + .save = conntrack2_mt6_save, + .alias = conntrack_print_name_alias, + .x6_options = conntrack2_mt_opts, + }, + { + .version = XTABLES_VERSION, + .name = "conntrack", + .revision = 3, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), + .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), + .help = conntrack_mt_help, + .x6_parse = conntrack3_mt_parse, + .x6_fcheck = conntrack_mt_check, + .print = conntrack3_mt_print, + .save = conntrack3_mt_save, + .alias = conntrack_print_name_alias, + .x6_options = conntrack3_mt_opts, + }, + { + .version = XTABLES_VERSION, + .name = "conntrack", + .revision = 3, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), + .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), + .help = conntrack_mt_help, + .x6_parse = conntrack3_mt_parse, + .x6_fcheck = conntrack_mt_check, + .print = conntrack3_mt6_print, + .save = conntrack3_mt6_save, + .alias = conntrack_print_name_alias, + .x6_options = conntrack3_mt_opts, + }, + { + .family = NFPROTO_UNSPEC, + .name = "state", + .real_name = "conntrack", + .revision = 1, + .ext_flags = XTABLES_EXT_ALIAS, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo1)), + .help = state_help, + .print = state_print, + .save = state_save, + .x6_parse = state_ct1_parse, + .x6_options = state_opts, + }, + { + .family = NFPROTO_UNSPEC, + .name = "state", + .real_name = "conntrack", + .revision = 2, + .ext_flags = XTABLES_EXT_ALIAS, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), + .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo2)), + .help = state_help, + .print = state_print, + .save = state_save, + .x6_parse = state_ct23_parse, + .x6_options = state_opts, + }, + { + .family = NFPROTO_UNSPEC, + .name = "state", + .real_name = "conntrack", + .revision = 3, + .ext_flags = XTABLES_EXT_ALIAS, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), + .userspacesize = XT_ALIGN(sizeof(struct xt_conntrack_mtinfo3)), + .help = state_help, + .print = state_print, + .save = state_save, + .x6_parse = state_ct23_parse, + .x6_options = state_opts, + }, + { + .family = NFPROTO_UNSPEC, + .name = "state", + .revision = 0, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_state_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)), + .help = state_help, + .print = state_print, + .save = state_save, + .x6_parse = state_parse, + .x6_options = state_opts, }, }; diff --git a/extensions/libxt_conntrack.man b/extensions/libxt_conntrack.man index ec51ef5..4b13f0f 100644 --- a/extensions/libxt_conntrack.man +++ b/extensions/libxt_conntrack.man @@ -1,36 +1,37 @@ This module, when combined with connection tracking, allows access to the connection tracking state for this packet/connection. .TP -[\fB!\fR] \fB\-\-ctstate\fP \fIstatelist\fP -\fIstatelist\fR is a comma separated list of the connection states to match. +[\fB!\fP] \fB\-\-ctstate\fP \fIstatelist\fP +\fIstatelist\fP is a comma separated list of the connection states to match. Possible states are listed below. .TP -[\fB!\fR] \fB\-\-ctproto\fP \fIl4proto\fP +[\fB!\fP] \fB\-\-ctproto\fP \fIl4proto\fP Layer-4 protocol to match (by number or name) .TP -[\fB!\fR] \fB\-\-ctorigsrc\fP \fIaddress\fP[\fB/\fP\fImask\fP] +[\fB!\fP] \fB\-\-ctorigsrc\fP \fIaddress\fP[\fB/\fP\fImask\fP] .TP -[\fB!\fR] \fB\-\-ctorigdst\fP \fIaddress\fP[\fB/\fP\fImask\fP] +[\fB!\fP] \fB\-\-ctorigdst\fP \fIaddress\fP[\fB/\fP\fImask\fP] .TP -[\fB!\fR] \fB\-\-ctreplsrc\fP \fIaddress\fP[\fB/\fP\fImask\fP] +[\fB!\fP] \fB\-\-ctreplsrc\fP \fIaddress\fP[\fB/\fP\fImask\fP] .TP -[\fB!\fR] \fB\-\-ctrepldst\fP \fIaddress\fP[\fB/\fP\fImask\fP] +[\fB!\fP] \fB\-\-ctrepldst\fP \fIaddress\fP[\fB/\fP\fImask\fP] Match against original/reply source/destination address .TP -[\fB!\fR] \fB\-\-ctorigsrcport\fP \fIport\fP +[\fB!\fP] \fB\-\-ctorigsrcport\fP \fIport\fP[\fB:\fP\fIport\fP] .TP -[\fB!\fR] \fB\-\-ctorigdstport\fP \fIport\fP +[\fB!\fP] \fB\-\-ctorigdstport\fP \fIport\fP[\fB:\fP\fIport\fP] .TP -[\fB!\fR] \fB\-\-ctreplsrcport\fP \fIport\fP +[\fB!\fP] \fB\-\-ctreplsrcport\fP \fIport\fP[\fB:\fP\fIport\fP] .TP -[\fB!\fR] \fB\-\-ctrepldstport\fP \fIport\fP +[\fB!\fP] \fB\-\-ctrepldstport\fP \fIport\fP[\fB:\fP\fIport\fP] Match against original/reply source/destination port (TCP/UDP/etc.) or GRE key. +Matching against port ranges is only supported in kernel versions above 2.6.38. .TP -[\fB!\fR] \fB\-\-ctstatus\fP \fIstatelist\fP -\fIstatuslist\fR is a comma separated list of the connection statuses to match. +[\fB!\fP] \fB\-\-ctstatus\fP \fIstatelist\fP +\fIstatuslist\fP is a comma separated list of the connection statuses to match. Possible statuses are listed below. .TP -[\fB!\fR] \fB\-\-ctexpire\fP \fItime\fP[\fB:\fP\fItime\fP] +[\fB!\fP] \fB\-\-ctexpire\fP \fItime\fP[\fB:\fP\fItime\fP] Match remaining lifetime in seconds against given value or range of values (inclusive) .TP @@ -40,46 +41,46 @@ specified at all, matches packets in both directions. .PP States for \fB\-\-ctstate\fP: .TP -\fBINVALID\fR -meaning that the packet is associated with no known connection +\fBINVALID\fP +The packet is associated with no known connection. .TP -\fBNEW\fR -meaning that the packet has started a new connection, or otherwise associated -with a connection which has not seen packets in both directions, and +\fBNEW\fP +The packet has started a new connection or otherwise associated +with a connection which has not seen packets in both directions. .TP -\fBESTABLISHED\fR -meaning that the packet is associated with a connection which has seen packets -in both directions, +\fBESTABLISHED\fP +The packet is associated with a connection which has seen packets +in both directions. .TP -\fBRELATED\fR -meaning that the packet is starting a new connection, but is associated with an -existing connection, such as an FTP data transfer, or an ICMP error. +\fBRELATED\fP +The packet is starting a new connection, but is associated with an +existing connection, such as an FTP data transfer or an ICMP error. .TP -\fBUNTRACKED\fR -meaning that the packet is not tracked at all, which happens if you use -the NOTRACK target in raw table. +\fBUNTRACKED\fP +The packet is not tracked at all, which happens if you explicitly untrack it +by using \-j CT \-\-notrack in the raw table. .TP -\fBSNAT\fR +\fBSNAT\fP A virtual state, matching if the original source address differs from the reply destination. .TP -\fBDNAT\fR +\fBDNAT\fP A virtual state, matching if the original destination differs from the reply source. .PP Statuses for \fB\-\-ctstatus\fP: .TP -\fBNONE\fR +\fBNONE\fP None of the below. .TP -\fBEXPECTED\fR -This is an expected connection (i.e. a conntrack helper set it up) +\fBEXPECTED\fP +This is an expected connection (i.e. a conntrack helper set it up). .TP -\fBSEEN_REPLY\fR +\fBSEEN_REPLY\fP Conntrack has seen packets in both directions. .TP -\fBASSURED\fR +\fBASSURED\fP Conntrack entry should never be early-expired. .TP -\fBCONFIRMED\fR +\fBCONFIRMED\fP Connection is confirmed: originating packet has left box. diff --git a/extensions/libxt_cpu.c b/extensions/libxt_cpu.c new file mode 100644 index 0000000..404a6a6 --- /dev/null +++ b/extensions/libxt_cpu.c @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter/xt_cpu.h> + +enum { + O_CPU = 0, +}; + +static void cpu_help(void) +{ + printf( +"cpu match options:\n" +"[!] --cpu number Match CPU number\n"); +} + +static const struct xt_option_entry cpu_opts[] = { + {.name = "cpu", .id = O_CPU, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_MAND | XTOPT_PUT, + XTOPT_POINTER(struct xt_cpu_info, cpu)}, + XTOPT_TABLEEND, +}; + +static void cpu_parse(struct xt_option_call *cb) +{ + struct xt_cpu_info *cpuinfo = cb->data; + + xtables_option_parse(cb); + if (cb->invert) + cpuinfo->invert = true; +} + +static void +cpu_print(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_cpu_info *info = (void *)match->data; + + printf(" cpu %s%u", info->invert ? "! ":"", info->cpu); +} + +static void cpu_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_cpu_info *info = (void *)match->data; + + printf("%s --cpu %u", info->invert ? " !" : "", info->cpu); +} + +static struct xtables_match cpu_match = { + .family = NFPROTO_UNSPEC, + .name = "cpu", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_cpu_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_cpu_info)), + .help = cpu_help, + .print = cpu_print, + .save = cpu_save, + .x6_parse = cpu_parse, + .x6_options = cpu_opts, +}; + +void _init(void) +{ + xtables_register_match(&cpu_match); +} diff --git a/extensions/libxt_cpu.man b/extensions/libxt_cpu.man new file mode 100644 index 0000000..d9ea5c2 --- /dev/null +++ b/extensions/libxt_cpu.man @@ -0,0 +1,15 @@ +.TP +[\fB!\fP] \fB\-\-cpu\fP \fInumber\fP +Match cpu handling this packet. cpus are numbered from 0 to NR_CPUS-1 +Can be used in combination with RPS (Remote Packet Steering) or +multiqueue NICs to spread network traffic on different queues. +.PP +Example: +.PP +iptables \-t nat \-A PREROUTING \-p tcp \-\-dport 80 \-m cpu \-\-cpu 0 +\-j REDIRECT \-\-to\-port 8080 +.PP +iptables \-t nat \-A PREROUTING \-p tcp \-\-dport 80 \-m cpu \-\-cpu 1 +\-j REDIRECT \-\-to\-port 8081 +.PP +Available since Linux 2.6.36. diff --git a/extensions/libxt_dccp.c b/extensions/libxt_dccp.c index 8d0b13a..a35cabb 100644 --- a/extensions/libxt_dccp.c +++ b/extensions/libxt_dccp.c @@ -5,14 +5,12 @@ * This program is distributed under the terms of GNU GPL v2, 1991 * */ +#include <stdint.h> #include <stdio.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <netdb.h> -#include <ctype.h> - -#include <netinet/in.h> +#include <arpa/inet.h> #include <xtables.h> #include <linux/dccp.h> #include <linux/netfilter/x_tables.h> @@ -25,12 +23,12 @@ #define DEBUGP(format, fist...) #endif -static void dccp_init(struct xt_entry_match *m) -{ - struct xt_dccp_info *einfo = (struct xt_dccp_info *)m->data; - - memset(einfo, 0, sizeof(struct xt_dccp_info)); -} +enum { + O_SOURCE_PORT = 0, + O_DEST_PORT, + O_DCCP_TYPES, + O_DCCP_OPTION, +}; static void dccp_help(void) { @@ -39,44 +37,30 @@ static void dccp_help(void) "[!] --source-port port[:port] match source port(s)\n" " --sport ...\n" "[!] --destination-port port[:port] match destination port(s)\n" -" --dport ...\n"); +" --dport ...\n" +"[!] --dccp-types type[,...] match when packet is one of the given types\n" +"[!] --dccp-option option match if option (by number!) is set\n" +); } -static const struct option dccp_opts[] = { - { .name = "source-port", .has_arg = 1, .val = '1' }, - { .name = "sport", .has_arg = 1, .val = '1' }, - { .name = "destination-port", .has_arg = 1, .val = '2' }, - { .name = "dport", .has_arg = 1, .val = '2' }, - { .name = "dccp-types", .has_arg = 1, .val = '3' }, - { .name = "dccp-option", .has_arg = 1, .val = '4' }, - { .name = NULL } +#define s struct xt_dccp_info +static const struct xt_option_entry dccp_opts[] = { + {.name = "source-port", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)}, + {.name = "sport", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)}, + {.name = "destination-port", .id = O_DEST_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)}, + {.name = "dport", .id = O_DEST_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)}, + {.name = "dccp-types", .id = O_DCCP_TYPES, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "dccp-option", .id = O_DCCP_OPTION, .type = XTTYPE_UINT8, + .min = 1, .max = UINT8_MAX, .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, option)}, + XTOPT_TABLEEND, }; - -static void -parse_dccp_ports(const char *portstring, - u_int16_t *ports) -{ - char *buffer; - char *cp; - - buffer = strdup(portstring); - DEBUGP("%s\n", portstring); - if ((cp = strchr(buffer, ':')) == NULL) { - ports[0] = ports[1] = xtables_parse_port(buffer, "dccp"); - } - else { - *cp = '\0'; - cp++; - - ports[0] = buffer[0] ? xtables_parse_port(buffer, "dccp") : 0; - ports[1] = cp[0] ? xtables_parse_port(cp, "dccp") : 0xFFFF; - - if (ports[0] > ports[1]) - xtables_error(PARAMETER_PROBLEM, - "invalid portrange (min > max)"); - } - free(buffer); -} +#undef s static const char *const dccp_pkt_types[] = { [DCCP_PKT_REQUEST] = "REQUEST", @@ -92,10 +76,10 @@ static const char *const dccp_pkt_types[] = { [DCCP_PKT_INVALID] = "INVALID", }; -static u_int16_t +static uint16_t parse_dccp_types(const char *typestring) { - u_int16_t typemask = 0; + uint16_t typemask = 0; char *ptr, *buffer; buffer = strdup(typestring); @@ -116,82 +100,40 @@ parse_dccp_types(const char *typestring) return typemask; } -static u_int8_t parse_dccp_option(char *optstring) -{ - unsigned int ret; - - if (!xtables_strtoui(optstring, NULL, &ret, 1, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, "Bad DCCP option \"%s\"", - optstring); - - return ret; -} - -static int -dccp_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void dccp_parse(struct xt_option_call *cb) { - struct xt_dccp_info *einfo - = (struct xt_dccp_info *)(*match)->data; + struct xt_dccp_info *einfo = cb->data; - switch (c) { - case '1': - if (*flags & XT_DCCP_SRC_PORTS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--source-port' allowed"); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SOURCE_PORT: einfo->flags |= XT_DCCP_SRC_PORTS; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_dccp_ports(optarg, einfo->spts); - if (invert) + if (cb->invert) einfo->invflags |= XT_DCCP_SRC_PORTS; - *flags |= XT_DCCP_SRC_PORTS; break; - - case '2': - if (*flags & XT_DCCP_DEST_PORTS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--destination-port' allowed"); + case O_DEST_PORT: einfo->flags |= XT_DCCP_DEST_PORTS; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_dccp_ports(optarg, einfo->dpts); - if (invert) + if (cb->invert) einfo->invflags |= XT_DCCP_DEST_PORTS; - *flags |= XT_DCCP_DEST_PORTS; break; - - case '3': - if (*flags & XT_DCCP_TYPE) - xtables_error(PARAMETER_PROBLEM, - "Only one `--dccp-types' allowed"); + case O_DCCP_TYPES: einfo->flags |= XT_DCCP_TYPE; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - einfo->typemask = parse_dccp_types(optarg); - if (invert) + einfo->typemask = parse_dccp_types(cb->arg); + if (cb->invert) einfo->invflags |= XT_DCCP_TYPE; - *flags |= XT_DCCP_TYPE; break; - - case '4': - if (*flags & XT_DCCP_OPTION) - xtables_error(PARAMETER_PROBLEM, - "Only one `--dccp-option' allowed"); + case O_DCCP_OPTION: einfo->flags |= XT_DCCP_OPTION; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - einfo->option = parse_dccp_option(optarg); - if (invert) + if (cb->invert) einfo->invflags |= XT_DCCP_OPTION; - *flags |= XT_DCCP_OPTION; break; - default: - return 0; } - return 1; } -static char * +static const char * port_to_service(int port) { - struct servent *service; + const struct servent *service; if ((service = getservbyport(htons(port), "dccp"))) return service->s_name; @@ -200,9 +142,9 @@ port_to_service(int port) } static void -print_port(u_int16_t port, int numeric) +print_port(uint16_t port, int numeric) { - char *service; + const char *service; if (numeric || (service = port_to_service(port)) == NULL) printf("%u", port); @@ -211,13 +153,13 @@ print_port(u_int16_t port, int numeric) } static void -print_ports(const char *name, u_int16_t min, u_int16_t max, +print_ports(const char *name, uint16_t min, uint16_t max, int invert, int numeric) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFFFF || invert) { - printf("%s", name); + printf(" %s", name); if (min == max) { printf(":%s", inv); print_port(min, numeric); @@ -227,18 +169,18 @@ print_ports(const char *name, u_int16_t min, u_int16_t max, printf(":"); print_port(max, numeric); } - printf(" "); } } static void -print_types(u_int16_t types, int inverted, int numeric) +print_types(uint16_t types, int inverted, int numeric) { int have_type = 0; if (inverted) - printf("! "); + printf(" !"); + printf(" "); while (types) { unsigned int i; @@ -259,10 +201,10 @@ print_types(u_int16_t types, int inverted, int numeric) } static void -print_option(u_int8_t option, int invert, int numeric) +print_option(uint8_t option, int invert, int numeric) { if (option || invert) - printf("option=%s%u ", invert ? "!" : "", option); + printf(" option=%s%u", invert ? "!" : "", option); } static void @@ -271,7 +213,7 @@ dccp_print(const void *ip, const struct xt_entry_match *match, int numeric) const struct xt_dccp_info *einfo = (const struct xt_dccp_info *)match->data; - printf("dccp "); + printf(" dccp"); if (einfo->flags & XT_DCCP_SRC_PORTS) { print_ports("spt", einfo->spts[0], einfo->spts[1], @@ -304,32 +246,33 @@ static void dccp_save(const void *ip, const struct xt_entry_match *match) if (einfo->flags & XT_DCCP_SRC_PORTS) { if (einfo->invflags & XT_DCCP_SRC_PORTS) - printf("! "); + printf(" !"); if (einfo->spts[0] != einfo->spts[1]) - printf("--sport %u:%u ", + printf(" --sport %u:%u", einfo->spts[0], einfo->spts[1]); else - printf("--sport %u ", einfo->spts[0]); + printf(" --sport %u", einfo->spts[0]); } if (einfo->flags & XT_DCCP_DEST_PORTS) { if (einfo->invflags & XT_DCCP_DEST_PORTS) - printf("! "); + printf(" !"); if (einfo->dpts[0] != einfo->dpts[1]) - printf("--dport %u:%u ", + printf(" --dport %u:%u", einfo->dpts[0], einfo->dpts[1]); else - printf("--dport %u ", einfo->dpts[0]); + printf(" --dport %u", einfo->dpts[0]); } if (einfo->flags & XT_DCCP_TYPE) { - printf("--dccp-type "); - print_types(einfo->typemask, einfo->invflags & XT_DCCP_TYPE,0); + printf("%s --dccp-types", + einfo->invflags & XT_DCCP_TYPE ? " !" : ""); + print_types(einfo->typemask, false, 0); } if (einfo->flags & XT_DCCP_OPTION) { - printf("--dccp-option %s%u ", - einfo->typemask & XT_DCCP_OPTION ? "! " : "", + printf("%s --dccp-option %u", + einfo->invflags & XT_DCCP_OPTION ? " !" : "", einfo->option); } } @@ -341,11 +284,10 @@ static struct xtables_match dccp_match = { .size = XT_ALIGN(sizeof(struct xt_dccp_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_dccp_info)), .help = dccp_help, - .init = dccp_init, - .parse = dccp_parse, .print = dccp_print, .save = dccp_save, - .extra_opts = dccp_opts, + .x6_parse = dccp_parse, + .x6_options = dccp_opts, }; void _init(void) diff --git a/extensions/libxt_dccp.man b/extensions/libxt_dccp.man index 82c3f70..71beb4b 100644 --- a/extensions/libxt_dccp.man +++ b/extensions/libxt_dccp.man @@ -9,4 +9,4 @@ list of packet types. Packet types are: .BR "REQUEST RESPONSE DATA ACK DATAACK CLOSEREQ CLOSE RESET SYNC SYNCACK INVALID" . .TP [\fB!\fP] \fB\-\-dccp\-option\fP \fInumber\fP -Match if DCP option set. +Match if DCCP option set. diff --git a/extensions/libxt_devgroup.c b/extensions/libxt_devgroup.c new file mode 100644 index 0000000..4a69c82 --- /dev/null +++ b/extensions/libxt_devgroup.c @@ -0,0 +1,172 @@ +/* Shared library add-on to iptables to add devgroup matching support. + * + * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <xtables.h> +#include <linux/netfilter/xt_devgroup.h> + +static void devgroup_help(void) +{ + printf( +"devgroup match options:\n" +"[!] --src-group value[/mask] Match device group of incoming device\n" +"[!] --dst-group value[/mask] Match device group of outgoing device\n" + ); +} + +enum { + O_SRC_GROUP = 0, + O_DST_GROUP, +}; + +static const struct xt_option_entry devgroup_opts[] = { + {.name = "src-group", .id = O_SRC_GROUP, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "dst-group", .id = O_DST_GROUP, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, +}; + +/* array of devgroups from /etc/iproute2/group_map */ +static struct xtables_lmap *devgroups; + +static void devgroup_init(struct xt_entry_match *match) +{ + const char file[] = "/etc/iproute2/group_map"; + devgroups = xtables_lmap_init(file); + if (devgroups == NULL && errno != ENOENT) + fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno)); +} + +static void devgroup_parse_groupspec(const char *arg, unsigned int *group, + unsigned int *mask) +{ + char *end; + bool ok; + + ok = xtables_strtoui(arg, &end, group, 0, UINT32_MAX); + if (ok && (*end == '/' || *end == '\0')) { + if (*end == '/') + ok = xtables_strtoui(end + 1, NULL, mask, + 0, UINT32_MAX); + else + *mask = ~0U; + if (!ok) + xtables_error(PARAMETER_PROBLEM, + "Bad group value \"%s\"", arg); + } else { + *group = xtables_lmap_name2id(devgroups, arg); + if (*group == -1) + xtables_error(PARAMETER_PROBLEM, + "Device group \"%s\" not found", arg); + *mask = ~0U; + } +} + +static void devgroup_parse(struct xt_option_call *cb) +{ + struct xt_devgroup_info *info = cb->data; + unsigned int id, mask; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRC_GROUP: + devgroup_parse_groupspec(cb->arg, &id, &mask); + info->src_group = id; + info->src_mask = mask; + info->flags |= XT_DEVGROUP_MATCH_SRC; + if (cb->invert) + info->flags |= XT_DEVGROUP_INVERT_SRC; + break; + case O_DST_GROUP: + devgroup_parse_groupspec(cb->arg, &id, &mask); + info->dst_group = id; + info->dst_mask = mask; + info->flags |= XT_DEVGROUP_MATCH_DST; + if (cb->invert) + info->flags |= XT_DEVGROUP_INVERT_DST; + break; + } +} + +static void +print_devgroup(unsigned int id, unsigned int mask, int numeric) +{ + const char *name = NULL; + + if (mask != 0xffffffff) + printf("0x%x/0x%x", id, mask); + else { + if (numeric == 0) + name = xtables_lmap_id2name(devgroups, id); + if (name) + printf("%s", name); + else + printf("0x%x", id); + } +} + +static void devgroup_show(const char *pfx, const struct xt_devgroup_info *info, + int numeric) +{ + if (info->flags & XT_DEVGROUP_MATCH_SRC) { + if (info->flags & XT_DEVGROUP_INVERT_SRC) + printf(" !"); + printf(" %ssrc-group ", pfx); + print_devgroup(info->src_group, info->src_mask, numeric); + } + + if (info->flags & XT_DEVGROUP_MATCH_DST) { + if (info->flags & XT_DEVGROUP_INVERT_DST) + printf(" !"); + printf(" %sdst-group ", pfx); + print_devgroup(info->src_group, info->src_mask, numeric); + } +} + +static void devgroup_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_devgroup_info *info = (const void *)match->data; + + devgroup_show("", info, numeric); +} + +static void devgroup_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_devgroup_info *info = (const void *)match->data; + + devgroup_show("--", info, 0); +} + +static void devgroup_check(struct xt_fcheck_call *cb) +{ + if (cb->xflags == 0) + xtables_error(PARAMETER_PROBLEM, + "devgroup match: You must specify either " + "'--src-group' or '--dst-group'"); +} + +static struct xtables_match devgroup_mt_reg = { + .name = "devgroup", + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_devgroup_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_devgroup_info)), + .init = devgroup_init, + .help = devgroup_help, + .print = devgroup_print, + .save = devgroup_save, + .x6_parse = devgroup_parse, + .x6_fcheck = devgroup_check, + .x6_options = devgroup_opts, +}; + +void _init(void) +{ + xtables_register_match(&devgroup_mt_reg); +} diff --git a/extensions/libxt_devgroup.man b/extensions/libxt_devgroup.man new file mode 100644 index 0000000..4a66c9f --- /dev/null +++ b/extensions/libxt_devgroup.man @@ -0,0 +1,7 @@ +Match device group of a packets incoming/outgoing interface. +.TP +[\fB!\fP] \fB\-\-src\-group\fP \fIname\fP +Match device group of incoming device +.TP +[\fB!\fP] \fB\-\-dst\-group\fP \fIname\fP +Match device group of outgoing device diff --git a/extensions/libxt_dscp.c b/extensions/libxt_dscp.c index 1569f7d..02b22a4 100644 --- a/extensions/libxt_dscp.c +++ b/extensions/libxt_dscp.c @@ -14,16 +14,19 @@ */ #include <stdio.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> -#include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_dscp.h> /* This is evil, but it's my code - HW*/ #include "dscp_helper.c" +enum { + O_DSCP = 0, + O_DSCP_CLASS, + F_DSCP = 1 << O_DSCP, + F_DSCP_CLASS = 1 << O_DSCP_CLASS, +}; + static void dscp_help(void) { printf( @@ -37,79 +40,37 @@ static void dscp_help(void) " These two options are mutually exclusive !\n"); } -static const struct option dscp_opts[] = { - { "dscp", 1, NULL, 'F' }, - { "dscp-class", 1, NULL, 'G' }, - { .name = NULL } +static const struct xt_option_entry dscp_opts[] = { + {.name = "dscp", .id = O_DSCP, .excl = F_DSCP_CLASS, + .type = XTTYPE_UINT8, .min = 0, .max = XT_DSCP_MAX, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_dscp_info, dscp)}, + {.name = "dscp-class", .id = O_DSCP_CLASS, .excl = F_DSCP, + .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, }; -static void -parse_dscp(const char *s, struct xt_dscp_info *dinfo) +static void dscp_parse(struct xt_option_call *cb) { - unsigned int dscp; - - if (!xtables_strtoui(s, NULL, &dscp, 0, UINT8_MAX)) - xtables_error(PARAMETER_PROBLEM, - "Invalid dscp `%s'\n", s); + struct xt_dscp_info *dinfo = cb->data; - if (dscp > XT_DSCP_MAX) - xtables_error(PARAMETER_PROBLEM, - "DSCP `%d` out of range\n", dscp); - - dinfo->dscp = dscp; -} - - -static void -parse_class(const char *s, struct xt_dscp_info *dinfo) -{ - unsigned int dscp = class_to_dscp(s); - - /* Assign the value */ - dinfo->dscp = dscp; -} - - -static int -dscp_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct xt_dscp_info *dinfo - = (struct xt_dscp_info *)(*match)->data; - - switch (c) { - case 'F': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "DSCP match: Only use --dscp ONCE!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_dscp(optarg, dinfo); - if (invert) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_DSCP: + if (cb->invert) dinfo->invert = 1; - *flags = 1; break; - - case 'G': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "DSCP match: Only use --dscp-class ONCE!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_class(optarg, dinfo); - if (invert) + case O_DSCP_CLASS: + dinfo->dscp = class_to_dscp(cb->arg); + if (cb->invert) dinfo->invert = 1; - *flags = 1; break; - - default: - return 0; } - - return 1; } -static void dscp_check(unsigned int flags) +static void dscp_check(struct xt_fcheck_call *cb) { - if (!flags) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "DSCP match: Parameter --dscp is required"); } @@ -119,7 +80,7 @@ dscp_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_dscp_info *dinfo = (const struct xt_dscp_info *)match->data; - printf("DSCP match %s0x%02x", dinfo->invert ? "!" : "", dinfo->dscp); + printf(" DSCP match %s0x%02x", dinfo->invert ? "!" : "", dinfo->dscp); } static void dscp_save(const void *ip, const struct xt_entry_match *match) @@ -127,7 +88,7 @@ static void dscp_save(const void *ip, const struct xt_entry_match *match) const struct xt_dscp_info *dinfo = (const struct xt_dscp_info *)match->data; - printf("%s--dscp 0x%02x ", dinfo->invert ? "! " : "", dinfo->dscp); + printf("%s --dscp 0x%02x", dinfo->invert ? " !" : "", dinfo->dscp); } static struct xtables_match dscp_match = { @@ -137,11 +98,11 @@ static struct xtables_match dscp_match = { .size = XT_ALIGN(sizeof(struct xt_dscp_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_dscp_info)), .help = dscp_help, - .parse = dscp_parse, - .final_check = dscp_check, .print = dscp_print, .save = dscp_save, - .extra_opts = dscp_opts, + .x6_parse = dscp_parse, + .x6_fcheck = dscp_check, + .x6_options = dscp_opts, }; void _init(void) diff --git a/extensions/libxt_ecn.c b/extensions/libxt_ecn.c new file mode 100644 index 0000000..286782a --- /dev/null +++ b/extensions/libxt_ecn.c @@ -0,0 +1,138 @@ +/* Shared library add-on to iptables for ECN matching + * + * (C) 2002 by Harald Welte <laforge@netfilter.org> + * (C) 2011 by Patrick McHardy <kaber@trash.net> + * + * This program is distributed under the terms of GNU GPL v2, 1991 + * + * libipt_ecn.c borrowed heavily from libipt_dscp.c + * + */ +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter/xt_ecn.h> + +enum { + O_ECN_TCP_CWR = 0, + O_ECN_TCP_ECE, + O_ECN_IP_ECT, +}; + +static void ecn_help(void) +{ + printf( +"ECN match options\n" +"[!] --ecn-tcp-cwr Match CWR bit of TCP header\n" +"[!] --ecn-tcp-ece Match ECE bit of TCP header\n" +"[!] --ecn-ip-ect [0..3] Match ECN codepoint in IPv4/IPv6 header\n"); +} + +static const struct xt_option_entry ecn_opts[] = { + {.name = "ecn-tcp-cwr", .id = O_ECN_TCP_CWR, .type = XTTYPE_NONE, + .flags = XTOPT_INVERT}, + {.name = "ecn-tcp-ece", .id = O_ECN_TCP_ECE, .type = XTTYPE_NONE, + .flags = XTOPT_INVERT}, + {.name = "ecn-ip-ect", .id = O_ECN_IP_ECT, .type = XTTYPE_UINT8, + .min = 0, .max = 3, .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, +}; + +static void ecn_parse(struct xt_option_call *cb) +{ + struct xt_ecn_info *einfo = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_ECN_TCP_CWR: + einfo->operation |= XT_ECN_OP_MATCH_CWR; + if (cb->invert) + einfo->invert |= XT_ECN_OP_MATCH_CWR; + break; + case O_ECN_TCP_ECE: + einfo->operation |= XT_ECN_OP_MATCH_ECE; + if (cb->invert) + einfo->invert |= XT_ECN_OP_MATCH_ECE; + break; + case O_ECN_IP_ECT: + if (cb->invert) + einfo->invert |= XT_ECN_OP_MATCH_IP; + einfo->operation |= XT_ECN_OP_MATCH_IP; + einfo->ip_ect = cb->val.u8; + break; + } +} + +static void ecn_check(struct xt_fcheck_call *cb) +{ + if (cb->xflags == 0) + xtables_error(PARAMETER_PROBLEM, + "ECN match: some option required"); +} + +static void ecn_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_ecn_info *einfo = + (const struct xt_ecn_info *)match->data; + + printf(" ECN match"); + + if (einfo->operation & XT_ECN_OP_MATCH_ECE) { + printf(" %sECE", + (einfo->invert & XT_ECN_OP_MATCH_ECE) ? "!" : ""); + } + + if (einfo->operation & XT_ECN_OP_MATCH_CWR) { + printf(" %sCWR", + (einfo->invert & XT_ECN_OP_MATCH_CWR) ? "!" : ""); + } + + if (einfo->operation & XT_ECN_OP_MATCH_IP) { + printf(" %sECT=%d", + (einfo->invert & XT_ECN_OP_MATCH_IP) ? "!" : "", + einfo->ip_ect); + } +} + +static void ecn_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_ecn_info *einfo = + (const struct xt_ecn_info *)match->data; + + if (einfo->operation & XT_ECN_OP_MATCH_ECE) { + if (einfo->invert & XT_ECN_OP_MATCH_ECE) + printf(" !"); + printf(" --ecn-tcp-ece"); + } + + if (einfo->operation & XT_ECN_OP_MATCH_CWR) { + if (einfo->invert & XT_ECN_OP_MATCH_CWR) + printf(" !"); + printf(" --ecn-tcp-cwr"); + } + + if (einfo->operation & XT_ECN_OP_MATCH_IP) { + if (einfo->invert & XT_ECN_OP_MATCH_IP) + printf(" !"); + printf(" --ecn-ip-ect %d", einfo->ip_ect); + } +} + +static struct xtables_match ecn_mt_reg = { + .name = "ecn", + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_ecn_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_ecn_info)), + .help = ecn_help, + .print = ecn_print, + .save = ecn_save, + .x6_parse = ecn_parse, + .x6_fcheck = ecn_check, + .x6_options = ecn_opts, +}; + +void _init(void) +{ + xtables_register_match(&ecn_mt_reg); +} diff --git a/extensions/libipt_ecn.man b/extensions/libxt_ecn.man index 7f80647..31c0a3e 100644 --- a/extensions/libipt_ecn.man +++ b/extensions/libxt_ecn.man @@ -1,4 +1,4 @@ -This allows you to match the ECN bits of the IPv4 and TCP header. ECN is the Explicit Congestion Notification mechanism as specified in RFC3168 +This allows you to match the ECN bits of the IPv4/IPv6 and TCP header. ECN is the Explicit Congestion Notification mechanism as specified in RFC3168 .TP [\fB!\fP] \fB\-\-ecn\-tcp\-cwr\fP This matches if the TCP ECN CWR (Congestion Window Received) bit is set. @@ -7,5 +7,5 @@ This matches if the TCP ECN CWR (Congestion Window Received) bit is set. This matches if the TCP ECN ECE (ECN Echo) bit is set. .TP [\fB!\fP] \fB\-\-ecn\-ip\-ect\fP \fInum\fP -This matches a particular IPv4 ECT (ECN-Capable Transport). You have to specify +This matches a particular IPv4/IPv6 ECT (ECN-Capable Transport). You have to specify a number between `0' and `3'. diff --git a/extensions/libxt_esp.c b/extensions/libxt_esp.c index 18218f4..294338b 100644 --- a/extensions/libxt_esp.c +++ b/extensions/libxt_esp.c @@ -1,15 +1,11 @@ -/* 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 <limits.h> - #include <xtables.h> #include <linux/netfilter/xt_esp.h> +enum { + O_ESPSPI = 0, +}; + static void esp_help(void) { printf( @@ -18,100 +14,35 @@ static void esp_help(void) " match spi (range)\n"); } -static const struct option esp_opts[] = { - { "espspi", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry esp_opts[] = { + {.name = "espspi", .id = O_ESPSPI, .type = XTTYPE_UINT32RC, + .flags = XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_esp, spis)}, + XTOPT_TABLEEND, }; -static u_int32_t -parse_esp_spi(const char *spistr) -{ - unsigned long int spi; - char* ep; - - spi = strtoul(spistr,&ep,0) ; - - if ( spistr == ep ) { - xtables_error(PARAMETER_PROBLEM, - "ESP no valid digits in spi `%s'", spistr); - } - if ( spi == ULONG_MAX && errno == ERANGE ) { - xtables_error(PARAMETER_PROBLEM, - "spi `%s' specified too big: would overflow", spistr); - } - if ( *spistr != '\0' && *ep != '\0' ) { - xtables_error(PARAMETER_PROBLEM, - "ESP error parsing spi `%s'", spistr); - } - return 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; - if (spis[0] > spis[1]) - xtables_error(PARAMETER_PROBLEM, - "Invalid ESP spi range: %s", spistring); - } - free(buffer); -} - -static void esp_init(struct xt_entry_match *m) -{ - struct xt_esp *espinfo = (struct xt_esp *)m->data; - - espinfo->spis[1] = 0xFFFFFFFF; -} - -#define ESP_SPI 0x01 - -static int -esp_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void esp_parse(struct xt_option_call *cb) { - struct xt_esp *espinfo = (struct xt_esp *)(*match)->data; - - switch (c) { - case '1': - if (*flags & ESP_SPI) - xtables_error(PARAMETER_PROBLEM, - "Only one `--espspi' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_esp_spis(optarg, espinfo->spis); - if (invert) - espinfo->invflags |= XT_ESP_INV_SPI; - *flags |= ESP_SPI; - break; - default: - return 0; - } + struct xt_esp *espinfo = cb->data; - return 1; + xtables_option_parse(cb); + if (cb->nvals == 1) + espinfo->spis[1] = espinfo->spis[0]; + if (cb->invert) + espinfo->invflags |= XT_ESP_INV_SPI; } static void -print_spis(const char *name, u_int32_t min, u_int32_t max, +print_spis(const char *name, uint32_t min, uint32_t max, int invert) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFFFFFFFF || invert) { if (min == max) - printf("%s:%s%u ", name, inv, min); + printf(" %s:%s%u", name, inv, min); else - printf("%ss:%s%u:%u ", name, inv, min, max); + printf(" %ss:%s%u:%u", name, inv, min, max); } } @@ -120,11 +51,11 @@ esp_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_esp *esp = (struct xt_esp *)match->data; - printf("esp "); + printf(" esp"); print_spis("spi", esp->spis[0], esp->spis[1], esp->invflags & XT_ESP_INV_SPI); if (esp->invflags & ~XT_ESP_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", esp->invflags & ~XT_ESP_INV_MASK); } @@ -134,15 +65,15 @@ static void esp_save(const void *ip, const struct xt_entry_match *match) if (!(espinfo->spis[0] == 0 && espinfo->spis[1] == 0xFFFFFFFF)) { - printf("%s--espspi ", - (espinfo->invflags & XT_ESP_INV_SPI) ? "! " : ""); + printf("%s --espspi ", + (espinfo->invflags & XT_ESP_INV_SPI) ? " !" : ""); if (espinfo->spis[0] != espinfo->spis[1]) - printf("%u:%u ", + printf("%u:%u", espinfo->spis[0], espinfo->spis[1]); else - printf("%u ", + printf("%u", espinfo->spis[0]); } @@ -155,11 +86,10 @@ static struct xtables_match esp_match = { .size = XT_ALIGN(sizeof(struct xt_esp)), .userspacesize = XT_ALIGN(sizeof(struct xt_esp)), .help = esp_help, - .init = esp_init, - .parse = esp_parse, .print = esp_print, .save = esp_save, - .extra_opts = esp_opts, + .x6_parse = esp_parse, + .x6_options = esp_opts, }; void diff --git a/extensions/libxt_hashlimit.c b/extensions/libxt_hashlimit.c index 7442dfc..c5b8d77 100644 --- a/extensions/libxt_hashlimit.c +++ b/extensions/libxt_hashlimit.c @@ -10,22 +10,30 @@ * * Error corections by nmalykh@bilim.com (22.01.2005) */ +#define _BSD_SOURCE 1 +#define _ISOC99_SOURCE 1 +#include <math.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <xtables.h> -#include <stddef.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_hashlimit.h> #define XT_HASHLIMIT_BURST 5 +#define XT_HASHLIMIT_BURST_MAX 10000 + +#define XT_HASHLIMIT_BYTE_EXPIRE 15 +#define XT_HASHLIMIT_BYTE_EXPIRE_BURST 60 /* miliseconds */ #define XT_HASHLIMIT_GCINTERVAL 1000 -#define XT_HASHLIMIT_EXPIRE 10000 + +struct hashlimit_mt_udata { + uint32_t mult; +}; static void hashlimit_help(void) { @@ -45,6 +53,25 @@ static void hashlimit_help(void) XT_HASHLIMIT_BURST); } +enum { + O_UPTO = 0, + O_ABOVE, + O_LIMIT, + O_MODE, + O_SRCMASK, + O_DSTMASK, + O_NAME, + O_BURST, + O_HTABLE_SIZE, + O_HTABLE_MAX, + O_HTABLE_GCINT, + O_HTABLE_EXPIRE, + F_BURST = 1 << O_BURST, + F_UPTO = 1 << O_UPTO, + F_ABOVE = 1 << O_ABOVE, + F_HTABLE_EXPIRE = 1 << O_HTABLE_EXPIRE, +}; + static void hashlimit_mt_help(void) { printf( @@ -66,54 +93,159 @@ static void hashlimit_mt_help(void) "\n", XT_HASHLIMIT_BURST); } -static const struct option hashlimit_opts[] = { - { "hashlimit", 1, NULL, '%' }, - { "hashlimit-burst", 1, NULL, '$' }, - { "hashlimit-htable-size", 1, NULL, '&' }, - { "hashlimit-htable-max", 1, NULL, '*' }, - { "hashlimit-htable-gcinterval", 1, NULL, '(' }, - { "hashlimit-htable-expire", 1, NULL, ')' }, - { "hashlimit-mode", 1, NULL, '_' }, - { "hashlimit-name", 1, NULL, '"' }, - { .name = NULL } +#define s struct xt_hashlimit_info +static const struct xt_option_entry hashlimit_opts[] = { + {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, + .type = XTTYPE_STRING}, + {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_UINT32, + .min = 1, .max = XT_HASHLIMIT_BURST_MAX, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.burst)}, + {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.size)}, + {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.max)}, + {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.gc_interval)}, + {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.expire)}, + {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, + XTOPT_TABLEEND, }; - -static const struct option hashlimit_mt_opts[] = { - {.name = "hashlimit-upto", .has_arg = true, .val = '%'}, - {.name = "hashlimit-above", .has_arg = true, .val = '^'}, - {.name = "hashlimit", .has_arg = true, .val = '%'}, - {.name = "hashlimit-srcmask", .has_arg = true, .val = '<'}, - {.name = "hashlimit-dstmask", .has_arg = true, .val = '>'}, - {.name = "hashlimit-burst", .has_arg = true, .val = '$'}, - {.name = "hashlimit-htable-size", .has_arg = true, .val = '&'}, - {.name = "hashlimit-htable-max", .has_arg = true, .val = '*'}, - {.name = "hashlimit-htable-gcinterval", .has_arg = true, .val = '('}, - {.name = "hashlimit-htable-expire", .has_arg = true, .val = ')'}, - {.name = "hashlimit-mode", .has_arg = true, .val = '_'}, - {.name = "hashlimit-name", .has_arg = true, .val = '"'}, - {}, +#undef s + +#define s struct xt_hashlimit_mtinfo1 +static const struct xt_option_entry hashlimit_mt_opts[] = { + {.name = "hashlimit-upto", .id = O_UPTO, .excl = F_ABOVE, + .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, + {.name = "hashlimit-above", .id = O_ABOVE, .excl = F_UPTO, + .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, + {.name = "hashlimit", .id = O_UPTO, .excl = F_ABOVE, + .type = XTTYPE_STRING, .flags = XTOPT_INVERT}, /* old name */ + {.name = "hashlimit-srcmask", .id = O_SRCMASK, .type = XTTYPE_PLEN}, + {.name = "hashlimit-dstmask", .id = O_DSTMASK, .type = XTTYPE_PLEN}, + {.name = "hashlimit-burst", .id = O_BURST, .type = XTTYPE_STRING}, + {.name = "hashlimit-htable-size", .id = O_HTABLE_SIZE, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.size)}, + {.name = "hashlimit-htable-max", .id = O_HTABLE_MAX, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.max)}, + {.name = "hashlimit-htable-gcinterval", .id = O_HTABLE_GCINT, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.gc_interval)}, + {.name = "hashlimit-htable-expire", .id = O_HTABLE_EXPIRE, + .type = XTTYPE_UINT32, .flags = XTOPT_PUT, + XTOPT_POINTER(s, cfg.expire)}, + {.name = "hashlimit-mode", .id = O_MODE, .type = XTTYPE_STRING}, + {.name = "hashlimit-name", .id = O_NAME, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, name), .min = 1}, + XTOPT_TABLEEND, }; +#undef s + +static uint32_t cost_to_bytes(uint32_t cost) +{ + uint32_t r; + + r = cost ? UINT32_MAX / cost : UINT32_MAX; + r = (r - 1) << XT_HASHLIMIT_BYTE_SHIFT; + return r; +} + +static uint64_t bytes_to_cost(uint32_t bytes) +{ + uint32_t r = bytes >> XT_HASHLIMIT_BYTE_SHIFT; + return UINT32_MAX / (r+1); +} + +static uint32_t get_factor(int chr) +{ + switch (chr) { + case 'm': return 1024 * 1024; + case 'k': return 1024; + } + return 1; +} + +static void burst_error(void) +{ + xtables_error(PARAMETER_PROBLEM, "bad value for option " + "\"--hashlimit-burst\", or out of range (1-%u).", XT_HASHLIMIT_BURST_MAX); +} + +static uint32_t parse_burst(const char *burst, struct xt_hashlimit_mtinfo1 *info) +{ + uintmax_t v; + char *end; + + if (!xtables_strtoul(burst, &end, &v, 1, UINT32_MAX) || + (*end == 0 && v > XT_HASHLIMIT_BURST_MAX)) + burst_error(); + + v *= get_factor(*end); + if (v > UINT32_MAX) + xtables_error(PARAMETER_PROBLEM, "bad value for option " + "\"--hashlimit-burst\", value \"%s\" too large " + "(max %umb).", burst, UINT32_MAX/1024/1024); + return v; +} + +static bool parse_bytes(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud) +{ + unsigned int factor = 1; + uint64_t tmp; + int r; + const char *mode = strstr(rate, "b/s"); + if (!mode || mode == rate) + return false; + + mode--; + r = atoi(rate); + if (r == 0) + return false; + + factor = get_factor(*mode); + tmp = (uint64_t) r * factor; + if (tmp > UINT32_MAX) + xtables_error(PARAMETER_PROBLEM, + "Rate value too large \"%llu\" (max %u)\n", + (unsigned long long)tmp, UINT32_MAX); + + *val = bytes_to_cost(tmp); + if (*val == 0) + xtables_error(PARAMETER_PROBLEM, "Rate too high \"%s\"\n", rate); + + ud->mult = XT_HASHLIMIT_BYTE_EXPIRE; + return true; +} static -int parse_rate(const char *rate, u_int32_t *val) +int parse_rate(const char *rate, uint32_t *val, struct hashlimit_mt_udata *ud) { const char *delim; - u_int32_t r; - u_int32_t mult = 1; /* Seconds by default. */ + uint32_t r; + ud->mult = 1; /* Seconds by default. */ delim = strchr(rate, '/'); if (delim) { if (strlen(delim+1) == 0) return 0; if (strncasecmp(delim+1, "second", strlen(delim+1)) == 0) - mult = 1; + ud->mult = 1; else if (strncasecmp(delim+1, "minute", strlen(delim+1)) == 0) - mult = 60; + ud->mult = 60; else if (strncasecmp(delim+1, "hour", strlen(delim+1)) == 0) - mult = 60*60; + ud->mult = 60*60; else if (strncasecmp(delim+1, "day", strlen(delim+1)) == 0) - mult = 24*60*60; + ud->mult = 24*60*60; else return 0; } @@ -121,12 +253,13 @@ int parse_rate(const char *rate, u_int32_t *val) if (!r) return 0; - /* This would get mapped to infinite (1/day is minimum they - can specify, so we're ok at that end). */ - if (r / mult > XT_HASHLIMIT_SCALE) + *val = XT_HASHLIMIT_SCALE * ud->mult / r; + if (*val == 0) + /* + * The rate maps to infinity. (1/day is the minimum they can + * specify, so we are ok at that end). + */ xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); - - *val = XT_HASHLIMIT_SCALE * mult / r; return 1; } @@ -134,10 +267,8 @@ static void hashlimit_init(struct xt_entry_match *m) { struct xt_hashlimit_info *r = (struct xt_hashlimit_info *)m->data; - r->cfg.mode = 0; r->cfg.burst = XT_HASHLIMIT_BURST; r->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; - r->cfg.expire = XT_HASHLIMIT_EXPIRE; } @@ -148,7 +279,6 @@ static void hashlimit_mt4_init(struct xt_entry_match *match) info->cfg.mode = 0; info->cfg.burst = XT_HASHLIMIT_BURST; info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; - info->cfg.expire = XT_HASHLIMIT_EXPIRE; info->cfg.srcmask = 32; info->cfg.dstmask = 32; } @@ -160,13 +290,12 @@ static void hashlimit_mt6_init(struct xt_entry_match *match) info->cfg.mode = 0; info->cfg.burst = XT_HASHLIMIT_BURST; info->cfg.gc_interval = XT_HASHLIMIT_GCINTERVAL; - info->cfg.expire = XT_HASHLIMIT_EXPIRE; info->cfg.srcmask = 128; info->cfg.dstmask = 128; } /* Parse a 'mode' parameter into the required bitmask */ -static int parse_mode(uint32_t *mode, char *option_arg) +static int parse_mode(uint32_t *mode, const char *option_arg) { char *tok; char *arg = strdup(option_arg); @@ -194,309 +323,176 @@ static int parse_mode(uint32_t *mode, char *option_arg) return 0; } -enum { - PARAM_LIMIT = 1 << 0, - PARAM_BURST = 1 << 1, - PARAM_MODE = 1 << 2, - PARAM_NAME = 1 << 3, - PARAM_SIZE = 1 << 4, - PARAM_MAX = 1 << 5, - PARAM_GCINTERVAL = 1 << 6, - PARAM_EXPIRE = 1 << 7, - PARAM_SRCMASK = 1 << 8, - PARAM_DSTMASK = 1 << 9, -}; - -static int -hashlimit_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void hashlimit_parse(struct xt_option_call *cb) { - struct xt_hashlimit_info *r = - (struct xt_hashlimit_info *)(*match)->data; - unsigned int num; - - switch(c) { - case '%': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit", - *flags & PARAM_LIMIT); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!parse_rate(optarg, &r->cfg.avg)) - xtables_error(PARAMETER_PROBLEM, - "bad rate `%s'", optarg); - *flags |= PARAM_LIMIT; - break; + struct xt_hashlimit_info *info = cb->data; - case '$': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst", - *flags & PARAM_BURST); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!xtables_strtoui(optarg, NULL, &num, 0, 10000)) - xtables_error(PARAMETER_PROBLEM, - "bad --hashlimit-burst `%s'", optarg); - r->cfg.burst = num; - *flags |= PARAM_BURST; - break; - case '&': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size", - *flags & PARAM_SIZE); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, - "bad --hashlimit-htable-size: `%s'", optarg); - r->cfg.size = num; - *flags |= PARAM_SIZE; - break; - case '*': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max", - *flags & PARAM_MAX); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, - "bad --hashlimit-htable-max: `%s'", optarg); - r->cfg.max = num; - *flags |= PARAM_MAX; - break; - case '(': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", - "--hashlimit-htable-gcinterval", - *flags & PARAM_GCINTERVAL); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, - "bad --hashlimit-htable-gcinterval: `%s'", - optarg); - /* FIXME: not HZ dependent!! */ - r->cfg.gc_interval = num; - *flags |= PARAM_GCINTERVAL; - break; - case ')': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", - "--hashlimit-htable-expire", *flags & PARAM_EXPIRE); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, - "bad --hashlimit-htable-expire: `%s'", optarg); - /* FIXME: not HZ dependent */ - r->cfg.expire = num; - *flags |= PARAM_EXPIRE; - break; - case '_': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode", - *flags & PARAM_MODE); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (parse_mode(&r->cfg.mode, optarg) < 0) - xtables_error(PARAMETER_PROBLEM, - "bad --hashlimit-mode: `%s'\n", optarg); - *flags |= PARAM_MODE; + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_UPTO: + if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata)) + xtables_param_act(XTF_BAD_VALUE, "hashlimit", + "--hashlimit-upto", cb->arg); break; - case '"': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name", - *flags & PARAM_NAME); - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (strlen(optarg) == 0) - xtables_error(PARAMETER_PROBLEM, "Zero-length name?"); - strncpy(r->name, optarg, sizeof(r->name)); - *flags |= PARAM_NAME; + case O_MODE: + if (parse_mode(&info->cfg.mode, cb->arg) < 0) + xtables_param_act(XTF_BAD_VALUE, "hashlimit", + "--hashlimit-mode", cb->arg); break; - default: - return 0; } - - if (invert) - xtables_error(PARAMETER_PROBLEM, - "hashlimit does not support invert"); - - return 1; } -static int -hashlimit_mt_parse(struct xt_hashlimit_mtinfo1 *info, unsigned int *flags, - int c, int invert, unsigned int maxmask) +static void hashlimit_mt_parse(struct xt_option_call *cb) { - unsigned int num; + struct xt_hashlimit_mtinfo1 *info = cb->data; - switch(c) { - case '%': /* --hashlimit / --hashlimit-below */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-upto", - *flags & PARAM_LIMIT); - if (invert) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_BURST: + info->cfg.burst = parse_burst(cb->arg, info); + break; + case O_UPTO: + if (cb->invert) info->cfg.mode |= XT_HASHLIMIT_INVERT; - if (!parse_rate(optarg, &info->cfg.avg)) + if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata)) + info->cfg.mode |= XT_HASHLIMIT_BYTES; + else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata)) xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-upto", optarg); - *flags |= PARAM_LIMIT; - return true; - - case '^': /* --hashlimit-above == !--hashlimit-below */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-above", - *flags & PARAM_LIMIT); - if (!invert) + "--hashlimit-upto", cb->arg); + break; + case O_ABOVE: + if (!cb->invert) info->cfg.mode |= XT_HASHLIMIT_INVERT; - if (!parse_rate(optarg, &info->cfg.avg)) - xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-above", optarg); - *flags |= PARAM_LIMIT; - return true; - - case '$': /* --hashlimit-burst */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-burst", - *flags & PARAM_BURST); - if (!xtables_strtoui(optarg, NULL, &num, 0, 10000)) - xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-burst", optarg); - info->cfg.burst = num; - *flags |= PARAM_BURST; - return true; - - case '&': /* --hashlimit-htable-size */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-size", - *flags & PARAM_SIZE); - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-htable-size", optarg); - info->cfg.size = num; - *flags |= PARAM_SIZE; - return true; - - case '*': /* --hashlimit-htable-max */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-htable-max", - *flags & PARAM_MAX); - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-htable-max", optarg); - info->cfg.max = num; - *flags |= PARAM_MAX; - return true; - - case '(': /* --hashlimit-htable-gcinterval */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", - "--hashlimit-htable-gcinterval", - *flags & PARAM_GCINTERVAL); - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-htable-gcinterval", optarg); - /* FIXME: not HZ dependent!! */ - info->cfg.gc_interval = num; - *flags |= PARAM_GCINTERVAL; - return true; - - case ')': /* --hashlimit-htable-expire */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", - "--hashlimit-htable-expire", *flags & PARAM_EXPIRE); - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) + if (parse_bytes(cb->arg, &info->cfg.avg, cb->udata)) + info->cfg.mode |= XT_HASHLIMIT_BYTES; + else if (!parse_rate(cb->arg, &info->cfg.avg, cb->udata)) xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-htable-expire", optarg); - /* FIXME: not HZ dependent */ - info->cfg.expire = num; - *flags |= PARAM_EXPIRE; - return true; - - case '_': - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-mode", - *flags & PARAM_MODE); - if (parse_mode(&info->cfg.mode, optarg) < 0) - xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-mode", optarg); - *flags |= PARAM_MODE; - return true; - - case '"': /* --hashlimit-name */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-name", - *flags & PARAM_NAME); - if (strlen(optarg) == 0) - xtables_error(PARAMETER_PROBLEM, "Zero-length name?"); - strncpy(info->name, optarg, sizeof(info->name)); - info->name[sizeof(info->name)-1] = '\0'; - *flags |= PARAM_NAME; - return true; - - case '<': /* --hashlimit-srcmask */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-srcmask", - *flags & PARAM_SRCMASK); - if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask)) - xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-srcmask", optarg); - info->cfg.srcmask = num; - *flags |= PARAM_SRCMASK; - return true; - - case '>': /* --hashlimit-dstmask */ - xtables_param_act(XTF_ONLY_ONCE, "hashlimit", "--hashlimit-dstmask", - *flags & PARAM_DSTMASK); - if (!xtables_strtoui(optarg, NULL, &num, 0, maxmask)) + "--hashlimit-above", cb->arg); + break; + case O_MODE: + if (parse_mode(&info->cfg.mode, cb->arg) < 0) xtables_param_act(XTF_BAD_VALUE, "hashlimit", - "--hashlimit-dstmask", optarg); - info->cfg.dstmask = num; - *flags |= PARAM_DSTMASK; - return true; + "--hashlimit-mode", cb->arg); + break; + case O_SRCMASK: + info->cfg.srcmask = cb->val.hlen; + break; + case O_DSTMASK: + info->cfg.dstmask = cb->val.hlen; + break; } - return false; } -static int -hashlimit_mt4_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void hashlimit_check(struct xt_fcheck_call *cb) { - return hashlimit_mt_parse((void *)(*match)->data, - flags, c, invert, 32); -} - -static int -hashlimit_mt6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - return hashlimit_mt_parse((void *)(*match)->data, - flags, c, invert, 128); -} + const struct hashlimit_mt_udata *udata = cb->udata; + struct xt_hashlimit_info *info = cb->data; -static void hashlimit_check(unsigned int flags) -{ - if (!(flags & PARAM_LIMIT)) + if (!(cb->xflags & (F_UPTO | F_ABOVE))) xtables_error(PARAMETER_PROBLEM, "You have to specify --hashlimit"); - if (!(flags & PARAM_MODE)) - xtables_error(PARAMETER_PROBLEM, - "You have to specify --hashlimit-mode"); - if (!(flags & PARAM_NAME)) - xtables_error(PARAMETER_PROBLEM, - "You have to specify --hashlimit-name"); + if (!(cb->xflags & F_HTABLE_EXPIRE)) + info->cfg.expire = udata->mult * 1000; /* from s to msec */ } -static void hashlimit_mt_check(unsigned int flags) +static void hashlimit_mt_check(struct xt_fcheck_call *cb) { - if (!(flags & PARAM_LIMIT)) - xtables_error(PARAMETER_PROBLEM, "You have to specify " - "--hashlimit-upto or --hashlimit-above"); - if (!(flags & PARAM_NAME)) + const struct hashlimit_mt_udata *udata = cb->udata; + struct xt_hashlimit_mtinfo1 *info = cb->data; + + if (!(cb->xflags & (F_UPTO | F_ABOVE))) xtables_error(PARAMETER_PROBLEM, - "You have to specify --hashlimit-name"); + "You have to specify --hashlimit"); + if (!(cb->xflags & F_HTABLE_EXPIRE)) + info->cfg.expire = udata->mult * 1000; /* from s to msec */ + + if (info->cfg.mode & XT_HASHLIMIT_BYTES) { + uint32_t burst = 0; + if (cb->xflags & F_BURST) { + if (info->cfg.burst < cost_to_bytes(info->cfg.avg)) + xtables_error(PARAMETER_PROBLEM, + "burst cannot be smaller than %ub", cost_to_bytes(info->cfg.avg)); + + burst = info->cfg.burst; + burst /= cost_to_bytes(info->cfg.avg); + if (info->cfg.burst % cost_to_bytes(info->cfg.avg)) + burst++; + if (!(cb->xflags & F_HTABLE_EXPIRE)) + info->cfg.expire = XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; + } + info->cfg.burst = burst; + } else if (info->cfg.burst > XT_HASHLIMIT_BURST_MAX) + burst_error(); } static const struct rates { const char *name; - u_int32_t mult; + uint32_t mult; } rates[] = { { "day", XT_HASHLIMIT_SCALE*24*60*60 }, { "hour", XT_HASHLIMIT_SCALE*60*60 }, { "min", XT_HASHLIMIT_SCALE*60 }, { "sec", XT_HASHLIMIT_SCALE } }; -static void print_rate(u_int32_t period) +static uint32_t print_rate(uint32_t period) { unsigned int i; + if (period == 0) { + printf(" %f", INFINITY); + return 0; + } + for (i = 1; i < ARRAY_SIZE(rates); ++i) if (period > rates[i].mult || rates[i].mult/period < rates[i].mult%period) break; - printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); + printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name); + /* return in msec */ + return rates[i-1].mult / XT_HASHLIMIT_SCALE * 1000; +} + +static const struct { + const char *name; + uint32_t thresh; +} units[] = { + { "m", 1024 * 1024 }, + { "k", 1024 }, + { "", 1 }, +}; + +static uint32_t print_bytes(uint32_t avg, uint32_t burst, const char *prefix) +{ + unsigned int i; + unsigned long long r; + + r = cost_to_bytes(avg); + + for (i = 0; i < ARRAY_SIZE(units) -1; ++i) + if (r >= units[i].thresh && + bytes_to_cost(r & ~(units[i].thresh - 1)) == avg) + break; + printf(" %llu%sb/s", r/units[i].thresh, units[i].name); + + if (burst == 0) + return XT_HASHLIMIT_BYTE_EXPIRE * 1000; + + r *= burst; + printf(" %s", prefix); + for (i = 0; i < ARRAY_SIZE(units) -1; ++i) + if (r >= units[i].thresh) + break; + + printf("burst %llu%sb", r / units[i].thresh, units[i].name); + return XT_HASHLIMIT_BYTE_EXPIRE_BURST * 1000; } static void print_mode(unsigned int mode, char separator) { bool prevmode = false; + putchar(' '); if (mode & XT_HASHLIMIT_HASH_SIP) { fputs("srcip", stdout); prevmode = 1; @@ -518,54 +514,63 @@ static void print_mode(unsigned int mode, char separator) putchar(separator); fputs("dstport", stdout); } - putchar(' '); } static void hashlimit_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_hashlimit_info *r = (const void *)match->data; - fputs("limit: avg ", stdout); print_rate(r->cfg.avg); - printf("burst %u ", r->cfg.burst); - fputs("mode ", stdout); + uint32_t quantum; + + fputs(" limit: avg", stdout); + quantum = print_rate(r->cfg.avg); + printf(" burst %u", r->cfg.burst); + fputs(" mode", stdout); print_mode(r->cfg.mode, '-'); if (r->cfg.size) - printf("htable-size %u ", r->cfg.size); + printf(" htable-size %u", r->cfg.size); if (r->cfg.max) - printf("htable-max %u ", r->cfg.max); + printf(" htable-max %u", r->cfg.max); if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) - printf("htable-gcinterval %u ", r->cfg.gc_interval); - if (r->cfg.expire != XT_HASHLIMIT_EXPIRE) - printf("htable-expire %u ", r->cfg.expire); + printf(" htable-gcinterval %u", r->cfg.gc_interval); + if (r->cfg.expire != quantum) + printf(" htable-expire %u", r->cfg.expire); } static void hashlimit_mt_print(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) { + uint32_t quantum; + if (info->cfg.mode & XT_HASHLIMIT_INVERT) - fputs("limit: above ", stdout); + fputs(" limit: above", stdout); else - fputs("limit: up to ", stdout); - print_rate(info->cfg.avg); - printf("burst %u ", info->cfg.burst); + fputs(" limit: up to", stdout); + + if (info->cfg.mode & XT_HASHLIMIT_BYTES) { + quantum = print_bytes(info->cfg.avg, info->cfg.burst, ""); + } else { + quantum = print_rate(info->cfg.avg); + printf(" burst %u", info->cfg.burst); + } if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { - fputs("mode ", stdout); + fputs(" mode", stdout); print_mode(info->cfg.mode, '-'); } if (info->cfg.size != 0) - printf("htable-size %u ", info->cfg.size); + printf(" htable-size %u", info->cfg.size); if (info->cfg.max != 0) - printf("htable-max %u ", info->cfg.max); + printf(" htable-max %u", info->cfg.max); if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) - printf("htable-gcinterval %u ", info->cfg.gc_interval); - if (info->cfg.expire != XT_HASHLIMIT_EXPIRE) - printf("htable-expire %u ", info->cfg.expire); + printf(" htable-gcinterval %u", info->cfg.gc_interval); + if (info->cfg.expire != quantum) + printf(" htable-expire %u", info->cfg.expire); if (info->cfg.srcmask != dmask) - printf("srcmask %u ", info->cfg.srcmask); + printf(" srcmask %u", info->cfg.srcmask); if (info->cfg.dstmask != dmask) - printf("dstmask %u ", info->cfg.dstmask); + printf(" dstmask %u", info->cfg.dstmask); } static void @@ -589,56 +594,65 @@ hashlimit_mt6_print(const void *ip, const struct xt_entry_match *match, static void hashlimit_save(const void *ip, const struct xt_entry_match *match) { const struct xt_hashlimit_info *r = (const void *)match->data; + uint32_t quantum; - fputs("--hashlimit ", stdout); print_rate(r->cfg.avg); - printf("--hashlimit-burst %u ", r->cfg.burst); + fputs(" --hashlimit", stdout); + quantum = print_rate(r->cfg.avg); + printf(" --hashlimit-burst %u", r->cfg.burst); - fputs("--hashlimit-mode ", stdout); + fputs(" --hashlimit-mode", stdout); print_mode(r->cfg.mode, ','); - - printf("--hashlimit-name %s ", r->name); + + printf(" --hashlimit-name %s", r->name); if (r->cfg.size) - printf("--hashlimit-htable-size %u ", r->cfg.size); + printf(" --hashlimit-htable-size %u", r->cfg.size); if (r->cfg.max) - printf("--hashlimit-htable-max %u ", r->cfg.max); + printf(" --hashlimit-htable-max %u", r->cfg.max); if (r->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) - printf("--hashlimit-htable-gcinterval %u ", r->cfg.gc_interval); - if (r->cfg.expire != XT_HASHLIMIT_EXPIRE) - printf("--hashlimit-htable-expire %u ", r->cfg.expire); + printf(" --hashlimit-htable-gcinterval %u", r->cfg.gc_interval); + if (r->cfg.expire != quantum) + printf(" --hashlimit-htable-expire %u", r->cfg.expire); } static void hashlimit_mt_save(const struct xt_hashlimit_mtinfo1 *info, unsigned int dmask) { + uint32_t quantum; + if (info->cfg.mode & XT_HASHLIMIT_INVERT) - fputs("--hashlimit-above ", stdout); + fputs(" --hashlimit-above", stdout); else - fputs("--hashlimit-upto ", stdout); - print_rate(info->cfg.avg); - printf("--hashlimit-burst %u ", info->cfg.burst); + fputs(" --hashlimit-upto", stdout); + + if (info->cfg.mode & XT_HASHLIMIT_BYTES) { + quantum = print_bytes(info->cfg.avg, info->cfg.burst, "--hashlimit-"); + } else { + quantum = print_rate(info->cfg.avg); + printf(" --hashlimit-burst %u", info->cfg.burst); + } if (info->cfg.mode & (XT_HASHLIMIT_HASH_SIP | XT_HASHLIMIT_HASH_SPT | XT_HASHLIMIT_HASH_DIP | XT_HASHLIMIT_HASH_DPT)) { - fputs("--hashlimit-mode ", stdout); + fputs(" --hashlimit-mode", stdout); print_mode(info->cfg.mode, ','); } - printf("--hashlimit-name %s ", info->name); + printf(" --hashlimit-name %s", info->name); if (info->cfg.size != 0) - printf("--hashlimit-htable-size %u ", info->cfg.size); + printf(" --hashlimit-htable-size %u", info->cfg.size); if (info->cfg.max != 0) - printf("--hashlimit-htable-max %u ", info->cfg.max); + printf(" --hashlimit-htable-max %u", info->cfg.max); if (info->cfg.gc_interval != XT_HASHLIMIT_GCINTERVAL) - printf("--hashlimit-htable-gcinterval %u ", info->cfg.gc_interval); - if (info->cfg.expire != XT_HASHLIMIT_EXPIRE) - printf("--hashlimit-htable-expire %u ", info->cfg.expire); + printf(" --hashlimit-htable-gcinterval %u", info->cfg.gc_interval); + if (info->cfg.expire != quantum) + printf(" --hashlimit-htable-expire %u", info->cfg.expire); if (info->cfg.srcmask != dmask) - printf("--hashlimit-srcmask %u ", info->cfg.srcmask); + printf(" --hashlimit-srcmask %u", info->cfg.srcmask); if (info->cfg.dstmask != dmask) - printf("--hashlimit-dstmask %u ", info->cfg.dstmask); + printf(" --hashlimit-dstmask %u", info->cfg.dstmask); } static void @@ -667,11 +681,12 @@ static struct xtables_match hashlimit_mt_reg[] = { .userspacesize = offsetof(struct xt_hashlimit_info, hinfo), .help = hashlimit_help, .init = hashlimit_init, - .parse = hashlimit_parse, - .final_check = hashlimit_check, + .x6_parse = hashlimit_parse, + .x6_fcheck = hashlimit_check, .print = hashlimit_print, .save = hashlimit_save, - .extra_opts = hashlimit_opts, + .x6_options = hashlimit_opts, + .udata_size = sizeof(struct hashlimit_mt_udata), }, { .version = XTABLES_VERSION, @@ -682,11 +697,12 @@ static struct xtables_match hashlimit_mt_reg[] = { .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), .help = hashlimit_mt_help, .init = hashlimit_mt4_init, - .parse = hashlimit_mt4_parse, - .final_check = hashlimit_mt_check, + .x6_parse = hashlimit_mt_parse, + .x6_fcheck = hashlimit_mt_check, .print = hashlimit_mt4_print, .save = hashlimit_mt4_save, - .extra_opts = hashlimit_mt_opts, + .x6_options = hashlimit_mt_opts, + .udata_size = sizeof(struct hashlimit_mt_udata), }, { .version = XTABLES_VERSION, @@ -697,11 +713,12 @@ static struct xtables_match hashlimit_mt_reg[] = { .userspacesize = offsetof(struct xt_hashlimit_mtinfo1, hinfo), .help = hashlimit_mt_help, .init = hashlimit_mt6_init, - .parse = hashlimit_mt6_parse, - .final_check = hashlimit_mt_check, + .x6_parse = hashlimit_mt_parse, + .x6_fcheck = hashlimit_mt_check, .print = hashlimit_mt6_print, .save = hashlimit_mt6_save, - .extra_opts = hashlimit_mt_opts, + .x6_options = hashlimit_mt_opts, + .udata_size = sizeof(struct hashlimit_mt_udata), }, }; diff --git a/extensions/libxt_hashlimit.man b/extensions/libxt_hashlimit.man index b870f55..6aac3f2 100644 --- a/extensions/libxt_hashlimit.man +++ b/extensions/libxt_hashlimit.man @@ -1,32 +1,26 @@ -\fBhashlimit\fR uses hash buckets to express a rate limiting match (like the -\fBlimit\fR match) for a group of connections using a \fBsingle\fR iptables +\fBhashlimit\fP uses hash buckets to express a rate limiting match (like the +\fBlimit\fP match) for a group of connections using a \fBsingle\fP iptables rule. Grouping can be done per-hostgroup (source and/or destination address) -and/or per-port. It gives you the ability to express "\fIN\fR packets per time -quantum per group": -.TP -matching on source host -"1000 packets per second for every host in 192.168.0.0/16" -.TP -matching on source port -"100 packets per second for every service of 192.168.1.1" -.TP -matching on subnet -"10000 packets per minute for every /28 subnet in 10.0.0.0/8" +and/or per-port. It gives you the ability to express "\fIN\fP packets per time +quantum per group" or "\fIN\fP bytes per seconds" (see below for some examples). .PP A hash limit option (\fB\-\-hashlimit\-upto\fP, \fB\-\-hashlimit\-above\fP) and \fB\-\-hashlimit\-name\fP are required. .TP \fB\-\-hashlimit\-upto\fP \fIamount\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP] -Match if the rate is below or equal to \fIamount\fR/quantum. It is specified as -a number, with an optional time quantum suffix; the default is 3/hour. +Match if the rate is below or equal to \fIamount\fP/quantum. It is specified either as +a number, with an optional time quantum suffix (the default is 3/hour), or as +\fIamount\fPb/second (number of bytes per second). .TP \fB\-\-hashlimit\-above\fP \fIamount\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP] -Match if the rate is above \fIamount\fR/quantum. +Match if the rate is above \fIamount\fP/quantum. .TP \fB\-\-hashlimit\-burst\fP \fIamount\fP Maximum initial number of packets to match: this number gets recharged by one every time the limit specified above is not reached, up to this number; the -default is 5. +default is 5. When byte-based rate matching is requested, this option specifies +the amount of bytes that can exceed the given rate. This option should be used +with caution -- if the entry expires, the burst value is reset too. .TP \fB\-\-hashlimit\-mode\fP {\fBsrcip\fP|\fBsrcport\fP|\fBdstip\fP|\fBdstport\fP}\fB,\fP... A comma-separated list of objects to take into consideration. If no @@ -36,7 +30,7 @@ expensive of doing the hash housekeeping. \fB\-\-hashlimit\-srcmask\fP \fIprefix\fP When \-\-hashlimit\-mode srcip is used, all source addresses encountered will be grouped according to the given prefix length and the so-created subnet will be -subject to hashlimit. \fIprefix\fR must be between (inclusive) 0 and 32. Note +subject to hashlimit. \fIprefix\fP must be between (inclusive) 0 and 32. Note that \-\-hashlimit\-srcmask 0 is basically doing the same thing as not specifying srcip for \-\-hashlimit\-mode, but is technically more expensive. .TP @@ -57,3 +51,26 @@ After how many milliseconds do hash entries expire. .TP \fB\-\-hashlimit\-htable\-gcinterval\fP \fImsec\fP How many milliseconds between garbage collection intervals. +.PP +Examples: +.TP +matching on source host +"1000 packets per second for every host in 192.168.0.0/16" => +\-s 192.168.0.0/16 \-\-hashlimit\-mode srcip \-\-hashlimit\-upto 1000/sec +.TP +matching on source port +"100 packets per second for every service of 192.168.1.1" => +\-s 192.168.1.1 \-\-hashlimit\-mode srcport \-\-hashlimit\-upto 100/sec +.TP +matching on subnet +"10000 packets per minute for every /28 subnet (groups of 8 addresses) +in 10.0.0.0/8" => +\-s 10.0.0.0/8 \-\-hashlimit\-mask 28 \-\-hashlimit\-upto 10000/min +.TP +matching bytes per second +"flows exceeding 512kbyte/s" => +\-\-hashlimit-mode srcip,dstip,srcport,dstport \-\-hashlimit\-above 512kb/s +.TP +matching bytes per second +"hosts that exceed 512kbyte/s, but permit up to 1Megabytes without matching" +\-\-hashlimit-mode dstip \-\-hashlimit\-above 512kb/s \-\-hashlimit-burst 1mb diff --git a/extensions/libxt_helper.c b/extensions/libxt_helper.c index 35b5f15..c9f9435 100644 --- a/extensions/libxt_helper.c +++ b/extensions/libxt_helper.c @@ -1,13 +1,11 @@ -/* Shared library add-on to iptables to add related packet matching support. */ #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_helper.h> +enum { + O_HELPER = 0, +}; + static void helper_help(void) { printf( @@ -15,41 +13,20 @@ static void helper_help(void) "[!] --helper string Match helper identified by string\n"); } -static const struct option helper_opts[] = { - { "helper", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry helper_opts[] = { + {.name = "helper", .id = O_HELPER, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_helper_info, name)}, + XTOPT_TABLEEND, }; -static int -helper_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void helper_parse(struct xt_option_call *cb) { - struct xt_helper_info *info = (struct xt_helper_info *)(*match)->data; - - switch (c) { - case '1': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "helper match: Only use --helper ONCE!"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - strncpy(info->name, optarg, 29); - info->name[29] = '\0'; - if (invert) - info->invert = 1; - *flags = 1; - break; + struct xt_helper_info *info = cb->data; - default: - return 0; - } - return 1; -} - -static void helper_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "helper match: You must specify `--helper'"); + xtables_option_parse(cb); + if (cb->invert) + info->invert = 1; } static void @@ -57,14 +34,14 @@ helper_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_helper_info *info = (const void *)match->data; - printf("helper match %s\"%s\" ", info->invert ? "! " : "", info->name); + printf(" helper match %s\"%s\"", info->invert ? "! " : "", info->name); } static void helper_save(const void *ip, const struct xt_entry_match *match) { const struct xt_helper_info *info = (const void *)match->data; - printf("%s--helper ",info->invert ? "! " : ""); + printf("%s --helper", info->invert ? " !" : ""); xtables_save_string(info->name); } @@ -74,11 +51,10 @@ static struct xtables_match helper_match = { .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_helper_info)), .help = helper_help, - .parse = helper_parse, - .final_check = helper_check, .print = helper_print, .save = helper_save, - .extra_opts = helper_opts, + .x6_parse = helper_parse, + .x6_options = helper_opts, }; void _init(void) diff --git a/extensions/libxt_iprange.c b/extensions/libxt_iprange.c index 55a2f84..2c9ea99 100644 --- a/extensions/libxt_iprange.c +++ b/extensions/libxt_iprange.c @@ -1,11 +1,7 @@ -/* Shared library add-on to iptables to add IP range matching support. */ +#include <stdint.h> #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> - -#include <netinet/in.h> #include <xtables.h> #include <linux/netfilter.h> #include <linux/netfilter/xt_iprange.h> @@ -20,12 +16,12 @@ struct ipt_iprange_info { struct ipt_iprange dst; /* Flags from above */ - u_int8_t flags; + uint8_t flags; }; enum { - F_SRCIP = 1 << 0, - F_DSTIP = 1 << 1, + O_SRC_RANGE = 0, + O_DST_RANGE, }; static void iprange_mt_help(void) @@ -36,10 +32,12 @@ static void iprange_mt_help(void) "[!] --dst-range ip[-ip] Match destination IP in the specified range\n"); } -static const struct option iprange_mt_opts[] = { - {.name = "src-range", .has_arg = true, .val = '1'}, - {.name = "dst-range", .has_arg = true, .val = '2'}, - { .name = NULL } +static const struct xt_option_entry iprange_mt_opts[] = { + {.name = "src-range", .id = O_SRC_RANGE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "dst-range", .id = O_DST_RANGE, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, }; static void @@ -72,14 +70,18 @@ iprange_parse_spec(const char *from, const char *to, union nf_inet_addr *range, } } -static void iprange_parse_range(char *arg, union nf_inet_addr *range, - u_int8_t family, const char *optname) +static void iprange_parse_range(const char *oarg, union nf_inet_addr *range, + uint8_t family, const char *optname) { + char *arg = strdup(oarg); char *dash; + if (arg == NULL) + xtables_error(RESOURCE_PROBLEM, "strdup"); dash = strchr(arg, '-'); if (dash == NULL) { iprange_parse_spec(arg, arg, range, family, optname); + free(arg); return; } @@ -88,111 +90,71 @@ static void iprange_parse_range(char *arg, union nf_inet_addr *range, if (memcmp(&range[0], &range[1], sizeof(*range)) > 0) fprintf(stderr, "xt_iprange: range %s-%s is reversed and " "will never match\n", arg, dash + 1); + free(arg); } -static int iprange_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void iprange_parse(struct xt_option_call *cb) { - struct ipt_iprange_info *info = (struct ipt_iprange_info *)(*match)->data; + struct ipt_iprange_info *info = cb->data; union nf_inet_addr range[2]; - switch (c) { - case '1': - if (*flags & IPRANGE_SRC) - xtables_error(PARAMETER_PROBLEM, - "iprange match: Only use --src-range ONCE!"); - *flags |= IPRANGE_SRC; - + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRC_RANGE: info->flags |= IPRANGE_SRC; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) + if (cb->invert) info->flags |= IPRANGE_SRC_INV; - iprange_parse_range(optarg, range, NFPROTO_IPV4, "--src-range"); + iprange_parse_range(cb->arg, range, NFPROTO_IPV4, "--src-range"); info->src.min_ip = range[0].ip; info->src.max_ip = range[1].ip; break; - - case '2': - if (*flags & IPRANGE_DST) - xtables_error(PARAMETER_PROBLEM, - "iprange match: Only use --dst-range ONCE!"); - *flags |= IPRANGE_DST; - + case O_DST_RANGE: info->flags |= IPRANGE_DST; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) + if (cb->invert) info->flags |= IPRANGE_DST_INV; - - iprange_parse_range(optarg, range, NFPROTO_IPV4, "--dst-range"); + iprange_parse_range(cb->arg, range, NFPROTO_IPV4, "--dst-range"); info->dst.min_ip = range[0].ip; info->dst.max_ip = range[1].ip; break; - - default: - return 0; } - return 1; } -static int -iprange_mt4_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void iprange_mt_parse(struct xt_option_call *cb, uint8_t nfproto) { - struct xt_iprange_mtinfo *info = (void *)(*match)->data; + struct xt_iprange_mtinfo *info = cb->data; - switch (c) { - case '1': /* --src-range */ - iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV4, + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SRC_RANGE: + iprange_parse_range(cb->arg, &info->src_min, nfproto, "--src-range"); info->flags |= IPRANGE_SRC; - if (invert) + if (cb->invert) info->flags |= IPRANGE_SRC_INV; - *flags |= F_SRCIP; - return true; - - case '2': /* --dst-range */ - iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV4, + break; + case O_DST_RANGE: + iprange_parse_range(cb->arg, &info->dst_min, nfproto, "--dst-range"); info->flags |= IPRANGE_DST; - if (invert) + if (cb->invert) info->flags |= IPRANGE_DST_INV; - *flags |= F_DSTIP; - return true; + break; } - return false; } -static int -iprange_mt6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void iprange_mt4_parse(struct xt_option_call *cb) { - struct xt_iprange_mtinfo *info = (void *)(*match)->data; - - switch (c) { - case '1': /* --src-range */ - iprange_parse_range(optarg, &info->src_min, NFPROTO_IPV6, - "--src-range"); - info->flags |= IPRANGE_SRC; - if (invert) - info->flags |= IPRANGE_SRC_INV; - *flags |= F_SRCIP; - return true; + iprange_mt_parse(cb, NFPROTO_IPV4); +} - case '2': /* --dst-range */ - iprange_parse_range(optarg, &info->dst_min, NFPROTO_IPV6, - "--dst-range"); - info->flags |= IPRANGE_DST; - if (invert) - info->flags |= IPRANGE_DST_INV; - *flags |= F_DSTIP; - return true; - } - return false; +static void iprange_mt6_parse(struct xt_option_call *cb) +{ + iprange_mt_parse(cb, NFPROTO_IPV6); } -static void iprange_mt_check(unsigned int flags) +static void iprange_mt_check(struct xt_fcheck_call *cb) { - if (flags == 0) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "iprange match: You must specify `--src-range' or `--dst-range'"); } @@ -204,7 +166,7 @@ print_iprange(const struct ipt_iprange *range) byte_min = (const unsigned char *)&range->min_ip; byte_max = (const unsigned char *)&range->max_ip; - printf("%u.%u.%u.%u-%u.%u.%u.%u ", + printf(" %u.%u.%u.%u-%u.%u.%u.%u", byte_min[0], byte_min[1], byte_min[2], byte_min[3], byte_max[0], byte_max[1], byte_max[2], byte_max[3]); } @@ -215,15 +177,15 @@ static void iprange_print(const void *ip, const struct xt_entry_match *match, const struct ipt_iprange_info *info = (const void *)match->data; if (info->flags & IPRANGE_SRC) { - printf("source IP range "); + printf(" source IP range"); if (info->flags & IPRANGE_SRC_INV) - printf("! "); + printf(" !"); print_iprange(&info->src); } if (info->flags & IPRANGE_DST) { - printf("destination IP range "); + printf(" destination IP range"); if (info->flags & IPRANGE_DST_INV) - printf("! "); + printf(" !"); print_iprange(&info->dst); } } @@ -235,22 +197,22 @@ iprange_mt4_print(const void *ip, const struct xt_entry_match *match, const struct xt_iprange_mtinfo *info = (const void *)match->data; if (info->flags & IPRANGE_SRC) { - printf("source IP range "); + printf(" source IP range"); if (info->flags & IPRANGE_SRC_INV) - printf("! "); + printf(" !"); /* * ipaddr_to_numeric() uses a static buffer, so cannot * combine the printf() calls. */ - printf("%s", xtables_ipaddr_to_numeric(&info->src_min.in)); - printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in)); + printf(" %s", xtables_ipaddr_to_numeric(&info->src_min.in)); + printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in)); } if (info->flags & IPRANGE_DST) { - printf("destination IP range "); + printf(" destination IP range"); if (info->flags & IPRANGE_DST_INV) - printf("! "); - printf("%s", xtables_ipaddr_to_numeric(&info->dst_min.in)); - printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in)); + printf(" !"); + printf(" %s", xtables_ipaddr_to_numeric(&info->dst_min.in)); + printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in)); } } @@ -261,22 +223,22 @@ iprange_mt6_print(const void *ip, const struct xt_entry_match *match, const struct xt_iprange_mtinfo *info = (const void *)match->data; if (info->flags & IPRANGE_SRC) { - printf("source IP range "); + printf(" source IP range"); if (info->flags & IPRANGE_SRC_INV) - printf("! "); + printf(" !"); /* * ipaddr_to_numeric() uses a static buffer, so cannot * combine the printf() calls. */ - printf("%s", xtables_ip6addr_to_numeric(&info->src_min.in6)); - printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6)); + printf(" %s", xtables_ip6addr_to_numeric(&info->src_min.in6)); + printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6)); } if (info->flags & IPRANGE_DST) { - printf("destination IP range "); + printf(" destination IP range"); if (info->flags & IPRANGE_DST_INV) - printf("! "); - printf("%s", xtables_ip6addr_to_numeric(&info->dst_min.in6)); - printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6)); + printf(" !"); + printf(" %s", xtables_ip6addr_to_numeric(&info->dst_min.in6)); + printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6)); } } @@ -286,16 +248,14 @@ static void iprange_save(const void *ip, const struct xt_entry_match *match) if (info->flags & IPRANGE_SRC) { if (info->flags & IPRANGE_SRC_INV) - printf("! "); - printf("--src-range "); + printf(" !"); + printf(" --src-range"); print_iprange(&info->src); - if (info->flags & IPRANGE_DST) - fputc(' ', stdout); } if (info->flags & IPRANGE_DST) { if (info->flags & IPRANGE_DST_INV) - printf("! "); - printf("--dst-range "); + printf(" !"); + printf(" --dst-range"); print_iprange(&info->dst); } } @@ -306,15 +266,15 @@ static void iprange_mt4_save(const void *ip, const struct xt_entry_match *match) if (info->flags & IPRANGE_SRC) { if (info->flags & IPRANGE_SRC_INV) - printf("! "); - printf("--src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in)); - printf("-%s ", xtables_ipaddr_to_numeric(&info->src_max.in)); + printf(" !"); + printf(" --src-range %s", xtables_ipaddr_to_numeric(&info->src_min.in)); + printf("-%s", xtables_ipaddr_to_numeric(&info->src_max.in)); } if (info->flags & IPRANGE_DST) { if (info->flags & IPRANGE_DST_INV) - printf("! "); - printf("--dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in)); - printf("-%s ", xtables_ipaddr_to_numeric(&info->dst_max.in)); + printf(" !"); + printf(" --dst-range %s", xtables_ipaddr_to_numeric(&info->dst_min.in)); + printf("-%s", xtables_ipaddr_to_numeric(&info->dst_max.in)); } } @@ -324,15 +284,15 @@ static void iprange_mt6_save(const void *ip, const struct xt_entry_match *match) if (info->flags & IPRANGE_SRC) { if (info->flags & IPRANGE_SRC_INV) - printf("! "); - printf("--src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6)); - printf("-%s ", xtables_ip6addr_to_numeric(&info->src_max.in6)); + printf(" !"); + printf(" --src-range %s", xtables_ip6addr_to_numeric(&info->src_min.in6)); + printf("-%s", xtables_ip6addr_to_numeric(&info->src_max.in6)); } if (info->flags & IPRANGE_DST) { if (info->flags & IPRANGE_DST_INV) - printf("! "); - printf("--dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6)); - printf("-%s ", xtables_ip6addr_to_numeric(&info->dst_max.in6)); + printf(" !"); + printf(" --dst-range %s", xtables_ip6addr_to_numeric(&info->dst_min.in6)); + printf("-%s", xtables_ip6addr_to_numeric(&info->dst_max.in6)); } } @@ -345,11 +305,11 @@ static struct xtables_match iprange_mt_reg[] = { .size = XT_ALIGN(sizeof(struct ipt_iprange_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_iprange_info)), .help = iprange_mt_help, - .parse = iprange_parse, - .final_check = iprange_mt_check, + .x6_parse = iprange_parse, + .x6_fcheck = iprange_mt_check, .print = iprange_print, .save = iprange_save, - .extra_opts = iprange_mt_opts, + .x6_options = iprange_mt_opts, }, { .version = XTABLES_VERSION, @@ -359,11 +319,11 @@ static struct xtables_match iprange_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), .help = iprange_mt_help, - .parse = iprange_mt4_parse, - .final_check = iprange_mt_check, + .x6_parse = iprange_mt4_parse, + .x6_fcheck = iprange_mt_check, .print = iprange_mt4_print, .save = iprange_mt4_save, - .extra_opts = iprange_mt_opts, + .x6_options = iprange_mt_opts, }, { .version = XTABLES_VERSION, @@ -373,11 +333,11 @@ static struct xtables_match iprange_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), .userspacesize = XT_ALIGN(sizeof(struct xt_iprange_mtinfo)), .help = iprange_mt_help, - .parse = iprange_mt6_parse, - .final_check = iprange_mt_check, + .x6_parse = iprange_mt6_parse, + .x6_fcheck = iprange_mt_check, .print = iprange_mt6_print, .save = iprange_mt6_save, - .extra_opts = iprange_mt_opts, + .x6_options = iprange_mt_opts, }, }; diff --git a/extensions/libxt_iprange.man b/extensions/libxt_iprange.man index 9f65de4..9bbaac3 100644 --- a/extensions/libxt_iprange.man +++ b/extensions/libxt_iprange.man @@ -1,7 +1,7 @@ This matches on a given arbitrary range of IP addresses. .TP -[\fB!\fR] \fB\-\-src\-range\fP \fIfrom\fP[\fB\-\fP\fIto\fP] +[\fB!\fP] \fB\-\-src\-range\fP \fIfrom\fP[\fB\-\fP\fIto\fP] Match source IP in the specified range. .TP -[\fB!\fR] \fB\-\-dst\-range\fP \fIfrom\fP[\fB\-\fP\fIto\fP] +[\fB!\fP] \fB\-\-dst\-range\fP \fIfrom\fP[\fB\-\fP\fIto\fP] Match destination IP in the specified range. diff --git a/extensions/libxt_ipvs.c b/extensions/libxt_ipvs.c new file mode 100644 index 0000000..4672766 --- /dev/null +++ b/extensions/libxt_ipvs.c @@ -0,0 +1,285 @@ +/* + * Shared library add-on to iptables to add IPVS matching. + * + * Detailed doc is in the kernel module source net/netfilter/xt_ipvs.c + * + * Author: Hannes Eder <heder@google.com> + */ +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <xtables.h> +#include <linux/ip_vs.h> +#include <linux/netfilter/xt_ipvs.h> + +enum { + /* For xt_ipvs: make sure this matches up with %XT_IPVS_*'s order */ + O_IPVS = 0, + O_VPROTO, + O_VADDR, + O_VPORT, + O_VDIR, + O_VMETHOD, + O_VPORTCTL, +}; + +#define s struct xt_ipvs_mtinfo +static const struct xt_option_entry ipvs_mt_opts[] = { + {.name = "ipvs", .id = O_IPVS, .type = XTTYPE_NONE, + .flags = XTOPT_INVERT}, + {.name = "vproto", .id = O_VPROTO, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, l4proto)}, + {.name = "vaddr", .id = O_VADDR, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_INVERT}, + {.name = "vport", .id = O_VPORT, .type = XTTYPE_PORT, + .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, vport)}, + {.name = "vdir", .id = O_VDIR, .type = XTTYPE_STRING}, + {.name = "vmethod", .id = O_VMETHOD, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "vportctl", .id = O_VPORTCTL, .type = XTTYPE_PORT, + .flags = XTOPT_NBO | XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, vportctl)}, + XTOPT_TABLEEND, +}; +#undef s + +static void ipvs_mt_help(void) +{ + printf( +"IPVS match options:\n" +"[!] --ipvs packet belongs to an IPVS connection\n" +"\n" +"Any of the following options implies --ipvs (even negated)\n" +"[!] --vproto protocol VIP protocol to match; by number or name,\n" +" e.g. \"tcp\"\n" +"[!] --vaddr address[/mask] VIP address to match\n" +"[!] --vport port VIP port to match; by number or name,\n" +" e.g. \"http\"\n" +" --vdir {ORIGINAL|REPLY} flow direction of packet\n" +"[!] --vmethod {GATE|IPIP|MASQ} IPVS forwarding method used\n" +"[!] --vportctl port VIP port of the controlling connection to\n" +" match, e.g. 21 for FTP\n" + ); +} + +static void ipvs_mt_parse(struct xt_option_call *cb) +{ + struct xt_ipvs_mtinfo *data = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_VPROTO: + data->l4proto = cb->val.protocol; + break; + case O_VADDR: + memcpy(&data->vaddr, &cb->val.haddr, sizeof(cb->val.haddr)); + memcpy(&data->vmask, &cb->val.hmask, sizeof(cb->val.hmask)); + break; + case O_VDIR: + if (strcasecmp(cb->arg, "ORIGINAL") == 0) { + data->bitmask |= XT_IPVS_DIR; + data->invert &= ~XT_IPVS_DIR; + } else if (strcasecmp(cb->arg, "REPLY") == 0) { + data->bitmask |= XT_IPVS_DIR; + data->invert |= XT_IPVS_DIR; + } else { + xtables_param_act(XTF_BAD_VALUE, + "ipvs", "--vdir", cb->arg); + } + break; + case O_VMETHOD: + if (strcasecmp(cb->arg, "GATE") == 0) + data->fwd_method = IP_VS_CONN_F_DROUTE; + else if (strcasecmp(cb->arg, "IPIP") == 0) + data->fwd_method = IP_VS_CONN_F_TUNNEL; + else if (strcasecmp(cb->arg, "MASQ") == 0) + data->fwd_method = IP_VS_CONN_F_MASQ; + else + xtables_param_act(XTF_BAD_VALUE, + "ipvs", "--vmethod", cb->arg); + break; + } + data->bitmask |= 1 << cb->entry->id; + if (cb->invert) + data->invert |= 1 << cb->entry->id; +} + +static void ipvs_mt_check(struct xt_fcheck_call *cb) +{ + struct xt_ipvs_mtinfo *info = cb->data; + + if (cb->xflags == 0) + xtables_error(PARAMETER_PROBLEM, + "IPVS: At least one option is required"); + if (info->bitmask & XT_IPVS_ONCE_MASK) { + if (info->invert & XT_IPVS_IPVS_PROPERTY) + xtables_error(PARAMETER_PROBLEM, + "! --ipvs cannot be together with" + " other options"); + info->bitmask |= XT_IPVS_IPVS_PROPERTY; + } +} + +/* Shamelessly copied from libxt_conntrack.c */ +static void ipvs_mt_dump_addr(const union nf_inet_addr *addr, + const union nf_inet_addr *mask, + unsigned int family, bool numeric) +{ + char buf[BUFSIZ]; + + if (family == NFPROTO_IPV4) { + if (!numeric && addr->ip == 0) { + printf(" anywhere"); + return; + } + if (numeric) + strcpy(buf, xtables_ipaddr_to_numeric(&addr->in)); + else + strcpy(buf, xtables_ipaddr_to_anyname(&addr->in)); + strcat(buf, xtables_ipmask_to_numeric(&mask->in)); + printf(" %s", buf); + } else if (family == NFPROTO_IPV6) { + if (!numeric && addr->ip6[0] == 0 && addr->ip6[1] == 0 && + addr->ip6[2] == 0 && addr->ip6[3] == 0) { + printf(" anywhere"); + return; + } + if (numeric) + strcpy(buf, xtables_ip6addr_to_numeric(&addr->in6)); + else + strcpy(buf, xtables_ip6addr_to_anyname(&addr->in6)); + strcat(buf, xtables_ip6mask_to_numeric(&mask->in6)); + printf(" %s", buf); + } +} + +static void ipvs_mt_dump(const void *ip, const struct xt_ipvs_mtinfo *data, + unsigned int family, bool numeric, const char *prefix) +{ + if (data->bitmask == XT_IPVS_IPVS_PROPERTY) { + if (data->invert & XT_IPVS_IPVS_PROPERTY) + printf(" !"); + printf(" %sipvs", prefix); + } + + if (data->bitmask & XT_IPVS_PROTO) { + if (data->invert & XT_IPVS_PROTO) + printf(" !"); + printf(" %sproto %u", prefix, data->l4proto); + } + + if (data->bitmask & XT_IPVS_VADDR) { + if (data->invert & XT_IPVS_VADDR) + printf(" !"); + + printf(" %svaddr", prefix); + ipvs_mt_dump_addr(&data->vaddr, &data->vmask, family, numeric); + } + + if (data->bitmask & XT_IPVS_VPORT) { + if (data->invert & XT_IPVS_VPORT) + printf(" !"); + + printf(" %svport %u", prefix, ntohs(data->vport)); + } + + if (data->bitmask & XT_IPVS_DIR) { + if (data->invert & XT_IPVS_DIR) + printf(" %svdir REPLY", prefix); + else + printf(" %svdir ORIGINAL", prefix); + } + + if (data->bitmask & XT_IPVS_METHOD) { + if (data->invert & XT_IPVS_METHOD) + printf(" !"); + + printf(" %svmethod", prefix); + switch (data->fwd_method) { + case IP_VS_CONN_F_DROUTE: + printf(" GATE"); + break; + case IP_VS_CONN_F_TUNNEL: + printf(" IPIP"); + break; + case IP_VS_CONN_F_MASQ: + printf(" MASQ"); + break; + default: + /* Hu? */ + printf(" UNKNOWN"); + break; + } + } + + if (data->bitmask & XT_IPVS_VPORTCTL) { + if (data->invert & XT_IPVS_VPORTCTL) + printf(" !"); + + printf(" %svportctl %u", prefix, ntohs(data->vportctl)); + } +} + +static void ipvs_mt4_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_ipvs_mtinfo *data = (const void *)match->data; + ipvs_mt_dump(ip, data, NFPROTO_IPV4, numeric, ""); +} + +static void ipvs_mt6_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_ipvs_mtinfo *data = (const void *)match->data; + ipvs_mt_dump(ip, data, NFPROTO_IPV6, numeric, ""); +} + +static void ipvs_mt4_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_ipvs_mtinfo *data = (const void *)match->data; + ipvs_mt_dump(ip, data, NFPROTO_IPV4, true, "--"); +} + +static void ipvs_mt6_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_ipvs_mtinfo *data = (const void *)match->data; + ipvs_mt_dump(ip, data, NFPROTO_IPV6, true, "--"); +} + +static struct xtables_match ipvs_matches_reg[] = { + { + .version = XTABLES_VERSION, + .name = "ipvs", + .revision = 0, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)), + .help = ipvs_mt_help, + .x6_parse = ipvs_mt_parse, + .x6_fcheck = ipvs_mt_check, + .print = ipvs_mt4_print, + .save = ipvs_mt4_save, + .x6_options = ipvs_mt_opts, + }, + { + .version = XTABLES_VERSION, + .name = "ipvs", + .revision = 0, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_ipvs_mtinfo)), + .help = ipvs_mt_help, + .x6_parse = ipvs_mt_parse, + .x6_fcheck = ipvs_mt_check, + .print = ipvs_mt6_print, + .save = ipvs_mt6_save, + .x6_options = ipvs_mt_opts, + }, +}; + +void _init(void) +{ + xtables_register_matches(ipvs_matches_reg, + ARRAY_SIZE(ipvs_matches_reg)); +} diff --git a/extensions/libxt_ipvs.man b/extensions/libxt_ipvs.man new file mode 100644 index 0000000..db9bc66 --- /dev/null +++ b/extensions/libxt_ipvs.man @@ -0,0 +1,24 @@ +Match IPVS connection properties. +.TP +[\fB!\fP] \fB\-\-ipvs\fP +packet belongs to an IPVS connection +.TP +Any of the following options implies \-\-ipvs (even negated) +.TP +[\fB!\fP] \fB\-\-vproto\fP \fIprotocol\fP +VIP protocol to match; by number or name, e.g. "tcp" +.TP +[\fB!\fP] \fB\-\-vaddr\fP \fIaddress\fP[\fB/\fP\fImask\fP] +VIP address to match +.TP +[\fB!\fP] \fB\-\-vport\fP \fIport\fP +VIP port to match; by number or name, e.g. "http" +.TP +\fB\-\-vdir\fP {\fBORIGINAL\fP|\fBREPLY\fP} +flow direction of packet +.TP +[\fB!\fP] \fB\-\-vmethod\fP {\fBGATE\fP|\fBIPIP\fP|\fBMASQ\fP} +IPVS forwarding method used +.TP +[\fB!\fP] \fB\-\-vportctl\fP \fIport\fP +VIP port of the controlling connection to match, e.g. 21 for FTP diff --git a/extensions/libxt_length.c b/extensions/libxt_length.c index 96e8b6c..6ea7646 100644 --- a/extensions/libxt_length.c +++ b/extensions/libxt_length.c @@ -1,13 +1,11 @@ -/* Shared library add-on to iptables to add packet length matching support. */ #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_length.h> +enum { + O_LENGTH = 0, +}; + static void length_help(void) { printf( @@ -16,78 +14,23 @@ static void length_help(void) " of values (inclusive)\n"); } -static const struct option length_opts[] = { - { "length", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry length_opts[] = { + {.name = "length", .id = O_LENGTH, .type = XTTYPE_UINT16RC, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; -static u_int16_t -parse_length(const char *s) -{ - unsigned int len; - - if (!xtables_strtoui(s, NULL, &len, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, "length invalid: \"%s\"\n", s); - else - return len; -} - -/* If a single value is provided, min and max are both set to the value */ -static void -parse_lengths(const char *s, struct xt_length_info *info) -{ - char *buffer; - char *cp; - - buffer = strdup(s); - if ((cp = strchr(buffer, ':')) == NULL) - info->min = info->max = parse_length(buffer); - else { - *cp = '\0'; - cp++; - - info->min = buffer[0] ? parse_length(buffer) : 0; - info->max = cp[0] ? parse_length(cp) : 0xFFFF; - } - free(buffer); - - if (info->min > info->max) - xtables_error(PARAMETER_PROBLEM, - "length min. range value `%u' greater than max. " - "range value `%u'", info->min, info->max); - -} - -static int -length_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void length_parse(struct xt_option_call *cb) { - struct xt_length_info *info = (struct xt_length_info *)(*match)->data; - - switch (c) { - case '1': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "length: `--length' may only be " - "specified once"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_lengths(optarg, info); - if (invert) - info->invert = 1; - *flags = 1; - break; - - default: - return 0; - } - return 1; -} + struct xt_length_info *info = cb->data; -static void length_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "length: You must specify `--length'"); + xtables_option_parse(cb); + info->min = cb->val.u16_range[0]; + info->max = cb->val.u16_range[0]; + if (cb->nvals >= 2) + info->max = cb->val.u16_range[1]; + if (cb->invert) + info->invert = 1; } static void @@ -95,22 +38,22 @@ length_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_length_info *info = (void *)match->data; - printf("length %s", info->invert ? "!" : ""); + printf(" length %s", info->invert ? "!" : ""); if (info->min == info->max) - printf("%u ", info->min); + printf("%u", info->min); else - printf("%u:%u ", info->min, info->max); + printf("%u:%u", info->min, info->max); } static void length_save(const void *ip, const struct xt_entry_match *match) { const struct xt_length_info *info = (void *)match->data; - printf("%s--length ", info->invert ? "! " : ""); + printf("%s --length ", info->invert ? " !" : ""); if (info->min == info->max) - printf("%u ", info->min); + printf("%u", info->min); else - printf("%u:%u ", info->min, info->max); + printf("%u:%u", info->min, info->max); } static struct xtables_match length_match = { @@ -120,11 +63,10 @@ static struct xtables_match length_match = { .size = XT_ALIGN(sizeof(struct xt_length_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_length_info)), .help = length_help, - .parse = length_parse, - .final_check = length_check, .print = length_print, .save = length_save, - .extra_opts = length_opts, + .x6_parse = length_parse, + .x6_options = length_opts, }; void _init(void) diff --git a/extensions/libxt_limit.c b/extensions/libxt_limit.c index c836303..f75ef2f 100644 --- a/extensions/libxt_limit.c +++ b/extensions/libxt_limit.c @@ -3,20 +3,24 @@ * Jérôme de Vivie <devivie@info.enserb.u-bordeaux.fr> * Hervé Eychenne <rv@wallfire.org> */ - +#define _BSD_SOURCE 1 +#define _ISOC99_SOURCE 1 +#include <math.h> #include <stdio.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <xtables.h> -#include <stddef.h> #include <linux/netfilter/x_tables.h> -/* For 64bit kernel / 32bit userspace */ #include <linux/netfilter/xt_limit.h> #define XT_LIMIT_AVG "3/hour" #define XT_LIMIT_BURST 5 +enum { + O_LIMIT = 0, + O_BURST, +}; + static void limit_help(void) { printf( @@ -28,18 +32,20 @@ static void limit_help(void) XT_LIMIT_BURST); } -static const struct option limit_opts[] = { - { "limit", 1, NULL, '%' }, - { "limit-burst", 1, NULL, '$' }, - { .name = NULL } +static const struct xt_option_entry limit_opts[] = { + {.name = "limit", .id = O_LIMIT, .type = XTTYPE_STRING}, + {.name = "limit-burst", .id = O_BURST, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(struct xt_rateinfo, burst), + .min = 0, .max = 10000}, + XTOPT_TABLEEND, }; static -int parse_rate(const char *rate, u_int32_t *val) +int parse_rate(const char *rate, uint32_t *val) { const char *delim; - u_int32_t r; - u_int32_t mult = 1; /* Seconds by default. */ + uint32_t r; + uint32_t mult = 1; /* Seconds by default. */ delim = strchr(rate, '/'); if (delim) { @@ -61,12 +67,13 @@ int parse_rate(const char *rate, u_int32_t *val) if (!r) return 0; - /* This would get mapped to infinite (1/day is minimum they - can specify, so we're ok at that end). */ - if (r / mult > XT_LIMIT_SCALE) - xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); - *val = XT_LIMIT_SCALE * mult / r; + if (*val == 0) + /* + * The rate maps to infinity. (1/day is the minimum they can + * specify, so we are ok at that end). + */ + xtables_error(PARAMETER_PROBLEM, "Rate too fast \"%s\"\n", rate); return 1; } @@ -85,76 +92,64 @@ static void limit_init(struct xt_entry_match *m) "Sorry: burst too large for that avg rate.\n"); */ -static int -limit_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void limit_parse(struct xt_option_call *cb) { - struct xt_rateinfo *r = (struct xt_rateinfo *)(*match)->data; - unsigned int num; - - switch(c) { - case '%': - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!parse_rate(optarg, &r->avg)) - xtables_error(PARAMETER_PROBLEM, - "bad rate `%s'", optarg); - break; + struct xt_rateinfo *r = cb->data; - case '$': - if (xtables_check_inverse(optarg, &invert, &optind, 0, argv)) break; - if (!xtables_strtoui(optarg, NULL, &num, 0, 10000)) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_LIMIT: + if (!parse_rate(cb->arg, &r->avg)) xtables_error(PARAMETER_PROBLEM, - "bad --limit-burst `%s'", optarg); - r->burst = num; + "bad rate \"%s\"'", cb->arg); break; - - default: - return 0; } - - if (invert) + if (cb->invert) xtables_error(PARAMETER_PROBLEM, "limit does not support invert"); - - return 1; } static const struct rates { const char *name; - u_int32_t mult; + uint32_t mult; } rates[] = { { "day", XT_LIMIT_SCALE*24*60*60 }, { "hour", XT_LIMIT_SCALE*60*60 }, { "min", XT_LIMIT_SCALE*60 }, { "sec", XT_LIMIT_SCALE } }; -static void print_rate(u_int32_t period) +static void print_rate(uint32_t period) { unsigned int i; + if (period == 0) { + printf(" %f", INFINITY); + return; + } + for (i = 1; i < ARRAY_SIZE(rates); ++i) if (period > rates[i].mult || rates[i].mult/period < rates[i].mult%period) break; - printf("%u/%s ", rates[i-1].mult / period, rates[i-1].name); + printf(" %u/%s", rates[i-1].mult / period, rates[i-1].name); } static void limit_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_rateinfo *r = (const void *)match->data; - printf("limit: avg "); print_rate(r->avg); - printf("burst %u ", r->burst); + printf(" limit: avg"); print_rate(r->avg); + printf(" burst %u", r->burst); } static void limit_save(const void *ip, const struct xt_entry_match *match) { const struct xt_rateinfo *r = (const void *)match->data; - printf("--limit "); print_rate(r->avg); + printf(" --limit"); print_rate(r->avg); if (r->burst != XT_LIMIT_BURST) - printf("--limit-burst %u ", r->burst); + printf(" --limit-burst %u", r->burst); } static struct xtables_match limit_match = { @@ -165,10 +160,10 @@ static struct xtables_match limit_match = { .userspacesize = offsetof(struct xt_rateinfo, prev), .help = limit_help, .init = limit_init, - .parse = limit_parse, + .x6_parse = limit_parse, .print = limit_print, .save = limit_save, - .extra_opts = limit_opts, + .x6_options = limit_opts, }; void _init(void) diff --git a/extensions/libxt_limit.man b/extensions/libxt_limit.man index 9f51ce3..6fb94cc 100644 --- a/extensions/libxt_limit.man +++ b/extensions/libxt_limit.man @@ -1,8 +1,11 @@ This module matches at a limited rate using a token bucket filter. -A rule using this extension will match until this limit is reached -(unless the `!' flag is used). It can be used in combination with the +A rule using this extension will match until this limit is reached. +It can be used in combination with the .B LOG target to give limited logging, for example. +.PP +xt_limit has no negation support - you will have to use \-m hashlimit ! +\-\-hashlimit \fIrate\fP in this case whilst omitting \-\-hashlimit\-mode. .TP \fB\-\-limit\fP \fIrate\fP[\fB/second\fP|\fB/minute\fP|\fB/hour\fP|\fB/day\fP] Maximum average matching rate: specified as a number, with an optional diff --git a/extensions/libxt_mac.c b/extensions/libxt_mac.c index 00996a0..f171d15 100644 --- a/extensions/libxt_mac.c +++ b/extensions/libxt_mac.c @@ -1,9 +1,4 @@ -/* Shared library add-on to iptables to add MAC address support. */ #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> #if defined(__GLIBC__) && __GLIBC__ == 2 #include <net/ethernet.h> #else @@ -12,6 +7,10 @@ #include <xtables.h> #include <linux/netfilter/xt_mac.h> +enum { + O_MAC = 0, +}; + static void mac_help(void) { printf( @@ -20,82 +19,41 @@ static void mac_help(void) " Match source MAC address\n"); } -static const struct option mac_opts[] = { - { "mac-source", 1, NULL, '1' }, - { .name = NULL } +#define s struct xt_mac_info +static const struct xt_option_entry mac_opts[] = { + {.name = "mac-source", .id = O_MAC, .type = XTTYPE_ETHERMAC, + .flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, srcaddr)}, + XTOPT_TABLEEND, }; +#undef s -static void -parse_mac(const char *mac, struct xt_mac_info *info) +static void mac_parse(struct xt_option_call *cb) { - unsigned int i = 0; - - if (strlen(mac) != ETH_ALEN*3-1) - xtables_error(PARAMETER_PROBLEM, "Bad mac address \"%s\"", mac); + struct xt_mac_info *macinfo = cb->data; - 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) - info->srcaddr[i] = number; - else - xtables_error(PARAMETER_PROBLEM, - "Bad mac address `%s'", mac); - } + xtables_option_parse(cb); + if (cb->invert) + macinfo->invert = 1; } -static int -mac_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct xt_mac_info *macinfo = (struct xt_mac_info *)(*match)->data; - - switch (c) { - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_mac(optarg, macinfo); - if (invert) - macinfo->invert = 1; - *flags = 1; - break; - - default: - return 0; - } - - return 1; -} - -static void print_mac(const unsigned char macaddress[ETH_ALEN]) +static void print_mac(const unsigned char *macaddress) { unsigned int i; - printf("%02X", macaddress[0]); - for (i = 1; i < ETH_ALEN; i++) + printf(" %02X", macaddress[0]); + for (i = 1; i < ETH_ALEN; ++i) printf(":%02X", macaddress[i]); - printf(" "); -} - -static void mac_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "You must specify `--mac-source'"); } static void mac_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_mac_info *info = (void *)match->data; - printf("MAC "); + printf(" MAC"); if (info->invert) - printf("! "); + printf(" !"); print_mac(info->srcaddr); } @@ -105,9 +63,9 @@ static void mac_save(const void *ip, const struct xt_entry_match *match) const struct xt_mac_info *info = (void *)match->data; if (info->invert) - printf("! "); + printf(" !"); - printf("--mac-source "); + printf(" --mac-source"); print_mac(info->srcaddr); } @@ -118,11 +76,10 @@ static struct xtables_match mac_match = { .size = XT_ALIGN(sizeof(struct xt_mac_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_mac_info)), .help = mac_help, - .parse = mac_parse, - .final_check = mac_check, + .x6_parse = mac_parse, .print = mac_print, .save = mac_save, - .extra_opts = mac_opts, + .x6_options = mac_opts, }; void _init(void) diff --git a/extensions/libxt_mark.c b/extensions/libxt_mark.c index 8013c9a..7f8c995 100644 --- a/extensions/libxt_mark.c +++ b/extensions/libxt_mark.c @@ -1,21 +1,15 @@ -/* Shared library add-on to iptables to add NFMARK matching support. */ #include <stdbool.h> #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_mark.h> struct xt_mark_info { unsigned long mark, mask; - u_int8_t invert; + uint8_t invert; }; enum { - F_MARK = 1 << 0, + O_MARK = 0, }; static void mark_mt_help(void) @@ -25,80 +19,40 @@ static void mark_mt_help(void) "[!] --mark value[/mask] Match nfmark value with optional mask\n"); } -static const struct option mark_mt_opts[] = { - {.name = "mark", .has_arg = true, .val = '1'}, - { .name = NULL } +static const struct xt_option_entry mark_mt_opts[] = { + {.name = "mark", .id = O_MARK, .type = XTTYPE_MARKMASK32, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; -static int mark_mt_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void mark_mt_parse(struct xt_option_call *cb) { - struct xt_mark_mtinfo1 *info = (void *)(*match)->data; - unsigned int mark, mask = UINT32_MAX; - char *end; - - switch (c) { - case '1': /* --mark */ - xtables_param_act(XTF_ONLY_ONCE, "mark", "--mark", *flags & F_MARK); - if (!xtables_strtoui(optarg, &end, &mark, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "mark", "--mark", optarg); - if (*end == '/') - if (!xtables_strtoui(end + 1, &end, &mask, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "mark", "--mark", optarg); - if (*end != '\0') - xtables_param_act(XTF_BAD_VALUE, "mark", "--mark", optarg); - - if (invert) - info->invert = true; - info->mark = mark; - info->mask = mask; - *flags |= F_MARK; - return true; - } - return false; + struct xt_mark_mtinfo1 *info = cb->data; + + xtables_option_parse(cb); + if (cb->invert) + info->invert = true; + info->mark = cb->val.mark; + info->mask = cb->val.mask; } -static int -mark_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void mark_parse(struct xt_option_call *cb) { - struct xt_mark_info *markinfo = (struct xt_mark_info *)(*match)->data; - - switch (c) { - char *end; - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - markinfo->mark = strtoul(optarg, &end, 0); - if (*end == '/') { - markinfo->mask = strtoul(end+1, &end, 0); - } else - markinfo->mask = 0xffffffff; - if (*end != '\0' || end == optarg) - xtables_error(PARAMETER_PROBLEM, "Bad MARK value \"%s\"", optarg); - if (invert) - markinfo->invert = 1; - *flags = 1; - break; - - default: - return 0; - } - return 1; + struct xt_mark_info *markinfo = cb->data; + + xtables_option_parse(cb); + if (cb->invert) + markinfo->invert = 1; + markinfo->mark = cb->val.mark; + markinfo->mask = cb->val.mask; } static void print_mark(unsigned int mark, unsigned int mask) { if (mask != 0xffffffffU) - printf("0x%x/0x%x ", mark, mask); + printf(" 0x%x/0x%x", mark, mask); else - printf("0x%x ", mark); -} - -static void mark_mt_check(unsigned int flags) -{ - if (flags == 0) - xtables_error(PARAMETER_PROBLEM, - "mark match: The --mark option is required"); + printf(" 0x%x", mark); } static void @@ -106,9 +60,9 @@ mark_mt_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_mark_mtinfo1 *info = (const void *)match->data; - printf("mark match "); + printf(" mark match"); if (info->invert) - printf("!"); + printf(" !"); print_mark(info->mark, info->mask); } @@ -117,10 +71,10 @@ mark_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_mark_info *info = (const void *)match->data; - printf("MARK match "); + printf(" MARK match"); if (info->invert) - printf("!"); + printf(" !"); print_mark(info->mark, info->mask); } @@ -130,9 +84,9 @@ static void mark_mt_save(const void *ip, const struct xt_entry_match *match) const struct xt_mark_mtinfo1 *info = (const void *)match->data; if (info->invert) - printf("! "); + printf(" !"); - printf("--mark "); + printf(" --mark"); print_mark(info->mark, info->mask); } @@ -142,9 +96,9 @@ mark_save(const void *ip, const struct xt_entry_match *match) const struct xt_mark_info *info = (const void *)match->data; if (info->invert) - printf("! "); + printf(" !"); - printf("--mark "); + printf(" --mark"); print_mark(info->mark, info->mask); } @@ -157,11 +111,10 @@ static struct xtables_match mark_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_mark_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_mark_info)), .help = mark_mt_help, - .parse = mark_parse, - .final_check = mark_mt_check, .print = mark_print, .save = mark_save, - .extra_opts = mark_mt_opts, + .x6_parse = mark_parse, + .x6_options = mark_mt_opts, }, { .version = XTABLES_VERSION, @@ -171,11 +124,10 @@ static struct xtables_match mark_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)), .userspacesize = XT_ALIGN(sizeof(struct xt_mark_mtinfo1)), .help = mark_mt_help, - .parse = mark_mt_parse, - .final_check = mark_mt_check, .print = mark_mt_print, .save = mark_mt_save, - .extra_opts = mark_mt_opts, + .x6_parse = mark_mt_parse, + .x6_options = mark_mt_opts, }, }; diff --git a/extensions/libxt_multiport.c b/extensions/libxt_multiport.c index e8a0dab..03af5a9 100644 --- a/extensions/libxt_multiport.c +++ b/extensions/libxt_multiport.c @@ -1,18 +1,23 @@ -/* Shared library add-on to iptables to add multiple TCP port support. */ #include <stdio.h> #include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> - #include <xtables.h> -#include <libiptc/libiptc.h> -#include <libiptc/libip6tc.h> #include <limits.h> /* INT_MAX in ip_tables.h/ip6_tables.h */ #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h> #include <linux/netfilter/xt_multiport.h> +enum { + O_SOURCE_PORTS = 0, + O_DEST_PORTS, + O_SD_PORTS, + F_SOURCE_PORTS = 1 << O_SOURCE_PORTS, + F_DEST_PORTS = 1 << O_DEST_PORTS, + F_SD_PORTS = 1 << O_SD_PORTS, + F_ANY = F_SOURCE_PORTS | F_DEST_PORTS | F_SD_PORTS, +}; + /* Function which prints out usage message. */ static void multiport_help(void) { @@ -43,17 +48,22 @@ static void multiport_help_v1(void) " match both source and destination port(s)\n"); } -static const struct option multiport_opts[] = { - { "source-ports", 1, NULL, '1' }, - { "sports", 1, NULL, '1' }, /* synonym */ - { "destination-ports", 1, NULL, '2' }, - { "dports", 1, NULL, '2' }, /* synonym */ - { "ports", 1, NULL, '3' }, - { .name = NULL } +static const struct xt_option_entry multiport_opts[] = { + {.name = "source-ports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING, + .excl = F_ANY, .flags = XTOPT_INVERT}, + {.name = "sports", .id = O_SOURCE_PORTS, .type = XTTYPE_STRING, + .excl = F_ANY, .flags = XTOPT_INVERT}, + {.name = "destination-ports", .id = O_DEST_PORTS, + .type = XTTYPE_STRING, .excl = F_ANY, .flags = XTOPT_INVERT}, + {.name = "dports", .id = O_DEST_PORTS, .type = XTTYPE_STRING, + .excl = F_ANY, .flags = XTOPT_INVERT}, + {.name = "ports", .id = O_SD_PORTS, .type = XTTYPE_STRING, + .excl = F_ANY, .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, }; -static char * -proto_to_name(u_int8_t proto) +static const char * +proto_to_name(uint8_t proto) { switch (proto) { case IPPROTO_TCP: @@ -72,7 +82,7 @@ proto_to_name(u_int8_t proto) } static unsigned int -parse_multi_ports(const char *portstring, u_int16_t *ports, const char *proto) +parse_multi_ports(const char *portstring, uint16_t *ports, const char *proto) { char *buffer, *cp, *next; unsigned int i; @@ -98,7 +108,7 @@ parse_multi_ports_v1(const char *portstring, { char *buffer, *cp, *next, *range; unsigned int i; - u_int16_t m; + uint16_t m; buffer = strdup(portstring); if (!buffer) xtables_error(OTHER_PROBLEM, "strdup failed"); @@ -132,9 +142,9 @@ parse_multi_ports_v1(const char *portstring, } static const char * -check_proto(u_int16_t pnum, u_int8_t invflags) +check_proto(uint16_t pnum, uint8_t invflags) { - char *proto; + const char *proto; if (invflags & XT_INV_PROTO) xtables_error(PARAMETER_PROBLEM, @@ -151,149 +161,104 @@ check_proto(u_int16_t pnum, u_int8_t invflags) "multiport only works with TCP, UDP, UDPLITE, SCTP and DCCP"); } -/* Function which parses command options; returns true if it - ate an option */ -static int -__multiport_parse(int c, char **argv, int invert, unsigned int *flags, - struct xt_entry_match **match, u_int16_t pnum, - u_int8_t invflags) +static void __multiport_parse(struct xt_option_call *cb, uint16_t pnum, + uint8_t invflags) { const char *proto; - struct xt_multiport *multiinfo - = (struct xt_multiport *)(*match)->data; + struct xt_multiport *multiinfo = cb->data; - switch (c) { - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SOURCE_PORTS: proto = check_proto(pnum, invflags); - multiinfo->count = parse_multi_ports(optarg, + multiinfo->count = parse_multi_ports(cb->arg, multiinfo->ports, proto); multiinfo->flags = XT_MULTIPORT_SOURCE; break; - - case '2': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + case O_DEST_PORTS: proto = check_proto(pnum, invflags); - multiinfo->count = parse_multi_ports(optarg, + multiinfo->count = parse_multi_ports(cb->arg, multiinfo->ports, proto); multiinfo->flags = XT_MULTIPORT_DESTINATION; break; - - case '3': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + case O_SD_PORTS: proto = check_proto(pnum, invflags); - multiinfo->count = parse_multi_ports(optarg, + multiinfo->count = parse_multi_ports(cb->arg, multiinfo->ports, proto); multiinfo->flags = XT_MULTIPORT_EITHER; break; - - default: - return 0; } - - if (invert) + if (cb->invert) xtables_error(PARAMETER_PROBLEM, - "multiport does not support invert"); - - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "multiport can only have one option"); - *flags = 1; - return 1; + "multiport.0 does not support invert"); } -static int -multiport_parse(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_match **match) +static void multiport_parse(struct xt_option_call *cb) { - const struct ipt_entry *entry = e; - return __multiport_parse(c, argv, invert, flags, match, + const struct ipt_entry *entry = cb->xt_entry; + return __multiport_parse(cb, entry->ip.proto, entry->ip.invflags); } -static int -multiport_parse6(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_match **match) +static void multiport_parse6(struct xt_option_call *cb) { - const struct ip6t_entry *entry = e; - return __multiport_parse(c, argv, invert, flags, match, + const struct ip6t_entry *entry = cb->xt_entry; + return __multiport_parse(cb, entry->ipv6.proto, entry->ipv6.invflags); } -static int -__multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags, - struct xt_entry_match **match, u_int16_t pnum, - u_int8_t invflags) +static void __multiport_parse_v1(struct xt_option_call *cb, uint16_t pnum, + uint8_t invflags) { const char *proto; - struct xt_multiport_v1 *multiinfo - = (struct xt_multiport_v1 *)(*match)->data; + struct xt_multiport_v1 *multiinfo = cb->data; - switch (c) { - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SOURCE_PORTS: proto = check_proto(pnum, invflags); - parse_multi_ports_v1(optarg, multiinfo, proto); + parse_multi_ports_v1(cb->arg, multiinfo, proto); multiinfo->flags = XT_MULTIPORT_SOURCE; break; - - case '2': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + case O_DEST_PORTS: proto = check_proto(pnum, invflags); - parse_multi_ports_v1(optarg, multiinfo, proto); + parse_multi_ports_v1(cb->arg, multiinfo, proto); multiinfo->flags = XT_MULTIPORT_DESTINATION; break; - - case '3': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + case O_SD_PORTS: proto = check_proto(pnum, invflags); - parse_multi_ports_v1(optarg, multiinfo, proto); + parse_multi_ports_v1(cb->arg, multiinfo, proto); multiinfo->flags = XT_MULTIPORT_EITHER; break; - - default: - return 0; } - - if (invert) + if (cb->invert) multiinfo->invert = 1; - - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "multiport can only have one option"); - *flags = 1; - return 1; } -static int -multiport_parse_v1(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_match **match) +static void multiport_parse_v1(struct xt_option_call *cb) { - const struct ipt_entry *entry = e; - return __multiport_parse_v1(c, argv, invert, flags, match, + const struct ipt_entry *entry = cb->xt_entry; + return __multiport_parse_v1(cb, entry->ip.proto, entry->ip.invflags); } -static int -multiport_parse6_v1(int c, char **argv, int invert, unsigned int *flags, - const void *e, struct xt_entry_match **match) +static void multiport_parse6_v1(struct xt_option_call *cb) { - const struct ip6t_entry *entry = e; - return __multiport_parse_v1(c, argv, invert, flags, match, + const struct ip6t_entry *entry = cb->xt_entry; + return __multiport_parse_v1(cb, entry->ipv6.proto, entry->ipv6.invflags); } -/* Final check; must specify something. */ -static void multiport_check(unsigned int flags) +static void multiport_check(struct xt_fcheck_call *cb) { - if (!flags) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "multiport expection an option"); } -static char * -port_to_service(int port, u_int8_t proto) +static const char * +port_to_service(int port, uint8_t proto) { - struct servent *service; + const struct servent *service; if ((service = getservbyport(htons(port), proto_to_name(proto)))) return service->s_name; @@ -302,9 +267,9 @@ port_to_service(int port, u_int8_t proto) } static void -print_port(u_int16_t port, u_int8_t protocol, int numeric) +print_port(uint16_t port, uint8_t protocol, int numeric) { - char *service; + const char *service; if (numeric || (service = port_to_service(port, protocol)) == NULL) printf("%u", port); @@ -312,16 +277,15 @@ print_port(u_int16_t port, u_int8_t protocol, int numeric) printf("%s", service); } -/* Prints out the matchinfo. */ static void __multiport_print(const struct xt_entry_match *match, int numeric, - u_int16_t proto) + uint16_t proto) { const struct xt_multiport *multiinfo = (const struct xt_multiport *)match->data; unsigned int i; - printf("multiport "); + printf(" multiport "); switch (multiinfo->flags) { case XT_MULTIPORT_SOURCE: @@ -345,7 +309,6 @@ __multiport_print(const struct xt_entry_match *match, int numeric, printf("%s", i ? "," : ""); print_port(multiinfo->ports[i], proto, numeric); } - printf(" "); } static void multiport_print(const void *ip_void, @@ -363,13 +326,13 @@ static void multiport_print6(const void *ip_void, } static void __multiport_print_v1(const struct xt_entry_match *match, - int numeric, u_int16_t proto) + int numeric, uint16_t proto) { const struct xt_multiport_v1 *multiinfo = (const struct xt_multiport_v1 *)match->data; unsigned int i; - printf("multiport "); + printf(" multiport "); switch (multiinfo->flags) { case XT_MULTIPORT_SOURCE: @@ -390,7 +353,7 @@ static void __multiport_print_v1(const struct xt_entry_match *match, } if (multiinfo->invert) - printf("! "); + printf(" !"); for (i=0; i < multiinfo->count; i++) { printf("%s", i ? "," : ""); @@ -400,7 +363,6 @@ static void __multiport_print_v1(const struct xt_entry_match *match, print_port(multiinfo->ports[++i], proto, numeric); } } - printf(" "); } static void multiport_print_v1(const void *ip_void, @@ -417,9 +379,8 @@ static void multiport_print6_v1(const void *ip_void, __multiport_print_v1(match, numeric, ip->proto); } -/* Saves the union ipt_matchinfo in parsable form to stdout. */ static void __multiport_save(const struct xt_entry_match *match, - u_int16_t proto) + uint16_t proto) { const struct xt_multiport *multiinfo = (const struct xt_multiport *)match->data; @@ -427,15 +388,15 @@ static void __multiport_save(const struct xt_entry_match *match, switch (multiinfo->flags) { case XT_MULTIPORT_SOURCE: - printf("--sports "); + printf(" --sports "); break; case XT_MULTIPORT_DESTINATION: - printf("--dports "); + printf(" --dports "); break; case XT_MULTIPORT_EITHER: - printf("--ports "); + printf(" --ports "); break; } @@ -443,7 +404,6 @@ static void __multiport_save(const struct xt_entry_match *match, printf("%s", i ? "," : ""); print_port(multiinfo->ports[i], proto, 1); } - printf(" "); } static void multiport_save(const void *ip_void, @@ -461,26 +421,26 @@ static void multiport_save6(const void *ip_void, } static void __multiport_save_v1(const struct xt_entry_match *match, - u_int16_t proto) + uint16_t proto) { const struct xt_multiport_v1 *multiinfo = (const struct xt_multiport_v1 *)match->data; unsigned int i; if (multiinfo->invert) - printf("! "); + printf(" !"); switch (multiinfo->flags) { case XT_MULTIPORT_SOURCE: - printf("--sports "); + printf(" --sports "); break; case XT_MULTIPORT_DESTINATION: - printf("--dports "); + printf(" --dports "); break; case XT_MULTIPORT_EITHER: - printf("--ports "); + printf(" --ports "); break; } @@ -492,7 +452,6 @@ static void __multiport_save_v1(const struct xt_entry_match *match, print_port(multiinfo->ports[++i], proto, 1); } } - printf(" "); } static void multiport_save_v1(const void *ip_void, @@ -518,11 +477,11 @@ static struct xtables_match multiport_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_multiport)), .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)), .help = multiport_help, - .parse = multiport_parse, - .final_check = multiport_check, + .x6_parse = multiport_parse, + .x6_fcheck = multiport_check, .print = multiport_print, .save = multiport_save, - .extra_opts = multiport_opts, + .x6_options = multiport_opts, }, { .family = NFPROTO_IPV6, @@ -532,11 +491,11 @@ static struct xtables_match multiport_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_multiport)), .userspacesize = XT_ALIGN(sizeof(struct xt_multiport)), .help = multiport_help, - .parse = multiport_parse6, - .final_check = multiport_check, + .x6_parse = multiport_parse6, + .x6_fcheck = multiport_check, .print = multiport_print6, .save = multiport_save6, - .extra_opts = multiport_opts, + .x6_options = multiport_opts, }, { .family = NFPROTO_IPV4, @@ -546,11 +505,11 @@ static struct xtables_match multiport_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_multiport_v1)), .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)), .help = multiport_help_v1, - .parse = multiport_parse_v1, - .final_check = multiport_check, + .x6_parse = multiport_parse_v1, + .x6_fcheck = multiport_check, .print = multiport_print_v1, .save = multiport_save_v1, - .extra_opts = multiport_opts, + .x6_options = multiport_opts, }, { .family = NFPROTO_IPV6, @@ -560,11 +519,11 @@ static struct xtables_match multiport_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_multiport_v1)), .userspacesize = XT_ALIGN(sizeof(struct xt_multiport_v1)), .help = multiport_help_v1, - .parse = multiport_parse6_v1, - .final_check = multiport_check, + .x6_parse = multiport_parse6_v1, + .x6_fcheck = multiport_check, .print = multiport_print6_v1, .save = multiport_save6_v1, - .extra_opts = multiport_opts, + .x6_options = multiport_opts, }, }; diff --git a/extensions/libxt_multiport.man b/extensions/libxt_multiport.man index caf5c56..7eb083e 100644 --- a/extensions/libxt_multiport.man +++ b/extensions/libxt_multiport.man @@ -1,9 +1,8 @@ This module matches a set of source or destination ports. Up to 15 ports can be specified. A port range (port:port) counts as two -ports. It can only be used in conjunction with -\fB\-p tcp\fP -or -\fB\-p udp\fP. +ports. It can only be used in conjunction with one of the +following protocols: +\fBtcp\fP, \fBudp\fP, \fBudplite\fP, \fBdccp\fP and \fBsctp\fP. .TP [\fB!\fP] \fB\-\-source\-ports\fP,\fB\-\-sports\fP \fIport\fP[\fB,\fP\fIport\fP|\fB,\fP\fIport\fP\fB:\fP\fIport\fP]... Match if the source port is one of the given ports. The flag diff --git a/extensions/libxt_nfacct.c b/extensions/libxt_nfacct.c new file mode 100644 index 0000000..2ad59d5 --- /dev/null +++ b/extensions/libxt_nfacct.c @@ -0,0 +1,89 @@ +/* + * (C) 2011 by Pablo Neira Ayuso <pablo@netfilter.org> + * (C) 2011 by Intra2Net AG <http://www.intra2net.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 (or + * any later at your option) as published by the Free Software Foundation. + */ +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <xtables.h> + +#include <linux/netfilter/x_tables.h> +#include <linux/netfilter/xt_nfacct.h> + +enum { + O_NAME = 0, +}; + +#define s struct xt_nfacct_match_info +static const struct xt_option_entry nfacct_opts[] = { + {.name = "nfacct-name", .id = O_NAME, .type = XTTYPE_STRING, + .min = 1, .flags = XTOPT_MAND|XTOPT_PUT, XTOPT_POINTER(s, name)}, + XTOPT_TABLEEND, +}; +#undef s + +static void nfacct_help(void) +{ + printf("nfacct match options:\n" + " --nfacct-name STRING Name of accouting area\n"); +} + +static void nfacct_parse(struct xt_option_call *cb) +{ + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_NAME: + if (strchr(cb->arg, '\n') != NULL) + xtables_error(PARAMETER_PROBLEM, + "Newlines not allowed in --nfacct-name"); + break; + } +} + +static void +nfacct_print_name(const struct xt_nfacct_match_info *info, char *name) +{ + printf(" %snfacct-name ", name); + xtables_save_string(info->name); +} + +static void nfacct_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + const struct xt_nfacct_match_info *info = + (struct xt_nfacct_match_info *)match->data; + + nfacct_print_name(info, ""); +} + +static void nfacct_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_nfacct_match_info *info = + (struct xt_nfacct_match_info *)match->data; + + nfacct_print_name(info, "--"); +} + +static struct xtables_match nfacct_match = { + .family = NFPROTO_UNSPEC, + .name = "nfacct", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_nfacct_match_info)), + .userspacesize = offsetof(struct xt_nfacct_match_info, nfacct), + .help = nfacct_help, + .x6_parse = nfacct_parse, + .print = nfacct_print, + .save = nfacct_save, + .x6_options = nfacct_opts, +}; + +void _init(void) +{ + xtables_register_match(&nfacct_match); +} diff --git a/extensions/libxt_nfacct.man b/extensions/libxt_nfacct.man new file mode 100644 index 0000000..b755f97 --- /dev/null +++ b/extensions/libxt_nfacct.man @@ -0,0 +1,30 @@ +The nfacct match provides the extended accounting infrastructure for iptables. +You have to use this match together with the standalone user-space utility +.B nfacct(8) +.PP +The only option available for this match is the following: +.TP +\fB\-\-nfacct\-name\fP \fIname\fP +This allows you to specify the existing object name that will be use for +accounting the traffic that this rule-set is matching. +.PP +To use this extension, you have to create an accounting object: +.IP +nfacct add http\-traffic +.PP +Then, you have to attach it to the accounting object via iptables: +.IP +iptables \-I INPUT \-p tcp \-\-sport 80 \-m nfacct \-\-nfacct\-name http\-traffic +.IP +iptables \-I OUTPUT \-p tcp \-\-dport 80 \-m nfacct \-\-nfacct\-name http\-traffic +.PP +Then, you can check for the amount of traffic that the rules match: +.IP +nfacct get http\-traffic +.IP +{ pkts = 00000000000000000156, bytes = 00000000000000151786 } = http-traffic; +.PP +You can obtain +.B nfacct(8) +from http://www.netfilter.org or, alternatively, from the git.netfilter.org +repository. diff --git a/extensions/libxt_osf.c b/extensions/libxt_osf.c index 07b86e4..52dba47 100644 --- a/extensions/libxt_osf.c +++ b/extensions/libxt_osf.c @@ -20,23 +20,19 @@ /* * xtables interface for OS fingerprint matching module. */ - #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <ctype.h> - -#include <linux/types.h> - #include <xtables.h> - #include <netinet/ip.h> #include <netinet/tcp.h> - #include <linux/netfilter/xt_osf.h> +enum { + O_GENRE = 0, + O_TTL, + O_LOGLEVEL, +}; + static void osf_help(void) { printf("OS fingerprint match options:\n" @@ -52,87 +48,58 @@ static void osf_help(void) ); } - -static const struct option osf_opts[] = { - { .name = "genre", .has_arg = true, .val = '1' }, - { .name = "ttl", .has_arg = true, .val = '2' }, - { .name = "log", .has_arg = true, .val = '3' }, - { .name = NULL } +#define s struct xt_osf_info +static const struct xt_option_entry osf_opts[] = { + {.name = "genre", .id = O_GENRE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(s, genre)}, + {.name = "ttl", .id = O_TTL, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, ttl), .min = 0, .max = 2}, + {.name = "log", .id = O_LOGLEVEL, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, loglevel), .min = 0, .max = 2}, + XTOPT_TABLEEND, }; +#undef s - -static void osf_parse_string(const char *s, struct xt_osf_info *info) +static void osf_parse(struct xt_option_call *cb) { - if (strlen(s) < MAXGENRELEN) - strcpy(info->genre, s); - else - xtables_error(PARAMETER_PROBLEM, - "Genre string too long `%s' [%zd], max=%d", - s, strlen(s), MAXGENRELEN); -} - -static int osf_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, - struct xt_entry_match **match) -{ - struct xt_osf_info *info = (struct xt_osf_info *)(*match)->data; + struct xt_osf_info *info = cb->data; - switch(c) { - case '1': /* --genre */ - if (*flags & XT_OSF_GENRE) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple genre parameter"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - osf_parse_string(argv[optind-1], info); - if (invert) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_GENRE: + if (cb->invert) info->flags |= XT_OSF_INVERT; - info->len=strlen(info->genre); - *flags |= XT_OSF_GENRE; + info->len = strlen(info->genre); break; - case '2': /* --ttl */ - if (*flags & XT_OSF_TTL) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple ttl parameter"); - *flags |= XT_OSF_TTL; + case O_TTL: info->flags |= XT_OSF_TTL; - if (!xtables_strtoui(argv[optind-1], NULL, &info->ttl, 0, 2)) - xtables_error(PARAMETER_PROBLEM, "TTL parameter is too big"); break; - case '3': /* --log */ - if (*flags & XT_OSF_LOG) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple log parameter"); - *flags |= XT_OSF_LOG; - if (!xtables_strtoui(argv[optind-1], NULL, &info->loglevel, 0, 2)) - xtables_error(PARAMETER_PROBLEM, "Log level parameter is too big"); + case O_LOGLEVEL: info->flags |= XT_OSF_LOG; break; - default: - return 0; } - - return 1; -} - -static void osf_final_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "OS fingerprint match: You must specify `--genre'"); } static void osf_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_osf_info *info = (const struct xt_osf_info*) match->data; - printf("OS fingerprint match %s%s ", (info->flags & XT_OSF_INVERT) ? "! " : "", info->genre); + printf(" OS fingerprint match %s%s", (info->flags & XT_OSF_INVERT) ? "! " : "", info->genre); } static void osf_save(const void *ip, const struct xt_entry_match *match) { const struct xt_osf_info *info = (const struct xt_osf_info*) match->data; - printf("--genre %s%s ", (info->flags & XT_OSF_INVERT) ? "! ": "", info->genre); + if (info->flags & XT_OSF_INVERT) + printf(" !"); + + printf(" --genre %s", info->genre); + if (info->flags & XT_OSF_TTL) + printf(" --ttl %u", info->ttl); + if (info->flags & XT_OSF_LOG) + printf(" --log %u", info->loglevel); } static struct xtables_match osf_match = { @@ -141,12 +108,11 @@ static struct xtables_match osf_match = { .size = XT_ALIGN(sizeof(struct xt_osf_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_osf_info)), .help = osf_help, - .parse = osf_parse, + .x6_parse = osf_parse, .print = osf_print, - .final_check = osf_final_check, .save = osf_save, - .extra_opts = osf_opts, - .family = NFPROTO_IPV4 + .x6_options = osf_opts, + .family = NFPROTO_IPV4, }; void _init(void) diff --git a/extensions/libxt_owner.c b/extensions/libxt_owner.c index b595d97..d9adc12 100644 --- a/extensions/libxt_owner.c +++ b/extensions/libxt_owner.c @@ -4,16 +4,11 @@ * Copyright © CC Computer Consultants GmbH, 2007 - 2008 * Jan Engelhardt <jengelh@computergmbh.de> */ -#include <getopt.h> #include <grp.h> -#include <netdb.h> #include <pwd.h> #include <stdbool.h> #include <stdio.h> -#include <stdlib.h> -#include <string.h> #include <limits.h> - #include <xtables.h> #include <linux/netfilter/xt_owner.h> @@ -37,7 +32,7 @@ struct ipt_owner_info { pid_t pid; pid_t sid; char comm[16]; - u_int8_t match, invert; /* flags */ + uint8_t match, invert; /* flags */ }; struct ip6t_owner_info { @@ -46,7 +41,7 @@ struct ip6t_owner_info { pid_t pid; pid_t sid; char comm[16]; - u_int8_t match, invert; /* flags */ + uint8_t match, invert; /* flags */ }; /* @@ -55,17 +50,16 @@ struct ip6t_owner_info { */ enum { - FLAG_UID_OWNER = 1 << 0, - FLAG_GID_OWNER = 1 << 1, - FLAG_SOCKET_EXISTS = 1 << 2, - FLAG_PID_OWNER = 1 << 3, - FLAG_SID_OWNER = 1 << 4, - FLAG_COMM = 1 << 5, + O_USER = 0, + O_GROUP, + O_SOCK_EXISTS, + O_PROCESS, + O_SESSION, + O_COMM, }; static void owner_mt_help_v0(void) { -#ifdef IPT_OWNER_COMM printf( "owner match options:\n" "[!] --uid-owner userid Match local UID\n" @@ -74,15 +68,6 @@ static void owner_mt_help_v0(void) "[!] --sid-owner sessionid Match local SID\n" "[!] --cmd-owner name Match local command name\n" "NOTE: PID, SID and command matching are broken on SMP\n"); -#else - printf( -"owner match options:\n" -"[!] --uid-owner userid Match local UID\n" -"[!] --gid-owner groupid Match local GID\n" -"[!] --pid-owner processid Match local PID\n" -"[!] --sid-owner sessionid Match local SID\n" -"NOTE: PID and SID matching are broken on SMP\n"); -#endif /* IPT_OWNER_COMM */ } static void owner_mt6_help_v0(void) @@ -105,174 +90,137 @@ static void owner_mt_help(void) "[!] --socket-exists Match if socket exists\n"); } -static const struct option owner_mt_opts_v0[] = { - {.name = "uid-owner", .has_arg = true, .val = 'u'}, - {.name = "gid-owner", .has_arg = true, .val = 'g'}, - {.name = "pid-owner", .has_arg = true, .val = 'p'}, - {.name = "sid-owner", .has_arg = true, .val = 's'}, -#ifdef IPT_OWNER_COMM - {.name = "cmd-owner", .has_arg = true, .val = 'c'}, -#endif - { .name = NULL } +#define s struct ipt_owner_info +static const struct xt_option_entry owner_mt_opts_v0[] = { + {.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid), + .max = INT_MAX}, + {.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid), + .max = INT_MAX}, + {.name = "cmd-owner", .id = O_COMM, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, comm)}, + XTOPT_TABLEEND, }; - -static const struct option owner_mt6_opts_v0[] = { - {.name = "uid-owner", .has_arg = true, .val = 'u'}, - {.name = "gid-owner", .has_arg = true, .val = 'g'}, - {.name = "pid-owner", .has_arg = true, .val = 'p'}, - {.name = "sid-owner", .has_arg = true, .val = 's'}, - { .name = NULL } +#undef s + +#define s struct ip6t_owner_info +static const struct xt_option_entry owner_mt6_opts_v0[] = { + {.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "pid-owner", .id = O_PROCESS, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, pid), + .max = INT_MAX}, + {.name = "sid-owner", .id = O_SESSION, .type = XTTYPE_UINT32, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, sid), + .max = INT_MAX}, + XTOPT_TABLEEND, }; - -static const struct option owner_mt_opts[] = { - {.name = "uid-owner", .has_arg = true, .val = 'u'}, - {.name = "gid-owner", .has_arg = true, .val = 'g'}, - {.name = "socket-exists", .has_arg = false, .val = 'k'}, - { .name = NULL } +#undef s + +static const struct xt_option_entry owner_mt_opts[] = { + {.name = "uid-owner", .id = O_USER, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "gid-owner", .id = O_GROUP, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "socket-exists", .id = O_SOCK_EXISTS, .type = XTTYPE_NONE, + .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, }; -static int -owner_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void owner_mt_parse_v0(struct xt_option_call *cb) { - struct ipt_owner_info *info = (void *)(*match)->data; + struct ipt_owner_info *info = cb->data; struct passwd *pwd; struct group *grp; unsigned int id; - switch (c) { - case 'u': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", *flags & FLAG_UID_OWNER); - if ((pwd = getpwnam(optarg)) != NULL) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_USER: + if ((pwd = getpwnam(cb->arg)) != NULL) id = pwd->pw_uid; - else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg); - if (invert) + else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1)) + xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg); + if (cb->invert) info->invert |= IPT_OWNER_UID; info->match |= IPT_OWNER_UID; info->uid = id; - *flags |= FLAG_UID_OWNER; - return true; - - case 'g': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", *flags & FLAG_GID_OWNER); - if ((grp = getgrnam(optarg)) != NULL) + break; + case O_GROUP: + if ((grp = getgrnam(cb->arg)) != NULL) id = grp->gr_gid; - else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg); - if (invert) + else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1)) + xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg); + if (cb->invert) info->invert |= IPT_OWNER_GID; info->match |= IPT_OWNER_GID; info->gid = id; - *flags |= FLAG_GID_OWNER; - return true; - - case 'p': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner", *flags & FLAG_PID_OWNER); - if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg); - if (invert) + break; + case O_PROCESS: + if (cb->invert) info->invert |= IPT_OWNER_PID; info->match |= IPT_OWNER_PID; - info->pid = id; - *flags |= FLAG_PID_OWNER; - return true; - - case 's': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner", *flags & FLAG_SID_OWNER); - if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-value", optarg); - if (invert) + break; + case O_SESSION: + if (cb->invert) info->invert |= IPT_OWNER_SID; info->match |= IPT_OWNER_SID; - info->sid = id; - *flags |= FLAG_SID_OWNER; - return true; - -#ifdef IPT_OWNER_COMM - case 'c': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--cmd-owner", *flags & FLAG_COMM); - if (strlen(optarg) > sizeof(info->comm)) - xtables_error(PARAMETER_PROBLEM, "owner match: command " - "\"%s\" too long, max. %zu characters", - optarg, sizeof(info->comm)); - - info->comm[sizeof(info->comm)-1] = '\0'; - strncpy(info->comm, optarg, sizeof(info->comm)); - - if (invert) + break; + case O_COMM: + if (cb->invert) info->invert |= IPT_OWNER_COMM; info->match |= IPT_OWNER_COMM; - *flags |= FLAG_COMM; - return true; -#endif + break; } - return false; } -static int -owner_mt6_parse_v0(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void owner_mt6_parse_v0(struct xt_option_call *cb) { - struct ip6t_owner_info *info = (void *)(*match)->data; + struct ip6t_owner_info *info = cb->data; struct passwd *pwd; struct group *grp; unsigned int id; - switch (c) { - case 'u': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", - *flags & FLAG_UID_OWNER); - if ((pwd = getpwnam(optarg)) != NULL) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_USER: + if ((pwd = getpwnam(cb->arg)) != NULL) id = pwd->pw_uid; - else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", optarg); - if (invert) + else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1)) + xtables_param_act(XTF_BAD_VALUE, "owner", "--uid-owner", cb->arg); + if (cb->invert) info->invert |= IP6T_OWNER_UID; info->match |= IP6T_OWNER_UID; info->uid = id; - *flags |= FLAG_UID_OWNER; - return true; - - case 'g': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", - *flags & FLAG_GID_OWNER); - if ((grp = getgrnam(optarg)) != NULL) + break; + case O_GROUP: + if ((grp = getgrnam(cb->arg)) != NULL) id = grp->gr_gid; - else if (!xtables_strtoui(optarg, NULL, &id, 0, UINT32_MAX - 1)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", optarg); - if (invert) + else if (!xtables_strtoui(cb->arg, NULL, &id, 0, UINT32_MAX - 1)) + xtables_param_act(XTF_BAD_VALUE, "owner", "--gid-owner", cb->arg); + if (cb->invert) info->invert |= IP6T_OWNER_GID; info->match |= IP6T_OWNER_GID; info->gid = id; - *flags |= FLAG_GID_OWNER; - return true; - - case 'p': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--pid-owner", - *flags & FLAG_PID_OWNER); - if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--pid-owner", optarg); - if (invert) + break; + case O_PROCESS: + if (cb->invert) info->invert |= IP6T_OWNER_PID; info->match |= IP6T_OWNER_PID; - info->pid = id; - *flags |= FLAG_PID_OWNER; - return true; - - case 's': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--sid-owner", - *flags & FLAG_SID_OWNER); - if (!xtables_strtoui(optarg, NULL, &id, 0, INT_MAX)) - xtables_param_act(XTF_BAD_VALUE, "owner", "--sid-owner", optarg); - if (invert) + break; + case O_SESSION: + if (cb->invert) info->invert |= IP6T_OWNER_SID; info->match |= IP6T_OWNER_SID; - info->sid = id; - *flags |= FLAG_SID_OWNER; - return true; + break; } - return false; } static void owner_parse_range(const char *s, unsigned int *from, @@ -291,61 +239,48 @@ static void owner_parse_range(const char *s, unsigned int *from, xtables_param_act(XTF_BAD_VALUE, "owner", opt, s); } -static int owner_mt_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void owner_mt_parse(struct xt_option_call *cb) { - struct xt_owner_match_info *info = (void *)(*match)->data; + struct xt_owner_match_info *info = cb->data; struct passwd *pwd; struct group *grp; unsigned int from, to; - switch (c) { - case 'u': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--uid-owner", - *flags & FLAG_UID_OWNER); - if ((pwd = getpwnam(optarg)) != NULL) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_USER: + if ((pwd = getpwnam(cb->arg)) != NULL) from = to = pwd->pw_uid; else - owner_parse_range(optarg, &from, &to, "--uid-owner"); - if (invert) + owner_parse_range(cb->arg, &from, &to, "--uid-owner"); + if (cb->invert) info->invert |= XT_OWNER_UID; info->match |= XT_OWNER_UID; info->uid_min = from; info->uid_max = to; - *flags |= FLAG_UID_OWNER; - return true; - - case 'g': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--gid-owner", - *flags & FLAG_GID_OWNER); - if ((grp = getgrnam(optarg)) != NULL) + break; + case O_GROUP: + if ((grp = getgrnam(cb->arg)) != NULL) from = to = grp->gr_gid; else - owner_parse_range(optarg, &from, &to, "--gid-owner"); - if (invert) + owner_parse_range(cb->arg, &from, &to, "--gid-owner"); + if (cb->invert) info->invert |= XT_OWNER_GID; info->match |= XT_OWNER_GID; info->gid_min = from; info->gid_max = to; - *flags |= FLAG_GID_OWNER; - return true; - - case 'k': - xtables_param_act(XTF_ONLY_ONCE, "owner", "--socket-exists", - *flags & FLAG_SOCKET_EXISTS); - if (invert) + break; + case O_SOCK_EXISTS: + if (cb->invert) info->invert |= XT_OWNER_SOCKET; info->match |= XT_OWNER_SOCKET; - *flags |= FLAG_SOCKET_EXISTS; - return true; - + break; } - return false; } -static void owner_mt_check(unsigned int flags) +static void owner_mt_check(struct xt_fcheck_call *cb) { - if (flags == 0) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "owner: At least one of " "--uid-owner, --gid-owner or --socket-exists " "is required"); @@ -353,13 +288,13 @@ static void owner_mt_check(unsigned int flags) static void owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label, - u_int8_t flag, bool numeric) + uint8_t flag, bool numeric) { if (!(info->match & flag)) return; if (info->invert & flag) - printf("! "); - printf("%s ", label); + printf(" !"); + printf(" %s", label); switch (info->match & flag) { case IPT_OWNER_UID: @@ -367,11 +302,11 @@ owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label, struct passwd *pwd = getpwuid(info->uid); if (pwd != NULL && pwd->pw_name != NULL) { - printf("%s ", pwd->pw_name); + printf(" %s", pwd->pw_name); break; } } - printf("%u ", (unsigned int)info->uid); + printf(" %u", (unsigned int)info->uid); break; case IPT_OWNER_GID: @@ -379,38 +314,36 @@ owner_mt_print_item_v0(const struct ipt_owner_info *info, const char *label, struct group *grp = getgrgid(info->gid); if (grp != NULL && grp->gr_name != NULL) { - printf("%s ", grp->gr_name); + printf(" %s", grp->gr_name); break; } } - printf("%u ", (unsigned int)info->gid); + printf(" %u", (unsigned int)info->gid); break; case IPT_OWNER_PID: - printf("%u ", (unsigned int)info->pid); + printf(" %u", (unsigned int)info->pid); break; case IPT_OWNER_SID: - printf("%u ", (unsigned int)info->sid); + printf(" %u", (unsigned int)info->sid); break; -#ifdef IPT_OWNER_COMM case IPT_OWNER_COMM: - printf("%.*s ", (int)sizeof(info->comm), info->comm); + printf(" %.*s", (int)sizeof(info->comm), info->comm); break; -#endif } } static void owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label, - u_int8_t flag, bool numeric) + uint8_t flag, bool numeric) { if (!(info->match & flag)) return; if (info->invert & flag) - printf("! "); - printf("%s ", label); + printf(" !"); + printf(" %s", label); switch (info->match & flag) { case IP6T_OWNER_UID: @@ -418,11 +351,11 @@ owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label, struct passwd *pwd = getpwuid(info->uid); if (pwd != NULL && pwd->pw_name != NULL) { - printf("%s ", pwd->pw_name); + printf(" %s", pwd->pw_name); break; } } - printf("%u ", (unsigned int)info->uid); + printf(" %u", (unsigned int)info->uid); break; case IP6T_OWNER_GID: @@ -430,64 +363,64 @@ owner_mt6_print_item_v0(const struct ip6t_owner_info *info, const char *label, struct group *grp = getgrgid(info->gid); if (grp != NULL && grp->gr_name != NULL) { - printf("%s ", grp->gr_name); + printf(" %s", grp->gr_name); break; } } - printf("%u ", (unsigned int)info->gid); + printf(" %u", (unsigned int)info->gid); break; case IP6T_OWNER_PID: - printf("%u ", (unsigned int)info->pid); + printf(" %u", (unsigned int)info->pid); break; case IP6T_OWNER_SID: - printf("%u ", (unsigned int)info->sid); + printf(" %u", (unsigned int)info->sid); break; } } static void owner_mt_print_item(const struct xt_owner_match_info *info, const char *label, - u_int8_t flag, bool numeric) + uint8_t flag, bool numeric) { if (!(info->match & flag)) return; if (info->invert & flag) - printf("! "); - printf("%s ", label); + printf(" !"); + printf(" %s", label); switch (info->match & flag) { case XT_OWNER_UID: if (info->uid_min != info->uid_max) { - printf("%u-%u ", (unsigned int)info->uid_min, + printf(" %u-%u", (unsigned int)info->uid_min, (unsigned int)info->uid_max); break; } else if (!numeric) { const struct passwd *pwd = getpwuid(info->uid_min); if (pwd != NULL && pwd->pw_name != NULL) { - printf("%s ", pwd->pw_name); + printf(" %s", pwd->pw_name); break; } } - printf("%u ", (unsigned int)info->uid_min); + printf(" %u", (unsigned int)info->uid_min); break; case XT_OWNER_GID: if (info->gid_min != info->gid_max) { - printf("%u-%u ", (unsigned int)info->gid_min, + printf(" %u-%u", (unsigned int)info->gid_min, (unsigned int)info->gid_max); break; } else if (!numeric) { const struct group *grp = getgrgid(info->gid_min); if (grp != NULL && grp->gr_name != NULL) { - printf("%s ", grp->gr_name); + printf(" %s", grp->gr_name); break; } } - printf("%u ", (unsigned int)info->gid_min); + printf(" %u", (unsigned int)info->gid_min); break; } } @@ -502,9 +435,7 @@ owner_mt_print_v0(const void *ip, const struct xt_entry_match *match, owner_mt_print_item_v0(info, "owner GID match", IPT_OWNER_GID, numeric); owner_mt_print_item_v0(info, "owner PID match", IPT_OWNER_PID, numeric); owner_mt_print_item_v0(info, "owner SID match", IPT_OWNER_SID, numeric); -#ifdef IPT_OWNER_COMM owner_mt_print_item_v0(info, "owner CMD match", IPT_OWNER_COMM, numeric); -#endif } static void @@ -538,9 +469,7 @@ owner_mt_save_v0(const void *ip, const struct xt_entry_match *match) owner_mt_print_item_v0(info, "--gid-owner", IPT_OWNER_GID, true); owner_mt_print_item_v0(info, "--pid-owner", IPT_OWNER_PID, true); owner_mt_print_item_v0(info, "--sid-owner", IPT_OWNER_SID, true); -#ifdef IPT_OWNER_COMM owner_mt_print_item_v0(info, "--cmd-owner", IPT_OWNER_COMM, true); -#endif } static void @@ -558,9 +487,9 @@ static void owner_mt_save(const void *ip, const struct xt_entry_match *match) { const struct xt_owner_match_info *info = (void *)match->data; - owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, false); - owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, false); - owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, false); + owner_mt_print_item(info, "--socket-exists", XT_OWNER_SOCKET, true); + owner_mt_print_item(info, "--uid-owner", XT_OWNER_UID, true); + owner_mt_print_item(info, "--gid-owner", XT_OWNER_GID, true); } static struct xtables_match owner_mt_reg[] = { @@ -572,11 +501,11 @@ static struct xtables_match owner_mt_reg[] = { .size = XT_ALIGN(sizeof(struct ipt_owner_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_owner_info)), .help = owner_mt_help_v0, - .parse = owner_mt_parse_v0, - .final_check = owner_mt_check, + .x6_parse = owner_mt_parse_v0, + .x6_fcheck = owner_mt_check, .print = owner_mt_print_v0, .save = owner_mt_save_v0, - .extra_opts = owner_mt_opts_v0, + .x6_options = owner_mt_opts_v0, }, { .version = XTABLES_VERSION, @@ -586,11 +515,11 @@ static struct xtables_match owner_mt_reg[] = { .size = XT_ALIGN(sizeof(struct ip6t_owner_info)), .userspacesize = XT_ALIGN(sizeof(struct ip6t_owner_info)), .help = owner_mt6_help_v0, - .parse = owner_mt6_parse_v0, - .final_check = owner_mt_check, + .x6_parse = owner_mt6_parse_v0, + .x6_fcheck = owner_mt_check, .print = owner_mt6_print_v0, .save = owner_mt6_save_v0, - .extra_opts = owner_mt6_opts_v0, + .x6_options = owner_mt6_opts_v0, }, { .version = XTABLES_VERSION, @@ -600,11 +529,11 @@ static struct xtables_match owner_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_owner_match_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_owner_match_info)), .help = owner_mt_help, - .parse = owner_mt_parse, - .final_check = owner_mt_check, + .x6_parse = owner_mt_parse, + .x6_fcheck = owner_mt_check, .print = owner_mt_print, .save = owner_mt_save, - .extra_opts = owner_mt_opts, + .x6_options = owner_mt_opts, }, }; diff --git a/extensions/libxt_physdev.c b/extensions/libxt_physdev.c index 5382ab6..a11faf4 100644 --- a/extensions/libxt_physdev.c +++ b/extensions/libxt_physdev.c @@ -1,16 +1,14 @@ -/* Shared library add-on to iptables to add bridge port matching support. */ #include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <ctype.h> #include <xtables.h> #include <linux/netfilter/xt_physdev.h> -#if defined(__GLIBC__) && __GLIBC__ == 2 -#include <net/ethernet.h> -#else -#include <linux/if_ether.h> -#endif + +enum { + O_PHYSDEV_IN = 0, + O_PHYSDEV_OUT, + O_PHYSDEV_IS_IN, + O_PHYSDEV_IS_OUT, + O_PHYSDEV_IS_BRIDGED, +}; static void physdev_help(void) { @@ -23,91 +21,63 @@ static void physdev_help(void) " [!] --physdev-is-bridged it's a bridged packet\n"); } -static const struct option physdev_opts[] = { - { "physdev-in", 1, NULL, '1' }, - { "physdev-out", 1, NULL, '2' }, - { "physdev-is-in", 0, NULL, '3' }, - { "physdev-is-out", 0, NULL, '4' }, - { "physdev-is-bridged", 0, NULL, '5' }, - { .name = NULL } +#define s struct xt_physdev_info +static const struct xt_option_entry physdev_opts[] = { + {.name = "physdev-in", .id = O_PHYSDEV_IN, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, physindev)}, + {.name = "physdev-out", .id = O_PHYSDEV_OUT, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, physoutdev)}, + {.name = "physdev-is-in", .id = O_PHYSDEV_IS_IN, .type = XTTYPE_NONE, + .flags = XTOPT_INVERT}, + {.name = "physdev-is-out", .id = O_PHYSDEV_IS_OUT, + .type = XTTYPE_NONE, .flags = XTOPT_INVERT}, + {.name = "physdev-is-bridged", .id = O_PHYSDEV_IS_BRIDGED, + .type = XTTYPE_NONE, .flags = XTOPT_INVERT}, + XTOPT_TABLEEND, }; +#undef s -static int -physdev_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void physdev_parse(struct xt_option_call *cb) { - struct xt_physdev_info *info = - (struct xt_physdev_info*)(*match)->data; + struct xt_physdev_info *info = cb->data; - switch (c) { - case '1': - if (*flags & XT_PHYSDEV_OP_IN) - goto multiple_use; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - xtables_parse_interface(optarg, info->physindev, + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_PHYSDEV_IN: + xtables_parse_interface(cb->arg, info->physindev, (unsigned char *)info->in_mask); - if (invert) + if (cb->invert) info->invert |= XT_PHYSDEV_OP_IN; info->bitmask |= XT_PHYSDEV_OP_IN; - *flags |= XT_PHYSDEV_OP_IN; break; - - case '2': - if (*flags & XT_PHYSDEV_OP_OUT) - goto multiple_use; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - xtables_parse_interface(optarg, info->physoutdev, + case O_PHYSDEV_OUT: + xtables_parse_interface(cb->arg, info->physoutdev, (unsigned char *)info->out_mask); - if (invert) + if (cb->invert) info->invert |= XT_PHYSDEV_OP_OUT; info->bitmask |= XT_PHYSDEV_OP_OUT; - *flags |= XT_PHYSDEV_OP_OUT; break; - - case '3': - if (*flags & XT_PHYSDEV_OP_ISIN) - goto multiple_use; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + case O_PHYSDEV_IS_IN: info->bitmask |= XT_PHYSDEV_OP_ISIN; - if (invert) + if (cb->invert) info->invert |= XT_PHYSDEV_OP_ISIN; - *flags |= XT_PHYSDEV_OP_ISIN; break; - - case '4': - if (*flags & XT_PHYSDEV_OP_ISOUT) - goto multiple_use; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); + case O_PHYSDEV_IS_OUT: info->bitmask |= XT_PHYSDEV_OP_ISOUT; - if (invert) + if (cb->invert) info->invert |= XT_PHYSDEV_OP_ISOUT; - *flags |= XT_PHYSDEV_OP_ISOUT; break; - - case '5': - if (*flags & XT_PHYSDEV_OP_BRIDGED) - goto multiple_use; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (invert) + case O_PHYSDEV_IS_BRIDGED: + if (cb->invert) info->invert |= XT_PHYSDEV_OP_BRIDGED; - *flags |= XT_PHYSDEV_OP_BRIDGED; info->bitmask |= XT_PHYSDEV_OP_BRIDGED; break; - - default: - return 0; } - - return 1; -multiple_use: - xtables_error(PARAMETER_PROBLEM, - "multiple use of the same physdev option is not allowed"); - } -static void physdev_check(unsigned int flags) +static void physdev_check(struct xt_fcheck_call *cb) { - if (flags == 0) + if (cb->xflags == 0) xtables_error(PARAMETER_PROBLEM, "PHYSDEV: no physdev option specified"); } @@ -116,7 +86,7 @@ physdev_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_physdev_info *info = (const void *)match->data; - printf("PHYSDEV match"); + printf(" PHYSDEV match"); if (info->bitmask & XT_PHYSDEV_OP_ISIN) printf("%s --physdev-is-in", info->invert & XT_PHYSDEV_OP_ISIN ? " !":""); @@ -133,7 +103,6 @@ physdev_print(const void *ip, const struct xt_entry_match *match, int numeric) if (info->bitmask & XT_PHYSDEV_OP_BRIDGED) printf("%s --physdev-is-bridged", info->invert & XT_PHYSDEV_OP_BRIDGED ? " !":""); - printf(" "); } static void physdev_save(const void *ip, const struct xt_entry_match *match) @@ -141,23 +110,23 @@ static void physdev_save(const void *ip, const struct xt_entry_match *match) const struct xt_physdev_info *info = (const void *)match->data; if (info->bitmask & XT_PHYSDEV_OP_ISIN) - printf("%s--physdev-is-in ", - (info->invert & XT_PHYSDEV_OP_ISIN) ? "! " : ""); + printf("%s --physdev-is-in", + (info->invert & XT_PHYSDEV_OP_ISIN) ? " !" : ""); if (info->bitmask & XT_PHYSDEV_OP_IN) - printf("%s--physdev-in %s ", - (info->invert & XT_PHYSDEV_OP_IN) ? "! " : "", + printf("%s --physdev-in %s", + (info->invert & XT_PHYSDEV_OP_IN) ? " !" : "", info->physindev); if (info->bitmask & XT_PHYSDEV_OP_ISOUT) - printf("%s--physdev-is-out ", - (info->invert & XT_PHYSDEV_OP_ISOUT) ? "! " : ""); + printf("%s --physdev-is-out", + (info->invert & XT_PHYSDEV_OP_ISOUT) ? " !" : ""); if (info->bitmask & XT_PHYSDEV_OP_OUT) - printf("%s--physdev-out %s ", - (info->invert & XT_PHYSDEV_OP_OUT) ? "! " : "", + printf("%s --physdev-out %s", + (info->invert & XT_PHYSDEV_OP_OUT) ? " !" : "", info->physoutdev); if (info->bitmask & XT_PHYSDEV_OP_BRIDGED) - printf("%s--physdev-is-bridged ", - (info->invert & XT_PHYSDEV_OP_BRIDGED) ? "! " : ""); + printf("%s --physdev-is-bridged", + (info->invert & XT_PHYSDEV_OP_BRIDGED) ? " !" : ""); } static struct xtables_match physdev_match = { @@ -167,11 +136,11 @@ static struct xtables_match physdev_match = { .size = XT_ALIGN(sizeof(struct xt_physdev_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_physdev_info)), .help = physdev_help, - .parse = physdev_parse, - .final_check = physdev_check, .print = physdev_print, .save = physdev_save, - .extra_opts = physdev_opts, + .x6_parse = physdev_parse, + .x6_fcheck = physdev_check, + .x6_options = physdev_opts, }; void _init(void) diff --git a/extensions/libxt_pkttype.c b/extensions/libxt_pkttype.c index cd83e73..b72c013 100644 --- a/extensions/libxt_pkttype.c +++ b/extensions/libxt_pkttype.c @@ -5,20 +5,15 @@ * Michal Ludvig <michal@logix.cz> */ #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> -#if defined(__GLIBC__) && __GLIBC__ == 2 -#include <net/ethernet.h> -#else -#include <linux/if_ether.h> -#endif #include <xtables.h> +#define __aligned_u64 __u64 __attribute__((aligned(8))) #include <linux/if_packet.h> #include <linux/netfilter/xt_pkttype.h> -#define PKTTYPE_VERSION "0.1" +enum { + O_PKTTYPE = 0, +}; struct pkttypes { const char *name; @@ -60,9 +55,10 @@ static void pkttype_help(void) print_types(); } -static const struct option pkttype_opts[] = { - {"pkt-type", 1, NULL, '1'}, - { .name = NULL } +static const struct xt_option_entry pkttype_opts[] = { + {.name = "pkt-type", .id = O_PKTTYPE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; static void parse_pkttype(const char *pkttype, struct xt_pkttype_info *info) @@ -79,32 +75,14 @@ static void parse_pkttype(const char *pkttype, struct xt_pkttype_info *info) xtables_error(PARAMETER_PROBLEM, "Bad packet type '%s'", pkttype); } -static int pkttype_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void pkttype_parse(struct xt_option_call *cb) { - struct xt_pkttype_info *info = (struct xt_pkttype_info *)(*match)->data; - - switch(c) - { - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_pkttype(optarg, info); - if(invert) - info->invert=1; - *flags=1; - break; - - default: - return 0; - } + struct xt_pkttype_info *info = cb->data; - return 1; -} - -static void pkttype_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, "You must specify \"--pkt-type\""); + xtables_option_parse(cb); + parse_pkttype(cb->arg, info); + if (cb->invert) + info->invert = 1; } static void print_pkttype(const struct xt_pkttype_info *info) @@ -114,11 +92,11 @@ static void print_pkttype(const struct xt_pkttype_info *info) for (i = 0; i < ARRAY_SIZE(supported_types); ++i) if(supported_types[i].pkttype==info->pkttype) { - printf("%s ", supported_types[i].name); + printf("%s", supported_types[i].name); return; } - printf("%d ", info->pkttype); /* in case we didn't find an entry in named-packtes */ + printf("%d", info->pkttype); /* in case we didn't find an entry in named-packtes */ } static void pkttype_print(const void *ip, const struct xt_entry_match *match, @@ -126,7 +104,7 @@ static void pkttype_print(const void *ip, const struct xt_entry_match *match, { const struct xt_pkttype_info *info = (const void *)match->data; - printf("PKTTYPE %s= ", info->invert?"!":""); + printf(" PKTTYPE %s= ", info->invert ? "!" : ""); print_pkttype(info); } @@ -134,7 +112,7 @@ static void pkttype_save(const void *ip, const struct xt_entry_match *match) { const struct xt_pkttype_info *info = (const void *)match->data; - printf("%s--pkt-type ", info->invert ? "! " : ""); + printf("%s --pkt-type ", info->invert ? " !" : ""); print_pkttype(info); } @@ -145,11 +123,10 @@ static struct xtables_match pkttype_match = { .size = XT_ALIGN(sizeof(struct xt_pkttype_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_pkttype_info)), .help = pkttype_help, - .parse = pkttype_parse, - .final_check = pkttype_check, .print = pkttype_print, .save = pkttype_save, - .extra_opts = pkttype_opts, + .x6_parse = pkttype_parse, + .x6_options = pkttype_opts, }; void _init(void) diff --git a/extensions/libxt_policy.c b/extensions/libxt_policy.c index a87ddd8..0a64a80 100644 --- a/extensions/libxt_policy.c +++ b/extensions/libxt_policy.c @@ -1,24 +1,28 @@ -/* Shared library add-on to iptables to add policy support. */ +/* + * Copyright (c) 2005-2013 Patrick McHardy <kaber@trash.net> + */ + +#include <stdbool.h> +#include <stdint.h> #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <syslog.h> -#include <getopt.h> #include <netdb.h> -#include <errno.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> #include <xtables.h> - #include <linux/netfilter/xt_policy.h> -/* - * HACK: global pointer to current matchinfo for making - * final checks and adjustments in final_check. - */ -static struct xt_policy_info *policy_info; +enum { + O_DIRECTION = 0, + O_POLICY, + O_STRICT, + O_REQID, + O_SPI, + O_PROTO, + O_MODE, + O_TUNNELSRC, + O_TUNNELDST, + O_NEXT, + F_STRICT = 1 << O_STRICT, +}; static void policy_help(void) { @@ -29,6 +33,7 @@ static void policy_help(void) " --pol none|ipsec match policy\n" " --strict match entire policy instead of single element\n" " at any position\n" +"These options may be used repeatedly, to describe policy elements:\n" "[!] --reqid reqid match reqid\n" "[!] --spi spi match SPI\n" "[!] --proto proto match protocol (ah/esp/ipcomp)\n" @@ -38,60 +43,28 @@ static void policy_help(void) " --next begin next element in policy\n"); } -static const struct option policy_opts[] = -{ - { - .name = "dir", - .has_arg = 1, - .val = '1', - }, - { - .name = "pol", - .has_arg = 1, - .val = '2', - }, - { - .name = "strict", - .val = '3' - }, - { - .name = "reqid", - .has_arg = 1, - .val = '4', - }, - { - .name = "spi", - .has_arg = 1, - .val = '5' - }, - { - .name = "tunnel-src", - .has_arg = 1, - .val = '6' - }, - { - .name = "tunnel-dst", - .has_arg = 1, - .val = '7' - }, - { - .name = "proto", - .has_arg = 1, - .val = '8' - }, - { - .name = "mode", - .has_arg = 1, - .val = '9' - }, - { - .name = "next", - .val = 'a' - }, - { .name = NULL } +static const struct xt_option_entry policy_opts[] = { + {.name = "dir", .id = O_DIRECTION, .type = XTTYPE_STRING}, + {.name = "pol", .id = O_POLICY, .type = XTTYPE_STRING}, + {.name = "strict", .id = O_STRICT, .type = XTTYPE_NONE}, + {.name = "reqid", .id = O_REQID, .type = XTTYPE_UINT32, + .flags = XTOPT_MULTI | XTOPT_INVERT}, + {.name = "spi", .id = O_SPI, .type = XTTYPE_UINT32, + .flags = XTOPT_MULTI | XTOPT_INVERT}, + {.name = "tunnel-src", .id = O_TUNNELSRC, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MULTI | XTOPT_INVERT}, + {.name = "tunnel-dst", .id = O_TUNNELDST, .type = XTTYPE_HOSTMASK, + .flags = XTOPT_MULTI | XTOPT_INVERT}, + {.name = "proto", .id = O_PROTO, .type = XTTYPE_PROTOCOL, + .flags = XTOPT_MULTI | XTOPT_INVERT}, + {.name = "mode", .id = O_MODE, .type = XTTYPE_STRING, + .flags = XTOPT_MULTI | XTOPT_INVERT}, + {.name = "next", .id = O_NEXT, .type = XTTYPE_NONE, + .flags = XTOPT_MULTI, .also = F_STRICT}, + XTOPT_TABLEEND, }; -static int parse_direction(char *s) +static int parse_direction(const char *s) { if (strcmp(s, "in") == 0) return XT_POLICY_MATCH_IN; @@ -100,7 +73,7 @@ static int parse_direction(char *s) xtables_error(PARAMETER_PROBLEM, "policy_match: invalid dir \"%s\"", s); } -static int parse_policy(char *s) +static int parse_policy(const char *s) { if (strcmp(s, "none") == 0) return XT_POLICY_MATCH_NONE; @@ -109,7 +82,7 @@ static int parse_policy(char *s) xtables_error(PARAMETER_PROBLEM, "policy match: invalid policy \"%s\"", s); } -static int parse_mode(char *s) +static int parse_mode(const char *s) { if (strcmp(s, "transport") == 0) return XT_POLICY_MODE_TRANSPORT; @@ -118,178 +91,95 @@ static int parse_mode(char *s) xtables_error(PARAMETER_PROBLEM, "policy match: invalid mode \"%s\"", s); } -static int policy_parse(int c, char **argv, int invert, unsigned int *flags, - struct xt_policy_info *info, uint8_t family) +static void policy_parse(struct xt_option_call *cb) { + struct xt_policy_info *info = cb->data; struct xt_policy_elem *e = &info->pol[info->len]; - struct in_addr *addr = NULL, mask; - struct in6_addr *addr6 = NULL, mask6; - unsigned int naddr = 0, num; - int mode; - - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - switch (c) { - case '1': - if (info->flags & (XT_POLICY_MATCH_IN | XT_POLICY_MATCH_OUT)) - xtables_error(PARAMETER_PROBLEM, - "policy match: double --dir option"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "policy match: can't invert --dir option"); - info->flags |= parse_direction(optarg); + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_DIRECTION: + info->flags |= parse_direction(cb->arg); break; - case '2': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "policy match: can't invert --policy option"); - - info->flags |= parse_policy(optarg); + case O_POLICY: + info->flags |= parse_policy(cb->arg); break; - case '3': - if (info->flags & XT_POLICY_MATCH_STRICT) - xtables_error(PARAMETER_PROBLEM, - "policy match: double --strict option"); - - if (invert) - xtables_error(PARAMETER_PROBLEM, - "policy match: can't invert --strict option"); - + case O_STRICT: info->flags |= XT_POLICY_MATCH_STRICT; break; - case '4': + case O_REQID: if (e->match.reqid) xtables_error(PARAMETER_PROBLEM, "policy match: double --reqid option"); - e->match.reqid = 1; - e->invert.reqid = invert; - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg); - e->reqid = num; + e->invert.reqid = cb->invert; + e->reqid = cb->val.u32; break; - case '5': + case O_SPI: if (e->match.spi) xtables_error(PARAMETER_PROBLEM, "policy match: double --spi option"); - e->match.spi = 1; - e->invert.spi = invert; - if (!xtables_strtoui(optarg, NULL, &num, 0, UINT32_MAX)) - xtables_param_act(XTF_BAD_VALUE, "policy", "--spi", optarg); - e->spi = num; + e->invert.spi = cb->invert; + e->spi = cb->val.u32; break; - case '6': + case O_TUNNELSRC: if (e->match.saddr) xtables_error(PARAMETER_PROBLEM, "policy match: double --tunnel-src option"); - if (family == NFPROTO_IPV6) - xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr); - else - xtables_ipparse_any(optarg, &addr, &mask, &naddr); - if (naddr > 1) - xtables_error(PARAMETER_PROBLEM, - "policy match: name resolves to multiple IPs"); - e->match.saddr = 1; - e->invert.saddr = invert; - if (family == NFPROTO_IPV6) { - memcpy(&e->saddr.a6, addr6, sizeof(*addr6)); - memcpy(&e->smask.a6, &mask6, sizeof(mask6)); - } else { - e->saddr.a4 = addr[0]; - e->smask.a4 = mask; - } + e->invert.saddr = cb->invert; + memcpy(&e->saddr, &cb->val.haddr, sizeof(cb->val.haddr)); + memcpy(&e->smask, &cb->val.hmask, sizeof(cb->val.hmask)); break; - case '7': + case O_TUNNELDST: if (e->match.daddr) xtables_error(PARAMETER_PROBLEM, "policy match: double --tunnel-dst option"); - - if (family == NFPROTO_IPV6) - xtables_ip6parse_any(optarg, &addr6, &mask6, &naddr); - else - xtables_ipparse_any(optarg, &addr, &mask, &naddr); - if (naddr > 1) - xtables_error(PARAMETER_PROBLEM, - "policy match: name resolves to multiple IPs"); - e->match.daddr = 1; - e->invert.daddr = invert; - if (family == NFPROTO_IPV6) { - memcpy(&e->daddr.a6, addr6, sizeof(*addr6)); - memcpy(&e->dmask.a6, &mask6, sizeof(mask6)); - } else { - e->daddr.a4 = addr[0]; - e->dmask.a4 = mask; - } + e->invert.daddr = cb->invert; + memcpy(&e->daddr, &cb->val.haddr, sizeof(cb->val.haddr)); + memcpy(&e->dmask, &cb->val.hmask, sizeof(cb->val.hmask)); break; - case '8': + case O_PROTO: if (e->match.proto) xtables_error(PARAMETER_PROBLEM, "policy match: double --proto option"); - - e->proto = xtables_parse_protocol(optarg); + e->proto = cb->val.protocol; if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP && e->proto != IPPROTO_COMP) xtables_error(PARAMETER_PROBLEM, - "policy match: protocol must ah/esp/ipcomp"); + "policy match: protocol must be ah/esp/ipcomp"); e->match.proto = 1; - e->invert.proto = invert; + e->invert.proto = cb->invert; break; - case '9': + case O_MODE: if (e->match.mode) xtables_error(PARAMETER_PROBLEM, "policy match: double --mode option"); - - mode = parse_mode(optarg); e->match.mode = 1; - e->invert.mode = invert; - e->mode = mode; + e->invert.mode = cb->invert; + e->mode = parse_mode(cb->arg); break; - case 'a': - if (invert) - xtables_error(PARAMETER_PROBLEM, - "policy match: can't invert --next option"); - + case O_NEXT: if (++info->len == XT_POLICY_MAX_ELEM) xtables_error(PARAMETER_PROBLEM, "policy match: maximum policy depth reached"); break; - default: - return 0; } - - policy_info = info; - return 1; } -static int policy4_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void policy_check(struct xt_fcheck_call *cb) { - return policy_parse(c, argv, invert, flags, (void *)(*match)->data, - NFPROTO_IPV4); -} - -static int policy6_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - return policy_parse(c, argv, invert, flags, (void *)(*match)->data, - NFPROTO_IPV6); -} - -static void policy_check(unsigned int flags) -{ - struct xt_policy_info *info = policy_info; - struct xt_policy_elem *e; + struct xt_policy_info *info = cb->data; + const struct xt_policy_elem *e; int i; - if (info == NULL) - xtables_error(PARAMETER_PROBLEM, - "policy match: no parameters given"); - + /* + * The old "no parameters given" check is carried out + * by testing for --dir. + */ if (!(info->flags & (XT_POLICY_MATCH_IN | XT_POLICY_MATCH_OUT))) xtables_error(PARAMETER_PROBLEM, "policy match: neither --dir in nor --dir out specified"); @@ -305,9 +195,14 @@ static void policy_check(unsigned int flags) } else info->len++; /* increase len by 1, no --next after last element */ + /* + * This is already represented with O_NEXT requiring F_STRICT in the + * options table, but will keep this code as a comment for reference. + * if (!(info->flags & XT_POLICY_MATCH_STRICT) && info->len > 1) xtables_error(PARAMETER_PROBLEM, "policy match: multiple elements but no --strict"); + */ for (i = 0; i < info->len; i++) { e = &info->pol[i]; @@ -316,7 +211,10 @@ static void policy_check(unsigned int flags) !(e->match.reqid || e->match.spi || e->match.saddr || e->match.daddr || e->match.proto || e->match.mode)) xtables_error(PARAMETER_PROBLEM, - "policy match: empty policy element"); + "policy match: empty policy element %u. " + "--strict is in effect, but at least one of " + "reqid, spi, tunnel-src, tunnel-dst, proto or " + "mode is required.", i); if ((e->match.saddr || e->match.daddr) && ((e->mode == XT_POLICY_MODE_TUNNEL && e->invert.mode) || @@ -327,40 +225,40 @@ static void policy_check(unsigned int flags) } } -static void print_mode(const char *prefix, u_int8_t mode, int numeric) +static void print_mode(const char *prefix, uint8_t mode, int numeric) { - printf("%smode ", prefix); + printf(" %smode ", prefix); switch (mode) { case XT_POLICY_MODE_TRANSPORT: - printf("transport "); + printf("transport"); break; case XT_POLICY_MODE_TUNNEL: - printf("tunnel "); + printf("tunnel"); break; default: - printf("??? "); + printf("???"); break; } } -static void print_proto(const char *prefix, u_int8_t proto, int numeric) +static void print_proto(const char *prefix, uint8_t proto, int numeric) { - struct protoent *p = NULL; + const struct protoent *p = NULL; - printf("%sproto ", prefix); + printf(" %sproto ", prefix); if (!numeric) p = getprotobynumber(proto); if (p != NULL) - printf("%s ", p->p_name); + printf("%s", p->p_name); else - printf("%u ", proto); + printf("%u", proto); } #define PRINT_INVERT(x) \ do { \ if (x) \ - printf("! "); \ + printf(" !"); \ } while(0) static void print_entry(const char *prefix, const struct xt_policy_elem *e, @@ -368,11 +266,11 @@ static void print_entry(const char *prefix, const struct xt_policy_elem *e, { if (e->match.reqid) { PRINT_INVERT(e->invert.reqid); - printf("%sreqid %u ", prefix, e->reqid); + printf(" %sreqid %u", prefix, e->reqid); } if (e->match.spi) { PRINT_INVERT(e->invert.spi); - printf("%sspi 0x%x ", prefix, e->spi); + printf(" %sspi 0x%x", prefix, e->spi); } if (e->match.proto) { PRINT_INVERT(e->invert.proto); @@ -385,41 +283,41 @@ static void print_entry(const char *prefix, const struct xt_policy_elem *e, if (e->match.daddr) { PRINT_INVERT(e->invert.daddr); if (family == NFPROTO_IPV6) - printf("%stunnel-dst %s%s ", prefix, + printf(" %stunnel-dst %s%s", prefix, xtables_ip6addr_to_numeric(&e->daddr.a6), xtables_ip6mask_to_numeric(&e->dmask.a6)); else - printf("%stunnel-dst %s%s ", prefix, + printf(" %stunnel-dst %s%s", prefix, xtables_ipaddr_to_numeric(&e->daddr.a4), xtables_ipmask_to_numeric(&e->dmask.a4)); } if (e->match.saddr) { PRINT_INVERT(e->invert.saddr); if (family == NFPROTO_IPV6) - printf("%stunnel-src %s%s ", prefix, + printf(" %stunnel-src %s%s", prefix, xtables_ip6addr_to_numeric(&e->saddr.a6), xtables_ip6mask_to_numeric(&e->smask.a6)); else - printf("%stunnel-src %s%s ", prefix, + printf(" %stunnel-src %s%s", prefix, xtables_ipaddr_to_numeric(&e->saddr.a4), xtables_ipmask_to_numeric(&e->smask.a4)); } } -static void print_flags(char *prefix, const struct xt_policy_info *info) +static void print_flags(const char *prefix, const struct xt_policy_info *info) { if (info->flags & XT_POLICY_MATCH_IN) - printf("%sdir in ", prefix); + printf(" %sdir in", prefix); else - printf("%sdir out ", prefix); + printf(" %sdir out", prefix); if (info->flags & XT_POLICY_MATCH_NONE) - printf("%spol none ", prefix); + printf(" %spol none", prefix); else - printf("%spol ipsec ", prefix); + printf(" %spol ipsec", prefix); if (info->flags & XT_POLICY_MATCH_STRICT) - printf("%sstrict ", prefix); + printf(" %sstrict", prefix); } static void policy4_print(const void *ip, const struct xt_entry_match *match, @@ -428,11 +326,11 @@ static void policy4_print(const void *ip, const struct xt_entry_match *match, const struct xt_policy_info *info = (void *)match->data; unsigned int i; - printf("policy match "); + printf(" policy match"); print_flags("", info); for (i = 0; i < info->len; i++) { if (info->len > 1) - printf("[%u] ", i); + printf(" [%u]", i); print_entry("", &info->pol[i], numeric, NFPROTO_IPV4); } } @@ -443,11 +341,11 @@ static void policy6_print(const void *ip, const struct xt_entry_match *match, const struct xt_policy_info *info = (void *)match->data; unsigned int i; - printf("policy match "); + printf(" policy match"); print_flags("", info); for (i = 0; i < info->len; i++) { if (info->len > 1) - printf("[%u] ", i); + printf(" [%u]", i); print_entry("", &info->pol[i], numeric, NFPROTO_IPV6); } } @@ -461,7 +359,7 @@ static void policy4_save(const void *ip, const struct xt_entry_match *match) for (i = 0; i < info->len; i++) { print_entry("--", &info->pol[i], false, NFPROTO_IPV4); if (i + 1 < info->len) - printf("--next "); + printf(" --next"); } } @@ -474,7 +372,7 @@ static void policy6_save(const void *ip, const struct xt_entry_match *match) for (i = 0; i < info->len; i++) { print_entry("--", &info->pol[i], false, NFPROTO_IPV6); if (i + 1 < info->len) - printf("--next "); + printf(" --next"); } } @@ -486,11 +384,11 @@ static struct xtables_match policy_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_policy_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_policy_info)), .help = policy_help, - .parse = policy4_parse, - .final_check = policy_check, + .x6_parse = policy_parse, + .x6_fcheck = policy_check, .print = policy4_print, .save = policy4_save, - .extra_opts = policy_opts, + .x6_options = policy_opts, }, { .name = "policy", @@ -499,11 +397,11 @@ static struct xtables_match policy_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_policy_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_policy_info)), .help = policy_help, - .parse = policy6_parse, - .final_check = policy_check, + .x6_parse = policy_parse, + .x6_fcheck = policy_check, .print = policy6_print, .save = policy6_save, - .extra_opts = policy_opts, + .x6_options = policy_opts, }, }; diff --git a/extensions/libxt_policy.man b/extensions/libxt_policy.man index 3500025..1b834fa 100644 --- a/extensions/libxt_policy.man +++ b/extensions/libxt_policy.man @@ -13,11 +13,16 @@ is valid in the chains. .TP \fB\-\-pol\fP {\fBnone\fP|\fBipsec\fP} -Matches if the packet is subject to IPsec processing. +Matches if the packet is subject to IPsec processing. \fB\-\-pol none\fP +cannot be combined with \fB\-\-strict\fP. .TP \fB\-\-strict\fP Selects whether to match the exact policy or match if any rule of the policy matches the given policy. +.PP +For each policy element that is to be described, one can use one or more of +the following options. When \fB\-\-strict\fP is in effect, at least one must be +used per element. .TP [\fB!\fP] \fB\-\-reqid\fP \fIid\fP Matches the reqid of the policy rule. The reqid can be specified with diff --git a/extensions/libxt_quota.c b/extensions/libxt_quota.c index ac7c686..ff498da 100644 --- a/extensions/libxt_quota.c +++ b/extensions/libxt_quota.c @@ -3,17 +3,19 @@ * * Sam Johnston <samj@samj.net> */ -#include <stddef.h> #include <stdio.h> -#include <stdlib.h> -#include <getopt.h> #include <xtables.h> - #include <linux/netfilter/xt_quota.h> -static const struct option quota_opts[] = { - {"quota", 1, NULL, '1'}, - { .name = NULL } +enum { + O_QUOTA = 0, +}; + +static const struct xt_option_entry quota_opts[] = { + {.name = "quota", .id = O_QUOTA, .type = XTTYPE_UINT64, + .flags = XTOPT_MAND | XTOPT_INVERT | XTOPT_PUT, + XTOPT_POINTER(struct xt_quota_info, quota)}, + XTOPT_TABLEEND, }; static void quota_help(void) @@ -26,55 +28,26 @@ static void quota_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_quota_info *q = (const void *)match->data; - printf("quota: %llu bytes", (unsigned long long) q->quota); + printf(" quota: %llu bytes", (unsigned long long)q->quota); } static void quota_save(const void *ip, const struct xt_entry_match *match) { const struct xt_quota_info *q = (const void *)match->data; - printf("--quota %llu ", (unsigned long long) q->quota); -} - -/* parse quota option */ -static int -parse_quota(const char *s, u_int64_t * quota) -{ - *quota = strtoull(s, NULL, 10); - -#ifdef DEBUG_XT_QUOTA - printf("Quota: %llu\n", *quota); -#endif - if (*quota == UINT64_MAX) - xtables_error(PARAMETER_PROBLEM, "quota invalid: '%s'\n", s); - else - return 1; + if (q->flags & XT_QUOTA_INVERT) + printf("! "); + printf(" --quota %llu", (unsigned long long) q->quota); } -static int -quota_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void quota_parse(struct xt_option_call *cb) { - struct xt_quota_info *info = (struct xt_quota_info *) (*match)->data; - - switch (c) { - case '1': - if (xtables_check_inverse(optarg, &invert, NULL, 0, argv)) - xtables_error(PARAMETER_PROBLEM, "quota: unexpected '!'"); - if (!parse_quota(optarg, &info->quota)) - xtables_error(PARAMETER_PROBLEM, - "bad quota: '%s'", optarg); - - if (invert) - info->flags |= XT_QUOTA_INVERT; - - break; + struct xt_quota_info *info = cb->data; - default: - return 0; - } - return 1; + xtables_option_parse(cb); + if (cb->invert) + info->flags |= XT_QUOTA_INVERT; } static struct xtables_match quota_match = { @@ -82,12 +55,12 @@ static struct xtables_match quota_match = { .name = "quota", .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof (struct xt_quota_info)), - .userspacesize = offsetof(struct xt_quota_info, quota), + .userspacesize = offsetof(struct xt_quota_info, master), .help = quota_help, - .parse = quota_parse, .print = quota_print, .save = quota_save, - .extra_opts = quota_opts, + .x6_parse = quota_parse, + .x6_options = quota_opts, }; void diff --git a/extensions/libxt_quota.man b/extensions/libxt_quota.man index 8d9e18b..fbecf37 100644 --- a/extensions/libxt_quota.man +++ b/extensions/libxt_quota.man @@ -1,5 +1,7 @@ Implements network quotas by decrementing a byte counter with each -packet. +packet. The condition matches until the byte counter reaches zero. Behavior +is reversed with negation (i.e. the condition does not match until the +byte counter reaches zero). .TP [\fB!\fP] \fB\-\-quota\fP \fIbytes\fP The quota in bytes. diff --git a/extensions/libxt_rateest.c b/extensions/libxt_rateest.c index ad0884e..fb24412 100644 --- a/extensions/libxt_rateest.c +++ b/extensions/libxt_rateest.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2008-2013 Patrick McHardy <kaber@trash.net> + */ + +#include <stdbool.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -7,9 +12,6 @@ #include <xtables.h> #include <linux/netfilter/xt_rateest.h> -/* Ugly hack to pass info to final_check function. We should fix the API */ -static struct xt_rateest_match_info *rateest_info; - static void rateest_help(void) { printf( @@ -40,20 +42,20 @@ enum rateest_options { }; static const struct option rateest_opts[] = { - { "rateest1", 1, NULL, OPT_RATEEST1 }, - { "rateest", 1, NULL, OPT_RATEEST1 }, /* alias for absolute mode */ - { "rateest2", 1, NULL, OPT_RATEEST2 }, - { "rateest-bps1", 0, NULL, OPT_RATEEST_BPS1 }, - { "rateest-pps1", 0, NULL, OPT_RATEEST_PPS1 }, - { "rateest-bps2", 0, NULL, OPT_RATEEST_BPS2 }, - { "rateest-pps2", 0, NULL, OPT_RATEEST_PPS2 }, - { "rateest-bps", 0, NULL, OPT_RATEEST_BPS2 }, /* alias for absolute mode */ - { "rateest-pps", 0, NULL, OPT_RATEEST_PPS2 }, /* alias for absolute mode */ - { "rateest-delta", 0, NULL, OPT_RATEEST_DELTA }, - { "rateest-lt", 0, NULL, OPT_RATEEST_LT }, - { "rateest-gt", 0, NULL, OPT_RATEEST_GT }, - { "rateest-eq", 0, NULL, OPT_RATEEST_EQ }, - { .name = NULL } + {.name = "rateest1", .has_arg = true, .val = OPT_RATEEST1}, + {.name = "rateest", .has_arg = true, .val = OPT_RATEEST1}, /* alias for absolute mode */ + {.name = "rateest2", .has_arg = true, .val = OPT_RATEEST2}, + {.name = "rateest-bps1", .has_arg = false, .val = OPT_RATEEST_BPS1}, + {.name = "rateest-pps1", .has_arg = false, .val = OPT_RATEEST_PPS1}, + {.name = "rateest-bps2", .has_arg = false, .val = OPT_RATEEST_BPS2}, + {.name = "rateest-pps2", .has_arg = false, .val = OPT_RATEEST_PPS2}, + {.name = "rateest-bps", .has_arg = false, .val = OPT_RATEEST_BPS2}, /* alias for absolute mode */ + {.name = "rateest-pps", .has_arg = false, .val = OPT_RATEEST_PPS2}, /* alias for absolute mode */ + {.name = "rateest-delta", .has_arg = false, .val = OPT_RATEEST_DELTA}, + {.name = "rateest-lt", .has_arg = false, .val = OPT_RATEEST_LT}, + {.name = "rateest-gt", .has_arg = false, .val = OPT_RATEEST_GT}, + {.name = "rateest-eq", .has_arg = false, .val = OPT_RATEEST_EQ}, + XT_GETOPT_TABLEEND, }; /* Copied from iproute. See http://physics.nist.gov/cuu/Units/binary.html */ @@ -64,11 +66,11 @@ static const struct rate_suffix { { "bit", 1. }, { "Kibit", 1024. }, { "kbit", 1000. }, - { "mibit", 1024.*1024. }, + { "Mibit", 1024.*1024. }, { "mbit", 1000000. }, - { "gibit", 1024.*1024.*1024. }, + { "Gibit", 1024.*1024.*1024. }, { "gbit", 1000000000. }, - { "tibit", 1024.*1024.*1024.*1024. }, + { "Tibit", 1024.*1024.*1024.*1024. }, { "tbit", 1000000000000. }, { "Bps", 8. }, { "KiBps", 8.*1024. }, @@ -79,11 +81,11 @@ static const struct rate_suffix { { "GBps", 8000000000. }, { "TiBps", 8.*1024.*1024.*1024.*1024. }, { "TBps", 8000000000000. }, - { .name = NULL } + {NULL}, }; static int -rateest_get_rate(u_int32_t *rate, const char *str) +rateest_get_rate(uint32_t *rate, const char *str) { char *p; double bps = strtod(str, &p); @@ -114,11 +116,8 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, struct xt_rateest_match_info *info = (void *)(*match)->data; unsigned int val; - rateest_info = info; - switch (c) { case OPT_RATEEST1: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) xtables_error(PARAMETER_PROBLEM, "rateest: rateest can't be inverted"); @@ -132,7 +131,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST2: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) xtables_error(PARAMETER_PROBLEM, "rateest: rateest can't be inverted"); @@ -147,7 +145,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_BPS1: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) xtables_error(PARAMETER_PROBLEM, "rateest: rateest-bps can't be inverted"); @@ -171,7 +168,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_PPS1: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) xtables_error(PARAMETER_PROBLEM, "rateest: rateest-pps can't be inverted"); @@ -196,7 +192,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_BPS2: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) xtables_error(PARAMETER_PROBLEM, "rateest: rateest-bps can't be inverted"); @@ -220,7 +215,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_PPS2: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) xtables_error(PARAMETER_PROBLEM, "rateest: rateest-pps can't be inverted"); @@ -245,7 +239,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_DELTA: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) xtables_error(PARAMETER_PROBLEM, "rateest: rateest-delta can't be inverted"); @@ -259,8 +252,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_EQ: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (*flags & (1 << c)) xtables_error(PARAMETER_PROBLEM, "rateest: can't specify lt/gt/eq twice"); @@ -272,8 +263,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_LT: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (*flags & (1 << c)) xtables_error(PARAMETER_PROBLEM, "rateest: can't specify lt/gt/eq twice"); @@ -285,8 +274,6 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, break; case OPT_RATEEST_GT: - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (*flags & (1 << c)) xtables_error(PARAMETER_PROBLEM, "rateest: can't specify lt/gt/eq twice"); @@ -296,18 +283,14 @@ rateest_parse(int c, char **argv, int invert, unsigned int *flags, if (invert) info->flags |= XT_RATEEST_MATCH_INVERT; break; - - default: - return 0; } return 1; } -static void -rateest_final_check(unsigned int flags) +static void rateest_final_check(struct xt_fcheck_call *cb) { - struct xt_rateest_match_info *info = rateest_info; + struct xt_rateest_match_info *info = cb->data; if (info == NULL) xtables_error(PARAMETER_PROBLEM, "rateest match: " @@ -317,18 +300,18 @@ rateest_final_check(unsigned int flags) } static void -rateest_print_rate(u_int32_t rate, int numeric) +rateest_print_rate(uint32_t rate, int numeric) { double tmp = (double)rate*8; if (numeric) - printf("%u ", rate); + printf(" %u", rate); else if (tmp >= 1000.0*1000000.0) - printf("%.0fMbit ", tmp/1000000.0); + printf(" %.0fMbit", tmp/1000000.0); else if (tmp >= 1000.0 * 1000.0) - printf("%.0fKbit ", tmp/1000.0); + printf(" %.0fKbit", tmp/1000.0); else - printf("%.0fbit ", tmp); + printf(" %.0fbit", tmp); } static void @@ -336,17 +319,17 @@ rateest_print_mode(const struct xt_rateest_match_info *info, const char *prefix) { if (info->flags & XT_RATEEST_MATCH_INVERT) - printf("! "); + printf(" !"); switch (info->mode) { case XT_RATEEST_MATCH_EQ: - printf("%seq ", prefix); + printf(" %seq", prefix); break; case XT_RATEEST_MATCH_LT: - printf("%slt ", prefix); + printf(" %slt", prefix); break; case XT_RATEEST_MATCH_GT: - printf("%sgt ", prefix); + printf(" %sgt", prefix); break; default: exit(1); @@ -358,78 +341,91 @@ rateest_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_rateest_match_info *info = (const void *)match->data; - printf("rateest match "); + printf(" rateest match "); - printf("%s ", info->name1); + printf("%s", info->name1); if (info->flags & XT_RATEEST_MATCH_DELTA) - printf("delta "); + printf(" delta"); if (info->flags & XT_RATEEST_MATCH_BPS) { - printf("bps "); + printf(" bps"); if (info->flags & XT_RATEEST_MATCH_DELTA) rateest_print_rate(info->bps1, numeric); if (info->flags & XT_RATEEST_MATCH_ABS) { - rateest_print_mode(info, ""); rateest_print_rate(info->bps2, numeric); + rateest_print_mode(info, ""); } } if (info->flags & XT_RATEEST_MATCH_PPS) { - printf("pps "); + printf(" pps"); if (info->flags & XT_RATEEST_MATCH_DELTA) - printf("%u ", info->pps1); + printf(" %u", info->pps1); if (info->flags & XT_RATEEST_MATCH_ABS) { rateest_print_mode(info, ""); - printf("%u ", info->pps2); + printf(" %u", info->pps2); } } if (info->flags & XT_RATEEST_MATCH_REL) { rateest_print_mode(info, ""); - printf("%s ", info->name2); - if (info->flags & XT_RATEEST_MATCH_DELTA) - printf("delta "); + printf(" %s", info->name2); if (info->flags & XT_RATEEST_MATCH_BPS) { - printf("bps "); + printf(" bps"); if (info->flags & XT_RATEEST_MATCH_DELTA) rateest_print_rate(info->bps2, numeric); } if (info->flags & XT_RATEEST_MATCH_PPS) { - printf("pps "); + printf(" pps"); if (info->flags & XT_RATEEST_MATCH_DELTA) - printf("%u ", info->pps2); + printf(" %u", info->pps2); } } } +static void __rateest_save_rate(const struct xt_rateest_match_info *info, + const char *name, uint32_t r1, uint32_t r2, + int numeric) +{ + if (info->flags & XT_RATEEST_MATCH_DELTA) { + printf(" --rateest-%s1", name); + rateest_print_rate(r1, numeric); + rateest_print_mode(info, "--rateest-"); + printf(" --rateest-%s2", name); + } else { + rateest_print_mode(info, "--rateest-"); + printf(" --rateest-%s", name); + } + + if (info->flags & (XT_RATEEST_MATCH_ABS|XT_RATEEST_MATCH_DELTA)) + rateest_print_rate(r2, numeric); +} + +static void rateest_save_rates(const struct xt_rateest_match_info *info) +{ + if (info->flags & XT_RATEEST_MATCH_BPS) + __rateest_save_rate(info, "bps", info->bps1, info->bps2, 0); + if (info->flags & XT_RATEEST_MATCH_PPS) + __rateest_save_rate(info, "pps", info->pps1, info->pps2, 1); +} + + static void rateest_save(const void *ip, const struct xt_entry_match *match) { const struct xt_rateest_match_info *info = (const void *)match->data; + if (info->flags & XT_RATEEST_MATCH_DELTA) + printf(" --rateest-delta"); + if (info->flags & XT_RATEEST_MATCH_REL) { - printf("--rateest1 %s ", info->name1); - if (info->flags & XT_RATEEST_MATCH_BPS) - printf("--rateest-bps "); - if (info->flags & XT_RATEEST_MATCH_PPS) - printf("--rateest-pps "); - rateest_print_mode(info, "--rateest-"); - printf("--rateest2 %s ", info->name2); - } else { - printf("--rateest %s ", info->name1); - if (info->flags & XT_RATEEST_MATCH_BPS) { - printf("--rateest-bps1 "); - rateest_print_rate(info->bps1, 0); - printf("--rateest-bps2 "); - rateest_print_rate(info->bps2, 0); - rateest_print_mode(info, "--rateest-"); - } - if (info->flags & XT_RATEEST_MATCH_PPS) { - printf("--rateest-pps "); - rateest_print_mode(info, "--rateest-"); - printf("%u ", info->pps2); - } + printf(" --rateest1 %s", info->name1); + rateest_save_rates(info); + printf(" --rateest2 %s", info->name2); + } else { /* XT_RATEEST_MATCH_ABS */ + printf(" --rateest %s", info->name1); + rateest_save_rates(info); } } @@ -441,7 +437,7 @@ static struct xtables_match rateest_mt_reg = { .userspacesize = XT_ALIGN(offsetof(struct xt_rateest_match_info, est1)), .help = rateest_help, .parse = rateest_parse, - .final_check = rateest_final_check, + .x6_fcheck = rateest_final_check, .print = rateest_print, .save = rateest_save, .extra_opts = rateest_opts, diff --git a/extensions/libxt_rateest.man b/extensions/libxt_rateest.man index de064af..42a82f3 100644 --- a/extensions/libxt_rateest.man +++ b/extensions/libxt_rateest.man @@ -1,25 +1,38 @@ The rate estimator can match on estimated rates as collected by the RATEEST target. It supports matching on absolute bps/pps values, comparing two rate estimators and matching on the difference between two rate estimators. -.TP -\fB\-\-rateest1\fP \fIname\fP -Name of the first rate estimator. -.TP -\fB\-\-rateest2\fP \fIname\fP -Name of the second rate estimator (if difference is to be calculated). +.PP +For a better understanding of the available options, these are all possible +combinations: +.\" * Absolute: +.IP \(bu 4 +\fBrateest\fP \fIoperator\fP \fBrateest-bps\fP +.IP \(bu 4 +\fBrateest\fP \fIoperator\fP \fBrateest-pps\fP +.\" * Absolute + Delta: +.IP \(bu 4 +(\fBrateest\fP minus \fBrateest-bps1\fP) \fIoperator\fP \fBrateest-bps2\fP +.IP \(bu 4 +(\fBrateest\fP minus \fBrateest-pps1\fP) \fIoperator\fP \fBrateest-pps2\fP +.\" * Relative: +.IP \(bu 4 +\fBrateest1\fP \fIoperator\fP \fBrateest2\fP \fBrateest-bps\fP(without rate!) +.IP \(bu 4 +\fBrateest1\fP \fIoperator\fP \fBrateest2\fP \fBrateest-pps\fP(without rate!) +.\" * Relative + Delta: +.IP \(bu 4 +(\fBrateest1\fP minus \fBrateest-bps1\fP) \fIoperator\fP +(\fBrateest2\fP minus \fBrateest-bps2\fP) +.IP \(bu 4 +(\fBrateest1\fP minus \fBrateest-pps1\fP) \fIoperator\fP +(\fBrateest2\fP minus \fBrateest-pps2\fP) .TP \fB\-\-rateest\-delta\fP -Compare difference(s) to given rate(s) -.TP -\fB\-\-rateest\-bps1\fP \fIvalue\fP -.TP -\fB\-\-rateest\-bps2\fP \fIvalue\fP -Compare bytes per second. -.TP -\fB\-\-rateest\-pps1\fP \fIvalue\fP -.TP -\fB\-\-rateest\-pps2\fP \fIvalue\fP -Compare packets per second. +For each estimator (either absolute or relative mode), calculate the difference +between the estimator-determined flow rate and the static value chosen with the +BPS/PPS options. If the flow rate is higher than the specified BPS/PPS, 0 will +be used instead of a negative value. In other words, "max(0, rateest#_rate - +rateest#_bps)" is used. .TP [\fB!\fP] \fB\-\-rateest\-lt\fP Match if rate is less than given rate/estimator. @@ -30,6 +43,34 @@ Match if rate is greater than given rate/estimator. [\fB!\fP] \fB\-\-rateest\-eq\fP Match if rate is equal to given rate/estimator. .PP +In the so-called "absolute mode", only one rate estimator is used and compared +against a static value, while in "relative mode", two rate estimators are +compared against another. +.TP +\fB\-\-rateest\fP \fIname\fP +Name of the one rate estimator for absolute mode. +.TP +\fB\-\-rateest1\fP \fIname\fP +.TP +\fB\-\-rateest2\fP \fIname\fP +The names of the two rate estimators for relative mode. +.TP +\fB\-\-rateest\-bps\fP [\fIvalue\fP] +.TP +\fB\-\-rateest\-pps\fP [\fIvalue\fP] +.TP +\fB\-\-rateest\-bps1\fP [\fIvalue\fP] +.TP +\fB\-\-rateest\-bps2\fP [\fIvalue\fP] +.TP +\fB\-\-rateest\-pps1\fP [\fIvalue\fP] +.TP +\fB\-\-rateest\-pps2\fP [\fIvalue\fP] +Compare the estimator(s) by bytes or packets per second, and compare against +the chosen value. See the above bullet list for which option is to be used in +which case. A unit suffix may be used - available ones are: bit, [kmgt]bit, +[KMGT]ibit, Bps, [KMGT]Bps, [KMGT]iBps. +.PP Example: This is what can be used to route outgoing data connections from an FTP server over two lines based on the available bandwidth at the time the data connection was started: diff --git a/extensions/libxt_recent.c b/extensions/libxt_recent.c index ecc17ad..e1801f1 100644 --- a/extensions/libxt_recent.c +++ b/extensions/libxt_recent.c @@ -1,26 +1,83 @@ -/* Shared library add-on to iptables to add recent matching support. */ +#include <stdbool.h> #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_recent.h> -static const struct option recent_opts[] = { - { .name = "set", .has_arg = 0, .val = 201 }, - { .name = "rcheck", .has_arg = 0, .val = 202 }, - { .name = "update", .has_arg = 0, .val = 203 }, - { .name = "seconds", .has_arg = 1, .val = 204 }, - { .name = "hitcount", .has_arg = 1, .val = 205 }, - { .name = "remove", .has_arg = 0, .val = 206 }, - { .name = "rttl", .has_arg = 0, .val = 207 }, - { .name = "name", .has_arg = 1, .val = 208 }, - { .name = "rsource", .has_arg = 0, .val = 209 }, - { .name = "rdest", .has_arg = 0, .val = 210 }, - { .name = NULL } +enum { + O_SET = 0, + O_RCHECK, + O_UPDATE, + O_REMOVE, + O_SECONDS, + O_REAP, + O_HITCOUNT, + O_RTTL, + O_NAME, + O_RSOURCE, + O_RDEST, + O_MASK, + F_SET = 1 << O_SET, + F_RCHECK = 1 << O_RCHECK, + F_UPDATE = 1 << O_UPDATE, + F_REMOVE = 1 << O_REMOVE, + F_SECONDS = 1 << O_SECONDS, + F_ANY_OP = F_SET | F_RCHECK | F_UPDATE | F_REMOVE, +}; + +#define s struct xt_recent_mtinfo +static const struct xt_option_entry recent_opts_v0[] = { + {.name = "set", .id = O_SET, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1}, + {.name = "reap", .id = O_REAP, .type = XTTYPE_NONE, + .also = F_SECONDS }, + {.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)}, + {.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE, + .excl = F_SET | F_REMOVE}, + {.name = "name", .id = O_NAME, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, name)}, + {.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE}, + {.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s + +#define s struct xt_recent_mtinfo_v1 +static const struct xt_option_entry recent_opts_v1[] = { + {.name = "set", .id = O_SET, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "rcheck", .id = O_RCHECK, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "update", .id = O_UPDATE, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "remove", .id = O_REMOVE, .type = XTTYPE_NONE, + .excl = F_ANY_OP, .flags = XTOPT_INVERT}, + {.name = "seconds", .id = O_SECONDS, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, seconds), .min = 1}, + {.name = "reap", .id = O_REAP, .type = XTTYPE_NONE, + .also = F_SECONDS }, + {.name = "hitcount", .id = O_HITCOUNT, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, hit_count)}, + {.name = "rttl", .id = O_RTTL, .type = XTTYPE_NONE, + .excl = F_SET | F_REMOVE}, + {.name = "name", .id = O_NAME, .type = XTTYPE_STRING, + .flags = XTOPT_PUT, XTOPT_POINTER(s, name)}, + {.name = "rsource", .id = O_RSOURCE, .type = XTTYPE_NONE}, + {.name = "rdest", .id = O_RDEST, .type = XTTYPE_NONE}, + {.name = "mask", .id = O_MASK, .type = XTTYPE_HOST, + .flags = XTOPT_PUT, XTOPT_POINTER(s, mask)}, + XTOPT_TABLEEND, +}; +#undef s static void recent_help(void) { @@ -33,6 +90,8 @@ static void recent_help(void) " --seconds seconds For check and update commands above.\n" " Specifies that the match will only occur if source address last seen within\n" " the last 'seconds' seconds.\n" +" --reap Purge entries older then 'seconds'.\n" +" Can only be used in conjunction with the seconds option.\n" " --hitcount hits For check and update commands above.\n" " Specifies that the match will only occur if source address seen hits times.\n" " May be used in conjunction with the seconds option.\n" @@ -44,190 +103,253 @@ static void recent_help(void) " --name name Name of the recent list to be used. DEFAULT used if none given.\n" " --rsource Match/Save the source address of each packet in the recent list table (default).\n" " --rdest Match/Save the destination address of each packet in the recent list table.\n" -"xt_recent by: Stephen Frost <sfrost@snowman.net>. http://snowman.net/projects/ipt_recent/\n"); +" --mask netmask Netmask that will be applied to this recent list.\n" +"xt_recent by: Stephen Frost <sfrost@snowman.net>.\n"); } -static void recent_init(struct xt_entry_match *match) +enum { + XT_RECENT_REV_0 = 0, + XT_RECENT_REV_1, +}; + +static void recent_init(struct xt_entry_match *match, unsigned int rev) { - struct xt_recent_mtinfo *info = (void *)(match)->data; + struct xt_recent_mtinfo *info = (struct xt_recent_mtinfo *)match->data; + struct xt_recent_mtinfo_v1 *info_v1 = + (struct xt_recent_mtinfo_v1 *)match->data; strncpy(info->name,"DEFAULT", XT_RECENT_NAME_LEN); /* even though XT_RECENT_NAME_LEN is currently defined as 200, * better be safe, than sorry */ info->name[XT_RECENT_NAME_LEN-1] = '\0'; info->side = XT_RECENT_SOURCE; + if (rev == XT_RECENT_REV_1) + memset(&info_v1->mask, 0xFF, sizeof(info_v1->mask)); } -#define RECENT_CMDS \ - (XT_RECENT_SET | XT_RECENT_CHECK | \ - XT_RECENT_UPDATE | XT_RECENT_REMOVE) - -static int recent_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void recent_parse(struct xt_option_call *cb) { - struct xt_recent_mtinfo *info = (void *)(*match)->data; - - switch (c) { - case 201: - if (*flags & RECENT_CMDS) - xtables_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--rcheck' " - "`--update' or `--remove' may be set"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - info->check_set |= XT_RECENT_SET; - if (invert) info->invert = 1; - *flags |= XT_RECENT_SET; - break; - - case 202: - if (*flags & RECENT_CMDS) - xtables_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--rcheck' " - "`--update' or `--remove' may be set"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - info->check_set |= XT_RECENT_CHECK; - if(invert) info->invert = 1; - *flags |= XT_RECENT_CHECK; - break; - - case 203: - if (*flags & RECENT_CMDS) - xtables_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--rcheck' " - "`--update' or `--remove' may be set"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - info->check_set |= XT_RECENT_UPDATE; - if (invert) info->invert = 1; - *flags |= XT_RECENT_UPDATE; - break; - - case 204: - info->seconds = atoi(optarg); - break; - - case 205: - info->hit_count = atoi(optarg); - break; - - case 206: - if (*flags & RECENT_CMDS) - xtables_error(PARAMETER_PROBLEM, - "recent: only one of `--set', `--rcheck' " - "`--update' or `--remove' may be set"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - info->check_set |= XT_RECENT_REMOVE; - if (invert) info->invert = 1; - *flags |= XT_RECENT_REMOVE; - break; - - case 207: - info->check_set |= XT_RECENT_TTL; - *flags |= XT_RECENT_TTL; - break; - - case 208: - strncpy(info->name,optarg, XT_RECENT_NAME_LEN); - info->name[XT_RECENT_NAME_LEN-1] = '\0'; - break; - - case 209: - info->side = XT_RECENT_SOURCE; - break; - - case 210: - info->side = XT_RECENT_DEST; - break; - - default: - return 0; - } + struct xt_recent_mtinfo *info = cb->data; - return 1; + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SET: + info->check_set |= XT_RECENT_SET; + if (cb->invert) + info->invert = true; + break; + case O_RCHECK: + info->check_set |= XT_RECENT_CHECK; + if (cb->invert) + info->invert = true; + break; + case O_UPDATE: + info->check_set |= XT_RECENT_UPDATE; + if (cb->invert) + info->invert = true; + break; + case O_REMOVE: + info->check_set |= XT_RECENT_REMOVE; + if (cb->invert) + info->invert = true; + break; + case O_RTTL: + info->check_set |= XT_RECENT_TTL; + break; + case O_RSOURCE: + info->side = XT_RECENT_SOURCE; + break; + case O_RDEST: + info->side = XT_RECENT_DEST; + break; + case O_REAP: + info->check_set |= XT_RECENT_REAP; + break; + } } -static void recent_check(unsigned int flags) +static void recent_check(struct xt_fcheck_call *cb) { - if (!(flags & RECENT_CMDS)) + if (!(cb->xflags & F_ANY_OP)) xtables_error(PARAMETER_PROBLEM, "recent: you must specify one of `--set', `--rcheck' " "`--update' or `--remove'"); - if ((flags & XT_RECENT_TTL) && - (flags & (XT_RECENT_SET | XT_RECENT_REMOVE))) - xtables_error(PARAMETER_PROBLEM, - "recent: --rttl may only be used with --rcheck or " - "--update"); } static void recent_print(const void *ip, const struct xt_entry_match *match, - int numeric) + unsigned int family) { - const struct xt_recent_mtinfo *info = (const void *)match->data; + const struct xt_recent_mtinfo_v1 *info = (const void *)match->data; if (info->invert) - fputc('!', stdout); + printf(" !"); - printf("recent: "); + printf(" recent:"); if (info->check_set & XT_RECENT_SET) - printf("SET "); + printf(" SET"); if (info->check_set & XT_RECENT_CHECK) - printf("CHECK "); + printf(" CHECK"); if (info->check_set & XT_RECENT_UPDATE) - printf("UPDATE "); + printf(" UPDATE"); if (info->check_set & XT_RECENT_REMOVE) - printf("REMOVE "); - if(info->seconds) printf("seconds: %d ",info->seconds); - if(info->hit_count) printf("hit_count: %d ",info->hit_count); + printf(" REMOVE"); + if(info->seconds) printf(" seconds: %d", info->seconds); + if (info->check_set & XT_RECENT_REAP) + printf(" reap"); + if(info->hit_count) printf(" hit_count: %d", info->hit_count); if (info->check_set & XT_RECENT_TTL) - printf("TTL-Match "); - if(info->name) printf("name: %s ",info->name); + printf(" TTL-Match"); + if(info->name) printf(" name: %s", info->name); if (info->side == XT_RECENT_SOURCE) - printf("side: source "); + printf(" side: source"); if (info->side == XT_RECENT_DEST) - printf("side: dest "); + printf(" side: dest"); + + switch(family) { + case NFPROTO_IPV4: + printf(" mask: %s", + xtables_ipaddr_to_numeric(&info->mask.in)); + break; + case NFPROTO_IPV6: + printf(" mask: %s", + xtables_ip6addr_to_numeric(&info->mask.in6)); + break; + } } -static void recent_save(const void *ip, const struct xt_entry_match *match) +static void recent_save(const void *ip, const struct xt_entry_match *match, + unsigned int family) { - const struct xt_recent_mtinfo *info = (const void *)match->data; + const struct xt_recent_mtinfo_v1 *info = (const void *)match->data; if (info->invert) - printf("! "); + printf(" !"); if (info->check_set & XT_RECENT_SET) - printf("--set "); + printf(" --set"); if (info->check_set & XT_RECENT_CHECK) - printf("--rcheck "); + printf(" --rcheck"); if (info->check_set & XT_RECENT_UPDATE) - printf("--update "); + printf(" --update"); if (info->check_set & XT_RECENT_REMOVE) - printf("--remove "); - if(info->seconds) printf("--seconds %d ",info->seconds); - if(info->hit_count) printf("--hitcount %d ",info->hit_count); + printf(" --remove"); + if(info->seconds) printf(" --seconds %d", info->seconds); + if (info->check_set & XT_RECENT_REAP) + printf(" --reap"); + if(info->hit_count) printf(" --hitcount %d", info->hit_count); if (info->check_set & XT_RECENT_TTL) - printf("--rttl "); - if(info->name) printf("--name %s ",info->name); + printf(" --rttl"); + if(info->name) printf(" --name %s",info->name); + + switch(family) { + case NFPROTO_IPV4: + printf(" --mask %s", + xtables_ipaddr_to_numeric(&info->mask.in)); + break; + case NFPROTO_IPV6: + printf(" --mask %s", + xtables_ip6addr_to_numeric(&info->mask.in6)); + break; + } + if (info->side == XT_RECENT_SOURCE) - printf("--rsource "); + printf(" --rsource"); if (info->side == XT_RECENT_DEST) - printf("--rdest "); + printf(" --rdest"); +} + +static void recent_init_v0(struct xt_entry_match *match) +{ + recent_init(match, XT_RECENT_REV_0); +} + +static void recent_init_v1(struct xt_entry_match *match) +{ + recent_init(match, XT_RECENT_REV_1); +} + +static void recent_save_v0(const void *ip, const struct xt_entry_match *match) +{ + recent_save(ip, match, NFPROTO_UNSPEC); +} + +static void recent_save_v4(const void *ip, const struct xt_entry_match *match) +{ + recent_save(ip, match, NFPROTO_IPV4); +} + +static void recent_save_v6(const void *ip, const struct xt_entry_match *match) +{ + recent_save(ip, match, NFPROTO_IPV6); +} + +static void recent_print_v0(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + recent_print(ip, match, NFPROTO_UNSPEC); +} + +static void recent_print_v4(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + recent_print(ip, match, NFPROTO_IPV4); +} + +static void recent_print_v6(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + recent_print(ip, match, NFPROTO_IPV6); } -static struct xtables_match recent_mt_reg = { - .name = "recent", - .version = XTABLES_VERSION, - .family = NFPROTO_UNSPEC, - .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)), - .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)), - .help = recent_help, - .init = recent_init, - .parse = recent_parse, - .final_check = recent_check, - .print = recent_print, - .save = recent_save, - .extra_opts = recent_opts, +static struct xtables_match recent_mt_reg[] = { + { + .name = "recent", + .version = XTABLES_VERSION, + .revision = 0, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo)), + .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo)), + .help = recent_help, + .init = recent_init_v0, + .x6_parse = recent_parse, + .x6_fcheck = recent_check, + .print = recent_print_v0, + .save = recent_save_v0, + .x6_options = recent_opts_v0, + }, + { + .name = "recent", + .version = XTABLES_VERSION, + .revision = 1, + .family = NFPROTO_IPV4, + .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)), + .help = recent_help, + .init = recent_init_v1, + .x6_parse = recent_parse, + .x6_fcheck = recent_check, + .print = recent_print_v4, + .save = recent_save_v4, + .x6_options = recent_opts_v1, + }, + { + .name = "recent", + .version = XTABLES_VERSION, + .revision = 1, + .family = NFPROTO_IPV6, + .size = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_recent_mtinfo_v1)), + .help = recent_help, + .init = recent_init_v1, + .x6_parse = recent_parse, + .x6_fcheck = recent_check, + .print = recent_print_v6, + .save = recent_save_v6, + .x6_options = recent_opts_v1, + }, }; void _init(void) { - xtables_register_match(&recent_mt_reg); + xtables_register_matches(recent_mt_reg, ARRAY_SIZE(recent_mt_reg)); } diff --git a/extensions/libxt_recent.man b/extensions/libxt_recent.man index 532c328..419be25 100644 --- a/extensions/libxt_recent.man +++ b/extensions/libxt_recent.man @@ -10,12 +10,12 @@ mutually exclusive. .TP \fB\-\-name\fP \fIname\fP Specify the list to use for the commands. If no name is given then -\fBDEFAULT\fR will be used. +\fBDEFAULT\fP will be used. .TP -[\fB!\fR] \fB\-\-set\fP +[\fB!\fP] \fB\-\-set\fP This will add the source address of the packet to the list. If the source address is already in the list, this will update the existing entry. This will -always return success (or failure if \fB!\fR is passed in). +always return success (or failure if \fB!\fP is passed in). .TP \fB\-\-rsource\fP Match/save the source address of each packet in the recent list table. This @@ -24,14 +24,17 @@ is the default. \fB\-\-rdest\fP Match/save the destination address of each packet in the recent list table. .TP -[\fB!\fR] \fB\-\-rcheck\fP +\fB\-\-mask\fP \fInetmask\fP +Netmask that will be applied to this recent list. +.TP +[\fB!\fP] \fB\-\-rcheck\fP Check if the source address of the packet is currently in the list. .TP -[\fB!\fR] \fB\-\-update\fP +[\fB!\fP] \fB\-\-update\fP Like \fB\-\-rcheck\fP, except it will update the "last seen" timestamp if it matches. .TP -[\fB!\fR] \fB\-\-remove\fP +[\fB!\fP] \fB\-\-remove\fP Check if the source address of the packet is currently in the list and if so that address will be removed from the list and the rule will return true. If the address is not found, false is returned. @@ -41,6 +44,11 @@ This option must be used in conjunction with one of \fB\-\-rcheck\fP or \fB\-\-update\fP. When used, this will narrow the match to only happen when the address is in the list and was seen within the last given number of seconds. .TP +\fB\-\-reap\fP +This option can only be used in conjunction with \fB\-\-seconds\fP. +When used, this will cause entries older than the last given number of seconds +to be purged. +.TP \fB\-\-hitcount\fP \fIhits\fP This option must be used in conjunction with one of \fB\-\-rcheck\fP or \fB\-\-update\fP. When used, this will narrow the match to only happen when the @@ -65,40 +73,37 @@ iptables \-A FORWARD \-m recent \-\-name badguy \-\-rcheck \-\-seconds 60 \-j DR .IP iptables \-A FORWARD \-p tcp \-i eth0 \-\-dport 139 \-m recent \-\-name badguy \-\-set \-j DROP .PP -Steve's ipt_recent website (http://snowman.net/projects/ipt_recent/) also has -some examples of usage. -.PP -\fB/proc/net/xt_recent/*\fR are the current lists of addresses and information +\fB/proc/net/xt_recent/*\fP are the current lists of addresses and information about each entry of each list. .PP -Each file in \fB/proc/net/xt_recent/\fR can be read from to see the current +Each file in \fB/proc/net/xt_recent/\fP can be read from to see the current list or written two using the following commands to modify the list: .TP -\fBecho +\fR\fIaddr\fR\fB >/proc/net/xt_recent/DEFAULT\fR -to add \fIaddr\fR to the DEFAULT list +\fBecho +\fP\fIaddr\fP\fB >/proc/net/xt_recent/DEFAULT\fP +to add \fIaddr\fP to the DEFAULT list .TP \fBecho \-\fP\fIaddr\fP\fB >/proc/net/xt_recent/DEFAULT\fP -to remove \fIaddr\fR from the DEFAULT list +to remove \fIaddr\fP from the DEFAULT list .TP -\fBecho / >/proc/net/xt_recent/DEFAULT\fR +\fBecho / >/proc/net/xt_recent/DEFAULT\fP to flush the DEFAULT list (remove all entries). .PP The module itself accepts parameters, defaults shown: .TP -\fBip_list_tot\fR=\fI100\fR +\fBip_list_tot\fP=\fI100\fP Number of addresses remembered per table. .TP -\fBip_pkt_list_tot\fR=\fI20\fR +\fBip_pkt_list_tot\fP=\fI20\fP Number of packets per address remembered. .TP -\fBip_list_hash_size\fR=\fI0\fR +\fBip_list_hash_size\fP=\fI0\fP Hash table size. 0 means to calculate it based on ip_list_tot, default: 512. .TP -\fBip_list_perms\fR=\fI0644\fR +\fBip_list_perms\fP=\fI0644\fP Permissions for /proc/net/xt_recent/* files. .TP -\fBip_list_uid\fR=\fI0\fR +\fBip_list_uid\fP=\fI0\fP Numerical UID for ownership of /proc/net/xt_recent/* files. .TP -\fBip_list_gid\fR=\fI0\fR +\fBip_list_gid\fP=\fI0\fP Numerical GID for ownership of /proc/net/xt_recent/* files. diff --git a/extensions/libxt_rpfilter.c b/extensions/libxt_rpfilter.c new file mode 100644 index 0000000..168e703 --- /dev/null +++ b/extensions/libxt_rpfilter.c @@ -0,0 +1,96 @@ +#include <stdio.h> +#include <xtables.h> +#include <linux/netfilter/xt_rpfilter.h> + +enum { + O_RPF_LOOSE = 0, + O_RPF_VMARK = 1, + O_RPF_ACCEPT_LOCAL = 2, + O_RPF_INVERT = 3, +}; + +static void rpfilter_help(void) +{ + printf( +"rpfilter match options:\n" +" --loose permit reverse path via any interface\n" +" --validmark use skb nfmark when performing route lookup\n" +" --accept-local do not reject packets with a local source address\n" +" --invert match packets that failed the reverse path test\n" + ); +} + +static const struct xt_option_entry rpfilter_opts[] = { + {.name = "loose", .id = O_RPF_LOOSE, .type = XTTYPE_NONE, }, + {.name = "validmark", .id = O_RPF_VMARK, .type = XTTYPE_NONE, }, + {.name = "accept-local", .id = O_RPF_ACCEPT_LOCAL, .type = XTTYPE_NONE, }, + {.name = "invert", .id = O_RPF_INVERT, .type = XTTYPE_NONE, }, + XTOPT_TABLEEND, +}; + +static void rpfilter_parse(struct xt_option_call *cb) +{ + struct xt_rpfilter_info *rpfinfo = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_RPF_LOOSE: + rpfinfo->flags |= XT_RPFILTER_LOOSE; + break; + case O_RPF_VMARK: + rpfinfo->flags |= XT_RPFILTER_VALID_MARK; + break; + case O_RPF_ACCEPT_LOCAL: + rpfinfo->flags |= XT_RPFILTER_ACCEPT_LOCAL; + break; + case O_RPF_INVERT: + rpfinfo->flags |= XT_RPFILTER_INVERT; + break; + } +} + +static void +rpfilter_print_prefix(const void *ip, const void *matchinfo, + const char *prefix) +{ + const struct xt_rpfilter_info *info = matchinfo; + if (info->flags & XT_RPFILTER_LOOSE) + printf(" %s%s", prefix, rpfilter_opts[O_RPF_LOOSE].name); + if (info->flags & XT_RPFILTER_VALID_MARK) + printf(" %s%s", prefix, rpfilter_opts[O_RPF_VMARK].name); + if (info->flags & XT_RPFILTER_ACCEPT_LOCAL) + printf(" %s%s", prefix, rpfilter_opts[O_RPF_ACCEPT_LOCAL].name); + if (info->flags & XT_RPFILTER_INVERT) + printf(" %s%s", prefix, rpfilter_opts[O_RPF_INVERT].name); +} + + +static void +rpfilter_print(const void *ip, const struct xt_entry_match *match, int numeric) +{ + printf(" rpfilter"); + return rpfilter_print_prefix(ip, match->data, ""); +} + +static void rpfilter_save(const void *ip, const struct xt_entry_match *match) +{ + return rpfilter_print_prefix(ip, match->data, "--"); +} + +static struct xtables_match rpfilter_match = { + .family = NFPROTO_UNSPEC, + .name = "rpfilter", + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_rpfilter_info)), + .userspacesize = XT_ALIGN(sizeof(struct xt_rpfilter_info)), + .help = rpfilter_help, + .print = rpfilter_print, + .save = rpfilter_save, + .x6_parse = rpfilter_parse, + .x6_options = rpfilter_opts, +}; + +void _init(void) +{ + xtables_register_match(&rpfilter_match); +} diff --git a/extensions/libxt_rpfilter.man b/extensions/libxt_rpfilter.man new file mode 100644 index 0000000..f7f56d2 --- /dev/null +++ b/extensions/libxt_rpfilter.man @@ -0,0 +1,39 @@ +Performs a reverse path filter test on a packet. +If a reply to the packet would be sent via the same interface +that the packet arrived on, the packet will match. +Note that, unlike the in-kernel rp_filter, packets protected +by IPSec are not treated specially. Combine this match with +the policy match if you want this. +Also, packets arriving via the loopback interface are always permitted. +This match can only be used in the PREROUTING chain of the raw or mangle table. +.TP +\fB\-\-loose\fP +Used to specifiy that the reverse path filter test should match +even if the selected output device is not the expected one. +.TP +\fB\-\-validmark\fP +Also use the packets' nfmark value when performing the reverse path route lookup. +.TP +\fB\-\-accept\-local\fP +This will permit packets arriving from the network with a source address that is also +assigned to the local machine. +.TP +\fB\-\-invert\fP +This will invert the sense of the match. Instead of matching packets that passed the +reverse path filter test, match those that have failed it. +.PP +Example to log and drop packets failing the reverse path filter test: + +iptables \-t raw \-N RPFILTER + +iptables \-t raw \-A RPFILTER \-m rpfilter \-j RETURN + +iptables \-t raw \-A RPFILTER \-m limit \-\-limit 10/minute \-j NFLOG \-\-nflog\-prefix "rpfilter drop" + +iptables \-t raw \-A RPFILTER \-j DROP + +iptables \-t raw \-A PREROUTING \-j RPFILTER + +Example to drop failed packets, without logging: + +iptables \-t raw \-A RPFILTER \-m rpfilter \-\-invert \-j DROP diff --git a/extensions/libxt_sctp.c b/extensions/libxt_sctp.c index d321fb8..56a4cdf 100644 --- a/extensions/libxt_sctp.c +++ b/extensions/libxt_sctp.c @@ -7,6 +7,7 @@ * libipt_ecn.c borrowed heavily from libipt_dscp.c * */ +#include <stdbool.h> #include <stdio.h> #include <string.h> #include <stdlib.h> @@ -27,15 +28,13 @@ #endif static void -print_chunk(u_int32_t chunknum, int numeric); +print_chunk(uint32_t chunknum, int numeric); static void sctp_init(struct xt_entry_match *m) { int i; struct xt_sctp_info *einfo = (struct xt_sctp_info *)m->data; - memset(einfo, 0, sizeof(struct xt_sctp_info)); - for (i = 0; i < XT_NUM_SCTP_FLAGS; i++) { einfo->flag_info[i].chunktype = -1; } @@ -55,17 +54,17 @@ static void sctp_help(void) } static const struct option sctp_opts[] = { - { .name = "source-port", .has_arg = 1, .val = '1' }, - { .name = "sport", .has_arg = 1, .val = '1' }, - { .name = "destination-port", .has_arg = 1, .val = '2' }, - { .name = "dport", .has_arg = 1, .val = '2' }, - { .name = "chunk-types", .has_arg = 1, .val = '3' }, - { .name = NULL } + {.name = "source-port", .has_arg = true, .val = '1'}, + {.name = "sport", .has_arg = true, .val = '1'}, + {.name = "destination-port", .has_arg = true, .val = '2'}, + {.name = "dport", .has_arg = true, .val = '2'}, + {.name = "chunk-types", .has_arg = true, .val = '3'}, + XT_GETOPT_TABLEEND, }; static void parse_sctp_ports(const char *portstring, - u_int16_t *ports) + uint16_t *ports) { char *buffer; char *cp; @@ -258,7 +257,6 @@ sctp_parse(int c, char **argv, int invert, unsigned int *flags, xtables_error(PARAMETER_PROBLEM, "Only one `--source-port' allowed"); einfo->flags |= XT_SCTP_SRC_PORTS; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_sctp_ports(optarg, einfo->spts); if (invert) einfo->invflags |= XT_SCTP_SRC_PORTS; @@ -270,7 +268,6 @@ sctp_parse(int c, char **argv, int invert, unsigned int *flags, xtables_error(PARAMETER_PROBLEM, "Only one `--destination-port' allowed"); einfo->flags |= XT_SCTP_DEST_PORTS; - xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_sctp_ports(optarg, einfo->dpts); if (invert) einfo->invflags |= XT_SCTP_DEST_PORTS; @@ -281,8 +278,6 @@ sctp_parse(int c, char **argv, int invert, unsigned int *flags, if (*flags & XT_SCTP_CHUNK_TYPES) xtables_error(PARAMETER_PROBLEM, "Only one `--chunk-types' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (!argv[optind] || argv[optind][0] == '-' || argv[optind][0] == '!') xtables_error(PARAMETER_PROBLEM, @@ -295,17 +290,14 @@ sctp_parse(int c, char **argv, int invert, unsigned int *flags, optind++; *flags |= XT_SCTP_CHUNK_TYPES; break; - - default: - return 0; } return 1; } -static char * +static const char * port_to_service(int port) { - struct servent *service; + const struct servent *service; if ((service = getservbyport(htons(port), "sctp"))) return service->s_name; @@ -314,9 +306,9 @@ port_to_service(int port) } static void -print_port(u_int16_t port, int numeric) +print_port(uint16_t port, int numeric) { - char *service; + const char *service; if (numeric || (service = port_to_service(port)) == NULL) printf("%u", port); @@ -325,13 +317,13 @@ print_port(u_int16_t port, int numeric) } static void -print_ports(const char *name, u_int16_t min, u_int16_t max, +print_ports(const char *name, uint16_t min, uint16_t max, int invert, int numeric) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFFFF || invert) { - printf("%s", name); + printf(" %s", name); if (min == max) { printf(":%s", inv); print_port(min, numeric); @@ -341,12 +333,11 @@ print_ports(const char *name, u_int16_t min, u_int16_t max, printf(":"); print_port(max, numeric); } - printf(" "); } } static void -print_chunk_flags(u_int32_t chunknum, u_int8_t chunk_flags, u_int8_t chunk_flags_mask) +print_chunk_flags(uint32_t chunknum, uint8_t chunk_flags, uint8_t chunk_flags_mask) { int i; @@ -369,7 +360,7 @@ print_chunk_flags(u_int32_t chunknum, u_int8_t chunk_flags, u_int8_t chunk_flags } static void -print_chunk(u_int32_t chunknum, int numeric) +print_chunk(uint32_t chunknum, int numeric) { if (numeric) { printf("0x%04X", chunknum); @@ -386,26 +377,26 @@ print_chunk(u_int32_t chunknum, int numeric) static void print_chunks(const struct xt_sctp_info *einfo, int numeric) { - u_int32_t chunk_match_type = einfo->chunk_match_type; + uint32_t chunk_match_type = einfo->chunk_match_type; const struct xt_sctp_flag_info *flag_info = einfo->flag_info; int flag_count = einfo->flag_count; int i, j; int flag; switch (chunk_match_type) { - case SCTP_CHUNK_MATCH_ANY: printf("any "); break; - case SCTP_CHUNK_MATCH_ALL: printf("all "); break; - case SCTP_CHUNK_MATCH_ONLY: printf("only "); break; - default: printf("Never reach herer\n"); break; + case SCTP_CHUNK_MATCH_ANY: printf(" any"); break; + case SCTP_CHUNK_MATCH_ALL: printf(" all"); break; + case SCTP_CHUNK_MATCH_ONLY: printf(" only"); break; + default: printf("Never reach here\n"); break; } if (SCTP_CHUNKMAP_IS_CLEAR(einfo->chunkmap)) { - printf("NONE "); + printf(" NONE"); goto out; } if (SCTP_CHUNKMAP_IS_ALL_SET(einfo->chunkmap)) { - printf("ALL "); + printf(" ALL"); goto out; } @@ -414,6 +405,8 @@ print_chunks(const struct xt_sctp_info *einfo, int numeric) if (SCTP_CHUNKMAP_IS_SET(einfo->chunkmap, i)) { if (flag) printf(","); + else + putchar(' '); flag = 1; print_chunk(i, numeric); for (j = 0; j < flag_count; j++) { @@ -424,9 +417,6 @@ print_chunks(const struct xt_sctp_info *einfo, int numeric) } } } - - if (flag) - printf(" "); out: return; } @@ -437,7 +427,7 @@ sctp_print(const void *ip, const struct xt_entry_match *match, int numeric) const struct xt_sctp_info *einfo = (const struct xt_sctp_info *)match->data; - printf("sctp "); + printf(" sctp"); if (einfo->flags & XT_SCTP_SRC_PORTS) { print_ports("spt", einfo->spts[0], einfo->spts[1], @@ -455,7 +445,7 @@ sctp_print(const void *ip, const struct xt_entry_match *match, int numeric) /* FIXME: print_chunks() is used in save() where the printing of '!' s taken care of, so we need to do that here as well */ if (einfo->invflags & XT_SCTP_CHUNK_TYPES) { - printf("! "); + printf(" !"); } print_chunks(einfo, numeric); } @@ -468,28 +458,28 @@ static void sctp_save(const void *ip, const struct xt_entry_match *match) if (einfo->flags & XT_SCTP_SRC_PORTS) { if (einfo->invflags & XT_SCTP_SRC_PORTS) - printf("! "); + printf(" !"); if (einfo->spts[0] != einfo->spts[1]) - printf("--sport %u:%u ", + printf(" --sport %u:%u", einfo->spts[0], einfo->spts[1]); else - printf("--sport %u ", einfo->spts[0]); + printf(" --sport %u", einfo->spts[0]); } if (einfo->flags & XT_SCTP_DEST_PORTS) { if (einfo->invflags & XT_SCTP_DEST_PORTS) - printf("! "); + printf(" !"); if (einfo->dpts[0] != einfo->dpts[1]) - printf("--dport %u:%u ", + printf(" --dport %u:%u", einfo->dpts[0], einfo->dpts[1]); else - printf("--dport %u ", einfo->dpts[0]); + printf(" --dport %u", einfo->dpts[0]); } if (einfo->flags & XT_SCTP_CHUNK_TYPES) { if (einfo->invflags & XT_SCTP_CHUNK_TYPES) - printf("! "); - printf("--chunk-types "); + printf(" !"); + printf(" --chunk-types"); print_chunks(einfo, 0); } diff --git a/extensions/libxt_set.c b/extensions/libxt_set.c index 75fa3c2..2cb9e78 100644 --- a/extensions/libxt_set.c +++ b/extensions/libxt_set.c @@ -9,6 +9,7 @@ */ /* Shared library add-on to iptables to add IP set matching. */ +#include <stdbool.h> #include <stdio.h> #include <netdb.h> #include <string.h> @@ -21,8 +22,10 @@ #include <linux/netfilter/xt_set.h> #include "libxt_set.h" +/* Revision 0 */ + static void -set_help(void) +set_help_v0(void) { printf("set match options:\n" " [!] --match-set name flags\n" @@ -31,14 +34,14 @@ set_help(void) " 'src' and 'dst' specifications.\n"); } -static const struct option set_opts[] = { - { .name = "match-set", .has_arg = true, .val = '1'}, - { .name = "set", .has_arg = true, .val = '2'}, - { .name = NULL } +static const struct option set_opts_v0[] = { + {.name = "match-set", .has_arg = true, .val = '1'}, + {.name = "set", .has_arg = true, .val = '2'}, + XT_GETOPT_TABLEEND, }; static void -set_check(unsigned int flags) +set_check_v0(unsigned int flags) { if (!flags) xtables_error(PARAMETER_PROBLEM, @@ -61,8 +64,6 @@ set_parse_v0(int c, char **argv, int invert, unsigned int *flags, if (info->u.flags[0]) xtables_error(PARAMETER_PROBLEM, "--match-set can be specified only once"); - - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) info->u.flags[0] |= IPSET_MATCH_INV; @@ -84,9 +85,6 @@ set_parse_v0(int c, char **argv, int invert, unsigned int *flags, *flags = 1; break; - - default: - return 0; } return 1; @@ -99,8 +97,8 @@ print_match_v0(const char *prefix, const struct xt_set_info_v0 *info) char setname[IPSET_MAXNAMELEN]; get_set_byid(setname, info->index); - printf("%s%s %s", - (info->u.flags[0] & IPSET_MATCH_INV) ? "! " : "", + printf("%s %s %s", + (info->u.flags[0] & IPSET_MATCH_INV) ? " !" : "", prefix, setname); for (i = 0; i < IPSET_DIM_MAX; i++) { @@ -110,7 +108,6 @@ print_match_v0(const char *prefix, const struct xt_set_info_v0 *info) i == 0 ? " " : ",", info->u.flags[i] & IPSET_SRC ? "src" : "dst"); } - printf(" "); } /* Prints out the matchinfo. */ @@ -130,12 +127,13 @@ set_save_v0(const void *ip, const struct xt_entry_match *match) print_match_v0("--match-set", &info->match_set); } +/* Revision 1 */ static int -set_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +set_parse_v1(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) { - struct xt_set_info_match *myinfo = - (struct xt_set_info_match *) (*match)->data; + struct xt_set_info_match_v1 *myinfo = + (struct xt_set_info_match_v1 *) (*match)->data; struct xt_set_info *info = &myinfo->match_set; switch (c) { @@ -146,8 +144,6 @@ set_parse(int c, char **argv, int invert, unsigned int *flags, if (info->dim) xtables_error(PARAMETER_PROBLEM, "--match-set can be specified only once"); - - xtables_check_inverse(optarg, &invert, &optind, 0, argv); if (invert) info->flags |= IPSET_INV_MATCH; @@ -169,9 +165,6 @@ set_parse(int c, char **argv, int invert, unsigned int *flags, *flags = 1; break; - - default: - return 0; } return 1; @@ -184,8 +177,8 @@ print_match(const char *prefix, const struct xt_set_info *info) char setname[IPSET_MAXNAMELEN]; get_set_byid(setname, info->index); - printf("%s%s %s", - (info->flags & IPSET_INV_MATCH) ? "! " : "", + printf("%s %s %s", + (info->flags & IPSET_INV_MATCH) ? " !" : "", prefix, setname); for (i = 1; i <= info->dim; i++) { @@ -193,26 +186,317 @@ print_match(const char *prefix, const struct xt_set_info *info) i == 1 ? " " : ",", info->flags & (1 << i) ? "src" : "dst"); } - printf(" "); } /* Prints out the matchinfo. */ static void -set_print(const void *ip, const struct xt_entry_match *match, int numeric) +set_print_v1(const void *ip, const struct xt_entry_match *match, int numeric) { - const struct xt_set_info_match *info = (const void *)match->data; + const struct xt_set_info_match_v1 *info = (const void *)match->data; print_match("match-set", &info->match_set); } static void -set_save(const void *ip, const struct xt_entry_match *match) +set_save_v1(const void *ip, const struct xt_entry_match *match) { - const struct xt_set_info_match *info = (const void *)match->data; + const struct xt_set_info_match_v1 *info = (const void *)match->data; print_match("--match-set", &info->match_set); } +/* Revision 2 */ +static void +set_help_v2(void) +{ + printf("set match options:\n" + " [!] --match-set name flags [--return-nomatch]\n" + " 'name' is the set name from to match,\n" + " 'flags' are the comma separated list of\n" + " 'src' and 'dst' specifications.\n"); +} + +static const struct option set_opts_v2[] = { + {.name = "match-set", .has_arg = true, .val = '1'}, + {.name = "set", .has_arg = true, .val = '2'}, + {.name = "return-nomatch", .has_arg = false, .val = '3'}, + XT_GETOPT_TABLEEND, +}; + +static int +set_parse_v2(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct xt_set_info_match_v1 *myinfo = + (struct xt_set_info_match_v1 *) (*match)->data; + struct xt_set_info *info = &myinfo->match_set; + + switch (c) { + case '3': + info->flags |= IPSET_RETURN_NOMATCH; + break; + case '2': + fprintf(stderr, + "--set option deprecated, please use --match-set\n"); + case '1': /* --match-set <set> <flag>[,<flag> */ + if (info->dim) + xtables_error(PARAMETER_PROBLEM, + "--match-set can be specified only once"); + if (invert) + info->flags |= IPSET_INV_MATCH; + + if (!argv[optind] + || argv[optind][0] == '-' + || argv[optind][0] == '!') + xtables_error(PARAMETER_PROBLEM, + "--match-set requires two args."); + + if (strlen(optarg) > IPSET_MAXNAMELEN - 1) + xtables_error(PARAMETER_PROBLEM, + "setname `%s' too long, max %d characters.", + optarg, IPSET_MAXNAMELEN - 1); + + get_set_byname(optarg, info); + parse_dirs(argv[optind], info); + DEBUGP("parse: set index %u\n", info->index); + optind++; + + *flags = 1; + break; + } + + return 1; +} + +/* Prints out the matchinfo. */ +static void +set_print_v2(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_set_info_match_v1 *info = (const void *)match->data; + + print_match("match-set", &info->match_set); + if (info->match_set.flags & IPSET_RETURN_NOMATCH) + printf(" return-nomatch"); +} + +static void +set_save_v2(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_set_info_match_v1 *info = (const void *)match->data; + + print_match("--match-set", &info->match_set); + if (info->match_set.flags & IPSET_RETURN_NOMATCH) + printf(" --return-nomatch"); +} + +/* Revision 3 */ +static void +set_help_v3(void) +{ + printf("set match options:\n" + " [!] --match-set name flags [--return-nomatch]\n" + " [! --update-counters] [! --update-subcounters]\n" + " [[!] --packets-eq value | --packets-lt value | --packets-gt value\n" + " [[!] --bytes-eq value | --bytes-lt value | --bytes-gt value\n" + " 'name' is the set name from to match,\n" + " 'flags' are the comma separated list of\n" + " 'src' and 'dst' specifications.\n"); +} + +static const struct option set_opts_v3[] = { + {.name = "match-set", .has_arg = true, .val = '1'}, + {.name = "set", .has_arg = true, .val = '2'}, + {.name = "return-nomatch", .has_arg = false, .val = '3'}, + {.name = "update-counters", .has_arg = false, .val = '4'}, + {.name = "packets-eq", .has_arg = true, .val = '5'}, + {.name = "packets-lt", .has_arg = true, .val = '6'}, + {.name = "packets-gt", .has_arg = true, .val = '7'}, + {.name = "bytes-eq", .has_arg = true, .val = '8'}, + {.name = "bytes-lt", .has_arg = true, .val = '9'}, + {.name = "bytes-gt", .has_arg = true, .val = '0'}, + {.name = "update-subcounters", .has_arg = false, .val = 'a'}, + XT_GETOPT_TABLEEND, +}; + +static uint64_t +parse_counter(const char *opt) +{ + uintmax_t value; + + if (!xtables_strtoul(opt, NULL, &value, 0, UINT64_MAX)) + xtables_error(PARAMETER_PROBLEM, + "Cannot parse %s as a counter value\n", + opt); + return (uint64_t)value; +} + +static int +set_parse_v3(int c, char **argv, int invert, unsigned int *flags, + const void *entry, struct xt_entry_match **match) +{ + struct xt_set_info_match_v3 *info = + (struct xt_set_info_match_v3 *) (*match)->data; + + switch (c) { + case 'a': + if (invert) + info->flags |= IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE; + break; + case '0': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--bytes-gt option cannot be inverted\n"); + info->bytes.op = IPSET_COUNTER_GT; + info->bytes.value = parse_counter(optarg); + break; + case '9': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--bytes-lt option cannot be inverted\n"); + info->bytes.op = IPSET_COUNTER_LT; + info->bytes.value = parse_counter(optarg); + break; + case '8': + if (info->bytes.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --bytes-[eq|lt|gt]" + " is allowed\n"); + info->bytes.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; + info->bytes.value = parse_counter(optarg); + break; + case '7': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--packets-gt option cannot be inverted\n"); + info->packets.op = IPSET_COUNTER_GT; + info->packets.value = parse_counter(optarg); + break; + case '6': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--packets-lt option cannot be inverted\n"); + info->packets.op = IPSET_COUNTER_LT; + info->packets.value = parse_counter(optarg); + break; + case '5': + if (info->packets.op != IPSET_COUNTER_NONE) + xtables_error(PARAMETER_PROBLEM, + "only one of the --packets-[eq|lt|gt]" + " is allowed\n"); + info->packets.op = invert ? IPSET_COUNTER_NE : IPSET_COUNTER_EQ; + info->packets.value = parse_counter(optarg); + break; + case '4': + if (invert) + info->flags |= IPSET_FLAG_SKIP_COUNTER_UPDATE; + break; + case '3': + if (invert) + xtables_error(PARAMETER_PROBLEM, + "--return-nomatch flag cannot be inverted\n"); + info->flags |= IPSET_FLAG_RETURN_NOMATCH; + break; + case '2': + fprintf(stderr, + "--set option deprecated, please use --match-set\n"); + case '1': /* --match-set <set> <flag>[,<flag> */ + if (info->match_set.dim) + xtables_error(PARAMETER_PROBLEM, + "--match-set can be specified only once"); + if (invert) + info->match_set.flags |= IPSET_INV_MATCH; + + if (!argv[optind] + || argv[optind][0] == '-' + || argv[optind][0] == '!') + xtables_error(PARAMETER_PROBLEM, + "--match-set requires two args."); + + if (strlen(optarg) > IPSET_MAXNAMELEN - 1) + xtables_error(PARAMETER_PROBLEM, + "setname `%s' too long, max %d characters.", + optarg, IPSET_MAXNAMELEN - 1); + + get_set_byname(optarg, &info->match_set); + parse_dirs(argv[optind], &info->match_set); + DEBUGP("parse: set index %u\n", info->match_set.index); + optind++; + + *flags = 1; + break; + } + + return 1; +} + +static void +set_printv3_counter(const struct ip_set_counter_match *c, const char *name, + const char *sep) +{ + switch (c->op) { + case IPSET_COUNTER_EQ: + printf(" %s%s-eq %llu", sep, name, c->value); + break; + case IPSET_COUNTER_NE: + printf(" ! %s%s-eq %llu", sep, name, c->value); + break; + case IPSET_COUNTER_LT: + printf(" %s%s-lt %llu", sep, name, c->value); + break; + case IPSET_COUNTER_GT: + printf(" %s%s-gt %llu", sep, name, c->value); + break; + } +} + +static void +set_print_v3_matchinfo(const struct xt_set_info_match_v3 *info, + const char *opt, const char *sep) +{ + print_match(opt, &info->match_set); + if (info->flags & IPSET_FLAG_RETURN_NOMATCH) + printf(" %sreturn-nomatch", sep); + if ((info->flags & IPSET_FLAG_SKIP_COUNTER_UPDATE)) + printf(" ! %supdate-counters", sep); + if ((info->flags & IPSET_FLAG_SKIP_SUBCOUNTER_UPDATE)) + printf(" ! %supdate-subcounters", sep); + set_printv3_counter(&info->packets, "packets", sep); + set_printv3_counter(&info->bytes, "bytes", sep); +} + +/* Prints out the matchinfo. */ +static void +set_print_v3(const void *ip, const struct xt_entry_match *match, int numeric) +{ + const struct xt_set_info_match_v3 *info = (const void *)match->data; + + set_print_v3_matchinfo(info, "match-set", ""); +} + +static void +set_save_v3(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_set_info_match_v3 *info = (const void *)match->data; + + set_print_v3_matchinfo(info, "--match-set", "--"); +} + static struct xtables_match set_mt_reg[] = { { .name = "set", @@ -221,26 +505,54 @@ static struct xtables_match set_mt_reg[] = { .family = NFPROTO_IPV4, .size = XT_ALIGN(sizeof(struct xt_set_info_match_v0)), .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v0)), - .help = set_help, + .help = set_help_v0, .parse = set_parse_v0, - .final_check = set_check, + .final_check = set_check_v0, .print = set_print_v0, .save = set_save_v0, - .extra_opts = set_opts, + .extra_opts = set_opts_v0, }, { .name = "set", .revision = 1, .version = XTABLES_VERSION, .family = NFPROTO_UNSPEC, - .size = XT_ALIGN(sizeof(struct xt_set_info_match)), - .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match)), - .help = set_help, - .parse = set_parse, - .final_check = set_check, - .print = set_print, - .save = set_save, - .extra_opts = set_opts, + .size = XT_ALIGN(sizeof(struct xt_set_info_match_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v1)), + .help = set_help_v0, + .parse = set_parse_v1, + .final_check = set_check_v0, + .print = set_print_v1, + .save = set_save_v1, + .extra_opts = set_opts_v0, + }, + { + .name = "set", + .revision = 2, + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_set_info_match_v1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v1)), + .help = set_help_v2, + .parse = set_parse_v2, + .final_check = set_check_v0, + .print = set_print_v2, + .save = set_save_v2, + .extra_opts = set_opts_v2, + }, + { + .name = "set", + .revision = 3, + .version = XTABLES_VERSION, + .family = NFPROTO_UNSPEC, + .size = XT_ALIGN(sizeof(struct xt_set_info_match_v3)), + .userspacesize = XT_ALIGN(sizeof(struct xt_set_info_match_v3)), + .help = set_help_v3, + .parse = set_parse_v3, + .final_check = set_check_v0, + .print = set_print_v3, + .save = set_save_v3, + .extra_opts = set_opts_v3, }, }; diff --git a/extensions/libxt_set.h b/extensions/libxt_set.h index 6b93691..5a1bdcf 100644 --- a/extensions/libxt_set.h +++ b/extensions/libxt_set.h @@ -2,9 +2,11 @@ #define _LIBXT_SET_H #include <unistd.h> +#include <fcntl.h> #include <sys/types.h> #include <sys/socket.h> #include <errno.h> +#include "../iptables/xshared.h" #ifdef DEBUG #define DEBUGP(x, args...) fprintf(stderr, x , ## args) @@ -23,6 +25,12 @@ get_version(unsigned *version) xtables_error(OTHER_PROBLEM, "Can't open socket to ipset.\n"); + if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) == -1) { + xtables_error(OTHER_PROBLEM, + "Could not set close on exec: %s\n", + strerror(errno)); + } + req_version.op = IP_SET_OP_VERSION; res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req_version, &size); if (res != 0) @@ -64,13 +72,13 @@ get_set_byid(char *setname, ip_set_id_t idx) } static void -get_set_byname(const char *setname, struct xt_set_info *info) +get_set_byname_only(const char *setname, struct xt_set_info *info, + int sockfd, unsigned int version) { - struct ip_set_req_get_set req; + struct ip_set_req_get_set req = { .version = version }; socklen_t size = sizeof(struct ip_set_req_get_set); - int res, sockfd; + int res; - sockfd = get_version(&req.version); req.op = IP_SET_OP_GET_BYNAME; strncpy(req.set.name, setname, IPSET_MAXNAMELEN); req.set.name[IPSET_MAXNAMELEN - 1] = '\0'; @@ -94,6 +102,49 @@ get_set_byname(const char *setname, struct xt_set_info *info) } static void +get_set_byname(const char *setname, struct xt_set_info *info) +{ + struct ip_set_req_get_set_family req; + socklen_t size = sizeof(struct ip_set_req_get_set_family); + int res, sockfd, version; + + sockfd = get_version(&req.version); + version = req.version; + req.op = IP_SET_OP_GET_FNAME; + strncpy(req.set.name, setname, IPSET_MAXNAMELEN); + req.set.name[IPSET_MAXNAMELEN - 1] = '\0'; + res = getsockopt(sockfd, SOL_IP, SO_IP_SET, &req, &size); + + if (res != 0 && errno == EBADMSG) + /* Backward compatibility */ + return get_set_byname_only(setname, info, sockfd, version); + + close(sockfd); + if (res != 0) + xtables_error(OTHER_PROBLEM, + "Problem when communicating with ipset, errno=%d.\n", + errno); + if (size != sizeof(struct ip_set_req_get_set_family)) + xtables_error(OTHER_PROBLEM, + "Incorrect return size from kernel during ipset lookup, " + "(want %zu, got %zu)\n", + sizeof(struct ip_set_req_get_set_family), + (size_t)size); + if (req.set.index == IPSET_INVALID_ID) + xtables_error(PARAMETER_PROBLEM, + "Set %s doesn't exist.\n", setname); + if (!(req.family == afinfo->family || + req.family == NFPROTO_UNSPEC)) + xtables_error(PARAMETER_PROBLEM, + "The protocol family of set %s is %s, " + "which is not applicable.\n", + setname, + req.family == NFPROTO_IPV4 ? "IPv4" : "IPv6"); + + info->index = req.set.index; +} + +static void parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info) { char *saved = strdup(opt_arg); @@ -114,7 +165,7 @@ parse_dirs_v0(const char *opt_arg, struct xt_set_info_v0 *info) if (tmp) xtables_error(PARAMETER_PROBLEM, "Can't be more src/dst options than %i.", - IPSET_DIM_MAX - 1); + IPSET_DIM_MAX); free(saved); } @@ -124,9 +175,8 @@ parse_dirs(const char *opt_arg, struct xt_set_info *info) { char *saved = strdup(opt_arg); char *ptr, *tmp = saved; - int i = 0; - while (i < (IPSET_DIM_MAX - 1) && tmp != NULL) { + while (info->dim < IPSET_DIM_MAX && tmp != NULL) { info->dim++; ptr = strsep(&tmp, ","); if (strncmp(ptr, "src", 3) == 0) @@ -139,7 +189,7 @@ parse_dirs(const char *opt_arg, struct xt_set_info *info) if (tmp) xtables_error(PARAMETER_PROBLEM, "Can't be more src/dst options than %i.", - IPSET_DIM_MAX - 1); + IPSET_DIM_MAX); free(saved); } diff --git a/extensions/libxt_set.man b/extensions/libxt_set.man index aca1bfc..7012ef2 100644 --- a/extensions/libxt_set.man +++ b/extensions/libxt_set.man @@ -14,10 +14,52 @@ address and destination port pair can be found in the specified set. If the set type of the specified set is single dimension (for example ipmap), then the command will match packets for which the source address can be found in the specified set. +.TP +\fB\-\-return\-nomatch\fP +If the \fB\-\-return\-nomatch\fP option is specified and the set type +supports the \fBnomatch\fP flag, then the matching is reversed: a match +with an element flagged with \fBnomatch\fP returns \fBtrue\fP, while a +match with a plain element returns \fBfalse\fP. +.TP +\fB!\fP \fB\-\-update\-counters\fP +If the \fB\-\-update\-counters\fP flag is negated, then the packet and +byte counters of the matching element in the set won't be updated. Default +the packet and byte counters are updated. +.TP +\fB!\fP \fB\-\-update\-subcounters\fP +If the \fB\-\-update\-subcounters\fP flag is negated, then the packet and +byte counters of the matching element in the member set of a list type of +set won't be updated. Default the packet and byte counters are updated. +.TP +[\fB!\fP] \fB\-\-packets\-eq\fP \fIvalue\fP +If the packet is matched an element in the set, match only if the +packet counter of the element matches the given value too. +.TP +\fB\-\-packets\-lt\fP \fIvalue\fP +If the packet is matched an element in the set, match only if the +packet counter of the element is less than the given value as well. +.TP +\fB\-\-packets\-gt\fP \fIvalue\fP +If the packet is matched an element in the set, match only if the +packet counter of the element is greater than the given value as well. +.TP +[\fB!\fP] \fB\-bytes\-eq\fP \fIvalue\fP +If the packet is matched an element in the set, match only if the +byte counter of the element matches the given value too. +.TP +\fB\-\-bytes\-lt\fP \fIvalue\fP +If the packet is matched an element in the set, match only if the +byte counter of the element is less than the given value as well. +.TP +\fB\-\-bytes\-gt\fP \fIvalue\fP +If the packet is matched an element in the set, match only if the +byte counter of the element is greater than the given value as well. +.PP +The packet and byte counters related options and flags are ignored +when the set was defined without counter support. .PP -The option \fB\-\-match\-set\fR can be replaced by \fB\-\-set\fR if that does +The option \fB\-\-match\-set\fP can be replaced by \fB\-\-set\fP if that does not clash with an option of other extensions. .PP -Use of -m set requires that ipset kernel support is provided. As standard -kernels do not ship this currently, the ipset or Xtables-addons package needs -to be installed. +Use of -m set requires that ipset kernel support is provided, which, for +standard kernels, is the case since Linux 2.6.39. diff --git a/extensions/libxt_socket.c b/extensions/libxt_socket.c index 1490473..f19c280 100644 --- a/extensions/libxt_socket.c +++ b/extensions/libxt_socket.c @@ -3,17 +3,142 @@ * * Copyright (C) 2007 BalaBit IT Ltd. */ +#include <stdio.h> #include <xtables.h> +#include <linux/netfilter/xt_socket.h> -static struct xtables_match socket_mt_reg = { - .name = "socket", - .version = XTABLES_VERSION, - .family = NFPROTO_IPV4, - .size = XT_ALIGN(0), - .userspacesize = XT_ALIGN(0), +enum { + O_TRANSPARENT = 0, + O_NOWILDCARD = 1, +}; + +static const struct xt_option_entry socket_mt_opts[] = { + {.name = "transparent", .id = O_TRANSPARENT, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry socket_mt_opts_v2[] = { + {.name = "transparent", .id = O_TRANSPARENT, .type = XTTYPE_NONE}, + {.name = "nowildcard", .id = O_NOWILDCARD, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, +}; + +static void socket_mt_help(void) +{ + printf( + "socket match options:\n" + " --transparent Ignore non-transparent sockets\n\n"); +} + +static void socket_mt_help_v2(void) +{ + printf( + "socket match options:\n" + " --nowildcard Do not ignore LISTEN sockets bound on INADDR_ANY\n" + " --transparent Ignore non-transparent sockets\n\n"); +} + +static void socket_mt_parse(struct xt_option_call *cb) +{ + struct xt_socket_mtinfo1 *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TRANSPARENT: + info->flags |= XT_SOCKET_TRANSPARENT; + break; + } +} + +static void socket_mt_parse_v2(struct xt_option_call *cb) +{ + struct xt_socket_mtinfo2 *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_TRANSPARENT: + info->flags |= XT_SOCKET_TRANSPARENT; + break; + case O_NOWILDCARD: + info->flags |= XT_SOCKET_NOWILDCARD; + break; + } +} + +static void +socket_mt_save(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_socket_mtinfo1 *info = (const void *)match->data; + + if (info->flags & XT_SOCKET_TRANSPARENT) + printf(" --transparent"); +} + +static void +socket_mt_print(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + printf(" socket"); + socket_mt_save(ip, match); +} + +static void +socket_mt_save_v2(const void *ip, const struct xt_entry_match *match) +{ + const struct xt_socket_mtinfo2 *info = (const void *)match->data; + + if (info->flags & XT_SOCKET_TRANSPARENT) + printf(" --transparent"); + if (info->flags & XT_SOCKET_NOWILDCARD) + printf(" --nowildcard"); +} + +static void +socket_mt_print_v2(const void *ip, const struct xt_entry_match *match, + int numeric) +{ + printf(" socket"); + socket_mt_save_v2(ip, match); +} + +static struct xtables_match socket_mt_reg[] = { + { + .name = "socket", + .revision = 0, + .family = NFPROTO_IPV4, + .version = XTABLES_VERSION, + .size = XT_ALIGN(0), + .userspacesize = XT_ALIGN(0), + }, + { + .name = "socket", + .revision = 1, + .family = NFPROTO_UNSPEC, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_socket_mtinfo1)), + .userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo1)), + .help = socket_mt_help, + .print = socket_mt_print, + .save = socket_mt_save, + .x6_parse = socket_mt_parse, + .x6_options = socket_mt_opts, + }, + { + .name = "socket", + .revision = 2, + .family = NFPROTO_UNSPEC, + .version = XTABLES_VERSION, + .size = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)), + .userspacesize = XT_ALIGN(sizeof(struct xt_socket_mtinfo2)), + .help = socket_mt_help_v2, + .print = socket_mt_print_v2, + .save = socket_mt_save_v2, + .x6_parse = socket_mt_parse_v2, + .x6_options = socket_mt_opts_v2, + }, }; void _init(void) { - xtables_register_match(&socket_mt_reg); + xtables_register_matches(socket_mt_reg, ARRAY_SIZE(socket_mt_reg)); } diff --git a/extensions/libxt_socket.man b/extensions/libxt_socket.man index 50c8854..2ef32ce 100644 --- a/extensions/libxt_socket.man +++ b/extensions/libxt_socket.man @@ -1,2 +1,22 @@ -This matches if an open socket can be found by doing a socket lookup on the -packet. +This matches if an open TCP/UDP socket can be found by doing a socket lookup on the +packet. It matches if there is an established or non\-zero bound listening +socket (possibly with a non\-local address). The lookup is performed using +the \fBpacket\fP tuple of TCP/UDP packets, or the original TCP/UDP header +\fBembedded\fP in an ICMP/ICPMv6 error packet. +.TP +\fB\-\-transparent\fP +Ignore non-transparent sockets. +.TP +\fB\-\-nowildcard\fP +Do not ignore sockets bound to 'any' address. +The socket match won't accept zero\-bound listeners by default, since +then local services could intercept traffic that would otherwise be forwarded. +This option therefore has security implications when used to match traffic being +forwarded to redirect such packets to local machine with policy routing. +When using the socket match to implement fully transparent +proxies bound to non\-local addresses it is recommended to use the \-\-transparent +option instead. +.PP +Example (assuming packets with mark 1 are delivered locally): +.IP +\-t mangle \-A PREROUTING \-m socket \-\-transparent \-j MARK \-\-set\-mark 1 diff --git a/extensions/libxt_state.c b/extensions/libxt_state.c deleted file mode 100644 index d8159e5..0000000 --- a/extensions/libxt_state.c +++ /dev/null @@ -1,158 +0,0 @@ -/* Shared library add-on to iptables to add state tracking support. */ -#include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <xtables.h> -#include <linux/netfilter/nf_conntrack_common.h> -#include <linux/netfilter/xt_state.h> - -#ifndef XT_STATE_UNTRACKED -#define XT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1)) -#endif - -static void -state_help(void) -{ - printf( -"state match options:\n" -" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n" -" State(s) to match\n"); -} - -static const struct option state_opts[] = { - { "state", 1, NULL, '1' }, - { .name = NULL } -}; - -static int -state_parse_state(const char *state, size_t len, struct xt_state_info *sinfo) -{ - if (strncasecmp(state, "INVALID", len) == 0) - sinfo->statemask |= XT_STATE_INVALID; - else if (strncasecmp(state, "NEW", len) == 0) - sinfo->statemask |= XT_STATE_BIT(IP_CT_NEW); - else if (strncasecmp(state, "ESTABLISHED", len) == 0) - sinfo->statemask |= XT_STATE_BIT(IP_CT_ESTABLISHED); - else if (strncasecmp(state, "RELATED", len) == 0) - sinfo->statemask |= XT_STATE_BIT(IP_CT_RELATED); - else if (strncasecmp(state, "UNTRACKED", len) == 0) - sinfo->statemask |= XT_STATE_UNTRACKED; - else - return 0; - return 1; -} - -static void -state_parse_states(const char *arg, struct xt_state_info *sinfo) -{ - const char *comma; - - while ((comma = strchr(arg, ',')) != NULL) { - if (comma == arg || !state_parse_state(arg, comma-arg, sinfo)) - xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg); - arg = comma+1; - } - if (!*arg) - xtables_error(PARAMETER_PROBLEM, "\"--state\" requires a list of " - "states with no spaces, e.g. " - "ESTABLISHED,RELATED"); - if (strlen(arg) == 0 || !state_parse_state(arg, strlen(arg), sinfo)) - xtables_error(PARAMETER_PROBLEM, "Bad state \"%s\"", arg); -} - -static int -state_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, - struct xt_entry_match **match) -{ - struct xt_state_info *sinfo = (struct xt_state_info *)(*match)->data; - - switch (c) { - case '1': - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - - state_parse_states(optarg, sinfo); - if (invert) - sinfo->statemask = ~sinfo->statemask; - *flags = 1; - break; - - default: - return 0; - } - - return 1; -} - -static void state_final_check(unsigned int flags) -{ - if (!flags) - xtables_error(PARAMETER_PROBLEM, "You must specify \"--state\""); -} - -static void state_print_state(unsigned int statemask) -{ - const char *sep = ""; - - if (statemask & XT_STATE_INVALID) { - printf("%sINVALID", sep); - sep = ","; - } - if (statemask & XT_STATE_BIT(IP_CT_NEW)) { - printf("%sNEW", sep); - sep = ","; - } - if (statemask & XT_STATE_BIT(IP_CT_RELATED)) { - printf("%sRELATED", sep); - sep = ","; - } - if (statemask & XT_STATE_BIT(IP_CT_ESTABLISHED)) { - printf("%sESTABLISHED", sep); - sep = ","; - } - if (statemask & XT_STATE_UNTRACKED) { - printf("%sUNTRACKED", sep); - sep = ","; - } - printf(" "); -} - -static void -state_print(const void *ip, - const struct xt_entry_match *match, - int numeric) -{ - const struct xt_state_info *sinfo = (const void *)match->data; - - printf("state "); - state_print_state(sinfo->statemask); -} - -static void state_save(const void *ip, const struct xt_entry_match *match) -{ - const struct xt_state_info *sinfo = (const void *)match->data; - - printf("--state "); - state_print_state(sinfo->statemask); -} - -static struct xtables_match state_match = { - .family = NFPROTO_UNSPEC, - .name = "state", - .version = XTABLES_VERSION, - .size = XT_ALIGN(sizeof(struct xt_state_info)), - .userspacesize = XT_ALIGN(sizeof(struct xt_state_info)), - .help = state_help, - .parse = state_parse, - .final_check = state_final_check, - .print = state_print, - .save = state_save, - .extra_opts = state_opts, -}; - -void _init(void) -{ - xtables_register_match(&state_match); -} diff --git a/extensions/libxt_state.man b/extensions/libxt_state.man index 37d095b..ec096ca 100644 --- a/extensions/libxt_state.man +++ b/extensions/libxt_state.man @@ -1,24 +1,8 @@ -This module, when combined with connection tracking, allows access to -the connection tracking state for this packet. +The "state" extension is a subset of the "conntrack" module. +"state" allows access to the connection tracking state for this packet. .TP [\fB!\fP] \fB\-\-state\fP \fIstate\fP -Where state is a comma separated list of the connection states to -match. Possible states are -.B INVALID -meaning that the packet could not be identified for some reason which -includes running out of memory and ICMP errors which don't correspond to any -known connection, -.B ESTABLISHED -meaning that the packet is associated with a connection which has seen -packets in both directions, -.B NEW -meaning that the packet has started a new connection, or otherwise -associated with a connection which has not seen packets in both -directions, and -.B RELATED -meaning that the packet is starting a new connection, but is -associated with an existing connection, such as an FTP data transfer, -or an ICMP error. -.B UNTRACKED -meaning that the packet is not tracked at all, which happens if you use -the NOTRACK target in raw table. +Where state is a comma separated list of the connection states to match. Only a +subset of the states unterstood by "conntrack" are recognized: \fBINVALID\fP, +\fBESTABLISHED\fP, \fBNEW\fP, \fBRELATED\fP or \fBUNTRACKED\fP. For their +description, see the "conntrack" heading in this manpage. diff --git a/extensions/libxt_statistic.c b/extensions/libxt_statistic.c index 913aa2c..b6ae5f5 100644 --- a/extensions/libxt_statistic.c +++ b/extensions/libxt_statistic.c @@ -1,144 +1,118 @@ +/* + * Copyright (c) 2006-2013 Patrick McHardy <kaber@trash.net> + */ + +#include <math.h> #include <stdio.h> -#include <netdb.h> #include <string.h> -#include <stdlib.h> -#include <stddef.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_statistic.h> +enum { + O_MODE = 0, + O_PROBABILITY, + O_EVERY, + O_PACKET, + F_PROBABILITY = 1 << O_PROBABILITY, + F_EVERY = 1 << O_EVERY, + F_PACKET = 1 << O_PACKET, +}; + static void statistic_help(void) { printf( "statistic match options:\n" " --mode mode Match mode (random, nth)\n" " random mode:\n" -" --probability p Probability\n" +"[!] --probability p Probability\n" " nth mode:\n" -" --every n Match every nth packet\n" +"[!] --every n Match every nth packet\n" " --packet p Initial counter value (0 <= p <= n-1, default 0)\n"); } -static const struct option statistic_opts[] = { - { "mode", 1, NULL, '1' }, - { "probability", 1, NULL, '2' }, - { "every", 1, NULL, '3' }, - { "packet", 1, NULL, '4' }, - { .name = NULL } +#define s struct xt_statistic_info +static const struct xt_option_entry statistic_opts[] = { + {.name = "mode", .id = O_MODE, .type = XTTYPE_STRING, + .flags = XTOPT_MAND}, + {.name = "probability", .id = O_PROBABILITY, .type = XTTYPE_DOUBLE, + .flags = XTOPT_INVERT, .min = 0, .max = 1, + .excl = F_EVERY | F_PACKET}, + {.name = "every", .id = O_EVERY, .type = XTTYPE_UINT32, .min = 1, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, u.nth.every), + .excl = F_PROBABILITY, .also = F_PACKET}, + {.name = "packet", .id = O_PACKET, .type = XTTYPE_UINT32, + .flags = XTOPT_PUT, XTOPT_POINTER(s, u.nth.packet), + .excl = F_PROBABILITY, .also = F_EVERY}, + XTOPT_TABLEEND, }; +#undef s -static struct xt_statistic_info *global_info; - -static void statistic_mt_init(struct xt_entry_match *match) -{ - global_info = (void *)match->data; -} - -static int -statistic_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void statistic_parse(struct xt_option_call *cb) { - struct xt_statistic_info *info = (void *)(*match)->data; - unsigned int val; - double prob; + struct xt_statistic_info *info = cb->data; - if (invert) + if (cb->invert) info->flags |= XT_STATISTIC_INVERT; - switch (c) { - case '1': - if (*flags & 0x1) - xtables_error(PARAMETER_PROBLEM, "double --mode"); - if (!strcmp(optarg, "random")) + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_MODE: + if (strcmp(cb->arg, "random") == 0) info->mode = XT_STATISTIC_MODE_RANDOM; - else if (!strcmp(optarg, "nth")) + else if (strcmp(cb->arg, "nth") == 0) info->mode = XT_STATISTIC_MODE_NTH; else - xtables_error(PARAMETER_PROBLEM, "Bad mode \"%s\"", optarg); - *flags |= 0x1; + xtables_error(PARAMETER_PROBLEM, "Bad mode \"%s\"", + cb->arg); break; - case '2': - if (*flags & 0x2) - xtables_error(PARAMETER_PROBLEM, "double --probability"); - prob = atof(optarg); - if (prob < 0 || prob > 1) - xtables_error(PARAMETER_PROBLEM, - "--probability must be between 0 and 1"); - info->u.random.probability = 0x80000000 * prob; - *flags |= 0x2; + case O_PROBABILITY: + info->u.random.probability = lround(0x80000000 * cb->val.dbl); break; - case '3': - if (*flags & 0x4) - xtables_error(PARAMETER_PROBLEM, "double --every"); - if (!xtables_strtoui(optarg, NULL, &val, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, - "cannot parse --every `%s'", optarg); - info->u.nth.every = val; - if (info->u.nth.every == 0) - xtables_error(PARAMETER_PROBLEM, "--every cannot be 0"); - info->u.nth.every--; - *flags |= 0x4; + case O_EVERY: + --info->u.nth.every; break; - case '4': - if (*flags & 0x8) - xtables_error(PARAMETER_PROBLEM, "double --packet"); - if (!xtables_strtoui(optarg, NULL, &val, 0, UINT32_MAX)) - xtables_error(PARAMETER_PROBLEM, - "cannot parse --packet `%s'", optarg); - info->u.nth.packet = val; - *flags |= 0x8; - break; - default: - return 0; } - return 1; } -static void statistic_check(unsigned int flags) +static void statistic_check(struct xt_fcheck_call *cb) { - if (!(flags & 0x1)) - xtables_error(PARAMETER_PROBLEM, "no mode specified"); - if ((flags & 0x2) && (flags & (0x4 | 0x8))) - xtables_error(PARAMETER_PROBLEM, - "both nth and random parameters given"); - if (flags & 0x2 && global_info->mode != XT_STATISTIC_MODE_RANDOM) - xtables_error(PARAMETER_PROBLEM, - "--probability can only be used in random mode"); - if (flags & 0x4 && global_info->mode != XT_STATISTIC_MODE_NTH) - xtables_error(PARAMETER_PROBLEM, - "--every can only be used in nth mode"); - if (flags & 0x8 && global_info->mode != XT_STATISTIC_MODE_NTH) + struct xt_statistic_info *info = cb->data; + + if (info->mode == XT_STATISTIC_MODE_RANDOM && + !(cb->xflags & F_PROBABILITY)) xtables_error(PARAMETER_PROBLEM, - "--packet can only be used in nth mode"); - if ((flags & 0x8) && !(flags & 0x4)) + "--probability must be specified when using " + "random mode"); + if (info->mode == XT_STATISTIC_MODE_NTH && + !(cb->xflags & (F_EVERY | F_PACKET))) xtables_error(PARAMETER_PROBLEM, - "--packet can only be used with --every"); + "--every and --packet must be specified when " + "using nth mode"); + /* at this point, info->u.nth.every have been decreased. */ - if (global_info->u.nth.packet > global_info->u.nth.every) + if (info->u.nth.packet > info->u.nth.every) xtables_error(PARAMETER_PROBLEM, "the --packet p must be 0 <= p <= n-1"); - - global_info->u.nth.count = global_info->u.nth.every - - global_info->u.nth.packet; + info->u.nth.count = info->u.nth.every - info->u.nth.packet; } static void print_match(const struct xt_statistic_info *info, char *prefix) { - if (info->flags & XT_STATISTIC_INVERT) - printf("! "); - switch (info->mode) { case XT_STATISTIC_MODE_RANDOM: - printf("%smode random %sprobability %f ", prefix, prefix, + printf(" %smode random%s %sprobability %.11f", prefix, + (info->flags & XT_STATISTIC_INVERT) ? " !" : "", + prefix, 1.0 * info->u.random.probability / 0x80000000); break; case XT_STATISTIC_MODE_NTH: - printf("%smode nth %severy %u ", prefix, prefix, + printf(" %smode nth%s %severy %u", prefix, + (info->flags & XT_STATISTIC_INVERT) ? " !" : "", + prefix, info->u.nth.every + 1); - if (info->u.nth.packet) - printf("%spacket %u ", prefix, info->u.nth.packet); + if (info->u.nth.packet || *prefix) + printf(" %spacket %u", prefix, info->u.nth.packet); break; } } @@ -148,7 +122,7 @@ statistic_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_statistic_info *info = (const void *)match->data; - printf("statistic "); + printf(" statistic"); print_match(info, ""); } @@ -165,13 +139,12 @@ static struct xtables_match statistic_match = { .version = XTABLES_VERSION, .size = XT_ALIGN(sizeof(struct xt_statistic_info)), .userspacesize = offsetof(struct xt_statistic_info, u.nth.count), - .init = statistic_mt_init, .help = statistic_help, - .parse = statistic_parse, - .final_check = statistic_check, + .x6_parse = statistic_parse, + .x6_fcheck = statistic_check, .print = statistic_print, .save = statistic_save, - .extra_opts = statistic_opts, + .x6_options = statistic_opts, }; void _init(void) diff --git a/extensions/libxt_statistic.man b/extensions/libxt_statistic.man index 8fc3b29..47182bf 100644 --- a/extensions/libxt_statistic.man +++ b/extensions/libxt_statistic.man @@ -11,13 +11,12 @@ Set the matching mode of the matching rule, supported modes are and .B nth. .TP -\fB\-\-probability\fP \fIp\fP -Set the probability from 0 to 1 for a packet to be randomly -matched. It works only with the -.B random -mode. +[\fB!\fP] \fB\-\-probability\fP \fIp\fP +Set the probability for a packet to be randomly matched. It only works with the +\fBrandom\fP mode. \fIp\fP must be within 0.0 and 1.0. The supported +granularity is in 1/2147483648th increments. .TP -\fB\-\-every\fP \fIn\fP +[\fB!\fP] \fB\-\-every\fP \fIn\fP Match one packet every nth packet. It works only with the .B nth mode (see also the diff --git a/extensions/libxt_string.c b/extensions/libxt_string.c index df6302e..fb15980 100644 --- a/extensions/libxt_string.c +++ b/extensions/libxt_string.c @@ -20,17 +20,26 @@ * updated to work with slightly modified * ipt_string_info. */ -#define _GNU_SOURCE 1 +#define _GNU_SOURCE 1 /* strnlen for older glibcs */ #include <stdio.h> -#include <netdb.h> #include <string.h> #include <stdlib.h> -#include <getopt.h> #include <ctype.h> #include <xtables.h> -#include <stddef.h> #include <linux/netfilter/xt_string.h> +enum { + O_FROM = 0, + O_TO, + O_ALGO, + O_ICASE, + O_STRING, + O_HEX_STRING, + F_STRING = 1 << O_STRING, + F_HEX_STRING = 1 << O_HEX_STRING, + F_OP_ANY = F_STRING | F_HEX_STRING, +}; + static void string_help(void) { printf( @@ -43,22 +52,28 @@ static void string_help(void) "[!] --hex-string string Match a hex string in a packet\n"); } -static const struct option string_opts[] = { - { "from", 1, NULL, '1' }, - { "to", 1, NULL, '2' }, - { "algo", 1, NULL, '3' }, - { "string", 1, NULL, '4' }, - { "hex-string", 1, NULL, '5' }, - { "icase", 0, NULL, '6' }, - { .name = NULL } +#define s struct xt_string_info +static const struct xt_option_entry string_opts[] = { + {.name = "from", .id = O_FROM, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, from_offset)}, + {.name = "to", .id = O_TO, .type = XTTYPE_UINT16, + .flags = XTOPT_PUT, XTOPT_POINTER(s, to_offset)}, + {.name = "algo", .id = O_ALGO, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_PUT, XTOPT_POINTER(s, algo)}, + {.name = "string", .id = O_STRING, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT, .excl = F_HEX_STRING}, + {.name = "hex-string", .id = O_HEX_STRING, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT, .excl = F_STRING}, + {.name = "icase", .id = O_ICASE, .type = XTTYPE_NONE}, + XTOPT_TABLEEND, }; +#undef s static void string_init(struct xt_entry_match *m) { struct xt_string_info *i = (struct xt_string_info *) m->data; - if (i->to_offset == 0) - i->to_offset = UINT16_MAX; + i->to_offset = UINT16_MAX; } static void @@ -74,17 +89,6 @@ parse_string(const char *s, struct xt_string_info *info) } static void -parse_algo(const char *s, struct xt_string_info *info) -{ - /* xt_string needs \0 for algo name */ - if (strlen(s) < XT_STRING_MAX_ALGO_NAME_SIZE) { - strncpy(info->algo, s, XT_STRING_MAX_ALGO_NAME_SIZE); - return; - } - xtables_error(PARAMETER_PROBLEM, "ALGO too long \"%s\"", s); -} - -static void parse_hex_string(const char *s, struct xt_string_info *info) { int i=0, slen, sindex=0, schar; @@ -162,97 +166,47 @@ parse_hex_string(const char *s, struct xt_string_info *info) info->patlen = sindex; } -#define STRING 0x1 -#define ALGO 0x2 -#define FROM 0x4 -#define TO 0x8 -#define ICASE 0x10 - -static int -string_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void string_parse(struct xt_option_call *cb) { - struct xt_string_info *stringinfo = - (struct xt_string_info *)(*match)->data; - const int revision = (*match)->u.user.revision; + struct xt_string_info *stringinfo = cb->data; + const unsigned int revision = (*cb->match)->u.user.revision; - switch (c) { - case '1': - if (*flags & FROM) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple --from"); - stringinfo->from_offset = atoi(optarg); - *flags |= FROM; - break; - case '2': - if (*flags & TO) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple --to"); - stringinfo->to_offset = atoi(optarg); - *flags |= TO; - break; - case '3': - if (*flags & ALGO) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple --algo"); - parse_algo(optarg, stringinfo); - *flags |= ALGO; - break; - case '4': - if (*flags & STRING) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple --string"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_string(optarg, stringinfo); - if (invert) { + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_STRING: + parse_string(cb->arg, stringinfo); + if (cb->invert) { if (revision == 0) stringinfo->u.v0.invert = 1; else stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT; } - *flags |= STRING; break; - - case '5': - if (*flags & STRING) - xtables_error(PARAMETER_PROBLEM, - "Can't specify multiple --hex-string"); - - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_hex_string(optarg, stringinfo); /* sets length */ - if (invert) { + case O_HEX_STRING: + parse_hex_string(cb->arg, stringinfo); /* sets length */ + if (cb->invert) { if (revision == 0) stringinfo->u.v0.invert = 1; else stringinfo->u.v1.flags |= XT_STRING_FLAG_INVERT; } - *flags |= STRING; break; - - case '6': + case O_ICASE: if (revision == 0) xtables_error(VERSION_PROBLEM, "Kernel doesn't support --icase"); stringinfo->u.v1.flags |= XT_STRING_FLAG_IGNORECASE; - *flags |= ICASE; break; - - default: - return 0; } - return 1; } -static void string_check(unsigned int flags) +static void string_check(struct xt_fcheck_call *cb) { - if (!(flags & STRING)) + if (!(cb->xflags & F_OP_ANY)) xtables_error(PARAMETER_PROBLEM, "STRING match: You must specify `--string' or " "`--hex-string'"); - if (!(flags & ALGO)) - xtables_error(PARAMETER_PROBLEM, - "STRING match: You must specify `--algo'"); } /* Test to see if the string contains non-printable chars or quotes */ @@ -264,7 +218,7 @@ is_hex_string(const char *str, const unsigned short int len) if (! isprint(str[i])) return 1; /* string contains at least one non-printable char */ /* use hex output if the last char is a "\" */ - if ((unsigned char) str[len-1] == 0x5c) + if (str[len-1] == '\\') return 1; return 0; } @@ -275,29 +229,24 @@ print_hex_string(const char *str, const unsigned short int len) { unsigned int i; /* start hex block */ - printf("\"|"); - for (i=0; i < len; i++) { - /* see if we need to prepend a zero */ - if ((unsigned char) str[i] <= 0x0F) - printf("0%x", (unsigned char) str[i]); - else - printf("%x", (unsigned char) str[i]); - } + printf(" \"|"); + for (i=0; i < len; i++) + printf("%02x", (unsigned char)str[i]); /* close hex block */ - printf("|\" "); + printf("|\""); } static void print_string(const char *str, const unsigned short int len) { unsigned int i; - printf("\""); + printf(" \""); for (i=0; i < len; i++) { - if ((unsigned char) str[i] == 0x22) /* escape any embedded quotes */ - printf("%c", 0x5c); + if (str[i] == '\"' || str[i] == '\\') + putchar('\\'); printf("%c", (unsigned char) str[i]); } - printf("\" "); /* closing space and quote */ + printf("\""); /* closing quote */ } static void @@ -310,19 +259,19 @@ string_print(const void *ip, const struct xt_entry_match *match, int numeric) info->u.v1.flags & XT_STRING_FLAG_INVERT); if (is_hex_string(info->pattern, info->patlen)) { - printf("STRING match %s", invert ? "!" : ""); + printf(" STRING match %s", invert ? "!" : ""); print_hex_string(info->pattern, info->patlen); } else { - printf("STRING match %s", invert ? "!" : ""); + printf(" STRING match %s", invert ? "!" : ""); print_string(info->pattern, info->patlen); } - printf("ALGO name %s ", info->algo); + printf(" ALGO name %s", info->algo); if (info->from_offset != 0) - printf("FROM %u ", info->from_offset); + printf(" FROM %u", info->from_offset); if (info->to_offset != 0) - printf("TO %u ", info->to_offset); + printf(" TO %u", info->to_offset); if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE) - printf("ICASE "); + printf(" ICASE"); } static void string_save(const void *ip, const struct xt_entry_match *match) @@ -334,19 +283,19 @@ static void string_save(const void *ip, const struct xt_entry_match *match) info->u.v1.flags & XT_STRING_FLAG_INVERT); if (is_hex_string(info->pattern, info->patlen)) { - printf("%s--hex-string ", (invert) ? "! ": ""); + printf("%s --hex-string", (invert) ? " !" : ""); print_hex_string(info->pattern, info->patlen); } else { - printf("%s--string ", (invert) ? "! ": ""); + printf("%s --string", (invert) ? " !": ""); print_string(info->pattern, info->patlen); } - printf("--algo %s ", info->algo); + printf(" --algo %s", info->algo); if (info->from_offset != 0) - printf("--from %u ", info->from_offset); + printf(" --from %u", info->from_offset); if (info->to_offset != 0) - printf("--to %u ", info->to_offset); + printf(" --to %u", info->to_offset); if (revision > 0 && info->u.v1.flags & XT_STRING_FLAG_IGNORECASE) - printf("--icase "); + printf(" --icase"); } @@ -360,11 +309,11 @@ static struct xtables_match string_mt_reg[] = { .userspacesize = offsetof(struct xt_string_info, config), .help = string_help, .init = string_init, - .parse = string_parse, - .final_check = string_check, .print = string_print, .save = string_save, - .extra_opts = string_opts, + .x6_parse = string_parse, + .x6_fcheck = string_check, + .x6_options = string_opts, }, { .name = "string", @@ -375,11 +324,11 @@ static struct xtables_match string_mt_reg[] = { .userspacesize = offsetof(struct xt_string_info, config), .help = string_help, .init = string_init, - .parse = string_parse, - .final_check = string_check, .print = string_print, .save = string_save, - .extra_opts = string_opts, + .x6_parse = string_parse, + .x6_fcheck = string_check, + .x6_options = string_opts, }, }; diff --git a/extensions/libxt_string.man b/extensions/libxt_string.man index b6b271d..adc9c18 100644 --- a/extensions/libxt_string.man +++ b/extensions/libxt_string.man @@ -16,3 +16,13 @@ Matches the given pattern. .TP [\fB!\fP] \fB\-\-hex\-string\fP \fIpattern\fP Matches the given pattern in hex notation. +.TP +Examples: +.IP +# The string pattern can be used for simple text characters. +.br +iptables \-A INPUT \-p tcp \-\-dport 80 \-m string \-\-algo bm \-\-string 'GET /index.html' \-j LOG +.IP +# The hex string pattern can be used for non-printable characters, like |0D 0A| or |0D0A|. +.br +iptables \-p udp \-\-dport 53 \-m string \-\-algo bm \-\-from 40 \-\-to 57 \-\-hex\-string '|03|www|09|netfilter|03|org|00|' diff --git a/extensions/libxt_tcp.c b/extensions/libxt_tcp.c index 75551d7..bbdec45 100644 --- a/extensions/libxt_tcp.c +++ b/extensions/libxt_tcp.c @@ -1,4 +1,5 @@ /* Shared library add-on to iptables to add TCP support. */ +#include <stdbool.h> #include <stdio.h> #include <netdb.h> #include <string.h> @@ -26,18 +27,18 @@ static void tcp_help(void) } static const struct option tcp_opts[] = { - { "source-port", 1, NULL, '1' }, - { "sport", 1, NULL, '1' }, /* synonym */ - { "destination-port", 1, NULL, '2' }, - { "dport", 1, NULL, '2' }, /* synonym */ - { "syn", 0, NULL, '3' }, - { "tcp-flags", 1, NULL, '4' }, - { "tcp-option", 1, NULL, '5' }, - { .name = NULL } + {.name = "source-port", .has_arg = true, .val = '1'}, + {.name = "sport", .has_arg = true, .val = '1'}, /* synonym */ + {.name = "destination-port", .has_arg = true, .val = '2'}, + {.name = "dport", .has_arg = true, .val = '2'}, /* synonym */ + {.name = "syn", .has_arg = false, .val = '3'}, + {.name = "tcp-flags", .has_arg = true, .val = '4'}, + {.name = "tcp-option", .has_arg = true, .val = '5'}, + XT_GETOPT_TABLEEND, }; static void -parse_tcp_ports(const char *portstring, u_int16_t *ports) +parse_tcp_ports(const char *portstring, uint16_t *ports) { char *buffer; char *cp; @@ -114,7 +115,7 @@ parse_tcp_flags(struct xt_tcp *tcpinfo, } static void -parse_tcp_option(const char *option, u_int8_t *result) +parse_tcp_option(const char *option, uint8_t *result) { unsigned int ret; @@ -147,7 +148,6 @@ tcp_parse(int c, char **argv, int invert, unsigned int *flags, if (*flags & TCP_SRC_PORTS) xtables_error(PARAMETER_PROBLEM, "Only one `--source-port' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_tcp_ports(optarg, tcpinfo->spts); if (invert) tcpinfo->invflags |= XT_TCP_INV_SRCPT; @@ -158,7 +158,6 @@ tcp_parse(int c, char **argv, int invert, unsigned int *flags, if (*flags & TCP_DST_PORTS) xtables_error(PARAMETER_PROBLEM, "Only one `--destination-port' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_tcp_ports(optarg, tcpinfo->dpts); if (invert) tcpinfo->invflags |= XT_TCP_INV_DSTPT; @@ -179,8 +178,6 @@ tcp_parse(int c, char **argv, int invert, unsigned int *flags, xtables_error(PARAMETER_PROBLEM, "Only one of `--syn' or `--tcp-flags' " " allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - if (!argv[optind] || argv[optind][0] == '-' || argv[optind][0] == '!') xtables_error(PARAMETER_PROBLEM, @@ -196,24 +193,20 @@ tcp_parse(int c, char **argv, int invert, unsigned int *flags, if (*flags & TCP_OPTION) xtables_error(PARAMETER_PROBLEM, "Only one `--tcp-option' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); parse_tcp_option(optarg, &tcpinfo->option); if (invert) tcpinfo->invflags |= XT_TCP_INV_OPTION; *flags |= TCP_OPTION; break; - - default: - return 0; } return 1; } -static char * +static const char * port_to_service(int port) { - struct servent *service; + const struct servent *service; if ((service = getservbyport(htons(port), "tcp"))) return service->s_name; @@ -222,9 +215,9 @@ port_to_service(int port) } static void -print_port(u_int16_t port, int numeric) +print_port(uint16_t port, int numeric) { - char *service; + const char *service; if (numeric || (service = port_to_service(port)) == NULL) printf("%u", port); @@ -233,13 +226,13 @@ print_port(u_int16_t port, int numeric) } static void -print_ports(const char *name, u_int16_t min, u_int16_t max, +print_ports(const char *name, uint16_t min, uint16_t max, int invert, int numeric) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFFFF || invert) { - printf("%s", name); + printf(" %s", name); if (min == max) { printf(":%s", inv); print_port(min, numeric); @@ -249,19 +242,18 @@ print_ports(const char *name, u_int16_t min, u_int16_t max, printf(":"); print_port(max, numeric); } - printf(" "); } } static void -print_option(u_int8_t option, int invert, int numeric) +print_option(uint8_t option, int invert, int numeric) { if (option || invert) - printf("option=%s%u ", invert ? "!" : "", option); + printf(" option=%s%u", invert ? "!" : "", option); } static void -print_tcpf(u_int8_t flags) +print_tcpf(uint8_t flags) { int have_flag = 0; @@ -283,17 +275,16 @@ print_tcpf(u_int8_t flags) } static void -print_flags(u_int8_t mask, u_int8_t cmp, int invert, int numeric) +print_flags(uint8_t mask, uint8_t cmp, int invert, int numeric) { if (mask || invert) { - printf("flags:%s", invert ? "!" : ""); + printf(" flags:%s", invert ? "!" : ""); if (numeric) - printf("0x%02X/0x%02X ", mask, cmp); + printf("0x%02X/0x%02X", mask, cmp); else { print_tcpf(mask); printf("/"); print_tcpf(cmp); - printf(" "); } } } @@ -303,7 +294,7 @@ tcp_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_tcp *tcp = (struct xt_tcp *)match->data; - printf("tcp "); + printf(" tcp"); print_ports("spt", tcp->spts[0], tcp->spts[1], tcp->invflags & XT_TCP_INV_SRCPT, numeric); @@ -317,7 +308,7 @@ tcp_print(const void *ip, const struct xt_entry_match *match, int numeric) tcp->invflags & XT_TCP_INV_FLAGS, numeric); if (tcp->invflags & ~XT_TCP_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", tcp->invflags & ~XT_TCP_INV_MASK); } @@ -328,49 +319,46 @@ static void tcp_save(const void *ip, const struct xt_entry_match *match) if (tcpinfo->spts[0] != 0 || tcpinfo->spts[1] != 0xFFFF) { if (tcpinfo->invflags & XT_TCP_INV_SRCPT) - printf("! "); + printf(" !"); if (tcpinfo->spts[0] != tcpinfo->spts[1]) - printf("--sport %u:%u ", + printf(" --sport %u:%u", tcpinfo->spts[0], tcpinfo->spts[1]); else - printf("--sport %u ", + printf(" --sport %u", tcpinfo->spts[0]); } if (tcpinfo->dpts[0] != 0 || tcpinfo->dpts[1] != 0xFFFF) { if (tcpinfo->invflags & XT_TCP_INV_DSTPT) - printf("! "); + printf(" !"); if (tcpinfo->dpts[0] != tcpinfo->dpts[1]) - printf("--dport %u:%u ", + printf(" --dport %u:%u", tcpinfo->dpts[0], tcpinfo->dpts[1]); else - printf("--dport %u ", + printf(" --dport %u", tcpinfo->dpts[0]); } if (tcpinfo->option || (tcpinfo->invflags & XT_TCP_INV_OPTION)) { if (tcpinfo->invflags & XT_TCP_INV_OPTION) - printf("! "); - printf("--tcp-option %u ", tcpinfo->option); + printf(" !"); + printf(" --tcp-option %u", tcpinfo->option); } if (tcpinfo->flg_mask || (tcpinfo->invflags & XT_TCP_INV_FLAGS)) { if (tcpinfo->invflags & XT_TCP_INV_FLAGS) - printf("! "); - printf("--tcp-flags "); - if (tcpinfo->flg_mask != 0xFF) { - print_tcpf(tcpinfo->flg_mask); - } + printf(" !"); + printf(" --tcp-flags "); + print_tcpf(tcpinfo->flg_mask); printf(" "); print_tcpf(tcpinfo->flg_cmp); - printf(" "); } } diff --git a/extensions/libxt_tcpmss.c b/extensions/libxt_tcpmss.c index b54a890..c7c5971 100644 --- a/extensions/libxt_tcpmss.c +++ b/extensions/libxt_tcpmss.c @@ -1,13 +1,11 @@ -/* Shared library add-on to iptables to add tcp MSS matching support. */ #include <stdio.h> -#include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> - #include <xtables.h> #include <linux/netfilter/xt_tcpmss.h> +enum { + O_TCPMSS = 0, +}; + static void tcpmss_help(void) { printf( @@ -16,73 +14,23 @@ static void tcpmss_help(void) " (only valid for TCP SYN or SYN/ACK packets)\n"); } -static const struct option tcpmss_opts[] = { - { "mss", 1, NULL, '1' }, - { .name = NULL } +static const struct xt_option_entry tcpmss_opts[] = { + {.name = "mss", .id = O_TCPMSS, .type = XTTYPE_UINT16RC, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; -static u_int16_t -parse_tcp_mssvalue(const char *mssvalue) -{ - unsigned int mssvaluenum; - - if (xtables_strtoui(mssvalue, NULL, &mssvaluenum, 0, UINT16_MAX)) - return mssvaluenum; - - xtables_error(PARAMETER_PROBLEM, - "Invalid mss `%s' specified", mssvalue); -} - -static void -parse_tcp_mssvalues(const char *mssvaluestring, - u_int16_t *mss_min, u_int16_t *mss_max) -{ - char *buffer; - char *cp; - - buffer = strdup(mssvaluestring); - if ((cp = strchr(buffer, ':')) == NULL) - *mss_min = *mss_max = parse_tcp_mssvalue(buffer); - else { - *cp = '\0'; - cp++; - - *mss_min = buffer[0] ? parse_tcp_mssvalue(buffer) : 0; - *mss_max = cp[0] ? parse_tcp_mssvalue(cp) : 0xFFFF; - } - free(buffer); -} - -static int -tcpmss_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) -{ - struct xt_tcpmss_match_info *mssinfo = - (struct xt_tcpmss_match_info *)(*match)->data; - - switch (c) { - case '1': - if (*flags) - xtables_error(PARAMETER_PROBLEM, - "Only one `--mss' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_tcp_mssvalues(optarg, - &mssinfo->mss_min, &mssinfo->mss_max); - if (invert) - mssinfo->invert = 1; - *flags = 1; - break; - default: - return 0; - } - return 1; -} - -static void tcpmss_check(unsigned int flags) +static void tcpmss_parse(struct xt_option_call *cb) { - if (!flags) - xtables_error(PARAMETER_PROBLEM, - "tcpmss match: You must specify `--mss'"); + struct xt_tcpmss_match_info *mssinfo = cb->data; + + xtables_option_parse(cb); + mssinfo->mss_min = cb->val.u16_range[0]; + mssinfo->mss_max = mssinfo->mss_min; + if (cb->nvals == 2) + mssinfo->mss_max = cb->val.u16_range[1]; + if (cb->invert) + mssinfo->invert = 1; } static void @@ -90,22 +38,22 @@ tcpmss_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_tcpmss_match_info *info = (void *)match->data; - printf("tcpmss match %s", info->invert ? "!" : ""); + printf(" tcpmss match %s", info->invert ? "!" : ""); if (info->mss_min == info->mss_max) - printf("%u ", info->mss_min); + printf("%u", info->mss_min); else - printf("%u:%u ", info->mss_min, info->mss_max); + printf("%u:%u", info->mss_min, info->mss_max); } static void tcpmss_save(const void *ip, const struct xt_entry_match *match) { const struct xt_tcpmss_match_info *info = (void *)match->data; - printf("%s--mss ", info->invert ? "! " : ""); + printf("%s --mss ", info->invert ? " !" : ""); if (info->mss_min == info->mss_max) - printf("%u ", info->mss_min); + printf("%u", info->mss_min); else - printf("%u:%u ", info->mss_min, info->mss_max); + printf("%u:%u", info->mss_min, info->mss_max); } static struct xtables_match tcpmss_match = { @@ -115,11 +63,10 @@ static struct xtables_match tcpmss_match = { .size = XT_ALIGN(sizeof(struct xt_tcpmss_match_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_tcpmss_match_info)), .help = tcpmss_help, - .parse = tcpmss_parse, - .final_check = tcpmss_check, .print = tcpmss_print, .save = tcpmss_save, - .extra_opts = tcpmss_opts, + .x6_parse = tcpmss_parse, + .x6_options = tcpmss_opts, }; void _init(void) diff --git a/extensions/libxt_time.c b/extensions/libxt_time.c index 098fc9c..9c5bda8 100644 --- a/extensions/libxt_time.c +++ b/extensions/libxt_time.c @@ -9,44 +9,52 @@ * * Based on libipt_time.c. */ -#include <sys/types.h> -#include <getopt.h> -#include <stdbool.h> -#include <stdint.h> #include <stdio.h> #include <string.h> #include <stdlib.h> -#include <stddef.h> #include <time.h> -#include <limits.h> - +#include <linux/types.h> #include <linux/netfilter/xt_time.h> #include <xtables.h> -enum { /* getopt "seen" bits */ - F_DATE_START = 1 << 0, - F_DATE_STOP = 1 << 1, - F_TIME_START = 1 << 2, - F_TIME_STOP = 1 << 3, - F_MONTHDAYS = 1 << 4, - F_WEEKDAYS = 1 << 5, - F_TIMEZONE = 1 << 6, +enum { + O_DATE_START = 0, + O_DATE_STOP, + O_TIME_START, + O_TIME_STOP, + O_TIME_CONTIGUOUS, + O_MONTHDAYS, + O_WEEKDAYS, + O_LOCAL_TZ, + O_UTC, + O_KERNEL_TZ, + F_LOCAL_TZ = 1 << O_LOCAL_TZ, + F_UTC = 1 << O_UTC, + F_KERNEL_TZ = 1 << O_KERNEL_TZ, + F_TIME_CONTIGUOUS = 1 << O_TIME_CONTIGUOUS, }; static const char *const week_days[] = { NULL, "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", }; -static const struct option time_opts[] = { - {"datestart", true, NULL, 'D'}, - {"datestop", true, NULL, 'E'}, - {"timestart", true, NULL, 'X'}, - {"timestop", true, NULL, 'Y'}, - {"weekdays", true, NULL, 'w'}, - {"monthdays", true, NULL, 'm'}, - {"localtz", false, NULL, 'l'}, - {"utc", false, NULL, 'u'}, - { .name = NULL } +static const struct xt_option_entry time_opts[] = { + {.name = "datestart", .id = O_DATE_START, .type = XTTYPE_STRING}, + {.name = "datestop", .id = O_DATE_STOP, .type = XTTYPE_STRING}, + {.name = "timestart", .id = O_TIME_START, .type = XTTYPE_STRING}, + {.name = "timestop", .id = O_TIME_STOP, .type = XTTYPE_STRING}, + {.name = "contiguous", .id = O_TIME_CONTIGUOUS, .type = XTTYPE_NONE}, + {.name = "weekdays", .id = O_WEEKDAYS, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "monthdays", .id = O_MONTHDAYS, .type = XTTYPE_STRING, + .flags = XTOPT_INVERT}, + {.name = "localtz", .id = O_LOCAL_TZ, .type = XTTYPE_NONE, + .excl = F_UTC}, + {.name = "utc", .id = O_UTC, .type = XTTYPE_NONE, + .excl = F_LOCAL_TZ | F_KERNEL_TZ}, + {.name = "kerneltz", .id = O_KERNEL_TZ, .type = XTTYPE_NONE, + .excl = F_UTC}, + XTOPT_TABLEEND, }; static void time_help(void) @@ -62,7 +70,7 @@ static void time_help(void) "[!] --weekdays value List of weekdays on which to match, sep. by comma\n" " (Possible days: Mon,Tue,Wed,Thu,Fri,Sat,Sun or 1 to 7\n" " Defaults to all weekdays.)\n" -" --localtz/--utc Time is interpreted as UTC/local time\n"); +" --kerneltz Work with the kernel timezone instead of UTC\n"); } static void time_init(struct xt_entry_match *m) @@ -78,9 +86,6 @@ static void time_init(struct xt_entry_match *m) /* ...and have no date-begin or date-end boundary */ info->date_start = 0; info->date_stop = INT_MAX; - - /* local time is default */ - info->flags |= XT_TIME_LOCAL_TZ; } static time_t time_parse_date(const char *s, bool end) @@ -138,6 +143,13 @@ static time_t time_parse_date(const char *s, bool end) tm.tm_hour = hour; tm.tm_min = minute; tm.tm_sec = second; + tm.tm_isdst = 0; + /* + * Offsetting, if any, is done by xt_time.ko, + * so we have to disable it here in userspace. + */ + setenv("TZ", "UTC", true); + tzset(); ret = mktime(&tm); if (ret >= 0) return ret; @@ -246,86 +258,47 @@ static unsigned int time_parse_weekdays(const char *arg) return ret; } -static int time_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void time_parse(struct xt_option_call *cb) { - struct xt_time_info *info = (void *)(*match)->data; - - switch (c) { - case 'D': /* --datestart */ - if (*flags & F_DATE_START) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --datestart twice"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "Unexpected \"!\" with --datestart"); - info->date_start = time_parse_date(optarg, false); - *flags |= F_DATE_START; - return 1; - case 'E': /* --datestop */ - if (*flags & F_DATE_STOP) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --datestop more than once"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "unexpected \"!\" with --datestop"); - info->date_stop = time_parse_date(optarg, true); - *flags |= F_DATE_STOP; - return 1; - case 'X': /* --timestart */ - if (*flags & F_TIME_START) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --timestart more than once"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "Unexpected \"!\" with --timestart"); - info->daytime_start = time_parse_minutes(optarg); - *flags |= F_TIME_START; - return 1; - case 'Y': /* --timestop */ - if (*flags & F_TIME_STOP) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --timestop more than once"); - if (invert) - xtables_error(PARAMETER_PROBLEM, - "Unexpected \"!\" with --timestop"); - info->daytime_stop = time_parse_minutes(optarg); - *flags |= F_TIME_STOP; - return 1; - case 'l': /* --localtz */ - if (*flags & F_TIMEZONE) - xtables_error(PARAMETER_PROBLEM, - "Can only specify exactly one of --localtz or --utc"); + struct xt_time_info *info = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_DATE_START: + info->date_start = time_parse_date(cb->arg, false); + break; + case O_DATE_STOP: + info->date_stop = time_parse_date(cb->arg, true); + break; + case O_TIME_START: + info->daytime_start = time_parse_minutes(cb->arg); + break; + case O_TIME_STOP: + info->daytime_stop = time_parse_minutes(cb->arg); + break; + case O_TIME_CONTIGUOUS: + info->flags |= XT_TIME_CONTIGUOUS; + break; + case O_LOCAL_TZ: + fprintf(stderr, "WARNING: --localtz is being replaced by " + "--kerneltz, since \"local\" is ambiguous. Note the " + "kernel timezone has caveats - " + "see manpage for details.\n"); + /* fallthrough */ + case O_KERNEL_TZ: info->flags |= XT_TIME_LOCAL_TZ; - *flags |= F_TIMEZONE; - return 1; - case 'm': /* --monthdays */ - if (*flags & F_MONTHDAYS) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --monthdays more than once"); - info->monthdays_match = time_parse_monthdays(optarg); - if (invert) + break; + case O_MONTHDAYS: + info->monthdays_match = time_parse_monthdays(cb->arg); + if (cb->invert) info->monthdays_match ^= XT_TIME_ALL_MONTHDAYS; - *flags |= F_MONTHDAYS; - return 1; - case 'w': /* --weekdays */ - if (*flags & F_WEEKDAYS) - xtables_error(PARAMETER_PROBLEM, - "Cannot specify --weekdays more than once"); - info->weekdays_match = time_parse_weekdays(optarg); - if (invert) + break; + case O_WEEKDAYS: + info->weekdays_match = time_parse_weekdays(cb->arg); + if (cb->invert) info->weekdays_match ^= XT_TIME_ALL_WEEKDAYS; - *flags |= F_WEEKDAYS; - return 1; - case 'u': /* --utc */ - if (*flags & F_TIMEZONE) - xtables_error(PARAMETER_PROBLEM, - "Can only specify exactly one of --localtz or --utc"); - info->flags &= ~XT_TIME_LOCAL_TZ; - *flags |= F_TIMEZONE; - return 1; + break; } - return 0; } static void time_print_date(time_t date, const char *command) @@ -336,17 +309,17 @@ static void time_print_date(time_t date, const char *command) if (date == 0 || date == LONG_MAX) return; - t = localtime(&date); + t = gmtime(&date); if (command != NULL) /* * Need a contiguous string (no whitespaces), hence using * the ISO 8601 "T" variant. */ - printf("%s %04u-%02u-%02uT%02u:%02u:%02u ", + printf(" %s %04u-%02u-%02uT%02u:%02u:%02u", command, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); else - printf("%04u-%02u-%02u %02u:%02u:%02u ", + printf(" %04u-%02u-%02u %02u:%02u:%02u", t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); } @@ -355,6 +328,7 @@ static void time_print_monthdays(uint32_t mask, bool human_readable) { unsigned int i, nbdays = 0; + printf(" "); for (i = 1; i <= 31; ++i) if (mask & (1 << i)) { if (nbdays++ > 0) @@ -376,13 +350,13 @@ static void time_print_monthdays(uint32_t mask, bool human_readable) break; } } - printf(" "); } static void time_print_weekdays(unsigned int mask) { unsigned int i, nbdays = 0; + printf(" "); for (i = 1; i <= 7; ++i) if (mask & (1 << i)) { if (nbdays > 0) @@ -391,7 +365,6 @@ static void time_print_weekdays(unsigned int mask) printf("%s", week_days[i]); ++nbdays; } - printf(" "); } static inline void divide_time(unsigned int fulltime, unsigned int *hours, @@ -409,33 +382,35 @@ static void time_print(const void *ip, const struct xt_entry_match *match, const struct xt_time_info *info = (const void *)match->data; unsigned int h, m, s; - printf("TIME "); + printf(" TIME"); if (info->daytime_start != XT_TIME_MIN_DAYTIME || info->daytime_stop != XT_TIME_MAX_DAYTIME) { divide_time(info->daytime_start, &h, &m, &s); - printf("from %02u:%02u:%02u ", h, m, s); + printf(" from %02u:%02u:%02u", h, m, s); divide_time(info->daytime_stop, &h, &m, &s); - printf("to %02u:%02u:%02u ", h, m, s); + printf(" to %02u:%02u:%02u", h, m, s); } if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) { - printf("on "); + printf(" on"); time_print_weekdays(info->weekdays_match); } if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) { - printf("on "); + printf(" on"); time_print_monthdays(info->monthdays_match, true); } if (info->date_start != 0) { - printf("starting from "); + printf(" starting from"); time_print_date(info->date_start, NULL); } if (info->date_stop != INT_MAX) { - printf("until date "); + printf(" until date"); time_print_date(info->date_stop, NULL); } if (!(info->flags & XT_TIME_LOCAL_TZ)) - printf("UTC "); + printf(" UTC"); + if (info->flags & XT_TIME_CONTIGUOUS) + printf(" contiguous"); } static void time_save(const void *ip, const struct xt_entry_match *match) @@ -446,23 +421,33 @@ static void time_save(const void *ip, const struct xt_entry_match *match) if (info->daytime_start != XT_TIME_MIN_DAYTIME || info->daytime_stop != XT_TIME_MAX_DAYTIME) { divide_time(info->daytime_start, &h, &m, &s); - printf("--timestart %02u:%02u:%02u ", h, m, s); + printf(" --timestart %02u:%02u:%02u", h, m, s); divide_time(info->daytime_stop, &h, &m, &s); - printf("--timestop %02u:%02u:%02u ", h, m, s); + printf(" --timestop %02u:%02u:%02u", h, m, s); } if (info->monthdays_match != XT_TIME_ALL_MONTHDAYS) { - printf("--monthdays "); + printf(" --monthdays"); time_print_monthdays(info->monthdays_match, false); } if (info->weekdays_match != XT_TIME_ALL_WEEKDAYS) { - printf("--weekdays "); + printf(" --weekdays"); time_print_weekdays(info->weekdays_match); - printf(" "); } time_print_date(info->date_start, "--datestart"); time_print_date(info->date_stop, "--datestop"); - if (!(info->flags & XT_TIME_LOCAL_TZ)) - printf("--utc "); + if (info->flags & XT_TIME_LOCAL_TZ) + printf(" --kerneltz"); + if (info->flags & XT_TIME_CONTIGUOUS) + printf(" --contiguous"); +} + +static void time_check(struct xt_fcheck_call *cb) +{ + const struct xt_time_info *info = (const void *) cb->data; + if ((cb->xflags & F_TIME_CONTIGUOUS) && + info->daytime_start < info->daytime_stop) + xtables_error(PARAMETER_PROBLEM, + "time: --contiguous only makes sense when stoptime is smaller than starttime"); } static struct xtables_match time_match = { @@ -473,10 +458,11 @@ static struct xtables_match time_match = { .userspacesize = XT_ALIGN(sizeof(struct xt_time_info)), .help = time_help, .init = time_init, - .parse = time_parse, .print = time_print, .save = time_save, - .extra_opts = time_opts, + .x6_parse = time_parse, + .x6_fcheck = time_check, + .x6_options = time_opts, }; void _init(void) diff --git a/extensions/libxt_time.man b/extensions/libxt_time.man index 83625a2..4c0cae0 100644 --- a/extensions/libxt_time.man +++ b/extensions/libxt_time.man @@ -1,10 +1,10 @@ This matches if the packet arrival time/date is within a given range. All -options are optional, but are ANDed when specified. +options are optional, but are ANDed when specified. All times are interpreted +as UTC by default. .TP \fB\-\-datestart\fP \fIYYYY\fP[\fB\-\fP\fIMM\fP[\fB\-\fP\fIDD\fP[\fBT\fP\fIhh\fP[\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]]]]] .TP \fB\-\-datestop\fP \fIYYYY\fP[\fB\-\fP\fIMM\fP[\fB\-\fP\fIDD\fP[\fBT\fP\fIhh\fP[\fB:\fP\fImm\fP[\fB:\fP\fIss\fP]]]]] -.IP Only match during the given time, which must be in ISO 8601 "T" notation. The possible time range is 1970-01-01T00:00:00 to 2038-01-19T04:17:07. .IP @@ -14,34 +14,55 @@ and 2038-01-19, respectively. \fB\-\-timestart\fP \fIhh\fP\fB:\fP\fImm\fP[\fB:\fP\fIss\fP] .TP \fB\-\-timestop\fP \fIhh\fP\fB:\fP\fImm\fP[\fB:\fP\fIss\fP] -.IP Only match during the given daytime. The possible time range is 00:00:00 to 23:59:59. Leading zeroes are allowed (e.g. "06:03") and correctly interpreted as base-10. .TP -[\fB!\fR] \fB\-\-monthdays\fP \fIday\fP[\fB,\fP\fIday\fP...] -.IP -Only match on the given days of the month. Possible values are \fB1\fR -to \fB31\fR. Note that specifying \fB31\fR will of course not match +[\fB!\fP] \fB\-\-monthdays\fP \fIday\fP[\fB,\fP\fIday\fP...] +Only match on the given days of the month. Possible values are \fB1\fP +to \fB31\fP. Note that specifying \fB31\fP will of course not match on months which do not have a 31st day; the same goes for 28- or 29-day February. .TP -[\fB!\fR] \fB\-\-weekdays\fP \fIday\fP[\fB,\fP\fIday\fP...] -.IP -Only match on the given weekdays. Possible values are \fBMon\fR, \fBTue\fR, -\fBWed\fR, \fBThu\fR, \fBFri\fR, \fBSat\fR, \fBSun\fR, or values from \fB1\fR -to \fB7\fR, respectively. You may also use two-character variants (\fBMo\fP, -\fBTu\fR, etc.). +[\fB!\fP] \fB\-\-weekdays\fP \fIday\fP[\fB,\fP\fIday\fP...] +Only match on the given weekdays. Possible values are \fBMon\fP, \fBTue\fP, +\fBWed\fP, \fBThu\fP, \fBFri\fP, \fBSat\fP, \fBSun\fP, or values from \fB1\fP +to \fB7\fP, respectively. You may also use two-character variants (\fBMo\fP, +\fBTu\fP, etc.). .TP -\fB\-\-utc\fP -.IP -Interpret the times given for \fB\-\-datestart\fP, \fB\-\-datestop\fP, -\fB\-\-timestart\fP and \fB\-\-timestop\fP to be UTC. +\fB\-\-contiguous\fP +When \fB\-\-timestop\fP is smaller than \fB\-\-timestart\fP value, match +this as a single time period instead distinct intervals. See EXAMPLES. .TP -\fB\-\-localtz\fP -.IP -Interpret the times given for \fB\-\-datestart\fP, \fB\-\-datestop\fP, -\fB\-\-timestart\fP and \fB\-\-timestop\fP to be local kernel time. (Default) +\fB\-\-kerneltz\fP +Use the kernel timezone instead of UTC to determine whether a packet meets the +time regulations. +.PP +About kernel timezones: Linux keeps the system time in UTC, and always does so. +On boot, system time is initialized from a referential time source. Where this +time source has no timezone information, such as the x86 CMOS RTC, UTC will be +assumed. If the time source is however not in UTC, userspace should provide the +correct system time and timezone to the kernel once it has the information. +.PP +Local time is a feature on top of the (timezone independent) system time. Each +process has its own idea of local time, specified via the TZ environment +variable. The kernel also has its own timezone offset variable. The TZ +userspace environment variable specifies how the UTC-based system time is +displayed, e.g. when you run date(1), or what you see on your desktop clock. +The TZ string may resolve to different offsets at different dates, which is +what enables the automatic time-jumping in userspace. when DST changes. The +kernel's timezone offset variable is used when it has to convert between +non-UTC sources, such as FAT filesystems, to UTC (since the latter is what the +rest of the system uses). +.PP +The caveat with the kernel timezone is that Linux distributions may ignore to +set the kernel timezone, and instead only set the system time. Even if a +particular distribution does set the timezone at boot, it is usually does not +keep the kernel timezone offset - which is what changes on DST - up to date. +ntpd will not touch the kernel timezone, so running it will not resolve the +issue. As such, one may encounter a timezone that is always +0000, or one that +is wrong half of the time of the year. As such, \fBusing \-\-kerneltz is highly +discouraged.\fP .PP EXAMPLES. To match on weekends, use: .IP @@ -67,3 +88,11 @@ The fourth Friday in the month: (Note that this exploits a certain mathematical property. It is not possible to say "fourth Thursday OR fourth Friday" in one rule. It is possible with multiple rules, though.) +.PP +Matching across days might not do what is expected. For instance, +.IP +\-m time \-\-weekdays Mo \-\-timestart 23:00 \-\-timestop 01:00 +Will match Monday, for one hour from midnight to 1 a.m., and then +again for another hour from 23:00 onwards. If this is unwanted, e.g. if you +would like 'match for two hours from Montay 23:00 onwards' you need to also specify +the \-\-contiguous option in the example above. diff --git a/extensions/libxt_tos.c b/extensions/libxt_tos.c index 6b8cd89..81c096f 100644 --- a/extensions/libxt_tos.c +++ b/extensions/libxt_tos.c @@ -16,17 +16,24 @@ #include "tos_values.c" struct ipt_tos_info { - u_int8_t tos; - u_int8_t invert; + uint8_t tos; + uint8_t invert; }; enum { - FLAG_TOS = 1 << 0, + O_TOS = 1 << 0, }; -static const struct option tos_mt_opts[] = { - {.name = "tos", .has_arg = true, .val = 't'}, - { .name = NULL } +static const struct xt_option_entry tos_mt_opts_v0[] = { + {.name = "tos", .id = O_TOS, .type = XTTYPE_TOSMASK, + .flags = XTOPT_INVERT | XTOPT_MAND, .max = 0xFF}, + XTOPT_TABLEEND, +}; + +static const struct xt_option_entry tos_mt_opts[] = { + {.name = "tos", .id = O_TOS, .type = XTTYPE_TOSMASK, + .flags = XTOPT_INVERT | XTOPT_MAND, .max = 0x3F}, + XTOPT_TABLEEND, }; static void tos_mt_help(void) @@ -46,56 +53,29 @@ static void tos_mt_help(void) printf("\n"); } -static int tos_mt_parse_v0(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void tos_mt_parse_v0(struct xt_option_call *cb) { - struct ipt_tos_info *info = (void *)(*match)->data; - struct tos_value_mask tvm; - - switch (c) { - case 't': - xtables_param_act(XTF_ONLY_ONCE, "tos", "--tos", *flags & FLAG_TOS); - if (!tos_parse_symbolic(optarg, &tvm, 0xFF)) - xtables_param_act(XTF_BAD_VALUE, "tos", "--tos", optarg); - if (tvm.mask != 0xFF) - xtables_error(PARAMETER_PROBLEM, "tos: Your kernel is " - "too old to support anything besides /0xFF " - "as a mask."); - info->tos = tvm.value; - if (invert) - info->invert = true; - *flags |= FLAG_TOS; - return true; - } - return false; + struct ipt_tos_info *info = cb->data; + + xtables_option_parse(cb); + if (cb->val.tos_mask != 0xFF) + xtables_error(PARAMETER_PROBLEM, "tos: Your kernel is " + "too old to support anything besides /0xFF " + "as a mask."); + info->tos = cb->val.tos_value; + if (cb->invert) + info->invert = true; } -static int tos_mt_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void tos_mt_parse(struct xt_option_call *cb) { - struct xt_tos_match_info *info = (void *)(*match)->data; - struct tos_value_mask tvm = {.mask = 0xFF}; - - switch (c) { - case 't': - xtables_param_act(XTF_ONLY_ONCE, "tos", "--tos", *flags & FLAG_TOS); - if (!tos_parse_symbolic(optarg, &tvm, 0x3F)) - xtables_param_act(XTF_BAD_VALUE, "tos", "--tos", optarg); - info->tos_value = tvm.value; - info->tos_mask = tvm.mask; - if (invert) - info->invert = true; - *flags |= FLAG_TOS; - return true; - } - return false; -} + struct xt_tos_match_info *info = cb->data; -static void tos_mt_check(unsigned int flags) -{ - if (flags == 0) - xtables_error(PARAMETER_PROBLEM, - "tos: --tos parameter required"); + xtables_option_parse(cb); + info->tos_value = cb->val.tos_value; + info->tos_mask = cb->val.tos_mask; + if (cb->invert) + info->invert = true; } static void tos_mt_print_v0(const void *ip, const struct xt_entry_match *match, @@ -103,11 +83,11 @@ static void tos_mt_print_v0(const void *ip, const struct xt_entry_match *match, { const struct ipt_tos_info *info = (const void *)match->data; - printf("tos match "); + printf(" tos match "); if (info->invert) printf("!"); if (numeric || !tos_try_print_symbolic("", info->tos, 0x3F)) - printf("0x%02x ", info->tos); + printf("0x%02x", info->tos); } static void tos_mt_print(const void *ip, const struct xt_entry_match *match, @@ -115,12 +95,12 @@ static void tos_mt_print(const void *ip, const struct xt_entry_match *match, { const struct xt_tos_match_info *info = (const void *)match->data; - printf("tos match "); + printf(" tos match"); if (info->invert) printf("!"); if (numeric || !tos_try_print_symbolic("", info->tos_value, info->tos_mask)) - printf("0x%02x/0x%02x ", info->tos_value, info->tos_mask); + printf("0x%02x/0x%02x", info->tos_value, info->tos_mask); } static void tos_mt_save_v0(const void *ip, const struct xt_entry_match *match) @@ -128,8 +108,8 @@ static void tos_mt_save_v0(const void *ip, const struct xt_entry_match *match) const struct ipt_tos_info *info = (const void *)match->data; if (info->invert) - printf("! "); - printf("--tos 0x%02x ", info->tos); + printf(" !"); + printf(" --tos 0x%02x", info->tos); } static void tos_mt_save(const void *ip, const struct xt_entry_match *match) @@ -137,8 +117,8 @@ static void tos_mt_save(const void *ip, const struct xt_entry_match *match) const struct xt_tos_match_info *info = (const void *)match->data; if (info->invert) - printf("! "); - printf("--tos 0x%02x/0x%02x ", info->tos_value, info->tos_mask); + printf(" !"); + printf(" --tos 0x%02x/0x%02x", info->tos_value, info->tos_mask); } static struct xtables_match tos_mt_reg[] = { @@ -150,11 +130,10 @@ static struct xtables_match tos_mt_reg[] = { .size = XT_ALIGN(sizeof(struct ipt_tos_info)), .userspacesize = XT_ALIGN(sizeof(struct ipt_tos_info)), .help = tos_mt_help, - .parse = tos_mt_parse_v0, - .final_check = tos_mt_check, .print = tos_mt_print_v0, .save = tos_mt_save_v0, - .extra_opts = tos_mt_opts, + .x6_parse = tos_mt_parse_v0, + .x6_options = tos_mt_opts_v0, }, { .version = XTABLES_VERSION, @@ -164,11 +143,10 @@ static struct xtables_match tos_mt_reg[] = { .size = XT_ALIGN(sizeof(struct xt_tos_match_info)), .userspacesize = XT_ALIGN(sizeof(struct xt_tos_match_info)), .help = tos_mt_help, - .parse = tos_mt_parse, - .final_check = tos_mt_check, .print = tos_mt_print, .save = tos_mt_save, - .extra_opts = tos_mt_opts, + .x6_parse = tos_mt_parse, + .x6_options = tos_mt_opts, }, }; diff --git a/extensions/libxt_u32.c b/extensions/libxt_u32.c index 9a61c8a..2a7f5d8 100644 --- a/extensions/libxt_u32.c +++ b/extensions/libxt_u32.c @@ -10,21 +10,22 @@ * Copyright © CC Computer Consultants GmbH, 2007 * Contact: <jengelh@computergmbh.de> */ -#include <sys/types.h> #include <ctype.h> #include <errno.h> -#include <getopt.h> -#include <netdb.h> +#include <stdint.h> #include <stdlib.h> #include <stdio.h> -#include <string.h> - #include <xtables.h> #include <linux/netfilter/xt_u32.h> -static const struct option u32_opts[] = { - {"u32", 1, NULL, 'u'}, - { .name = NULL } +enum { + O_U32 = 0, +}; + +static const struct xt_option_entry u32_opts[] = { + {.name = "u32", .id = O_U32, .type = XTTYPE_STRING, + .flags = XTOPT_MAND | XTOPT_INVERT}, + XTOPT_TABLEEND, }; static void u32_help(void) @@ -44,6 +45,7 @@ static void u32_dump(const struct xt_u32 *data) const struct xt_u32_test *ct; unsigned int testind, i; + printf(" \""); for (testind = 0; testind < data->ntests; ++testind) { ct = &data->tests[testind]; @@ -80,41 +82,34 @@ static void u32_dump(const struct xt_u32 *data) ct->value[i].max); } } - printf(" "); + putchar('\"'); } /* string_to_number() is not quite what we need here ... */ -static u_int32_t parse_number(char **s, int pos) +static uint32_t parse_number(const char **s, int pos) { - u_int32_t number; + unsigned int number; char *end; - errno = 0; - number = strtoul(*s, &end, 0); - if (end == *s) + if (!xtables_strtoui(*s, &end, &number, 0, UINT32_MAX) || + end == *s) xtables_error(PARAMETER_PROBLEM, - "u32: at char %d: expected number", pos); - if (errno != 0) - xtables_error(PARAMETER_PROBLEM, - "u32: at char %d: error reading number", pos); + "u32: at char %d: not a number or out of range", pos); *s = end; return number; } -static int u32_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void u32_parse(struct xt_option_call *cb) { - struct xt_u32 *data = (void *)(*match)->data; + struct xt_u32 *data = cb->data; unsigned int testind = 0, locind = 0, valind = 0; struct xt_u32_test *ct = &data->tests[testind]; /* current test */ - char *arg = optarg; /* the argument string */ - char *start = arg; + const char *arg = cb->arg; /* the argument string */ + const char *start = cb->arg; int state = 0; - if (c != 'u') - return 0; - - data->invert = invert; + xtables_option_parse(cb); + data->invert = cb->invert; /* * states: @@ -143,7 +138,7 @@ static int u32_parse(int c, char **argv, int invert, unsigned int *flags, xtables_error(PARAMETER_PROBLEM, "u32: at char %u: too many \"&&\"s", (unsigned int)(arg - start)); - return 1; + return; } if (state == 0) { @@ -250,9 +245,9 @@ static void u32_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_u32 *data = (const void *)match->data; - printf("u32 "); + printf(" u32"); if (data->invert) - printf("! "); + printf(" !"); u32_dump(data); } @@ -260,8 +255,8 @@ static void u32_save(const void *ip, const struct xt_entry_match *match) { const struct xt_u32 *data = (const void *)match->data; if (data->invert) - printf("! "); - printf("--u32 "); + printf(" !"); + printf(" --u32"); u32_dump(data); } @@ -272,10 +267,10 @@ static struct xtables_match u32_match = { .size = XT_ALIGN(sizeof(struct xt_u32)), .userspacesize = XT_ALIGN(sizeof(struct xt_u32)), .help = u32_help, - .parse = u32_parse, .print = u32_print, .save = u32_save, - .extra_opts = u32_opts, + .x6_parse = u32_parse, + .x6_options = u32_opts, }; void _init(void) diff --git a/extensions/libxt_u32.man b/extensions/libxt_u32.man index 2ffab30..7c8615d 100644 --- a/extensions/libxt_u32.man +++ b/extensions/libxt_u32.man @@ -11,22 +11,22 @@ value := range | value "," range .IP range := number | number ":" number .PP -a single number, \fIn\fR, is interpreted the same as \fIn:n\fR. \fIn:m\fR is -interpreted as the range of numbers \fB>=n\fR and \fB<=m\fR. +a single number, \fIn\fP, is interpreted the same as \fIn:n\fP. \fIn:m\fP is +interpreted as the range of numbers \fB>=n\fP and \fB<=m\fP. .IP "" 4 location := number | location operator number .IP "" 4 operator := "&" | "<<" | ">>" | "@" .PP -The operators \fB&\fR, \fB<<\fR, \fB>>\fR and \fB&&\fR mean the same as in C. -The \fB=\fR is really a set membership operator and the value syntax describes -a set. The \fB@\fR operator is what allows moving to the next header and is +The operators \fB&\fP, \fB<<\fP, \fB>>\fP and \fB&&\fP mean the same as in C. +The \fB=\fP is really a set membership operator and the value syntax describes +a set. The \fB@\fP operator is what allows moving to the next header and is described further below. .PP There are currently some artificial implementation limits on the size of the tests: .IP " *" -no more than 10 of "\fB=\fR" (and 9 "\fB&&\fR"s) in the u32 argument +no more than 10 of "\fB=\fP" (and 9 "\fB&&\fP"s) in the u32 argument .IP " *" no more than 10 ranges (and 9 commas) per value .IP " *" @@ -35,7 +35,7 @@ no more than 10 numbers (and 9 operators) per location To describe the meaning of location, imagine the following machine that interprets it. There are three registers: .IP -A is of type \fBchar *\fR, initially the address of the IP header +A is of type \fBchar *\fP, initially the address of the IP header .IP B and C are unsigned 32 bit integers, initially zero .PP @@ -81,28 +81,28 @@ First test that it is an ICMP packet, true iff byte 9 (protocol) = 1 .IP \-\-u32 "\fB6 & 0xFF = 1 &&\fP ... .IP -read bytes 6-9, use \fB&\fR to throw away bytes 6-8 and compare the result to +read bytes 6-9, use \fB&\fP to throw away bytes 6-8 and compare the result to 1. Next test that it is not a fragment. (If so, it might be part of such a packet but we cannot always tell.) N.B.: This test is generally needed if you want to match anything beyond the IP header. The last 6 bits of byte 6 and all of byte 7 are 0 iff this is a complete packet (not a fragment). Alternatively, you can allow first fragments by only testing the last 5 bits of byte 6. .IP - ... \fB4 & 0x3FFF = 0 &&\fR ... + ... \fB4 & 0x3FFF = 0 &&\fP ... .IP Last test: the first byte past the IP header (the type) is 0. This is where we have to use the @syntax. The length of the IP header (IHL) in 32 bit words is stored in the right half of byte 0 of the IP header itself. .IP - ... \fB0 >> 22 & 0x3C @ 0 >> 24 = 0\fR" + ... \fB0 >> 22 & 0x3C @ 0 >> 24 = 0\fP" .IP -The first 0 means read bytes 0-3, \fB>>22\fR means shift that 22 bits to the +The first 0 means read bytes 0-3, \fB>>22\fP means shift that 22 bits to the right. Shifting 24 bits would give the first byte, so only 22 bits is four -times that plus a few more bits. \fB&3C\fR then eliminates the two extra bits +times that plus a few more bits. \fB&3C\fP then eliminates the two extra bits on the right and the first four bits of the first byte. For instance, if IHL=5, then the IP header is 20 (4 x 5) bytes long. In this case, bytes 0-1 are (in -binary) xxxx0101 yyzzzzzz, \fB>>22\fR gives the 10 bit value xxxx0101yy and -\fB&3C\fR gives 010100. \fB@\fR means to use this number as a new offset into +binary) xxxx0101 yyzzzzzz, \fB>>22\fP gives the 10 bit value xxxx0101yy and +\fB&3C\fP gives 010100. \fB@\fP means to use this number as a new offset into the packet, and read four bytes starting from there. This is the first 4 bytes of the ICMP payload, of which byte 0 is the ICMP type. Therefore, we simply shift the value 24 to the right to throw out all but the first byte and compare @@ -118,12 +118,12 @@ First we test that the packet is a tcp packet (similar to ICMP). .IP Next, test that it is not a fragment (same as above). .IP - ... \fB0 >> 22 & 0x3C @ 12 >> 26 & 0x3C @ 8 = 1,2,5,8\fR" + ... \fB0 >> 22 & 0x3C @ 12 >> 26 & 0x3C @ 8 = 1,2,5,8\fP" .IP -\fB0>>22&3C\fR as above computes the number of bytes in the IP header. \fB@\fR +\fB0>>22&3C\fP as above computes the number of bytes in the IP header. \fB@\fP makes this the new offset into the packet, which is the start of the TCP header. The length of the TCP header (again in 32 bit words) is the left half -of byte 12 of the TCP header. The \fB12>>26&3C\fR computes this length in bytes +of byte 12 of the TCP header. The \fB12>>26&3C\fP computes this length in bytes (similar to the IP header before). "@" makes this the new offset, which is the start of the TCP payload. Finally, 8 reads bytes 8-12 of the payload and -\fB=\fR checks whether the result is any of 1, 2, 5 or 8. +\fB=\fP checks whether the result is any of 1, 2, 5 or 8. diff --git a/extensions/libxt_udp.c b/extensions/libxt_udp.c index 135e7af..b9f39ee 100644 --- a/extensions/libxt_udp.c +++ b/extensions/libxt_udp.c @@ -1,13 +1,15 @@ -/* Shared library add-on to iptables to add UDP support. */ +#include <stdint.h> #include <stdio.h> #include <netdb.h> -#include <string.h> -#include <stdlib.h> -#include <getopt.h> -#include <netinet/in.h> +#include <arpa/inet.h> #include <xtables.h> #include <linux/netfilter/xt_tcpudp.h> +enum { + O_SOURCE_PORT = 0, + O_DEST_PORT, +}; + static void udp_help(void) { printf( @@ -20,36 +22,19 @@ static void udp_help(void) " match destination port(s)\n"); } -static const struct option udp_opts[] = { - { "source-port", 1, NULL, '1' }, - { "sport", 1, NULL, '1' }, /* synonym */ - { "destination-port", 1, NULL, '2' }, - { "dport", 1, NULL, '2' }, /* synonym */ - { .name = NULL } +#define s struct xt_udp +static const struct xt_option_entry udp_opts[] = { + {.name = "source-port", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)}, + {.name = "sport", .id = O_SOURCE_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, spts)}, + {.name = "destination-port", .id = O_DEST_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)}, + {.name = "dport", .id = O_DEST_PORT, .type = XTTYPE_PORTRC, + .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, dpts)}, + XTOPT_TABLEEND, }; - -static void -parse_udp_ports(const char *portstring, u_int16_t *ports) -{ - char *buffer; - char *cp; - - buffer = strdup(portstring); - if ((cp = strchr(buffer, ':')) == NULL) - ports[0] = ports[1] = xtables_parse_port(buffer, "udp"); - else { - *cp = '\0'; - cp++; - - ports[0] = buffer[0] ? xtables_parse_port(buffer, "udp") : 0; - ports[1] = cp[0] ? xtables_parse_port(cp, "udp") : 0xFFFF; - - if (ports[0] > ports[1]) - xtables_error(PARAMETER_PROBLEM, - "invalid portrange (min > max)"); - } - free(buffer); -} +#undef s static void udp_init(struct xt_entry_match *m) { @@ -58,49 +43,27 @@ static void udp_init(struct xt_entry_match *m) udpinfo->spts[1] = udpinfo->dpts[1] = 0xFFFF; } -#define UDP_SRC_PORTS 0x01 -#define UDP_DST_PORTS 0x02 - -static int -udp_parse(int c, char **argv, int invert, unsigned int *flags, - const void *entry, struct xt_entry_match **match) +static void udp_parse(struct xt_option_call *cb) { - struct xt_udp *udpinfo = (struct xt_udp *)(*match)->data; - - switch (c) { - case '1': - if (*flags & UDP_SRC_PORTS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--source-port' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_udp_ports(optarg, udpinfo->spts); - if (invert) + struct xt_udp *udpinfo = cb->data; + + xtables_option_parse(cb); + switch (cb->entry->id) { + case O_SOURCE_PORT: + if (cb->invert) udpinfo->invflags |= XT_UDP_INV_SRCPT; - *flags |= UDP_SRC_PORTS; break; - - case '2': - if (*flags & UDP_DST_PORTS) - xtables_error(PARAMETER_PROBLEM, - "Only one `--destination-port' allowed"); - xtables_check_inverse(optarg, &invert, &optind, 0, argv); - parse_udp_ports(optarg, udpinfo->dpts); - if (invert) + case O_DEST_PORT: + if (cb->invert) udpinfo->invflags |= XT_UDP_INV_DSTPT; - *flags |= UDP_DST_PORTS; break; - - default: - return 0; } - - return 1; } -static char * +static const char * port_to_service(int port) { - struct servent *service; + const struct servent *service; if ((service = getservbyport(htons(port), "udp"))) return service->s_name; @@ -109,9 +72,9 @@ port_to_service(int port) } static void -print_port(u_int16_t port, int numeric) +print_port(uint16_t port, int numeric) { - char *service; + const char *service; if (numeric || (service = port_to_service(port)) == NULL) printf("%u", port); @@ -120,13 +83,13 @@ print_port(u_int16_t port, int numeric) } static void -print_ports(const char *name, u_int16_t min, u_int16_t max, +print_ports(const char *name, uint16_t min, uint16_t max, int invert, int numeric) { const char *inv = invert ? "!" : ""; if (min != 0 || max != 0xFFFF || invert) { - printf("%s", name); + printf(" %s", name); if (min == max) { printf(":%s", inv); print_port(min, numeric); @@ -136,7 +99,6 @@ print_ports(const char *name, u_int16_t min, u_int16_t max, printf(":"); print_port(max, numeric); } - printf(" "); } } @@ -145,7 +107,7 @@ udp_print(const void *ip, const struct xt_entry_match *match, int numeric) { const struct xt_udp *udp = (struct xt_udp *)match->data; - printf("udp "); + printf(" udp"); print_ports("spt", udp->spts[0], udp->spts[1], udp->invflags & XT_UDP_INV_SRCPT, numeric); @@ -153,7 +115,7 @@ udp_print(const void *ip, const struct xt_entry_match *match, int numeric) udp->invflags & XT_UDP_INV_DSTPT, numeric); if (udp->invflags & ~XT_UDP_INV_MASK) - printf("Unknown invflags: 0x%X ", + printf(" Unknown invflags: 0x%X", udp->invflags & ~XT_UDP_INV_MASK); } @@ -164,28 +126,28 @@ static void udp_save(const void *ip, const struct xt_entry_match *match) if (udpinfo->spts[0] != 0 || udpinfo->spts[1] != 0xFFFF) { if (udpinfo->invflags & XT_UDP_INV_SRCPT) - printf("! "); + printf(" !"); if (udpinfo->spts[0] != udpinfo->spts[1]) - printf("--sport %u:%u ", + printf(" --sport %u:%u", udpinfo->spts[0], udpinfo->spts[1]); else - printf("--sport %u ", + printf(" --sport %u", udpinfo->spts[0]); } if (udpinfo->dpts[0] != 0 || udpinfo->dpts[1] != 0xFFFF) { if (udpinfo->invflags & XT_UDP_INV_DSTPT) - printf("! "); + printf(" !"); if (udpinfo->dpts[0] != udpinfo->dpts[1]) - printf("--dport %u:%u ", + printf(" --dport %u:%u", udpinfo->dpts[0], udpinfo->dpts[1]); else - printf("--dport %u ", + printf(" --dport %u", udpinfo->dpts[0]); } } @@ -198,10 +160,10 @@ static struct xtables_match udp_match = { .userspacesize = XT_ALIGN(sizeof(struct xt_udp)), .help = udp_help, .init = udp_init, - .parse = udp_parse, .print = udp_print, .save = udp_save, - .extra_opts = udp_opts, + .x6_parse = udp_parse, + .x6_options = udp_opts, }; void diff --git a/extensions/tos_values.c b/extensions/tos_values.c index e8f1563..6dc4743 100644 --- a/extensions/tos_values.c +++ b/extensions/tos_values.c @@ -20,66 +20,11 @@ static const struct tos_symbol_info { {IPTOS_RELIABILITY, "Maximize-Reliability"}, {IPTOS_MINCOST, "Minimize-Cost"}, {IPTOS_NORMALSVC, "Normal-Service"}, - { .name = NULL } + {}, }; -/* - * tos_parse_numeric - parse sth. like "15/255" - * - * @s: input string - * @info: accompanying structure - * @bits: number of bits that are allowed - * (8 for IPv4 TOS field, 4 for IPv6 Priority Field) - */ -static bool tos_parse_numeric(const char *str, struct tos_value_mask *tvm, - unsigned int bits) -{ - const unsigned int max = (1 << bits) - 1; - unsigned int value; - char *end; - - xtables_strtoui(str, &end, &value, 0, max); - tvm->value = value; - tvm->mask = max; - - if (*end == '/') { - const char *p = end + 1; - - if (!xtables_strtoui(p, &end, &value, 0, max)) - xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"", - str); - tvm->mask = value; - } - - if (*end != '\0') - xtables_error(PARAMETER_PROBLEM, "Illegal value: \"%s\"", str); - return true; -} - -static bool tos_parse_symbolic(const char *str, struct tos_value_mask *tvm, - unsigned int def_mask) -{ - const unsigned int max = UINT8_MAX; - const struct tos_symbol_info *symbol; - char *tmp; - - if (xtables_strtoui(str, &tmp, NULL, 0, max)) - return tos_parse_numeric(str, tvm, max); - - /* Do not consider ECN bits */ - tvm->mask = def_mask; - for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol) - if (strcasecmp(str, symbol->name) == 0) { - tvm->value = symbol->value; - return true; - } - - xtables_error(PARAMETER_PROBLEM, "Symbolic name \"%s\" is unknown", str); - return false; -} - static bool tos_try_print_symbolic(const char *prefix, - u_int8_t value, u_int8_t mask) + uint8_t value, uint8_t mask) { const struct tos_symbol_info *symbol; @@ -88,7 +33,7 @@ static bool tos_try_print_symbolic(const char *prefix, for (symbol = tos_symbol_names; symbol->name != NULL; ++symbol) if (value == symbol->value) { - printf("%s%s ", prefix, symbol->name); + printf(" %s%s", prefix, symbol->name); return true; } |