summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--iptables-restore.c136
-rw-r--r--iptables-save.c160
-rw-r--r--iptables-standalone.c13
-rw-r--r--iptables.c48
5 files changed, 235 insertions, 126 deletions
diff --git a/Makefile b/Makefile
index 60acf0ef..dd28ae5f 100644
--- a/Makefile
+++ b/Makefile
@@ -18,8 +18,8 @@ CFLAGS:=$(COPT_FLAGS) -Wall -Wunused -Iinclude/ -I$(KERNEL_DIR)/include -DNETFIL
DEPFILES = $(SHARED_LIBS:%.so=%.d)
SH_CFLAGS:=$(CFLAGS) -fPIC
-EXTRAS+=iptables iptables.o ip6tables ip6tables.o #iptables-save iptables-restore
-EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables $(DESTDIR)$(BINDIR)/ip6tables $(DESTDIR)$(MANDIR)/man8/iptables.8 #$(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore
+EXTRAS+=iptables iptables.o iptables-save iptables-restore # ip6tables ip6tables.o
+EXTRA_INSTALLS+=$(DESTDIR)$(BINDIR)/iptables $(DESTDIR)$(MANDIR)/man8/iptables.8 $(DESTDIR)$(BINDIR)/iptables-save $(DESTDIR)$(BINDIR)/iptables-restore # $(DESTDIR)$(BINDIR)/ip6tables
# Sparc64 hack
ifeq ($(shell uname -m),sparc64)
diff --git a/iptables-restore.c b/iptables-restore.c
index f9a95952..5e017200 100644
--- a/iptables-restore.c
+++ b/iptables-restore.c
@@ -1,10 +1,23 @@
-/* Code to restore the iptables state, from file by iptables-save. */
+/* Code to restore the iptables state, from file by iptables-save.
+ * (C) 2000 by Harald Welte <laforge@gnumonks.org>
+ * based on previous code from Rusty Russell <rusty@linuxcare.com.au>
+ *
+ * This coude is distributed under the terms of GNU GPL
+ */
+
#include <getopt.h>
#include <sys/errno.h>
#include <string.h>
#include <stdio.h>
-#include "packet-filter/userspace/iptables.h"
-#include "packet-filter/userspace/libiptc/libiptc.h"
+#include <stdlib.h>
+#include "iptables.h"
+#include "libiptc/libiptc.h"
+
+#ifdef DEBUG
+#define DEBUGP(x, args ...) fprintf(stderr, x, ## args)
+#else
+#define DEBUGP(x, args ...)
+#endif
/* Keeping track of external matches and targets. */
static struct option options[] = {
@@ -23,29 +36,28 @@ static void print_usage(const char *name, const char *version)
exit(1);
}
-static int clean_slate(iptc_handle_t *handle)
+iptc_handle_t create_handle(const char *tablename)
{
- /* Skip over builtins. */
- const char *i, *last = IPTC_LABEL_OUTPUT;
-
- /* Be careful iterating: it isn't safe during delete. */
- /* Re-iterate after each delete successful */
- while ((i = iptc_next_chain(last, handle)) != NULL) {
- if (!iptc_flush_entries(i, handle)
- || !iptc_delete_chain(i, handle))
- return 0;
+ iptc_handle_t handle;
+
+ handle = iptc_init(tablename);
+ if (!handle) {
+ exit_error(PARAMETER_PROBLEM, "%s: unable to initialize"
+ "table '%s'\n", program_name, tablename);
+ exit(1);
}
- return 1;
+ return handle;
}
+
int main(int argc, char *argv[])
{
iptc_handle_t handle;
char buffer[10240];
int counters = 0, binary = 0, verbose = 0;
unsigned int line = 0;
- int c;
- const char *chain;
+ char curtable[IPT_TABLE_MAXNAMELEN + 1];
+ char curchain[IPT_FUNCTION_MAXNAMELEN + 1];
FILE *in;
program_name = "iptables-restore";
@@ -65,8 +77,8 @@ int main(int argc, char *argv[])
exit(1);
}
else in = stdin;
-
- handle = iptc_init();
+/*
+ handle = iptc_init("filter");
if (!handle)
exit_error(VERSION_PROBLEM,
"can't initialize iptables-restore: %s",
@@ -75,7 +87,7 @@ int main(int argc, char *argv[])
if (!clean_slate(&handle))
exit_error(OTHER_PROBLEM, "Deleting old chains: %s",
iptc_strerror(errno));
-
+*/
/* Grab standard input. */
while (fgets(buffer, sizeof(buffer), in)) {
int ret;
@@ -85,37 +97,84 @@ int main(int argc, char *argv[])
else if (buffer[0] == '#') {
if (verbose) fputs(buffer, stdout);
continue;
- } else if (strcmp(buffer, "COMMIT\n") == 0)
+ } else if (strcmp(buffer, "COMMIT\n") == 0) {
+ DEBUGP("Calling commit\n");
ret = iptc_commit(&handle);
- else if (buffer[0] == ':') {
+ } else if (buffer[0] == '*') {
+ /* New table */
+ char *table;
+
+ table = strtok(buffer+1, " \t\n");
+ DEBUGP("line %u, table '%s'\n", line, table);
+ if (!table) {
+ exit_error(PARAMETER_PROBLEM,
+ "%s: line %u table name invalid\n",
+ program_name, line);
+ exit(1);
+ }
+ strncpy(curtable, table, IPT_TABLE_MAXNAMELEN);
+
+ handle = create_handle(table);
+
+ DEBUGP("Cleaning all chains of table '%s'\n", table);
+ for_each_chain(flush_entries, verbose, 1, &handle) ;
+
+ DEBUGP("Deleting all user-defined chains of table '%s'\n", table);
+ for_each_chain(delete_chain, verbose, 0, &handle) ;
+
+ ret = 1;
+
+ } else if (buffer[0] == ':') {
/* New chain. */
- char *chain, *policy;
+ char *policy, *chain;
/* FIXME: Don't ignore counters. */
+
chain = strtok(buffer+1, " \t\n");
+ DEBUGP("line %u, chain '%s'\n", line, chain);
if (!chain) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u chain name invalid\n",
program_name, line);
exit(1);
}
+ strncpy(curchain, chain, IPT_FUNCTION_MAXNAMELEN);
+
+ /* why the f... does iptc_builtin not work here ? */
+// if (!iptc_builtin(curchain, &handle)) {
+ DEBUGP("Creating new chain '%s'\n", curchain);
+ if (!iptc_create_chain(curchain, &handle))
+ DEBUGP("unable to create chain '%s':%s\n", curchain,
+ strerror(errno));
+// }
+
policy = strtok(NULL, " \t\n");
+ DEBUGP("line %u, policy '%s'\n", line, policy);
if (!policy) {
exit_error(PARAMETER_PROBLEM,
"%s: line %u policy invalid\n",
program_name, line);
exit(1);
}
- if (strcmp(policy, "-") != 0
- && !iptc_set_policy(chain, policy, &handle))
- exit_error(OTHER_PROBLEM,
- "Can't set policy `%s'"
- " on `%s' line %u: %s\n",
- chain, policy, line,
- iptc_strerror(errno));
+
+ if (strcmp(policy, "-") != 0) {
+
+ DEBUGP("Setting policy of chain %s to %s\n",
+ chain, policy);
+
+ if (!iptc_set_policy(chain, policy, &handle))
+ exit_error(OTHER_PROBLEM,
+ "Can't set policy `%s'"
+ " on `%s' line %u: %s\n",
+ chain, policy, line,
+ iptc_strerror(errno));
+ }
+
+ ret = 1;
+
} else {
char *newargv[1024];
- int i;
+ int i,a;
char *ptr = buffer;
/* FIXME: Don't ignore counters. */
@@ -127,9 +186,14 @@ int main(int argc, char *argv[])
line);
}
- /* strtok: a function only a coder could love */
newargv[0] = argv[0];
- for (i = 1; i < sizeof(newargv)/sizeof(char *); i++) {
+ newargv[1] = "-t";
+ newargv[2] = (char *) &curtable;
+ newargv[3] = "-A";
+ newargv[4] = (char *) &curchain;
+
+ /* strtok: a function only a coder could love */
+ for (i = 5; i < sizeof(newargv)/sizeof(char *); i++) {
if (!(newargv[i] = strtok(ptr, " \t\n")))
break;
ptr = NULL;
@@ -141,7 +205,13 @@ int main(int argc, char *argv[])
exit(1);
}
- ret = do_command(i, newargv, &handle);
+ DEBUGP("===>calling do_command(%u, argv, &%s, handle):\n",
+ i, curtable);
+
+ for (a = 0; a <= i; a++)
+ DEBUGP("argv[%u]: %s\n", a, newargv[a]);
+
+ ret = do_command(i, newargv, &newargv[2], &handle);
}
if (!ret) {
fprintf(stderr, "%s: line %u failed\n",
diff --git a/iptables-save.c b/iptables-save.c
index d858817e..413e1ad3 100644
--- a/iptables-save.c
+++ b/iptables-save.c
@@ -1,7 +1,13 @@
/* Code to save the iptables state, in human readable-form. */
+/* Authors: Paul 'Rusty' Russel <rusty@linuxcare.com.au> and
+ * Harald Welte <laforge@gnumonks.org>
+ */
#include <getopt.h>
#include <sys/errno.h>
#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
#include <dlfcn.h>
#include <time.h>
#include "libiptc/libiptc.h"
@@ -47,6 +53,8 @@ print_iface(char letter, const char *iface, const unsigned char *mask,
break;
}
}
+
+ printf(" ");
}
/* These are hardcoded backups in iptables.c, so they are safe */
@@ -55,6 +63,7 @@ struct pprot {
u_int8_t num;
};
+/* FIXME: why don't we use /etc/services ? */
static const struct pprot chain_protos[] = {
{ "tcp", IPPROTO_TCP },
{ "udp", IPPROTO_UDP },
@@ -78,6 +87,7 @@ static void print_proto(u_int16_t proto, int invert)
}
}
+#if 0
static int non_zero(const void *ptr, size_t size)
{
unsigned int i;
@@ -88,74 +98,97 @@ static int non_zero(const void *ptr, size_t size)
return 1;
}
+#endif
+
+static int print_match(const struct ipt_entry_match *e)
+{
+ struct iptables_match *match
+ = find_match(e->u.user.name, TRY_LOAD);
+
+ if (match) {
+ printf("-m %s ", e->u.user.name);
+ match->save(NULL, 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(char *prefix, u_int32_t ip, u_int32_t mask, int invert)
+{
+ if (!mask && !ip)
+ return;
+
+ printf("%s %s%u.%u.%u.%u",
+ prefix,
+ invert ? "! " : "",
+ IP_PARTS(ip));
+
+ if (mask != 0xffffffff)
+ printf("/%u.%u.%u.%u ", IP_PARTS(mask));
+ else
+ printf(" ");
+}
/* We want this to be readable, so only print out neccessary fields.
* Because that's the kind of world I want to live in. */
-static void print_rule(const struct ipt_entry *e, int counters)
+static void print_rule(const struct ipt_entry *e,
+ iptc_handle_t *h, int counters)
{
+ struct ipt_entry_target *t;
+
+ /* print counters */
if (counters)
printf("[%llu,%llu] ", e->counters.pcnt, e->counters.bcnt);
/* Print IP part. */
- if (e->ip.smsk.s_addr)
- printf("-s %s%u.%u.%u.%u/%u.%u.%u.%u ",
- e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
- IP_PARTS(e->ip.src.s_addr),
- IP_PARTS(e->ip.smsk.s_addr));
- if (e->ip.dmsk.s_addr)
- printf("-d %s%u.%u.%u.%u/%u.%u.%u.%u ",
- e->ip.invflags & IPT_INV_SRCIP ? "! " : "",
- IP_PARTS(e->ip.dst.s_addr),
- IP_PARTS(e->ip.dmsk.s_addr));
+ 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_SRCIP);
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 ? "! " : "");
- if (e->ip.flags & IPT_F_TOS)
- printf("-t %s0x%02X ",
- e->ip.invflags & IPT_INV_TOS ? "! " : "",
- e->ip.tos);
-
/* Print matchinfo part */
- if (e->match_name[0]) {
- struct iptables_match *match
- = find_match(e->match_name, TRY_LOAD);
-
- if (match)
- match->save(e);
- else {
- /* If some bits are non-zero, it implies we *need*
- to understand it */
- if (non_zero(&e->matchinfo, sizeof(e->matchinfo))) {
- fprintf(stderr,
- "Can't find library for match `%s'\n",
- e->match_name);
- exit(1);
- }
- }
+ if (e->target_offset) {
+ IPT_MATCH_ITERATE(e, print_match);
}
+ /* Print target name */
+ printf("-j %s ", iptc_get_target(e, h));
+
/* Print targinfo part */
- if (e->target_name[0]) {
+ t = ipt_get_target(e);
+ if (t->u.user.name[0]) {
struct iptables_target *target
- = find_target(e->target_name, TRY_LOAD);
+ = find_target(t->u.user.name, TRY_LOAD);
if (target)
- target->save(e);
+ target->save(NULL, t);
else {
/* If some bits are non-zero, it implies we *need*
to understand it */
- if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
+ if (t->u.target_size) {
fprintf(stderr,
"Can't find library for target `%s'\n",
- e->target_name);
+ t->u.user.name);
exit(1);
}
}
@@ -164,15 +197,13 @@ static void print_rule(const struct ipt_entry *e, int counters)
}
/* Debugging prototype. */
-extern void dump_entries(iptc_handle_t handle);
-
static int for_each_table(int (*func)(const char *tablename))
{
int ret = 1;
- FILE *procfile;
+ FILE *procfile = NULL;
char tablename[IPT_TABLE_MAXNAMELEN+1];
- procfile = fopen("/proc/net/ip_tables_names", O_RDONLY);
+ procfile = fopen("/proc/net/ip_tables_names", "r");
if (!procfile)
return 0;
@@ -189,21 +220,6 @@ static int for_each_table(int (*func)(const char *tablename))
}
-static int dump_table(const char *tablename)
-{
- iptc_handle_t h;
-
- if (!tablename)
- return for_each_table(&dump_table);
-
- /* Debugging dump. */
- h = iptc_init(tablename);
- if (!h)
- exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
- iptc_strerror(errno));
- dump_entries(h);
-}
-
static int do_output(const char *tablename)
{
iptc_handle_t h;
@@ -222,39 +238,29 @@ static int do_output(const char *tablename)
printf("# Generated by iptables-save v%s on %s",
NETFILTER_VERSION, ctime(&now));
+ printf("*%s\n", tablename);
/* Dump out chain names */
for (chain = iptc_first_chain(&h);
chain;
chain = iptc_next_chain(&h)) {
+ const struct ipt_entry *e;
+
printf(":%s ", chain);
- if (iptc_builtin(chain, &h)) {
+ if (iptc_builtin(chain, h)) {
struct ipt_counters count;
printf("%s ",
iptc_get_policy(chain, &count, &h));
- printf("%llu %llu\n", count.pcnt, count.bcnt);
+ printf("%llu:%llu\n", count.pcnt, count.bcnt);
} else {
printf("- 0 0\n");
}
- }
- /* Dump out rules */
- for (chain = iptc_first_chain(&h);
- chain;
- chain = iptc_next_chain(&h)) {
- unsigned int i;
-
- for (i = 0; i < iptc_num_rules(chain, &h); i++) {
- const struct ipt_entry *e
- = iptc_get_rule(chain, i, &h);
-
- if (!e)
- exit_error(OTHER_PROBLEM,
- "Can't read rule %u"
- " of chain %s: %s\n",
- i, chain,
- iptc_strerror(errno));
- print_rule(e, counters);
+ /* Dump out rules */
+ e = iptc_first_rule(chain, &h);
+ while(e) {
+ print_rule(e, &h, counters);
+ e = iptc_next_rule(e, &h);
}
}
@@ -296,7 +302,7 @@ int main(int argc, char *argv[])
tablename = optarg;
break;
case 'd':
- dump_table(tablename);
+ do_output(tablename);
exit(0);
}
}
diff --git a/iptables-standalone.c b/iptables-standalone.c
index dfbc0fa3..53d21890 100644
--- a/iptables-standalone.c
+++ b/iptables-standalone.c
@@ -33,14 +33,21 @@ main(int argc, char *argv[])
{
int ret;
char *table = "filter";
- iptc_handle_t handle;
+ iptc_handle_t *handle;
+
+ handle = (iptc_handle_t *) malloc(sizeof(iptc_handle_t));
+ if (!handle) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ memset(handle, 0, sizeof(iptc_handle_t));
program_name = "iptables";
program_version = NETFILTER_VERSION;
- ret = do_command(argc, argv, &table, &handle);
+ ret = do_command(argc, argv, &table, handle);
if (ret)
- ret = iptc_commit(&handle);
+ ret = iptc_commit(handle);
if (!ret)
fprintf(stderr, "iptables: %s\n",
diff --git a/iptables.c b/iptables.c
index 4dbe8917..73f400b5 100644
--- a/iptables.c
+++ b/iptables.c
@@ -126,7 +126,7 @@ static struct option original_opts[] = {
};
#ifndef __OPTIMIZE__
-static struct ipt_entry_target *
+struct ipt_entry_target *
ipt_get_target(struct ipt_entry *e)
{
return (void *)e + e->target_offset;
@@ -643,6 +643,9 @@ find_match(const char *name, enum ipt_tryload tryload)
name, dlerror());
}
+ if (ptr)
+ ptr->used = 1;
+
return ptr;
}
@@ -893,6 +896,9 @@ find_target(const char *name, enum ipt_tryload tryload)
name, dlerror());
}
+ if (ptr)
+ ptr->used = 1;
+
return ptr;
}
@@ -1290,7 +1296,7 @@ make_delete_mask(struct ipt_entry *fw)
unsigned char *mask, *mptr;
size = sizeof(struct ipt_entry);
- for (m = iptables_matches; m; m = m->next)
+ for (m = iptables_matches; m && m->used; m = m->next)
size += IPT_ALIGN(sizeof(struct ipt_entry_match)) + m->size;
mask = fw_calloc(1, size
@@ -1300,7 +1306,7 @@ make_delete_mask(struct ipt_entry *fw)
memset(mask, 0xFF, sizeof(struct ipt_entry));
mptr = mask + sizeof(struct ipt_entry);
- for (m = iptables_matches; m; m = m->next) {
+ for (m = iptables_matches; m && m->used; m = m->next) {
memset(mptr, 0xFF,
IPT_ALIGN(sizeof(struct ipt_entry_match))
+ m->userspacesize);
@@ -1370,7 +1376,7 @@ check_packet(const ipt_chainlabel chain,
return ret;
}
-static int
+int
for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
int verbose, int builtinstoo, iptc_handle_t *handle)
{
@@ -1406,7 +1412,7 @@ for_each_chain(int (*fn)(const ipt_chainlabel, int, iptc_handle_t *),
return ret;
}
-static int
+int
flush_entries(const ipt_chainlabel chain, int verbose,
iptc_handle_t *handle)
{
@@ -1430,7 +1436,7 @@ zero_entries(const ipt_chainlabel chain, int verbose,
return iptc_zero_entries(chain, handle);
}
-static int
+int
delete_chain(const ipt_chainlabel chain, int verbose,
iptc_handle_t *handle)
{
@@ -1505,7 +1511,7 @@ generate_entry(const struct ipt_entry *fw,
struct ipt_entry *e;
size = sizeof(struct ipt_entry);
- for (m = matches; m; m = m->next)
+ for (m = matches; m && m->used; m = m->next)
size += m->m->u.match_size;
e = fw_malloc(size + target->u.target_size);
@@ -1514,7 +1520,7 @@ generate_entry(const struct ipt_entry *fw,
e->next_offset = size + target->u.target_size;
size = 0;
- for (m = matches; m; m = m->next) {
+ for (m = matches; m && m->used; m = m->next) {
memcpy(e->elems + size, m->m, m->m->u.match_size);
size += m->m->u.match_size;
}
@@ -1538,11 +1544,28 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
int ret = 1;
struct iptables_match *m;
struct iptables_target *target = NULL;
+ struct iptables_target *t;
const char *jumpto = "";
char *protocol = NULL;
memset(&fw, 0, sizeof(fw));
+ /* re-set optind to 0 in case do_command gets called
+ * a second time */
+ optind = 0;
+
+ /* clear mflags in case do_command gets called a second time
+ * (we clear the global list of all matches for security)*/
+ for (m = iptables_matches; m; m = m->next) {
+ m->mflags = 0;
+ m->used = 0;
+ }
+
+ for (t = iptables_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;
@@ -1845,7 +1868,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
argv, invert,
&target->tflags,
&fw, &target->t))) {
- for (m = iptables_matches; m; m = m->next) {
+ for (m = iptables_matches; m && m->used; m = m->next) {
if (m->parse(c - m->option_offset,
argv, invert,
&m->mflags,
@@ -1886,7 +1909,7 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
invert = FALSE;
}
- for (m = iptables_matches; m; m = m->next)
+ for (m = iptables_matches; m && m->used; m = m->next)
m->final_check(m->mflags);
if (target)
target->final_check(target->tflags);
@@ -1938,7 +1961,10 @@ int do_command(int argc, char *argv[], char **table, iptc_handle_t *handle)
"chain name `%s' too long (must be under %i chars)",
chain, IPT_FUNCTION_MAXNAMELEN);
- *handle = iptc_init(*table);
+ /* only allocate handle if we weren't called with a handle */
+ if (!*handle)
+ *handle = iptc_init(*table);
+
if (!*handle)
exit_error(VERSION_PROBLEM,
"can't initialize iptables table `%s': %s",