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"); 25 26#define MAX_PORTS 8 27static unsigned short ports[MAX_PORTS]; 28static int ports_c; 29module_param_array(ports, ushort, &ports_c, 0400); 30MODULE_PARM_DESC(ports, "Port numbers of TFTP servers"); 31 32#define DEBUGP(format, args...) 33 34unsigned int (*nf_nat_tftp_hook)(struct sk_buff **pskb, 35 enum ip_conntrack_info ctinfo, 36 struct nf_conntrack_expect *exp) __read_mostly; 37EXPORT_SYMBOL_GPL(nf_nat_tftp_hook); 38 39static int tftp_help(struct sk_buff **pskb, 40 unsigned int protoff, 41 struct nf_conn *ct, 42 enum ip_conntrack_info ctinfo) 43{ 44 struct tftphdr _tftph, *tfh; 45 struct nf_conntrack_expect *exp; 46 struct nf_conntrack_tuple *tuple; 47 unsigned int ret = NF_ACCEPT; 48 int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; 49 typeof(nf_nat_tftp_hook) nf_nat_tftp; 50 51 tfh = skb_header_pointer(*pskb, protoff + sizeof(struct udphdr), 52 sizeof(_tftph), &_tftph); 53 if (tfh == NULL) 54 return NF_ACCEPT; 55 56 switch (ntohs(tfh->opcode)) { 57 case TFTP_OPCODE_READ: 58 case TFTP_OPCODE_WRITE: 59 /* RRQ and WRQ works the same way */ 60 DEBUGP(""); 61 NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); 62 NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); 63 64 exp = nf_conntrack_expect_alloc(ct); 65 if (exp == NULL) 66 return NF_DROP; 67 tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; 68 nf_conntrack_expect_init(exp, family, 69 &tuple->src.u3, &tuple->dst.u3, 70 IPPROTO_UDP, 71 NULL, &tuple->dst.u.udp.port); 72 73 DEBUGP("expect: "); 74 NF_CT_DUMP_TUPLE(&exp->tuple); 75 NF_CT_DUMP_TUPLE(&exp->mask); 76 77 nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook); 78 if (nf_nat_tftp && ct->status & IPS_NAT_MASK) 79 ret = nf_nat_tftp(pskb, ctinfo, exp); 80 else if (nf_conntrack_expect_related(exp) != 0) 81 ret = NF_DROP; 82 nf_conntrack_expect_put(exp); 83 break; 84 case TFTP_OPCODE_DATA: 85 case TFTP_OPCODE_ACK: 86 DEBUGP("Data/ACK opcode\n"); 87 break; 88 case TFTP_OPCODE_ERROR: 89 DEBUGP("Error opcode\n"); 90 break; 91 default: 92 DEBUGP("Unknown opcode\n"); 93 } 94 return ret; 95} 96 97static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly; 98static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly; 99 100static void nf_conntrack_tftp_fini(void) 101{ 102 int i, j; 103 104 for (i = 0; i < ports_c; i++) { 105 for (j = 0; j < 2; j++) 106 nf_conntrack_helper_unregister(&tftp[i][j]); 107 } 108} 109 110static int __init nf_conntrack_tftp_init(void) 111{ 112 int i, j, ret; 113 char *tmpname; 114 115 if (ports_c == 0) 116 ports[ports_c++] = TFTP_PORT; 117 118 for (i = 0; i < ports_c; i++) { 119 memset(&tftp[i], 0, sizeof(tftp[i])); 120 121 tftp[i][0].tuple.src.l3num = AF_INET; 122 tftp[i][1].tuple.src.l3num = AF_INET6; 123 for (j = 0; j < 2; j++) { 124 tftp[i][j].tuple.dst.protonum = IPPROTO_UDP; 125 tftp[i][j].tuple.src.u.udp.port = htons(ports[i]); 126 tftp[i][j].mask.src.l3num = 0xFFFF; 127 tftp[i][j].mask.dst.protonum = 0xFF; 128 tftp[i][j].mask.src.u.udp.port = htons(0xFFFF); 129 tftp[i][j].max_expected = 1; 130 tftp[i][j].timeout = 5 * 60; /* 5 minutes */ 131 tftp[i][j].me = THIS_MODULE; 132 tftp[i][j].help = tftp_help; 133 134 tmpname = &tftp_names[i][j][0]; 135 if (ports[i] == TFTP_PORT) 136 sprintf(tmpname, "tftp"); 137 else 138 sprintf(tmpname, "tftp-%u", i); 139 tftp[i][j].name = tmpname; 140 141 ret = nf_conntrack_helper_register(&tftp[i][j]); 142 if (ret) { 143 printk("nf_ct_tftp: failed to register helper " 144 "for pf: %u port: %u\n", 145 tftp[i][j].tuple.src.l3num, ports[i]); 146 nf_conntrack_tftp_fini(); 147 return ret; 148 } 149 } 150 } 151 return 0; 152} 153 154module_init(nf_conntrack_tftp_init); 155module_exit(nf_conntrack_tftp_fini); 156