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