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