Root/
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 | |
21 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); |
22 | MODULE_DESCRIPTION("TFTP connection tracking helper"); |
23 | MODULE_LICENSE("GPL"); |
24 | MODULE_ALIAS("ip_conntrack_tftp"); |
25 | MODULE_ALIAS_NFCT_HELPER("tftp"); |
26 | |
27 | #define MAX_PORTS 8 |
28 | static unsigned short ports[MAX_PORTS]; |
29 | static unsigned int ports_c; |
30 | module_param_array(ports, ushort, &ports_c, 0400); |
31 | MODULE_PARM_DESC(ports, "Port numbers of TFTP servers"); |
32 | |
33 | unsigned int (*nf_nat_tftp_hook)(struct sk_buff *skb, |
34 | enum ip_conntrack_info ctinfo, |
35 | struct nf_conntrack_expect *exp) __read_mostly; |
36 | EXPORT_SYMBOL_GPL(nf_nat_tftp_hook); |
37 | |
38 | static 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 | |
94 | static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly; |
95 | static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly; |
96 | |
97 | static const struct nf_conntrack_expect_policy tftp_exp_policy = { |
98 | .max_expected = 1, |
99 | .timeout = 5 * 60, |
100 | }; |
101 | |
102 | static 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 | |
112 | static 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 | |
152 | module_init(nf_conntrack_tftp_init); |
153 | module_exit(nf_conntrack_tftp_fini); |
154 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9