diff options
| -rw-r--r-- | include/linux/netfilter_ipv4/ip_conntrack_tftp.h | 13 | ||||
| -rw-r--r-- | net/ipv4/netfilter/Kconfig | 22 | ||||
| -rw-r--r-- | net/ipv4/netfilter/Makefile | 2 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_conntrack_tftp.c | 131 | ||||
| -rw-r--r-- | net/ipv4/netfilter/ip_nat_tftp.c | 197 |
5 files changed, 363 insertions, 2 deletions
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tftp.h b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h new file mode 100644 index 000000000000..7a68bafaac2d --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_conntrack_tftp.h @@ -0,0 +1,13 @@ +#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 */ diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index ff7687cc6f94..77d6472f3cca 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -44,8 +44,20 @@ config IP_NF_IRC chats. Note that you do NOT need this extension to get files or have others initiate chats, or everything else in IRC. - If you want to compile it as a module, say 'M' here and read - Documentation/modules.txt. If unsure, say 'N'. + 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_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 tristate "Userspace queueing via NETLINK (EXPERIMENTAL)" @@ -380,6 +392,12 @@ config IP_NF_NAT_FTP default IP_NF_NAT if IP_NF_FTP=y 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 tristate "Packet mangling" depends on IP_NF_IPTABLES diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 1e6682d4b161..342ea3b7e83a 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -20,6 +20,7 @@ ipchains-objs := $(ip_nf_compat-objs) ipchains_core.o obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o # connection tracking helpers +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 @@ -28,6 +29,7 @@ ifdef CONFIG_IP_NF_NAT_IRC endif # 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_IRC) += ip_nat_irc.o diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c new file mode 100644 index 000000000000..f75910aa0652 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c @@ -0,0 +1,131 @@ +/* + * 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); diff --git a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c new file mode 100644 index 000000000000..70a6fb4d346a --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_tftp.c @@ -0,0 +1,197 @@ +/* + * 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); |
