1/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu> 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 as 5 * published by the Free Software Foundation. 6 */ 7 8#include <linux/module.h> 9#include <linux/moduleparam.h> 10#include <linux/in.h> 11#include <linux/udp.h> 12#include <linux/netfilter.h> 13 14#include <net/netfilter/nf_conntrack.h> 15#include <net/netfilter/nf_conntrack_tuple.h> 16#include <net/netfilter/nf_conntrack_expect.h> 17#include <net/netfilter/nf_conntrack_ecache.h> 18#include <net/netfilter/nf_conntrack_helper.h> 19#include <linux/netfilter/nf_conntrack_tftp.h> 20 21MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); 22MODULE_DESCRIPTION("TFTP connection tracking helper"); 23MODULE_LICENSE("GPL"); 24MODULE_ALIAS("ip_conntrack_tftp"); 25MODULE_ALIAS_NFCT_HELPER("tftp"); 26 27#define MAX_PORTS 8 28static unsigned short ports[MAX_PORTS]; 29static unsigned int ports_c; 30module_param_array(ports, ushort, &ports_c, 0400); 31MODULE_PARM_DESC(ports, "Port numbers of TFTP servers"); 32 33unsigned int (*nf_nat_tftp_hook)(struct sk_buff *skb, 34 enum ip_conntrack_info ctinfo, 35 struct nf_conntrack_expect *exp) __read_mostly; 36EXPORT_SYMBOL_GPL(nf_nat_tftp_hook); 37 38static int tftp_help(struct sk_buff *skb, 39 unsigned int protoff, 40 struct nf_conn *ct, 41 enum ip_conntrack_info ctinfo) 42{ 43 const struct tftphdr *tfh; 44 struct tftphdr _tftph; 45 struct nf_conntrack_expect *exp; 46 struct nf_conntrack_tuple *tuple; 47 unsigned int ret = NF_ACCEPT; 48 typeof(nf_nat_tftp_hook) nf_nat_tftp; 49 50 tfh = skb_header_pointer(skb, protoff + sizeof(struct udphdr), 51 sizeof(_tftph), &_tftph); 52 if (tfh == NULL) 53 return NF_ACCEPT; 54 55 switch (ntohs(tfh->opcode)) { 56 case TFTP_OPCODE_READ: 57 case TFTP_OPCODE_WRITE: 58 /* RRQ and WRQ works the same way */ 59 nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 60 nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 61 62 exp = nf_ct_expect_alloc(ct); 63 if (exp == NULL) 64 return NF_DROP; 65 tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; 66 nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, 67 nf_ct_l3num(ct), 68 &tuple->src.u3, &tuple->dst.u3, 69 IPPROTO_UDP, NULL, &tuple->dst.u.udp.port); 70 71 pr_debug("expect: "); 72 nf_ct_dump_tuple(&exp->tuple); 73 74 nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook); 75 if (nf_nat_tftp && ct->status & IPS_NAT_MASK) 76 ret = nf_nat_tftp(skb, ctinfo, exp); 77 else if (nf_ct_expect_related(exp) != 0) 78 ret = NF_DROP; 79 nf_ct_expect_put(exp); 80 break; 81 case TFTP_OPCODE_DATA: 82 case TFTP_OPCODE_ACK: 83 pr_debug("Data/ACK opcode\n"); 84 break; 85 case TFTP_OPCODE_ERROR: 86 pr_debug("Error opcode\n"); 87 break; 88 default: 89 pr_debug("Unknown opcode\n"); 90 } 91 return ret; 92} 93 94static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly; 95static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly; 96 97static const struct nf_conntrack_expect_policy tftp_exp_policy = { 98 .max_expected = 1, 99 .timeout = 5 * 60, 100}; 101 102static void nf_conntrack_tftp_fini(void) 103{ 104 int i, j; 105 106 for (i = 0; i < ports_c; i++) { 107 for (j = 0; j < 2; j++) 108 nf_conntrack_helper_unregister(&tftp[i][j]); 109 } 110} 111 112static int __init nf_conntrack_tftp_init(void) 113{ 114 int i, j, ret; 115 char *tmpname; 116 117 if (ports_c == 0) 118 ports[ports_c++] = TFTP_PORT; 119 120 for (i = 0; i < ports_c; i++) { 121 memset(&tftp[i], 0, sizeof(tftp[i])); 122 123 tftp[i][0].tuple.src.l3num = AF_INET; 124 tftp[i][1].tuple.src.l3num = AF_INET6; 125 for (j = 0; j < 2; j++) { 126 tftp[i][j].tuple.dst.protonum = IPPROTO_UDP; 127 tftp[i][j].tuple.src.u.udp.port = htons(ports[i]); 128 tftp[i][j].expect_policy = &tftp_exp_policy; 129 tftp[i][j].me = THIS_MODULE; 130 tftp[i][j].help = tftp_help; 131 132 tmpname = &tftp_names[i][j][0]; 133 if (ports[i] == TFTP_PORT) 134 sprintf(tmpname, "tftp"); 135 else 136 sprintf(tmpname, "tftp-%u", i); 137 tftp[i][j].name = tmpname; 138 139 ret = nf_conntrack_helper_register(&tftp[i][j]); 140 if (ret) { 141 printk(KERN_ERR "nf_ct_tftp: failed to register" 142 " helper for pf: %u port: %u\n", 143 tftp[i][j].tuple.src.l3num, ports[i]); 144 nf_conntrack_tftp_fini(); 145 return ret; 146 } 147 } 148 } 149 return 0; 150} 151 152module_init(nf_conntrack_tftp_init); 153module_exit(nf_conntrack_tftp_fini); 154