Commit b3a3a329 authored by Magnus Boden's avatar Magnus Boden Committed by David S. Miller

[NETFILTER]: Add tftp conntrack + NAT support.

parent 95e329cb
#ifndef _IP_CT_TFTP
#define _IP_CT_TFTP
#define TFTP_PORT 69
struct tftphdr {
u_int16_t opcode;
};
#define TFTP_OPCODE_READ 1
#define TFTP_OPCODE_WRITE 2
#endif /* _IP_CT_TFTP */
...@@ -44,8 +44,20 @@ config IP_NF_IRC ...@@ -44,8 +44,20 @@ config IP_NF_IRC
chats. Note that you do NOT need this extension to get files or chats. Note that you do NOT need this extension to get files or
have others initiate chats, or everything else in IRC. have others initiate chats, or everything else in IRC.
If you want to compile it as a module, say 'M' here and read If you want to compile it as a module, say M here and read
Documentation/modules.txt. If unsure, say 'N'. <file:Documentation/modules.txt>. If unsure, say `Y'.
config IP_NF_TFTP
tristate "TFTP prtocol support"
depends on IP_NF_CONNTRACK
help
TFTP connection tracking helper, this is required depending
on how restrictive your ruleset is.
If you are using a tftp client behind -j SNAT or -j MASQUERADING
you will need this.
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 config IP_NF_QUEUE
tristate "Userspace queueing via NETLINK (EXPERIMENTAL)" tristate "Userspace queueing via NETLINK (EXPERIMENTAL)"
...@@ -380,6 +392,12 @@ config IP_NF_NAT_FTP ...@@ -380,6 +392,12 @@ config IP_NF_NAT_FTP
default IP_NF_NAT if IP_NF_FTP=y default IP_NF_NAT if IP_NF_FTP=y
default m if IP_NF_FTP=m default m if IP_NF_FTP=m
config IP_NF_NAT_TFTP
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 config IP_NF_MANGLE
tristate "Packet mangling" tristate "Packet mangling"
depends on IP_NF_IPTABLES depends on IP_NF_IPTABLES
......
...@@ -20,6 +20,7 @@ ipchains-objs := $(ip_nf_compat-objs) ipchains_core.o ...@@ -20,6 +20,7 @@ ipchains-objs := $(ip_nf_compat-objs) ipchains_core.o
obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o
# connection tracking helpers # connection tracking helpers
obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o
obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o
ifdef CONFIG_IP_NF_NAT_FTP ifdef CONFIG_IP_NF_NAT_FTP
endif endif
...@@ -28,6 +29,7 @@ ifdef CONFIG_IP_NF_NAT_IRC ...@@ -28,6 +29,7 @@ ifdef CONFIG_IP_NF_NAT_IRC
endif endif
# NAT helpers # NAT helpers
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_FTP) += ip_nat_ftp.o
obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
......
/*
* Licensed under GNU GPL version 2 Copyright Magnus Boden <mb@ozaba.mine.nu>
* Version: 0.0.7
*
* Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
* - port to newnat API
*
*/
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
MODULE_DESCRIPTION("Netfilter connection tracking module for tftp");
MODULE_LICENSE("GPL");
#define MAX_PORTS 8
static int ports[MAX_PORTS];
static int ports_c = 0;
#ifdef MODULE_PARM
MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
MODULE_PARM_DESC(ports, "port numbers of tftp servers");
#endif
#if 0
#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ": " \
format, ## args)
#else
#define DEBUGP(format, args...)
#endif
static int tftp_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;
struct tftphdr *tftph = (void *)udph + 8;
struct ip_conntrack_expect exp;
switch (ntohs(tftph->opcode)) {
/* RRQ and WRQ works the same way */
case TFTP_OPCODE_READ:
case TFTP_OPCODE_WRITE:
DEBUGP("");
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
memset(&exp, 0, sizeof(exp));
exp.tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
exp.mask.src.ip = 0xffffffff;
exp.mask.dst.ip = 0xffffffff;
exp.mask.dst.u.udp.port = 0xffff;
exp.mask.dst.protonum = 0xffff;
exp.expectfn = NULL;
DEBUGP("expect: ");
DUMP_TUPLE(&exp.tuple);
DUMP_TUPLE(&exp.mask);
ip_conntrack_expect_related(ct, &exp);
break;
default:
DEBUGP("Unknown opcode\n");
}
return NF_ACCEPT;
}
static struct ip_conntrack_helper tftp[MAX_PORTS];
static char tftp_names[MAX_PORTS][10];
static void fini(void)
{
int i;
for (i = 0 ; i < ports_c; i++) {
DEBUGP("unregistering helper for port %d\n",
ports[i]);
ip_conntrack_helper_unregister(&tftp[i]);
}
}
static int __init init(void)
{
int i, ret;
char *tmpname;
if (!ports[0])
ports[0]=TFTP_PORT;
for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
/* Create helper structure */
memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper));
tftp[i].tuple.dst.protonum = IPPROTO_UDP;
tftp[i].tuple.src.u.udp.port = htons(ports[i]);
tftp[i].mask.dst.protonum = 0xFFFF;
tftp[i].mask.src.u.udp.port = 0xFFFF;
tftp[i].max_expected = 1;
tftp[i].timeout = 0;
tftp[i].flags = IP_CT_HELPER_F_REUSE_EXPECT;
tftp[i].me = THIS_MODULE;
tftp[i].help = tftp_help;
tmpname = &tftp_names[i][0];
if (ports[i] == TFTP_PORT)
sprintf(tmpname, "tftp");
else
sprintf(tmpname, "tftp-%d", i);
tftp[i].name = tmpname;
DEBUGP("port #%d: %d\n", i, ports[i]);
ret=ip_conntrack_helper_register(&tftp[i]);
if (ret) {
printk("ERROR registering helper for port %d\n",
ports[i]);
fini();
return(ret);
}
ports_c++;
}
return(0);
}
module_init(init);
module_exit(fini);
/*
* Licensed under GNU GPL version 2 Copyright Magnus Boden <mb@ozaba.mine.nu>
* Version: 0.0.7
*
* Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org>
* - Port to newnat API
*
* This module currently supports DNAT:
* iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y
*
* and SNAT:
* iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x }
*
* It has not been tested with
* -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip
* If you do test this please let me know if it works or not.
*
*/
#include <linux/module.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_conntrack_tftp.h>
#include <linux/netfilter_ipv4/ip_nat_helper.h>
#include <linux/netfilter_ipv4/ip_nat_rule.h>
MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
MODULE_DESCRIPTION("Netfilter NAT helper for tftp");
MODULE_LICENSE("GPL");
#define MAX_PORTS 8
static int ports[MAX_PORTS];
static int ports_c = 0;
#ifdef MODULE_PARM
MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i");
MODULE_PARM_DESC(ports, "port numbers of tftp servers");
#endif
#if 0
#define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ": " \
format, ## args)
#else
#define DEBUGP(format, args...)
#endif
static unsigned int
tftp_nat_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 = CTINFO2DIR(ctinfo);
struct iphdr *iph = (*pskb)->nh.iph;
struct udphdr *udph = (void *)iph + iph->ihl * 4;
struct tftphdr *tftph = (void *)udph + 8;
struct ip_conntrack_tuple repl;
if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
|| (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
return NF_ACCEPT;
if (!exp) {
DEBUGP("no conntrack expectation to modify\n");
return NF_ACCEPT;
}
switch (ntohs(tftph->opcode)) {
/* RRQ and WRQ works the same way */
case TFTP_OPCODE_READ:
case TFTP_OPCODE_WRITE:
repl = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
DEBUGP("");
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
DEBUGP("expecting: ");
DUMP_TUPLE(&repl);
DUMP_TUPLE(&exp->mask);
ip_conntrack_change_expect(exp, &repl);
break;
default:
DEBUGP("Unknown opcode\n");
}
return NF_ACCEPT;
}
static unsigned int
tftp_nat_expected(struct sk_buff **pskb,
unsigned int hooknum,
struct ip_conntrack *ct,
struct ip_nat_info *info)
{
const struct ip_conntrack *master = ct->master->expectant;
const struct ip_conntrack_tuple *orig =
&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
struct ip_nat_multi_range mr;
#if 0
const struct ip_conntrack_tuple *repl =
&master->tuplehash[IP_CT_DIR_REPLY].tuple;
struct iphdr *iph = (*pskb)->nh.iph;
struct udphdr *udph = (void *)iph + iph->ihl*4;
#endif
IP_NF_ASSERT(info);
IP_NF_ASSERT(master);
IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
mr.rangesize = 1;
mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) {
mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip;
DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
"newsrc: %u.%u.%u.%u\n",
NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
NIPQUAD(orig->dst.ip));
} else {
mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip;
mr.range[0].min.udp.port = mr.range[0].max.udp.port =
orig->src.u.udp.port;
mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
"newdst: %u.%u.%u.%u:%u\n",
NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port));
}
return ip_nat_setup_info(ct,&mr,hooknum);
}
static struct ip_nat_helper tftp[MAX_PORTS];
static char tftp_names[MAX_PORTS][10];
static void fini(void)
{
int i;
for (i = 0 ; i < ports_c; i++) {
DEBUGP("unregistering helper for port %d\n", ports[i]);
ip_nat_helper_unregister(&tftp[i]);
}
}
static int __init init(void)
{
int i, ret;
char *tmpname;
if (!ports[0])
ports[0] = TFTP_PORT;
for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) {
memset(&tftp[i], 0, sizeof(struct ip_nat_helper));
tftp[i].tuple.dst.protonum = IPPROTO_UDP;
tftp[i].tuple.src.u.udp.port = htons(ports[i]);
tftp[i].mask.dst.protonum = 0xFFFF;
tftp[i].mask.src.u.udp.port = 0xFFFF;
tftp[i].help = tftp_nat_help;
tftp[i].flags = 0;
tftp[i].me = THIS_MODULE;
tftp[i].expect = tftp_nat_expected;
tmpname = &tftp_names[i][0];
if (ports[i] == TFTP_PORT)
sprintf(tmpname, "tftp");
else
sprintf(tmpname, "tftp-%d", i);
tftp[i].name = tmpname;
DEBUGP("ip_nat_tftp: registering for port %d: name %s\n",
ports[i], tftp[i].name);
ret = ip_nat_helper_register(&tftp[i]);
if (ret) {
printk("ip_nat_tftp: unable to register for port %d\n",
ports[i]);
fini();
return ret;
}
ports_c++;
}
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