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
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
11 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
13 define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT
16 + if [ "$CONFIG_IP_NF_SIP" = "m" ]; then
17 + define_tristate CONFIG_IP_NF_NAT_SIP m
19 + if [ "$CONFIG_IP_NF_SIP" = "y" ]; then
20 + define_tristate CONFIG_IP_NF_NAT_SIP $CONFIG_IP_NF_NAT
23 if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then
24 define_tristate CONFIG_IP_NF_NAT_AMANDA m
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
30 ifdef CONFIG_IP_NF_NAT_PPTP
31 export-objs += ip_conntrack_pptp.o
33 +obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o
34 +ifdef CONFIG_IP_NF_NAT_SIP
35 + export-objs += ip_conntrack_sip.o
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
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
53 + * SIP extension for IP connection tracking.
55 + * Copyright (C) 2004, CyberTAN Corporation
56 + * All Rights Reserved.
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.
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>
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>
77 +DECLARE_LOCK(ip_sip_lock);
79 +struct module *ip_conntrack_sip = THIS_MODULE;
82 +static int ports[MAX_PORTS];
85 +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
89 + #define DEBUGP printk
91 + #define DEBUGP(format, args...)
96 +static int set_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip,
97 + u_int16_t dstport, unsigned int conntype)
99 + struct ip_conntrack_expect expect, *exp = &expect;
100 + struct ip_ct_sip_expect *exp_sip_info = &exp->help.exp_sip_info;
103 + memset(&expect, 0, sizeof(expect));
104 + LOCK_BH(&ip_sip_lock);
106 + DEBUGP("conntrack_sip: %s: [%s]: DST=%u.%u.%u.%u:%u\n", __FUNCTION__,
107 + conntype == CONN_RTP ? "RTP" : "RTCP", NIPQUAD(dstip), dstport);
110 + exp_sip_info->port = dstport;
111 + exp_sip_info->type = conntype;
112 + exp_sip_info->nated = 0;
114 + /* new expectation */
115 + exp->tuple = ((struct ip_conntrack_tuple)
117 + { dstip, { htons(dstport) }, IPPROTO_UDP }});
118 + exp->mask = ((struct ip_conntrack_tuple)
120 + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }});
121 + exp->expectfn = NULL;
123 + if ((ret=ip_conntrack_expect_related(ct, exp)) != 0) {
124 + DEBUGP("Can't add new expectation. \n");
127 + UNLOCK_BH(&ip_sip_lock);
133 +static int unset_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport)
135 + struct ip_conntrack_expect *exp;
136 + const struct ip_conntrack_tuple tuple = { { 0, { 0 } },
137 + { dstip, { htons(dstport) }, IPPROTO_UDP }};
139 + LOCK_BH(&ip_sip_lock);
141 + exp = ip_conntrack_expect_find_get(&tuple);
143 + DEBUGP("Find the expectation %p, then delete it.\n", exp);
144 + ip_conntrack_unexpect_related(exp);
147 + UNLOCK_BH(&ip_sip_lock);
154 + * 1 : Found domain name
155 + * 2 : Found dotted quads
157 +int find_sdp_rtp_addr(const char *data, size_t dlen,
158 + unsigned int *numoff, unsigned int *numlen, u_int32_t *addr)
160 + char *st, *p = (char *)data;
161 + const char *limit = data + dlen;
162 + unsigned char p1, p2, p3, p4;
164 + while (p < limit) {
165 + /* find 'c=' line */
166 + if (strncmp(p, "\nc=",3) && strncmp(p, "\rc=",3)) {
172 + if (strncmp(p, "IN IP4 ",7))
179 + /* FQDNs or dotted quads */
180 + while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
186 + *numoff = st - data;
189 + /* Convert the IP address */
190 + p1 = simple_strtoul(st, &st ,10);
193 + p2 = simple_strtoul(st+1, &st, 10);
196 + p3 = simple_strtoul(st+1, &st, 10);
199 + p4 = simple_strtoul(st+1, &st, 10);
201 + *addr = (p1<<24) | (p2<<16) | (p3<<8) | p4;
209 +u_int16_t find_sdp_audio_port(const char *data, size_t dlen,
210 + unsigned int *numoff, unsigned int *numlen)
212 + char *st, *p = (char *)data;
213 + const char *limit = data + dlen;
214 + u_int16_t port = 0;
216 + while (p < limit) {
218 + if (strncmp(p, "\nm=", 3) && strncmp(p, "\rm=", 3)) {
225 + if (strncmp(p ,"audio ",6))
230 + port = simple_strtoul(p, &p, 10);
232 + *numoff = st - data;
241 +static int help(const struct iphdr *iph, size_t len,
242 + struct ip_conntrack *ct,
243 + enum ip_conntrack_info ctinfo)
245 + int dir = CTINFO2DIR(ctinfo);
246 + unsigned int matchlen, matchoff;
248 + u_int32_t ipaddr=0;
249 + u_int16_t port = 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;
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) );
265 + /* Reset for a new incoming packet */
266 + ct_sip_info->mangled = 0;
268 + /* keep the connection alive */
269 + ip_ct_refresh(ct, (SIP_EXPIRES * HZ));
271 + /* Don't need to set the expectation for upstream direction */
272 + if (dir == IP_CT_DIR_REPLY)
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");
281 + /* Find RTP address */
282 + found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
286 + DEBUGP("conntrack_sip: 'IN IP4' is %s.\n", (found == 1) ? "FQDNs" : "dotted quads");
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");
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);
300 + DEBUGP("conntrack_sip: audio port=%d.\n", port);
302 + ipaddr = ct->tuplehash[dir].tuple.src.ip;
303 + ct_sip_info->rtpport = port;
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) {
309 + set_expected_rtp(ct, ipaddr, port + 1, CONN_RTCP);
316 +static struct ip_conntrack_helper sip[MAX_PORTS];
319 +/* Not __exit: called from init() */
320 +static void fini(void)
323 + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
324 + DEBUGP("ip_ct_sip: unregistering helper for port %d\n",
326 + ip_conntrack_helper_unregister(&sip[i]);
330 +static int __init init(void)
335 + ports[0] = SIP_PORT;
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",
347 + ret = ip_conntrack_helper_register(&sip[i]);
359 +EXPORT_SYMBOL(ip_sip_lock);
360 +EXPORT_SYMBOL(ip_conntrack_sip);
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
369 + * SIP extension for TCP NAT alteration.
371 + * Copyright (C) 2004, CyberTAN Corporation
372 + * All Rights Reserved.
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.
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>
396 + #define DEBUGP printk
398 + #define DEBUGP(format, args...)
402 +static int ports[MAX_PORTS];
403 +static int ports_c = 0;
406 +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
409 +DECLARE_LOCK_EXTERN(ip_sip_lock);
411 +#define RTCP_SUPPORT
413 +/* down(stream): caller -> callee
414 + up(stream): caller <- callee */
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
427 +// DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
431 + if (dlen <= plen) {
432 + /* Short packet: try for partial? */
433 + if (strnicmp(data, pattern, dlen) == 0)
438 + for(i=0; i<= (dlen - plen); i++){
439 + if( memcmp(data + i, pattern, plen ) != 0 ) continue;
441 + /* patten match !! */
443 + for (j=*numoff, k=0; data[j] != term; j++, k++)
444 + if( j > dlen ) return -1 ; /* no terminal char */
454 +sip_nat_expected(struct sk_buff **pskb,
455 + unsigned int hooknum,
456 + struct ip_conntrack *ct,
457 + struct ip_nat_info *info)
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);
464 + IP_NF_ASSERT(info);
465 + IP_NF_ASSERT(master);
466 + IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
468 + exp_sip_info = &ct->master->help.exp_sip_info;
470 + LOCK_BH(&ip_sip_lock);
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;
477 + UNLOCK_BH(&ip_sip_lock);
479 + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
484 + DEBUGP("sip_nat_expected: IP to %u.%u.%u.%u:%u\n", NIPQUAD(newip),
485 + htons(exp_sip_info->port));
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;
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) });
501 + return ip_nat_setup_info(ct, &mr, hooknum);
504 +static int _find_sip_via_addrport(const char *data, size_t dlen,
505 + unsigned int *numoff, unsigned int *numlen)
507 + const char *addr, *p = data;
508 + const char *limit = data + dlen;
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)) {
519 + while (*p!='U' && *p!='u') {
539 + /* FQDNs or dotted quads */
540 + while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
546 + /* If there is a port number, skip it */
552 + while (isdigit(*p)) {
559 + *numoff = addr - data;
560 + *numlen = p - addr;
565 + return 0; /* Not found */
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)
573 + char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
575 + sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
576 + buflen = strlen(buffer);
578 + MUST_BE_LOCKED(&ip_sip_lock);
580 + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, numoff,
581 + numlen, buffer, buflen) )
584 + DEBUGP("(SIP) Via is changed to %s.\n", buffer);
586 + return buflen - numlen;
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)
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;
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);
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)
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;
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;
620 + while (p < limit) {
621 + if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) &&
622 + strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) {
627 + while (strnicmp(p, "sip:", 4)) {
634 + /* If there is user info in the contact */
637 + while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
646 + p = uri; /* back to previous URI pointer */
651 + /* FQDNs or dotted quads */
652 + while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
658 + /* If there is a port number, skip it */
661 + while (isdigit(*p))
665 + sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
666 + buflen = strlen(buffer);
668 + MUST_BE_LOCKED(&ip_sip_lock);
670 + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data,
671 + p - addr, buffer, buflen) )
674 + diff_len = buflen - (p - addr);
675 + DEBUGP("(SIP) Contact is changed to %s.\n", buffer);
682 +static int _find_sip_content_length_size(const char *data, size_t dlen,
683 + unsigned int *numoff, unsigned int *numlen)
685 + char *st, *p = (char *)data;
686 + const char *limit = data + dlen;
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)) {
696 + /* Go through the string above */
697 + while (*p != ':') {
704 + while (*p == ' ') {
711 + size = simple_strtoul(p, &p, 10);
713 + *numoff = st - data;
722 +static int mangle_sip_content_length(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
723 + struct sk_buff **pskb, int diff_len)
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;
731 + unsigned int matchlen, matchoff;
733 + char buffer[sizeof("nnnnn")];
735 + /* original legth */
736 + size = _find_sip_content_length_size(data, datalen, &matchoff, &matchlen);
739 + sprintf(buffer, "%u", size + diff_len);
740 + buflen = strlen(buffer);
742 + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
743 + matchlen, buffer, buflen) )
746 + DEBUGP("(SDP) Content-Length is changed %d->%s.\n", size, buffer);
747 + return buflen - matchlen;
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)
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;
760 + unsigned int matchlen, matchoff;
761 + int found, buflen, diff_len = 0;
762 + char buffer[sizeof("nnn.nnn.nnn.nnn")];
764 + char *limit = (char *)data + datalen;
765 + u_int32_t ipaddr = 0;
769 + /* Find RTP address */
770 + found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
772 + /* If it's a null address, then the call is on hold */
773 + if (found == 2 && ipaddr == 0)
776 + sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
777 + buflen = strlen(buffer);
779 + MUST_BE_LOCKED(&ip_sip_lock);
781 + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
782 + matchlen, buffer, buflen) )
785 + diff_len += (buflen - matchlen);
786 + DEBUGP("(SDP) RTP address is changed to %s.\n", buffer);
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);
795 + MUST_BE_LOCKED(&ip_sip_lock);
797 + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
798 + matchlen, buffer, buflen) )
801 + diff_len += (buflen - matchlen);
802 + DEBUGP("(SDP) audio port is changed to %d.\n", newport);
805 + dir = CTINFO2DIR(ctinfo);
806 + if (dir == IP_CT_DIR_ORIGINAL)
809 + /* Find Session ID address */
810 + found = find_pattern(data, datalen, " IN IP4 ", 8, ' ', '\r',
811 + &matchoff, &matchlen);
813 + p = addr = (char *)data + matchoff;
815 + /* FQDNs or dotted quads */
816 + while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
822 + sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
823 + buflen = strlen(buffer);
825 + MUST_BE_LOCKED(&ip_sip_lock);
827 + if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data,
828 + p - addr, buffer, buflen) )
831 + diff_len += (buflen - (p - addr));
832 + DEBUGP("(SDP) Session ID is changed to %s.\n", buffer);
838 +static int mangle_sip_packet(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
839 + struct sk_buff **pskb, u_int32_t newip)
841 + struct iphdr *iph = (*pskb)->nh.iph;
842 + struct udphdr *udph = (void *)iph + iph->ihl * 4;
843 + const char *data = (const char *)udph + 8;
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);
848 + DEBUGP("nat_sip: %s:(%d)\n", __FUNCTION__, __LINE__);
850 + ct_sip_info->mangled = 1;
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);
857 + mangle_sip_contact(ct, ctinfo, pskb, newip, natport);
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);
865 +static struct ip_conntrack_expect *
866 +expect_find(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport)
868 + const struct ip_conntrack_tuple tuple = { { 0, { 0 } },
869 + { dstip, { htons(dstport) }, IPPROTO_UDP }};
871 + return ip_conntrack_expect_find_get(&tuple);
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)
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;
886 + struct ip_conntrack_expect *rtcp_exp;
889 + MUST_BE_LOCKED(&ip_sip_lock);
892 + DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
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);
901 + if (exp_sip_info->type == CONN_RTP) {
902 + port = ntohs(expect->tuple.dst.u.udp.port);
904 + rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1);
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. */
912 + /* fullfill newtuple */
913 + newtuple.dst.ip = wanip;
914 + newtuple.src.ip = expect->tuple.src.ip;
915 + newtuple.dst.protonum = expect->tuple.dst.protonum;
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) {
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);
932 + rtcp_exp->help.exp_sip_info.nated = 1;
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);
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);
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))
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)
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;
983 + struct ip_conntrack_expect *rtcpexp;
987 + DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
989 + /* Prevent from mangling the packet or expect twice */
990 + if (ct_sip_info->mangled)
993 + ct_sip_info->mangled = 1;
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);
1000 + char *p = (char *)data + matchoff;
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);
1014 + /* Only interesting the SDP content. */
1015 + if (strnicmp(data, "INVITE", 6) != 0 && strnicmp(data, "SIP/2.0 200", 11) != 0)
1018 + /* Find RTP address */
1019 + found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
1021 + DEBUGP("nat_sip: sdp address found = %d, ipaddr = %u.\n", found, ipaddr);
1025 + /* Is it a null address or our WAN address? */
1026 + if (ipaddr == 0 || (htonl(ipaddr) != wanip))
1029 + DEBUGP("nat_sip: %s: This is a lookback RTP connection.\n", __FUNCTION__);
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);
1037 + exp = expect_find(ct, wanip, port);
1039 + DEBUGP("nat_sip: %s: Found exp %p, tuple.dst=%u.%u.%u.%u:%u.\n",
1040 + __FUNCTION__, exp, NIPQUAD(ipaddr), port);
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);
1048 + /* Unset RTP, RTCP expect, respectively */
1049 + ip_conntrack_unexpect_related(exp);
1050 +#ifdef RTCP_SUPPORT
1051 + rtcpexp = expect_find(ct, wanip, port + 1);
1053 + ip_conntrack_unexpect_related(rtcpexp);
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)
1068 + struct iphdr *iph = (*pskb)->nh.iph;
1069 + struct udphdr *udph = (void *)iph + iph->ihl * 4;
1070 + const char *data = (const char *)udph + 8;
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" : "???");
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");
1100 + LOCK_BH(&ip_sip_lock);
1102 + if (dir == IP_CT_DIR_ORIGINAL)
1103 + sip_out_data_fixup(ct, pskb, ctinfo, exp);
1105 + sip_in_data_fixup(ct, pskb, ctinfo, exp);
1107 + UNLOCK_BH(&ip_sip_lock);
1112 +static struct ip_nat_helper sip[MAX_PORTS];
1113 +static char sip_names[MAX_PORTS][6];
1115 +/* Not __exit: called from init() */
1116 +static void fini(void)
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]);
1126 +static int __init init(void)
1131 + if (ports[0] == 0)
1132 + ports[0] = SIP_PORT;
1134 + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1136 + memset(&sip[i], 0, sizeof(struct ip_nat_helper));
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;
1146 + tmpname = &sip_names[i][0];
1147 + sprintf(tmpname, "sip%2.2d", i);
1148 + sip[i].name = tmpname;
1150 + DEBUGP("ip_nat_sip: Trying to register for port %d\n",
1152 + ret = ip_nat_helper_register(&sip[i]);
1155 + printk("ip_nat_sip: error registering "
1156 + "helper for port %d\n", ports[i]);
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
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>
1177 /* per expectation: application helper private data */
1178 union ip_conntrack_expect_help {
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;
1185 #ifdef CONFIG_IP_NF_NAT_NEEDED
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;
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
1199 +#ifndef _IP_CONNTRACK_SIP_H
1200 +#define _IP_CONNTRACK_SIP_H
1201 +/* SIP tracking. */
1205 +#include <linux/netfilter_ipv4/lockhelp.h>
1207 +/* Protects sip part of conntracks */
1208 +DECLARE_LOCK_EXTERN(ip_sip_lock);
1210 +#define SIP_PORT 5060 /* UDP */
1211 +#define SIP_EXPIRES 3600 /* seconds */
1212 +#define RTP_TIMEOUT 180 /* seconds */
1214 +#endif /* __KERNEL__ */
1217 +#define SIP_INVITE 0x01
1218 +#define SIP_ACK 0x02
1219 +#define SIP_BYE 0x04
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
1228 +enum ip_ct_conntype
1235 +/* This structure is per expected connection */
1236 +struct ip_ct_sip_expect
1238 + u_int16_t port; /* TCP port that was to be used */
1240 + enum ip_ct_conntype type;
1244 +/* This structure exists only once per master */
1245 +struct ip_ct_sip_master {
1247 + u_int16_t rtpport;
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 */