Commit | Line | Data |
---|---|---|
f587de0e PM |
1 | /* |
2 | * H.323 extension for NAT alteration. | |
3 | * | |
4 | * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> | |
5 | * | |
6 | * This source code is licensed under General Public License version 2. | |
7 | * | |
8 | * Based on the 'brute force' H.323 NAT module by | |
9 | * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | |
10 | */ | |
11 | ||
12 | #include <linux/module.h> | |
13 | #include <linux/moduleparam.h> | |
14 | #include <linux/tcp.h> | |
15 | #include <net/tcp.h> | |
16 | ||
17 | #include <net/netfilter/nf_nat.h> | |
18 | #include <net/netfilter/nf_nat_helper.h> | |
19 | #include <net/netfilter/nf_nat_rule.h> | |
20 | #include <net/netfilter/nf_conntrack_helper.h> | |
21 | #include <net/netfilter/nf_conntrack_expect.h> | |
22 | #include <linux/netfilter/nf_conntrack_h323.h> | |
23 | ||
f587de0e | 24 | /****************************************************************************/ |
3db05fea | 25 | static int set_addr(struct sk_buff *skb, |
f587de0e PM |
26 | unsigned char **data, int dataoff, |
27 | unsigned int addroff, __be32 ip, __be16 port) | |
28 | { | |
29 | enum ip_conntrack_info ctinfo; | |
3db05fea | 30 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
f587de0e PM |
31 | struct { |
32 | __be32 ip; | |
33 | __be16 port; | |
34 | } __attribute__ ((__packed__)) buf; | |
905e3e8e JE |
35 | const struct tcphdr *th; |
36 | struct tcphdr _tcph; | |
f587de0e PM |
37 | |
38 | buf.ip = ip; | |
39 | buf.port = port; | |
40 | addroff += dataoff; | |
41 | ||
3db05fea HX |
42 | if (ip_hdr(skb)->protocol == IPPROTO_TCP) { |
43 | if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, | |
f587de0e PM |
44 | addroff, sizeof(buf), |
45 | (char *) &buf, sizeof(buf))) { | |
46 | if (net_ratelimit()) | |
47 | printk("nf_nat_h323: nf_nat_mangle_tcp_packet" | |
48 | " error\n"); | |
49 | return -1; | |
50 | } | |
51 | ||
52 | /* Relocate data pointer */ | |
3db05fea | 53 | th = skb_header_pointer(skb, ip_hdrlen(skb), |
f587de0e PM |
54 | sizeof(_tcph), &_tcph); |
55 | if (th == NULL) | |
56 | return -1; | |
3db05fea | 57 | *data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff; |
f587de0e | 58 | } else { |
3db05fea | 59 | if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, |
f587de0e PM |
60 | addroff, sizeof(buf), |
61 | (char *) &buf, sizeof(buf))) { | |
62 | if (net_ratelimit()) | |
63 | printk("nf_nat_h323: nf_nat_mangle_udp_packet" | |
64 | " error\n"); | |
65 | return -1; | |
66 | } | |
67 | /* nf_nat_mangle_udp_packet uses skb_make_writable() to copy | |
68 | * or pull everything in a linear buffer, so we can safely | |
69 | * use the skb pointers now */ | |
3db05fea | 70 | *data = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); |
f587de0e PM |
71 | } |
72 | ||
73 | return 0; | |
74 | } | |
75 | ||
76 | /****************************************************************************/ | |
3db05fea | 77 | static int set_h225_addr(struct sk_buff *skb, |
f587de0e PM |
78 | unsigned char **data, int dataoff, |
79 | TransportAddress *taddr, | |
643a2c15 | 80 | union nf_inet_addr *addr, __be16 port) |
f587de0e | 81 | { |
3db05fea | 82 | return set_addr(skb, data, dataoff, taddr->ipAddress.ip, |
f587de0e PM |
83 | addr->ip, port); |
84 | } | |
85 | ||
86 | /****************************************************************************/ | |
3db05fea | 87 | static int set_h245_addr(struct sk_buff *skb, |
f587de0e PM |
88 | unsigned char **data, int dataoff, |
89 | H245_TransportAddress *taddr, | |
643a2c15 | 90 | union nf_inet_addr *addr, __be16 port) |
f587de0e | 91 | { |
3db05fea | 92 | return set_addr(skb, data, dataoff, |
f587de0e PM |
93 | taddr->unicastAddress.iPAddress.network, |
94 | addr->ip, port); | |
95 | } | |
96 | ||
97 | /****************************************************************************/ | |
3db05fea | 98 | static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct, |
f587de0e PM |
99 | enum ip_conntrack_info ctinfo, |
100 | unsigned char **data, | |
101 | TransportAddress *taddr, int count) | |
102 | { | |
905e3e8e | 103 | const struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; |
f587de0e PM |
104 | int dir = CTINFO2DIR(ctinfo); |
105 | int i; | |
106 | __be16 port; | |
643a2c15 | 107 | union nf_inet_addr addr; |
f587de0e PM |
108 | |
109 | for (i = 0; i < count; i++) { | |
110 | if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) { | |
111 | if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && | |
112 | port == info->sig_port[dir]) { | |
113 | /* GW->GK */ | |
114 | ||
115 | /* Fix for Gnomemeeting */ | |
116 | if (i > 0 && | |
117 | get_h225_addr(ct, *data, &taddr[0], | |
118 | &addr, &port) && | |
119 | (ntohl(addr.ip) & 0xff000000) == 0x7f000000) | |
120 | i = 0; | |
121 | ||
cffee385 HH |
122 | pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n", |
123 | &addr.ip, port, | |
124 | &ct->tuplehash[!dir].tuple.dst.u3.ip, | |
0d53778e | 125 | info->sig_port[!dir]); |
3db05fea | 126 | return set_h225_addr(skb, data, 0, &taddr[i], |
f587de0e PM |
127 | &ct->tuplehash[!dir]. |
128 | tuple.dst.u3, | |
129 | info->sig_port[!dir]); | |
130 | } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && | |
131 | port == info->sig_port[dir]) { | |
132 | /* GK->GW */ | |
cffee385 HH |
133 | pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n", |
134 | &addr.ip, port, | |
135 | &ct->tuplehash[!dir].tuple.src.u3.ip, | |
0d53778e | 136 | info->sig_port[!dir]); |
3db05fea | 137 | return set_h225_addr(skb, data, 0, &taddr[i], |
f587de0e PM |
138 | &ct->tuplehash[!dir]. |
139 | tuple.src.u3, | |
140 | info->sig_port[!dir]); | |
141 | } | |
142 | } | |
143 | } | |
144 | ||
145 | return 0; | |
146 | } | |
147 | ||
148 | /****************************************************************************/ | |
3db05fea | 149 | static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct, |
f587de0e PM |
150 | enum ip_conntrack_info ctinfo, |
151 | unsigned char **data, | |
152 | TransportAddress *taddr, int count) | |
153 | { | |
154 | int dir = CTINFO2DIR(ctinfo); | |
155 | int i; | |
156 | __be16 port; | |
643a2c15 | 157 | union nf_inet_addr addr; |
f587de0e PM |
158 | |
159 | for (i = 0; i < count; i++) { | |
160 | if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && | |
161 | addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && | |
162 | port == ct->tuplehash[dir].tuple.src.u.udp.port) { | |
cffee385 HH |
163 | pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n", |
164 | &addr.ip, ntohs(port), | |
165 | &ct->tuplehash[!dir].tuple.dst.u3.ip, | |
0d53778e | 166 | ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port)); |
3db05fea | 167 | return set_h225_addr(skb, data, 0, &taddr[i], |
f587de0e PM |
168 | &ct->tuplehash[!dir].tuple.dst.u3, |
169 | ct->tuplehash[!dir].tuple. | |
170 | dst.u.udp.port); | |
171 | } | |
172 | } | |
173 | ||
174 | return 0; | |
175 | } | |
176 | ||
177 | /****************************************************************************/ | |
3db05fea | 178 | static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, |
f587de0e PM |
179 | enum ip_conntrack_info ctinfo, |
180 | unsigned char **data, int dataoff, | |
181 | H245_TransportAddress *taddr, | |
182 | __be16 port, __be16 rtp_port, | |
183 | struct nf_conntrack_expect *rtp_exp, | |
184 | struct nf_conntrack_expect *rtcp_exp) | |
185 | { | |
186 | struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; | |
187 | int dir = CTINFO2DIR(ctinfo); | |
188 | int i; | |
189 | u_int16_t nated_port; | |
190 | ||
191 | /* Set expectations for NAT */ | |
192 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; | |
193 | rtp_exp->expectfn = nf_nat_follow_master; | |
194 | rtp_exp->dir = !dir; | |
195 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | |
196 | rtcp_exp->expectfn = nf_nat_follow_master; | |
197 | rtcp_exp->dir = !dir; | |
198 | ||
199 | /* Lookup existing expects */ | |
200 | for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) { | |
201 | if (info->rtp_port[i][dir] == rtp_port) { | |
202 | /* Expected */ | |
203 | ||
204 | /* Use allocated ports first. This will refresh | |
205 | * the expects */ | |
206 | rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir]; | |
207 | rtcp_exp->tuple.dst.u.udp.port = | |
208 | htons(ntohs(info->rtp_port[i][dir]) + 1); | |
209 | break; | |
210 | } else if (info->rtp_port[i][dir] == 0) { | |
211 | /* Not expected */ | |
212 | break; | |
213 | } | |
214 | } | |
215 | ||
216 | /* Run out of expectations */ | |
217 | if (i >= H323_RTP_CHANNEL_MAX) { | |
218 | if (net_ratelimit()) | |
219 | printk("nf_nat_h323: out of expectations\n"); | |
220 | return 0; | |
221 | } | |
222 | ||
223 | /* Try to get a pair of ports. */ | |
224 | for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port); | |
225 | nated_port != 0; nated_port += 2) { | |
226 | rtp_exp->tuple.dst.u.udp.port = htons(nated_port); | |
6823645d | 227 | if (nf_ct_expect_related(rtp_exp) == 0) { |
f587de0e PM |
228 | rtcp_exp->tuple.dst.u.udp.port = |
229 | htons(nated_port + 1); | |
6823645d | 230 | if (nf_ct_expect_related(rtcp_exp) == 0) |
f587de0e | 231 | break; |
6823645d | 232 | nf_ct_unexpect_related(rtp_exp); |
f587de0e PM |
233 | } |
234 | } | |
235 | ||
236 | if (nated_port == 0) { /* No port available */ | |
237 | if (net_ratelimit()) | |
238 | printk("nf_nat_h323: out of RTP ports\n"); | |
239 | return 0; | |
240 | } | |
241 | ||
242 | /* Modify signal */ | |
3db05fea | 243 | if (set_h245_addr(skb, data, dataoff, taddr, |
f587de0e PM |
244 | &ct->tuplehash[!dir].tuple.dst.u3, |
245 | htons((port & htons(1)) ? nated_port + 1 : | |
e905a9ed | 246 | nated_port)) == 0) { |
f587de0e PM |
247 | /* Save ports */ |
248 | info->rtp_port[i][dir] = rtp_port; | |
249 | info->rtp_port[i][!dir] = htons(nated_port); | |
250 | } else { | |
6823645d PM |
251 | nf_ct_unexpect_related(rtp_exp); |
252 | nf_ct_unexpect_related(rtcp_exp); | |
f587de0e PM |
253 | return -1; |
254 | } | |
255 | ||
256 | /* Success */ | |
cffee385 HH |
257 | pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n", |
258 | &rtp_exp->tuple.src.u3.ip, | |
0d53778e | 259 | ntohs(rtp_exp->tuple.src.u.udp.port), |
cffee385 | 260 | &rtp_exp->tuple.dst.u3.ip, |
0d53778e | 261 | ntohs(rtp_exp->tuple.dst.u.udp.port)); |
cffee385 HH |
262 | pr_debug("nf_nat_h323: expect RTCP %pI4:%hu->%pI4:%hu\n", |
263 | &rtcp_exp->tuple.src.u3.ip, | |
0d53778e | 264 | ntohs(rtcp_exp->tuple.src.u.udp.port), |
cffee385 | 265 | &rtcp_exp->tuple.dst.u3.ip, |
0d53778e | 266 | ntohs(rtcp_exp->tuple.dst.u.udp.port)); |
f587de0e PM |
267 | |
268 | return 0; | |
269 | } | |
270 | ||
271 | /****************************************************************************/ | |
3db05fea | 272 | static int nat_t120(struct sk_buff *skb, struct nf_conn *ct, |
f587de0e PM |
273 | enum ip_conntrack_info ctinfo, |
274 | unsigned char **data, int dataoff, | |
275 | H245_TransportAddress *taddr, __be16 port, | |
276 | struct nf_conntrack_expect *exp) | |
277 | { | |
278 | int dir = CTINFO2DIR(ctinfo); | |
279 | u_int16_t nated_port = ntohs(port); | |
280 | ||
281 | /* Set expectations for NAT */ | |
282 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | |
283 | exp->expectfn = nf_nat_follow_master; | |
284 | exp->dir = !dir; | |
285 | ||
286 | /* Try to get same port: if not, try to change it. */ | |
287 | for (; nated_port != 0; nated_port++) { | |
288 | exp->tuple.dst.u.tcp.port = htons(nated_port); | |
6823645d | 289 | if (nf_ct_expect_related(exp) == 0) |
f587de0e PM |
290 | break; |
291 | } | |
292 | ||
293 | if (nated_port == 0) { /* No port available */ | |
294 | if (net_ratelimit()) | |
295 | printk("nf_nat_h323: out of TCP ports\n"); | |
296 | return 0; | |
297 | } | |
298 | ||
299 | /* Modify signal */ | |
3db05fea | 300 | if (set_h245_addr(skb, data, dataoff, taddr, |
f587de0e PM |
301 | &ct->tuplehash[!dir].tuple.dst.u3, |
302 | htons(nated_port)) < 0) { | |
6823645d | 303 | nf_ct_unexpect_related(exp); |
f587de0e PM |
304 | return -1; |
305 | } | |
306 | ||
cffee385 HH |
307 | pr_debug("nf_nat_h323: expect T.120 %pI4:%hu->%pI4:%hu\n", |
308 | &exp->tuple.src.u3.ip, | |
0d53778e | 309 | ntohs(exp->tuple.src.u.tcp.port), |
cffee385 | 310 | &exp->tuple.dst.u3.ip, |
0d53778e | 311 | ntohs(exp->tuple.dst.u.tcp.port)); |
f587de0e PM |
312 | |
313 | return 0; | |
314 | } | |
315 | ||
316 | /****************************************************************************/ | |
3db05fea | 317 | static int nat_h245(struct sk_buff *skb, struct nf_conn *ct, |
f587de0e PM |
318 | enum ip_conntrack_info ctinfo, |
319 | unsigned char **data, int dataoff, | |
320 | TransportAddress *taddr, __be16 port, | |
321 | struct nf_conntrack_expect *exp) | |
322 | { | |
323 | struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; | |
324 | int dir = CTINFO2DIR(ctinfo); | |
325 | u_int16_t nated_port = ntohs(port); | |
326 | ||
327 | /* Set expectations for NAT */ | |
328 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | |
329 | exp->expectfn = nf_nat_follow_master; | |
330 | exp->dir = !dir; | |
331 | ||
332 | /* Check existing expects */ | |
333 | if (info->sig_port[dir] == port) | |
334 | nated_port = ntohs(info->sig_port[!dir]); | |
335 | ||
336 | /* Try to get same port: if not, try to change it. */ | |
337 | for (; nated_port != 0; nated_port++) { | |
338 | exp->tuple.dst.u.tcp.port = htons(nated_port); | |
6823645d | 339 | if (nf_ct_expect_related(exp) == 0) |
f587de0e PM |
340 | break; |
341 | } | |
342 | ||
343 | if (nated_port == 0) { /* No port available */ | |
344 | if (net_ratelimit()) | |
345 | printk("nf_nat_q931: out of TCP ports\n"); | |
346 | return 0; | |
347 | } | |
348 | ||
349 | /* Modify signal */ | |
3db05fea | 350 | if (set_h225_addr(skb, data, dataoff, taddr, |
f587de0e PM |
351 | &ct->tuplehash[!dir].tuple.dst.u3, |
352 | htons(nated_port)) == 0) { | |
353 | /* Save ports */ | |
354 | info->sig_port[dir] = port; | |
355 | info->sig_port[!dir] = htons(nated_port); | |
356 | } else { | |
6823645d | 357 | nf_ct_unexpect_related(exp); |
f587de0e PM |
358 | return -1; |
359 | } | |
360 | ||
cffee385 HH |
361 | pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n", |
362 | &exp->tuple.src.u3.ip, | |
0d53778e | 363 | ntohs(exp->tuple.src.u.tcp.port), |
cffee385 | 364 | &exp->tuple.dst.u3.ip, |
0d53778e | 365 | ntohs(exp->tuple.dst.u.tcp.port)); |
f587de0e PM |
366 | |
367 | return 0; | |
368 | } | |
369 | ||
370 | /**************************************************************************** | |
371 | * This conntrack expect function replaces nf_conntrack_q931_expect() | |
372 | * which was set by nf_conntrack_h323.c. | |
373 | ****************************************************************************/ | |
374 | static void ip_nat_q931_expect(struct nf_conn *new, | |
375 | struct nf_conntrack_expect *this) | |
376 | { | |
587aa641 | 377 | struct nf_nat_range range; |
f587de0e PM |
378 | |
379 | if (this->tuple.src.u3.ip != 0) { /* Only accept calls from GK */ | |
380 | nf_nat_follow_master(new, this); | |
381 | return; | |
382 | } | |
383 | ||
384 | /* This must be a fresh one. */ | |
385 | BUG_ON(new->status & IPS_NAT_DONE_MASK); | |
386 | ||
387 | /* Change src to where master sends to */ | |
388 | range.flags = IP_NAT_RANGE_MAP_IPS; | |
389 | range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; | |
cc01dcbd | 390 | nf_nat_setup_info(new, &range, IP_NAT_MANIP_SRC); |
f587de0e PM |
391 | |
392 | /* For DST manip, map port here to where it's expected. */ | |
393 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | |
394 | range.min = range.max = this->saved_proto; | |
395 | range.min_ip = range.max_ip = | |
396 | new->master->tuplehash[!this->dir].tuple.src.u3.ip; | |
cc01dcbd | 397 | nf_nat_setup_info(new, &range, IP_NAT_MANIP_DST); |
f587de0e PM |
398 | } |
399 | ||
400 | /****************************************************************************/ | |
3db05fea | 401 | static int nat_q931(struct sk_buff *skb, struct nf_conn *ct, |
f587de0e PM |
402 | enum ip_conntrack_info ctinfo, |
403 | unsigned char **data, TransportAddress *taddr, int idx, | |
404 | __be16 port, struct nf_conntrack_expect *exp) | |
405 | { | |
406 | struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info; | |
407 | int dir = CTINFO2DIR(ctinfo); | |
408 | u_int16_t nated_port = ntohs(port); | |
643a2c15 | 409 | union nf_inet_addr addr; |
f587de0e PM |
410 | |
411 | /* Set expectations for NAT */ | |
412 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | |
413 | exp->expectfn = ip_nat_q931_expect; | |
414 | exp->dir = !dir; | |
415 | ||
416 | /* Check existing expects */ | |
417 | if (info->sig_port[dir] == port) | |
418 | nated_port = ntohs(info->sig_port[!dir]); | |
419 | ||
420 | /* Try to get same port: if not, try to change it. */ | |
421 | for (; nated_port != 0; nated_port++) { | |
422 | exp->tuple.dst.u.tcp.port = htons(nated_port); | |
6823645d | 423 | if (nf_ct_expect_related(exp) == 0) |
f587de0e PM |
424 | break; |
425 | } | |
426 | ||
427 | if (nated_port == 0) { /* No port available */ | |
428 | if (net_ratelimit()) | |
429 | printk("nf_nat_ras: out of TCP ports\n"); | |
430 | return 0; | |
431 | } | |
432 | ||
433 | /* Modify signal */ | |
3db05fea | 434 | if (set_h225_addr(skb, data, 0, &taddr[idx], |
f587de0e PM |
435 | &ct->tuplehash[!dir].tuple.dst.u3, |
436 | htons(nated_port)) == 0) { | |
437 | /* Save ports */ | |
438 | info->sig_port[dir] = port; | |
439 | info->sig_port[!dir] = htons(nated_port); | |
440 | ||
441 | /* Fix for Gnomemeeting */ | |
442 | if (idx > 0 && | |
443 | get_h225_addr(ct, *data, &taddr[0], &addr, &port) && | |
444 | (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { | |
3db05fea | 445 | set_h225_addr(skb, data, 0, &taddr[0], |
1ff75ed2 JMZ |
446 | &ct->tuplehash[!dir].tuple.dst.u3, |
447 | info->sig_port[!dir]); | |
f587de0e PM |
448 | } |
449 | } else { | |
6823645d | 450 | nf_ct_unexpect_related(exp); |
f587de0e PM |
451 | return -1; |
452 | } | |
453 | ||
454 | /* Success */ | |
cffee385 HH |
455 | pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n", |
456 | &exp->tuple.src.u3.ip, | |
0d53778e | 457 | ntohs(exp->tuple.src.u.tcp.port), |
cffee385 | 458 | &exp->tuple.dst.u3.ip, |
0d53778e | 459 | ntohs(exp->tuple.dst.u.tcp.port)); |
f587de0e PM |
460 | |
461 | return 0; | |
462 | } | |
463 | ||
464 | /****************************************************************************/ | |
465 | static void ip_nat_callforwarding_expect(struct nf_conn *new, | |
466 | struct nf_conntrack_expect *this) | |
467 | { | |
468 | struct nf_nat_range range; | |
469 | ||
470 | /* This must be a fresh one. */ | |
471 | BUG_ON(new->status & IPS_NAT_DONE_MASK); | |
472 | ||
473 | /* Change src to where master sends to */ | |
474 | range.flags = IP_NAT_RANGE_MAP_IPS; | |
475 | range.min_ip = range.max_ip = new->tuplehash[!this->dir].tuple.src.u3.ip; | |
cc01dcbd | 476 | nf_nat_setup_info(new, &range, IP_NAT_MANIP_SRC); |
f587de0e PM |
477 | |
478 | /* For DST manip, map port here to where it's expected. */ | |
479 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | |
480 | range.min = range.max = this->saved_proto; | |
481 | range.min_ip = range.max_ip = this->saved_ip; | |
cc01dcbd | 482 | nf_nat_setup_info(new, &range, IP_NAT_MANIP_DST); |
f587de0e PM |
483 | } |
484 | ||
485 | /****************************************************************************/ | |
3db05fea | 486 | static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, |
f587de0e PM |
487 | enum ip_conntrack_info ctinfo, |
488 | unsigned char **data, int dataoff, | |
489 | TransportAddress *taddr, __be16 port, | |
490 | struct nf_conntrack_expect *exp) | |
491 | { | |
492 | int dir = CTINFO2DIR(ctinfo); | |
493 | u_int16_t nated_port; | |
494 | ||
495 | /* Set expectations for NAT */ | |
496 | exp->saved_ip = exp->tuple.dst.u3.ip; | |
497 | exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip; | |
498 | exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port; | |
499 | exp->expectfn = ip_nat_callforwarding_expect; | |
500 | exp->dir = !dir; | |
501 | ||
502 | /* Try to get same port: if not, try to change it. */ | |
503 | for (nated_port = ntohs(port); nated_port != 0; nated_port++) { | |
504 | exp->tuple.dst.u.tcp.port = htons(nated_port); | |
6823645d | 505 | if (nf_ct_expect_related(exp) == 0) |
f587de0e PM |
506 | break; |
507 | } | |
508 | ||
509 | if (nated_port == 0) { /* No port available */ | |
510 | if (net_ratelimit()) | |
511 | printk("nf_nat_q931: out of TCP ports\n"); | |
512 | return 0; | |
513 | } | |
514 | ||
515 | /* Modify signal */ | |
3db05fea | 516 | if (!set_h225_addr(skb, data, dataoff, taddr, |
f587de0e PM |
517 | &ct->tuplehash[!dir].tuple.dst.u3, |
518 | htons(nated_port)) == 0) { | |
6823645d | 519 | nf_ct_unexpect_related(exp); |
f587de0e PM |
520 | return -1; |
521 | } | |
522 | ||
523 | /* Success */ | |
cffee385 HH |
524 | pr_debug("nf_nat_q931: expect Call Forwarding %pI4:%hu->%pI4:%hu\n", |
525 | &exp->tuple.src.u3.ip, | |
0d53778e | 526 | ntohs(exp->tuple.src.u.tcp.port), |
cffee385 | 527 | &exp->tuple.dst.u3.ip, |
0d53778e | 528 | ntohs(exp->tuple.dst.u.tcp.port)); |
f587de0e PM |
529 | |
530 | return 0; | |
531 | } | |
532 | ||
533 | /****************************************************************************/ | |
534 | static int __init init(void) | |
535 | { | |
d1332e0a PM |
536 | BUG_ON(set_h245_addr_hook != NULL); |
537 | BUG_ON(set_h225_addr_hook != NULL); | |
538 | BUG_ON(set_sig_addr_hook != NULL); | |
539 | BUG_ON(set_ras_addr_hook != NULL); | |
540 | BUG_ON(nat_rtp_rtcp_hook != NULL); | |
541 | BUG_ON(nat_t120_hook != NULL); | |
542 | BUG_ON(nat_h245_hook != NULL); | |
543 | BUG_ON(nat_callforwarding_hook != NULL); | |
544 | BUG_ON(nat_q931_hook != NULL); | |
f587de0e PM |
545 | |
546 | rcu_assign_pointer(set_h245_addr_hook, set_h245_addr); | |
547 | rcu_assign_pointer(set_h225_addr_hook, set_h225_addr); | |
548 | rcu_assign_pointer(set_sig_addr_hook, set_sig_addr); | |
549 | rcu_assign_pointer(set_ras_addr_hook, set_ras_addr); | |
550 | rcu_assign_pointer(nat_rtp_rtcp_hook, nat_rtp_rtcp); | |
551 | rcu_assign_pointer(nat_t120_hook, nat_t120); | |
552 | rcu_assign_pointer(nat_h245_hook, nat_h245); | |
553 | rcu_assign_pointer(nat_callforwarding_hook, nat_callforwarding); | |
554 | rcu_assign_pointer(nat_q931_hook, nat_q931); | |
f587de0e PM |
555 | return 0; |
556 | } | |
557 | ||
558 | /****************************************************************************/ | |
559 | static void __exit fini(void) | |
560 | { | |
561 | rcu_assign_pointer(set_h245_addr_hook, NULL); | |
562 | rcu_assign_pointer(set_h225_addr_hook, NULL); | |
563 | rcu_assign_pointer(set_sig_addr_hook, NULL); | |
564 | rcu_assign_pointer(set_ras_addr_hook, NULL); | |
565 | rcu_assign_pointer(nat_rtp_rtcp_hook, NULL); | |
566 | rcu_assign_pointer(nat_t120_hook, NULL); | |
567 | rcu_assign_pointer(nat_h245_hook, NULL); | |
568 | rcu_assign_pointer(nat_callforwarding_hook, NULL); | |
569 | rcu_assign_pointer(nat_q931_hook, NULL); | |
570 | synchronize_rcu(); | |
571 | } | |
572 | ||
573 | /****************************************************************************/ | |
574 | module_init(init); | |
575 | module_exit(fini); | |
576 | ||
577 | MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>"); | |
578 | MODULE_DESCRIPTION("H.323 NAT helper"); | |
579 | MODULE_LICENSE("GPL"); | |
580 | MODULE_ALIAS("ip_nat_h323"); |