summaryrefslogtreecommitdiffstats
path: root/iptables-save.c
diff options
context:
space:
mode:
authorMarc Boucher <marc@mbsi.ca>2000-03-20 06:03:29 +0000
committerMarc Boucher <marc@mbsi.ca>2000-03-20 06:03:29 +0000
commite6869a8f59d779ff4d5a0984c86d80db70784962 (patch)
treecbaf2a4e3f8249de3967b959a214c27ff5fdee2a /iptables-save.c
reorganized tree after kernel merge
Diffstat (limited to 'iptables-save.c')
-rw-r--r--iptables-save.c260
1 files changed, 260 insertions, 0 deletions
diff --git a/iptables-save.c b/iptables-save.c
new file mode 100644
index 00000000..40e9d6a5
--- /dev/null
+++ b/iptables-save.c
@@ -0,0 +1,260 @@
+/* Code to save the iptables state, in human readable-form. */
+#include <getopt.h>
+#include <sys/errno.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <time.h>
+#include "packet-match/userspace/libiptc/libiptc.h"
+#include "packet-match/userspace/iptables.h"
+
+/* Keeping track of external matches and targets. */
+static struct option options[] = {
+ { "binary", 1, 0, 'b' },
+ { "counters", 1, 0, 'c' },
+ { "dump", 1, 0, 'd' },
+ { 0 }
+};
+
+#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("-%c %s", letter, invert ? "! " : "");
+
+ for (i = 0; i < IFNAMSIZ; i++) {
+ if (mask[i] != 0) {
+ if (iface[i] != '\0')
+ printf("%c", iface[i]);
+ } else {
+ if (iface[i] != '\0')
+ printf("+");
+ break;
+ }
+ }
+}
+
+/* These are hardcoded backups in iptables.c, so they are safe */
+struct pprot {
+ char *name;
+ u_int8_t num;
+};
+
+static const struct pprot chain_protos[] = {
+ { "tcp", IPPROTO_TCP },
+ { "udp", IPPROTO_UDP },
+ { "icmp", IPPROTO_ICMP },
+};
+
+static void print_proto(u_int16_t proto, int invert)
+{
+ if (proto) {
+ unsigned int i;
+ const char *invertstr = invert ? "! " : "";
+
+ for (i = 0; i < sizeof(chain_protos)/sizeof(struct pprot); i++)
+ if (chain_protos[i].num == proto) {
+ printf("-p %s%s ",
+ invertstr, chain_protos[i].name);
+ return;
+ }
+
+ printf("-p %s%u ", invertstr, proto);
+ }
+}
+
+static int non_zero(const void *ptr, size_t size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++)
+ if (((char *)ptr)[i])
+ return 0;
+
+ return 1;
+}
+
+/* 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)
+{
+ 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_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, 1);
+
+ 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);
+ }
+ }
+ }
+
+ /* Print targinfo part */
+ if (e->target_name[0]) {
+ struct iptables_target *target
+ = find_target(e->target_name, 1);
+
+ if (target)
+ target->save(e);
+ else {
+ /* If some bits are non-zero, it implies we *need*
+ to understand it */
+ if (non_zero(&e->targinfo, sizeof(e->targinfo))) {
+ fprintf(stderr,
+ "Can't find library for target `%s'\n",
+ e->target_name);
+ exit(1);
+ }
+ }
+ }
+ printf("\n");
+}
+
+/* Debugging prototype. */
+extern void dump_entries(iptc_handle_t handle);
+
+/* Format:
+ * :Chain name POLICY packets bytes
+ * rule
+ */
+int main(int argc, char *argv[])
+{
+ iptc_handle_t h;
+ const char *chain = NULL;
+ int c;
+ int binary = 0, counters = 0;
+
+ program_name = "iptables-save";
+ program_version = NETFILTER_VERSION;
+
+ while ((c = getopt_long(argc, argv, "bc", options, NULL)) != -1) {
+ switch (c) {
+ case 'b':
+ binary = 1;
+ break;
+
+ case 'c':
+ counters = 1;
+ break;
+
+ case 'd':
+ /* Debugging dump. */
+ h = iptc_init();
+ if (!h)
+ exit_error(OTHER_PROBLEM, "iptc_init: %s\n",
+ iptc_strerror(errno));
+ dump_entries(h);
+ exit(0);
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "Unknown arguments found on commandline");
+ exit(1);
+ }
+
+ h = iptc_init();
+ if (!h) {
+ fprintf(stderr, "Can't initialize: %s\n",
+ iptc_strerror(errno));
+ exit(1);
+ }
+
+ if (!binary) {
+ time_t now = time(NULL);
+
+ printf("# Generated by iptables-save v%s on %s",
+ NETFILTER_VERSION, ctime(&now));
+
+ /* Dump out chain names */
+ while ((chain = iptc_next_chain(chain, &h)) != NULL) {
+ printf(":%s ", chain);
+ 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);
+ } else {
+ printf("- 0 0\n");
+ }
+ }
+
+ /* Dump out rules */
+ while ((chain = iptc_next_chain(chain, &h)) != NULL) {
+ 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) {
+ fprintf(stderr,
+ "Can't read rule %u of chain %s: %s\n",
+ i, chain, iptc_strerror(errno));
+ exit(1);
+ }
+ print_rule(e, counters);
+ }
+ }
+
+ now = time(NULL);
+ printf("COMMIT\n");
+ printf("# Completed on %s", ctime(&now));
+ } else {
+ /* Binary, huh? OK. */
+ fprintf(stderr, "Binary NYI\n");
+ exit(1);
+ }
+
+ return 0;
+}