which included commits to RCS files with non-trunk default branches.
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
--- /dev/null
+#!/bin/sh
+# True if dccp is applied.
+[ -f $KERNEL_DIR/include/linux/netfilter_ipv4/ipt_dccp.h ] && echo dccp
--- /dev/null
+/* 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);
+}
-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.
--- /dev/null
+/* 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);
+}
--- /dev/null
+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.
.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
.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.
-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.
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
--- /dev/null
+/* 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);
+}
-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.
-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]"
-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.
-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.
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"
-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.
-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.
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
-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.
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);
-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]"
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).
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" .
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"
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;
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;
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 ,
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 ,
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.
--- /dev/null
+/* 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);
+}
--- /dev/null
+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
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.
--- /dev/null
+/* 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);
+}
{
}
-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;
" --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 }
};
}
}
-#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,
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;
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;
}
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");
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 = {
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)
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;
"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)
{
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. */
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;
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;
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.
+
};
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;
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);
= (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;
--- /dev/null
+/* 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);
+}
--- /dev/null
+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.
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;
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 (*)"}
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;
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;
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.
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
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
}
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;
-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]"
};
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);
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
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
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);
{
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:
fputs("--connbytes-mode ", stdout);
print_mode(sinfo);
- fputs("--connbytes-direction ", stdout);
+ fputs("--connbytes-dir ", stdout);
print_direction(sinfo);
}
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)
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
{
char buf[BUFSIZ];
- if (inv)
- fputc('!', stdout);
+ if (inv)
+ printf("! ");
if (mask->s_addr == 0L && !numeric)
printf("%s ", "anywhere");
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);
--- /dev/null
+/* 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);
+}
+
--- /dev/null
+.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.
};
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;
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
-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]"
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"
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]"
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).
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;
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;
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 ,
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 ,
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.
--- /dev/null
+/* 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);
+}
--- /dev/null
+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
}
-static int k_atoi(signed char *string)
+static int k_atoi(char *string)
{
unsigned int result = 0;
int maxoctet = IPT_RPC_CHAR_LEN;
#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
*
* 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;
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) {
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 */
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:
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 */
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);
}
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
};
--- /dev/null
+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.
};
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;
/* 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 */
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
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 `!'");
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 `!'");
enum ip6t_tryload {
DONT_LOAD,
+ DURING_LOAD,
TRY_LOAD,
LOAD_MUST_SUCCEED
};
enum ipt_tryload {
DONT_LOAD,
+ DURING_LOAD,
TRY_LOAD,
LOAD_MUST_SUCCEED
};
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*/
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);
--- /dev/null
+/* 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 */
#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)
--- /dev/null
+#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 */
--- /dev/null
+#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 */
-.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.
.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
(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
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 .
.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,
.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.
}
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");
}
#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)
}
#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);
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++);
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;
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);
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);
/* 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);
.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
.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
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
.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,
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
.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 ..
#include <iptables.h>
#include <fcntl.h>
#include <sys/wait.h>
+#include <sys/utsname.h>
#ifndef TRUE
#define TRUE 1
{ "line-numbers", 0, 0, '0' },
{ "modprobe", 1, 0, 'M' },
{ "set-counters", 1, 0, 'c' },
+ { "goto", 1, 0, 'g' },
{ 0 }
};
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;
" 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"
}
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");
}
#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);
}
#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);
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++);
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;
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,
exit(1);
}
- old = find_target(me->name, DONT_LOAD);
+ old = find_target(me->name, DURING_LOAD);
if (old) {
struct iptables_target **i;
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) {
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;
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) {
/*
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);
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);
}
* 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);
unsigned char *buf, size_t len,
int timeout)
{
- int addrlen, status;
+ unsigned int addrlen;
+ int status;
struct nlmsghdr *nlh;
if (len < sizeof(struct nlmsgerr)) {
-/* Library which manipulates firewall rules. Version $Revision: 3756 $ */
+/* Library which manipulates firewall rules. Version $Revision: 4511 $ */
/* Architecture of firewall rules is as follows:
*
/* 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;
}
/* 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;
{
TC_HANDLE_T h;
STRUCT_GETINFO info;
- int tmp;
+ unsigned int tmp;
socklen_t s;
iptc_fn = TC_INIT;
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);
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);
ret = iptcc_compile_table(*handle, repl);
if (ret < 0) {
errno = ret;
- free(repl->counters);
- free(repl);
- return 0;
+ goto out_free_newcounters;
}
}
#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. */
}
#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. */