Commit 01709170 authored by Brian J. Murrell's avatar Brian J. Murrell Committed by David S. Miller

[NETFILTER]: Add amanda conntrack + NAT support.

parent b3a3a329
......@@ -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;
......
#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 */
......@@ -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
......
......@@ -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
......
/* 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);
/* 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);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment