This commit was generated by cvs2svn to compensate for changes in r2290,
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)
which included commits to RCS files with non-trunk default branches.

83 files changed:
INCOMPATIBILITIES
extensions/.dccp-test [new file with mode: 0755]
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 
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
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. */