Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 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);
|