Commit 26b4fa1c authored by Patrick McHardy's avatar Patrick McHardy

[NETFILTER]: Fix amanda helpers, forward port from 2.4.x version.

parent 61e7d4eb
...@@ -2,20 +2,11 @@ ...@@ -2,20 +2,11 @@
#define _IP_CONNTRACK_AMANDA_H #define _IP_CONNTRACK_AMANDA_H
/* AMANDA tracking. */ /* AMANDA tracking. */
#ifdef __KERNEL__
#include <linux/netfilter_ipv4/lockhelp.h>
/* Protects amanda part of conntracks */
DECLARE_LOCK_EXTERN(ip_amanda_lock);
#endif
struct ip_ct_amanda_expect struct ip_ct_amanda_expect
{ {
u_int16_t port; /* port number of this expectation */ u_int16_t port; /* port number of this expectation */
u_int16_t offset; /* offset of the port specification in ctrl packet */ u_int16_t offset; /* offset of port in ctrl packet */
u_int16_t len; /* the length of the port number specification */ u_int16_t len; /* length of the port number string */
}; };
#endif /* _IP_CONNTRACK_AMANDA_H */ #endif /* _IP_CONNTRACK_AMANDA_H */
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
* *
*/ */
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
#include <linux/ip.h> #include <linux/ip.h>
...@@ -36,50 +37,37 @@ MODULE_LICENSE("GPL"); ...@@ -36,50 +37,37 @@ MODULE_LICENSE("GPL");
MODULE_PARM(master_timeout, "i"); MODULE_PARM(master_timeout, "i");
MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
DECLARE_LOCK(ip_amanda_lock); static char *conns[] = { "DATA ", "MESG ", "INDEX " };
char *conns[] = { "DATA ", "MESG ", "INDEX " };
#if 0
#define DEBUGP printk
#else
#define DEBUGP(format, args...)
#endif
/* This is slow, but it's simple. --RR */ /* This is slow, but it's simple. --RR */
static char amanda_buffer[65536]; static char amanda_buffer[65536];
static DECLARE_LOCK(amanda_buffer_lock);
static int help(struct sk_buff *skb, static int help(struct sk_buff *skb,
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{ {
char *data, *data_limit; struct ip_conntrack_expect exp;
int dir = CTINFO2DIR(ctinfo); struct ip_ct_amanda_expect *exp_amanda_info;
char *data, *data_limit, *tmp;
unsigned int dataoff, i; unsigned int dataoff, i;
struct ip_ct_amanda *info =
(struct ip_ct_amanda *)&ct->help.ct_ftp_info;
/* Can't track connections formed before we registered */ /* Only look at packets from the Amanda server */
if (!info) if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
return NF_ACCEPT; return NF_ACCEPT;
/* increase the UDP timeout of the master connection as replies from /* increase the UDP timeout of the master connection as replies from
* Amanda clients to the server can be quite delayed */ * Amanda clients to the server can be quite delayed */
ip_ct_refresh(ct, master_timeout * HZ); ip_ct_refresh(ct, master_timeout * HZ);
/* If packet is coming from Amanda server */
if (dir == IP_CT_DIR_ORIGINAL)
return NF_ACCEPT;
/* No data? */ /* No data? */
dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr); dataoff = skb->nh.iph->ihl*4 + sizeof(struct udphdr);
if (dataoff >= skb->len) { if (dataoff >= skb->len) {
if (net_ratelimit()) if (net_ratelimit())
printk("ip_conntrack_amanda_help: skblen = %u\n", printk("amanda_help: skblen = %u\n", skb->len);
(unsigned)skb->len);
return NF_ACCEPT; return NF_ACCEPT;
} }
LOCK_BH(&ip_amanda_lock); LOCK_BH(&amanda_buffer_lock);
skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff); skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff);
data = amanda_buffer; data = amanda_buffer;
data_limit = amanda_buffer + skb->len - dataoff; data_limit = amanda_buffer + skb->len - dataoff;
...@@ -89,84 +77,39 @@ static int help(struct sk_buff *skb, ...@@ -89,84 +77,39 @@ static int help(struct sk_buff *skb,
data = strstr(data, "CONNECT "); data = strstr(data, "CONNECT ");
if (!data) if (!data)
goto out; goto out;
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 += strlen("CONNECT "); data += strlen("CONNECT ");
memset(&exp, 0, sizeof(exp));
exp.tuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
exp.tuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
exp.tuple.dst.protonum = IPPROTO_TCP;
exp.mask.src.ip = 0xFFFFFFFF;
exp.mask.dst.ip = 0xFFFFFFFF;
exp.mask.dst.protonum = 0xFFFF;
exp.mask.dst.u.tcp.port = 0xFFFF;
/* Only search first line. */ /* Only search first line. */
if (strchr(data, '\n')) if ((tmp = strchr(data, '\n')))
*strchr(data, '\n') = '\0'; *tmp = '\0';
exp_amanda_info = &exp.help.exp_amanda_info;
for (i = 0; i < ARRAY_SIZE(conns); i++) { for (i = 0; i < ARRAY_SIZE(conns); i++) {
char *match = strstr(data, conns[i]); char *match = strstr(data, conns[i]);
if (match) { if (!match)
char *portchr; continue;
struct ip_conntrack_expect expect; tmp = data = match + strlen(conns[i]);
struct ip_ct_amanda_expect *exp_amanda_info = exp_amanda_info->offset = data - amanda_buffer;
&expect.help.exp_amanda_info; exp_amanda_info->port = simple_strtoul(data, &data, 10);
exp_amanda_info->len = data - tmp;
memset(&expect, 0, sizeof(expect)); if (exp_amanda_info->port == 0 || exp_amanda_info->len > 5)
break;
data += strlen(conns[i]);
/* this is not really tcp, but let's steal an exp.tuple.dst.u.tcp.port = htons(exp_amanda_info->port);
* idea from a tcp stream helper :-) */ ip_conntrack_expect_related(ct, &exp);
// XXX expect.seq = data - amanda_buffer;
exp_amanda_info->offset = data - amanda_buffer;
// XXX DEBUGP("expect.seq = %p - %p = %d\n", data, amanda_buffer, expect.seq);
DEBUGP("exp_amanda_info->offset = %p - %p = %d\n", data, amanda_buffer, 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],
exp_amanda_info->port);
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.
*/
}
}
} }
out:
UNLOCK_BH(&ip_amanda_lock); out:
UNLOCK_BH(&amanda_buffer_lock);
return NF_ACCEPT; return NF_ACCEPT;
} }
...@@ -186,29 +129,16 @@ static struct ip_conntrack_helper amanda_helper = { ...@@ -186,29 +129,16 @@ static struct ip_conntrack_helper amanda_helper = {
}, },
}; };
static void fini(void) static void __exit fini(void)
{ {
DEBUGP("ip_ct_amanda: unregistering helper for port 10080\n");
ip_conntrack_helper_unregister(&amanda_helper); ip_conntrack_helper_unregister(&amanda_helper);
} }
static int __init init(void) static int __init init(void)
{ {
int ret; return ip_conntrack_helper_register(&amanda_helper);
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;
} }
PROVIDES_CONNTRACK(amanda); PROVIDES_CONNTRACK(amanda);
EXPORT_SYMBOL(ip_amanda_lock);
module_init(init); module_init(init);
module_exit(fini); module_exit(fini);
...@@ -11,69 +11,45 @@ ...@@ -11,69 +11,45 @@
* insmod ip_nat_amanda.o * insmod ip_nat_amanda.o
*/ */
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netfilter_ipv4.h> #include <linux/netfilter.h>
#include <linux/skbuff.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/udp.h> #include <linux/udp.h>
#include <linux/kernel.h>
#include <net/tcp.h> #include <net/tcp.h>
#include <net/udp.h> #include <net/udp.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv4/ip_nat.h> #include <linux/netfilter_ipv4/ip_nat.h>
#include <linux/netfilter_ipv4/ip_nat_helper.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_helper.h>
#include <linux/netfilter_ipv4/ip_conntrack_amanda.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_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
MODULE_DESCRIPTION("Amanda NAT helper"); MODULE_DESCRIPTION("Amanda NAT helper");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* protects amanda part of conntracks */
DECLARE_LOCK_EXTERN(ip_amanda_lock);
static unsigned int static unsigned int
amanda_nat_expected(struct sk_buff **pskb, amanda_nat_expected(struct sk_buff **pskb,
unsigned int hooknum, unsigned int hooknum,
struct ip_conntrack *ct, struct ip_conntrack *ct,
struct ip_nat_info *info) 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); struct ip_conntrack *master = master_ct(ct);
struct ip_ct_amanda_expect *exp_amanda_info;
struct ip_nat_multi_range mr;
u_int32_t newip;
IP_NF_ASSERT(info); IP_NF_ASSERT(info);
IP_NF_ASSERT(master); IP_NF_ASSERT(master);
IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); 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) if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
newip = newsrcip; newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
else else
newip = newdstip; newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
DEBUGP("nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip));
mr.rangesize = 1; mr.rangesize = 1;
/* We don't want to manip the per-protocol, just the IPs. */ /* We don't want to manip the per-protocol, just the IPs. */
...@@ -81,121 +57,79 @@ amanda_nat_expected(struct sk_buff **pskb, ...@@ -81,121 +57,79 @@ amanda_nat_expected(struct sk_buff **pskb,
mr.range[0].min_ip = mr.range[0].max_ip = newip; mr.range[0].min_ip = mr.range[0].max_ip = newip;
if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
exp_amanda_info = &ct->master->help.exp_amanda_info;
mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
mr.range[0].min = mr.range[0].max mr.range[0].min = mr.range[0].max
= ((union ip_conntrack_manip_proto) = ((union ip_conntrack_manip_proto)
{ .udp = { htons(port) } }); { .udp = { htons(exp_amanda_info->port) } });
} }
return ip_nat_setup_info(ct, &mr, hooknum); return ip_nat_setup_info(ct, &mr, hooknum);
} }
static int amanda_data_fixup(struct ip_conntrack *ct, static int amanda_data_fixup(struct ip_conntrack *ct,
struct sk_buff **pskb, struct sk_buff **pskb,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
struct ip_conntrack_expect *expect) struct ip_conntrack_expect *exp)
{ {
u_int32_t newip; struct ip_ct_amanda_expect *exp_amanda_info;
/* 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; struct ip_conntrack_tuple t = exp->tuple;
char buffer[sizeof("65535")];
u_int16_t port; u_int16_t 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. */ /* Alter conntrack's expectations. */
exp_amanda_info = &exp->help.exp_amanda_info;
/* We can read expect here without conntrack lock, since it's t.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
only set in ip_conntrack_amanda, with ip_amanda_lock held for (port = exp_amanda_info->port; port != 0; port++) {
writable */
t.dst.ip = newip;
for (port = ct_amanda_info->port; port != 0; port++) {
t.dst.u.tcp.port = htons(port); t.dst.u.tcp.port = htons(port);
if (ip_conntrack_change_expect(exp, &t) == 0) if (ip_conntrack_change_expect(exp, &t) == 0)
break; break;
} }
if (port == 0) if (port == 0)
return 0; return 0;
sprintf(buffer, "%u", port); sprintf(buffer, "%u", port);
return ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
return ip_nat_mangle_udp_packet(pskb, ct, ctinfo, /* XXX exp->seq */ ct_amanda_info->offset, exp_amanda_info->offset,
ct_amanda_info->len, buffer, strlen(buffer)); exp_amanda_info->len,
buffer, strlen(buffer));
} }
static unsigned int help(struct ip_conntrack *ct, static unsigned int help(struct ip_conntrack *ct,
struct ip_conntrack_expect *exp, struct ip_conntrack_expect *exp,
struct ip_nat_info *info, struct ip_nat_info *info,
enum ip_conntrack_info ctinfo, enum ip_conntrack_info ctinfo,
unsigned int hooknum, unsigned int hooknum,
struct sk_buff **pskb) struct sk_buff **pskb)
{ {
int dir; int dir = CTINFO2DIR(ctinfo);
int ret = NF_ACCEPT;
if (!exp)
DEBUGP("ip_nat_amanda: no exp!!");
/* Only mangle things once: original direction in POST_ROUTING /* Only mangle things once: original direction in POST_ROUTING
and reply direction on PRE_ROUTING. */ and reply direction on PRE_ROUTING. */
dir = CTINFO2DIR(ctinfo);
if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
|| (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { || (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; return NF_ACCEPT;
}
DEBUGP("ip_nat_amanda_help: got beyond not touching: dir %s at hook %s for expect: ", /* if this exectation has a "offset" the packet needs to be mangled */
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 (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))
if (!amanda_data_fixup(ct, pskb, ctinfo, exp)) { ret = NF_DROP;
UNLOCK_BH(&ip_amanda_lock);
DEBUGP("ip_nat_amanda: NF_DROP\n");
return NF_DROP;
}
exp->help.exp_amanda_info.offset = 0; exp->help.exp_amanda_info.offset = 0;
UNLOCK_BH(&ip_amanda_lock);
DEBUGP("ip_nat_amanda: NF_ACCEPT\n"); return ret;
return NF_ACCEPT;
} }
static struct ip_nat_helper ip_nat_amanda_helper; static struct ip_nat_helper ip_nat_amanda_helper;
/* This function is intentionally _NOT_ defined as __exit, because static void __exit fini(void)
* 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); ip_nat_helper_unregister(&ip_nat_amanda_helper);
} }
static int __init init(void) static int __init init(void)
{ {
int ret = 0; struct ip_nat_helper *hlpr = &ip_nat_amanda_helper;
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.dst.protonum = IPPROTO_UDP;
hlpr->tuple.src.u.udp.port = htons(10080); hlpr->tuple.src.u.udp.port = htons(10080);
...@@ -205,20 +139,9 @@ static int __init init(void) ...@@ -205,20 +139,9 @@ static int __init init(void)
hlpr->flags = 0; hlpr->flags = 0;
hlpr->me = THIS_MODULE; hlpr->me = THIS_MODULE;
hlpr->expect = amanda_nat_expected; hlpr->expect = amanda_nat_expected;
hlpr->name = "amanda"; hlpr->name = "amanda";
DEBUGP return ip_nat_helper_register(hlpr);
("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;
} }
NEEDS_CONNTRACK(amanda); NEEDS_CONNTRACK(amanda);
......
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