diff options
| author | Brian J. Murrell <netfilter@interlinx.bc.ca> | 2003-03-30 23:40:07 -0800 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2003-03-30 23:40:07 -0800 |
| commit | 017091704fc496fd59f49591d09165984dc3cbb5 (patch) | |
| tree | f6004c16a1e57c64ce49c8896c3f27b44978f2cf | |
| parent | b3a3a32973d95963d9cd806d9d7046830dca202b (diff) | |
[NETFILTER]: Add amanda conntrack + NAT support.
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack.h | 2 | ||||
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack_amanda.h | 29 | ||||
| -rw-r--r-- | net/ipv4/netfilter/Kconfig | 20 | ||||
| -rw-r--r-- | net/ipv4/netfilter/Makefile | 6 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_amanda.c | 233 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_nat_amanda.c | 226 |
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); |
