4f55935b8305b001738bc0d17d9e4dfad6758f5b
[openwrt.git] / target / linux / generic-2.4 / patches / 613-netfilter_nat_sip.patch
1 diff -urN linux-2.4.32/net/ipv4/netfilter/Config.in linux-2.4.32/net/ipv4/netfilter/Config.in
2 --- linux-2.4.32/net/ipv4/netfilter/Config.in   2005-12-11 21:34:32.000000000 +0100
3 +++ linux-2.4.32/net/ipv4/netfilter/Config.in   2005-12-11 21:38:12.000000000 +0100
4 @@ -15,6 +15,7 @@
5    dep_tristate '  Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES
6    dep_tristate '  GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK
7    dep_tristate '   PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE
8 +  dep_tristate '  SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK
9  fi
10  
11  if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
12 @@ -104,6 +105,13 @@
13            define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
14          fi
15        fi
16 +      if [ "$CONFIG_IP_NF_SIP" = "m" ]; then
17 +       define_tristate CONFIG_IP_NF_NAT_SIP m
18 +      else
19 +       if [ "$CONFIG_IP_NF_SIP" = "y" ]; then
20 +         define_tristate CONFIG_IP_NF_NAT_SIP $CONFIG_IP_NF_NAT
21 +       fi
22 +      fi
23        if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then
24          define_tristate CONFIG_IP_NF_NAT_AMANDA m
25        else
26 diff -urN linux-2.4.32/net/ipv4/netfilter/Makefile linux-2.4.32/net/ipv4/netfilter/Makefile
27 --- linux-2.4.32/net/ipv4/netfilter/Makefile    2005-12-11 21:34:32.000000000 +0100
28 +++ linux-2.4.32/net/ipv4/netfilter/Makefile    2005-12-11 21:39:08.000000000 +0100
29 @@ -53,6 +53,10 @@
30  ifdef CONFIG_IP_NF_NAT_PPTP
31         export-objs += ip_conntrack_pptp.o
32  endif
33 +obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
34 +ifdef CONFIG_IP_NF_NAT_SIP
35 +        export-objs += ip_conntrack_sip.o
36 +endif
37  
38  
39  # NAT helpers 
40 @@ -62,6 +66,7 @@
41  obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o
42  obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o
43  obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o
44 +obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o
45  
46  # generic IP tables 
47  obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o
48 diff -urN linux-2.4.32/net/ipv4/netfilter/ip_conntrack_sip.c linux-2.4.32/net/ipv4/netfilter/ip_conntrack_sip.c
49 --- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_sip.c  1970-01-01 01:00:00.000000000 +0100
50 +++ linux-2.4.32/net/ipv4/netfilter/ip_conntrack_sip.c  2005-12-11 21:35:51.000000000 +0100
51 @@ -0,0 +1,312 @@
52 +/*
53 + * SIP extension for IP connection tracking. 
54 + *
55 + * Copyright (C) 2004, CyberTAN Corporation
56 + * All Rights Reserved.
57 + *
58 + * THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
59 + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
60 + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
61 + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
62 + *
63 + */
64 +
65 +#include <linux/module.h>
66 +#include <linux/netfilter.h>
67 +#include <linux/ip.h>
68 +#include <linux/ctype.h>
69 +#include <net/checksum.h>
70 +#include <net/tcp.h>
71 +
72 +#include <linux/netfilter_ipv4/lockhelp.h>
73 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
74 +#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
75 +#include <linux/netfilter_ipv4/ip_conntrack_core.h>
76 +
77 +DECLARE_LOCK(ip_sip_lock);
78
79 +struct module *ip_conntrack_sip = THIS_MODULE;
80 +
81 +#define MAX_PORTS 8
82 +static int ports[MAX_PORTS];
83 +static int ports_c;
84 +#ifdef MODULE_PARM
85 +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
86 +#endif
87 +
88 +#if 0
89 +  #define DEBUGP printk
90 +#else
91 +  #define DEBUGP(format, args...)
92 +#endif
93 +
94 +#define RTCP_SUPPORT
95 +
96 +static int set_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip,
97 +               u_int16_t dstport, unsigned int conntype)
98 +{
99 +       struct ip_conntrack_expect expect, *exp = &expect;
100 +       struct ip_ct_sip_expect *exp_sip_info = &exp->help.exp_sip_info;
101 +       int ret = 0;
102 +
103 +       memset(&expect, 0, sizeof(expect));
104 +       LOCK_BH(&ip_sip_lock);
105 +
106 +       DEBUGP("conntrack_sip: %s: [%s]: DST=%u.%u.%u.%u:%u\n", __FUNCTION__, 
107 +                       conntype == CONN_RTP ? "RTP" : "RTCP", NIPQUAD(dstip), dstport);
108 +
109 +       /* exp_sip_info */
110 +       exp_sip_info->port = dstport;
111 +       exp_sip_info->type = conntype;
112 +       exp_sip_info->nated = 0;
113 +
114 +       /* new expectation */
115 +       exp->tuple = ((struct ip_conntrack_tuple)
116 +               { { 0, { 0 } },
117 +                 { dstip, { htons(dstport) }, IPPROTO_UDP }});
118 +       exp->mask = ((struct ip_conntrack_tuple)
119 +               { { 0, { 0 } },
120 +                 { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
121 +       exp->expectfn = NULL;
122 +
123 +       if ((ret=ip_conntrack_expect_related(ct, exp)) != 0) {
124 +               DEBUGP("Can't add new expectation. \n");
125 +       }
126 +
127 +       UNLOCK_BH(&ip_sip_lock);
128 +
129 +       return ret;
130 +}
131 +
132 +/*
133 +static int unset_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport)
134 +{
135 +       struct ip_conntrack_expect *exp;
136 +       const struct ip_conntrack_tuple tuple = { { 0, { 0 } },
137 +                       { dstip, { htons(dstport) }, IPPROTO_UDP }};
138 +
139 +       LOCK_BH(&ip_sip_lock);
140 +
141 +       exp = ip_conntrack_expect_find_get(&tuple);
142 +       if (exp) {
143 +               DEBUGP("Find the expectation %p, then delete it.\n", exp);
144 +               ip_conntrack_unexpect_related(exp);
145 +       }
146 +
147 +       UNLOCK_BH(&ip_sip_lock);
148 +
149 +       return 0;
150 +}*/
151 +
152 +/* return:
153 + *       0 : Not found
154 + *       1 : Found domain name
155 + *       2 : Found dotted quads
156 + */
157 +int find_sdp_rtp_addr(const char *data, size_t dlen,
158 +                       unsigned int *numoff, unsigned int *numlen, u_int32_t *addr)
159 +{
160 +       char *st, *p = (char *)data;
161 +       const char *limit = data + dlen;
162 +       unsigned char p1, p2, p3, p4;
163 +
164 +       while (p < limit) {
165 +               /* find 'c=' line */
166 +               if (strncmp(p, "\nc=",3) && strncmp(p, "\rc=",3)) {
167 +                       p++;
168 +                       continue;
169 +               }
170 +               p += 3;
171 +
172 +               if (strncmp(p, "IN IP4 ",7))
173 +                       continue;
174 +               p += 7;
175 +
176 +               /* IP address */
177 +               st = p;
178 +
179 +               /* FQDNs or dotted quads */
180 +               while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
181 +                       p++;
182 +                       if (p == limit)
183 +                               return 0;
184 +               }
185 +
186 +               *numoff = st - data;
187 +               *numlen = p - st;
188 +
189 +               /* Convert the IP address */
190 +               p1 = simple_strtoul(st, &st ,10);
191 +               if (*st != '.')
192 +                       return 1;
193 +               p2 = simple_strtoul(st+1, &st, 10);
194 +               if (*st != '.')
195 +                       return 1;
196 +               p3 = simple_strtoul(st+1, &st, 10);
197 +               if (*st != '.')
198 +                       return 1;
199 +               p4 = simple_strtoul(st+1, &st, 10);
200 +
201 +               *addr = (p1<<24) | (p2<<16) | (p3<<8) | p4;
202 +
203 +               return 2;
204 +       }
205 +
206 +       return 0;
207 +}
208 +
209 +u_int16_t find_sdp_audio_port(const char *data, size_t dlen,
210 +                       unsigned int *numoff, unsigned int *numlen)
211 +{
212 +       char *st, *p = (char *)data;
213 +       const char *limit = data + dlen;
214 +       u_int16_t port = 0;
215 +
216 +       while (p < limit) {
217 +               /* find 'm=' */
218 +               if (strncmp(p, "\nm=", 3) && strncmp(p, "\rm=", 3)) {
219 +                       p++;
220 +                       continue;
221 +               }
222 +               p += 3;
223 +
224 +               /* audio stream */
225 +               if (strncmp(p ,"audio ",6))
226 +                       continue;
227 +               p += 6;
228 +
229 +               st = p;
230 +               port = simple_strtoul(p, &p, 10);
231 +
232 +               *numoff = st - data;
233 +               *numlen = p - st;
234 +
235 +               return port;
236 +       }
237 +
238 +       return 0;
239 +}
240 +
241 +static int help(const struct iphdr *iph, size_t len,
242 +               struct ip_conntrack *ct,
243 +               enum ip_conntrack_info ctinfo)
244 +{
245 +       int dir = CTINFO2DIR(ctinfo);
246 +       unsigned int matchlen, matchoff;
247 +
248 +       u_int32_t ipaddr=0;
249 +       u_int16_t port = 0;
250 +
251 +       int found = 0;
252 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
253 +       const char *data = (const char *)udph + 8;
254 +       unsigned int udplen = len - iph->ihl * 4;
255 +       unsigned int datalen = udplen - 8;
256 +       struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
257 +
258 +       DEBUGP("\nconntrack_sip: help(): DIR=%d, conntrackinfo=%u\n", dir, ctinfo);
259 +       DEBUGP("conntrack_sip: %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", 
260 +                       NIPQUAD(ct->tuplehash[dir].tuple.src.ip),
261 +                       ntohs(ct->tuplehash[dir].tuple.src.u.udp.port),
262 +                       NIPQUAD(ct->tuplehash[dir].tuple.dst.ip), 
263 +                       ntohs(ct->tuplehash[dir].tuple.dst.u.udp.port) );
264 +
265 +       /* Reset for a new incoming packet */
266 +       ct_sip_info->mangled = 0;       
267 +
268 +       /* keep the connection alive */
269 +       ip_ct_refresh(ct, (SIP_EXPIRES * HZ));
270 +
271 +       /* Don't need to set the expectation for upstream direction */
272 +       if (dir == IP_CT_DIR_REPLY)
273 +               return NF_ACCEPT;
274 +
275 +       /* Need to set the expected connection for further incoming RTP stream */
276 +       if (strncmp(data, "INVITE", 6) != 0 && strncmp(data, "SIP/2.0 200", 11) != 0) {
277 +               DEBUGP("conntrack_sip: Not interesting packet.\n");
278 +               return NF_ACCEPT;
279 +       }
280 +
281 +       /* Find RTP address */
282 +       found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
283 +       if (!found)
284 +               return NF_ACCEPT;
285 +
286 +       DEBUGP("conntrack_sip: 'IN IP4' is %s.\n", (found == 1) ? "FQDNs" : "dotted quads");
287 +
288 +       /* If it's a null address, then the call is on hold */
289 +       if (found == 2 && ipaddr == 0) {
290 +               DEBUGP("conntrack_sip: Null address is found.\n");
291 +               return NF_ACCEPT;
292 +       }
293 +
294 +       /* Find audio port, and we don't like the well-known ports,
295 +        * which is less than 1024 */
296 +       port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen);
297 +       if (port < 1024)
298 +               return NF_ACCEPT;
299 +
300 +       DEBUGP("conntrack_sip: audio port=%d.\n", port);
301 +
302 +       ipaddr = ct->tuplehash[dir].tuple.src.ip; 
303 +       ct_sip_info->rtpport = port;
304 +
305 +       /* RFC1889 - RTP uses an even port number and the corresponding RTCP
306 +        * stream uses the next higher (odd) port number. */
307 +       if (set_expected_rtp(ct, ipaddr, port, CONN_RTP) == 0) {
308 +#ifdef RTCP_SUPPORT
309 +               set_expected_rtp(ct, ipaddr, port + 1, CONN_RTCP);
310 +#endif
311 +       }
312 +
313 +       return NF_ACCEPT;
314 +}
315 +
316 +static struct ip_conntrack_helper sip[MAX_PORTS];
317 +
318 +
319 +/* Not __exit: called from init() */
320 +static void fini(void)
321 +{
322 +       int i;
323 +       for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
324 +               DEBUGP("ip_ct_sip: unregistering helper for port %d\n",
325 +                               ports[i]);
326 +               ip_conntrack_helper_unregister(&sip[i]);
327 +       }
328 +}
329 +
330 +static int __init init(void)
331 +{
332 +       int i, ret;
333 +
334 +       if (ports[0] == 0)
335 +               ports[0] = SIP_PORT;
336 +
337 +       for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
338 +               memset(&sip[i], 0, sizeof(struct ip_conntrack_helper));
339 +               sip[i].tuple.dst.u.udp.port = htons(ports[i]);
340 +               sip[i].tuple.dst.protonum = IPPROTO_UDP;
341 +               sip[i].mask.dst.u.udp.port = 0xF0FF;
342 +               sip[i].mask.dst.protonum = 0xFFFF;
343 +               sip[i].help = help;
344 +               sip[i].timeout = RTP_TIMEOUT;
345 +               DEBUGP("ip_ct_sip: registering helper for port %d\n", 
346 +                               ports[i]);
347 +               ret = ip_conntrack_helper_register(&sip[i]);
348 +
349 +               if (ret) {
350 +                       fini();
351 +                       return ret;
352 +               }
353 +               ports_c++;
354 +       }
355 +       return 0;
356 +}
357 +
358 +
359 +EXPORT_SYMBOL(ip_sip_lock);
360 +EXPORT_SYMBOL(ip_conntrack_sip);
361 +
362 +module_init(init);
363 +module_exit(fini);
364 diff -urN linux-2.4.32/net/ipv4/netfilter/ip_nat_sip.c linux-2.4.32/net/ipv4/netfilter/ip_nat_sip.c
365 --- linux-2.4.32/net/ipv4/netfilter/ip_nat_sip.c        1970-01-01 01:00:00.000000000 +0100
366 +++ linux-2.4.32/net/ipv4/netfilter/ip_nat_sip.c        2005-12-11 21:35:51.000000000 +0100
367 @@ -0,0 +1,800 @@
368 +/*
369 + * SIP extension for TCP NAT alteration. 
370 + *
371 + * Copyright (C) 2004, CyberTAN Corporation
372 + * All Rights Reserved.
373 + *
374 + * THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY
375 + * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN
376 + * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
377 + * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
378 + *
379 + */
380
381 +#include <linux/module.h>
382 +#include <linux/netfilter_ipv4.h>
383 +#include <linux/ip.h>
384 +#include <linux/tcp.h>
385 +#include <linux/udp.h>
386 +#include <linux/ctype.h>
387 +#include <net/tcp.h>
388 +#include <net/udp.h>
389 +#include <linux/netfilter_ipv4/ip_nat.h>
390 +#include <linux/netfilter_ipv4/ip_nat_helper.h>
391 +#include <linux/netfilter_ipv4/ip_nat_rule.h>
392 +#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
393 +#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
394 +
395 +#if 0
396 +  #define DEBUGP printk
397 +#else
398 +  #define DEBUGP(format, args...)
399 +#endif
400 +
401 +#define MAX_PORTS 8
402 +static int ports[MAX_PORTS];
403 +static int ports_c = 0;
404 +
405 +#ifdef MODULE_PARM
406 +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
407 +#endif
408 +
409 +DECLARE_LOCK_EXTERN(ip_sip_lock);
410 +
411 +#define RTCP_SUPPORT
412 +
413 +/* down(stream): caller -> callee
414 +     up(stream): caller <- callee */
415 +
416 +
417 +/* Return 1 for match, 0 for accept, -1 for partial. */
418 +static int find_pattern(const char *data, size_t dlen,
419 +                       const char *pattern, size_t plen,
420 +                       char skip, char term,
421 +                       unsigned int *numoff,
422 +                       unsigned int *numlen
423 +                       )
424 +{
425 +       size_t i, j, k;
426 +
427 +//     DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
428 +       if (dlen == 0)
429 +               return 0;
430 +
431 +       if (dlen <= plen) {
432 +               /* Short packet: try for partial? */
433 +               if (strnicmp(data, pattern, dlen) == 0)
434 +                       return -1;
435 +               else return 0;
436 +       }
437 +
438 +       for(i=0; i<= (dlen - plen); i++){
439 +               if( memcmp(data + i, pattern, plen ) != 0 ) continue;   
440 +
441 +               /* patten match !! */   
442 +               *numoff=i + plen;
443 +               for (j=*numoff, k=0; data[j] != term; j++, k++)
444 +                       if( j > dlen ) return -1 ;      /* no terminal char */
445 +
446 +               *numlen = k;
447 +               return 1;
448 +       }
449 +
450 +       return 0;
451 +}
452 +
453 +static unsigned int
454 +sip_nat_expected(struct sk_buff **pskb,
455 +                unsigned int hooknum,
456 +                struct ip_conntrack *ct,
457 +                struct ip_nat_info *info)
458 +{
459 +       struct ip_nat_multi_range mr;
460 +       u_int32_t newdstip, newsrcip, newip;
461 +       struct ip_ct_sip_expect *exp_sip_info;
462 +       struct ip_conntrack *master = master_ct(ct);
463 +
464 +       IP_NF_ASSERT(info);
465 +       IP_NF_ASSERT(master);
466 +       IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
467 +
468 +       exp_sip_info = &ct->master->help.exp_sip_info;
469 +
470 +       LOCK_BH(&ip_sip_lock);
471 +
472 +       /* Outer machine IP */
473 +       newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
474 +       /* Client (virtual) IP under NAT */
475 +       newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
476 +
477 +       UNLOCK_BH(&ip_sip_lock);
478 +
479 +       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
480 +               newip = newsrcip;
481 +       else
482 +               newip = newdstip;
483 +
484 +       DEBUGP("sip_nat_expected: IP to %u.%u.%u.%u:%u\n", NIPQUAD(newip),
485 +                       htons(exp_sip_info->port));
486 +
487 +       mr.rangesize = 1;
488 +       /* We don't want to manip the per-protocol, just the IPs... */
489 +       mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
490 +       mr.range[0].min_ip = mr.range[0].max_ip = newip;
491 +
492 +       /* ... unless we're doing a MANIP_DST, in which case, make
493 +          sure we map to the correct port */
494 +       if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
495 +               mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
496 +               mr.range[0].min = mr.range[0].max
497 +                       = ((union ip_conntrack_manip_proto) 
498 +                                       { htons(exp_sip_info->port) });
499 +       }
500 +
501 +       return ip_nat_setup_info(ct, &mr, hooknum);
502 +}
503 +
504 +static int _find_sip_via_addrport(const char *data, size_t dlen,
505 +                       unsigned int *numoff, unsigned int *numlen)
506 +{
507 +       const char *addr, *p = data;
508 +       const char *limit = data + dlen;
509 +
510 +       while (p < limit) {
511 +               /* Find the topmost via tag */
512 +               if (strnicmp(p, "\nvia:",5) && strnicmp(p, "\nv:",3) &&
513 +                   strnicmp(p, "\rvia:",5) && strnicmp(p, "\rv:",3)) {
514 +                       p++;
515 +                       continue;
516 +               }
517 +
518 +               /* Look for UDP */
519 +               while (*p!='U' && *p!='u') {
520 +                       if (p == limit)
521 +                               return 0;
522 +                       p++;
523 +               }
524 +               p+= 3;
525 +
526 +               if (p >= limit)
527 +                       return 0;
528 +
529 +               /* Skip a space */
530 +               while (*p == ' '){
531 +                       if (p == limit)
532 +                               return 0;
533 +                       p++;
534 +               }
535 +
536 +               /* IP address */
537 +               addr = p;
538 +
539 +               /* FQDNs or dotted quads */
540 +               while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
541 +                       p++;
542 +                       if (p == limit)
543 +                               return 0;
544 +               }
545 +
546 +               /* If there is a port number, skip it */
547 +               if (*p == ':') {
548 +                       p++;
549 +                       if (p == limit)
550 +                               return 0;
551 +
552 +                       while (isdigit(*p)) {
553 +                               p++;
554 +                               if (p == limit)
555 +                                       return 0;
556 +                       }
557 +               }
558 +
559 +               *numoff = addr - data;
560 +               *numlen = p - addr;
561 +
562 +               return 1;
563 +       }
564 +
565 +       return 0;       /* Not found */
566 +}
567 +
568 +static int _mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
569 +               struct sk_buff **pskb, u_int32_t newip, u_int16_t newport,
570 +               unsigned int numoff, unsigned int numlen)
571 +{
572 +       int buflen;
573 +       char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
574 +
575 +       sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
576 +       buflen = strlen(buffer);
577 +
578 +       MUST_BE_LOCKED(&ip_sip_lock);
579 +
580 +       if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, numoff, 
581 +                               numlen, buffer, buflen) )
582 +               return 0;
583 +
584 +       DEBUGP("(SIP) Via is changed to %s.\n", buffer);
585 +
586 +       return buflen - numlen;
587 +}
588 +
589 +static int mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
590 +               struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
591 +{
592 +       struct iphdr *iph = (*pskb)->nh.iph;
593 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
594 +       const char *data = (const char *)udph + 8;
595 +       unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
596 +       unsigned int datalen = udplen - 8;
597 +       unsigned int matchoff, matchlen;
598 +
599 +        /* Find the topmost via tag */
600 +       _find_sip_via_addrport(data , datalen, &matchoff, &matchlen);
601 +       return _mangle_sip_via(ct, ctinfo, pskb, newip, newport,
602 +                       matchoff, matchlen);
603 +}
604 +
605 +static int mangle_sip_contact(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
606 +               struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
607 +{
608 +       struct iphdr *iph = (*pskb)->nh.iph;
609 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
610 +       const char *data = (const char *)udph + 8;
611 +       unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
612 +       unsigned int datalen = udplen - 8;
613 +
614 +       int buflen, diff_len = 0;
615 +       char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
616 +       const char *uri, *addr, *p = data;
617 +       const char *limit = data + datalen;
618 +
619 +
620 +       while (p < limit) {
621 +               if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) &&
622 +                   strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) {
623 +                       p++;
624 +                       continue;
625 +               }
626 +
627 +               while (strnicmp(p, "sip:", 4)) {
628 +                       if (p == limit)
629 +                               return 0;
630 +                       p++;
631 +               }
632 +               p += 4;
633 +
634 +               /* If there is user info in the contact */
635 +               uri = p;
636 +
637 +               while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
638 +                       if (p == limit)
639 +                               return 0;
640 +                       p++;
641 +               }
642 +
643 +               if (*p=='@')
644 +                       p++;
645 +               else
646 +                       p = uri;        /* back to previous URI pointer */
647 +
648 +               /* IP address */
649 +               addr = p;
650 +
651 +               /* FQDNs or dotted quads */
652 +               while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
653 +                       p++;
654 +                       if (p == limit)
655 +                               return 0;
656 +               }
657 +
658 +               /* If there is a port number, skip it */
659 +               if (*p==':') {
660 +                       p++;
661 +                       while (isdigit(*p))
662 +                               p++;
663 +               }
664 +
665 +               sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
666 +               buflen = strlen(buffer);
667 +
668 +               MUST_BE_LOCKED(&ip_sip_lock);
669 +
670 +               if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, 
671 +                                       p - addr, buffer, buflen) )
672 +                       return 0;
673 +       
674 +               diff_len = buflen - (p - addr);
675 +               DEBUGP("(SIP) Contact is changed to %s.\n", buffer);
676 +               break;
677 +       }
678 +
679 +       return diff_len;
680 +}
681 +
682 +static int _find_sip_content_length_size(const char *data, size_t dlen,
683 +                       unsigned int *numoff, unsigned int *numlen)
684 +{
685 +       char *st, *p = (char *)data;
686 +       const char *limit = data + dlen;
687 +       int size = 0;
688 +
689 +       while (p < limit) {
690 +               if (strnicmp(p, "\nContent-Length:", 16) && strnicmp(p, "\nl:", 3) &&
691 +                   strnicmp(p, "\rContent-Length:", 16) && strnicmp(p, "\rm:", 3)) {
692 +                       p++;
693 +                       continue;
694 +               }
695 +
696 +               /* Go through the string above */
697 +               while (*p != ':') {
698 +                       if (p == limit)
699 +                               return 0;
700 +                       p++;
701 +               }
702 +               p++;
703 +
704 +               while (*p == ' ') {
705 +                       if (p == limit)
706 +                               return 0;
707 +                       p++;
708 +               }
709 +
710 +               st = p;
711 +               size = simple_strtoul(p, &p, 10);
712 +
713 +               *numoff = st - data;
714 +               *numlen = p - st;
715 +
716 +               return size;
717 +       }
718 +
719 +       return 0;
720 +}
721 +
722 +static int mangle_sip_content_length(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
723 +               struct sk_buff **pskb, int diff_len)
724 +{
725 +       struct iphdr *iph = (*pskb)->nh.iph;
726 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
727 +       const char *data = (const char *)udph + 8;
728 +       unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
729 +       unsigned int datalen = udplen - 8;
730 +
731 +       unsigned int matchlen, matchoff;
732 +       int size, buflen;
733 +       char buffer[sizeof("nnnnn")];
734 +
735 +       /* original legth */
736 +       size = _find_sip_content_length_size(data, datalen, &matchoff, &matchlen);
737 +
738 +       /* new legth */
739 +       sprintf(buffer, "%u", size + diff_len);
740 +       buflen = strlen(buffer);
741 +
742 +       if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, 
743 +                               matchlen, buffer, buflen) )
744 +               return 0;
745 +
746 +       DEBUGP("(SDP) Content-Length is changed %d->%s.\n", size, buffer);
747 +       return buflen - matchlen;
748 +
749 +}
750 +
751 +static int mangle_sip_sdp_content(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
752 +               struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
753 +{
754 +       struct iphdr *iph = (*pskb)->nh.iph;
755 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
756 +       const char *data = (const char *)udph + 8;
757 +       unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
758 +       unsigned int datalen = udplen - 8;
759 +
760 +       unsigned int matchlen, matchoff;
761 +       int found, buflen, diff_len = 0;
762 +       char buffer[sizeof("nnn.nnn.nnn.nnn")];
763 +       char *addr, *p;
764 +       char *limit = (char *)data + datalen;
765 +       u_int32_t ipaddr = 0;
766 +       u_int16_t getport;
767 +       int dir;
768 +
769 +       /* Find RTP address */
770 +       found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
771 +       if (found) {
772 +               /* If it's a null address, then the call is on hold */
773 +               if (found == 2 && ipaddr == 0)
774 +                       return 0;
775 +                       
776 +               sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
777 +               buflen = strlen(buffer);
778 +
779 +               MUST_BE_LOCKED(&ip_sip_lock);
780 +
781 +               if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, 
782 +                                       matchlen, buffer, buflen) )
783 +                       return 0;
784 +       
785 +               diff_len += (buflen - matchlen);
786 +               DEBUGP("(SDP) RTP address is changed to %s.\n", buffer);
787 +       }
788 +
789 +       /* Find audio port */
790 +       getport = find_sdp_audio_port(data, datalen, &matchoff, &matchlen);
791 +       if (getport != newport) {
792 +               sprintf(buffer, "%d", newport);
793 +               buflen = strlen(buffer);
794 +
795 +               MUST_BE_LOCKED(&ip_sip_lock);
796 +
797 +               if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, 
798 +                                       matchlen, buffer, buflen) )
799 +                       return 0;
800 +
801 +               diff_len += (buflen - matchlen);
802 +               DEBUGP("(SDP) audio port is changed to %d.\n", newport);
803 +       }
804 +
805 +       dir = CTINFO2DIR(ctinfo);
806 +       if (dir == IP_CT_DIR_ORIGINAL)
807 +               return diff_len;
808 +
809 +       /* Find Session ID address */
810 +       found = find_pattern(data, datalen, " IN IP4 ", 8, ' ', '\r',
811 +                       &matchoff, &matchlen);
812 +       if (found) {
813 +               p = addr = (char *)data + matchoff;
814 +
815 +               /* FQDNs or dotted quads */
816 +               while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
817 +                       p++;
818 +                       if (p == limit)
819 +                               return 0;
820 +               }
821 +
822 +               sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
823 +               buflen = strlen(buffer);
824 +
825 +               MUST_BE_LOCKED(&ip_sip_lock);
826 +
827 +               if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, 
828 +                                       p - addr, buffer, buflen) )
829 +                       return 0;
830 +       
831 +               diff_len += (buflen - (p - addr));
832 +               DEBUGP("(SDP) Session ID is changed to %s.\n", buffer);
833 +       }
834 +
835 +       return diff_len;
836 +}
837 +
838 +static int mangle_sip_packet(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
839 +               struct sk_buff **pskb, u_int32_t newip)
840 +{
841 +       struct iphdr *iph = (*pskb)->nh.iph;
842 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
843 +       const char *data = (const char *)udph + 8;
844 +       int diff_len = 0;
845 +       struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
846 +       u_int16_t natport = ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port); 
847 +
848 +       DEBUGP("nat_sip: %s:(%d)\n", __FUNCTION__, __LINE__);
849 +
850 +       ct_sip_info->mangled = 1;
851 +
852 +       /* Changes the via, if this is a request */
853 +       if (strnicmp(data,"SIP/2.0",7) != 0) {
854 +               mangle_sip_via(ct, ctinfo, pskb, newip, natport);
855 +       }
856 +
857 +       mangle_sip_contact(ct, ctinfo, pskb, newip, natport);
858 +
859 +       if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, newip, ct_sip_info->rtpport)) != 0)
860 +               mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
861 +
862 +       return 1;
863 +}
864 +
865 +static struct ip_conntrack_expect *
866 +expect_find(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport)
867 +{
868 +       const struct ip_conntrack_tuple tuple = { { 0, { 0 } },
869 +                       { dstip, { htons(dstport) }, IPPROTO_UDP }};
870 +
871 +       return ip_conntrack_expect_find_get(&tuple);
872 +
873 +}
874 +
875 +static int sip_out_data_fixup(struct ip_conntrack *ct,
876 +               struct sk_buff **pskb,
877 +               enum ip_conntrack_info ctinfo,
878 +               struct ip_conntrack_expect *expect)
879 +{
880 +       struct ip_conntrack_tuple newtuple;
881 +       struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
882 +       struct ip_ct_sip_expect *exp_sip_info;
883 +       u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;     // NAT wan ip
884 +       u_int16_t port = 0;
885 +#ifdef RTCP_SUPPORT
886 +       struct ip_conntrack_expect *rtcp_exp;
887 +#endif
888 +
889 +       MUST_BE_LOCKED(&ip_sip_lock);
890 +
891 +       if (expect) {
892 +               DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
893 +
894 +               exp_sip_info = &expect->help.exp_sip_info;
895 +               if (exp_sip_info->nated) {
896 +                       DEBUGP("nat_sip: %s: The exp %p had been changed.\n", __FUNCTION__, expect);
897 +                       goto mangle;
898 +               }
899 +
900 +               /* RTP expect */
901 +               if (exp_sip_info->type == CONN_RTP) {
902 +                       port = ntohs(expect->tuple.dst.u.udp.port); 
903 +#ifdef RTCP_SUPPORT
904 +                       rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1); 
905 +#endif
906 +                       /* RFC1889 - If an application is supplied with an odd number
907 +                        * for use as the RTP port, it should replace this number with
908 +                        * the next lower (even) number. */
909 +                       if (port % 2) 
910 +                               port++;
911 +
912 +                       /* fullfill newtuple */
913 +                       newtuple.dst.ip = wanip;
914 +                       newtuple.src.ip = expect->tuple.src.ip;
915 +                       newtuple.dst.protonum = expect->tuple.dst.protonum;
916 +
917 +                       /* Try to get same port: if not, try to change it. */
918 +                       for (; port != 0; port += 2) {
919 +                               newtuple.dst.u.udp.port = htons(port);
920 +                               if (ip_conntrack_change_expect(expect, &newtuple) == 0) {
921 +#ifdef RTCP_SUPPORT
922 +                                       /* Change RTCP */
923 +                                       if (rtcp_exp) {
924 +                                               DEBUGP("nat_sip: %s: RTCP exp %p found.\n",
925 +                                                               __FUNCTION__, rtcp_exp);
926 +                                               newtuple.dst.u.udp.port = htons(port + 1);
927 +                                               if (ip_conntrack_change_expect(rtcp_exp, &newtuple) != 0) {
928 +                                                       DEBUGP("nat_sip: %s: Can't change RTCP exp %p.\n",
929 +                                                                       __FUNCTION__, rtcp_exp);
930 +                                                       continue;
931 +                                               }
932 +                                               rtcp_exp->help.exp_sip_info.nated = 1;
933 +                                       }
934 +#endif
935 +                                       break;
936 +                               }
937 +                       }
938 +                       if (port == 0)
939 +                               return 0;
940 +
941 +                       exp_sip_info->nated = 1;
942 +                       ct_sip_info->rtpport = port;
943 +                       DEBUGP("nat_sip: %s: RTP exp %p, masq port=%d\n", __FUNCTION__, expect, port);
944 +               }
945 +#ifdef RTCP_SUPPORT
946 +               else {
947 +                       /* We ignore the RTCP expect, and will adjust it later
948 +                        * during RTP expect */
949 +                       DEBUGP("nat_sip: %s: RTCP exp %p, by-pass.\n", __FUNCTION__, expect);
950 +                       return 1;
951 +               }
952 +#endif
953 +       }
954 +
955 +mangle:
956 +       /* Change address inside packet to match way we're mapping
957 +          this connection. */
958 +       if (!ct_sip_info->mangled)
959 +               if (!mangle_sip_packet(ct, ctinfo, pskb, wanip))
960 +                       return 0;
961 +
962 +       return 1;
963 +}
964 +
965 +static int sip_in_data_fixup(struct ip_conntrack *ct,
966 +               struct sk_buff **pskb,
967 +               enum ip_conntrack_info ctinfo,
968 +               struct ip_conntrack_expect *expect)
969 +{
970 +       struct iphdr *iph = (*pskb)->nh.iph;
971 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
972 +       const char *data = (const char *)udph + 8;
973 +       unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
974 +       unsigned int datalen = udplen - 8;
975 +       struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
976 +       u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;     // NAT wan ip
977 +       unsigned int matchlen, matchoff;
978 +       int found, diff_len = 0;
979 +       u_int32_t ipaddr = 0, vip = 0;
980 +       u_int16_t port = 0, vport = 0, aport = 0;
981 +       struct ip_conntrack_expect *exp;
982 +#ifdef RTCP_SUPPORT
983 +       struct ip_conntrack_expect *rtcpexp;
984 +#endif
985 +
986 +       if (expect)
987 +               DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
988 +
989 +       /* Prevent from mangling the packet or expect twice */
990 +       if (ct_sip_info->mangled)
991 +               return 1;
992 +
993 +       ct_sip_info->mangled = 1;
994 +
995 +       if (strnicmp(data, "SIP/2.0 200", 11) == 0) {
996 +               /* Find CSeq field */
997 +               found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
998 +                               &matchoff, &matchlen);
999 +               if (found) {
1000 +                       char *p = (char *)data + matchoff;
1001 +
1002 +                       simple_strtoul(p, &p, 10);
1003 +                       if (strnicmp(p, " REGISTER", 9) == 0) {
1004 +                               DEBUGP("nat_sip: 200 OK - REGISTER\n");
1005 +                               vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1006 +                               vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
1007 +                               mangle_sip_via(ct, ctinfo, pskb, vip, vport);
1008 +                               mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
1009 +                               return 1;
1010 +                       }
1011 +               }
1012 +       }
1013 +
1014 +       /* Only interesting the SDP content. */
1015 +       if (strnicmp(data, "INVITE", 6) != 0 && strnicmp(data, "SIP/2.0 200", 11) != 0)
1016 +               return 1;
1017 +       
1018 +       /* Find RTP address */
1019 +       found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
1020 +
1021 +       DEBUGP("nat_sip: sdp address found = %d, ipaddr = %u.\n", found, ipaddr);
1022 +       if (found < 2)
1023 +               return 1;
1024 +
1025 +       /* Is it a null address or our WAN address? */
1026 +       if (ipaddr == 0 || (htonl(ipaddr) != wanip))
1027 +               return 1;
1028 +
1029 +       DEBUGP("nat_sip: %s: This is a lookback RTP connection.\n", __FUNCTION__);
1030 +
1031 +       /* Find audio port, and we don't like the well-known ports,
1032 +        * which is less than 1024 */
1033 +       port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen);
1034 +       if (port < 1024)
1035 +               return 0;
1036 +       
1037 +       exp = expect_find(ct, wanip, port);
1038 +       if (exp) {
1039 +               DEBUGP("nat_sip: %s: Found exp %p, tuple.dst=%u.%u.%u.%u:%u.\n",
1040 +                               __FUNCTION__, exp, NIPQUAD(ipaddr), port);
1041 +
1042 +               /* Restore masq-ed SDP */
1043 +               vip = exp->expectant->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1044 +               aport = exp->help.exp_sip_info.port;
1045 +               if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, vip, aport)) != 0)
1046 +                       mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
1047 +
1048 +               /* Unset RTP, RTCP expect, respectively */
1049 +               ip_conntrack_unexpect_related(exp);
1050 +#ifdef RTCP_SUPPORT
1051 +               rtcpexp = expect_find(ct, wanip, port + 1);
1052 +               if (rtcpexp)
1053 +                       ip_conntrack_unexpect_related(rtcpexp);
1054 +#endif
1055 +       }
1056 +
1057 +       return 1;
1058 +}
1059 +
1060 +static unsigned int nat_help(struct ip_conntrack *ct,
1061 +                        struct ip_conntrack_expect *exp,
1062 +                        struct ip_nat_info *info,
1063 +                        enum ip_conntrack_info ctinfo,
1064 +                        unsigned int hooknum,
1065 +                        struct sk_buff **pskb)
1066 +{
1067 +       int dir;
1068 +       struct iphdr *iph = (*pskb)->nh.iph;
1069 +       struct udphdr *udph = (void *)iph + iph->ihl * 4;
1070 +       const char *data = (const char *)udph + 8;
1071 +
1072 +       /* Only mangle things once: original direction in POST_ROUTING
1073 +          and reply direction on PRE_ROUTING. */
1074 +       dir = CTINFO2DIR(ctinfo);
1075 +       if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
1076 +             || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
1077 +               DEBUGP("nat_sip: Not touching dir %s at hook %s\n",
1078 +                      dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
1079 +                      hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
1080 +                      : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
1081 +                      : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
1082 +               return NF_ACCEPT;
1083 +       }
1084 +
1085 +       if (strnicmp(data, "REGISTER" , 8) == 0)
1086 +               DEBUGP("nat_sip: REGISTER\n");
1087 +       else if (strnicmp(data, "INVITE" , 6) == 0)
1088 +               DEBUGP("nat_sip: INVITE\n");
1089 +       else if (strnicmp(data, "ACK" , 3) == 0)
1090 +               DEBUGP("nat_sip: ACK\n");
1091 +       else if (strnicmp(data, "BYE", 3) == 0)
1092 +               DEBUGP("nat_sip: BYE\n");
1093 +       else if (strnicmp(data, "SIP/2.0 200", 11) == 0)
1094 +               DEBUGP("nat_sip: 200 OK\n");
1095 +       else if (strnicmp(data, "SIP/2.0 100", 11) == 0)
1096 +               DEBUGP("nat_sip: 100 Trying\n");
1097 +       else if (strnicmp(data, "SIP/2.0 180", 11) == 0)
1098 +               DEBUGP("nat_sip: 180 Ringing\n");
1099 +
1100 +       LOCK_BH(&ip_sip_lock);
1101 +
1102 +       if (dir == IP_CT_DIR_ORIGINAL)
1103 +               sip_out_data_fixup(ct, pskb, ctinfo, exp);
1104 +       else
1105 +               sip_in_data_fixup(ct, pskb, ctinfo, exp);
1106 +
1107 +       UNLOCK_BH(&ip_sip_lock);
1108 +
1109 +       return NF_ACCEPT;
1110 +}
1111 +
1112 +static struct ip_nat_helper sip[MAX_PORTS];
1113 +static char sip_names[MAX_PORTS][6];
1114 +
1115 +/* Not __exit: called from init() */
1116 +static void fini(void)
1117 +{
1118 +       int i;
1119 +
1120 +       for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1121 +               DEBUGP("ip_nat_sip: unregistering port %d\n", ports[i]);
1122 +               ip_nat_helper_unregister(&sip[i]);
1123 +       }
1124 +}
1125 +
1126 +static int __init init(void)
1127 +{
1128 +       int i, ret=0;
1129 +       char *tmpname;
1130 +
1131 +       if (ports[0] == 0)
1132 +               ports[0] = SIP_PORT;
1133 +
1134 +       for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1135 +
1136 +               memset(&sip[i], 0, sizeof(struct ip_nat_helper));
1137 +
1138 +               sip[i].tuple.dst.u.udp.port = htons(ports[i]);
1139 +               sip[i].tuple.dst.protonum = IPPROTO_UDP;
1140 +               sip[i].mask.dst.u.udp.port = 0xF0FF;
1141 +               sip[i].mask.dst.protonum = 0xFFFF;
1142 +               sip[i].help = nat_help;
1143 +               sip[i].expect = sip_nat_expected;
1144 +               sip[i].flags = IP_NAT_HELPER_F_ALWAYS;
1145 +
1146 +               tmpname = &sip_names[i][0];
1147 +               sprintf(tmpname, "sip%2.2d", i);
1148 +               sip[i].name = tmpname;
1149 +
1150 +               DEBUGP("ip_nat_sip: Trying to register for port %d\n",
1151 +                               ports[i]);
1152 +               ret = ip_nat_helper_register(&sip[i]);
1153 +
1154 +               if (ret) {
1155 +                       printk("ip_nat_sip: error registering "
1156 +                              "helper for port %d\n", ports[i]);
1157 +                       fini();
1158 +                       return ret;
1159 +               }
1160 +               ports_c++;
1161 +       }
1162 +
1163 +       return ret;
1164 +}
1165 +
1166 +module_init(init);
1167 +module_exit(fini);
1168 diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h
1169 --- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h    2005-12-11 21:34:32.000000000 +0100
1170 +++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack.h    2005-12-11 22:06:57.000000000 +0100
1171 @@ -71,6 +71,7 @@
1172  #include <linux/netfilter_ipv4/ip_conntrack_ftp.h>
1173  #include <linux/netfilter_ipv4/ip_conntrack_irc.h>
1174  #include <linux/netfilter_ipv4/ip_conntrack_pptp.h>
1175 +#include <linux/netfilter_ipv4/ip_conntrack_sip.h>
1176  
1177  /* per expectation: application helper private data */
1178  union ip_conntrack_expect_help {
1179 @@ -79,6 +80,7 @@
1180         struct ip_ct_ftp_expect exp_ftp_info;
1181         struct ip_ct_irc_expect exp_irc_info;
1182         struct ip_ct_pptp_expect exp_pptp_info;
1183 +       struct ip_ct_sip_expect exp_sip_info;
1184  
1185  #ifdef CONFIG_IP_NF_NAT_NEEDED
1186         union {
1187 @@ -93,6 +95,7 @@
1188         struct ip_ct_ftp_master ct_ftp_info;
1189         struct ip_ct_irc_master ct_irc_info;
1190         struct ip_ct_pptp_master ct_pptp_info;
1191 +       struct ip_ct_sip_master ct_sip_info;
1192  };
1193  
1194  #ifdef CONFIG_IP_NF_NAT_NEEDED
1195 diff -urN linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_sip.h linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_sip.h
1196 --- linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_sip.h        1970-01-01 01:00:00.000000000 +0100
1197 +++ linux-2.4.32/include/linux/netfilter_ipv4/ip_conntrack_sip.h        2005-12-11 21:35:51.000000000 +0100
1198 @@ -0,0 +1,56 @@
1199 +#ifndef _IP_CONNTRACK_SIP_H
1200 +#define _IP_CONNTRACK_SIP_H
1201 +/* SIP tracking. */
1202 +
1203 +#ifdef __KERNEL__
1204 +
1205 +#include <linux/netfilter_ipv4/lockhelp.h>
1206 +
1207 +/* Protects sip part of conntracks */
1208 +DECLARE_LOCK_EXTERN(ip_sip_lock);
1209 +
1210 +#define SIP_PORT       5060    /* UDP */
1211 +#define SIP_EXPIRES    3600    /* seconds */
1212 +#define RTP_TIMEOUT    180     /* seconds */
1213 +
1214 +#endif /* __KERNEL__ */
1215 +
1216 +/* SIP Request */
1217 +#define SIP_INVITE             0x01
1218 +#define SIP_ACK                        0x02
1219 +#define SIP_BYE                        0x04
1220 +/* SIP Response */
1221 +#define SIP_100                        0x10
1222 +#define SIP_200                        0x20
1223 +#define SIP_200_BYE            0x40
1224 +/* SIP session direction */
1225 +#define SIP_OUTGOING           0
1226 +#define SIP_INCOMING           1
1227 +
1228 +enum ip_ct_conntype
1229 +{
1230 +       CONN_SIP,
1231 +       CONN_RTP,
1232 +       CONN_RTCP,
1233 +};
1234 +
1235 +/* This structure is per expected connection */
1236 +struct ip_ct_sip_expect
1237 +{
1238 +       u_int16_t port;                 /* TCP port that was to be used */
1239 +
1240 +       enum ip_ct_conntype type;
1241 +       int nated;
1242 +};
1243 +
1244 +/* This structure exists only once per master */
1245 +struct ip_ct_sip_master {
1246 +       int mangled;
1247 +       u_int16_t rtpport;
1248 +};
1249 +
1250 +extern u_int16_t find_sdp_audio_port(const char *data, size_t dlen,
1251 +               unsigned int *numoff, unsigned int *numlen);
1252 +extern int find_sdp_rtp_addr(const char *data, size_t dlen,
1253 +                       unsigned int *numoff, unsigned int *numlen, u_int32_t *addr);
1254 +#endif /* _IP_CONNTRACK_SIP_H */