diff --git a/.gitignore b/.gitignore index e69de29..5d3a318 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +/IPTables-libiptc-0.51.tar.gz diff --git a/perl-IPTables-libiptc-0.51-Support-iptables-1.4.12.patch b/perl-IPTables-libiptc-0.51-Support-iptables-1.4.12.patch new file mode 100644 index 0000000..cbb5c2a --- /dev/null +++ b/perl-IPTables-libiptc-0.51-Support-iptables-1.4.12.patch @@ -0,0 +1,2844 @@ +From 3fa08a692972050c75d2a1225febd91d6f5a3e71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20P=C3=ADsa=C5=99?= +Date: Wed, 31 Aug 2011 12:58:08 +0200 +Subject: [PATCH] Support iptables-1.4.12 + +--- + iptables/iptables-blocking.c | 4 + + iptables/iptables-detect-version.c | 6 +- + iptables/iptables-standalone.c | 90 +-- + iptables/iptables-standalone.c-old | 86 ++ + iptables/iptables-standalone.c-v1.4.12 | 87 ++ + iptables/iptables.c-v1.4.12 | 1998 ++++++++++++++++++++++++++++++++ + iptables/xshared.c | 39 +- + iptables/xshared.c-old | 31 + + iptables/xshared.c-v1.4.12 | 238 ++++ + iptables/xshared.h | 16 +- + iptables/xshared.h-old | 10 + + iptables/xshared.h-v1.4.12 | 89 ++ + libiptc.xs | 6 + + 13 files changed, 2581 insertions(+), 119 deletions(-) + create mode 100644 iptables/iptables-standalone.c-old + create mode 100644 iptables/iptables-standalone.c-v1.4.12 + create mode 100644 iptables/iptables.c-v1.4.12 + create mode 100644 iptables/xshared.c-old + create mode 100644 iptables/xshared.c-v1.4.12 + create mode 100644 iptables/xshared.h-old + create mode 100644 iptables/xshared.h-v1.4.12 + +diff --git a/iptables/iptables-blocking.c b/iptables/iptables-blocking.c +index 3906e4a..883a170 100644 +--- a/iptables/iptables-blocking.c ++++ b/iptables/iptables-blocking.c +@@ -37,6 +37,7 @@ + #include + #include + #include "iptables-multi.h" ++#include + + #include + #include +@@ -80,6 +81,9 @@ main(int argc, char *argv[]) + } + flock(fd, LOCK_EX); + ++#if XTABLES_VERSION_CODE >= 7 ++#define do_command do_command4 ++#endif + ret = do_command(argc, argv, &table, &handle); + if (ret) { + ret = iptc_commit(handle); +diff --git a/iptables/iptables-detect-version.c b/iptables/iptables-detect-version.c +index bd64c70..f069a96 100644 +--- a/iptables/iptables-detect-version.c ++++ b/iptables/iptables-detect-version.c +@@ -45,7 +45,11 @@ + #warning "This version of xtables is currently not supported by this Perl package" + #include "iptables.c-v1.4.11.1" + +-#elif XTABLES_VERSION_CODE > 6 ++#elif XTABLES_VERSION_CODE == 7 ++#warning "This version of xtables is currently not supported by this Perl package" ++#include "iptables.c-v1.4.12" ++ ++#elif XTABLES_VERSION_CODE > 7 + #error "The libxtables is newer than this package support and know of - Sorry!" + #error " Please inform the package author of this issue, thanks! " + +diff --git a/iptables/iptables-standalone.c b/iptables/iptables-standalone.c +index 9185388..e9f2de5 100644 +--- a/iptables/iptables-standalone.c ++++ b/iptables/iptables-standalone.c +@@ -1,86 +1,12 @@ +-/* +- * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au +- * +- * Based on the ipchains code by Paul Russell and Michael Neuling +- * +- * (C) 2000-2002 by the netfilter coreteam : +- * Paul 'Rusty' Russell +- * Marc Boucher +- * James Morris +- * Harald Welte +- * Jozsef Kadlecsik +- * +- * iptables -- IP firewall administration for kernels with +- * firewall table (aimed for the 2.3 kernels) +- * +- * See the accompanying manual page iptables(8) for information +- * about proper usage of this program. +- * +- * 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., 675 Mass Ave, Cambridge, MA 02139, USA. +- */ ++#include + +-#include +-#include +-#include +-#include +-#include +-#include "iptables-multi.h" ++#if XTABLES_VERSION_CODE < 7 ++#include "iptables-standalone.c-old" + +-#ifdef IPTABLES_MULTI +-int +-iptables_main(int argc, char *argv[]) +-#else +-int +-main(int argc, char *argv[]) +-#endif +-{ +- int ret; +- char *table = "filter"; +- struct iptc_handle *handle = NULL; ++#elif XTABLES_VERSION_CODE == 7 ++#include "iptables-standalone.c-v1.4.12" + +- iptables_globals.program_name = "iptables"; +- ret = xtables_init_all(&iptables_globals, NFPROTO_IPV4); +- if (ret < 0) { +- fprintf(stderr, "%s/%s Failed to initialize xtables\n", +- iptables_globals.program_name, +- iptables_globals.program_version); +- exit(1); +- } +-#ifdef NO_SHARED_LIBS +- init_extensions(); ++#else ++#error "The libxtables is newer than this package support and know of - Sorry!" ++#error " Please inform the package author of this issue, thanks! " + #endif +- +- ret = do_command(argc, argv, &table, &handle); +- if (ret) { +- ret = iptc_commit(handle); +- iptc_free(handle); +- } +- +- if (!ret) { +- if (errno == EINVAL) { +- fprintf(stderr, "iptables: %s. " +- "Run `dmesg' for more information.\n", +- iptc_strerror(errno)); +- } else { +- fprintf(stderr, "iptables: %s.\n", +- iptc_strerror(errno)); +- } +- if (errno == EAGAIN) { +- exit(RESOURCE_PROBLEM); +- } +- } +- +- exit(!ret); +-} +diff --git a/iptables/iptables-standalone.c-old b/iptables/iptables-standalone.c-old +new file mode 100644 +index 0000000..9185388 +--- /dev/null ++++ b/iptables/iptables-standalone.c-old +@@ -0,0 +1,86 @@ ++/* ++ * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au ++ * ++ * Based on the ipchains code by Paul Russell and Michael Neuling ++ * ++ * (C) 2000-2002 by the netfilter coreteam : ++ * Paul 'Rusty' Russell ++ * Marc Boucher ++ * James Morris ++ * Harald Welte ++ * Jozsef Kadlecsik ++ * ++ * iptables -- IP firewall administration for kernels with ++ * firewall table (aimed for the 2.3 kernels) ++ * ++ * See the accompanying manual page iptables(8) for information ++ * about proper usage of this program. ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "iptables-multi.h" ++ ++#ifdef IPTABLES_MULTI ++int ++iptables_main(int argc, char *argv[]) ++#else ++int ++main(int argc, char *argv[]) ++#endif ++{ ++ int ret; ++ char *table = "filter"; ++ struct iptc_handle *handle = NULL; ++ ++ iptables_globals.program_name = "iptables"; ++ ret = xtables_init_all(&iptables_globals, NFPROTO_IPV4); ++ if (ret < 0) { ++ fprintf(stderr, "%s/%s Failed to initialize xtables\n", ++ iptables_globals.program_name, ++ iptables_globals.program_version); ++ exit(1); ++ } ++#ifdef NO_SHARED_LIBS ++ init_extensions(); ++#endif ++ ++ ret = do_command(argc, argv, &table, &handle); ++ if (ret) { ++ ret = iptc_commit(handle); ++ iptc_free(handle); ++ } ++ ++ if (!ret) { ++ if (errno == EINVAL) { ++ fprintf(stderr, "iptables: %s. " ++ "Run `dmesg' for more information.\n", ++ iptc_strerror(errno)); ++ } else { ++ fprintf(stderr, "iptables: %s.\n", ++ iptc_strerror(errno)); ++ } ++ if (errno == EAGAIN) { ++ exit(RESOURCE_PROBLEM); ++ } ++ } ++ ++ exit(!ret); ++} +diff --git a/iptables/iptables-standalone.c-v1.4.12 b/iptables/iptables-standalone.c-v1.4.12 +new file mode 100644 +index 0000000..87f1d31 +--- /dev/null ++++ b/iptables/iptables-standalone.c-v1.4.12 +@@ -0,0 +1,87 @@ ++/* ++ * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au ++ * ++ * Based on the ipchains code by Paul Russell and Michael Neuling ++ * ++ * (C) 2000-2002 by the netfilter coreteam : ++ * Paul 'Rusty' Russell ++ * Marc Boucher ++ * James Morris ++ * Harald Welte ++ * Jozsef Kadlecsik ++ * ++ * iptables -- IP firewall administration for kernels with ++ * firewall table (aimed for the 2.3 kernels) ++ * ++ * See the accompanying manual page iptables(8) for information ++ * about proper usage of this program. ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include "iptables-multi.h" ++ ++#ifdef IPTABLES_MULTI ++int ++iptables_main(int argc, char *argv[]) ++#else ++int ++main(int argc, char *argv[]) ++#endif ++{ ++ int ret; ++ char *table = "filter"; ++ struct iptc_handle *handle = NULL; ++ ++ iptables_globals.program_name = "iptables"; ++ ret = xtables_init_all(&iptables_globals, NFPROTO_IPV4); ++ if (ret < 0) { ++ fprintf(stderr, "%s/%s Failed to initialize xtables\n", ++ iptables_globals.program_name, ++ iptables_globals.program_version); ++ exit(1); ++ } ++#if defined(ALL_INCLUSIVE) || defined(NO_SHARED_LIBS) ++ init_extensions(); ++ init_extensions4(); ++#endif ++ ++ ret = do_command4(argc, argv, &table, &handle); ++ if (ret) { ++ ret = iptc_commit(handle); ++ iptc_free(handle); ++ } ++ ++ if (!ret) { ++ if (errno == EINVAL) { ++ fprintf(stderr, "iptables: %s. " ++ "Run `dmesg' for more information.\n", ++ iptc_strerror(errno)); ++ } else { ++ fprintf(stderr, "iptables: %s.\n", ++ iptc_strerror(errno)); ++ } ++ if (errno == EAGAIN) { ++ exit(RESOURCE_PROBLEM); ++ } ++ } ++ ++ exit(!ret); ++} +diff --git a/iptables/iptables.c-v1.4.12 b/iptables/iptables.c-v1.4.12 +new file mode 100644 +index 0000000..50dc1e7 +--- /dev/null ++++ b/iptables/iptables.c-v1.4.12 +@@ -0,0 +1,1998 @@ ++/* Code to take an iptables-style command line and do it. */ ++ ++/* ++ * Author: Paul.Russell@rustcorp.com.au and mneuling@radlogic.com.au ++ * ++ * (C) 2000-2002 by the netfilter coreteam : ++ * Paul 'Rusty' Russell ++ * Marc Boucher ++ * James Morris ++ * Harald Welte ++ * Jozsef Kadlecsik ++ * ++ * 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "xshared.h" ++ ++#ifndef TRUE ++#define TRUE 1 ++#endif ++#ifndef FALSE ++#define FALSE 0 ++#endif ++ ++#define FMT_NUMERIC 0x0001 ++#define FMT_NOCOUNTS 0x0002 ++#define FMT_KILOMEGAGIGA 0x0004 ++#define FMT_OPTIONS 0x0008 ++#define FMT_NOTABLE 0x0010 ++#define FMT_NOTARGET 0x0020 ++#define FMT_VIA 0x0040 ++#define FMT_NONEWLINE 0x0080 ++#define FMT_LINENUMBERS 0x0100 ++ ++#define FMT_PRINT_RULE (FMT_NOCOUNTS | FMT_OPTIONS | FMT_VIA \ ++ | FMT_NUMERIC | FMT_NOTABLE) ++#define FMT(tab,notab) ((format) & FMT_NOTABLE ? (notab) : (tab)) ++ ++ ++#define CMD_NONE 0x0000U ++#define CMD_INSERT 0x0001U ++#define CMD_DELETE 0x0002U ++#define CMD_DELETE_NUM 0x0004U ++#define CMD_REPLACE 0x0008U ++#define CMD_APPEND 0x0010U ++#define CMD_LIST 0x0020U ++#define CMD_FLUSH 0x0040U ++#define CMD_ZERO 0x0080U ++#define CMD_NEW_CHAIN 0x0100U ++#define CMD_DELETE_CHAIN 0x0200U ++#define CMD_SET_POLICY 0x0400U ++#define CMD_RENAME_CHAIN 0x0800U ++#define CMD_LIST_RULES 0x1000U ++#define CMD_ZERO_NUM 0x2000U ++#define CMD_CHECK 0x4000U ++#define NUMBER_OF_CMD 16 ++static const char cmdflags[] = { 'I', 'D', 'D', 'R', 'A', 'L', 'F', 'Z', ++ 'Z', 'N', 'X', 'P', 'E', 'S', 'C' }; ++ ++#define OPT_FRAGMENT 0x00800U ++#define NUMBER_OF_OPT ARRAY_SIZE(optflags) ++static const char optflags[] ++= { 'n', 's', 'd', 'p', 'j', 'v', 'x', 'i', 'o', '0', 'c', 'f'}; ++ ++static struct option original_opts[] = { ++ {.name = "append", .has_arg = 1, .val = 'A'}, ++ {.name = "delete", .has_arg = 1, .val = 'D'}, ++ {.name = "check", .has_arg = 1, .val = 'C'}, ++ {.name = "insert", .has_arg = 1, .val = 'I'}, ++ {.name = "replace", .has_arg = 1, .val = 'R'}, ++ {.name = "list", .has_arg = 2, .val = 'L'}, ++ {.name = "list-rules", .has_arg = 2, .val = 'S'}, ++ {.name = "flush", .has_arg = 2, .val = 'F'}, ++ {.name = "zero", .has_arg = 2, .val = 'Z'}, ++ {.name = "new-chain", .has_arg = 1, .val = 'N'}, ++ {.name = "delete-chain", .has_arg = 2, .val = 'X'}, ++ {.name = "rename-chain", .has_arg = 1, .val = 'E'}, ++ {.name = "policy", .has_arg = 1, .val = 'P'}, ++ {.name = "source", .has_arg = 1, .val = 's'}, ++ {.name = "destination", .has_arg = 1, .val = 'd'}, ++ {.name = "src", .has_arg = 1, .val = 's'}, /* synonym */ ++ {.name = "dst", .has_arg = 1, .val = 'd'}, /* synonym */ ++ {.name = "protocol", .has_arg = 1, .val = 'p'}, ++ {.name = "in-interface", .has_arg = 1, .val = 'i'}, ++ {.name = "jump", .has_arg = 1, .val = 'j'}, ++ {.name = "table", .has_arg = 1, .val = 't'}, ++ {.name = "match", .has_arg = 1, .val = 'm'}, ++ {.name = "numeric", .has_arg = 0, .val = 'n'}, ++ {.name = "out-interface", .has_arg = 1, .val = 'o'}, ++ {.name = "verbose", .has_arg = 0, .val = 'v'}, ++ {.name = "exact", .has_arg = 0, .val = 'x'}, ++ {.name = "fragments", .has_arg = 0, .val = 'f'}, ++ {.name = "version", .has_arg = 0, .val = 'V'}, ++ {.name = "help", .has_arg = 2, .val = 'h'}, ++ {.name = "line-numbers", .has_arg = 0, .val = '0'}, ++ {.name = "modprobe", .has_arg = 1, .val = 'M'}, ++ {.name = "set-counters", .has_arg = 1, .val = 'c'}, ++ {.name = "goto", .has_arg = 1, .val = 'g'}, ++ {.name = "ipv4", .has_arg = 0, .val = '4'}, ++ {.name = "ipv6", .has_arg = 0, .val = '6'}, ++ {NULL}, ++}; ++ ++void iptables_exit_error(enum xtables_exittype status, const char *msg, ...) __attribute__((noreturn, format(printf,2,3))); ++ ++struct xtables_globals iptables_globals = { ++ .option_offset = 0, ++ .program_version = IPTABLES_VERSION, ++ .orig_opts = original_opts, ++ .exit_err = iptables_exit_error, ++}; ++ ++/* Table of legal combinations of commands and options. If any of the ++ * given commands make an option legal, that option is legal (applies to ++ * CMD_LIST and CMD_ZERO only). ++ * Key: ++ * + compulsory ++ * x illegal ++ * optional ++ */ ++ ++static const char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] = ++/* Well, it's better than "Re: Linux vs FreeBSD" */ ++{ ++ /* -n -s -d -p -j -v -x -i -o --line -c -f */ ++/*INSERT*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '}, ++/*DELETE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '}, ++/*DELETE_NUM*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*REPLACE*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '}, ++/*APPEND*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x',' ',' '}, ++/*LIST*/ {' ','x','x','x','x',' ',' ','x','x',' ','x','x'}, ++/*FLUSH*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*ZERO*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*ZERO_NUM*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*NEW_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*DEL_CHAIN*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*SET_POLICY*/{'x','x','x','x','x',' ','x','x','x','x',' ','x'}, ++/*RENAME*/ {'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*LIST_RULES*/{'x','x','x','x','x',' ','x','x','x','x','x','x'}, ++/*CHECK*/ {'x',' ',' ',' ',' ',' ','x',' ',' ','x','x',' '}, ++}; ++ ++static const int inverse_for_options[NUMBER_OF_OPT] = ++{ ++/* -n */ 0, ++/* -s */ IPT_INV_SRCIP, ++/* -d */ IPT_INV_DSTIP, ++/* -p */ IPT_INV_PROTO, ++/* -j */ 0, ++/* -v */ 0, ++/* -x */ 0, ++/* -i */ IPT_INV_VIA_IN, ++/* -o */ IPT_INV_VIA_OUT, ++/*--line*/ 0, ++/* -c */ 0, ++/* -f */ IPT_INV_FRAG, ++}; ++ ++#define opts iptables_globals.opts ++#define prog_name iptables_globals.program_name ++#define prog_vers iptables_globals.program_version ++ ++int kernel_version; ++ ++/* Primitive headers... */ ++/* defined in netinet/in.h */ ++#if 0 ++#ifndef IPPROTO_ESP ++#define IPPROTO_ESP 50 ++#endif ++#ifndef IPPROTO_AH ++#define IPPROTO_AH 51 ++#endif ++#endif ++ ++enum { ++ IPT_DOTTED_ADDR = 0, ++ IPT_DOTTED_MASK ++}; ++ ++static void __attribute__((noreturn)) ++exit_tryhelp(int status) ++{ ++ if (line != -1) ++ fprintf(stderr, "Error occurred at line: %d\n", line); ++ fprintf(stderr, "Try `%s -h' or '%s --help' for more information.\n", ++ prog_name, prog_name); ++ xtables_free_opts(1); ++ exit(status); ++} ++ ++static void ++exit_printhelp(const struct xtables_rule_match *matches) ++{ ++ printf("%s v%s\n\n" ++"Usage: %s -[ACD] chain rule-specification [options]\n" ++" %s -I chain [rulenum] rule-specification [options]\n" ++" %s -R chain rulenum rule-specification [options]\n" ++" %s -D chain rulenum [options]\n" ++" %s -[LS] [chain [rulenum]] [options]\n" ++" %s -[FZ] [chain] [options]\n" ++" %s -[NX] chain\n" ++" %s -E old-chain-name new-chain-name\n" ++" %s -P chain target [options]\n" ++" %s -h (print this help information)\n\n", ++ prog_name, prog_vers, prog_name, prog_name, ++ prog_name, prog_name, prog_name, prog_name, ++ prog_name, prog_name, prog_name, prog_name); ++ ++ printf( ++"Commands:\n" ++"Either long or short options are allowed.\n" ++" --append -A chain Append to chain\n" ++" --check -C chain Check for the existence of a rule\n" ++" --delete -D chain Delete matching rule from chain\n" ++" --delete -D chain rulenum\n" ++" Delete rule rulenum (1 = first) from chain\n" ++" --insert -I chain [rulenum]\n" ++" Insert in chain as rulenum (default 1=first)\n" ++" --replace -R chain rulenum\n" ++" Replace rule rulenum (1 = first) in chain\n" ++" --list -L [chain [rulenum]]\n" ++" List the rules in a chain or all chains\n" ++" --list-rules -S [chain [rulenum]]\n" ++" Print the rules in a chain or all chains\n" ++" --flush -F [chain] Delete all rules in chain or all chains\n" ++" --zero -Z [chain [rulenum]]\n" ++" Zero counters in chain or all chains\n" ++" --new -N chain Create a new user-defined chain\n" ++" --delete-chain\n" ++" -X [chain] Delete a user-defined chain\n" ++" --policy -P chain target\n" ++" Change policy on chain to target\n" ++" --rename-chain\n" ++" -E old-chain new-chain\n" ++" Change chain name, (moving any references)\n" ++ ++"Options:\n" ++" --ipv4 -4 Nothing (line is ignored by ip6tables-restore)\n" ++" --ipv6 -6 Error (line is ignored by iptables-restore)\n" ++"[!] --proto -p proto protocol: by number or name, eg. `tcp'\n" ++"[!] --source -s address[/mask][...]\n" ++" source specification\n" ++"[!] --destination -d address[/mask][...]\n" ++" destination specification\n" ++"[!] --in-interface -i input name[+]\n" ++" 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" ++"[!] --out-interface -o output name[+]\n" ++" network interface name ([+] for wildcard)\n" ++" --table -t table table to manipulate (default: `filter')\n" ++" --verbose -v verbose mode\n" ++" --line-numbers print line numbers when listing\n" ++" --exact -x expand numbers (display exact values)\n" ++"[!] --fragment -f match second or further fragments only\n" ++" --modprobe= try to insert modules using this command\n" ++" --set-counters PKTS BYTES set the counter during insert/append\n" ++"[!] --version -V print package version.\n"); ++ ++ print_extension_helps(xtables_targets, matches); ++ exit(0); ++} ++ ++void ++iptables_exit_error(enum xtables_exittype status, const char *msg, ...) ++{ ++ va_list args; ++ ++ va_start(args, msg); ++ fprintf(stderr, "%s v%s: ", prog_name, prog_vers); ++ vfprintf(stderr, msg, args); ++ va_end(args); ++ fprintf(stderr, "\n"); ++ if (status == PARAMETER_PROBLEM) ++ exit_tryhelp(status); ++ if (status == VERSION_PROBLEM) ++ fprintf(stderr, ++ "Perhaps iptables or your kernel needs to be upgraded.\n"); ++ /* On error paths, make sure that we don't leak memory */ ++ xtables_free_opts(1); ++ exit(status); ++} ++ ++static void ++generic_opt_check(int command, int options) ++{ ++ int i, j, legal = 0; ++ ++ /* Check that commands are valid with options. Complicated by the ++ * fact that if an option is legal with *any* command given, it is ++ * legal overall (ie. -z and -l). ++ */ ++ for (i = 0; i < NUMBER_OF_OPT; i++) { ++ legal = 0; /* -1 => illegal, 1 => legal, 0 => undecided. */ ++ ++ for (j = 0; j < NUMBER_OF_CMD; j++) { ++ if (!(command & (1< 1; option >>= 1, ptr++); ++ ++ return *ptr; ++} ++ ++static char ++cmd2char(int option) ++{ ++ const char *ptr; ++ for (ptr = cmdflags; option > 1; option >>= 1, ptr++); ++ ++ return *ptr; ++} ++ ++static void ++add_command(unsigned int *cmd, const int newcmd, const int othercmds, ++ int invert) ++{ ++ if (invert) ++ xtables_error(PARAMETER_PROBLEM, "unexpected ! flag"); ++ if (*cmd & (~othercmds)) ++ xtables_error(PARAMETER_PROBLEM, "Cannot use -%c with -%c\n", ++ cmd2char(newcmd), cmd2char(*cmd & (~othercmds))); ++ *cmd |= newcmd; ++} ++ ++/* ++ * All functions starting with "parse" should succeed, otherwise ++ * the program fails. ++ * Most routines return pointers to static data that may change ++ * between calls to the same or other routines with a few exceptions: ++ * "host_to_addr", "parse_hostnetwork", and "parse_hostnetworkmask" ++ * return global static data. ++*/ ++ ++/* Christophe Burki wants `-p 6' to imply `-m tcp'. */ ++/* Can't be zero. */ ++static int ++parse_rulenumber(const char *rule) ++{ ++ unsigned int rulenum; ++ ++ if (!xtables_strtoui(rule, NULL, &rulenum, 1, INT_MAX)) ++ xtables_error(PARAMETER_PROBLEM, ++ "Invalid rule number `%s'", rule); ++ ++ return rulenum; ++} ++ ++static const char * ++parse_target(const char *targetname) ++{ ++ const char *ptr; ++ ++ if (strlen(targetname) < 1) ++ xtables_error(PARAMETER_PROBLEM, ++ "Invalid target name (too short)"); ++ ++ if (strlen(targetname) >= XT_EXTENSION_MAXNAMELEN) ++ xtables_error(PARAMETER_PROBLEM, ++ "Invalid target name `%s' (%u chars max)", ++ targetname, XT_EXTENSION_MAXNAMELEN - 1); ++ ++ for (ptr = targetname; *ptr; ptr++) ++ if (isspace(*ptr)) ++ xtables_error(PARAMETER_PROBLEM, ++ "Invalid target name `%s'", targetname); ++ return targetname; ++} ++ ++static void ++set_option(unsigned int *options, unsigned int option, uint8_t *invflg, ++ int invert) ++{ ++ if (*options & option) ++ xtables_error(PARAMETER_PROBLEM, "multiple -%c flags not allowed", ++ opt2char(option)); ++ *options |= option; ++ ++ if (invert) { ++ unsigned int i; ++ for (i = 0; 1 << i != option; i++); ++ ++ if (!inverse_for_options[i]) ++ xtables_error(PARAMETER_PROBLEM, ++ "cannot have ! before -%c", ++ opt2char(option)); ++ *invflg |= inverse_for_options[i]; ++ } ++} ++ ++static void ++print_num(uint64_t number, unsigned int format) ++{ ++ if (format & FMT_KILOMEGAGIGA) { ++ if (number > 99999) { ++ number = (number + 500) / 1000; ++ if (number > 9999) { ++ number = (number + 500) / 1000; ++ if (number > 9999) { ++ number = (number + 500) / 1000; ++ if (number > 9999) { ++ number = (number + 500) / 1000; ++ printf(FMT("%4lluT ","%lluT "), (unsigned long long)number); ++ } ++ else printf(FMT("%4lluG ","%lluG "), (unsigned long long)number); ++ } ++ else printf(FMT("%4lluM ","%lluM "), (unsigned long long)number); ++ } else ++ printf(FMT("%4lluK ","%lluK "), (unsigned long long)number); ++ } else ++ printf(FMT("%5llu ","%llu "), (unsigned long long)number); ++ } else ++ printf(FMT("%8llu ","%llu "), (unsigned long long)number); ++} ++ ++ ++static void ++print_header(unsigned int format, const char *chain, struct iptc_handle *handle) ++{ ++ struct ipt_counters counters; ++ const char *pol = iptc_get_policy(chain, &counters, handle); ++ printf("Chain %s", chain); ++ if (pol) { ++ printf(" (policy %s", pol); ++ if (!(format & FMT_NOCOUNTS)) { ++ fputc(' ', stdout); ++ print_num(counters.pcnt, (format|FMT_NOTABLE)); ++ fputs("packets, ", stdout); ++ print_num(counters.bcnt, (format|FMT_NOTABLE)); ++ fputs("bytes", stdout); ++ } ++ printf(")\n"); ++ } else { ++ unsigned int refs; ++ if (!iptc_get_references(&refs, chain, handle)) ++ printf(" (ERROR obtaining refs)\n"); ++ else ++ printf(" (%u references)\n", refs); ++ } ++ ++ if (format & FMT_LINENUMBERS) ++ printf(FMT("%-4s ", "%s "), "num"); ++ if (!(format & FMT_NOCOUNTS)) { ++ if (format & FMT_KILOMEGAGIGA) { ++ printf(FMT("%5s ","%s "), "pkts"); ++ printf(FMT("%5s ","%s "), "bytes"); ++ } else { ++ printf(FMT("%8s ","%s "), "pkts"); ++ printf(FMT("%10s ","%s "), "bytes"); ++ } ++ } ++ if (!(format & FMT_NOTARGET)) ++ printf(FMT("%-9s ","%s "), "target"); ++ fputs(" prot ", stdout); ++ if (format & FMT_OPTIONS) ++ fputs("opt", stdout); ++ if (format & FMT_VIA) { ++ printf(FMT(" %-6s ","%s "), "in"); ++ printf(FMT("%-6s ","%s "), "out"); ++ } ++ printf(FMT(" %-19s ","%s "), "source"); ++ printf(FMT(" %-19s "," %s "), "destination"); ++ printf("\n"); ++} ++ ++ ++static int ++print_match(const struct ipt_entry_match *m, ++ const struct ipt_ip *ip, ++ int numeric) ++{ ++ const struct xtables_match *match = ++ xtables_find_match(m->u.user.name, XTF_TRY_LOAD, NULL); ++ ++ if (match) { ++ if (match->print) ++ match->print(ip, m, numeric); ++ else ++ printf("%s ", match->name); ++ } else { ++ if (m->u.user.name[0]) ++ printf("UNKNOWN match `%s' ", m->u.user.name); ++ } ++ /* Don't stop iterating. */ ++ return 0; ++} ++ ++/* e is called `fw' here for historical reasons */ ++static void ++print_firewall(const struct ipt_entry *fw, ++ const char *targname, ++ unsigned int num, ++ unsigned int format, ++ struct iptc_handle *const handle) ++{ ++ const struct xtables_target *target = NULL; ++ const struct ipt_entry_target *t; ++ uint8_t flags; ++ char buf[BUFSIZ]; ++ ++ if (!iptc_is_chain(targname, handle)) ++ target = xtables_find_target(targname, XTF_TRY_LOAD); ++ else ++ target = xtables_find_target(IPT_STANDARD_TARGET, ++ XTF_LOAD_MUST_SUCCEED); ++ ++ t = ipt_get_target((struct ipt_entry *)fw); ++ flags = fw->ip.flags; ++ ++ if (format & FMT_LINENUMBERS) ++ printf(FMT("%-4u ", "%u "), num); ++ ++ if (!(format & FMT_NOCOUNTS)) { ++ print_num(fw->counters.pcnt, format); ++ print_num(fw->counters.bcnt, format); ++ } ++ ++ if (!(format & FMT_NOTARGET)) ++ printf(FMT("%-9s ", "%s "), targname); ++ ++ fputc(fw->ip.invflags & IPT_INV_PROTO ? '!' : ' ', stdout); ++ { ++ const char *pname = proto_to_name(fw->ip.proto, format&FMT_NUMERIC); ++ if (pname) ++ printf(FMT("%-5s", "%s "), pname); ++ else ++ printf(FMT("%-5hu", "%hu "), fw->ip.proto); ++ } ++ ++ if (format & FMT_OPTIONS) { ++ if (format & FMT_NOTABLE) ++ fputs("opt ", stdout); ++ fputc(fw->ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout); ++ fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout); ++ fputc(' ', stdout); ++ } ++ ++ if (format & FMT_VIA) { ++ char iface[IFNAMSIZ+2]; ++ ++ if (fw->ip.invflags & IPT_INV_VIA_IN) { ++ iface[0] = '!'; ++ iface[1] = '\0'; ++ } ++ else iface[0] = '\0'; ++ ++ if (fw->ip.iniface[0] != '\0') { ++ strcat(iface, fw->ip.iniface); ++ } ++ else if (format & FMT_NUMERIC) strcat(iface, "*"); ++ else strcat(iface, "any"); ++ printf(FMT(" %-6s ","in %s "), iface); ++ ++ if (fw->ip.invflags & IPT_INV_VIA_OUT) { ++ iface[0] = '!'; ++ iface[1] = '\0'; ++ } ++ else iface[0] = '\0'; ++ ++ if (fw->ip.outiface[0] != '\0') { ++ strcat(iface, fw->ip.outiface); ++ } ++ else if (format & FMT_NUMERIC) strcat(iface, "*"); ++ else strcat(iface, "any"); ++ printf(FMT("%-6s ","out %s "), iface); ++ } ++ ++ fputc(fw->ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout); ++ if (fw->ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC)) ++ printf(FMT("%-19s ","%s "), "anywhere"); ++ else { ++ if (format & FMT_NUMERIC) ++ strcpy(buf, xtables_ipaddr_to_numeric(&fw->ip.src)); ++ else ++ strcpy(buf, xtables_ipaddr_to_anyname(&fw->ip.src)); ++ strcat(buf, xtables_ipmask_to_numeric(&fw->ip.smsk)); ++ printf(FMT("%-19s ","%s "), buf); ++ } ++ ++ fputc(fw->ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout); ++ if (fw->ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC)) ++ printf(FMT("%-19s ","-> %s"), "anywhere"); ++ else { ++ if (format & FMT_NUMERIC) ++ strcpy(buf, xtables_ipaddr_to_numeric(&fw->ip.dst)); ++ else ++ strcpy(buf, xtables_ipaddr_to_anyname(&fw->ip.dst)); ++ strcat(buf, xtables_ipmask_to_numeric(&fw->ip.dmsk)); ++ printf(FMT("%-19s ","-> %s"), buf); ++ } ++ ++ 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) { ++ if (target->print) ++ /* Print the target information. */ ++ target->print(&fw->ip, t, format & FMT_NUMERIC); ++ } else if (t->u.target_size != sizeof(*t)) ++ printf("[%u bytes of unknown target data] ", ++ (unsigned int)(t->u.target_size - sizeof(*t))); ++ ++ if (!(format & FMT_NONEWLINE)) ++ fputc('\n', stdout); ++} ++ ++static void ++print_firewall_line(const struct ipt_entry *fw, ++ struct iptc_handle *const h) ++{ ++ struct ipt_entry_target *t; ++ ++ t = ipt_get_target((struct ipt_entry *)fw); ++ print_firewall(fw, t->u.user.name, 0, FMT_PRINT_RULE, h); ++} ++ ++static int ++append_entry(const ipt_chainlabel chain, ++ struct ipt_entry *fw, ++ unsigned int nsaddrs, ++ const struct in_addr saddrs[], ++ const struct in_addr smasks[], ++ unsigned int ndaddrs, ++ const struct in_addr daddrs[], ++ const struct in_addr dmasks[], ++ int verbose, ++ struct iptc_handle *handle) ++{ ++ unsigned int i, j; ++ int ret = 1; ++ ++ for (i = 0; i < nsaddrs; i++) { ++ fw->ip.src.s_addr = saddrs[i].s_addr; ++ fw->ip.smsk.s_addr = smasks[i].s_addr; ++ for (j = 0; j < ndaddrs; j++) { ++ fw->ip.dst.s_addr = daddrs[j].s_addr; ++ fw->ip.dmsk.s_addr = dmasks[j].s_addr; ++ if (verbose) ++ print_firewall_line(fw, handle); ++ ret &= iptc_append_entry(chain, fw, handle); ++ } ++ } ++ ++ return ret; ++} ++ ++static int ++replace_entry(const ipt_chainlabel chain, ++ struct ipt_entry *fw, ++ unsigned int rulenum, ++ const struct in_addr *saddr, const struct in_addr *smask, ++ const struct in_addr *daddr, const struct in_addr *dmask, ++ int verbose, ++ struct iptc_handle *handle) ++{ ++ fw->ip.src.s_addr = saddr->s_addr; ++ fw->ip.dst.s_addr = daddr->s_addr; ++ fw->ip.smsk.s_addr = smask->s_addr; ++ fw->ip.dmsk.s_addr = dmask->s_addr; ++ ++ if (verbose) ++ print_firewall_line(fw, handle); ++ return iptc_replace_entry(chain, fw, rulenum, handle); ++} ++ ++static int ++insert_entry(const ipt_chainlabel chain, ++ struct ipt_entry *fw, ++ unsigned int rulenum, ++ unsigned int nsaddrs, ++ const struct in_addr saddrs[], ++ const struct in_addr smasks[], ++ unsigned int ndaddrs, ++ const struct in_addr daddrs[], ++ const struct in_addr dmasks[], ++ int verbose, ++ struct iptc_handle *handle) ++{ ++ unsigned int i, j; ++ int ret = 1; ++ ++ for (i = 0; i < nsaddrs; i++) { ++ fw->ip.src.s_addr = saddrs[i].s_addr; ++ fw->ip.smsk.s_addr = smasks[i].s_addr; ++ for (j = 0; j < ndaddrs; j++) { ++ fw->ip.dst.s_addr = daddrs[j].s_addr; ++ fw->ip.dmsk.s_addr = dmasks[j].s_addr; ++ if (verbose) ++ print_firewall_line(fw, handle); ++ ret &= iptc_insert_entry(chain, fw, rulenum, handle); ++ } ++ } ++ ++ return ret; ++} ++ ++static unsigned char * ++make_delete_mask(const struct xtables_rule_match *matches, ++ const struct xtables_target *target) ++{ ++ /* Establish mask for comparison */ ++ unsigned int size; ++ const struct xtables_rule_match *matchp; ++ unsigned char *mask, *mptr; ++ ++ size = sizeof(struct ipt_entry); ++ for (matchp = matches; matchp; matchp = matchp->next) ++ size += XT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size; ++ ++ mask = xtables_calloc(1, size ++ + XT_ALIGN(sizeof(struct ipt_entry_target)) ++ + target->size); ++ ++ memset(mask, 0xFF, sizeof(struct ipt_entry)); ++ mptr = mask + sizeof(struct ipt_entry); ++ ++ for (matchp = matches; matchp; matchp = matchp->next) { ++ memset(mptr, 0xFF, ++ XT_ALIGN(sizeof(struct ipt_entry_match)) ++ + matchp->match->userspacesize); ++ mptr += XT_ALIGN(sizeof(struct ipt_entry_match)) + matchp->match->size; ++ } ++ ++ memset(mptr, 0xFF, ++ XT_ALIGN(sizeof(struct ipt_entry_target)) ++ + target->userspacesize); ++ ++ return mask; ++} ++ ++static int ++delete_entry(const ipt_chainlabel chain, ++ struct ipt_entry *fw, ++ unsigned int nsaddrs, ++ const struct in_addr saddrs[], ++ const struct in_addr smasks[], ++ unsigned int ndaddrs, ++ const struct in_addr daddrs[], ++ const struct in_addr dmasks[], ++ int verbose, ++ struct iptc_handle *handle, ++ struct xtables_rule_match *matches, ++ const struct xtables_target *target) ++{ ++ unsigned int i, j; ++ int ret = 1; ++ unsigned char *mask; ++ ++ mask = make_delete_mask(matches, target); ++ for (i = 0; i < nsaddrs; i++) { ++ fw->ip.src.s_addr = saddrs[i].s_addr; ++ fw->ip.smsk.s_addr = smasks[i].s_addr; ++ for (j = 0; j < ndaddrs; j++) { ++ fw->ip.dst.s_addr = daddrs[j].s_addr; ++ fw->ip.dmsk.s_addr = dmasks[j].s_addr; ++ if (verbose) ++ print_firewall_line(fw, handle); ++ ret &= iptc_delete_entry(chain, fw, mask, handle); ++ } ++ } ++ free(mask); ++ ++ return ret; ++} ++ ++static int ++check_entry(const ipt_chainlabel chain, struct ipt_entry *fw, ++ unsigned int nsaddrs, const struct in_addr *saddrs, ++ const struct in_addr *smasks, unsigned int ndaddrs, ++ const struct in_addr *daddrs, const struct in_addr *dmasks, ++ bool verbose, struct iptc_handle *handle, ++ struct xtables_rule_match *matches, ++ const struct xtables_target *target) ++{ ++ unsigned int i, j; ++ int ret = 1; ++ unsigned char *mask; ++ ++ mask = make_delete_mask(matches, target); ++ for (i = 0; i < nsaddrs; i++) { ++ fw->ip.src.s_addr = saddrs[i].s_addr; ++ fw->ip.smsk.s_addr = smasks[i].s_addr; ++ for (j = 0; j < ndaddrs; j++) { ++ fw->ip.dst.s_addr = daddrs[j].s_addr; ++ fw->ip.dmsk.s_addr = dmasks[j].s_addr; ++ if (verbose) ++ print_firewall_line(fw, handle); ++ ret &= iptc_check_entry(chain, fw, mask, handle); ++ } ++ } ++ ++ free(mask); ++ return ret; ++} ++ ++int ++for_each_chain4(int (*fn)(const ipt_chainlabel, int, struct iptc_handle *), ++ int verbose, int builtinstoo, struct iptc_handle *handle) ++{ ++ int ret = 1; ++ const char *chain; ++ char *chains; ++ unsigned int i, chaincount = 0; ++ ++ chain = iptc_first_chain(handle); ++ while (chain) { ++ chaincount++; ++ chain = iptc_next_chain(handle); ++ } ++ ++ chains = xtables_malloc(sizeof(ipt_chainlabel) * chaincount); ++ i = 0; ++ chain = iptc_first_chain(handle); ++ while (chain) { ++ strcpy(chains + i*sizeof(ipt_chainlabel), chain); ++ i++; ++ chain = iptc_next_chain(handle); ++ } ++ ++ for (i = 0; i < chaincount; i++) { ++ if (!builtinstoo ++ && iptc_builtin(chains + i*sizeof(ipt_chainlabel), ++ handle) == 1) ++ continue; ++ ret &= fn(chains + i*sizeof(ipt_chainlabel), verbose, handle); ++ } ++ ++ free(chains); ++ return ret; ++} ++ ++int ++flush_entries4(const ipt_chainlabel chain, int verbose, ++ struct iptc_handle *handle) ++{ ++ if (!chain) ++ return for_each_chain4(flush_entries4, verbose, 1, handle); ++ ++ if (verbose) ++ fprintf(stdout, "Flushing chain `%s'\n", chain); ++ return iptc_flush_entries(chain, handle); ++} ++ ++static int ++zero_entries(const ipt_chainlabel chain, int verbose, ++ struct iptc_handle *handle) ++{ ++ if (!chain) ++ return for_each_chain4(zero_entries, verbose, 1, handle); ++ ++ if (verbose) ++ fprintf(stdout, "Zeroing chain `%s'\n", chain); ++ return iptc_zero_entries(chain, handle); ++} ++ ++int ++delete_chain4(const ipt_chainlabel chain, int verbose, ++ struct iptc_handle *handle) ++{ ++ if (!chain) ++ return for_each_chain4(delete_chain4, verbose, 0, handle); ++ ++ if (verbose) ++ fprintf(stdout, "Deleting chain `%s'\n", chain); ++ return iptc_delete_chain(chain, handle); ++} ++ ++static int ++list_entries(const ipt_chainlabel chain, int rulenum, int verbose, int numeric, ++ int expanded, int linenumbers, struct iptc_handle *handle) ++{ ++ int found = 0; ++ unsigned int format; ++ const char *this; ++ ++ format = FMT_OPTIONS; ++ if (!verbose) ++ format |= FMT_NOCOUNTS; ++ else ++ format |= FMT_VIA; ++ ++ if (numeric) ++ format |= FMT_NUMERIC; ++ ++ if (!expanded) ++ format |= FMT_KILOMEGAGIGA; ++ ++ if (linenumbers) ++ format |= FMT_LINENUMBERS; ++ ++ for (this = iptc_first_chain(handle); ++ this; ++ this = iptc_next_chain(handle)) { ++ const struct ipt_entry *i; ++ unsigned int num; ++ ++ if (chain && strcmp(chain, this) != 0) ++ continue; ++ ++ if (found) printf("\n"); ++ ++ if (!rulenum) ++ print_header(format, this, handle); ++ i = iptc_first_rule(this, handle); ++ ++ num = 0; ++ while (i) { ++ num++; ++ if (!rulenum || num == rulenum) ++ print_firewall(i, ++ iptc_get_target(i, handle), ++ num, ++ format, ++ handle); ++ i = iptc_next_rule(i, handle); ++ } ++ found = 1; ++ } ++ ++ errno = ENOENT; ++ return found; ++} ++ ++static void print_proto(uint16_t proto, int invert) ++{ ++ if (proto) { ++ unsigned int i; ++ const char *invertstr = invert ? " !" : ""; ++ ++ const struct protoent *pent = getprotobynumber(proto); ++ if (pent) { ++ printf("%s -p %s", invertstr, pent->p_name); ++ return; ++ } ++ ++ for (i = 0; xtables_chain_protos[i].name != NULL; ++i) ++ if (xtables_chain_protos[i].num == proto) { ++ printf("%s -p %s", ++ invertstr, xtables_chain_protos[i].name); ++ return; ++ } ++ ++ printf("%s -p %u", invertstr, proto); ++ } ++} ++ ++#define IP_PARTS_NATIVE(n) \ ++(unsigned int)((n)>>24)&0xFF, \ ++(unsigned int)((n)>>16)&0xFF, \ ++(unsigned int)((n)>>8)&0xFF, \ ++(unsigned int)((n)&0xFF) ++ ++#define IP_PARTS(n) IP_PARTS_NATIVE(ntohl(n)) ++ ++/* This assumes that mask is contiguous, and byte-bounded. */ ++static void ++print_iface(char letter, const char *iface, const unsigned char *mask, ++ int invert) ++{ ++ unsigned int i; ++ ++ if (mask[0] == 0) ++ return; ++ ++ printf("%s -%c ", invert ? " !" : "", letter); ++ ++ for (i = 0; i < IFNAMSIZ; i++) { ++ if (mask[i] != 0) { ++ if (iface[i] != '\0') ++ printf("%c", iface[i]); ++ } else { ++ /* we can access iface[i-1] here, because ++ * a few lines above we make sure that mask[0] != 0 */ ++ if (iface[i-1] != '\0') ++ printf("+"); ++ break; ++ } ++ } ++} ++ ++static int print_match_save(const struct ipt_entry_match *e, ++ const struct ipt_ip *ip) ++{ ++ const struct xtables_match *match = ++ xtables_find_match(e->u.user.name, XTF_TRY_LOAD, NULL); ++ ++ if (match) { ++ printf(" -m %s", e->u.user.name); ++ ++ /* some matches don't provide a save function */ ++ if (match->save) ++ match->save(ip, e); ++ } else { ++ if (e->u.match_size) { ++ fprintf(stderr, ++ "Can't find library for match `%s'\n", ++ e->u.user.name); ++ exit(1); ++ } ++ } ++ return 0; ++} ++ ++/* print a given ip including mask if neccessary */ ++static void print_ip(const char *prefix, uint32_t ip, ++ uint32_t mask, int invert) ++{ ++ uint32_t bits, hmask = ntohl(mask); ++ int i; ++ ++ if (!mask && !ip && !invert) ++ return; ++ ++ printf("%s %s %u.%u.%u.%u", ++ invert ? " !" : "", ++ prefix, ++ IP_PARTS(ip)); ++ ++ if (mask == 0xFFFFFFFFU) { ++ printf("/32"); ++ return; ++ } ++ ++ i = 32; ++ bits = 0xFFFFFFFEU; ++ while (--i >= 0 && hmask != bits) ++ bits <<= 1; ++ if (i >= 0) ++ printf("/%u", i); ++ else ++ printf("/%u.%u.%u.%u", IP_PARTS(mask)); ++} ++ ++/* We want this to be readable, so only print out neccessary fields. ++ * Because that's the kind of world I want to live in. */ ++void print_rule4(const struct ipt_entry *e, ++ struct iptc_handle *h, const char *chain, int counters) ++{ ++ const struct ipt_entry_target *t; ++ const char *target_name; ++ ++ /* print counters for iptables-save */ ++ if (counters > 0) ++ printf("[%llu:%llu] ", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); ++ ++ /* print chain name */ ++ printf("-A %s", chain); ++ ++ /* Print IP part. */ ++ print_ip("-s", e->ip.src.s_addr,e->ip.smsk.s_addr, ++ e->ip.invflags & IPT_INV_SRCIP); ++ ++ print_ip("-d", e->ip.dst.s_addr, e->ip.dmsk.s_addr, ++ e->ip.invflags & IPT_INV_DSTIP); ++ ++ print_iface('i', e->ip.iniface, e->ip.iniface_mask, ++ e->ip.invflags & IPT_INV_VIA_IN); ++ ++ print_iface('o', e->ip.outiface, e->ip.outiface_mask, ++ e->ip.invflags & IPT_INV_VIA_OUT); ++ ++ print_proto(e->ip.proto, e->ip.invflags & IPT_INV_PROTO); ++ ++ if (e->ip.flags & IPT_F_FRAG) ++ printf("%s -f", ++ e->ip.invflags & IPT_INV_FRAG ? " !" : ""); ++ ++ /* Print matchinfo part */ ++ if (e->target_offset) { ++ IPT_MATCH_ITERATE(e, print_match_save, &e->ip); ++ } ++ ++ /* print counters for iptables -R */ ++ if (counters < 0) ++ printf(" -c %llu %llu", (unsigned long long)e->counters.pcnt, (unsigned long long)e->counters.bcnt); ++ ++ /* 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); ++ if (t->u.user.name[0]) { ++ const struct xtables_target *target = ++ xtables_find_target(t->u.user.name, XTF_TRY_LOAD); ++ ++ if (!target) { ++ fprintf(stderr, "Can't find library for target `%s'\n", ++ t->u.user.name); ++ exit(1); ++ } ++ ++ if (target->save) ++ target->save(&e->ip, t); ++ else { ++ /* If the target size is greater than ipt_entry_target ++ * there is something to be saved, we just don't know ++ * how to print it */ ++ if (t->u.target_size != ++ sizeof(struct ipt_entry_target)) { ++ fprintf(stderr, "Target `%s' is missing " ++ "save function\n", ++ t->u.user.name); ++ exit(1); ++ } ++ } ++ } ++ printf("\n"); ++} ++ ++static int ++list_rules(const ipt_chainlabel chain, int rulenum, int counters, ++ struct iptc_handle *handle) ++{ ++ const char *this = NULL; ++ int found = 0; ++ ++ if (counters) ++ counters = -1; /* iptables -c format */ ++ ++ /* Dump out chain names first, ++ * thereby preventing dependency conflicts */ ++ if (!rulenum) for (this = iptc_first_chain(handle); ++ this; ++ this = iptc_next_chain(handle)) { ++ if (chain && strcmp(this, chain) != 0) ++ continue; ++ ++ if (iptc_builtin(this, handle)) { ++ struct ipt_counters count; ++ printf("-P %s %s", this, iptc_get_policy(this, &count, handle)); ++ if (counters) ++ printf(" -c %llu %llu", (unsigned long long)count.pcnt, (unsigned long long)count.bcnt); ++ printf("\n"); ++ } else { ++ printf("-N %s\n", this); ++ } ++ } ++ ++ for (this = iptc_first_chain(handle); ++ this; ++ this = iptc_next_chain(handle)) { ++ const struct ipt_entry *e; ++ int num = 0; ++ ++ if (chain && strcmp(this, chain) != 0) ++ continue; ++ ++ /* Dump out rules */ ++ e = iptc_first_rule(this, handle); ++ while(e) { ++ num++; ++ if (!rulenum || num == rulenum) ++ print_rule4(e, handle, this, counters); ++ e = iptc_next_rule(e, handle); ++ } ++ found = 1; ++ } ++ ++ errno = ENOENT; ++ return found; ++} ++ ++static struct ipt_entry * ++generate_entry(const struct ipt_entry *fw, ++ struct xtables_rule_match *matches, ++ struct ipt_entry_target *target) ++{ ++ unsigned int size; ++ struct xtables_rule_match *matchp; ++ struct ipt_entry *e; ++ ++ size = sizeof(struct ipt_entry); ++ for (matchp = matches; matchp; matchp = matchp->next) ++ size += matchp->match->m->u.match_size; ++ ++ e = xtables_malloc(size + target->u.target_size); ++ *e = *fw; ++ e->target_offset = size; ++ e->next_offset = size + target->u.target_size; ++ ++ size = 0; ++ for (matchp = matches; matchp; matchp = matchp->next) { ++ memcpy(e->elems + size, matchp->match->m, matchp->match->m->u.match_size); ++ size += matchp->match->m->u.match_size; ++ } ++ memcpy(e->elems + size, target, target->u.target_size); ++ ++ return e; ++} ++ ++static void clear_rule_matches(struct xtables_rule_match **matches) ++{ ++ struct xtables_rule_match *matchp, *tmp; ++ ++ for (matchp = *matches; matchp;) { ++ tmp = matchp->next; ++ if (matchp->match->m) { ++ free(matchp->match->m); ++ matchp->match->m = NULL; ++ } ++ if (matchp->match == matchp->match->next) { ++ free(matchp->match); ++ matchp->match = NULL; ++ } ++ free(matchp); ++ matchp = tmp; ++ } ++ ++ *matches = NULL; ++} ++ ++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"); ++ xtables_free_opts(1); ++ exit(1); ++ } ++ ++ sscanf(uts.release, "%d.%d.%d", &x, &y, &z); ++ kernel_version = LINUX_VERSION(x, y, z); ++} ++ ++static void command_jump(struct iptables_command_state *cs) ++{ ++ size_t size; ++ ++ set_option(&cs->options, OPT_JUMP, &cs->fw.ip.invflags, cs->invert); ++ cs->jumpto = parse_target(optarg); ++ /* TRY_LOAD (may be chain name) */ ++ cs->target = xtables_find_target(cs->jumpto, XTF_TRY_LOAD); ++ ++ if (cs->target == NULL) ++ return; ++ ++ size = XT_ALIGN(sizeof(struct ipt_entry_target)) ++ + cs->target->size; ++ ++ cs->target->t = xtables_calloc(1, size); ++ cs->target->t->u.target_size = size; ++ strcpy(cs->target->t->u.user.name, cs->jumpto); ++ cs->target->t->u.user.revision = cs->target->revision; ++ xs_init_target(cs->target); ++ ++ if (cs->target->x6_options != NULL) ++ opts = xtables_options_xfrm(iptables_globals.orig_opts, opts, ++ cs->target->x6_options, ++ &cs->target->option_offset); ++ else ++ opts = xtables_merge_options(iptables_globals.orig_opts, opts, ++ cs->target->extra_opts, ++ &cs->target->option_offset); ++ if (opts == NULL) ++ xtables_error(OTHER_PROBLEM, "can't alloc memory!"); ++} ++ ++static void command_match(struct iptables_command_state *cs) ++{ ++ struct xtables_match *m; ++ size_t size; ++ ++ if (cs->invert) ++ xtables_error(PARAMETER_PROBLEM, ++ "unexpected ! flag before --match"); ++ ++ m = xtables_find_match(optarg, XTF_LOAD_MUST_SUCCEED, &cs->matches); ++ size = XT_ALIGN(sizeof(struct ipt_entry_match)) + m->size; ++ m->m = xtables_calloc(1, size); ++ m->m->u.match_size = size; ++ strcpy(m->m->u.user.name, m->name); ++ m->m->u.user.revision = m->revision; ++ xs_init_match(m); ++ if (m == m->next) ++ return; ++ /* Merge options for non-cloned matches */ ++ if (m->x6_options != NULL) ++ opts = xtables_options_xfrm(iptables_globals.orig_opts, opts, ++ m->x6_options, &m->option_offset); ++ else if (m->extra_opts != NULL) ++ opts = xtables_merge_options(iptables_globals.orig_opts, opts, ++ m->extra_opts, &m->option_offset); ++ if (opts == NULL) ++ xtables_error(OTHER_PROBLEM, "can't alloc memory!"); ++} ++ ++int do_command4(int argc, char *argv[], char **table, struct iptc_handle **handle) ++{ ++ struct iptables_command_state cs; ++ struct ipt_entry *e = NULL; ++ unsigned int nsaddrs = 0, ndaddrs = 0; ++ struct in_addr *saddrs = NULL, *smasks = NULL; ++ struct in_addr *daddrs = NULL, *dmasks = NULL; ++ ++ int verbose = 0; ++ const char *chain = NULL; ++ const char *shostnetworkmask = NULL, *dhostnetworkmask = NULL; ++ const char *policy = NULL, *newname = NULL; ++ unsigned int rulenum = 0, command = 0; ++ const char *pcnt = NULL, *bcnt = NULL; ++ int ret = 1; ++ struct xtables_match *m; ++ struct xtables_rule_match *matchp; ++ struct xtables_target *t; ++ unsigned long long cnt; ++ ++ memset(&cs, 0, sizeof(cs)); ++ cs.jumpto = ""; ++ cs.argv = argv; ++ ++ /* re-set optind to 0 in case do_command4 gets called ++ * a second time */ ++ optind = 0; ++ ++ /* clear mflags in case do_command4 gets called a second time ++ * (we clear the global list of all matches for security)*/ ++ for (m = xtables_matches; m; m = m->next) ++ m->mflags = 0; ++ ++ for (t = xtables_targets; t; t = t->next) { ++ t->tflags = 0; ++ t->used = 0; ++ } ++ ++ /* Suppress error messages: we may add new options if we ++ demand-load a protocol. */ ++ opterr = 0; ++ ++ opts = xt_params->orig_opts; ++ while ((cs.c = getopt_long(argc, argv, ++ "-:A:C:D:R:I:L::S::M:F::Z::N:X::E:P:Vh::o:p:s:d:j:i:fbvnt:m:xc:g:46", ++ opts, NULL)) != -1) { ++ switch (cs.c) { ++ /* ++ * Command selection ++ */ ++ case 'A': ++ add_command(&command, CMD_APPEND, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ break; ++ ++ case 'C': ++ add_command(&command, CMD_CHECK, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ break; ++ ++ case 'D': ++ add_command(&command, CMD_DELETE, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') { ++ rulenum = parse_rulenumber(argv[optind++]); ++ command = CMD_DELETE_NUM; ++ } ++ break; ++ ++ case 'R': ++ add_command(&command, CMD_REPLACE, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ rulenum = parse_rulenumber(argv[optind++]); ++ else ++ xtables_error(PARAMETER_PROBLEM, ++ "-%c requires a rule number", ++ cmd2char(CMD_REPLACE)); ++ break; ++ ++ case 'I': ++ add_command(&command, CMD_INSERT, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ rulenum = parse_rulenumber(argv[optind++]); ++ else rulenum = 1; ++ break; ++ ++ case 'L': ++ add_command(&command, CMD_LIST, ++ CMD_ZERO | CMD_ZERO_NUM, cs.invert); ++ if (optarg) chain = optarg; ++ else if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ chain = argv[optind++]; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ rulenum = parse_rulenumber(argv[optind++]); ++ break; ++ ++ case 'S': ++ add_command(&command, CMD_LIST_RULES, ++ CMD_ZERO|CMD_ZERO_NUM, cs.invert); ++ if (optarg) chain = optarg; ++ else if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ chain = argv[optind++]; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ rulenum = parse_rulenumber(argv[optind++]); ++ break; ++ ++ case 'F': ++ add_command(&command, CMD_FLUSH, CMD_NONE, ++ cs.invert); ++ if (optarg) chain = optarg; ++ else if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ chain = argv[optind++]; ++ break; ++ ++ case 'Z': ++ add_command(&command, CMD_ZERO, CMD_LIST|CMD_LIST_RULES, ++ cs.invert); ++ if (optarg) chain = optarg; ++ else if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ chain = argv[optind++]; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') { ++ rulenum = parse_rulenumber(argv[optind++]); ++ command = CMD_ZERO_NUM; ++ } ++ break; ++ ++ case 'N': ++ if (optarg && (*optarg == '-' || *optarg == '!')) ++ xtables_error(PARAMETER_PROBLEM, ++ "chain name not allowed to start " ++ "with `%c'\n", *optarg); ++ if (xtables_find_target(optarg, XTF_TRY_LOAD)) ++ xtables_error(PARAMETER_PROBLEM, ++ "chain name may not clash " ++ "with target name\n"); ++ add_command(&command, CMD_NEW_CHAIN, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ break; ++ ++ case 'X': ++ add_command(&command, CMD_DELETE_CHAIN, CMD_NONE, ++ cs.invert); ++ if (optarg) chain = optarg; ++ else if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ chain = argv[optind++]; ++ break; ++ ++ case 'E': ++ add_command(&command, CMD_RENAME_CHAIN, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ newname = argv[optind++]; ++ else ++ xtables_error(PARAMETER_PROBLEM, ++ "-%c requires old-chain-name and " ++ "new-chain-name", ++ cmd2char(CMD_RENAME_CHAIN)); ++ break; ++ ++ case 'P': ++ add_command(&command, CMD_SET_POLICY, CMD_NONE, ++ cs.invert); ++ chain = optarg; ++ if (optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ policy = argv[optind++]; ++ else ++ xtables_error(PARAMETER_PROBLEM, ++ "-%c requires a chain and a policy", ++ cmd2char(CMD_SET_POLICY)); ++ break; ++ ++ case 'h': ++ if (!optarg) ++ optarg = argv[optind]; ++ ++ /* iptables -p icmp -h */ ++ if (!cs.matches && cs.protocol) ++ xtables_find_match(cs.protocol, ++ XTF_TRY_LOAD, &cs.matches); ++ ++ exit_printhelp(cs.matches); ++ ++ /* ++ * Option selection ++ */ ++ case 'p': ++ set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags, ++ cs.invert); ++ ++ /* Canonicalize into lower case */ ++ for (cs.protocol = optarg; *cs.protocol; cs.protocol++) ++ *cs.protocol = tolower(*cs.protocol); ++ ++ cs.protocol = optarg; ++ cs.fw.ip.proto = xtables_parse_protocol(cs.protocol); ++ ++ if (cs.fw.ip.proto == 0 ++ && (cs.fw.ip.invflags & IPT_INV_PROTO)) ++ xtables_error(PARAMETER_PROBLEM, ++ "rule would never match protocol"); ++ break; ++ ++ case 's': ++ set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags, ++ cs.invert); ++ shostnetworkmask = optarg; ++ break; ++ ++ case 'd': ++ set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags, ++ cs.invert); ++ dhostnetworkmask = optarg; ++ break; ++ ++#ifdef IPT_F_GOTO ++ case 'g': ++ set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags, ++ cs.invert); ++ cs.fw.ip.flags |= IPT_F_GOTO; ++ cs.jumpto = parse_target(optarg); ++ break; ++#endif ++ ++ case 'j': ++ command_jump(&cs); ++ break; ++ ++ ++ case 'i': ++ if (*optarg == '\0') ++ xtables_error(PARAMETER_PROBLEM, ++ "Empty interface is likely to be " ++ "undesired"); ++ set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags, ++ cs.invert); ++ xtables_parse_interface(optarg, ++ cs.fw.ip.iniface, ++ cs.fw.ip.iniface_mask); ++ break; ++ ++ case 'o': ++ if (*optarg == '\0') ++ xtables_error(PARAMETER_PROBLEM, ++ "Empty interface is likely to be " ++ "undesired"); ++ set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags, ++ cs.invert); ++ xtables_parse_interface(optarg, ++ cs.fw.ip.outiface, ++ cs.fw.ip.outiface_mask); ++ break; ++ ++ case 'f': ++ set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags, ++ cs.invert); ++ cs.fw.ip.flags |= IPT_F_FRAG; ++ break; ++ ++ case 'v': ++ if (!verbose) ++ set_option(&cs.options, OPT_VERBOSE, ++ &cs.fw.ip.invflags, cs.invert); ++ verbose++; ++ break; ++ ++ case 'm': ++ command_match(&cs); ++ break; ++ ++ case 'n': ++ set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags, ++ cs.invert); ++ break; ++ ++ case 't': ++ if (cs.invert) ++ xtables_error(PARAMETER_PROBLEM, ++ "unexpected ! flag before --table"); ++ *table = optarg; ++ break; ++ ++ case 'x': ++ set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags, ++ cs.invert); ++ break; ++ ++ case 'V': ++ if (cs.invert) ++ printf("Not %s ;-)\n", prog_vers); ++ else ++ printf("%s v%s\n", ++ prog_name, prog_vers); ++ exit(0); ++ ++ case '0': ++ set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags, ++ cs.invert); ++ break; ++ ++ case 'M': ++ xtables_modprobe_program = optarg; ++ break; ++ ++ case 'c': ++ ++ set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags, ++ cs.invert); ++ pcnt = optarg; ++ bcnt = strchr(pcnt + 1, ','); ++ if (bcnt) ++ bcnt++; ++ if (!bcnt && optind < argc && argv[optind][0] != '-' ++ && argv[optind][0] != '!') ++ bcnt = argv[optind++]; ++ if (!bcnt) ++ xtables_error(PARAMETER_PROBLEM, ++ "-%c requires packet and byte counter", ++ opt2char(OPT_COUNTERS)); ++ ++ if (sscanf(pcnt, "%llu", &cnt) != 1) ++ xtables_error(PARAMETER_PROBLEM, ++ "-%c packet counter not numeric", ++ opt2char(OPT_COUNTERS)); ++ cs.fw.counters.pcnt = cnt; ++ ++ if (sscanf(bcnt, "%llu", &cnt) != 1) ++ xtables_error(PARAMETER_PROBLEM, ++ "-%c byte counter not numeric", ++ opt2char(OPT_COUNTERS)); ++ cs.fw.counters.bcnt = cnt; ++ break; ++ ++ case '4': ++ /* This is indeed the IPv4 iptables */ ++ break; ++ ++ case '6': ++ /* This is not the IPv6 ip6tables */ ++ if (line != -1) ++ return 1; /* success: line ignored */ ++ fprintf(stderr, "This is the IPv4 version of iptables.\n"); ++ exit_tryhelp(2); ++ ++ case 1: /* non option */ ++ if (optarg[0] == '!' && optarg[1] == '\0') { ++ if (cs.invert) ++ xtables_error(PARAMETER_PROBLEM, ++ "multiple consecutive ! not" ++ " allowed"); ++ cs.invert = TRUE; ++ optarg[0] = '\0'; ++ continue; ++ } ++ fprintf(stderr, "Bad argument `%s'\n", optarg); ++ exit_tryhelp(2); ++ ++ default: ++ if (command_default(&cs, &iptables_globals) == 1) ++ /* cf. ip6tables.c */ ++ continue; ++ break; ++ } ++ cs.invert = FALSE; ++ } ++ ++ if (strcmp(*table, "nat") == 0 && ++ ((policy != NULL && strcmp(policy, "DROP") == 0) || ++ (cs.jumpto != NULL && strcmp(cs.jumpto, "DROP") == 0))) ++ xtables_error(PARAMETER_PROBLEM, ++ "\nThe \"nat\" table is not intended for filtering, " ++ "the use of DROP is therefore inhibited.\n\n"); ++ ++ for (matchp = cs.matches; matchp; matchp = matchp->next) ++ xtables_option_mfcall(matchp->match); ++ if (cs.target != NULL) ++ xtables_option_tfcall(cs.target); ++ ++ /* Fix me: must put inverse options checking here --MN */ ++ ++ if (optind < argc) ++ xtables_error(PARAMETER_PROBLEM, ++ "unknown arguments found on commandline"); ++ if (!command) ++ xtables_error(PARAMETER_PROBLEM, "no command specified"); ++ if (cs.invert) ++ xtables_error(PARAMETER_PROBLEM, ++ "nothing appropriate following !"); ++ ++ if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) { ++ if (!(cs.options & OPT_DESTINATION)) ++ dhostnetworkmask = "0.0.0.0/0"; ++ if (!(cs.options & OPT_SOURCE)) ++ shostnetworkmask = "0.0.0.0/0"; ++ } ++ ++ if (shostnetworkmask) ++ xtables_ipparse_multiple(shostnetworkmask, &saddrs, ++ &smasks, &nsaddrs); ++ ++ if (dhostnetworkmask) ++ xtables_ipparse_multiple(dhostnetworkmask, &daddrs, ++ &dmasks, &ndaddrs); ++ ++ if ((nsaddrs > 1 || ndaddrs > 1) && ++ (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP))) ++ xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple" ++ " source or destination IP addresses"); ++ ++ if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1)) ++ xtables_error(PARAMETER_PROBLEM, "Replacement rule does not " ++ "specify a unique address"); ++ ++ generic_opt_check(command, cs.options); ++ ++ if (chain != NULL && strlen(chain) >= XT_EXTENSION_MAXNAMELEN) ++ xtables_error(PARAMETER_PROBLEM, ++ "chain name `%s' too long (must be under %u chars)", ++ chain, XT_EXTENSION_MAXNAMELEN); ++ ++ /* only allocate handle if we weren't called with a handle */ ++ if (!*handle) ++ *handle = iptc_init(*table); ++ ++ /* try to insmod the module if iptc_init failed */ ++ if (!*handle && xtables_load_ko(xtables_modprobe_program, false) != -1) ++ *handle = iptc_init(*table); ++ ++ if (!*handle) ++ xtables_error(VERSION_PROBLEM, ++ "can't initialize iptables table `%s': %s", ++ *table, iptc_strerror(errno)); ++ ++ if (command == CMD_APPEND ++ || command == CMD_DELETE ++ || command == CMD_CHECK ++ || command == CMD_INSERT ++ || command == CMD_REPLACE) { ++ if (strcmp(chain, "PREROUTING") == 0 ++ || strcmp(chain, "INPUT") == 0) { ++ /* -o not valid with incoming packets. */ ++ if (cs.options & OPT_VIANAMEOUT) ++ xtables_error(PARAMETER_PROBLEM, ++ "Can't use -%c with %s\n", ++ opt2char(OPT_VIANAMEOUT), ++ chain); ++ } ++ ++ if (strcmp(chain, "POSTROUTING") == 0 ++ || strcmp(chain, "OUTPUT") == 0) { ++ /* -i not valid with outgoing packets */ ++ if (cs.options & OPT_VIANAMEIN) ++ xtables_error(PARAMETER_PROBLEM, ++ "Can't use -%c with %s\n", ++ opt2char(OPT_VIANAMEIN), ++ chain); ++ } ++ ++ if (cs.target && iptc_is_chain(cs.jumpto, *handle)) { ++ fprintf(stderr, ++ "Warning: using chain %s, not extension\n", ++ cs.jumpto); ++ ++ if (cs.target->t) ++ free(cs.target->t); ++ ++ cs.target = NULL; ++ } ++ ++ /* If they didn't specify a target, or it's a chain ++ name, use standard. */ ++ if (!cs.target ++ && (strlen(cs.jumpto) == 0 ++ || iptc_is_chain(cs.jumpto, *handle))) { ++ size_t size; ++ ++ cs.target = xtables_find_target(IPT_STANDARD_TARGET, ++ XTF_LOAD_MUST_SUCCEED); ++ ++ size = sizeof(struct ipt_entry_target) ++ + cs.target->size; ++ cs.target->t = xtables_calloc(1, size); ++ cs.target->t->u.target_size = size; ++ strcpy(cs.target->t->u.user.name, cs.jumpto); ++ if (!iptc_is_chain(cs.jumpto, *handle)) ++ cs.target->t->u.user.revision = cs.target->revision; ++ xs_init_target(cs.target); ++ } ++ ++ if (!cs.target) { ++ /* it is no chain, and we can't load a plugin. ++ * We cannot know if the plugin is corrupt, non ++ * existant OR if the user just misspelled a ++ * chain. */ ++#ifdef IPT_F_GOTO ++ if (cs.fw.ip.flags & IPT_F_GOTO) ++ xtables_error(PARAMETER_PROBLEM, ++ "goto '%s' is not a chain\n", ++ cs.jumpto); ++#endif ++ xtables_find_target(cs.jumpto, XTF_LOAD_MUST_SUCCEED); ++ } else { ++ e = generate_entry(&cs.fw, cs.matches, cs.target->t); ++ free(cs.target->t); ++ } ++ } ++ ++ switch (command) { ++ case CMD_APPEND: ++ ret = append_entry(chain, e, ++ nsaddrs, saddrs, smasks, ++ ndaddrs, daddrs, dmasks, ++ cs.options&OPT_VERBOSE, ++ *handle); ++ break; ++ case CMD_DELETE: ++ ret = delete_entry(chain, e, ++ nsaddrs, saddrs, smasks, ++ ndaddrs, daddrs, dmasks, ++ cs.options&OPT_VERBOSE, ++ *handle, cs.matches, cs.target); ++ break; ++ case CMD_DELETE_NUM: ++ ret = iptc_delete_num_entry(chain, rulenum - 1, *handle); ++ break; ++ case CMD_CHECK: ++ ret = check_entry(chain, e, ++ nsaddrs, saddrs, smasks, ++ ndaddrs, daddrs, dmasks, ++ cs.options&OPT_VERBOSE, ++ *handle, cs.matches, cs.target); ++ break; ++ case CMD_REPLACE: ++ ret = replace_entry(chain, e, rulenum - 1, ++ saddrs, smasks, daddrs, dmasks, ++ cs.options&OPT_VERBOSE, *handle); ++ break; ++ case CMD_INSERT: ++ ret = insert_entry(chain, e, rulenum - 1, ++ nsaddrs, saddrs, smasks, ++ ndaddrs, daddrs, dmasks, ++ cs.options&OPT_VERBOSE, ++ *handle); ++ break; ++ case CMD_FLUSH: ++ ret = flush_entries4(chain, cs.options&OPT_VERBOSE, *handle); ++ break; ++ case CMD_ZERO: ++ ret = zero_entries(chain, cs.options&OPT_VERBOSE, *handle); ++ break; ++ case CMD_ZERO_NUM: ++ ret = iptc_zero_counter(chain, rulenum, *handle); ++ break; ++ case CMD_LIST: ++ case CMD_LIST|CMD_ZERO: ++ case CMD_LIST|CMD_ZERO_NUM: ++ ret = list_entries(chain, ++ rulenum, ++ cs.options&OPT_VERBOSE, ++ cs.options&OPT_NUMERIC, ++ cs.options&OPT_EXPANDED, ++ cs.options&OPT_LINENUMBERS, ++ *handle); ++ if (ret && (command & CMD_ZERO)) ++ ret = zero_entries(chain, ++ cs.options&OPT_VERBOSE, *handle); ++ if (ret && (command & CMD_ZERO_NUM)) ++ ret = iptc_zero_counter(chain, rulenum, *handle); ++ break; ++ case CMD_LIST_RULES: ++ case CMD_LIST_RULES|CMD_ZERO: ++ case CMD_LIST_RULES|CMD_ZERO_NUM: ++ ret = list_rules(chain, ++ rulenum, ++ cs.options&OPT_VERBOSE, ++ *handle); ++ if (ret && (command & CMD_ZERO)) ++ ret = zero_entries(chain, ++ cs.options&OPT_VERBOSE, *handle); ++ if (ret && (command & CMD_ZERO_NUM)) ++ ret = iptc_zero_counter(chain, rulenum, *handle); ++ break; ++ case CMD_NEW_CHAIN: ++ ret = iptc_create_chain(chain, *handle); ++ break; ++ case CMD_DELETE_CHAIN: ++ ret = delete_chain4(chain, cs.options&OPT_VERBOSE, *handle); ++ break; ++ case CMD_RENAME_CHAIN: ++ ret = iptc_rename_chain(chain, newname, *handle); ++ break; ++ case CMD_SET_POLICY: ++ ret = iptc_set_policy(chain, policy, cs.options&OPT_COUNTERS ? &cs.fw.counters : NULL, *handle); ++ break; ++ default: ++ /* We should never reach this... */ ++ exit_tryhelp(2); ++ } ++ ++ if (verbose > 1) ++ dump_entries(*handle); ++ ++ clear_rule_matches(&cs.matches); ++ ++ if (e != NULL) { ++ free(e); ++ e = NULL; ++ } ++ ++ free(saddrs); ++ free(smasks); ++ free(daddrs); ++ free(dmasks); ++ xtables_free_opts(1); ++ ++ return ret; ++} +diff --git a/iptables/xshared.c b/iptables/xshared.c +index 21b5b2c..197016d 100644 +--- a/iptables/xshared.c ++++ b/iptables/xshared.c +@@ -1,31 +1,12 @@ +-#include + #include +-#include "xshared.h" + +-/* +- * Print out any special helps. A user might like to be able to add a --help +- * to the commandline, and see expected results. So we call help for all +- * specified matches and targets. +- */ +-void print_extension_helps(const struct xtables_target *t, +- const struct xtables_rule_match *m) +-{ +- for (; t != NULL; t = t->next) { +- if (t->used) { +- printf("\n"); +- if (t->help == NULL) +- printf("%s does not take any options\n", +- t->name); +- else +- t->help(); +- } +- } +- for (; m != NULL; m = m->next) { +- printf("\n"); +- if (m->match->help == NULL) +- printf("%s does not take any options\n", +- m->match->name); +- else +- m->match->help(); +- } +-} ++#if XTABLES_VERSION_CODE < 7 ++#include "xshared.c-old" ++ ++#elif XTABLES_VERSION_CODE == 7 ++#include "xshared.c-v1.4.12" ++ ++#else ++#error "The libxtables is newer than this package support and know of - Sorry!" ++#error " Please inform the package author of this issue, thanks! " ++#endif +diff --git a/iptables/xshared.c-old b/iptables/xshared.c-old +new file mode 100644 +index 0000000..21b5b2c +--- /dev/null ++++ b/iptables/xshared.c-old +@@ -0,0 +1,31 @@ ++#include ++#include ++#include "xshared.h" ++ ++/* ++ * Print out any special helps. A user might like to be able to add a --help ++ * to the commandline, and see expected results. So we call help for all ++ * specified matches and targets. ++ */ ++void print_extension_helps(const struct xtables_target *t, ++ const struct xtables_rule_match *m) ++{ ++ for (; t != NULL; t = t->next) { ++ if (t->used) { ++ printf("\n"); ++ if (t->help == NULL) ++ printf("%s does not take any options\n", ++ t->name); ++ else ++ t->help(); ++ } ++ } ++ for (; m != NULL; m = m->next) { ++ printf("\n"); ++ if (m->match->help == NULL) ++ printf("%s does not take any options\n", ++ m->match->name); ++ else ++ m->match->help(); ++ } ++} +diff --git a/iptables/xshared.c-v1.4.12 b/iptables/xshared.c-v1.4.12 +new file mode 100644 +index 0000000..79da507 +--- /dev/null ++++ b/iptables/xshared.c-v1.4.12 +@@ -0,0 +1,238 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "xshared.h" ++ ++/* ++ * Print out any special helps. A user might like to be able to add a --help ++ * to the commandline, and see expected results. So we call help for all ++ * specified matches and targets. ++ */ ++void print_extension_helps(const struct xtables_target *t, ++ const struct xtables_rule_match *m) ++{ ++ for (; t != NULL; t = t->next) { ++ if (t->used) { ++ printf("\n"); ++ if (t->help == NULL) ++ printf("%s does not take any options\n", ++ t->name); ++ else ++ t->help(); ++ } ++ } ++ for (; m != NULL; m = m->next) { ++ printf("\n"); ++ if (m->match->help == NULL) ++ printf("%s does not take any options\n", ++ m->match->name); ++ else ++ m->match->help(); ++ } ++} ++ ++const char * ++proto_to_name(uint8_t proto, int nolookup) ++{ ++ unsigned int i; ++ ++ if (proto && !nolookup) { ++ struct protoent *pent = getprotobynumber(proto); ++ if (pent) ++ return pent->p_name; ++ } ++ ++ for (i = 0; xtables_chain_protos[i].name != NULL; ++i) ++ if (xtables_chain_protos[i].num == proto) ++ return xtables_chain_protos[i].name; ++ ++ return NULL; ++} ++ ++static struct xtables_match * ++find_proto(const char *pname, enum xtables_tryload tryload, ++ int nolookup, struct xtables_rule_match **matches) ++{ ++ unsigned int proto; ++ ++ if (xtables_strtoui(pname, NULL, &proto, 0, UINT8_MAX)) { ++ const char *protoname = proto_to_name(proto, nolookup); ++ ++ if (protoname) ++ return xtables_find_match(protoname, tryload, matches); ++ } else ++ return xtables_find_match(pname, tryload, matches); ++ ++ return NULL; ++} ++ ++/* ++ * Some explanations (after four different bugs in 3 different releases): If ++ * we encounter a parameter, that has not been parsed yet, it's not an option ++ * of an explicitly loaded match or a target. However, we support implicit ++ * loading of the protocol match extension. '-p tcp' means 'l4 proto 6' and at ++ * the same time 'load tcp protocol match on demand if we specify --dport'. ++ * ++ * To make this work, we need to make sure: ++ * - the parameter has not been parsed by a match (m above) ++ * - a protocol has been specified ++ * - the protocol extension has not been loaded yet, or is loaded and unused ++ * [think of ip6tables-restore!] ++ * - the protocol extension can be successively loaded ++ */ ++static bool should_load_proto(struct iptables_command_state *cs) ++{ ++ if (cs->protocol == NULL) ++ return false; ++ if (find_proto(cs->protocol, XTF_DONT_LOAD, ++ cs->options & OPT_NUMERIC, NULL) == NULL) ++ return true; ++ return !cs->proto_used; ++} ++ ++struct xtables_match *load_proto(struct iptables_command_state *cs) ++{ ++ if (!should_load_proto(cs)) ++ return NULL; ++ return find_proto(cs->protocol, XTF_TRY_LOAD, ++ cs->options & OPT_NUMERIC, &cs->matches); ++} ++ ++int command_default(struct iptables_command_state *cs, ++ struct xtables_globals *gl) ++{ ++ struct xtables_rule_match *matchp; ++ struct xtables_match *m; ++ ++ if (cs->target != NULL && ++ (cs->target->parse != NULL || cs->target->x6_parse != NULL) && ++ cs->c >= cs->target->option_offset && ++ cs->c < cs->target->option_offset + XT_OPTION_OFFSET_SCALE) { ++ xtables_option_tpcall(cs->c, cs->argv, cs->invert, ++ cs->target, &cs->fw); ++ return 0; ++ } ++ ++ for (matchp = cs->matches; matchp; matchp = matchp->next) { ++ m = matchp->match; ++ ++ if (matchp->completed || ++ (m->x6_parse == NULL && m->parse == NULL)) ++ continue; ++ if (cs->c < matchp->match->option_offset || ++ cs->c >= matchp->match->option_offset + XT_OPTION_OFFSET_SCALE) ++ continue; ++ xtables_option_mpcall(cs->c, cs->argv, cs->invert, m, &cs->fw); ++ return 0; ++ } ++ ++ /* Try loading protocol */ ++ m = load_proto(cs); ++ if (m != NULL) { ++ size_t size; ++ ++ cs->proto_used = 1; ++ ++ size = XT_ALIGN(sizeof(struct ip6t_entry_match)) + m->size; ++ ++ m->m = xtables_calloc(1, size); ++ m->m->u.match_size = size; ++ strcpy(m->m->u.user.name, m->name); ++ m->m->u.user.revision = m->revision; ++ xs_init_match(m); ++ ++ if (m->x6_options != NULL) ++ gl->opts = xtables_options_xfrm(gl->orig_opts, ++ gl->opts, ++ m->x6_options, ++ &m->option_offset); ++ else ++ gl->opts = xtables_merge_options(gl->orig_opts, ++ gl->opts, ++ m->extra_opts, ++ &m->option_offset); ++ if (gl->opts == NULL) ++ xtables_error(OTHER_PROBLEM, "can't alloc memory!"); ++ optind--; ++ /* Indicate to rerun getopt *immediately* */ ++ return 1; ++ } ++ ++ if (cs->c == ':') ++ xtables_error(PARAMETER_PROBLEM, "option \"%s\" " ++ "requires an argument", cs->argv[optind-1]); ++ if (cs->c == '?') ++ xtables_error(PARAMETER_PROBLEM, "unknown option " ++ "\"%s\"", cs->argv[optind-1]); ++ xtables_error(PARAMETER_PROBLEM, "Unknown arg \"%s\"", optarg); ++ return 0; ++} ++ ++static mainfunc_t subcmd_get(const char *cmd, const struct subcommand *cb) ++{ ++ for (; cb->name != NULL; ++cb) ++ if (strcmp(cb->name, cmd) == 0) ++ return cb->main; ++ return NULL; ++} ++ ++int subcmd_main(int argc, char **argv, const struct subcommand *cb) ++{ ++ const char *cmd = basename(*argv); ++ mainfunc_t f = subcmd_get(cmd, cb); ++ ++ if (f == NULL && argc > 1) { ++ /* ++ * Unable to find a main method for our command name? ++ * Let's try again with the first argument! ++ */ ++ ++argv; ++ --argc; ++ f = subcmd_get(*argv, cb); ++ } ++ ++ /* now we should have a valid function pointer */ ++ if (f != NULL) ++ return f(argc, argv); ++ ++ fprintf(stderr, "ERROR: No valid subcommand given.\nValid subcommands:\n"); ++ for (; cb->name != NULL; ++cb) ++ fprintf(stderr, " * %s\n", cb->name); ++ exit(EXIT_FAILURE); ++} ++ ++void xs_init_target(struct xtables_target *target) ++{ ++ if (target->udata_size != 0) { ++ free(target->udata); ++ target->udata = calloc(1, target->udata_size); ++ if (target->udata == NULL) ++ xtables_error(RESOURCE_PROBLEM, "malloc"); ++ } ++ if (target->init != NULL) ++ target->init(target->t); ++} ++ ++void xs_init_match(struct xtables_match *match) ++{ ++ if (match->udata_size != 0) { ++ /* ++ * As soon as a subsequent instance of the same match ++ * is used, e.g. "-m time -m time", the first instance ++ * is no longer reachable anyway, so we can free udata. ++ * Same goes for target. ++ */ ++ free(match->udata); ++ match->udata = calloc(1, match->udata_size); ++ if (match->udata == NULL) ++ xtables_error(RESOURCE_PROBLEM, "malloc"); ++ } ++ if (match->init != NULL) ++ match->init(match->m); ++} +diff --git a/iptables/xshared.h b/iptables/xshared.h +index c53b618..c3de49a 100644 +--- a/iptables/xshared.h ++++ b/iptables/xshared.h +@@ -1,10 +1,12 @@ +-#ifndef IPTABLES_XSHARED_H +-#define IPTABLES_XSHARED_H 1 ++#include + +-struct xtables_rule_match; +-struct xtables_target; ++#if XTABLES_VERSION_CODE < 7 ++#include "xshared.h-old" + +-extern void print_extension_helps(const struct xtables_target *, +- const struct xtables_rule_match *); ++#elif XTABLES_VERSION_CODE == 7 ++#include "xshared.h-v1.4.12" + +-#endif /* IPTABLES_XSHARED_H */ ++#else ++#error "The libxtables is newer than this package support and know of - Sorry!" ++#error " Please inform the package author of this issue, thanks! " ++#endif +diff --git a/iptables/xshared.h-old b/iptables/xshared.h-old +new file mode 100644 +index 0000000..c53b618 +--- /dev/null ++++ b/iptables/xshared.h-old +@@ -0,0 +1,10 @@ ++#ifndef IPTABLES_XSHARED_H ++#define IPTABLES_XSHARED_H 1 ++ ++struct xtables_rule_match; ++struct xtables_target; ++ ++extern void print_extension_helps(const struct xtables_target *, ++ const struct xtables_rule_match *); ++ ++#endif /* IPTABLES_XSHARED_H */ +diff --git a/iptables/xshared.h-v1.4.12 b/iptables/xshared.h-v1.4.12 +new file mode 100644 +index 0000000..b804aaf +--- /dev/null ++++ b/iptables/xshared.h-v1.4.12 +@@ -0,0 +1,89 @@ ++#ifndef IPTABLES_XSHARED_H ++#define IPTABLES_XSHARED_H 1 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++enum { ++ OPT_NONE = 0, ++ OPT_NUMERIC = 1 << 0, ++ OPT_SOURCE = 1 << 1, ++ OPT_DESTINATION = 1 << 2, ++ OPT_PROTOCOL = 1 << 3, ++ OPT_JUMP = 1 << 4, ++ OPT_VERBOSE = 1 << 5, ++ OPT_EXPANDED = 1 << 6, ++ OPT_VIANAMEIN = 1 << 7, ++ OPT_VIANAMEOUT = 1 << 8, ++ OPT_LINENUMBERS = 1 << 9, ++ OPT_COUNTERS = 1 << 10, ++}; ++ ++struct xtables_globals; ++struct xtables_rule_match; ++struct xtables_target; ++ ++/** ++ * xtables_afinfo - protocol family dependent information ++ * @kmod: kernel module basename (e.g. "ip_tables") ++ * @proc_exists: file which exists in procfs when module already loaded ++ * @libprefix: prefix of .so library name (e.g. "libipt_") ++ * @family: nfproto family ++ * @ipproto: used by setsockopt (e.g. IPPROTO_IP) ++ * @so_rev_match: optname to check revision support of match ++ * @so_rev_target: optname to check revision support of target ++ */ ++struct xtables_afinfo { ++ const char *kmod; ++ const char *proc_exists; ++ const char *libprefix; ++ uint8_t family; ++ uint8_t ipproto; ++ int so_rev_match; ++ int so_rev_target; ++}; ++ ++struct iptables_command_state { ++ union { ++ struct ipt_entry fw; ++ struct ip6t_entry fw6; ++ }; ++ int invert; ++ int c; ++ unsigned int options; ++ struct xtables_rule_match *matches; ++ struct xtables_target *target; ++ char *protocol; ++ int proto_used; ++ const char *jumpto; ++ char **argv; ++}; ++ ++typedef int (*mainfunc_t)(int, char **); ++ ++struct subcommand { ++ const char *name; ++ mainfunc_t main; ++}; ++ ++enum { ++ XT_OPTION_OFFSET_SCALE = 256, ++}; ++ ++extern void print_extension_helps(const struct xtables_target *, ++ const struct xtables_rule_match *); ++extern const char *proto_to_name(uint8_t, int); ++extern int command_default(struct iptables_command_state *, ++ struct xtables_globals *); ++extern struct xtables_match *load_proto(struct iptables_command_state *); ++extern int subcmd_main(int, char **, const struct subcommand *); ++extern void xs_init_target(struct xtables_target *); ++extern void xs_init_match(struct xtables_match *); ++ ++extern const struct xtables_afinfo *afinfo; ++ ++#endif /* IPTABLES_XSHARED_H */ +diff --git a/libiptc.xs b/libiptc.xs +index 26df3b8..79b3c96 100644 +--- a/libiptc.xs ++++ b/libiptc.xs +@@ -436,6 +436,9 @@ iptables_delete_chain(self, chain) + CODE: + if (self == NULL) croak(ERRSTR_NULL_HANDLE); + else { ++#if XTABLES_VERSION_CODE >= 7 ++#define delete_chain delete_chain4 ++#endif + RETVAL = delete_chain(chain, 0, self); + if (!RETVAL) { + SET_ERRNUM(errno); +@@ -513,6 +516,9 @@ iptables_do_command(self, array_ref) + * actually is a bug), thus we need to assign something valid + * to fake_table, to avoid a segfault. + */ ++#if XTABLES_VERSION_CODE >= 7 ++#define do_command do_command4 ++#endif + RETVAL = do_command(argc, argv, &fake_table, &self); + if (!RETVAL) { + SET_ERRNUM(errno); +-- +1.7.6.1 + diff --git a/perl-IPTables-libiptc.spec b/perl-IPTables-libiptc.spec new file mode 100644 index 0000000..7bafa5c --- /dev/null +++ b/perl-IPTables-libiptc.spec @@ -0,0 +1,55 @@ +Name: perl-IPTables-libiptc +Version: 0.51 +Release: 1%{?dist} +Summary: Perl extension for iptables libiptc +License: GPLv2+ +Group: Development/Libraries +URL: http://search.cpan.org/dist/IPTables-libiptc/ +Source0: http://www.cpan.org/authors/id/H/HA/HAWK/IPTables-libiptc-%{version}.tar.gz +# RT#70639 +Patch0: %{name}-0.51-Support-iptables-1.4.12.patch +BuildRequires: iptables-devel >= 1.4.4 +BuildRequires: perl(ExtUtils::MakeMaker) +BuildRequires: perl(File::Basename) +# Tests only: +BuildRequires: perl(AutoLoader) +BuildRequires: perl(DynaLoader) +BuildRequires: perl(Exporter) +BuildRequires: perl(Test::More) +Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version)) + +%{?perl_default_filter} + +%description +This package provides a perl interface to the netfilter/iptables C-code and +library libiptc. + +%prep +%setup -q -n IPTables-libiptc-%{version} +%patch0 -p1 -b .1412 + +%build +%{__perl} Makefile.PL PREFIX=%{_prefix} INSTALLDIRS=vendor OPTIMIZE="$RPM_OPT_FLAGS" +make %{?_smp_mflags} + +%install +make pure_install PERL_INSTALL_ROOT=$RPM_BUILD_ROOT +find $RPM_BUILD_ROOT -type f -name .packlist -exec rm -f {} \; +find $RPM_BUILD_ROOT -type f -name '*.bs' -size 0 -exec rm -f {} \; +find $RPM_BUILD_ROOT -depth -type d -exec rmdir {} 2>/dev/null \; +%{_fixperms} $RPM_BUILD_ROOT/* + +%check +make test + +%files +%doc Changes README +%{perl_vendorarch}/auto/* +%{perl_vendorarch}/IPTables* +%{_mandir}/man3/* + +%changelog +* Wed Aug 31 2011 Petr Pisar 0.51-1 +- Specfile autogenerated by cpanspec 1.78. +- Remove BuildRoot and defattr from spec code +- Add support for iptables-1.4.12 (RT#70639) diff --git a/sources b/sources index e69de29..aa06048 100644 --- a/sources +++ b/sources @@ -0,0 +1 @@ +e79410de009695a989d571c18ba2c91a IPTables-libiptc-0.51.tar.gz