iptables-1.3.5
authorMark Huang <mlhuang@cs.princeton.edu>
Fri, 28 Jul 2006 14:34:27 +0000 (14:34 +0000)
committerMark Huang <mlhuang@cs.princeton.edu>
Fri, 28 Jul 2006 14:34:27 +0000 (14:34 +0000)
85 files changed:
INCOMPATIBILITIES
Makefile
extensions/.dccp-test [new file with mode: 0755]
extensions/Makefile
extensions/libip6t_CONNMARK.c [new file with mode: 0644]
extensions/libip6t_HL.man
extensions/libip6t_NFQUEUE.c [new file with mode: 0644]
extensions/libip6t_NFQUEUE.man [new file with mode: 0644]
extensions/libip6t_REJECT.man
extensions/libip6t_ah.man
extensions/libip6t_condition.man
extensions/libip6t_connmark.c [new file with mode: 0644]
extensions/libip6t_dst.man
extensions/libip6t_esp.man
extensions/libip6t_eui64.man
extensions/libip6t_frag.man
extensions/libip6t_fuzzy.man
extensions/libip6t_hbh.man
extensions/libip6t_hl.man
extensions/libip6t_icmpv6.man
extensions/libip6t_ipv6header.man
extensions/libip6t_length.c
extensions/libip6t_length.man
extensions/libip6t_mark.man
extensions/libip6t_multiport.man
extensions/libip6t_owner.man
extensions/libip6t_physdev.c
extensions/libip6t_physdev.man
extensions/libip6t_policy.c [new file with mode: 0644]
extensions/libip6t_policy.man [new file with mode: 0644]
extensions/libip6t_rt.man
extensions/libip6t_state.c [new file with mode: 0644]
extensions/libipt_CLASSIFY.c
extensions/libipt_CLUSTERIP.c
extensions/libipt_CONNMARK.c
extensions/libipt_DNAT.c
extensions/libipt_DNAT.man
extensions/libipt_DSCP.c
extensions/libipt_MASQUERADE.c
extensions/libipt_NFQUEUE.c [new file with mode: 0644]
extensions/libipt_NFQUEUE.man [new file with mode: 0644]
extensions/libipt_REDIRECT.c
extensions/libipt_REJECT.c
extensions/libipt_SNAT.c
extensions/libipt_SNAT.man
extensions/libipt_TCPMSS.man
extensions/libipt_TOS.c
extensions/libipt_ah.man
extensions/libipt_comment.c
extensions/libipt_condition.man
extensions/libipt_connbytes.c
extensions/libipt_connmark.c
extensions/libipt_conntrack.c
extensions/libipt_dccp.c [new file with mode: 0644]
extensions/libipt_dccp.man [new file with mode: 0644]
extensions/libipt_dscp.c
extensions/libipt_dstlimit.man
extensions/libipt_esp.man
extensions/libipt_fuzzy.man
extensions/libipt_length.man
extensions/libipt_mark.man
extensions/libipt_physdev.c
extensions/libipt_physdev.man
extensions/libipt_policy.c [new file with mode: 0644]
extensions/libipt_policy.man [new file with mode: 0644]
extensions/libipt_rpc.c
extensions/libipt_sctp.c
extensions/libipt_string.c
extensions/libipt_string.man [new file with mode: 0644]
extensions/libipt_tos.c
extensions/libipt_ttl.c
include/ip6tables.h
include/iptables.h
include/iptables_common.h
include/linux/netfilter_ipv4/ipt_NFQUEUE.h [new file with mode: 0644]
include/linux/netfilter_ipv4/ipt_conntrack.h
include/linux/netfilter_ipv4/ipt_policy.h [new file with mode: 0644]
include/linux/netfilter_ipv6/ip6t_policy.h [new file with mode: 0644]
ip6tables.8.in
ip6tables.c
iptables-save.c
iptables.8.in
iptables.c
libipq/libipq.c
libiptc/libiptc.c

index 7057b26..ddb2408 100644 (file)
@@ -4,6 +4,8 @@ INCOMPATIBILITIES:
   with kernels that do not support it, will result in a plain DROP instead
   of REJECT.  Use with caution.
   Kernels that do support it:
+       2.4 - since 2.4.22-pre9
+       2.6 - all
 
 - There are some issues related to upgrading from 1.2.x to 1.3.x on a system
   with dynamic ruleset changes during runtime. (Please see 
index cd2fe5f..558367e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,8 +14,8 @@ TOPLEVEL_INCLUDED=YES
 ifndef KERNEL_DIR
 KERNEL_DIR=/usr/src/linux
 endif
-IPTABLES_VERSION:=1.3.2
-OLD_IPTABLES_VERSION:=1.3.1
+IPTABLES_VERSION:=1.3.5
+OLD_IPTABLES_VERSION:=1.3.4
 
 PREFIX:=/usr/local
 LIBDIR:=$(PREFIX)/lib
diff --git a/extensions/.dccp-test b/extensions/.dccp-test
new file mode 100755 (executable)
index 0000000..5b67527
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+# True if dccp is applied.
+[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_dccp.h ] && echo dccp
index 5840502..7164e1d 100644 (file)
@@ -5,8 +5,8 @@
 # header files are present in the include/linux directory of this iptables
 # package (HW)
 #
-PF_EXT_SLIB:=ah addrtype comment connlimit connmark conntrack dscp ecn esp hashlimit helper icmp iprange length limit mac mark multiport owner physdev pkttype realm rpc sctp standard state tcp tcpmss tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE TTL ULOG
-PF6_EXT_SLIB:=eui64 hl icmpv6 length limit mac mark multiport owner physdev standard tcp udp HL LOG MARK TRACE
+PF_EXT_SLIB:=ah addrtype comment connlimit connmark conntrack dscp ecn esp hashlimit helper icmp iprange length limit mac mark multiport owner physdev pkttype policy realm rpc sctp standard state tcp tcpmss tos ttl udp unclean CLASSIFY CONNMARK DNAT DSCP ECN LOG MARK MASQUERADE MIRROR NETMAP NFQUEUE NOTRACK REDIRECT REJECT SAME SNAT TARPIT TCPMSS TOS TRACE TTL ULOG
+PF6_EXT_SLIB:=connmark eui64 hl icmpv6 length limit mac mark multiport owner physdev policy standard state tcp udp CONNMARK HL LOG NFQUEUE MARK TRACE
 
 # Optionals
 PF_EXT_SLIB_OPTS:=$(foreach T,$(wildcard extensions/.*-test),$(shell KERNEL_DIR=$(KERNEL_DIR) $(T)))
diff --git a/extensions/libip6t_CONNMARK.c b/extensions/libip6t_CONNMARK.c
new file mode 100644 (file)
index 0000000..9506f26
--- /dev/null
@@ -0,0 +1,220 @@
+/* Shared library add-on to iptables to add CONNMARK target support.
+ *
+ * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * Version 1.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <ip6tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include "../include/linux/netfilter_ipv4/ipt_CONNMARK.h"
+
+#if 0
+struct markinfo {
+       struct ipt_entry_target t;
+       struct ipt_connmark_target_info mark;
+};
+#endif
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+       printf(
+"CONNMARK target v%s options:\n"
+"  --set-mark value[/mask]       Set conntrack mark value\n"
+"  --save-mark [--mask mask]     Save the packet nfmark in the connection\n"
+"  --restore-mark [--mask mask]  Restore saved nfmark value\n"
+"\n",
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { "set-mark", 1, 0, '1' },
+       { "save-mark", 0, 0, '2' },
+       { "restore-mark", 0, 0, '3' },
+       { "mask", 1, 0, '4' },
+       { 0 }
+};
+
+/* Initialize the target. */
+static void
+init(struct ip6t_entry_target *t, unsigned int *nfcache)
+{
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ip6t_entry *entry,
+      struct ip6t_entry_target **target)
+{
+       struct ipt_connmark_target_info *markinfo
+               = (struct ipt_connmark_target_info *)(*target)->data;
+
+       markinfo->mask = 0xffffffffUL;
+
+       switch (c) {
+               char *end;
+       case '1':
+               markinfo->mode = IPT_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)
+                       exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
+               if (*flags)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "CONNMARK target: Can't specify --set-mark twice");
+               *flags = 1;
+               break;
+       case '2':
+               markinfo->mode = IPT_CONNMARK_SAVE;
+               if (*flags)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "CONNMARK target: Can't specify --save-mark twice");
+               *flags = 1;
+               break;
+       case '3':
+               markinfo->mode = IPT_CONNMARK_RESTORE;
+               if (*flags)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "CONNMARK target: Can't specify --restore-mark twice");
+               *flags = 1;
+               break;
+       case '4':
+               if (!*flags)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "CONNMARK target: Can't specify --mask without a operation");
+               markinfo->mask = strtoul(optarg, &end, 0);
+
+               if (*end != '\0' || end == optarg)
+                       exit_error(PARAMETER_PROBLEM, "Bad MASK value `%s'", optarg);
+               break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM,
+                          "CONNMARK target: No operation specified");
+}
+
+static void
+print_mark(unsigned long mark)
+{
+       printf("0x%lx", mark);
+}
+
+static void
+print_mask(const char *text, unsigned long mask)
+{
+       if (mask != 0xffffffffUL)
+               printf("%s0x%lx", text, mask);
+}
+
+
+/* Prints out the target info. */
+static void
+print(const struct ip6t_ip6 *ip,
+      const struct ip6t_entry_target *target,
+      int numeric)
+{
+       const struct ipt_connmark_target_info *markinfo =
+               (const struct ipt_connmark_target_info *)target->data;
+       switch (markinfo->mode) {
+       case IPT_CONNMARK_SET:
+           printf("CONNMARK set ");
+           print_mark(markinfo->mark);
+           print_mask("/", markinfo->mask);
+           printf(" ");
+           break;
+       case IPT_CONNMARK_SAVE:
+           printf("CONNMARK save ");
+           print_mask("mask ", markinfo->mask);
+           printf(" ");
+           break;
+       case IPT_CONNMARK_RESTORE:
+           printf("CONNMARK restore ");
+           print_mask("mask ", markinfo->mask);
+           break;
+       default:
+           printf("ERROR: UNKNOWN CONNMARK MODE ");
+           break;
+       }
+}
+
+/* Saves the target into in parsable form to stdout. */
+static void
+save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target)
+{
+       const struct ipt_connmark_target_info *markinfo =
+               (const struct ipt_connmark_target_info *)target->data;
+
+       switch (markinfo->mode) {
+       case IPT_CONNMARK_SET:
+           printf("--set-mark ");
+           print_mark(markinfo->mark);
+           print_mask("/", markinfo->mask);
+           printf(" ");
+           break;
+       case IPT_CONNMARK_SAVE:
+           printf("--save-mark ");
+           print_mask("--mask ", markinfo->mask);
+           break;
+       case IPT_CONNMARK_RESTORE:
+           printf("--restore-mark ");
+           print_mask("--mask ", markinfo->mask);
+           break;
+       default:
+           printf("ERROR: UNKNOWN CONNMARK MODE ");
+           break;
+       }
+}
+
+static struct ip6tables_target connmark_target = {
+    .name          = "CONNMARK",
+    .version       = IPTABLES_VERSION,
+    .size          = IP6T_ALIGN(sizeof(struct ipt_connmark_target_info)),
+    .userspacesize = IP6T_ALIGN(sizeof(struct ipt_connmark_target_info)),
+    .help          = &help,
+    .init          = &init,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+void _init(void)
+{
+       register_target6(&connmark_target);
+}
index 6b8291d..bf46881 100644 (file)
@@ -1,17 +1,17 @@
-This is used to modify the IPv6 HOPLIMIT header field.  The HOPLIMIT field is 
-similar to what is known as TTL value in IPv4.  Setting or incrementing the
-HOPLIMIT field can potentially be very dangerous, so it should be avoided at
-any cost.  
-.TP
-.B Don't ever set or increment the value on packets that leave your local network!
+This is used to modify the Hop Limit field in IPv6 header. The Hop Limit field
+is similar to what is known as TTL value in IPv4.  Setting or incrementing the
+Hop Limit field can potentially be very dangerous, so it should be avoided at
+any cost. This target is only valid in
 .B mangle
 table.
 .TP
+.B Don't ever set or increment the value on packets that leave your local network!
+.TP
 .BI "--hl-set " "value"
-Set the HOPLIMIT value to `value'.
+Set the Hop Limit to `value'.
 .TP
 .BI "--hl-dec " "value"
-Decrement the HOPLIMIT value `value' times.
+Decrement the Hop Limit `value' times.
 .TP
 .BI "--hl-inc " "value"
-Increment the HOPLIMIT value `value' times.
+Increment the Hop Limit `value' times.
diff --git a/extensions/libip6t_NFQUEUE.c b/extensions/libip6t_NFQUEUE.c
new file mode 100644 (file)
index 0000000..e1964af
--- /dev/null
@@ -0,0 +1,114 @@
+/* Shared library add-on to ip666666tables for NFQ
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <ip6tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
+
+static void init(struct ip6t_entry_target *t, unsigned int *nfcache) 
+{
+}
+
+static void help(void) 
+{
+       printf(
+"NFQUEUE target options\n"
+"  --queue-num value           Send packet to QUEUE number <value>.\n"
+"                              Valid queue numbers are 0-65535\n"
+);
+}
+
+static struct option opts[] = {
+       { "queue-num", 1, 0, 'F' },
+       { 0 }
+};
+
+static void
+parse_num(const char *s, struct ipt_NFQ_info *tinfo)
+{
+       unsigned int num;
+       
+       if (string_to_number(s, 0, 65535, &num) == -1)
+               exit_error(PARAMETER_PROBLEM,
+                          "Invalid queue number `%s'\n", s);
+
+       tinfo->queuenum = num & 0xffff;
+       return;
+}
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ip6t_entry *entry,
+      struct ip6t_entry_target **target)
+{
+       struct ipt_NFQ_info *tinfo
+               = (struct ipt_NFQ_info *)(*target)->data;
+
+       switch (c) {
+       case 'F':
+               if (*flags)
+                       exit_error(PARAMETER_PROBLEM, "NFQUEUE target: "
+                                  "Only use --queue-num ONCE!");
+               parse_num(optarg, tinfo);
+               break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ip6t_ip6 *ip,
+      const struct ip6t_entry_target *target,
+      int numeric)
+{
+       const struct ipt_NFQ_info *tinfo =
+               (const struct ipt_NFQ_info *)target->data;
+       printf("NFQUEUE num %u", tinfo->queuenum);
+}
+
+/* Saves the union ip6t_targinfo in parsable form to stdout. */
+static void
+save(const struct ip6t_ip6 *ip, const struct ip6t_entry_target *target)
+{
+       const struct ipt_NFQ_info *tinfo =
+               (const struct ipt_NFQ_info *)target->data;
+
+       printf("--queue-num %u ", tinfo->queuenum);
+}
+
+static struct ip6tables_target nfqueue = { 
+       .next           = NULL,
+       .name           = "NFQUEUE",
+       .version        = IPTABLES_VERSION,
+       .size           = IP6T_ALIGN(sizeof(struct ipt_NFQ_info)),
+       .userspacesize  = IP6T_ALIGN(sizeof(struct ipt_NFQ_info)),
+       .help           = &help,
+       .init           = &init,
+       .parse          = &parse,
+       .final_check    = &final_check,
+       .print          = &print,
+       .save           = &save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_target6(&nfqueue);
+}
diff --git a/extensions/libip6t_NFQUEUE.man b/extensions/libip6t_NFQUEUE.man
new file mode 100644 (file)
index 0000000..c4e9d11
--- /dev/null
@@ -0,0 +1,12 @@
+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.  
+.TP
+.BR "--queue-num " "\fIvalue"
+This specifies the QUEUE number to use. Valud queue numbers are 0 to 65535. The default value is 0.
+.TP
+It can only be used with Kernel versions 2.6.14 or later, since it requires
+the
+.B
+nfnetlink_queue
+kernel support.
index 75930f1..909d826 100644 (file)
@@ -23,7 +23,7 @@ The type given can be
 .B " icmp6-port-unreachable"
 .B " port-unreach"
 .fi
-which return the appropriate IPv6-ICMP error message (\fBport-unreach\fP is
+which return the appropriate ICMPv6 error message (\fBport-unreach\fP is
 the default). Finally, the option
 .B tcp-reset
 can be used on rules which only match the TCP protocol: this causes a
@@ -31,4 +31,6 @@ TCP RST packet to be sent back.  This is mainly useful for blocking
 .I ident
 (113/tcp) probes which frequently occur when sending mail to broken mail
 hosts (which won't accept your mail otherwise).
+.B tcp-reset
+can only be used with kernel versions 2.6.14 or latter.
 
index 97de1e1..09d00fd 100644 (file)
@@ -1,3 +1,10 @@
-This module matches the SPIs in AH header of IPSec packets.
+This module matches the parameters in Authentication header of IPsec packets.
 .TP
 .BR "--ahspi " "[!] \fIspi\fP[:\fIspi\fP]"
+Matches SPI.
+.TP
+.BR "--ahlen " "[!] \fIlength"
+Total length of this header in octets.
+.TP
+.BI "--ahres"
+Matches if the reserved field is filled with zero.
index 30c478c..e0bba75 100644 (file)
@@ -1,4 +1,4 @@
 This matches if a specific /proc filename is '0' or '1'.
 .TP
-.BI "--condition " "[!] filename"
+.BR "--condition " "[!] \fIfilename"
 Match on boolean value stored in /proc/net/ip6t_condition/filename file
diff --git a/extensions/libip6t_connmark.c b/extensions/libip6t_connmark.c
new file mode 100644 (file)
index 0000000..419da30
--- /dev/null
@@ -0,0 +1,151 @@
+/* Shared library add-on to iptables to add connmark matching support.
+ *
+ * (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
+ * by Henrik Nordstrom <hno@marasystems.com>
+ *
+ * Version 1.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <ip6tables.h>
+#include "../include/linux/netfilter_ipv4/ipt_connmark.h"
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+       printf(
+"CONNMARK match v%s options:\n"
+"[!] --mark value[/mask]         Match nfmark value with optional mask\n"
+"\n",
+IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { "mark", 1, 0, '1' },
+       {0}
+};
+
+/* Initialize the match. */
+static void
+init(struct ip6t_entry_match *m, unsigned int *nfcache)
+{
+       /* Can't cache this. */
+       *nfcache |= NFC_UNKNOWN;
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ip6t_entry *entry,
+      unsigned int *nfcache,
+      struct ip6t_entry_match **match)
+{
+       struct ipt_connmark_info *markinfo = (struct ipt_connmark_info *)(*match)->data;
+
+       switch (c) {
+               char *end;
+       case '1':
+               check_inverse(optarg, &invert, &optind, 0);
+
+               markinfo->mark = strtoul(optarg, &end, 0);
+               markinfo->mask = 0xffffffffUL;
+               
+               if (*end == '/')
+                       markinfo->mask = strtoul(end+1, &end, 0);
+
+               if (*end != '\0' || end == optarg)
+                       exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
+               if (invert)
+                       markinfo->invert = 1;
+               *flags = 1;
+               break;
+
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static void
+print_mark(unsigned long mark, unsigned long mask, int numeric)
+{
+       if(mask != 0xffffffffUL)
+               printf("0x%lx/0x%lx ", mark, mask);
+       else
+               printf("0x%lx ", mark);
+}
+
+/* Final check; must have specified --mark. */
+static void
+final_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM,
+                          "MARK match: You must specify `--mark'");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ip6t_ip6 *ip,
+      const struct ip6t_entry_match *match,
+      int numeric)
+{
+       struct ipt_connmark_info *info = (struct ipt_connmark_info *)match->data;
+
+       printf("CONNMARK match ");
+       if (info->invert)
+               printf("!");
+       print_mark(info->mark, info->mask, numeric);
+}
+
+/* Saves the matchinfo in parsable form to stdout. */
+static void
+save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
+{
+       struct ipt_connmark_info *info = (struct ipt_connmark_info *)match->data;
+
+       if (info->invert)
+               printf("! ");
+
+       printf("--mark ");
+       print_mark(info->mark, info->mask, 0);
+}
+
+static struct ip6tables_match connmark_match = {
+    .name          = "connmark",
+    .version       = IPTABLES_VERSION,
+    .size          = IP6T_ALIGN(sizeof(struct ipt_connmark_info)),
+    .userspacesize = IP6T_ALIGN(sizeof(struct ipt_connmark_info)),
+    .help          = &help,
+    .init          = &init,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+void _init(void)
+{
+       register_match6(&connmark_match);
+}
index 168a10f..f42d822 100644 (file)
@@ -1,7 +1,7 @@
-This module matches the IPv6 destination header options
+This module matches the parameters in Destination Options header
 .TP
-.BI "--dst-len" "[!]" "length"
-Total length of this header
+.BR "--dst-len " "[!] \fIlength"
+Total length of this header in octets.
 .TP
-.BI "--dst-opts " "TYPE[:LEN],[,TYPE[:LEN]...]"
-Options and it's length (List).
+.BR "--dst-opts " "\fItype\fP[:\fIlength\fP][,\fItype\fP[:\fIlength\fP]...]"
+numeric type of option and the length of the option data in octets.
index 7b84368..7898e02 100644 (file)
@@ -1,3 +1,3 @@
-This module matches the SPIs in ESP header of IPSec packets.
+This module matches the SPIs in ESP header of IPsec packets.
 .TP
 .BR "--espspi " "[!] \fIspi\fP[:\fIspi\fP]"
index 24fc56c..d01cb4f 100644 (file)
@@ -1 +1,10 @@
-This module matches the EUI64 part of a stateless autoconfigured IPv6 address.  It compares the source MAC address with the lower 64 bits of the IPv6 address. 
+This module matches the EUI-64 part of a stateless autoconfigured IPv6 address.
+It compares the EUI-64 derived from the source MAC address in Ehternet frame
+with the lower 64 bits of the IPv6 source address. But "Universal/Local"
+bit is not compared. This module doesn't match other link layer frame, and
+is only valid in the
+.BR PREROUTING ,
+.BR INPUT
+and
+.BR FORWARD
+chains.
index fff3db3..5ac13a4 100644 (file)
@@ -1,19 +1,20 @@
-This module matches the time IPv6 fragmentathion header
+This module matches the parameters in Fragment header.
 .TP
-.BI "--fragid " "[!]" "id[:id]"
-Matches the given fragmentation ID (range).
+.BR "--fragid " "[!] \fIid\fP[:\fIid\fP]"
+Matches the given Identification or range of it.
 .TP
-.BI "--fraglen " "[!]" "length"
-Matches the total length of this header.
+.BR "--fraglen " "[!] \fIlength\fP"
+This option cannot be used with kernel version 2.6.10 or later. The length of
+Fragment header is static and this option doesn't make sense.
 .TP
-.BI "--fragres "
-Matches the reserved field, too.
+.BR "--fragres "
+Matches if the reserved fields are filled with zero.
 .TP
-.BI "--fragfirst "
+.BR "--fragfirst "
 Matches on the first fragment.
 .TP
-.BI "[--fragmore]"
+.BR "[--fragmore]"
 Matches if there are more fragments.
 .TP
-.BI "[--fraglast]"
+.BR "[--fraglast]"
 Matches if this is the last fragement.
index 270c8d6..397727a 100644 (file)
@@ -1,6 +1,6 @@
 This module matches a rate limit based on a fuzzy logic controller [FLC]
 .TP
-.BI "--lower-limit  "number"
+.BI "--lower-limit " "number"
 Specifies the lower limit (in packets per second).
 .TP
 .BI "--upper-limit " "number"
index 8376f91..938e1f3 100644 (file)
@@ -1,7 +1,7 @@
-This module matches the IPv6 hop-by-hop header options
+This module matches the parameters in Hop-by-Hop Options header
 .TP
-.BI "--hbh-len" "[!]" "length"
-Total length of this header
+.BR "--hbh-len " "[!] \fIlength\fP"
+Total length of this header in octets.
 .TP
-.BI "--hbh-opts " "TYPE[:LEN],[,TYPE[:LEN]...]"
-Options and it's length (List).
+.BR "--hbh-opts " "\fItype\fP[:\fIlength\fP][,\fItype\fP[:\fIlength\fP]...]"
+numeric type of option and the length of the option data in octets.
index 9fcb730..d33e431 100644 (file)
@@ -1,10 +1,10 @@
-This module matches the HOPLIMIT field in the IPv6 header.
+This module matches the Hop Limit field in the IPv6 header.
 .TP
-.BI "--hl-eq " "value"
-Matches if HOPLIMIT equals the given value.
+.BR "--hl-eq " "[!] \fIvalue\fP"
+Matches if Hop Limit equals \fIvalue\fP.
 .TP
-.BI "--hl-lt " "ttl"
-Matches if HOPLIMIT is less than the given value.
+.BI "--hl-lt " "value"
+Matches if Hop Limit is less than \fIvalue\fP.
 .TP
-.BI "--hl-gt " "ttl"
-Matches if HOPLIMIT is greater than the given value.
+.BI "--hl-gt " "value"
+Matches if Hop Limit is greater than \fIvalue\fP.
index 2702954..2047180 100644 (file)
@@ -1,9 +1,14 @@
 This extension is loaded if `--protocol ipv6-icmp' or `--protocol icmpv6' is
 specified. It provides the following option:
 .TP
-.BR "--icmpv6-type " "[!] \fItypename\fP"
-This allows specification of the ICMP type, which can be a numeric
-IPv6-ICMP type, or one of the IPv6-ICMP type names shown by the command
+.BR "--icmpv6-type " "[!] \fItype\fP[/\fIcode\fP]|\fItypename\fP"
+This allows specification of the ICMPv6 type, which can be a numeric
+ICMPv6
+.IR type ,
+.IR type
+and
+.IR code ,
+or one of the ICMPv6 type names shown by the command
 .nf
  ip6tables -p ipv6-icmp -h
 .fi
index bec3e18..fe3fe98 100644 (file)
@@ -1,10 +1,29 @@
-This module matches on IPv6 option headers
+This module matches IPv6 extension headers and/or upper layer header.
 .TP
-.BI "--header " "[!]" "headers"
-Matches the given type of headers.  
-Names: hop,dst,route,frag,auth,esp,none,proto
-Long Names: hop-by-hop,ipv6-opts,ipv6-route,ipv6-frag,ah,esp,ipv6-nonxt,protocol
-Numbers: 0,60,43,44,51,50,59
+.BR "--header " "[!] \fIheader\fP[,\fIheader\fP...]"
+Matches the packet which EXACTLY includes all specified headers. The headers
+encapsulated with ESP header are out of scope.
+.IR header
+can be
+.IR hop | hop-by-hop
+(Hop-by-Hop Options header),
+.IR dst
+(Destination Options header),
+.IR route
+(Routing header),
+.IR frag
+(Fragment header),
+.IR auth
+(Authentication header),
+.IR esp
+(Encapsulating Security Payload header),
+.IR none
+(No Next header) which matches 59 in the 'Next Header field' of IPv6 header or any IPv6 extension headers, or
+.IR proto
+which matches any upper layer protocol header. A protocol name from /etc/protocols and numeric value also allowed. The number 255 is equivalent to
+.IR proto .
 .TP
-.BI "--soft"
-The header CONTAINS the specified extensions.
+.BR "[--soft]"
+Matches if the packet includes all specified headers with
+.BR --header ,
+AT LEAST.
index c944c65..9f7ba16 100644 (file)
@@ -30,7 +30,7 @@ static u_int16_t
 parse_length(const char *s)
 {
 
-       int len;
+       unsigned int len;
        
        if (string_to_number(s, 0, 0xFFFF, &len) == -1)
                exit_error(PARAMETER_PROBLEM, "length invalid: `%s'\n", s);
index 72a6b5d..d781a04 100644 (file)
@@ -1,4 +1,4 @@
-This module matches the length of a packet against a specific value
-or range of values.
+This module matches the length of the IPv6 payload in octets, or range of it.
+IPv6 header itself isn't counted.
 .TP
-.BR "--length " "\fIlength\fP[:\fIlength\fP]"
+.BR "--length " "[!] \fIlength\fP[:\fIlength\fP]"
index 05f8e1e..a2a1395 100644 (file)
@@ -4,6 +4,6 @@ This module matches the netfilter mark field associated with a packet
 target below).
 .TP
 .BR "--mark " "\fIvalue\fP[/\fImask\fP]"
-Matches packets with the given unsigned mark value (if a mask is
-specified, this is logically ANDed with the mask before the
+Matches packets with the given unsigned mark value (if a \fImask\fP is
+specified, this is logically ANDed with the \fImask\fP before the
 comparison).
index 684f49f..159cc6d 100644 (file)
@@ -1,6 +1,7 @@
 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
+ports, but range isn't supported now. It can only be used in conjunction
+with
 .B "-p tcp"
 or
 .BR "-p udp" .
index 99680a6..edd72b1 100644 (file)
@@ -1,7 +1,7 @@
 This module attempts to match various characteristics of the packet
 creator, for locally-generated packets.  It is only valid in the
 .B OUTPUT
-chain, and even this some packets (such as ICMP ping responses) may
+chain, and even this some packets (such as ICMPv6 ping responses) may
 have no owner, and hence never match.  This is regarded as experimental.
 .TP
 .BI "--uid-owner " "userid"
index fb47347..e7fa22e 100644 (file)
@@ -53,7 +53,8 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                if (*flags & IP6T_PHYSDEV_OP_IN)
                        goto multiple_use;
                check_inverse(optarg, &invert, &optind, 0);
-               parse_interface(argv[optind-1], info->physindev, info->in_mask);
+               parse_interface(argv[optind-1], info->physindev,
+                               (unsigned char *)info->in_mask);
                if (invert)
                        info->invert |= IP6T_PHYSDEV_OP_IN;
                info->bitmask |= IP6T_PHYSDEV_OP_IN;
@@ -65,7 +66,7 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                        goto multiple_use;
                check_inverse(optarg, &invert, &optind, 0);
                parse_interface(argv[optind-1], info->physoutdev,
-                               info->out_mask);
+                               (unsigned char *)info->out_mask);
                if (invert)
                        info->invert |= IP6T_PHYSDEV_OP_OUT;
                info->bitmask |= IP6T_PHYSDEV_OP_OUT;
index 846ec7c..1e635fc 100644 (file)
@@ -3,7 +3,7 @@ to a bridge device. This module is a part of the infrastructure that enables
 a transparent bridging IP firewall and is only useful for kernel versions
 above version 2.5.44.
 .TP
-.B --physdev-in name
+.BR --physdev-in " [!] \fIname\fP"
 Name of a bridge port via which a packet is received (only for
 packets entering the
 .BR INPUT ,
@@ -14,7 +14,7 @@ chains). If the interface name ends in a "+", then any
 interface which begins with this name will match. If the packet didn't arrive
 through a bridge device, this packet won't match this option, unless '!' is used.
 .TP
-.B --physdev-out name
+.BR --physdev-out " [!] \fIname\fP"
 Name of a bridge port via which a packet is going to be sent (for packets
 entering the
 .BR FORWARD ,
@@ -31,12 +31,12 @@ chain. If the packet won't leave by a bridge device or it is yet unknown what
 the output device will be, then the packet won't match this option, unless
 '!' is used.
 .TP
-.B --physdev-is-in
+.RB "[!] " --physdev-is-in
 Matches if the packet has entered through a bridge interface.
 .TP
-.B --physdev-is-out
+.RB "[!] " --physdev-is-out
 Matches if the packet will leave through a bridge interface.
 .TP
-.B --physdev-is-bridged
+.RB "[!] " --physdev-is-bridged
 Matches if the packet is being bridged and therefore is not being routed.
 This is only useful in the FORWARD and POSTROUTING chains.
diff --git a/extensions/libip6t_policy.c b/extensions/libip6t_policy.c
new file mode 100644 (file)
index 0000000..2f4453e
--- /dev/null
@@ -0,0 +1,478 @@
+/* Shared library add-on to iptables to add policy support. */
+
+#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 <ip6tables.h>
+
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include "../include/linux/netfilter_ipv6/ip6t_policy.h"
+
+/*
+ * HACK: global pointer to current matchinfo for making
+ * final checks and adjustments in final_check.
+ */
+static struct ip6t_policy_info *policy_info;
+
+static void help(void)
+{
+       printf(
+"policy v%s options:\n"
+"  --dir in|out                        match policy applied during decapsulation/\n"
+"                              policy to be applied during encapsulation\n"
+"  --pol none|ipsec            match policy\n"
+"  --strict                    match entire policy instead of single element\n"
+"                              at any position\n"
+"[!] --reqid reqid             match reqid\n"
+"[!] --spi spi                 match SPI\n"
+"[!] --proto proto             match protocol (ah/esp/ipcomp)\n"
+"[!] --mode mode               match mode (transport/tunnel)\n"
+"[!] --tunnel-src addr/masklen match tunnel source\n"
+"[!] --tunnel-dst addr/masklen match tunnel destination\n"
+"  --next                      begin next element in policy\n",
+       IPTABLES_VERSION);
+}
+
+static struct option 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'
+       },
+       { }
+};
+
+/* FIXME - Duplicated code from ip6tables.c */
+/* Duplicated to stop too many changes in other files .... */
+static void
+in6addrcpy(struct in6_addr *dst, struct in6_addr *src)
+{
+        memcpy(dst, src, sizeof(struct in6_addr));
+        /* dst->s6_addr = src->s6_addr; */
+}
+
+static char *
+addr_to_numeric(const struct in6_addr *addrp)
+{
+        /* 0000:0000:0000:0000:0000:000.000.000.000
+        * 0000:0000:0000:0000:0000:0000:0000:0000 */
+        static char buf[50+1];
+        return (char *)inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
+}
+
+static char *
+mask_to_numeric(const struct in6_addr *addrp)
+{
+        static char buf[50+2];
+        int l = ipv6_prefix_length(addrp);
+        if (l == -1) {
+               strcpy(buf, "/");
+               strcat(buf, addr_to_numeric(addrp));
+               return buf;
+       }
+       sprintf(buf, "/%d", l);
+       return buf;
+}
+
+/* These should be in include/ip6tables.h... */
+extern u_int16_t parse_protocol(const char *s);
+extern void parse_hostnetworkmask(const char *name, struct in6_addr **addrpp,
+               struct in6_addr *maskp, unsigned int *naddrs);
+
+/* End duplicated code from ip6tables.c */
+
+static void init(struct ip6t_entry_match *m, unsigned int *nfcache)
+{
+       *nfcache |= NFC_UNKNOWN;
+}
+
+static int parse_direction(char *s)
+{
+       if (strcmp(s, "in") == 0)
+               return IP6T_POLICY_MATCH_IN;
+       if (strcmp(s, "out") == 0)
+               return IP6T_POLICY_MATCH_OUT;
+       exit_error(PARAMETER_PROBLEM, "policy_match: invalid dir `%s'", s);
+}
+
+static int parse_policy(char *s)
+{
+       if (strcmp(s, "none") == 0)
+               return IP6T_POLICY_MATCH_NONE;
+       if (strcmp(s, "ipsec") == 0)
+               return 0;
+       exit_error(PARAMETER_PROBLEM, "policy match: invalid policy `%s'", s);
+}
+
+static int parse_mode(char *s)
+{
+       if (strcmp(s, "transport") == 0)
+               return IP6T_POLICY_MODE_TRANSPORT;
+       if (strcmp(s, "tunnel") == 0)
+               return IP6T_POLICY_MODE_TUNNEL;
+       exit_error(PARAMETER_PROBLEM, "policy match: invalid mode `%s'", s);
+}
+
+static int parse(int c, char **argv, int invert, unsigned int *flags,
+                 const struct ip6t_entry *entry,
+                 unsigned int *nfcache,
+                 struct ip6t_entry_match **match)
+{
+       struct ip6t_policy_info *info = (void *)(*match)->data;
+       struct ip6t_policy_elem *e = &info->pol[info->len];
+       struct in6_addr *addr = NULL, mask;
+       unsigned int naddr = 0;
+       int mode;
+
+       check_inverse(optarg, &invert, &optind, 0);
+
+       switch (c) {
+       case '1':
+               if (info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --dir option");
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --dir option");
+
+               info->flags |= parse_direction(argv[optind-1]);
+               break;
+       case '2':
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --policy option");
+
+               info->flags |= parse_policy(argv[optind-1]);
+               break;
+       case '3':
+               if (info->flags & IP6T_POLICY_MATCH_STRICT)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --strict option");
+
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --strict option");
+
+               info->flags |= IP6T_POLICY_MATCH_STRICT;
+               break;
+       case '4':
+               if (e->match.reqid)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --reqid option");
+
+               e->match.reqid = 1;
+               e->invert.reqid = invert;
+               e->reqid = strtol(argv[optind-1], NULL, 10);
+               break;
+       case '5':
+               if (e->match.spi)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --spi option");
+
+               e->match.spi = 1;
+               e->invert.spi = invert;
+               e->spi = strtol(argv[optind-1], NULL, 0x10);
+               break;
+       case '6':
+               if (e->match.saddr)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --tunnel-src option");
+
+               parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
+               if (naddr > 1)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: name resolves to multiple IPs");
+
+               e->match.saddr = 1;
+               e->invert.saddr = invert;
+               in6addrcpy(&e->saddr.a6, addr);
+               in6addrcpy(&e->smask.a6, &mask);
+                break;
+       case '7':
+               if (e->match.daddr)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --tunnel-dst option");
+
+               parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
+               if (naddr > 1)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: name resolves to multiple IPs");
+
+               e->match.daddr = 1;
+               e->invert.daddr = invert;
+               in6addrcpy(&e->daddr.a6, addr);
+               in6addrcpy(&e->dmask.a6, &mask);
+               break;
+       case '8':
+               if (e->match.proto)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --proto option");
+
+               e->proto = parse_protocol(argv[optind-1]);
+               if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
+                   e->proto != IPPROTO_COMP)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: protocol must ah/esp/ipcomp");
+               e->match.proto = 1;
+               e->invert.proto = invert;
+               break;
+       case '9':
+               if (e->match.mode)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --mode option");
+
+               mode = parse_mode(argv[optind-1]);
+               e->match.mode = 1;
+               e->invert.mode = invert;
+               e->mode = mode;
+               break;
+       case 'a':
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --next option");
+
+               if (++info->len == IP6T_POLICY_MAX_ELEM)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: maximum policy depth reached");
+               break;
+       default:
+               return 0;
+       }
+
+       policy_info = info;
+       return 1;
+}
+
+static void final_check(unsigned int flags)
+{
+       struct ip6t_policy_info *info = policy_info;
+       struct ip6t_policy_elem *e;
+       int i;
+
+       if (info == NULL)
+               exit_error(PARAMETER_PROBLEM,
+                          "policy match: no parameters given");
+
+       if (!(info->flags & (IP6T_POLICY_MATCH_IN|IP6T_POLICY_MATCH_OUT)))
+               exit_error(PARAMETER_PROBLEM,
+                          "policy match: neither --in nor --out specified");
+
+       if (info->flags & IP6T_POLICY_MATCH_NONE) {
+               if (info->flags & IP6T_POLICY_MATCH_STRICT)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: policy none but --strict given");
+
+               if (info->len != 0)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: policy none but policy given");
+       } else
+               info->len++;    /* increase len by 1, no --next after last element */
+
+       if (!(info->flags & IP6T_POLICY_MATCH_STRICT) && info->len > 1)
+               exit_error(PARAMETER_PROBLEM,
+                          "policy match: multiple elements but no --strict");
+
+       for (i = 0; i < info->len; i++) {
+               e = &info->pol[i];
+
+                if (info->flags & IP6T_POLICY_MATCH_STRICT &&
+                   !(e->match.reqid || e->match.spi || e->match.saddr ||
+                      e->match.daddr || e->match.proto || e->match.mode))
+                        exit_error(PARAMETER_PROBLEM,
+                                   "policy match: empty policy element");
+
+               if ((e->match.saddr || e->match.daddr)
+                   && ((e->mode == IP6T_POLICY_MODE_TUNNEL && e->invert.mode) ||
+                       (e->mode == IP6T_POLICY_MODE_TRANSPORT && !e->invert.mode)))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: --tunnel-src/--tunnel-dst "
+                                  "is only valid in tunnel mode");
+       }
+}
+
+static void print_mode(char *prefix, u_int8_t mode, int numeric)
+{
+       printf("%smode ", prefix);
+
+       switch (mode) {
+       case IP6T_POLICY_MODE_TRANSPORT:
+               printf("transport ");
+               break;
+       case IP6T_POLICY_MODE_TUNNEL:
+               printf("tunnel ");
+               break;
+       default:
+               printf("??? ");
+               break;
+       }
+}
+
+static void print_proto(char *prefix, u_int8_t proto, int numeric)
+{
+       struct protoent *p = NULL;
+
+       printf("%sproto ", prefix);
+       if (!numeric)
+               p = getprotobynumber(proto);
+       if (p != NULL)
+               printf("%s ", p->p_name);
+       else
+               printf("%u ", proto);
+}
+
+#define PRINT_INVERT(x)                \
+do {                           \
+       if (x)                  \
+               printf("! ");   \
+} while(0)
+
+static void print_entry(char *prefix, const struct ip6t_policy_elem *e,
+                        int numeric)
+{
+       if (e->match.reqid) {
+               PRINT_INVERT(e->invert.reqid);
+               printf("%sreqid %u ", prefix, e->reqid);
+       }
+       if (e->match.spi) {
+               PRINT_INVERT(e->invert.spi);
+               printf("%sspi 0x%x ", prefix, e->spi);
+       }
+       if (e->match.proto) {
+               PRINT_INVERT(e->invert.proto);
+               print_proto(prefix, e->proto, numeric);
+       }
+       if (e->match.mode) {
+               PRINT_INVERT(e->invert.mode);
+               print_mode(prefix, e->mode, numeric);
+       }
+       if (e->match.daddr) {
+               PRINT_INVERT(e->invert.daddr);
+               printf("%stunnel-dst %s%s ", prefix,
+                      addr_to_numeric((struct in6_addr *)&e->daddr),
+                      mask_to_numeric((struct in6_addr *)&e->dmask));
+       }
+       if (e->match.saddr) {
+               PRINT_INVERT(e->invert.saddr);
+               printf("%stunnel-src %s%s ", prefix,
+                      addr_to_numeric((struct in6_addr *)&e->saddr),
+                      mask_to_numeric((struct in6_addr *)&e->smask));
+       }
+}
+
+static void print_flags(char *prefix, const struct ip6t_policy_info *info)
+{
+       if (info->flags & IP6T_POLICY_MATCH_IN)
+               printf("%sdir in ", prefix);
+       else
+               printf("%sdir out ", prefix);
+
+       if (info->flags & IP6T_POLICY_MATCH_NONE)
+               printf("%spol none ", prefix);
+       else
+               printf("%spol ipsec ", prefix);
+
+       if (info->flags & IP6T_POLICY_MATCH_STRICT)
+               printf("%sstrict ", prefix);
+}
+
+static void print(const struct ip6t_ip6 *ip,
+                  const struct ip6t_entry_match *match,
+                 int numeric)
+{
+       const struct ip6t_policy_info *info = (void *)match->data;
+       unsigned int i;
+
+       printf("policy match ");
+       print_flags("", info);
+       for (i = 0; i < info->len; i++) {
+               if (info->len > 1)
+                       printf("[%u] ", i);
+               print_entry("", &info->pol[i], numeric);
+       }
+
+       printf("\n");
+}
+
+static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
+{
+       const struct ip6t_policy_info *info = (void *)match->data;
+       unsigned int i;
+
+       print_flags("--", info);
+       for (i = 0; i < info->len; i++) {
+               print_entry("--", &info->pol[i], 0);
+               if (i + 1 < info->len)
+                       printf("--next ");
+       }
+}
+
+struct ip6tables_match policy = {
+       .name           = "policy",
+       .version        = IPTABLES_VERSION,
+       .size           = IP6T_ALIGN(sizeof(struct ip6t_policy_info)),
+       .userspacesize  = IP6T_ALIGN(sizeof(struct ip6t_policy_info)),
+       .help           = help,
+       .init           = init,
+       .parse          = parse,
+       .final_check    = final_check,
+       .print          = print,
+       .save           = save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_match6(&policy);
+}
diff --git a/extensions/libip6t_policy.man b/extensions/libip6t_policy.man
new file mode 100644 (file)
index 0000000..eed163e
--- /dev/null
@@ -0,0 +1,48 @@
+This modules matches the policy used by IPsec for handling a packet.
+.TP
+.BI "--dir " "in|out"
+Used to select whether to match the policy used for decapsulation or the
+policy that will be used for encapsulation.
+.B in
+is valid in the
+.B PREROUTING, INPUT and FORWARD
+chains,
+.B out
+is valid in the
+.B POSTROUTING, OUTPUT and FORWARD
+chains.
+.TP
+.BI "--pol " "none|ipsec"
+Matches if the packet is subject to IPsec processing.
+.TP
+.BI "--strict"
+Selects whether to match the exact policy or match if any rule of
+the policy matches the given policy.
+.TP
+.BI "--reqid " "id"
+Matches the reqid of the policy rule. The reqid can be specified with
+.B setkey(8)
+using
+.B unique:id
+as level.
+.TP
+.BI "--spi " "spi"
+Matches the SPI of the SA.
+.TP
+.BI "--proto " "ah|esp|ipcomp"
+Matches the encapsulation protocol.
+.TP
+.BI "--mode " "tunnel|transport"
+Matches the encapsulation mode.
+.TP
+.BI "--tunnel-src " "addr[/mask]"
+Matches the source end-point address of a tunnel mode SA.
+Only valid with --mode tunnel.
+.TP
+.BI "--tunnel-dst " "addr[/mask]"
+Matches the destination end-point address of a tunnel mode SA.
+Only valid with --mode tunnel.
+.TP
+.BI "--next"
+Start the next element in the policy specification. Can only be used with
+--strict
index 4347ecd..e56d5f4 100644 (file)
@@ -1,19 +1,19 @@
 Match on IPv6 routing header
 .TP
-.BI "--rt-type " "[!]" "type"
+.BR "--rt-type" " [!] \fItype\fP"
 Match the type (numeric).
 .TP
-.BI "--rt-segsleft" "[!]" "num[:num]"
+.BR "--rt-segsleft" " [!] \fInum\fP[:\fInum\fP]"
 Match the `segments left' field (range).
 .TP
-.BI "--rt-len" "[!]" "length"
-Match the length of this header
+.BR "--rt-len" " [!] \fIlength\fP"
+Match the length of this header.
 .TP
-.BI "--rt-0-res"
+.BR "--rt-0-res"
 Match the reserved field, too (type=0)
 .TP
-.BI "--rt-0-addrs ADDR[,ADDR...]
+.BR "--rt-0-addrs" " \fIADDR\fP[,\fIADDR\fP...]"
 Match type=0 addresses (list).
 .TP
-.BI "--rt-0-not-strict"
+.BR "--rt-0-not-strict"
 List of type=0 addresses is not a strict list.
diff --git a/extensions/libip6t_state.c b/extensions/libip6t_state.c
new file mode 100644 (file)
index 0000000..84fd1a4
--- /dev/null
@@ -0,0 +1,163 @@
+/* Ugly hack to make state matching for ipv6 work before iptables-1.4.x is finished */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <ip6tables.h>
+#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ipt_state.h>
+
+#ifndef IPT_STATE_UNTRACKED
+#define IPT_STATE_UNTRACKED (1 << (IP_CT_NUMBER + 1))
+#endif
+
+/* Function which prints out usage message. */
+static void
+help(void)
+{
+       printf(
+"state v%s options:\n"
+" [!] --state [INVALID|ESTABLISHED|NEW|RELATED|UNTRACKED][,...]\n"
+"                              State(s) to match\n"
+"\n", IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { "state", 1, 0, '1' },
+       {0}
+};
+
+static int
+parse_state(const char *state, size_t strlen, struct ipt_state_info *sinfo)
+{
+       if (strncasecmp(state, "INVALID", strlen) == 0)
+               sinfo->statemask |= IPT_STATE_INVALID;
+       else if (strncasecmp(state, "NEW", strlen) == 0)
+               sinfo->statemask |= IPT_STATE_BIT(IP_CT_NEW);
+       else if (strncasecmp(state, "ESTABLISHED", strlen) == 0)
+               sinfo->statemask |= IPT_STATE_BIT(IP_CT_ESTABLISHED);
+       else if (strncasecmp(state, "RELATED", strlen) == 0)
+               sinfo->statemask |= IPT_STATE_BIT(IP_CT_RELATED);
+       else if (strncasecmp(state, "UNTRACKED", strlen) == 0)
+               sinfo->statemask |= IPT_STATE_UNTRACKED;
+       else
+               return 0;
+       return 1;
+}
+
+static void
+parse_states(const char *arg, struct ipt_state_info *sinfo)
+{
+       const char *comma;
+
+       while ((comma = strchr(arg, ',')) != NULL) {
+               if (comma == arg || !parse_state(arg, comma-arg, sinfo))
+                       exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
+               arg = comma+1;
+       }
+
+       if (strlen(arg) == 0 || !parse_state(arg, strlen(arg), sinfo))
+               exit_error(PARAMETER_PROBLEM, "Bad state `%s'", arg);
+}
+
+/* Function which parses command options; returns true if it
+   ate an option */
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ip6t_entry *entry,
+      unsigned int *nfcache,
+      struct ip6t_entry_match **match)
+{
+       struct ipt_state_info *sinfo = (struct ipt_state_info *)(*match)->data;
+
+       switch (c) {
+       case '1':
+               check_inverse(optarg, &invert, &optind, 0);
+
+               parse_states(argv[optind-1], sinfo);
+               if (invert)
+                       sinfo->statemask = ~sinfo->statemask;
+               *flags = 1;
+               break;
+
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+/* Final check; must have specified --state. */
+static void final_check(unsigned int flags)
+{
+       if (!flags)
+               exit_error(PARAMETER_PROBLEM, "You must specify `--state'");
+}
+
+static void print_state(unsigned int statemask)
+{
+       const char *sep = "";
+
+       if (statemask & IPT_STATE_INVALID) {
+               printf("%sINVALID", sep);
+               sep = ",";
+       }
+       if (statemask & IPT_STATE_BIT(IP_CT_NEW)) {
+               printf("%sNEW", sep);
+               sep = ",";
+       }
+       if (statemask & IPT_STATE_BIT(IP_CT_RELATED)) {
+               printf("%sRELATED", sep);
+               sep = ",";
+       }
+       if (statemask & IPT_STATE_BIT(IP_CT_ESTABLISHED)) {
+               printf("%sESTABLISHED", sep);
+               sep = ",";
+       }
+       if (statemask & IPT_STATE_UNTRACKED) {
+               printf("%sUNTRACKED", sep);
+               sep = ",";
+       }
+       printf(" ");
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ip6t_ip6 *ip,
+      const struct ip6t_entry_match *match,
+      int numeric)
+{
+       struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data;
+
+       printf("state ");
+       print_state(sinfo->statemask);
+}
+
+/* Saves the matchinfo in parsable form to stdout. */
+static void save(const struct ip6t_ip6 *ip, const struct ip6t_entry_match *match)
+{
+       struct ipt_state_info *sinfo = (struct ipt_state_info *)match->data;
+
+       printf("--state ");
+       print_state(sinfo->statemask);
+}
+
+static struct ip6tables_match state = { 
+       .next           = NULL,
+       .name           = "state",
+       .version        = IPTABLES_VERSION,
+       .size           = IP6T_ALIGN(sizeof(struct ipt_state_info)),
+       .userspacesize  = IP6T_ALIGN(sizeof(struct ipt_state_info)),
+       .help           = &help,
+       .parse          = &parse,
+       .final_check    = &final_check,
+       .print          = &print,
+       .save           = &save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_match6(&state);
+}
index 16c8053..07c9b25 100644 (file)
@@ -32,7 +32,7 @@ init(struct ipt_entry_target *t, unsigned int *nfcache)
 {
 }
 
-int string_to_priority(const unsigned char *s, unsigned int *p)
+int string_to_priority(const char *s, unsigned int *p)
 {
        unsigned int i, j;
 
index d2bee97..3268ac5 100644 (file)
@@ -32,17 +32,25 @@ help(void)
 "  --clustermac <mac>           Set clusterIP MAC address\n"
 "  --total-nodes <num>          Set number of total nodes in cluster\n"
 "  --local-node <num>           Set the local node number\n"
-"  --hash-init\n"
+"  --hash-init <num>            Set init value of the Jenkins hash\n"
 "\n",
 IPTABLES_VERSION);
 }
 
+#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 struct option opts[] = {
        { "new", 0, 0, '1' },
        { "hashmode", 1, 0, '2' },
        { "clustermac", 1, 0, '3' },
        { "total-nodes", 1, 0, '4' },
        { "local-node", 1, 0, '5' },
+       { "hash-init", 1, 0, '6' },
        { 0 }
 };
 
@@ -75,12 +83,6 @@ parse_mac(const char *mac, char *macbuf)
        }
 }
 
-#define        PARAM_NEW       0x0001
-#define PARAM_HMODE    0x0002
-#define PARAM_MAC      0x0004
-#define PARAM_TOTALNODE        0x0008
-#define PARAM_LOCALNODE        0x0010
-
 static int
 parse(int c, char **argv, int invert, unsigned int *flags,
       const struct ipt_entry *entry,
@@ -118,7 +120,7 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                        exit_error(PARAMETER_PROBLEM, "Can only specify MAC combined with `--new'\n");
                if (*flags & PARAM_MAC)
                        exit_error(PARAMETER_PROBLEM, "Can only specify MAC once\n");
-               parse_mac(optarg, cipinfo->clustermac);
+               parse_mac(optarg, (char *)cipinfo->clustermac);
                if (!(cipinfo->clustermac[0] & 0x01))
                        exit_error(PARAMETER_PROBLEM, "MAC has to be a multicast ethernet address\n");
                *flags |= PARAM_MAC;
@@ -144,6 +146,16 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                cipinfo->local_nodes[0] = (u_int16_t)num;
                *flags |= PARAM_LOCALNODE;
                break;
+       case '6':
+               if (!(*flags & PARAM_NEW))
+                       exit_error(PARAMETER_PROBLEM, "Can only specify hash init value combined with `--new'\n");
+               if (*flags & PARAM_HASHINIT)
+                       exit_error(PARAMETER_PROBLEM, "Can specify hash init value only once\n");
+               if (string_to_number(optarg, 0, UINT_MAX, &num) < 0)
+                       exit_error(PARAMETER_PROBLEM, "Unable to parse `%s'\n", optarg);
+               cipinfo->hash_initval = num;
+               *flags |= PARAM_HASHINIT;
+               break;
        default:
                return 0;
        }
@@ -157,7 +169,8 @@ final_check(unsigned int flags)
        if (flags == 0)
                return;
 
-       if (flags == (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE))
+       if ((flags & (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE))
+               == (PARAM_NEW|PARAM_HMODE|PARAM_MAC|PARAM_TOTALNODE|PARAM_LOCALNODE))
                return;
 
        exit_error(PARAMETER_PROBLEM, "CLUSTERIP target: Invalid parameter combination\n");
@@ -206,36 +219,32 @@ print(const struct ipt_ip *ip,
                return;
        }
 
-       printf("CLUSTERIP hashmode=%s clustermac=%s total_nodes=%u local_node=%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,
-               cipinfo->local_nodes[0]);
+               cipinfo->local_nodes[0],
+               cipinfo->hash_initval);
 }
 
 /* Saves the union ipt_targinfo in parsable form to stdout. */
 static void
 save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
 {
-       /*
-       const struct ipt_connmark_target_info *markinfo =
-               (const struct ipt_connmark_target_info *)target->data;
+       const struct ipt_clusterip_tgt_info *cipinfo =
+               (const struct ipt_clusterip_tgt_info *)target->data;
 
-       switch (markinfo->mode) {
-       case IPT_CONNMARK_SET:
-           printf("--set-mark 0x%lx ", markinfo->mark);
-           break;
-       case IPT_CONNMARK_SAVE:
-           printf("--save-mark ");
-           break;
-       case IPT_CONNMARK_RESTORE:
-           printf("--restore-mark ");
-           break;
-       default:
-           printf("ERROR: UNKNOWN CONNMARK MODE ");
-           break;
-       }
-       */
+       /* if this is not a new entry, we don't need to save target
+        * parameters */
+       if (!cipinfo->flags & CLUSTERIP_FLAG_NEW)
+               return;
+
+       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,
+              cipinfo->local_nodes[0],
+              cipinfo->hash_initval);
 }
 
 static struct iptables_target clusterip = { 
index bc739fc..2e17b3f 100644 (file)
@@ -72,25 +72,17 @@ parse(int c, char **argv, int invert, unsigned int *flags,
        struct ipt_connmark_target_info *markinfo
                = (struct ipt_connmark_target_info *)(*target)->data;
 
-#ifdef KERNEL_64_USERSPACE_32
-       markinfo->mask = ~0ULL;
-#else
-       markinfo->mask = ~0UL;
-#endif
+       markinfo->mask = 0xffffffffUL;
 
        switch (c) {
                char *end;
        case '1':
                markinfo->mode = IPT_CONNMARK_SET;
-#ifdef KERNEL_64_USERSPACE_32
-               markinfo->mark = strtoull(optarg, &end, 0);
-               if (*end == '/' && end[1] != '\0')
-                   markinfo->mask = strtoull(end+1, &end, 0);
-#else
+
                markinfo->mark = strtoul(optarg, &end, 0);
                if (*end == '/' && end[1] != '\0')
                    markinfo->mask = strtoul(end+1, &end, 0);
-#endif
+
                if (*end != '\0' || end == optarg)
                        exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
                if (*flags)
@@ -116,11 +108,8 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                if (!*flags)
                        exit_error(PARAMETER_PROBLEM,
                                   "CONNMARK target: Can't specify --mask without a operation");
-#ifdef KERNEL_64_USERSPACE_32
-               markinfo->mask = strtoull(optarg, &end, 0);
-#else
                markinfo->mask = strtoul(optarg, &end, 0);
-#endif
+
                if (*end != '\0' || end == optarg)
                        exit_error(PARAMETER_PROBLEM, "Bad MASK value `%s'", optarg);
                break;
@@ -139,22 +128,6 @@ final_check(unsigned int flags)
                           "CONNMARK target: No operation specified");
 }
 
-#ifdef KERNEL_64_USERSPACE_32
-static void
-print_mark(unsigned long long mark)
-{
-       printf("0x%llx", mark);
-}
-
-static void
-print_mask(const char *text, unsigned long long mask)
-{
-       if (mask != ~0ULL)
-               printf("%s0x%llx", text, mask);
-}
-
-#else
-
 static void
 print_mark(unsigned long mark)
 {
@@ -164,10 +137,9 @@ print_mark(unsigned long mark)
 static void
 print_mask(const char *text, unsigned long mask)
 {
-       if (mask != ~0UL)
+       if (mask != 0xffffffffUL)
                printf("%s0x%lx", text, mask);
 }
-#endif
 
 
 /* Prints out the target info. */
index 9e4f525..bdc15eb 100644 (file)
@@ -143,7 +143,8 @@ parse(int c, char **argv, int invert, unsigned int *flags,
        int portok;
 
        if (entry->ip.proto == IPPROTO_TCP
-           || entry->ip.proto == IPPROTO_UDP)
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
                portok = 1;
        else
                portok = 0;
@@ -154,6 +155,13 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                        exit_error(PARAMETER_PROBLEM,
                                   "Unexpected `!' after --to-destination");
 
+               if (*flags) {
+                       if (!kernel_version)
+                               get_kernel_version();
+                       if (kernel_version > LINUX_VERSION(2, 6, 10))
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Multiple --to-destination not supported");
+               }
                *target = parse_to(optarg, portok, info);
                *flags = 1;
                return 1;
index 7579e14..b14c6da 100644 (file)
@@ -21,7 +21,10 @@ If no port range is specified, then the destination port will never be
 modified.
 .RS
 .PP
-You can add several --to-destination options.  If you specify more
-than one destination address, either via an address range or multiple
---to-destination options, a simple round-robin (one after another in
-cycle) load balancing takes place between these adresses.
+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
+after another in cycle) load balancing takes place between these addresses.
+Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
+anymore.
+
index 90e2a34..c50d902 100644 (file)
@@ -49,7 +49,7 @@ static struct option opts[] = {
 };
 
 static void
-parse_dscp(const unsigned char *s, struct ipt_DSCP_info *dinfo)
+parse_dscp(const char *s, struct ipt_DSCP_info *dinfo)
 {
        unsigned int dscp;
        
@@ -67,7 +67,7 @@ parse_dscp(const unsigned char *s, struct ipt_DSCP_info *dinfo)
 
 
 static void
-parse_class(const unsigned char *s, struct ipt_DSCP_info *dinfo)
+parse_class(const char *s, struct ipt_DSCP_info *dinfo)
 {
        unsigned int dscp = class_to_dscp(s);
 
index b661012..7eddcc0 100644 (file)
@@ -81,7 +81,8 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                = (struct ip_nat_multi_range *)(*target)->data;
 
        if (entry->ip.proto == IPPROTO_TCP
-           || entry->ip.proto == IPPROTO_UDP)
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
                portok = 1;
        else
                portok = 0;
diff --git a/extensions/libipt_NFQUEUE.c b/extensions/libipt_NFQUEUE.c
new file mode 100644 (file)
index 0000000..bc4e82f
--- /dev/null
@@ -0,0 +1,114 @@
+/* Shared library add-on to iptables for NFQ
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+#include <iptables.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_NFQUEUE.h>
+
+static void init(struct ipt_entry_target *t, unsigned int *nfcache) 
+{
+}
+
+static void help(void) 
+{
+       printf(
+"NFQUEUE target options\n"
+"  --queue-num value           Send packet to QUEUE number <value>.\n"
+"                              Valid queue numbers are 0-65535\n"
+);
+}
+
+static struct option opts[] = {
+       { "queue-num", 1, 0, 'F' },
+       { 0 }
+};
+
+static void
+parse_num(const char *s, struct ipt_NFQ_info *tinfo)
+{
+       unsigned int num;
+       
+       if (string_to_number(s, 0, 65535, &num) == -1)
+               exit_error(PARAMETER_PROBLEM,
+                          "Invalid queue number `%s'\n", s);
+
+       tinfo->queuenum = num & 0xffff;
+       return;
+}
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ipt_entry *entry,
+      struct ipt_entry_target **target)
+{
+       struct ipt_NFQ_info *tinfo
+               = (struct ipt_NFQ_info *)(*target)->data;
+
+       switch (c) {
+       case 'F':
+               if (*flags)
+                       exit_error(PARAMETER_PROBLEM, "NFQUEUE target: "
+                                  "Only use --queue-num ONCE!");
+               parse_num(optarg, tinfo);
+               break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+}
+
+/* Prints out the targinfo. */
+static void
+print(const struct ipt_ip *ip,
+      const struct ipt_entry_target *target,
+      int numeric)
+{
+       const struct ipt_NFQ_info *tinfo =
+               (const struct ipt_NFQ_info *)target->data;
+       printf("NFQUEUE num %u", tinfo->queuenum);
+}
+
+/* Saves the union ipt_targinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
+{
+       const struct ipt_NFQ_info *tinfo =
+               (const struct ipt_NFQ_info *)target->data;
+
+       printf("--queue-num %u ", tinfo->queuenum);
+}
+
+static struct iptables_target nfqueue = { 
+       .next           = NULL,
+       .name           = "NFQUEUE",
+       .version        = IPTABLES_VERSION,
+       .size           = IPT_ALIGN(sizeof(struct ipt_NFQ_info)),
+       .userspacesize  = IPT_ALIGN(sizeof(struct ipt_NFQ_info)),
+       .help           = &help,
+       .init           = &init,
+       .parse          = &parse,
+       .final_check    = &final_check,
+       .print          = &print,
+       .save           = &save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_target(&nfqueue);
+}
diff --git a/extensions/libipt_NFQUEUE.man b/extensions/libipt_NFQUEUE.man
new file mode 100644 (file)
index 0000000..c4e9d11
--- /dev/null
@@ -0,0 +1,12 @@
+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.  
+.TP
+.BR "--queue-num " "\fIvalue"
+This specifies the QUEUE number to use. Valud queue numbers are 0 to 65535. The default value is 0.
+.TP
+It can only be used with Kernel versions 2.6.14 or later, since it requires
+the
+.B
+nfnetlink_queue
+kernel support.
index 1395f62..e29bf2f 100644 (file)
@@ -81,7 +81,8 @@ parse(int c, char **argv, int invert, unsigned int *flags,
        int portok;
 
        if (entry->ip.proto == IPPROTO_TCP
-           || entry->ip.proto == IPPROTO_UDP)
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
                portok = 1;
        else
                portok = 0;
index f982331..70859eb 100644 (file)
@@ -44,7 +44,7 @@ static const struct reject_names reject_table[] = {
         IPT_ICMP_NET_PROHIBITED, "ICMP network prohibited"},
        {"icmp-host-prohibited", "host-prohib",
         IPT_ICMP_HOST_PROHIBITED, "ICMP host prohibited"},
-       {"tcp-reset", "tcp-reset",
+       {"tcp-reset", "tcp-rst",
         IPT_TCP_RESET, "TCP RST packet"},
        {"icmp-admin-prohibited", "admin-prohib",
         IPT_ICMP_ADMIN_PROHIBITED, "ICMP administratively prohibited (*)"}
index a893a47..867c9d0 100644 (file)
@@ -143,7 +143,8 @@ parse(int c, char **argv, int invert, unsigned int *flags,
        int portok;
 
        if (entry->ip.proto == IPPROTO_TCP
-           || entry->ip.proto == IPPROTO_UDP)
+           || entry->ip.proto == IPPROTO_UDP
+           || entry->ip.proto == IPPROTO_ICMP)
                portok = 1;
        else
                portok = 0;
@@ -154,6 +155,13 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                        exit_error(PARAMETER_PROBLEM,
                                   "Unexpected `!' after --to-source");
 
+               if (*flags) {
+                       if (!kernel_version)
+                               get_kernel_version();
+                       if (kernel_version > LINUX_VERSION(2, 6, 10))
+                               exit_error(PARAMETER_PROBLEM,
+                                          "Multiple --to-source not supported");
+               }
                *target = parse_to(optarg, portok, info);
                *flags = 1;
                return 1;
index 4cc0397..2d9427f 100644 (file)
@@ -20,7 +20,9 @@ will be mapped to ports below 1024, and other ports will be mapped to
 1024 or above. Where possible, no port alteration will occur.
 .RS
 .PP
-You can add several --to-source options.  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 in
-cycle) takes place between these adresses.
+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
+in cycle) takes place between these addresses.
+Later Kernels (>= 2.6.11-rc1) don't have the ability to NAT to multiple ranges
+anymore.
index da1bce2..30668b0 100644 (file)
@@ -3,6 +3,9 @@ the maximum size for that connection (usually limiting it to your
 outgoing interface's MTU minus 40).  Of course, it can only be used
 in conjunction with
 .BR "-p tcp" .
+It is only valid in the
+.BR mangle
+table.
 .br
 This target is used to overcome criminally braindead ISPs or servers
 which block ICMP Fragmentation Needed packets.  The symptoms of this
@@ -25,7 +28,7 @@ ssh works fine, but scp hangs after initial handshaking.
 Workaround: activate this option and add a rule to your firewall
 configuration like:
 .nf
- iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \\
+ iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN \\
              -j TCPMSS --clamp-mss-to-pmtu
 .fi
 .TP
index 4302950..999f7b0 100644 (file)
@@ -59,7 +59,7 @@ init(struct ipt_entry_target *t, unsigned int *nfcache)
 }
 
 static void
-parse_tos(const unsigned char *s, struct ipt_tos_target_info *info)
+parse_tos(const char *s, struct ipt_tos_target_info *info)
 {
        unsigned int i, tos;
 
index 97de1e1..7300c18 100644 (file)
@@ -1,3 +1,3 @@
-This module matches the SPIs in AH header of IPSec packets.
+This module matches the SPIs in Authentication header of IPsec packets.
 .TP
 .BR "--ahspi " "[!] \fIspi\fP[:\fIspi\fP]"
index c543fc6..692acca 100644 (file)
@@ -30,7 +30,7 @@ static struct option opts[] = {
 };
 
 static void
-parse_comment(const unsigned char *s, struct ipt_comment_info *info)
+parse_comment(const char *s, struct ipt_comment_info *info)
 {      
        int slen = strlen(s);
 
@@ -38,7 +38,7 @@ parse_comment(const unsigned char *s, struct ipt_comment_info *info)
                exit_error(PARAMETER_PROBLEM,
                        "COMMENT must be shorter than %i characters", IPT_MAX_COMMENT_LEN);
        }
-       strcpy(info->comment, s);
+       strcpy((char *)info->comment, s);
 }
 
 /* Function which parses command options; returns true if it
index 0fc51ff..ce2aa95 100644 (file)
@@ -1,4 +1,4 @@
 This matches if a specific /proc filename is '0' or '1'.
 .TP
-.BI "--condition " "[!] filename"
+.BI "--condition " "[!] \fIfilename\fP"
 Match on boolean value stored in /proc/net/ipt_condition/filename file
index 7274194..42e1ab5 100644 (file)
@@ -84,11 +84,11 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                break;
        case '3':
                if (!strcmp(optarg, "packets"))
-                       sinfo->what = IPT_CONNBYTES_WHAT_PKTS;
+                       sinfo->what = IPT_CONNBYTES_PKTS;
                else if (!strcmp(optarg, "bytes"))
-                       sinfo->what = IPT_CONNBYTES_WHAT_BYTES;
+                       sinfo->what = IPT_CONNBYTES_BYTES;
                else if (!strcmp(optarg, "avgpkt"))
-                       sinfo->what = IPT_CONNBYTES_WHAT_AVGPKT;
+                       sinfo->what = IPT_CONNBYTES_AVGPKT;
                else
                        exit_error(PARAMETER_PROBLEM,
                                   "Unknown --connbytes-mode `%s'", optarg);
@@ -105,19 +105,19 @@ static void final_check(unsigned int flags)
 {
        if (flags != 7)
                exit_error(PARAMETER_PROBLEM, "You must specify `--connbytes'"
-                          "`--connbytes-direction' and `--connbytes-mode'");
+                          "`--connbytes-dir' and `--connbytes-mode'");
 }
 
 static void print_mode(struct ipt_connbytes_info *sinfo)
 {
        switch (sinfo->what) {
-               case IPT_CONNBYTES_WHAT_PKTS:
+               case IPT_CONNBYTES_PKTS:
                        fputs("packets ", stdout);
                        break;
-               case IPT_CONNBYTES_WHAT_BYTES:
+               case IPT_CONNBYTES_BYTES:
                        fputs("bytes ", stdout);
                        break;
-               case IPT_CONNBYTES_WHAT_AVGPKT:
+               case IPT_CONNBYTES_AVGPKT:
                        fputs("avgpkt ", stdout);
                        break;
                default:
@@ -181,7 +181,7 @@ static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
        fputs("--connbytes-mode ", stdout);
        print_mode(sinfo);
 
-       fputs("--connbytes-direction ", stdout);
+       fputs("--connbytes-dir ", stdout);
        print_direction(sinfo);
 }
 
index 5bb2491..bc15f0d 100644 (file)
@@ -66,17 +66,13 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                char *end;
        case '1':
                check_inverse(optarg, &invert, &optind, 0);
-#ifdef KERNEL_64_USERSPACE_32
-               markinfo->mark = strtoull(optarg, &end, 0);
-               markinfo->mask = ~0ULL;
-               if (*end == '/')
-                       markinfo->mask = strtoull(end+1, &end, 0);
-#else
+
                markinfo->mark = strtoul(optarg, &end, 0);
-               markinfo->mask = ~0UL;
+               markinfo->mask = 0xffffffffUL;
+               
                if (*end == '/')
                        markinfo->mask = strtoul(end+1, &end, 0);
-#endif
+
                if (*end != '\0' || end == optarg)
                        exit_error(PARAMETER_PROBLEM, "Bad MARK value `%s'", optarg);
                if (invert)
@@ -90,25 +86,14 @@ parse(int c, char **argv, int invert, unsigned int *flags,
        return 1;
 }
 
-#ifdef KERNEL_64_USERSPACE_32
-static void
-print_mark(unsigned long long mark, unsigned long long mask, int numeric)
-{
-       if(mask != ~0ULL)
-               printf("0x%llx/0x%llx ", mark, mask);
-       else
-               printf("0x%llx ", mark);
-}
-#else
 static void
 print_mark(unsigned long mark, unsigned long mask, int numeric)
 {
-       if(mask != ~0UL)
+       if(mask != 0xffffffffUL)
                printf("0x%lx/0x%lx ", mark, mask);
        else
                printf("0x%lx ", mark);
 }
-#endif
 
 /* Final check; must have specified --mark. */
 static void
index 5521684..cdb86c4 100644 (file)
@@ -414,8 +414,8 @@ print_addr(struct in_addr *addr, struct in_addr *mask, int inv, int numeric)
 {
        char buf[BUFSIZ];
 
-        if (inv)
-                       fputc('!', stdout);
+        if (inv) 
+                       printf("! ");
 
        if (mask->s_addr == 0L && !numeric)
                printf("%s ", "anywhere");
@@ -442,6 +442,13 @@ matchinfo_print(const struct ipt_ip *ip, const struct ipt_entry_match *match, in
                print_state(sinfo->statemask);
        }
 
+       if(sinfo->flags & IPT_CONNTRACK_PROTO) {
+               printf("%sctproto ", optpfx);
+               if (sinfo->invflags & IPT_CONNTRACK_PROTO)
+                       printf("! ");
+               printf("%u ", sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum);
+       }
+
        if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) {
                printf("%sctorigsrc ", optpfx);
 
diff --git a/extensions/libipt_dccp.c b/extensions/libipt_dccp.c
new file mode 100644 (file)
index 0000000..af1d20e
--- /dev/null
@@ -0,0 +1,399 @@
+/* Shared library add-on to iptables for DCCP matching
+ *
+ * (C) 2005 by Harald Welte <laforge@netfilter.org>
+ *
+ * This program is distributed under the terms of GNU GPL v2, 1991
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <netdb.h>
+#include <ctype.h>
+
+#include <iptables.h>
+#include <linux/dccp.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_dccp.h>
+
+#if 0
+#define DEBUGP(format, first...) printf(format, ##first)
+#define static
+#else
+#define DEBUGP(format, fist...) 
+#endif
+
+/* Initialize the match. */
+static void
+init(struct ipt_entry_match *m, 
+     unsigned int *nfcache)
+{
+       struct ipt_dccp_info *einfo = (struct ipt_dccp_info *)m->data;
+
+       memset(einfo, 0, sizeof(struct ipt_dccp_info));
+}
+
+static void help(void)
+{
+       printf(
+"DCCP match v%s options\n"
+" --source-port [!] port[:port]                          match source port(s)\n"
+" --sport ...\n"
+" --destination-port [!] port[:port]                     match destination port(s)\n"
+" --dport ...\n"
+,
+       IPTABLES_VERSION);
+}
+
+static struct option opts[] = {
+       { .name = "source-port", .has_arg = 1, .flag = 0, .val = '1' },
+       { .name = "sport", .has_arg = 1, .flag = 0, .val = '1' },
+       { .name = "destination-port", .has_arg = 1, .flag = 0, .val = '2' },
+       { .name = "dport", .has_arg = 1, .flag = 0, .val = '2' },
+       { .name = "dccp-types", .has_arg = 1, .flag = 0, .val = '3' },
+       { .name = "dccp-option", .has_arg = 1, .flag = 0, .val = '4' },
+       { .name = 0 }
+};
+
+static int
+service_to_port(const char *name)
+{
+       struct servent *service;
+
+       if ((service = getservbyname(name, "dccp")) != NULL)
+               return ntohs((unsigned short) service->s_port);
+
+       return -1;
+}
+
+static u_int16_t
+parse_dccp_port(const char *port)
+{
+       unsigned int portnum;
+
+       DEBUGP("%s\n", port);
+       if (string_to_number(port, 0, 65535, &portnum) != -1 ||
+           (portnum = service_to_port(port)) != -1)
+               return (u_int16_t)portnum;
+
+       exit_error(PARAMETER_PROBLEM,
+                  "invalid DCCP port/service `%s' specified", port);
+}
+
+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] = parse_dccp_port(buffer);
+       }
+       else {
+               *cp = '\0';
+               cp++;
+
+               ports[0] = buffer[0] ? parse_dccp_port(buffer) : 0;
+               ports[1] = cp[0] ? parse_dccp_port(cp) : 0xFFFF;
+
+               if (ports[0] > ports[1])
+                       exit_error(PARAMETER_PROBLEM,
+                                  "invalid portrange (min > max)");
+       }
+       free(buffer);
+}
+
+static char *dccp_pkt_types[] = {
+       [DCCP_PKT_REQUEST]      = "REQUEST",
+       [DCCP_PKT_RESPONSE]     = "RESPONSE",
+       [DCCP_PKT_DATA]         = "DATA",
+       [DCCP_PKT_ACK]          = "ACK",
+       [DCCP_PKT_DATAACK]      = "DATAACK",
+       [DCCP_PKT_CLOSEREQ]     = "CLOSEREQ",
+       [DCCP_PKT_CLOSE]        = "CLOSE",
+       [DCCP_PKT_RESET]        = "RESET",
+       [DCCP_PKT_SYNC]         = "SYNC",
+       [DCCP_PKT_SYNCACK]      = "SYNCACK",
+       [DCCP_PKT_INVALID]      = "INVALID",
+};
+
+static u_int16_t
+parse_dccp_types(const char *typestring)
+{
+       u_int16_t typemask = 0;
+       char *ptr, *buffer;
+
+       buffer = strdup(typestring);
+
+       for (ptr = strtok(buffer, ","); ptr; ptr = strtok(NULL, ",")) {
+               unsigned int i;
+               for (i = 0; i < sizeof(dccp_pkt_types)/sizeof(char *); i++) {
+                       if (!strcasecmp(dccp_pkt_types[i], ptr)) {
+                               typemask |= (1 << i);
+                               break;
+                       }
+               }
+               if (i == sizeof(dccp_pkt_types)/sizeof(char *))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Unknown DCCP type `%s'", ptr);
+       }
+
+       free(buffer);
+       return typemask;
+}
+
+static u_int8_t parse_dccp_option(char *optstring)
+{
+       unsigned int ret;
+
+       if (string_to_number(optstring, 1, 255, &ret) == -1)
+               exit_error(PARAMETER_PROBLEM, "Bad DCCP option `%s'",
+                          optstring);
+
+       return (u_int8_t)ret;
+}
+
+static int
+parse(int c, char **argv, int invert, unsigned int *flags,
+      const struct ipt_entry *entry,
+      unsigned int *nfcache,
+      struct ipt_entry_match **match)
+{
+       struct ipt_dccp_info *einfo
+               = (struct ipt_dccp_info *)(*match)->data;
+
+       switch (c) {
+       case '1':
+               if (*flags & IPT_DCCP_SRC_PORTS)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Only one `--source-port' allowed");
+               einfo->flags |= IPT_DCCP_SRC_PORTS;
+               check_inverse(optarg, &invert, &optind, 0);
+               parse_dccp_ports(argv[optind-1], einfo->spts);
+               if (invert)
+                       einfo->invflags |= IPT_DCCP_SRC_PORTS;
+               *flags |= IPT_DCCP_SRC_PORTS;
+               break;
+
+       case '2':
+               if (*flags & IPT_DCCP_DEST_PORTS)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Only one `--destination-port' allowed");
+               einfo->flags |= IPT_DCCP_DEST_PORTS;
+               check_inverse(optarg, &invert, &optind, 0);
+               parse_dccp_ports(argv[optind-1], einfo->dpts);
+               if (invert)
+                       einfo->invflags |= IPT_DCCP_DEST_PORTS;
+               *flags |= IPT_DCCP_DEST_PORTS;
+               break;
+
+       case '3':
+               if (*flags & IPT_DCCP_TYPE)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Only one `--dccp-types' allowed");
+               einfo->flags |= IPT_DCCP_TYPE;
+               check_inverse(optarg, &invert, &optind, 0);
+               einfo->typemask = parse_dccp_types(argv[optind-1]);
+               if (invert)
+                       einfo->invflags |= IPT_DCCP_TYPE;
+               *flags |= IPT_DCCP_TYPE;
+               break;
+
+       case '4':
+               if (*flags & IPT_DCCP_OPTION)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Only one `--dccp-option' allowed");
+               einfo->flags |= IPT_DCCP_OPTION;
+               check_inverse(optarg, &invert, &optind, 0);
+               einfo->option = parse_dccp_option(argv[optind-1]);
+               if (invert)
+                       einfo->invflags |= IPT_DCCP_OPTION;
+               *flags |= IPT_DCCP_OPTION;
+               break;
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static void
+final_check(unsigned int flags)
+{
+}
+
+static char *
+port_to_service(int port)
+{
+       struct servent *service;
+
+       if ((service = getservbyport(htons(port), "dccp")))
+               return service->s_name;
+
+       return NULL;
+}
+
+static void
+print_port(u_int16_t port, int numeric)
+{
+       char *service;
+
+       if (numeric || (service = port_to_service(port)) == NULL)
+               printf("%u", port);
+       else
+               printf("%s", service);
+}
+
+static void
+print_ports(const char *name, u_int16_t min, u_int16_t max,
+           int invert, int numeric)
+{
+       const char *inv = invert ? "!" : "";
+
+       if (min != 0 || max != 0xFFFF || invert) {
+               printf("%s", name);
+               if (min == max) {
+                       printf(":%s", inv);
+                       print_port(min, numeric);
+               } else {
+                       printf("s:%s", inv);
+                       print_port(min, numeric);
+                       printf(":");
+                       print_port(max, numeric);
+               }
+               printf(" ");
+       }
+}
+
+static void
+print_types(u_int16_t types, int inverted, int numeric)
+{
+       int have_type = 0;
+
+       if (inverted)
+               printf("! ");
+
+       while (types) {
+               unsigned int i;
+
+               for (i = 0; !(types & (1 << i)); i++);
+
+               if (have_type)
+                       printf(",");
+               else
+                       have_type = 1;
+
+               if (numeric)
+                       printf("%u", i);
+               else
+                       printf("%s", dccp_pkt_types[i]);
+
+               types &= ~(1 << i);
+       }
+}
+
+static void
+print_option(u_int8_t option, int invert, int numeric)
+{
+       if (option || invert)
+               printf("option=%s%u ", invert ? "!" : "", option);
+}
+
+/* Prints out the matchinfo. */
+static void
+print(const struct ipt_ip *ip,
+      const struct ipt_entry_match *match,
+      int numeric)
+{
+       const struct ipt_dccp_info *einfo =
+               (const struct ipt_dccp_info *)match->data;
+
+       printf("dccp ");
+
+       if (einfo->flags & IPT_DCCP_SRC_PORTS) {
+               print_ports("spt", einfo->spts[0], einfo->spts[1],
+                       einfo->invflags & IPT_DCCP_SRC_PORTS,
+                       numeric);
+       }
+
+       if (einfo->flags & IPT_DCCP_DEST_PORTS) {
+               print_ports("dpt", einfo->dpts[0], einfo->dpts[1],
+                       einfo->invflags & IPT_DCCP_DEST_PORTS,
+                       numeric);
+       }
+
+       if (einfo->flags & IPT_DCCP_TYPE) {
+               print_types(einfo->typemask,
+                          einfo->invflags & IPT_DCCP_TYPE,
+                          numeric);
+       }
+
+       if (einfo->flags & IPT_DCCP_OPTION) {
+               print_option(einfo->option,
+                            einfo->invflags & IPT_DCCP_OPTION, numeric);
+       }
+}
+
+/* Saves the union ipt_matchinfo in parsable form to stdout. */
+static void
+save(const struct ipt_ip *ip, 
+     const struct ipt_entry_match *match)
+{
+       const struct ipt_dccp_info *einfo =
+               (const struct ipt_dccp_info *)match->data;
+
+       if (einfo->flags & IPT_DCCP_SRC_PORTS) {
+               if (einfo->invflags & IPT_DCCP_SRC_PORTS)
+                       printf("! ");
+               if (einfo->spts[0] != einfo->spts[1])
+                       printf("--sport %u:%u ", 
+                              einfo->spts[0], einfo->spts[1]);
+               else
+                       printf("--sport %u ", einfo->spts[0]);
+       }
+
+       if (einfo->flags & IPT_DCCP_DEST_PORTS) {
+               if (einfo->invflags & IPT_DCCP_DEST_PORTS)
+                       printf("! ");
+               if (einfo->dpts[0] != einfo->dpts[1])
+                       printf("--dport %u:%u ",
+                              einfo->dpts[0], einfo->dpts[1]);
+               else
+                       printf("--dport %u ", einfo->dpts[0]);
+       }
+
+       if (einfo->flags & IPT_DCCP_TYPE) {
+               printf("--dccp-type ");
+               print_types(einfo->typemask, einfo->invflags & IPT_DCCP_TYPE,0);
+       }
+
+       if (einfo->flags & IPT_DCCP_OPTION) {
+               printf("--dccp-option %s%u ", 
+                       einfo->typemask & IPT_DCCP_OPTION ? "! " : "",
+                       einfo->option);
+       }
+}
+
+static
+struct iptables_match dccp
+= { .name          = "dccp",
+    .version       = IPTABLES_VERSION,
+    .size          = IPT_ALIGN(sizeof(struct ipt_dccp_info)),
+    .userspacesize = IPT_ALIGN(sizeof(struct ipt_dccp_info)),
+    .help          = &help,
+    .init          = &init,
+    .parse         = &parse,
+    .final_check   = &final_check,
+    .print         = &print,
+    .save          = &save,
+    .extra_opts    = opts
+};
+
+void _init(void)
+{
+       register_match(&dccp);
+}
+
diff --git a/extensions/libipt_dccp.man b/extensions/libipt_dccp.man
new file mode 100644 (file)
index 0000000..6443ec3
--- /dev/null
@@ -0,0 +1,12 @@
+.TP
+\fB--source-port\fR,\fB--sport \fR[\fB!\fR] \fIport\fR[\fB:\fIport\fR]
+.TP
+\fB--destination-port\fR,\fB--dport \fR[\fB!\fR] \fIport\fR[\fB:\fIport\fR]
+.TP
+\fB--dccp-types\fR [\fB!\fR] \fImask\fP
+Match when the DCCP packet type is one of 'mask'. 'mask' is a comma-separated
+list of packet types.  Packet types are: 
+.BR "REQUEST RESPONSE DATA ACK DATAACK CLOSEREQ CLOSE RESET SYNC SYNCACK INVALID" .
+.TP
+\fB--dccp-option\fR [\fB!\fR\] \fInumber\fP
+Match if DCP option set.
index 4520a6a..bb19bed 100644 (file)
@@ -46,7 +46,7 @@ static struct option opts[] = {
 };
 
 static void
-parse_dscp(const unsigned char *s, struct ipt_dscp_info *dinfo)
+parse_dscp(const char *s, struct ipt_dscp_info *dinfo)
 {
        unsigned int dscp;
        
index e4a4a5a..9df00f1 100644 (file)
@@ -2,6 +2,8 @@ This module allows you to limit the packet per second (pps) rate on a per
 destination IP or per destination port base.  As opposed to the `limit' match,
 every destination ip / destination port has it's own limit.
 .TP
+THIS MODULE IS DEPRECATED AND HAS BEEN REPLACED BY ``hashlimit''
+.TP
 .BI "--dstlimit " "avg"
 Maximum average match rate (packets per second unless followed by /sec /minute /hour /day postfixes).
 .TP
index 7b84368..7898e02 100644 (file)
@@ -1,3 +1,3 @@
-This module matches the SPIs in ESP header of IPSec packets.
+This module matches the SPIs in ESP header of IPsec packets.
 .TP
 .BR "--espspi " "[!] \fIspi\fP[:\fIspi\fP]"
index 270c8d6..397727a 100644 (file)
@@ -1,6 +1,6 @@
 This module matches a rate limit based on a fuzzy logic controller [FLC]
 .TP
-.BI "--lower-limit  "number"
+.BI "--lower-limit " "number"
 Specifies the lower limit (in packets per second).
 .TP
 .BI "--upper-limit " "number"
index 72a6b5d..43bbdcf 100644 (file)
@@ -1,4 +1,4 @@
 This module matches the length of a packet against a specific value
 or range of values.
 .TP
-.BR "--length " "\fIlength\fP[:\fIlength\fP]"
+.BR "--length " "[!] \fIlength\fP[:\fIlength\fP]"
index 05f8e1e..a2a1395 100644 (file)
@@ -4,6 +4,6 @@ This module matches the netfilter mark field associated with a packet
 target below).
 .TP
 .BR "--mark " "\fIvalue\fP[/\fImask\fP]"
-Matches packets with the given unsigned mark value (if a mask is
-specified, this is logically ANDed with the mask before the
+Matches packets with the given unsigned mark value (if a \fImask\fP is
+specified, this is logically ANDed with the \fImask\fP before the
 comparison).
index b6dae2a..28ee827 100644 (file)
@@ -53,7 +53,8 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                if (*flags & IPT_PHYSDEV_OP_IN)
                        goto multiple_use;
                check_inverse(optarg, &invert, &optind, 0);
-               parse_interface(argv[optind-1], info->physindev, info->in_mask);
+               parse_interface(argv[optind-1], info->physindev,
+                               (unsigned char *)info->in_mask);
                if (invert)
                        info->invert |= IPT_PHYSDEV_OP_IN;
                info->bitmask |= IPT_PHYSDEV_OP_IN;
@@ -65,7 +66,7 @@ parse(int c, char **argv, int invert, unsigned int *flags,
                        goto multiple_use;
                check_inverse(optarg, &invert, &optind, 0);
                parse_interface(argv[optind-1], info->physoutdev,
-                               info->out_mask);
+                               (unsigned char *)info->out_mask);
                if (invert)
                        info->invert |= IPT_PHYSDEV_OP_OUT;
                info->bitmask |= IPT_PHYSDEV_OP_OUT;
index 846ec7c..1e635fc 100644 (file)
@@ -3,7 +3,7 @@ to a bridge device. This module is a part of the infrastructure that enables
 a transparent bridging IP firewall and is only useful for kernel versions
 above version 2.5.44.
 .TP
-.B --physdev-in name
+.BR --physdev-in " [!] \fIname\fP"
 Name of a bridge port via which a packet is received (only for
 packets entering the
 .BR INPUT ,
@@ -14,7 +14,7 @@ chains). If the interface name ends in a "+", then any
 interface which begins with this name will match. If the packet didn't arrive
 through a bridge device, this packet won't match this option, unless '!' is used.
 .TP
-.B --physdev-out name
+.BR --physdev-out " [!] \fIname\fP"
 Name of a bridge port via which a packet is going to be sent (for packets
 entering the
 .BR FORWARD ,
@@ -31,12 +31,12 @@ chain. If the packet won't leave by a bridge device or it is yet unknown what
 the output device will be, then the packet won't match this option, unless
 '!' is used.
 .TP
-.B --physdev-is-in
+.RB "[!] " --physdev-is-in
 Matches if the packet has entered through a bridge interface.
 .TP
-.B --physdev-is-out
+.RB "[!] " --physdev-is-out
 Matches if the packet will leave through a bridge interface.
 .TP
-.B --physdev-is-bridged
+.RB "[!] " --physdev-is-bridged
 Matches if the packet is being bridged and therefore is not being routed.
 This is only useful in the FORWARD and POSTROUTING chains.
diff --git a/extensions/libipt_policy.c b/extensions/libipt_policy.c
new file mode 100644 (file)
index 0000000..681995a
--- /dev/null
@@ -0,0 +1,436 @@
+/* Shared library add-on to iptables to add policy support. */
+#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 <iptables.h>
+
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include "../include/linux/netfilter_ipv4/ipt_policy.h"
+
+/*
+ * HACK: global pointer to current matchinfo for making
+ * final checks and adjustments in final_check.
+ */
+static struct ipt_policy_info *policy_info;
+
+static void help(void)
+{
+       printf(
+"policy v%s options:\n"
+"  --dir in|out                        match policy applied during decapsulation/\n"
+"                              policy to be applied during encapsulation\n"
+"  --pol none|ipsec            match policy\n"
+"  --strict                    match entire policy instead of single element\n"
+"                              at any position\n"
+"[!] --reqid reqid             match reqid\n"
+"[!] --spi spi                 match SPI\n"
+"[!] --proto proto             match protocol (ah/esp/ipcomp)\n"
+"[!] --mode mode               match mode (transport/tunnel)\n"
+"[!] --tunnel-src addr/mask    match tunnel source\n"
+"[!] --tunnel-dst addr/mask    match tunnel destination\n"
+"  --next                      begin next element in policy\n",
+       IPTABLES_VERSION);
+}
+
+static struct option 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'
+       },
+       { }
+};
+
+static void init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+       *nfcache |= NFC_UNKNOWN;
+}
+
+static int parse_direction(char *s)
+{
+       if (strcmp(s, "in") == 0)
+               return IPT_POLICY_MATCH_IN;
+       if (strcmp(s, "out") == 0)
+               return IPT_POLICY_MATCH_OUT;
+       exit_error(PARAMETER_PROBLEM, "policy_match: invalid dir `%s'", s);
+}
+
+static int parse_policy(char *s)
+{
+       if (strcmp(s, "none") == 0)
+               return IPT_POLICY_MATCH_NONE;
+       if (strcmp(s, "ipsec") == 0)
+               return 0;
+       exit_error(PARAMETER_PROBLEM, "policy match: invalid policy `%s'", s);
+}
+
+static int parse_mode(char *s)
+{
+       if (strcmp(s, "transport") == 0)
+               return IPT_POLICY_MODE_TRANSPORT;
+       if (strcmp(s, "tunnel") == 0)
+               return IPT_POLICY_MODE_TUNNEL;
+       exit_error(PARAMETER_PROBLEM, "policy match: invalid mode `%s'", s);
+}
+
+static int parse(int c, char **argv, int invert, unsigned int *flags,
+                 const struct ipt_entry *entry,
+                 unsigned int *nfcache,
+                 struct ipt_entry_match **match)
+{
+       struct ipt_policy_info *info = (void *)(*match)->data;
+       struct ipt_policy_elem *e = &info->pol[info->len];
+       struct in_addr *addr = NULL, mask;
+       unsigned int naddr = 0;
+       int mode;
+
+       check_inverse(optarg, &invert, &optind, 0);
+
+       switch (c) {
+       case '1':
+               if (info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --dir option");
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --dir option");
+
+               info->flags |= parse_direction(argv[optind-1]);
+               break;
+       case '2':
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --policy option");
+
+               info->flags |= parse_policy(argv[optind-1]);
+               break;
+       case '3':
+               if (info->flags & IPT_POLICY_MATCH_STRICT)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --strict option");
+
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --strict option");
+
+               info->flags |= IPT_POLICY_MATCH_STRICT;
+               break;
+       case '4':
+               if (e->match.reqid)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --reqid option");
+
+               e->match.reqid = 1;
+               e->invert.reqid = invert;
+               e->reqid = strtol(argv[optind-1], NULL, 10);
+               break;
+       case '5':
+               if (e->match.spi)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --spi option");
+
+               e->match.spi = 1;
+               e->invert.spi = invert;
+               e->spi = strtol(argv[optind-1], NULL, 0x10);
+               break;
+       case '6':
+               if (e->match.saddr)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --tunnel-src option");
+
+               parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
+               if (naddr > 1)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: name resolves to multiple IPs");
+
+               e->match.saddr = 1;
+               e->invert.saddr = invert;
+               e->saddr.a4 = addr[0];
+               e->smask.a4 = mask;
+                break;
+       case '7':
+               if (e->match.daddr)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --tunnel-dst option");
+
+               parse_hostnetworkmask(argv[optind-1], &addr, &mask, &naddr);
+               if (naddr > 1)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: name resolves to multiple IPs");
+
+               e->match.daddr = 1;
+               e->invert.daddr = invert;
+               e->daddr.a4 = addr[0];
+               e->dmask.a4 = mask;
+               break;
+       case '8':
+               if (e->match.proto)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --proto option");
+
+               e->proto = parse_protocol(argv[optind-1]);
+               if (e->proto != IPPROTO_AH && e->proto != IPPROTO_ESP &&
+                   e->proto != IPPROTO_COMP)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: protocol must ah/esp/ipcomp");
+               e->match.proto = 1;
+               e->invert.proto = invert;
+               break;
+       case '9':
+               if (e->match.mode)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: double --mode option");
+
+               mode = parse_mode(argv[optind-1]);
+               e->match.mode = 1;
+               e->invert.mode = invert;
+               e->mode = mode;
+               break;
+       case 'a':
+               if (invert)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: can't invert --next option");
+
+               if (++info->len == IPT_POLICY_MAX_ELEM)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: maximum policy depth reached");
+               break;
+       default:
+               return 0;
+       }
+
+       policy_info = info;
+       return 1;
+}
+
+static void final_check(unsigned int flags)
+{
+       struct ipt_policy_info *info = policy_info;
+       struct ipt_policy_elem *e;
+       int i;
+
+       if (info == NULL)
+               exit_error(PARAMETER_PROBLEM,
+                          "policy match: no parameters given");
+
+       if (!(info->flags & (IPT_POLICY_MATCH_IN|IPT_POLICY_MATCH_OUT)))
+               exit_error(PARAMETER_PROBLEM,
+                          "policy match: neither --in nor --out specified");
+
+       if (info->flags & IPT_POLICY_MATCH_NONE) {
+               if (info->flags & IPT_POLICY_MATCH_STRICT)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: policy none but --strict given");
+
+               if (info->len != 0)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: policy none but policy given");
+       } else
+               info->len++;    /* increase len by 1, no --next after last element */
+
+       if (!(info->flags & IPT_POLICY_MATCH_STRICT) && info->len > 1)
+               exit_error(PARAMETER_PROBLEM,
+                          "policy match: multiple elements but no --strict");
+
+       for (i = 0; i < info->len; i++) {
+               e = &info->pol[i];
+
+               if (info->flags & IPT_POLICY_MATCH_STRICT &&
+                   !(e->match.reqid || e->match.spi || e->match.saddr ||
+                     e->match.daddr || e->match.proto || e->match.mode))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: empty policy element");
+
+               if ((e->match.saddr || e->match.daddr)
+                   && ((e->mode == IPT_POLICY_MODE_TUNNEL && e->invert.mode) ||
+                       (e->mode == IPT_POLICY_MODE_TRANSPORT && !e->invert.mode)))
+                       exit_error(PARAMETER_PROBLEM,
+                                  "policy match: --tunnel-src/--tunnel-dst "
+                                  "is only valid in tunnel mode");
+       }
+}
+
+static void print_mode(char *prefix, u_int8_t mode, int numeric)
+{
+       printf("%smode ", prefix);
+
+       switch (mode) {
+       case IPT_POLICY_MODE_TRANSPORT:
+               printf("transport ");
+               break;
+       case IPT_POLICY_MODE_TUNNEL:
+               printf("tunnel ");
+               break;
+       default:
+               printf("??? ");
+               break;
+       }
+}
+
+static void print_proto(char *prefix, u_int8_t proto, int numeric)
+{
+       struct protoent *p = NULL;
+
+       printf("%sproto ", prefix);
+       if (!numeric)
+               p = getprotobynumber(proto);
+       if (p != NULL)
+               printf("%s ", p->p_name);
+       else
+               printf("%u ", proto);
+}
+
+#define PRINT_INVERT(x)                \
+do {                           \
+       if (x)                  \
+               printf("! ");   \
+} while(0)
+
+static void print_entry(char *prefix, const struct ipt_policy_elem *e,
+                        int numeric)
+{
+       if (e->match.reqid) {
+               PRINT_INVERT(e->invert.reqid);
+               printf("%sreqid %u ", prefix, e->reqid);
+       }
+       if (e->match.spi) {
+               PRINT_INVERT(e->invert.spi);
+               printf("%sspi 0x%x ", prefix, e->spi);
+       }
+       if (e->match.proto) {
+               PRINT_INVERT(e->invert.proto);
+               print_proto(prefix, e->proto, numeric);
+       }
+       if (e->match.mode) {
+               PRINT_INVERT(e->invert.mode);
+               print_mode(prefix, e->mode, numeric);
+       }
+       if (e->match.daddr) {
+               PRINT_INVERT(e->invert.daddr);
+               printf("%stunnel-dst %s%s ", prefix,
+                      addr_to_dotted((struct in_addr *)&e->daddr),
+                      mask_to_dotted((struct in_addr *)&e->dmask));
+       }
+       if (e->match.saddr) {
+               PRINT_INVERT(e->invert.saddr);
+               printf("%stunnel-src %s%s ", prefix,
+                      addr_to_dotted((struct in_addr *)&e->saddr),
+                      mask_to_dotted((struct in_addr *)&e->smask));
+       }
+}
+
+static void print_flags(char *prefix, const struct ipt_policy_info *info)
+{
+       if (info->flags & IPT_POLICY_MATCH_IN)
+               printf("%sdir in ", prefix);
+       else
+               printf("%sdir out ", prefix);
+
+       if (info->flags & IPT_POLICY_MATCH_NONE)
+               printf("%spol none ", prefix);
+       else
+               printf("%spol ipsec ", prefix);
+
+       if (info->flags & IPT_POLICY_MATCH_STRICT)
+               printf("%sstrict ", prefix);
+}
+
+static void print(const struct ipt_ip *ip,
+                  const struct ipt_entry_match *match,
+                 int numeric)
+{
+       const struct ipt_policy_info *info = (void *)match->data;
+       unsigned int i;
+
+       printf("policy match ");
+       print_flags("", info);
+       for (i = 0; i < info->len; i++) {
+               if (info->len > 1)
+                       printf("[%u] ", i);
+               print_entry("", &info->pol[i], numeric);
+       }
+}
+
+static void save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
+{
+       const struct ipt_policy_info *info = (void *)match->data;
+       unsigned int i;
+
+       print_flags("--", info);
+       for (i = 0; i < info->len; i++) {
+               print_entry("--", &info->pol[i], 0);
+               if (i + 1 < info->len)
+                       printf("--next ");
+       }
+}
+
+struct iptables_match policy = {
+       .name           = "policy",
+       .version        = IPTABLES_VERSION,
+       .size           = IPT_ALIGN(sizeof(struct ipt_policy_info)),
+       .userspacesize  = IPT_ALIGN(sizeof(struct ipt_policy_info)),
+       .help           = help,
+       .init           = init,
+       .parse          = parse,
+       .final_check    = final_check,
+       .print          = print,
+       .save           = save,
+       .extra_opts     = opts
+};
+
+void _init(void)
+{
+       register_match(&policy);
+}
diff --git a/extensions/libipt_policy.man b/extensions/libipt_policy.man
new file mode 100644 (file)
index 0000000..eed163e
--- /dev/null
@@ -0,0 +1,48 @@
+This modules matches the policy used by IPsec for handling a packet.
+.TP
+.BI "--dir " "in|out"
+Used to select whether to match the policy used for decapsulation or the
+policy that will be used for encapsulation.
+.B in
+is valid in the
+.B PREROUTING, INPUT and FORWARD
+chains,
+.B out
+is valid in the
+.B POSTROUTING, OUTPUT and FORWARD
+chains.
+.TP
+.BI "--pol " "none|ipsec"
+Matches if the packet is subject to IPsec processing.
+.TP
+.BI "--strict"
+Selects whether to match the exact policy or match if any rule of
+the policy matches the given policy.
+.TP
+.BI "--reqid " "id"
+Matches the reqid of the policy rule. The reqid can be specified with
+.B setkey(8)
+using
+.B unique:id
+as level.
+.TP
+.BI "--spi " "spi"
+Matches the SPI of the SA.
+.TP
+.BI "--proto " "ah|esp|ipcomp"
+Matches the encapsulation protocol.
+.TP
+.BI "--mode " "tunnel|transport"
+Matches the encapsulation mode.
+.TP
+.BI "--tunnel-src " "addr[/mask]"
+Matches the source end-point address of a tunnel mode SA.
+Only valid with --mode tunnel.
+.TP
+.BI "--tunnel-dst " "addr[/mask]"
+Matches the destination end-point address of a tunnel mode SA.
+Only valid with --mode tunnel.
+.TP
+.BI "--next"
+Start the next element in the policy specification. Can only be used with
+--strict
index f6e897a..dbfb396 100644 (file)
@@ -89,7 +89,7 @@ static int k_itoa(char *string, int number)
 }
 
 
-static int k_atoi(signed char *string)
+static int k_atoi(char *string)
 {
        unsigned int result = 0;
        int maxoctet = IPT_RPC_CHAR_LEN;
index af35f9c..18fe6ad 100644 (file)
 
 #include <iptables.h>
 #include <linux/netfilter_ipv4/ip_tables.h>
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
+
 #include <linux/netfilter_ipv4/ipt_sctp.h>
 
+/* Some ZS!#@:$%*#$! has replaced the ELEMCOUNT macro in ipt_sctp.h with
+ * ARRAY_SIZE without noticing that this file is used from userserspace,
+ * and userspace doesn't have ARRAY_SIZE */
+
+#ifndef ELEMCOUNT
+#define ELEMCOUNT ARRAY_SIZE
+#endif
+
 #if 0
 #define DEBUGP(format, first...) printf(format, ##first)
 #define static
index 508eb90..5492cfc 100644 (file)
@@ -2,6 +2,11 @@
  * 
  * Copyright (C) 2000 Emmanuel Roger  <winfield@freegates.be>
  *
+ * 2005-08-05 Pablo Neira Ayuso <pablo@eurodev.net>
+ *     - reimplemented to use new string matching iptables match
+ *     - add functionality to match packets by using window offsets
+ *     - add functionality to select the string matching algorithm
+ *
  * ChangeLog
  *     29.12.2003: Michael Rash <mbr@cipherdyne.org>
  *             Fixed iptables save/restore for ascii strings
 #include <stdlib.h>
 #include <getopt.h>
 #include <ctype.h>
-
 #include <iptables.h>
+#include <stddef.h>
 #include <linux/netfilter_ipv4/ipt_string.h>
 
-
 /* Function which prints out usage message. */
 static void
 help(void)
 {
        printf(
 "STRING match v%s options:\n"
+"--from                       Offset to start searching from\n"
+"--to                         Offset to stop searching\n"
+"--algo                              Algorithm\n"
 "--string [!] string          Match a string in a packet\n"
 "--hex-string [!] string      Match a hex string in a packet\n",
 IPTABLES_VERSION);
 }
 
-
 static struct option opts[] = {
-       { .name = "string",     .has_arg = 1, .flag = 0, .val = '1' },
-       { .name = "hex-string", .has_arg = 1, .flag = 0, .val = '2' },
-       { .name = 0 }
+       { "from", 1, 0, '1' },
+       { "to", 1, 0, '2' },
+       { "algo", 1, 0, '3' },
+       { "string", 1, 0, '4' },
+       { "hex-string", 1, 0, '5' },
+       {0}
 };
 
 static void
-parse_string(const unsigned char *s, struct ipt_string_info *info)
+init(struct ipt_entry_match *m, unsigned int *nfcache)
+{
+       struct ipt_string_info *i = (struct ipt_string_info *) m->data;
+
+       if (i->to_offset == 0)
+               i->to_offset = (u_int16_t) ~0UL;
+}
+
+static void
+parse_string(const char *s, struct ipt_string_info *info)
 {      
-       if (strlen(s) <= BM_MAX_NLEN) strcpy(info->string, s);
-       else exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
+       if (strlen(s) <= IPT_STRING_MAX_PATTERN_SIZE) {
+               strncpy(info->pattern, s, IPT_STRING_MAX_PATTERN_SIZE);
+               info->patlen = strlen(s);
+               return;
+       }
+       exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
 }
 
+static void
+parse_algo(const char *s, struct ipt_string_info *info)
+{
+       if (strlen(s) <= IPT_STRING_MAX_ALGO_NAME_SIZE) {
+               strncpy(info->algo, s, IPT_STRING_MAX_ALGO_NAME_SIZE);
+               return;
+       }
+       exit_error(PARAMETER_PROBLEM, "ALGO too long `%s'", s);
+}
 
 static void
-parse_hex_string(const unsigned char *s, struct ipt_string_info *info)
+parse_hex_string(const char *s, struct ipt_string_info *info)
 {
        int i=0, slen, sindex=0, schar;
        short hex_f = 0, literal_f = 0;
@@ -92,7 +123,7 @@ parse_hex_string(const unsigned char *s, struct ipt_string_info *info)
                                exit_error(PARAMETER_PROBLEM,
                                        "Bad literal placement at end of string");
                        }
-                       info->string[sindex] = s[i+1];
+                       info->pattern[sindex] = s[i+1];
                        i += 2;  /* skip over literal char */
                        literal_f = 0;
                } else if (hex_f) {
@@ -114,22 +145,26 @@ parse_hex_string(const unsigned char *s, struct ipt_string_info *info)
                        if (! sscanf(hextmp, "%x", &schar))
                                exit_error(PARAMETER_PROBLEM,
                                        "Invalid hex char `%c'", s[i]);
-                       info->string[sindex] = (char) schar;
+                       info->pattern[sindex] = (char) schar;
                        if (s[i+2] == ' ')
                                i += 3;  /* spaces included in the hex block */
                        else
                                i += 2;
                } else {  /* the char is not part of hex data, so just copy */
-                       info->string[sindex] = s[i];
+                       info->pattern[sindex] = s[i];
                        i++;
                }
-               if (sindex > BM_MAX_NLEN)
+               if (sindex > IPT_STRING_MAX_PATTERN_SIZE)
                        exit_error(PARAMETER_PROBLEM, "STRING too long `%s'", s);
                sindex++;
        }
-       info->len = sindex;
+       info->patlen = sindex;
 }
 
+#define STRING 0x1
+#define ALGO   0x2
+#define FROM   0x4
+#define TO     0x8
 
 /* Function which parses command options; returns true if it
    ate an option */
@@ -143,28 +178,48 @@ parse(int c, char **argv, int invert, unsigned int *flags,
 
        switch (c) {
        case '1':
-               if (*flags)
+               if (*flags & FROM)
                        exit_error(PARAMETER_PROBLEM,
-                                  "Can't specify multiple strings");
-
+                                  "Can't specify multiple --from");
+               stringinfo->from_offset = atoi(optarg);
+               *flags |= FROM;
+               break;
+       case '2':
+               if (*flags & TO)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Can't specify multiple --to");
+               stringinfo->to_offset = atoi(optarg);
+               *flags |= TO;
+               break;
+       case '3':
+               if (*flags & ALGO)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Can't specify multiple --algo");
+               parse_algo(optarg, stringinfo);
+               *flags |= ALGO;
+               break;
+       case '4':
+               if (*flags & STRING)
+                       exit_error(PARAMETER_PROBLEM,
+                                  "Can't specify multiple --string");
                check_inverse(optarg, &invert, &optind, 0);
                parse_string(argv[optind-1], stringinfo);
                if (invert)
                        stringinfo->invert = 1;
-               stringinfo->len=strlen((char *)&stringinfo->string);
-               *flags = 1;
+               stringinfo->patlen=strlen((char *)&stringinfo->pattern);
+               *flags |= STRING;
                break;
 
-       case '2':
-               if (*flags)
+       case '5':
+               if (*flags & STRING)
                        exit_error(PARAMETER_PROBLEM,
-                                  "Can't specify multiple strings");
+                                  "Can't specify multiple --hex-string");
 
                check_inverse(optarg, &invert, &optind, 0);
                parse_hex_string(argv[optind-1], stringinfo);  /* sets length */
                if (invert)
                        stringinfo->invert = 1;
-               *flags = 1;
+               *flags |= STRING;
                break;
 
        default:
@@ -178,9 +233,13 @@ parse(int c, char **argv, int invert, unsigned int *flags,
 static void
 final_check(unsigned int flags)
 {
-       if (!flags)
+       if (!(flags & STRING))
+               exit_error(PARAMETER_PROBLEM,
+                          "STRING match: You must specify `--string' or "
+                          "`--hex-string'");
+       if (!(flags & ALGO))
                exit_error(PARAMETER_PROBLEM,
-                          "STRING match: You must specify `--string' or `--hex-string'");
+                          "STRING match: You must specify `--algo'");
 }
 
 /* Test to see if the string contains non-printable chars or quotes */
@@ -237,13 +296,18 @@ print(const struct ipt_ip *ip,
        const struct ipt_string_info *info =
            (const struct ipt_string_info*) match->data;
 
-       if (is_hex_string(info->string, info->len)) {
+       if (is_hex_string(info->pattern, info->patlen)) {
                printf("STRING match %s", (info->invert) ? "!" : "");
-               print_hex_string(info->string, info->len);
+               print_hex_string(info->pattern, info->patlen);
        } else {
                printf("STRING match %s", (info->invert) ? "!" : "");
-               print_string(info->string, info->len);
+               print_string(info->pattern, info->patlen);
        }
+       printf("ALGO name %s ", info->algo);
+       if (info->from_offset != 0)
+               printf("FROM %u ", info->from_offset);
+       if (info->to_offset != 0)
+               printf("TO %u", info->to_offset);
 }
 
 
@@ -254,27 +318,33 @@ save(const struct ipt_ip *ip, const struct ipt_entry_match *match)
        const struct ipt_string_info *info =
            (const struct ipt_string_info*) match->data;
 
-       if (is_hex_string(info->string, info->len)) {
+       if (is_hex_string(info->pattern, info->patlen)) {
                printf("--hex-string %s", (info->invert) ? "! ": "");
-               print_hex_string(info->string, info->len);
+               print_hex_string(info->pattern, info->patlen);
        } else {
                printf("--string %s", (info->invert) ? "! ": "");
-               print_string(info->string, info->len);
+               print_string(info->pattern, info->patlen);
        }
+       printf("--algo %s ", info->algo);
+       if (info->from_offset != 0)
+               printf("--from %u ", info->from_offset);
+       if (info->to_offset != 0)
+               printf("--to %u ", info->to_offset);
 }
 
 
 static struct iptables_match string = {
-    .name          = "string",
-    .version       = IPTABLES_VERSION,
-    .size          = IPT_ALIGN(sizeof(struct ipt_string_info)),
-    .userspacesize = IPT_ALIGN(sizeof(struct ipt_string_info)),
-    .help          = &help,
-    .parse         = &parse,
-    .final_check   = &final_check,
-    .print         = &print,
-    .save          = &save,
-    .extra_opts    = opts
+    .name              = "string",
+    .version           = IPTABLES_VERSION,
+    .size              = IPT_ALIGN(sizeof(struct ipt_string_info)),
+    .userspacesize     = offsetof(struct ipt_string_info, config),
+    .help              = help,
+    .init              = init,
+    .parse             = parse,
+    .final_check       = final_check,
+    .print             = print,
+    .save              = save,
+    .extra_opts                = opts
 };
 
 
diff --git a/extensions/libipt_string.man b/extensions/libipt_string.man
new file mode 100644 (file)
index 0000000..3f3e5b7
--- /dev/null
@@ -0,0 +1,15 @@
+This modules matches a given string by using some pattern matching strategy. It requires a linux kernel >= 2.6.14.
+.TP
+.BI "--algo  " "bm|kmp"
+Select the pattern matching strategy. (bm = Boyer-Moore, kmp = Knuth-Pratt-Morris)
+.TP
+.BI "--from " "offset"
+Set the offset from which it starts looking for any matching. If not passed, default is 0.
+.TP
+.BI "--to " "offset"
+Set the offset from which it starts looking for any matching. If not passed, default is the packet size.
+.TP
+.BI "--string " "pattern"
+Matches the given pattern.
+.BI "--hex-string " "pattern"
+Matches the given pattern in hex notation.
index 7a10a50..f8b5cb4 100644 (file)
@@ -48,7 +48,7 @@ static struct option opts[] = {
 };
 
 static void
-parse_tos(const unsigned char *s, struct ipt_tos_info *info)
+parse_tos(const char *s, struct ipt_tos_info *info)
 {
        unsigned int i;
        unsigned int tos;
index 2391986..89ea084 100644 (file)
@@ -1,7 +1,7 @@
 /* Shared library add-on to iptables to add TTL matching support 
  * (C) 2000 by Harald Welte <laforge@gnumonks.org>
  *
- * $Id: libipt_ttl.c 3687 2005-02-14 13:13:04Z /C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kaber/emailAddress=kaber@netfilter.org $
+ * $Id: libipt_ttl.c 4544 2005-11-18 17:59:56Z /C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=kaber/emailAddress=kaber@netfilter.org $
  *
  * This program is released under the terms of GNU GPL */
 
@@ -29,16 +29,16 @@ static int parse(int c, char **argv, int invert, unsigned int *flags,
                struct ipt_entry_match **match)
 {
        struct ipt_ttl_info *info = (struct ipt_ttl_info *) (*match)->data;
-       int value;
+       unsigned int value;
 
        check_inverse(optarg, &invert, &optind, 0);
 
-       if (string_to_number(optarg, 0, 255, &value) == -1)
-               exit_error(PARAMETER_PROBLEM,
-                          "ttl: Expected value between 0 and 255");
-
        switch (c) {
                case '2':
+                       if (string_to_number(optarg, 0, 255, &value) == -1)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "ttl: Expected value between 0 and 255");
+
                        if (invert)
                                info->mode = IPT_TTL_NE;
                        else
@@ -48,6 +48,10 @@ static int parse(int c, char **argv, int invert, unsigned int *flags,
                        info->ttl = value;
                        break;
                case '3':
+                       if (string_to_number(optarg, 0, 255, &value) == -1)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "ttl: Expected value between 0 and 255");
+
                        if (invert) 
                                exit_error(PARAMETER_PROBLEM,
                                                "ttl: unexpected `!'");
@@ -56,6 +60,10 @@ static int parse(int c, char **argv, int invert, unsigned int *flags,
                        info->ttl = value;
                        break;
                case '4':
+                       if (string_to_number(optarg, 0, 255, &value) == -1)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "ttl: Expected value between 0 and 255");
+
                        if (invert)
                                exit_error(PARAMETER_PROBLEM,
                                                "ttl: unexpected `!'");
index 81d99d8..549e041 100644 (file)
@@ -130,6 +130,7 @@ extern struct ip6tables_target *ip6tables_targets;
 
 enum ip6t_tryload {
        DONT_LOAD,
+       DURING_LOAD,
        TRY_LOAD,
        LOAD_MUST_SUCCEED
 };
index f0cad8d..bf71e52 100644 (file)
@@ -162,6 +162,7 @@ extern struct iptables_target *iptables_targets;
 
 enum ipt_tryload {
        DONT_LOAD,
+       DURING_LOAD,
        TRY_LOAD,
        LOAD_MUST_SUCCEED
 };
@@ -175,4 +176,13 @@ extern int flush_entries(const ipt_chainlabel chain, int verbose,
                        iptc_handle_t *handle);
 extern int for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
                int verbose, int builtinstoo, iptc_handle_t *handle);
+
+/* kernel revision handling */
+extern int kernel_version;
+extern void get_kernel_version(void);
+#define LINUX_VERSION(x,y,z)   (0x10000*(x) + 0x100*(y) + z)
+#define LINUX_VERSION_MAJOR(x) (((x)>>16) & 0xFF)
+#define LINUX_VERSION_MINOR(x) (((x)>> 8) & 0xFF)
+#define LINUX_VERSION_PATCH(x) ( (x)      & 0xFF)
+
 #endif /*_IPTABLES_USER_H*/
index db5e93f..28bda9f 100644 (file)
@@ -7,6 +7,10 @@ enum exittype {
        PARAMETER_PROBLEM,
        VERSION_PROBLEM
 };
+
+/* this is a special 64bit data type that is 8-byte aligned */
+#define aligned_u64 unsigned long long __attribute__((aligned(8)))
+
 extern void exit_printhelp() __attribute__((noreturn));
 extern void exit_tryhelp(int) __attribute__((noreturn));
 int check_inverse(const char option[], int *invert, int *optind, int argc);
diff --git a/include/linux/netfilter_ipv4/ipt_NFQUEUE.h b/include/linux/netfilter_ipv4/ipt_NFQUEUE.h
new file mode 100644 (file)
index 0000000..b5b2943
--- /dev/null
@@ -0,0 +1,16 @@
+/* iptables module for using NFQUEUE mechanism
+ *
+ * (C) 2005 Harald Welte <laforge@netfilter.org>
+ *
+ * This software is distributed under GNU GPL v2, 1991
+ * 
+*/
+#ifndef _IPT_NFQ_TARGET_H
+#define _IPT_NFQ_TARGET_H
+
+/* target info */
+struct ipt_NFQ_info {
+       u_int16_t queuenum;
+};
+
+#endif /* _IPT_DSCP_TARGET_H */
index eba410d..9f074c6 100644 (file)
@@ -13,7 +13,7 @@
 #define KERNEL_VERSION(a,b,c) (((a) << 16) | ((b) << 8) | (c))
 #endif
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18)) || !defined IPS_EXPECTED
 #define IPS_EXPECTED   (1 << 0)
 #define IPS_SEEN_REPLY (1 << 1)
 #define IPS_ASSURED    (1 << 2)
diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h
new file mode 100644 (file)
index 0000000..74ca65c
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef _IPT_POLICY_H
+#define _IPT_POLICY_H
+
+#define IPT_POLICY_MAX_ELEM    4
+
+#ifndef __KERNEL__
+#include <netinet/in.h>
+#endif
+
+enum ipt_policy_flags
+{
+       IPT_POLICY_MATCH_IN     = 0x1,
+       IPT_POLICY_MATCH_OUT    = 0x2,
+       IPT_POLICY_MATCH_NONE   = 0x4,
+       IPT_POLICY_MATCH_STRICT = 0x8,
+};
+
+enum ipt_policy_modes
+{
+       IPT_POLICY_MODE_TRANSPORT,
+       IPT_POLICY_MODE_TUNNEL
+};
+
+struct ipt_policy_spec
+{
+       u_int8_t        saddr:1,
+                       daddr:1,
+                       proto:1,
+                       mode:1,
+                       spi:1,
+                       reqid:1;
+};
+
+union ipt_policy_addr
+{
+       struct in_addr  a4;
+       struct in6_addr a6;
+};
+
+struct ipt_policy_elem
+{
+       union ipt_policy_addr   saddr;
+       union ipt_policy_addr   smask;
+       union ipt_policy_addr   daddr;
+       union ipt_policy_addr   dmask;
+       u_int32_t               spi;
+       u_int32_t               reqid;
+       u_int8_t                proto;
+       u_int8_t                mode;
+
+       struct ipt_policy_spec  match;
+       struct ipt_policy_spec  invert;
+};
+
+struct ipt_policy_info
+{
+       struct ipt_policy_elem pol[IPT_POLICY_MAX_ELEM];
+       u_int16_t flags;
+       u_int16_t len;
+};
+
+#endif /* _IPT_POLICY_H */
diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h
new file mode 100644 (file)
index 0000000..671bd81
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef _IP6T_POLICY_H
+#define _IP6T_POLICY_H
+
+#define IP6T_POLICY_MAX_ELEM   4
+
+enum ip6t_policy_flags
+{
+       IP6T_POLICY_MATCH_IN            = 0x1,
+       IP6T_POLICY_MATCH_OUT           = 0x2,
+       IP6T_POLICY_MATCH_NONE          = 0x4,
+       IP6T_POLICY_MATCH_STRICT        = 0x8,
+};
+
+enum ip6t_policy_modes
+{
+       IP6T_POLICY_MODE_TRANSPORT,
+       IP6T_POLICY_MODE_TUNNEL
+};
+
+struct ip6t_policy_spec
+{
+       u_int8_t        saddr:1,
+                       daddr:1,
+                       proto:1,
+                       mode:1,
+                       spi:1,
+                       reqid:1;
+};
+
+union ip6t_policy_addr
+{
+       struct in_addr  a4;
+       struct in6_addr a6;
+};
+
+struct ip6t_policy_elem
+{
+       union ip6t_policy_addr  saddr;
+       union ip6t_policy_addr  smask;
+       union ip6t_policy_addr  daddr;
+       union ip6t_policy_addr  dmask;
+       u_int32_t               spi;
+       u_int32_t               reqid;
+       u_int8_t                proto;
+       u_int8_t                mode;
+
+       struct ip6t_policy_spec match;
+       struct ip6t_policy_spec invert;
+};
+
+struct ip6t_policy_info
+{
+       struct ip6t_policy_elem pol[IP6T_POLICY_MAX_ELEM];
+       u_int16_t flags;
+       u_int16_t len;
+};
+
+#endif /* _IP6T_POLICY_H */
index 6d3f56c..bf24d55 100644 (file)
@@ -1,4 +1,4 @@
-.TH IP6TABLES 8 "Mar 09, 2002" "" ""
+.TH IP6TABLES 8 "Jan 22, 2006" "" ""
 .\"
 .\" Man page written by Andras Kis-Szabo <kisza@sch.bme.hu>
 .\" It is based on iptables man page.
@@ -73,7 +73,19 @@ means to let the packet through.
 .I DROP
 means to drop the packet on the floor.
 .I QUEUE
-means to pass the packet to userspace (if supported by the kernel).
+means to pass the packet to userspace.  (How the packet can be received
+by a userspace process differs by the particular queue handler.  2.4.x
+and 2.6.x kernels up to 2.6.13 include the 
+.B
+ip_queue
+queue handler.  Kernels 2.6.14 and later additionally include the 
+.B
+nfnetlink_queue
+queue handler.  Packets with a target of QUEUE will be sent to queue number '0'
+in this case. Please also see the
+.B
+NFQUEUE
+target as described later in this man page.)
 .I RETURN
 means stop traversing this chain and resume at the next rule in the
 previous (calling) chain.  If the end of a built-in chain is reached
@@ -119,6 +131,16 @@ Since kernel 2.4.18, three other built-in chains are also supported:
 (for altering packets being routed through the box), and
 .B POSTROUTING
 (for altering packets as they are about to go out).
+.TP
+.BR "raw" :
+This table is used mainly for configuring exemptions from connection
+tracking in combination with the NOTRACK target.  It registers at the netfilter
+hooks with higher priority and is thus called before nf_conntrack, or any other
+IP6 tables.  It provides the following built-in chains:
+.B PREROUTING
+(for packets arriving via any network interface)
+.B OUTPUT
+(for packets generated by local processes)
 .RE
 .SH OPTIONS
 The options that are recognized by
@@ -219,11 +241,18 @@ The protocol of the rule or of the packet to check.
 The specified protocol can be one of
 .IR tcp ,
 .IR udp ,
-.IR ipv6-icmp|icmpv6 ,
-or
+.IR icmpv6 ,
+.IR esp ,
 .IR all ,
 or it can be a numeric value, representing one of these protocols or a
-different one.  A protocol name from /etc/protocols is also allowed.
+different one. A protocol name from /etc/protocols is also allowed.
+But IPv6 extension headers except
+.IR esp
+are not allowed.
+.IR esp ,
+and
+.IR ipv6-nonext
+can be used with Kernel version 2.6.11 or later.
 A "!" argument before the protocol inverts the
 test.  The number zero is equivalent to
 .IR all .
@@ -426,7 +455,8 @@ There are several other changes in ip6tables.
 .BR ip6tables-restore(8),
 .BR iptables (8),
 .BR iptables-save (8),
-.BR iptables-restore (8).
+.BR iptables-restore (8),
+.BR libipq (3).
 .P
 The packet-filtering-HOWTO details iptables usage for
 packet filtering, the NAT-HOWTO details NAT,
@@ -448,7 +478,7 @@ James Morris wrote the TOS target, and tos match.
 .PP
 Jozsef Kadlecsik wrote the REJECT target.
 .PP
-Harald Welte wrote the ULOG target, TTL match+target and libipulog.
+Harald Welte wrote the ULOG and NFQUEUE target, the new libiptc, aswell as TTL match+target and libipulog.
 .PP
 The Netfilter Core Team is: Marc Boucher, Martin Josefsson, Jozsef Kadlecsik,
 James Morris, Harald Welte and Rusty Russell.
index 9bfe1d3..6afe68f 100644 (file)
@@ -430,7 +430,8 @@ cmd2char(int option)
 }
 
 static void
-add_command(int *cmd, const int newcmd, const int othercmds, int invert)
+add_command(unsigned int *cmd, const int newcmd, const int othercmds,
+           int invert)
 {
        if (invert)
                exit_error(PARAMETER_PROBLEM, "unexpected ! flag");
@@ -733,7 +734,7 @@ find_match(const char *name, enum ip6t_tryload tryload, struct ip6tables_rule_ma
        }
 
 #ifndef NO_SHARED_LIBS
-       if (!ptr && tryload != DONT_LOAD) {
+       if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
                char path[strlen(lib_dir) + sizeof("/libip6t_.so")
                         + strlen(name)];
                if (!icmphack)
@@ -985,7 +986,7 @@ find_target(const char *name, enum ip6t_tryload tryload)
        }
 
 #ifndef NO_SHARED_LIBS
-       if (!ptr && tryload != DONT_LOAD) {
+       if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
                char path[strlen(lib_dir) + sizeof("/libip6t_.so")
                         + strlen(name)];
                sprintf(path, "%s/libip6t_%s.so", lib_dir, name);
@@ -1028,9 +1029,6 @@ merge_options(struct option *oldopts, const struct option *newopts,
        unsigned int num_old, num_new, i;
        struct option *merge;
 
-       /* Release previous options merged if any */
-       free_opts(0);
-
        for (num_old = 0; oldopts[num_old].name; num_old++);
        for (num_new = 0; newopts[num_new].name; num_new++);
 
@@ -1039,6 +1037,7 @@ merge_options(struct option *oldopts, const struct option *newopts,
 
        merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
        memcpy(merge, oldopts, num_old * sizeof(struct option));
+       free_opts(0); /* Release previous options merged if any */
        for (i = 0; i < num_new; i++) {
                merge[num_old + i] = newopts[i];
                merge[num_old + i].val += *option_offset;
@@ -1059,7 +1058,7 @@ register_match6(struct ip6tables_match *me)
                exit(1);
        }
 
-       if (find_match(me->name, DONT_LOAD, NULL)) {
+       if (find_match(me->name, DURING_LOAD, NULL)) {
                fprintf(stderr, "%s: match `%s' already registered.\n",
                        program_name, me->name);
                exit(1);
@@ -1089,7 +1088,7 @@ register_target6(struct ip6tables_target *me)
                exit(1);
        }
 
-       if (find_target(me->name, DONT_LOAD)) {
+       if (find_target(me->name, DURING_LOAD)) {
                fprintf(stderr, "%s: target `%s' already registered.\n",
                        program_name, me->name);
                exit(1);
index 6c7267e..79b5dc7 100644 (file)
@@ -197,7 +197,11 @@ static void print_rule(const struct ipt_entry *e,
        /* Print target name */ 
        target_name = iptc_get_target(e, h);
        if (target_name && (*target_name != '\0'))
+#ifdef IPT_F_GOTO
+               printf("-%c %s ", e->ip.flags & IPT_F_GOTO ? 'g' : 'j', target_name);
+#else
                printf("-j %s ", target_name);
+#endif
 
        /* Print targinfo part */
        t = ipt_get_target((struct ipt_entry *)e);
index 0d17bd5..66800a5 100644 (file)
@@ -71,7 +71,19 @@ means to let the packet through.
 .I DROP
 means to drop the packet on the floor.
 .I QUEUE
-means to pass the packet to userspace (if supported by the kernel).
+means to pass the packet to userspace.  (How the packet can be received
+by a userspace process differs by the particular queue handler.  2.4.x
+and 2.6.x kernels up to 2.6.13 include the 
+.B
+ip_queue
+queue handler.  Kernels 2.6.14 and later additionally include the 
+.B
+nfnetlink_queue
+queue handler.  Packets with a target of QUEUE will be sent to queue number '0'
+in this case. Please also see the
+.B
+NFQUEUE
+target as described later in this man page.)
 .I RETURN
 means stop traversing this chain and resume at the next rule in the
 previous (calling) chain.  If the end of a built-in chain is reached
@@ -210,9 +222,10 @@ target of that name already.
 .TP
 .BR "-X, --delete-chain " "[\fIchain\fP]"
 Delete the optional user-defined chain specified.  There must be no references
-to the chain.  If there are, you must delete or replace the referring
-rules before the chain can be deleted.  If no argument is given, it
-will attempt to delete every non-builtin chain in the table.
+to the chain.  If there are, you must delete or replace the referring rules
+before the chain can be deleted.  The chain must be empty, i.e. not contain
+any rules.  If no argument is given, it will attempt to delete every
+non-builtin chain in the table.
 .TP
 .BI "-P, --policy " "chain target"
 Set the policy for the chain to the given target.  See the section
@@ -284,10 +297,18 @@ one this rule is in), one of the special builtin targets which decide
 the fate of the packet immediately, or an extension (see
 .B EXTENSIONS
 below).  If this
-option is omitted in a rule, then matching the rule will have no
+option is omitted in a rule (and
+.B -g
+is not used), then matching the rule will have no
 effect on the packet's fate, but the counters on the rule will be
 incremented.
 .TP
+.BI "-g, --goto " "chain"
+This specifies that the processing should continue in a user
+specified chain. Unlike the --jump option return will not continue
+processing in this chain but instead in the chain that called us via
+--jump.
+.TP
 .BR "-i, --in-interface " "[!] \fIname\fP"
 Name of an interface via which a packet was received (only for
 packets entering the 
@@ -440,7 +461,8 @@ There are several other changes in iptables.
 .BR iptables-restore (8),
 .BR ip6tables (8),
 .BR ip6tables-save (8),
-.BR ip6tables-restore (8).
+.BR ip6tables-restore (8),
+.BR libipq (3).
 .P
 The packet-filtering-HOWTO details iptables usage for
 packet filtering, the NAT-HOWTO details NAT,
@@ -451,7 +473,7 @@ and the netfilter-hacking-HOWTO details the netfilter internals.
 See
 .BR "http://www.netfilter.org/" .
 .SH AUTHORS
-Rusty Russell wrote iptables, in early consultation with Michael
+Rusty Russell originally wrote iptables, in early consultation with Michael
 Neuling.
 .PP
 Marc Boucher made Rusty abandon ipnatctl by lobbying for a generic packet
@@ -462,12 +484,12 @@ James Morris wrote the TOS target, and tos match.
 .PP
 Jozsef Kadlecsik wrote the REJECT target.
 .PP
-Harald Welte wrote the ULOG target, TTL, DSCP, ECN matches and targets.
+Harald Welte wrote the ULOG and NFQUEUE target, the new libiptc, as well as the TTL, DSCP, ECN matches and targets.
 .PP
 The Netfilter Core Team is: Marc Boucher, Martin Josefsson, Jozsef Kadlecsik, 
 Patrick McHardy, James Morris, Harald Welte and Rusty Russell.
 .PP
-Man page written by Herve Eychenne <rv@wallfire.org>.
+Man page originally written by Herve Eychenne <rv@wallfire.org>.
 .\" .. and did I mention that we are incredibly cool people?
 .\" .. sexy, too ..
 .\" .. witty, charming, powerful ..
index 92c6c49..e22b9ea 100644 (file)
@@ -39,6 +39,7 @@
 #include <iptables.h>
 #include <fcntl.h>
 #include <sys/wait.h>
+#include <sys/utsname.h>
 
 #ifndef TRUE
 #define TRUE 1
@@ -134,6 +135,7 @@ static struct option original_opts[] = {
        { "line-numbers", 0, 0, '0' },
        { "modprobe", 1, 0, 'M' },
        { "set-counters", 1, 0, 'c' },
+       { "goto", 1, 0, 'g' },
        { 0 }
 };
 
@@ -193,6 +195,8 @@ const char *program_version;
 const char *program_name;
 char *lib_dir;
 
+int kernel_version;
+
 /* Keeping track of external matches and targets: linked lists.  */
 struct iptables_match *iptables_matches = NULL;
 struct iptables_target *iptables_targets = NULL;
@@ -399,6 +403,10 @@ exit_printhelp(struct iptables_rule_match *matches)
 "                              network interface name ([+] for wildcard)\n"
 "  --jump      -j target\n"
 "                              target for rule (may load target extension)\n"
+#ifdef IPT_F_GOTO
+"  --goto      -g chain\n"
+"                              jump to chain with no return\n"
+#endif
 "  --match     -m match\n"
 "                              extended match (may load extension)\n"
 "  --numeric   -n              numeric output of addresses and ports\n"
@@ -484,7 +492,8 @@ cmd2char(int option)
 }
 
 static void
-add_command(int *cmd, const int newcmd, const int othercmds, int invert)
+add_command(unsigned int *cmd, const int newcmd, const int othercmds, 
+           int invert)
 {
        if (invert)
                exit_error(PARAMETER_PROBLEM, "unexpected ! flag");
@@ -676,7 +685,7 @@ find_match(const char *name, enum ipt_tryload tryload, struct iptables_rule_matc
        }
 
 #ifndef NO_SHARED_LIBS
-       if (!ptr && tryload != DONT_LOAD) {
+       if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
                char path[strlen(lib_dir) + sizeof("/libipt_.so")
                         + strlen(name)];
                sprintf(path, "%s/libipt_%s.so", lib_dir, name);
@@ -985,7 +994,7 @@ find_target(const char *name, enum ipt_tryload tryload)
        }
 
 #ifndef NO_SHARED_LIBS
-       if (!ptr && tryload != DONT_LOAD) {
+       if (!ptr && tryload != DONT_LOAD && tryload != DURING_LOAD) {
                char path[strlen(lib_dir) + sizeof("/libipt_.so")
                         + strlen(name)];
                sprintf(path, "%s/libipt_%s.so", lib_dir, name);
@@ -1028,9 +1037,6 @@ merge_options(struct option *oldopts, const struct option *newopts,
        unsigned int num_old, num_new, i;
        struct option *merge;
 
-       /* Release previous options merged if any */
-       free_opts(0);
-       
        for (num_old = 0; oldopts[num_old].name; num_old++);
        for (num_new = 0; newopts[num_new].name; num_new++);
 
@@ -1039,6 +1045,7 @@ merge_options(struct option *oldopts, const struct option *newopts,
 
        merge = malloc(sizeof(struct option) * (num_new + num_old + 1));
        memcpy(merge, oldopts, num_old * sizeof(struct option));
+       free_opts(0); /* Release previous options merged if any */
        for (i = 0; i < num_new; i++) {
                merge[num_old + i] = newopts[i];
                merge[num_old + i].val += *option_offset;
@@ -1112,7 +1119,7 @@ register_match(struct iptables_match *me)
                exit(1);
        }
 
-       old = find_match(me->name, DONT_LOAD, NULL);
+       old = find_match(me->name, DURING_LOAD, NULL);
        if (old) {
                if (old->revision == me->revision) {
                        fprintf(stderr,
@@ -1168,7 +1175,7 @@ register_target(struct iptables_target *me)
                exit(1);
        }
 
-       old = find_target(me->name, DONT_LOAD);
+       old = find_target(me->name, DURING_LOAD);
        if (old) {
                struct iptables_target **i;
 
@@ -1408,6 +1415,11 @@ print_firewall(const struct ipt_entry *fw,
        if (format & FMT_NOTABLE)
                fputs("  ", stdout);
 
+#ifdef IPT_F_GOTO
+       if(fw->ip.flags & IPT_F_GOTO)
+               printf("[goto] ");
+#endif
+
        IPT_MATCH_ITERATE(fw, print_match, &fw->ip, format & FMT_NUMERIC);
 
        if (target) {
@@ -1805,6 +1817,21 @@ static void set_revision(char *name, u_int8_t revision)
        name[IPT_FUNCTION_MAXNAMELEN - 1] = revision;
 }
 
+void
+get_kernel_version(void) {
+       static struct utsname uts;
+       int x = 0, y = 0, z = 0;
+
+       if (uname(&uts) == -1) {
+               fprintf(stderr, "Unable to retrieve kernel version.\n");
+               free_opts(1);
+               exit(1); 
+       }
+
+       sscanf(uts.release, "%d.%d.%d", &x, &y, &z);
+       kernel_version = LINUX_VERSION(x, y, z);
+}
+
 int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
 {
        struct ipt_entry fw, *e = NULL;
@@ -1850,7 +1877,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
        opterr = 0;
 
        while ((c = getopt_long(argc, argv,
-          "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:",
+          "-A:D:R:I:L::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:",
                                           opts, NULL)) != -1) {
                switch (c) {
                        /*
@@ -2018,6 +2045,15 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                        dhostnetworkmask = argv[optind-1];
                        break;
 
+#ifdef IPT_F_GOTO
+               case 'g':
+                       set_option(&options, OPT_JUMP, &fw.ip.invflags,
+                                  invert);
+                       fw.ip.flags |= IPT_F_GOTO;
+                       jumpto = parse_target(optarg);
+                       break;
+#endif
+
                case 'j':
                        set_option(&options, OPT_JUMP, &fw.ip.invflags,
                                   invert);
@@ -2360,7 +2396,9 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                        target->t = fw_calloc(1, size);
                        target->t->u.target_size = size;
                        strcpy(target->t->u.user.name, jumpto);
-                       set_revision(target->t->u.user.name, target->revision);
+                       if (!iptc_is_chain(jumpto, *handle))
+                               set_revision(target->t->u.user.name,
+                                            target->revision);
                        if (target->init != NULL)
                                target->init(target->t, &fw.nfcache);
                }
@@ -2370,6 +2408,11 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
                         * We cannot know if the plugin is corrupt, non
                         * existant OR if the user just misspelled a
                         * chain. */
+#ifdef IPT_F_GOTO
+                       if (fw.ip.flags & IPT_F_GOTO)
+                               exit_error(PARAMETER_PROBLEM,
+                                          "goto '%s' is not a chain\n", jumpto);
+#endif
                        find_target(jumpto, LOAD_MUST_SUCCEED);
                } else {
                        e = generate_entry(&fw, matches, target->t);
index a25ad4c..658af97 100644 (file)
@@ -122,7 +122,8 @@ static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h,
                                     unsigned char *buf, size_t len,
                                     int timeout)
 {
-       int addrlen, status;
+       unsigned int addrlen;
+       int status;
        struct nlmsghdr *nlh;
 
        if (len < sizeof(struct nlmsgerr)) {
index 88d23d0..a281e89 100644 (file)
@@ -1,4 +1,4 @@
-/* Library which manipulates firewall rules.  Version $Revision: 3756 $ */
+/* Library which manipulates firewall rules.  Version $Revision: 4511 $ */
 
 /* Architecture of firewall rules is as follows:
  *
@@ -399,7 +399,7 @@ static inline void iptc_insert_chain(TC_HANDLE_T h, struct chain_head *c)
        /* sort only user defined chains */
        if (!c->hooknum) {
                list_for_each_entry(tmp, &h->chains, list) {
-                       if (strcmp(c->name, tmp->name) <= 0) {
+                       if (!tmp->hooknum && strcmp(c->name, tmp->name) <= 0) {
                                list_add(&c->list, tmp->list.prev);
                                return;
                        }
@@ -674,7 +674,7 @@ static int iptcc_compile_chain(TC_HANDLE_T h, STRUCT_REPLACE *repl, struct chain
 
 /* calculate offset and number for every rule in the cache */
 static int iptcc_compile_chain_offsets(TC_HANDLE_T h, struct chain_head *c,
-                                      int *offset, int *num)
+                                      unsigned int *offset, unsigned int *num)
 {
        struct rule_head *r;
 
@@ -798,7 +798,7 @@ TC_INIT(const char *tablename)
 {
        TC_HANDLE_T h;
        STRUCT_GETINFO info;
-       int tmp;
+       unsigned int tmp;
        socklen_t s;
 
        iptc_fn = TC_INIT;
@@ -2034,13 +2034,13 @@ TC_COMMIT(TC_HANDLE_T *handle)
        new_number = iptcc_compile_table_prep(*handle, &new_size);
        if (new_number < 0) {
                errno = ENOMEM;
-               return 0;
+               goto out_zero;
        }
 
        repl = malloc(sizeof(*repl) + new_size);
        if (!repl) {
                errno = ENOMEM;
-               return 0;
+               goto out_zero;
        }
        memset(repl, 0, sizeof(*repl) + new_size);
 
@@ -2055,17 +2055,14 @@ TC_COMMIT(TC_HANDLE_T *handle)
        repl->counters = malloc(sizeof(STRUCT_COUNTERS)
                                * (*handle)->info.num_entries);
        if (!repl->counters) {
-               free(repl);
                errno = ENOMEM;
-               return 0;
+               goto out_free_repl;
        }
        /* These are the counters we're going to put back, later. */
        newcounters = malloc(counterlen);
        if (!newcounters) {
-               free(repl->counters);
-               free(repl);
                errno = ENOMEM;
-               return 0;
+               goto out_free_repl_counters;
        }
        memset(newcounters, 0, counterlen);
 
@@ -2082,9 +2079,7 @@ TC_COMMIT(TC_HANDLE_T *handle)
        ret = iptcc_compile_table(*handle, repl);
        if (ret < 0) {
                errno = ret;
-               free(repl->counters);
-               free(repl);
-               return 0;
+               goto out_free_newcounters;
        }
 
 
@@ -2099,12 +2094,11 @@ TC_COMMIT(TC_HANDLE_T *handle)
        }
 #endif
 
-       if (setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
-                      sizeof(*repl) + repl->size) < 0) {
-               free(repl->counters);
-               free(repl);
-               free(newcounters);
-               return 0;
+       ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_REPLACE, repl,
+                        sizeof(*repl) + repl->size);
+       if (ret < 0) {
+               errno = ret;
+               goto out_free_newcounters;
        }
 
        /* Put counters back. */
@@ -2194,21 +2188,29 @@ TC_COMMIT(TC_HANDLE_T *handle)
        }
 #endif
 
-       if (setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
-                      newcounters, counterlen) < 0) {
-               free(repl->counters);
-               free(repl);
-               free(newcounters);
-               return 0;
+       ret = setsockopt(sockfd, TC_IPPROTO, SO_SET_ADD_COUNTERS,
+                        newcounters, counterlen);
+       if (ret < 0) {
+               errno = ret;
+               goto out_free_newcounters;
        }
 
        free(repl->counters);
        free(repl);
        free(newcounters);
 
- finished:
+finished:
        TC_FREE(handle);
        return 1;
+
+out_free_newcounters:
+       free(newcounters);
+out_free_repl_counters:
+       free(repl->counters);
+out_free_repl:
+       free(repl);
+out_zero:
+       return 0;
 }
 
 /* Get raw socket. */