summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian J. Murrell <netfilter@interlinx.bc.ca>2003-03-30 23:40:07 -0800
committerDavid S. Miller <davem@nuts.ninka.net>2003-03-30 23:40:07 -0800
commit017091704fc496fd59f49591d09165984dc3cbb5 (patch)
treef6004c16a1e57c64ce49c8896c3f27b44978f2cf
parentb3a3a32973d95963d9cd806d9d7046830dca202b (diff)
[NETFILTER]: Add amanda conntrack + NAT support.
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_amanda.h29
-rw-r--r--net/ipv4/netfilter/Kconfig20
-rw-r--r--net/ipv4/netfilter/Makefile6
-rw-r--r--net/ipv4/netfilter/ip_conntrack_amanda.c233
-rw-r--r--net/ipv4/netfilter/ip_nat_amanda.c226
6 files changed, 512 insertions, 4 deletions
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index 6908061d0deb..1dc2e0d5ce5e 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -63,12 +63,14 @@ union ip_conntrack_expect_proto {
};
/* Add protocol helper include file here */
+#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
#include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
#include <linux/netfilter_ipv4/ip_conntrack_irc.h>
/* per expectation: application helper private data */
union ip_conntrack_expect_help {
/* insert conntrack helper private data (expect) here */
+ struct ip_ct_amanda_expect exp_amanda_info;
struct ip_ct_ftp_expect exp_ftp_info;
struct ip_ct_irc_expect exp_irc_info;
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_amanda.h b/include/linux/netfilter_ipv4/ip_conntrack_amanda.h
new file mode 100644
index 000000000000..98f8e0df3467
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ip_conntrack_amanda.h
@@ -0,0 +1,29 @@
+#ifndef _IP_CONNTRACK_AMANDA_H
+#define _IP_CONNTRACK_AMANDA_H
+/* AMANDA tracking. */
+
+#ifdef __KERNEL__
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+
+/* Protects amanda part of conntracks */
+DECLARE_LOCK_EXTERN(ip_amanda_lock);
+
+#endif
+
+struct conn {
+ char* match;
+ int matchlen;
+};
+
+#define NUM_MSGS 3
+
+
+struct ip_ct_amanda_expect
+{
+ u_int16_t port; /* port number of this expectation */
+ u_int16_t offset; /* offset of the port specification in ctrl packet */
+ u_int16_t len; /* the length of the port number specification */
+};
+
+#endif /* _IP_CONNTRACK_AMANDA_H */
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index 77d6472f3cca..cbb5bb2f9ebc 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -59,6 +59,20 @@ config IP_NF_TFTP
If you want to compile it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say `Y'.
+config IP_NF_AMANDA
+ tristate "Amanda backup protocol support"
+ depends on IP_NF_CONNTRACK
+ help
+ If you are running the Amanda backup package (http://www.amanda.org/)
+ on this machine or machines that will be MASQUERADED through this
+ machine, then you may want to enable this feature. This allows the
+ connection tracking and natting code to allow the sub-channels that
+ Amanda requires for communication of the backup data, messages and
+ index.
+
+ If you want to compile it as a module, say M here and read
+ <file:Documentation/modules.txt>. If unsure, say `Y'.
+
config IP_NF_QUEUE
tristate "Userspace queueing via NETLINK (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -398,6 +412,12 @@ config IP_NF_NAT_TFTP
default IP_NF_NAT if IP_NF_TFTP=y
default m if IP_NF_TFTP=m
+config IP_NF_NAT_AMANDA
+ tristate
+ depends on IP_NF_IPTABLES!=n && IP_NF_CONNTRACK!=n && IP_NF_NAT!=n
+ default IP_NF_NAT if IP_NF_TFTP=y
+ default m if IP_NF_TFTP=m
+
config IP_NF_MANGLE
tristate "Packet mangling"
depends on IP_NF_IPTABLES
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index 342ea3b7e83a..8c21c15a6af3 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -20,15 +20,13 @@ ipchains-objs := $(ip_nf_compat-objs) ipchains_core.o
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
# connection tracking helpers
+obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o
obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
-ifdef CONFIG_IP_NF_NAT_FTP
-endif
obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o
-ifdef CONFIG_IP_NF_NAT_IRC
-endif
# NAT helpers
+obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o
obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o
obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o
obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
new file mode 100644
index 000000000000..453c1fb5b88b
--- /dev/null
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -0,0 +1,233 @@
+/* Amanda extension for IP connection tracking, Version 0.2
+ * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
+ * based on HW's ip_conntrack_irc.c as well as other modules
+ *
+ * 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.
+ *
+ * Module load syntax:
+ * insmod ip_conntrack_amanda.o [master_timeout=n]
+ *
+ * Where master_timeout is the timeout (in seconds) of the master
+ * connection (port 10080). This defaults to 5 minutes but if
+ * your clients take longer than 5 minutes to do their work
+ * before getting back to the Amanda server, you can increase
+ * this value.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/ip.h>
+#include <net/checksum.h>
+#include <net/udp.h>
+
+#include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+
+static unsigned int master_timeout = 300;
+
+MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
+MODULE_DESCRIPTION("Amanda connection tracking module");
+MODULE_LICENSE("GPL");
+MODULE_PARM(master_timeout, "i");
+MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
+
+DECLARE_LOCK(ip_amanda_lock);
+struct module *ip_conntrack_amanda = THIS_MODULE;
+
+#define MAXMATCHLEN 6
+struct conn conns[NUM_MSGS] = {
+ {"DATA ", 5},
+ {"MESG ", 5},
+ {"INDEX ", 6},
+};
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+
+/* FIXME: This should be in userspace. Later. */
+static int help(const struct iphdr *iph, size_t len,
+ struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
+{
+ struct udphdr *udph = (void *)iph + iph->ihl * 4;
+ u_int32_t udplen = len - iph->ihl * 4;
+ u_int32_t datalen = udplen - sizeof(struct udphdr);
+ char *data = (char *)udph + sizeof(struct udphdr);
+ char *datap = data;
+ char *data_limit = (char *) data + datalen;
+ int dir = CTINFO2DIR(ctinfo);
+ struct ip_ct_amanda *info =
+ (struct ip_ct_amanda *)&ct->help.ct_ftp_info;
+
+ /* Can't track connections formed before we registered */
+ if (!info)
+ return NF_ACCEPT;
+
+ /* increase the UDP timeout of the master connection as replies from
+ * Amanda clients to the server can be quite delayed */
+ ip_ct_refresh(ct, master_timeout * HZ);
+
+ /* If packet is coming from Amanda server */
+ if (dir == IP_CT_DIR_ORIGINAL)
+ return NF_ACCEPT;
+
+ /* Not whole UDP header? */
+ if (udplen < sizeof(struct udphdr)) {
+ printk("ip_conntrack_amanda_help: udplen = %u\n",
+ (unsigned)udplen);
+ return NF_ACCEPT;
+ }
+
+ /* Checksum invalid? Ignore. */
+ if (csum_tcpudp_magic(iph->saddr, iph->daddr, udplen, IPPROTO_UDP,
+ csum_partial((char *)udph, udplen, 0))) {
+ DEBUGP("ip_ct_talk_help: bad csum: %p %u %u.%u.%u.%u "
+ "%u.%u.%u.%u\n",
+ udph, udplen, NIPQUAD(iph->saddr),
+ NIPQUAD(iph->daddr));
+ return NF_ACCEPT;
+ }
+
+ /* Search for the CONNECT string */
+ while (data < data_limit) {
+ if (!memcmp(data, "CONNECT ", 8)) {
+ break;
+ }
+ data++;
+ }
+ if (memcmp(data, "CONNECT ", 8))
+ return NF_ACCEPT;
+
+ DEBUGP("ip_conntrack_amanda_help: CONNECT found in connection "
+ "%u.%u.%u.%u:%u %u.%u.%u.%u:%u\n",
+ NIPQUAD(iph->saddr), htons(udph->source),
+ NIPQUAD(iph->daddr), htons(udph->dest));
+ data += 8;
+ while (*data != 0x0a && data < data_limit) {
+
+ int i;
+
+ for (i = 0; i < NUM_MSGS; i++) {
+ if (!memcmp(data, conns[i].match,
+ conns[i].matchlen)) {
+
+ char *portchr;
+ struct ip_conntrack_expect expect;
+ struct ip_ct_amanda_expect
+ *exp_amanda_info =
+ &expect.help.exp_amanda_info;
+
+ memset(&expect, 0, sizeof(expect));
+
+ data += conns[i].matchlen;
+ /* this is not really tcp, but let's steal an
+ * idea from a tcp stream helper :-)
+ */
+ // XXX expect.seq = data - datap;
+ exp_amanda_info->offset = data - datap;
+// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, datap, expect.seq);
+DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, datap, exp_amanda_info->offset);
+ portchr = data;
+ exp_amanda_info->port =
+ simple_strtoul(data, &data, 10);
+ exp_amanda_info->len = data - portchr;
+
+ /* eat whitespace */
+ while (*data == ' ')
+ data++;
+ DEBUGP ("ip_conntrack_amanda_help: "
+ "CONNECT %s request with port "
+ "%u found\n", conns[i].match,
+ exp_amanda_info->port);
+
+ LOCK_BH(&ip_amanda_lock);
+
+ expect.tuple = ((struct ip_conntrack_tuple)
+ { { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip,
+ { 0 } },
+ { ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip,
+ { htons(exp_amanda_info->port) },
+ IPPROTO_TCP }});
+ expect.mask = ((struct ip_conntrack_tuple)
+ { { 0, { 0 } },
+ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
+
+ expect.expectfn = NULL;
+
+ DEBUGP ("ip_conntrack_amanda_help: "
+ "expect_related: %u.%u.%u.%u:%u - "
+ "%u.%u.%u.%u:%u\n",
+ NIPQUAD(expect.tuple.src.ip),
+ ntohs(expect.tuple.src.u.tcp.port),
+ NIPQUAD(expect.tuple.dst.ip),
+ ntohs(expect.tuple.dst.u.tcp.port));
+ if (ip_conntrack_expect_related(ct, &expect) ==
+ -EEXIST) {
+ ;
+ /* this must be a packet being resent */
+ /* XXX - how do I get the
+ * ip_conntrack_expect that
+ * already exists so that I can
+ * update the .seq so that the
+ * nat module rewrites the port
+ * numbers?
+ * Perhaps I should use the
+ * exp_amanda_info instead of
+ * .seq.
+ */
+ }
+ UNLOCK_BH(&ip_amanda_lock);
+ } /* if memcmp(conns) */
+ } /* for .. NUM_MSGS */
+ data++;
+ } /* while (*data != 0x0a && data < data_limit) */
+
+ return NF_ACCEPT;
+}
+
+static struct ip_conntrack_helper amanda_helper;
+
+static void fini(void)
+{
+ DEBUGP("ip_ct_amanda: unregistering helper for port 10080\n");
+ ip_conntrack_helper_unregister(&amanda_helper);
+}
+
+static int __init init(void)
+{
+ int ret;
+
+ memset(&amanda_helper, 0, sizeof(struct ip_conntrack_helper));
+ amanda_helper.tuple.src.u.udp.port = htons(10080);
+ amanda_helper.tuple.dst.protonum = IPPROTO_UDP;
+ amanda_helper.mask.src.u.udp.port = 0xFFFF;
+ amanda_helper.mask.dst.protonum = 0xFFFF;
+ amanda_helper.max_expected = NUM_MSGS;
+ amanda_helper.timeout = 180;
+ amanda_helper.flags = IP_CT_HELPER_F_REUSE_EXPECT;
+ amanda_helper.me = ip_conntrack_amanda;
+ amanda_helper.help = help;
+ amanda_helper.name = "amanda";
+
+ DEBUGP("ip_ct_amanda: registering helper for port 10080\n");
+
+ ret = ip_conntrack_helper_register(&amanda_helper);
+
+ if (ret) {
+ printk("ip_ct_amanda: ERROR registering helper\n");
+ fini();
+ return -EBUSY;
+ }
+ return 0;
+}
+
+module_init(init);
+module_exit(fini);
diff --git a/net/ipv4/netfilter/ip_nat_amanda.c b/net/ipv4/netfilter/ip_nat_amanda.c
new file mode 100644
index 000000000000..d3e9ccb80641
--- /dev/null
+++ b/net/ipv4/netfilter/ip_nat_amanda.c
@@ -0,0 +1,226 @@
+/* Amanda extension for TCP NAT alteration.
+ * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
+ * based on a copy of HW's ip_nat_irc.c as well as other modules
+ *
+ * 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.
+ *
+ * Module load syntax:
+ * insmod ip_nat_amanda.o
+ */
+
+#include <linux/module.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/kernel.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+#include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_helper.h>
+#include <linux/netfilter_ipv4/ip_nat_rule.h>
+#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
+#include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
+
+
+#if 0
+#define DEBUGP printk
+#define DUMP_OFFSET(x) printk("offset_before=%d, offset_after=%d, correction_pos=%u\n", x->offset_before, x->offset_after, x->correction_pos);
+#else
+#define DEBUGP(format, args...)
+#define DUMP_OFFSET(x)
+#endif
+
+MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
+MODULE_DESCRIPTION("Amanda network address translation module");
+MODULE_LICENSE("GPL");
+
+/* protects amanda part of conntracks */
+DECLARE_LOCK_EXTERN(ip_amanda_lock);
+
+static unsigned int
+amanda_nat_expected(struct sk_buff **pskb,
+ unsigned int hooknum,
+ struct ip_conntrack *ct,
+ struct ip_nat_info *info)
+{
+ struct ip_nat_multi_range mr;
+ u_int32_t newdstip, newsrcip, newip;
+ u_int16_t port;
+ struct ip_ct_amanda_expect *exp_info;
+ struct ip_conntrack *master = master_ct(ct);
+
+ IP_NF_ASSERT(info);
+ IP_NF_ASSERT(master);
+
+ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
+
+ DEBUGP("nat_expected: We have a connection!\n");
+ exp_info = &ct->master->help.exp_amanda_info;
+
+ newdstip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
+ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
+ DEBUGP("nat_expected: %u.%u.%u.%u->%u.%u.%u.%u\n",
+ NIPQUAD(newsrcip), NIPQUAD(newdstip));
+
+ port = exp_info->port;
+
+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
+ newip = newsrcip;
+ else
+ newip = newdstip;
+
+ DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
+
+ mr.rangesize = 1;
+ /* We don't want to manip the per-protocol, just the IPs. */
+ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
+ mr.range[0].min_ip = mr.range[0].max_ip = newip;
+
+ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
+ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
+ mr.range[0].min = mr.range[0].max
+ = ((union ip_conntrack_manip_proto)
+ { htons(port) });
+ }
+
+ return ip_nat_setup_info(ct, &mr, hooknum);
+}
+
+static int amanda_data_fixup(struct ip_conntrack *ct,
+ struct sk_buff **pskb,
+ enum ip_conntrack_info ctinfo,
+ struct ip_conntrack_expect *expect)
+{
+ u_int32_t newip;
+ /* DATA 99999 MESG 99999 INDEX 99999 */
+ char buffer[6];
+ struct ip_conntrack_expect *exp = expect;
+ struct ip_ct_amanda_expect *ct_amanda_info = &exp->help.exp_amanda_info;
+ struct ip_conntrack_tuple t = exp->tuple;
+ int port;
+
+ MUST_BE_LOCKED(&ip_amanda_lock);
+
+ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
+ DEBUGP ("ip_nat_amanda_help: newip = %u.%u.%u.%u\n", NIPQUAD(newip));
+
+ /* Alter conntrack's expectations. */
+
+ /* We can read expect here without conntrack lock, since it's
+ only set in ip_conntrack_amanda, with ip_amanda_lock held
+ writable */
+
+ t.dst.ip = newip;
+ for (port = ct_amanda_info->port + 10; port != 0; port++) {
+ t.dst.u.tcp.port = htons(port);
+ if (ip_conntrack_change_expect(exp, &t) == 0)
+ break;
+ }
+
+ if (port == 0)
+ return 0;
+
+ sprintf(buffer, "%u", port);
+
+ return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, /* XXX exp->seq */ ct_amanda_info->offset,
+ ct_amanda_info->len, buffer, strlen(buffer));
+}
+
+static unsigned int help(struct ip_conntrack *ct,
+ struct ip_conntrack_expect *exp,
+ struct ip_nat_info *info,
+ enum ip_conntrack_info ctinfo,
+ unsigned int hooknum,
+ struct sk_buff **pskb)
+{
+ int dir;
+
+ if (!exp)
+ DEBUGP("ip_nat_amanda: no exp!!");
+
+ /* Only mangle things once: original direction in POST_ROUTING
+ and reply direction on PRE_ROUTING. */
+ dir = CTINFO2DIR(ctinfo);
+ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
+ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
+ DEBUGP("ip_nat_amanda_help: Not touching dir %s at hook %s\n",
+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
+ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
+ return NF_ACCEPT;
+ }
+ DEBUGP("ip_nat_amanda_help: got beyond not touching: dir %s at hook %s for expect: ",
+ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
+ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
+ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
+ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT"
+ : hooknum == NF_IP_LOCAL_IN ? "INPUT" : "???");
+ DUMP_TUPLE(&exp->tuple);
+
+ LOCK_BH(&ip_amanda_lock);
+// XXX if (exp->seq != 0)
+ if (exp->help.exp_amanda_info.offset != 0)
+ /* if this packet has a "seq" it needs to have it's content mangled */
+ if (!amanda_data_fixup(ct, pskb, ctinfo, exp)) {
+ UNLOCK_BH(&ip_amanda_lock);
+ DEBUGP("ip_nat_amanda: NF_DROP\n");
+ return NF_DROP;
+ }
+ exp->help.exp_amanda_info.offset = 0;
+ UNLOCK_BH(&ip_amanda_lock);
+
+ DEBUGP("ip_nat_amanda: NF_ACCEPT\n");
+ return NF_ACCEPT;
+}
+
+static struct ip_nat_helper ip_nat_amanda_helper;
+
+/* This function is intentionally _NOT_ defined as __exit, because
+ * it is needed by init() */
+static void fini(void)
+{
+ DEBUGP("ip_nat_amanda: unregistering nat helper\n");
+ ip_nat_helper_unregister(&ip_nat_amanda_helper);
+}
+
+static int __init init(void)
+{
+ int ret = 0;
+ struct ip_nat_helper *hlpr;
+
+ hlpr = &ip_nat_amanda_helper;
+ memset(hlpr, 0, sizeof(struct ip_nat_helper));
+
+ hlpr->tuple.dst.protonum = IPPROTO_UDP;
+ hlpr->tuple.src.u.udp.port = htons(10080);
+ hlpr->mask.src.u.udp.port = 0xFFFF;
+ hlpr->mask.dst.protonum = 0xFFFF;
+ hlpr->help = help;
+ hlpr->flags = 0;
+ hlpr->me = THIS_MODULE;
+ hlpr->expect = amanda_nat_expected;
+
+ hlpr->name = "amanda";
+
+ DEBUGP
+ ("ip_nat_amanda: Trying to register nat helper\n");
+ ret = ip_nat_helper_register(hlpr);
+
+ if (ret) {
+ printk
+ ("ip_nat_amanda: error registering nat helper\n");
+ fini();
+ return 1;
+ }
+ return ret;
+}
+
+
+module_init(init);
+module_exit(fini);