Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 | * Version: 0.0.7 | |
8 | * | |
9 | * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org> | |
10 | * - port to newnat API | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/ip.h> | |
16 | #include <linux/udp.h> | |
17 | ||
18 | #include <linux/netfilter.h> | |
19 | #include <linux/netfilter_ipv4/ip_tables.h> | |
20 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | |
21 | #include <linux/netfilter_ipv4/ip_conntrack_tftp.h> | |
22 | #include <linux/moduleparam.h> | |
23 | ||
24 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); | |
25 | MODULE_DESCRIPTION("tftp connection tracking helper"); | |
26 | MODULE_LICENSE("GPL"); | |
27 | ||
28 | #define MAX_PORTS 8 | |
2fce76af | 29 | static unsigned short ports[MAX_PORTS]; |
1da177e4 | 30 | static int ports_c; |
2fce76af | 31 | module_param_array(ports, ushort, &ports_c, 0400); |
1da177e4 LT |
32 | MODULE_PARM_DESC(ports, "port numbers of tftp servers"); |
33 | ||
34 | #if 0 | |
35 | #define DEBUGP(format, args...) printk("%s:%s:" format, \ | |
e905a9ed | 36 | __FILE__, __FUNCTION__ , ## args) |
1da177e4 LT |
37 | #else |
38 | #define DEBUGP(format, args...) | |
39 | #endif | |
40 | ||
41 | unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb, | |
42 | enum ip_conntrack_info ctinfo, | |
43 | struct ip_conntrack_expect *exp); | |
44 | EXPORT_SYMBOL_GPL(ip_nat_tftp_hook); | |
45 | ||
46 | static int tftp_help(struct sk_buff **pskb, | |
47 | struct ip_conntrack *ct, | |
48 | enum ip_conntrack_info ctinfo) | |
49 | { | |
50 | struct tftphdr _tftph, *tfh; | |
51 | struct ip_conntrack_expect *exp; | |
52 | unsigned int ret = NF_ACCEPT; | |
337fbc41 | 53 | typeof(ip_nat_tftp_hook) ip_nat_tftp; |
1da177e4 LT |
54 | |
55 | tfh = skb_header_pointer(*pskb, | |
56 | (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr), | |
57 | sizeof(_tftph), &_tftph); | |
58 | if (tfh == NULL) | |
59 | return NF_ACCEPT; | |
60 | ||
61 | switch (ntohs(tfh->opcode)) { | |
62 | /* RRQ and WRQ works the same way */ | |
63 | case TFTP_OPCODE_READ: | |
64 | case TFTP_OPCODE_WRITE: | |
65 | DEBUGP(""); | |
66 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
67 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
68 | ||
4acdbdbe | 69 | exp = ip_conntrack_expect_alloc(ct); |
1da177e4 LT |
70 | if (exp == NULL) |
71 | return NF_DROP; | |
72 | ||
73 | exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | |
cdcb71bf | 74 | exp->mask.src.ip = htonl(0xffffffff); |
6f169300 | 75 | exp->mask.src.u.udp.port = 0; |
cdcb71bf AV |
76 | exp->mask.dst.ip = htonl(0xffffffff); |
77 | exp->mask.dst.u.udp.port = htons(0xffff); | |
1da177e4 LT |
78 | exp->mask.dst.protonum = 0xff; |
79 | exp->expectfn = NULL; | |
2248bcfc | 80 | exp->flags = 0; |
1da177e4 LT |
81 | |
82 | DEBUGP("expect: "); | |
83 | DUMP_TUPLE(&exp->tuple); | |
84 | DUMP_TUPLE(&exp->mask); | |
337fbc41 PM |
85 | ip_nat_tftp = rcu_dereference(ip_nat_tftp_hook); |
86 | if (ip_nat_tftp) | |
87 | ret = ip_nat_tftp(pskb, ctinfo, exp); | |
4acdbdbe | 88 | else if (ip_conntrack_expect_related(exp) != 0) |
1da177e4 | 89 | ret = NF_DROP; |
4acdbdbe | 90 | ip_conntrack_expect_put(exp); |
1da177e4 LT |
91 | break; |
92 | case TFTP_OPCODE_DATA: | |
93 | case TFTP_OPCODE_ACK: | |
94 | DEBUGP("Data/ACK opcode\n"); | |
95 | break; | |
96 | case TFTP_OPCODE_ERROR: | |
97 | DEBUGP("Error opcode\n"); | |
98 | break; | |
99 | default: | |
100 | DEBUGP("Unknown opcode\n"); | |
101 | } | |
102 | return NF_ACCEPT; | |
103 | } | |
104 | ||
105 | static struct ip_conntrack_helper tftp[MAX_PORTS]; | |
5cb30640 | 106 | static char tftp_names[MAX_PORTS][sizeof("tftp-65535")]; |
1da177e4 | 107 | |
65b4b4e8 | 108 | static void ip_conntrack_tftp_fini(void) |
1da177e4 LT |
109 | { |
110 | int i; | |
111 | ||
112 | for (i = 0 ; i < ports_c; i++) { | |
113 | DEBUGP("unregistering helper for port %d\n", | |
114 | ports[i]); | |
115 | ip_conntrack_helper_unregister(&tftp[i]); | |
e905a9ed | 116 | } |
1da177e4 LT |
117 | } |
118 | ||
65b4b4e8 | 119 | static int __init ip_conntrack_tftp_init(void) |
1da177e4 LT |
120 | { |
121 | int i, ret; | |
122 | char *tmpname; | |
123 | ||
124 | if (ports_c == 0) | |
125 | ports[ports_c++] = TFTP_PORT; | |
126 | ||
127 | for (i = 0; i < ports_c; i++) { | |
128 | /* Create helper structure */ | |
129 | memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); | |
130 | ||
131 | tftp[i].tuple.dst.protonum = IPPROTO_UDP; | |
132 | tftp[i].tuple.src.u.udp.port = htons(ports[i]); | |
133 | tftp[i].mask.dst.protonum = 0xFF; | |
cdcb71bf | 134 | tftp[i].mask.src.u.udp.port = htons(0xFFFF); |
1da177e4 LT |
135 | tftp[i].max_expected = 1; |
136 | tftp[i].timeout = 5 * 60; /* 5 minutes */ | |
137 | tftp[i].me = THIS_MODULE; | |
138 | tftp[i].help = tftp_help; | |
139 | ||
140 | tmpname = &tftp_names[i][0]; | |
141 | if (ports[i] == TFTP_PORT) | |
142 | sprintf(tmpname, "tftp"); | |
143 | else | |
144 | sprintf(tmpname, "tftp-%d", i); | |
145 | tftp[i].name = tmpname; | |
146 | ||
147 | DEBUGP("port #%d: %d\n", i, ports[i]); | |
148 | ||
149 | ret=ip_conntrack_helper_register(&tftp[i]); | |
150 | if (ret) { | |
151 | printk("ERROR registering helper for port %d\n", | |
152 | ports[i]); | |
65b4b4e8 | 153 | ip_conntrack_tftp_fini(); |
1da177e4 LT |
154 | return(ret); |
155 | } | |
156 | } | |
157 | return(0); | |
158 | } | |
159 | ||
65b4b4e8 AM |
160 | module_init(ip_conntrack_tftp_init); |
161 | module_exit(ip_conntrack_tftp_fini); |