large target/linux cleanup
[openwrt/svn-archive/archive.git] / openwrt / 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 */