1/* 2 * Licensed under GNU GPL version 2 Copyright Magnus Boden <mb@ozaba.mine.nu> 3 * Version: 0.0.7 4 * 5 * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org> 6 * - Port to newnat API 7 * 8 * This module currently supports DNAT: 9 * iptables -t nat -A PREROUTING -d x.x.x.x -j DNAT --to-dest x.x.x.y 10 * 11 * and SNAT: 12 * iptables -t nat -A POSTROUTING { -j MASQUERADE , -j SNAT --to-source x.x.x.x } 13 * 14 * It has not been tested with 15 * -j SNAT --to-source x.x.x.x-x.x.x.y since I only have one external ip 16 * If you do test this please let me know if it works or not. 17 * 18 */ 19 20#include <linux/module.h> 21#include <linux/netfilter_ipv4.h> 22#include <linux/ip.h> 23#include <linux/udp.h> 24 25#include <linux/netfilter.h> 26#include <linux/netfilter_ipv4/ip_tables.h> 27#include <linux/netfilter_ipv4/ip_conntrack_helper.h> 28#include <linux/netfilter_ipv4/ip_conntrack_tftp.h> 29#include <linux/netfilter_ipv4/ip_nat_helper.h> 30#include <linux/netfilter_ipv4/ip_nat_rule.h> 31 32MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); 33MODULE_DESCRIPTION("Netfilter NAT helper for tftp"); 34MODULE_LICENSE("GPL"); 35 36#define MAX_PORTS 8 37 38static int ports[MAX_PORTS]; 39static int ports_c = 0; 40#ifdef MODULE_PARM 41MODULE_PARM(ports,"1-" __MODULE_STRING(MAX_PORTS) "i"); 42MODULE_PARM_DESC(ports, "port numbers of tftp servers"); 43#endif 44 45#define DEBUGP(format, args...) 46static unsigned int 47tftp_nat_help(struct ip_conntrack *ct, 48 struct ip_conntrack_expect *exp, 49 struct ip_nat_info *info, 50 enum ip_conntrack_info ctinfo, 51 unsigned int hooknum, 52 struct sk_buff **pskb) 53{ 54 int dir = CTINFO2DIR(ctinfo); 55 struct iphdr *iph = (*pskb)->nh.iph; 56 struct udphdr *udph = (void *)iph + iph->ihl * 4; 57 struct tftphdr *tftph = (void *)udph + 8; 58 struct ip_conntrack_tuple repl; 59 60 if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) 61 || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) 62 return NF_ACCEPT; 63 64 if (!exp) { 65 DEBUGP("no conntrack expectation to modify\n"); 66 return NF_ACCEPT; 67 } 68 69 switch (ntohs(tftph->opcode)) { 70 /* RRQ and WRQ works the same way */ 71 case TFTP_OPCODE_READ: 72 case TFTP_OPCODE_WRITE: 73 repl = ct->tuplehash[IP_CT_DIR_REPLY].tuple; 74 DEBUGP(""); 75 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 76 DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 77 DEBUGP("expecting: "); 78 DUMP_TUPLE_RAW(&repl); 79 DUMP_TUPLE_RAW(&exp->mask); 80 ip_conntrack_change_expect(exp, &repl); 81 break; 82 default: 83 DEBUGP("Unknown opcode\n"); 84 } 85 86 return NF_ACCEPT; 87} 88 89static unsigned int 90tftp_nat_expected(struct sk_buff **pskb, 91 unsigned int hooknum, 92 struct ip_conntrack *ct, 93 struct ip_nat_info *info) 94{ 95 const struct ip_conntrack *master = ct->master->expectant; 96 const struct ip_conntrack_tuple *orig = 97 &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple; 98 struct ip_nat_multi_range mr; 99 100 IP_NF_ASSERT(info); 101 IP_NF_ASSERT(master); 102 IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); 103 104 mr.rangesize = 1; 105 mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; 106 107 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) { 108 mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip; 109 DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " 110 "newsrc: %u.%u.%u.%u\n", 111 NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), 112 NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), 113 NIPQUAD(orig->dst.ip)); 114 } else { 115 mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip; 116 mr.range[0].min.udp.port = mr.range[0].max.udp.port = 117 orig->src.u.udp.port; 118 mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; 119 120 DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u " 121 "newdst: %u.%u.%u.%u:%u\n", 122 NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source), 123 NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest), 124 NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port)); 125 } 126 127 return ip_nat_setup_info(ct,&mr,hooknum); 128} 129 130static struct ip_nat_helper tftp[MAX_PORTS]; 131static char tftp_names[MAX_PORTS][10]; 132 133static void fini(void) 134{ 135 int i; 136 137 for (i = 0 ; i < ports_c; i++) { 138 DEBUGP("unregistering helper for port %d\n", ports[i]); 139 ip_nat_helper_unregister(&tftp[i]); 140 } 141} 142 143static int __init init(void) 144{ 145 int i, ret; 146 char *tmpname; 147 148 if (!ports[0]) 149 ports[0] = TFTP_PORT; 150 151 for (i = 0 ; (i < MAX_PORTS) && ports[i] ; i++) { 152 memset(&tftp[i], 0, sizeof(struct ip_nat_helper)); 153 154 tftp[i].tuple.dst.protonum = IPPROTO_UDP; 155 tftp[i].tuple.src.u.udp.port = htons(ports[i]); 156 tftp[i].mask.dst.protonum = 0xFFFF; 157 tftp[i].mask.src.u.udp.port = 0xFFFF; 158 tftp[i].help = tftp_nat_help; 159 tftp[i].flags = 0; 160 tftp[i].me = THIS_MODULE; 161 tftp[i].expect = tftp_nat_expected; 162 163 tmpname = &tftp_names[i][0]; 164 if (ports[i] == TFTP_PORT) 165 sprintf(tmpname, "tftp"); 166 else 167 sprintf(tmpname, "tftp-%d", i); 168 tftp[i].name = tmpname; 169 170 DEBUGP("ip_nat_tftp: registering for port %d: name %s\n", 171 ports[i], tftp[i].name); 172 ret = ip_nat_helper_register(&tftp[i]); 173 174 if (ret) { 175 printk("ip_nat_tftp: unable to register for port %d\n", 176 ports[i]); 177 fini(); 178 return ret; 179 } 180 ports_c++; 181 } 182 return ret; 183} 184 185module_init(init); 186module_exit(fini); 187