1/* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu> 2 * (C) 2006-2012 Patrick McHardy <kaber@trash.net> 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 nf_ct_helper_log(skb, ct, "cannot alloc expectation"); 65 return NF_DROP; 66 } 67 tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; 68 nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, 69 nf_ct_l3num(ct), 70 &tuple->src.u3, &tuple->dst.u3, 71 IPPROTO_UDP, NULL, &tuple->dst.u.udp.port); 72 73 pr_debug("expect: "); 74 nf_ct_dump_tuple(&exp->tuple); 75 76 nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook); 77 if (nf_nat_tftp && ct->status & IPS_NAT_MASK) 78 ret = nf_nat_tftp(skb, ctinfo, exp); 79 else if (nf_ct_expect_related(exp) != 0) { 80 nf_ct_helper_log(skb, ct, "cannot add expectation"); 81 ret = NF_DROP; 82 } 83 nf_ct_expect_put(exp); 84 break; 85 case TFTP_OPCODE_DATA: 86 case TFTP_OPCODE_ACK: 87 pr_debug("Data/ACK opcode\n"); 88 break; 89 case TFTP_OPCODE_ERROR: 90 pr_debug("Error opcode\n"); 91 break; 92 default: 93 pr_debug("Unknown opcode\n"); 94 } 95 return ret; 96} 97 98static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly; 99 100static const struct nf_conntrack_expect_policy tftp_exp_policy = { 101 .max_expected = 1, 102 .timeout = 5 * 60, 103}; 104 105static void nf_conntrack_tftp_fini(void) 106{ 107 int i, j; 108 109 for (i = 0; i < ports_c; i++) { 110 for (j = 0; j < 2; j++) 111 nf_conntrack_helper_unregister(&tftp[i][j]); 112 } 113} 114 115static int __init nf_conntrack_tftp_init(void) 116{ 117 int i, j, ret; 118 119 if (ports_c == 0) 120 ports[ports_c++] = TFTP_PORT; 121 122 for (i = 0; i < ports_c; i++) { 123 memset(&tftp[i], 0, sizeof(tftp[i])); 124 125 tftp[i][0].tuple.src.l3num = AF_INET; 126 tftp[i][1].tuple.src.l3num = AF_INET6; 127 for (j = 0; j < 2; j++) { 128 tftp[i][j].tuple.dst.protonum = IPPROTO_UDP; 129 tftp[i][j].tuple.src.u.udp.port = htons(ports[i]); 130 tftp[i][j].expect_policy = &tftp_exp_policy; 131 tftp[i][j].me = THIS_MODULE; 132 tftp[i][j].help = tftp_help; 133 134 if (ports[i] == TFTP_PORT) 135 sprintf(tftp[i][j].name, "tftp"); 136 else 137 sprintf(tftp[i][j].name, "tftp-%u", i); 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