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