2 * SIP extension for UDP/TCP NAT alteration.
5 #include <linux/module.h>
6 #include <linux/netfilter_ipv4.h>
10 #include <linux/ctype.h>
13 #include <linux/netfilter_ipv4/ip_nat.h>
14 #include <linux/netfilter_ipv4/ip_nat_helper.h>
15 #include <linux/netfilter_ipv4/ip_nat_rule.h>
16 #include <linux/netfilter_ipv4/ip_conntrack_sip.h>
17 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
23 #define DEBUGP(format, args...)
27 static int ports[MAX_PORTS];
28 static int ports_c = 0;
31 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i");
34 DECLARE_LOCK_EXTERN(ip_sip_lock);
39 /*dump_packet(struct sk_buff **pskb)
41 struct iphdr *iph = (*pskb)->nh.iph;
42 struct udphdr *udph = (void *)iph + iph->ihl * 4;
43 const char *data = (const char *)udph + 8;
48 /* down(stream): caller -> callee
49 up(stream): caller <- callee */
52 /* Return 1 for match, 0 for accept, -1 for partial. */
53 static int find_pattern(const char *data, size_t dlen,
54 const char *pattern, size_t plen,
62 //DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen);
70 /* Short packet: try for partial? */
71 if (strnicmp(data, pattern, dlen) == 0)
76 for(i=0; i<= (dlen - plen); i++){
77 if( memcmp(data + i, pattern, plen ) != 0 ) continue;
81 for (j=*numoff, k=0; data[j] != term; j++, k++)
82 if( j > dlen ) return -1 ; /* no terminal char */
92 sip_nat_expected(struct sk_buff **pskb,
94 struct ip_conntrack *ct,
95 struct ip_nat_info *info)
97 struct ip_nat_multi_range mr;
98 u_int32_t newdstip, newsrcip, newip;
99 struct ip_ct_sip_expect *exp_sip_info;
100 struct ip_conntrack *master = master_ct(ct);
103 IP_NF_ASSERT(master);
104 IP_NF_ASSERT(!(info->initialized & (1<<HOOK2MANIP(hooknum))));
106 exp_sip_info = &ct->master->help.exp_sip_info;
108 LOCK_BH(&ip_sip_lock);
110 /* Outer machine IP */
111 newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
112 /* Client (virtual) IP under NAT */
113 newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
115 UNLOCK_BH(&ip_sip_lock);
117 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
122 DEBUGP("sip_nat_expected: IP to %u.%u.%u.%u:%u\n", NIPQUAD(newip),
123 htons(exp_sip_info->port));
126 /* We don't want to manip the per-protocol, just the IPs... */
127 mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
128 mr.range[0].min_ip = mr.range[0].max_ip = newip;
130 /* ... unless we're doing a MANIP_DST, in which case, make
131 sure we map to the correct port */
132 if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
133 mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
134 mr.range[0].min.udp.port = mr.range[0].max.udp.port = exp_sip_info->port;
137 return ip_nat_setup_info(ct, &mr, hooknum);
140 static int _find_sip_via_addrport(const char *data, size_t dlen,
141 unsigned int *numoff, unsigned int *numlen)
143 const char *addr, *p = data;
144 const char *limit = data + dlen;
150 /* Find the topmost via tag */
151 if (strnicmp(p, "\nvia:",5) && strnicmp(p, "\nv:",3) &&
152 strnicmp(p, "\rvia:",5) && strnicmp(p, "\rv:",3)) {
158 while (*p!='U' && *p!='u') {
178 /* FQDNs or dotted quads */
179 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
185 /* If there is a port number, skip it */
191 while (isdigit(*p)) {
198 *numoff = addr - data;
204 return 0; /* Not found */
207 static int _mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
208 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport,
209 unsigned int numoff, unsigned int numlen)
212 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
214 sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
215 buflen = strlen(buffer);
217 MUST_BE_LOCKED(&ip_sip_lock);
222 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, numoff,
223 numlen, buffer, buflen) )
226 DEBUGP("(SIP) Via is changed to %s.\n", buffer);
228 return buflen - numlen;
231 static int mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
232 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
234 struct iphdr *iph = (*pskb)->nh.iph;
235 struct udphdr *udph = (void *)iph + iph->ihl * 4;
236 const char *data = (const char *)udph + 8;
237 unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
238 unsigned int datalen = udplen - 8;
239 unsigned int matchoff, matchlen;
241 /* Find the topmost via tag */
242 _find_sip_via_addrport(data , datalen, &matchoff, &matchlen);
243 return _mangle_sip_via(ct, ctinfo, pskb, newip, newport,
247 static int mangle_sip_contact_in(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
248 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
250 struct iphdr *iph = (*pskb)->nh.iph;
251 struct udphdr *udph = (void *)iph + iph->ihl * 4;
252 const char *data = (const char *)udph + 8;
253 unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
254 unsigned int datalen = udplen - 8;
255 int buflen, diff_len = 0;
256 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
257 const char *uri, *addr, *p = data;
258 const char *limit = data + datalen;
259 u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; // NAT wan ip
263 memset(buffer2,0,16);
264 sprintf(buffer2,"%u.%u.%u.%u",NIPQUAD(wanip));
266 if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) &&
267 strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) {
272 while (strnicmp(p, "sip:", 4)) {
279 /* If there is user info in the contact */
282 while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
291 p = uri; /* back to previous URI pointer */
295 while (*p!=':' && *p!='>' && *p!=';') {
302 memset(buffer1,0,16);
303 memcpy(buffer1,addr,p-addr);
304 if (strcmp(buffer1, buffer2)!=0){
307 /* FQDNs or dotted quads */
308 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
314 /* If there is a port number, skip it */
321 sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
322 buflen = strlen(buffer);
324 MUST_BE_LOCKED(&ip_sip_lock);
329 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data,
330 p - addr, buffer, buflen) )
333 diff_len = buflen - (p - addr);
334 DEBUGP("(SIP) Contact is changed to %s.\n", buffer);
341 static int mangle_sip_contact(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
342 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
344 struct iphdr *iph = (*pskb)->nh.iph;
345 struct udphdr *udph = (void *)iph + iph->ihl * 4;
346 const char *data = (const char *)udph + 8;
347 unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
348 unsigned int datalen = udplen - 8;
350 int buflen, diff_len = 0;
351 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
352 const char *uri, *addr, *p = data;
353 const char *limit = data + datalen;
357 if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) &&
358 strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) {
363 while (strnicmp(p, "sip:", 4)) {
370 /* If there is user info in the contact */
373 while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
382 p = uri; /* back to previous URI pointer */
387 /* FQDNs or dotted quads */
388 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
394 /* If there is a port number, skip it */
401 sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
402 buflen = strlen(buffer);
404 MUST_BE_LOCKED(&ip_sip_lock);
409 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data,
410 p - addr, buffer, buflen) )
413 diff_len = buflen - (p - addr);
414 DEBUGP("(SIP) Contact is changed to %s.\n", buffer);
421 static int mangle_sip_requestline(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
422 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport)
424 struct iphdr *iph = (*pskb)->nh.iph;
425 struct udphdr *udph = (void *)iph + iph->ihl * 4;
426 const char *data = (const char *)udph + 8;
427 unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
428 unsigned int datalen = udplen - 8;
430 int buflen, diff_len = 0;
431 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
432 const char *uri, *addr, *p = data;
433 const char *limit = data + datalen;
436 while (strnicmp(p, "sip:", 4)) {
443 /* If there is user info in the contact */
446 while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') {
455 p = uri; /* back to previous URI pointer */
460 /* FQDNs or dotted quads */
461 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
467 /* If there is a port number, skip it */
474 sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport);
475 buflen = strlen(buffer);
477 MUST_BE_LOCKED(&ip_sip_lock);
482 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, p - addr, buffer, buflen) )
485 diff_len = buflen - (p - addr);
492 static int _find_sip_content_length_size(const char *data, size_t dlen,
493 unsigned int *numoff, unsigned int *numlen)
495 char *st, *p = (char *)data;
496 const char *limit = data + dlen;
503 if (strnicmp(p, "\nContent-Length:", 16) && strnicmp(p, "\nl:", 3) &&
504 strnicmp(p, "\rContent-Length:", 16) && strnicmp(p, "\rm:", 3)) {
509 /* Go through the string above */
524 size = simple_strtoul(p, &p, 10);
535 static int mangle_sip_content_length(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
536 struct sk_buff **pskb, int diff_len)
538 struct iphdr *iph = (*pskb)->nh.iph;
539 struct udphdr *udph = (void *)iph + iph->ihl * 4;
540 const char *data = (const char *)udph + 8;
541 unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
542 unsigned int datalen = udplen - 8;
544 unsigned int matchlen, matchoff;
546 char buffer[sizeof("nnnnn")];
549 size = _find_sip_content_length_size(data, datalen, &matchoff, &matchlen);
552 sprintf(buffer, "%u", size + diff_len);
553 buflen = strlen(buffer);
558 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
559 matchlen, buffer, buflen) )
562 DEBUGP("(SDP) Content-Length is changed %d->%s.\n", size, buffer);
563 return buflen - matchlen;
567 static int mangle_sip_sdp_content(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
568 struct sk_buff **pskb, u_int32_t newip, u_int16_t newport, u_int16_t isvideoport)
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;
576 unsigned int matchlen, matchoff;
577 int found, buflen, diff_len = 0;
578 char buffer[sizeof("nnn.nnn.nnn.nnn")];
580 char *limit = (char *)data + datalen;
581 u_int32_t ipaddr = 0;
585 /* Find RTP address */
586 found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
587 if (found && matchlen != 0) {
588 /* If it's a null address, then the call is on hold */
589 if (found == 2 && ipaddr == 0)
592 sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
593 buflen = strlen(buffer);
595 MUST_BE_LOCKED(&ip_sip_lock);
597 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
598 matchlen, buffer, buflen) )
601 diff_len += (buflen - matchlen);
602 DEBUGP("(SDP) RTP address is changed to %s.\n", buffer);
605 /* Find audio port */
606 if (isvideoport == 0){
607 getport = find_sdp_audio_port(data, datalen, &matchoff, &matchlen);
608 if (getport != newport && matchlen != 0) {
609 sprintf(buffer, "%d", newport);
610 buflen = strlen(buffer);
612 MUST_BE_LOCKED(&ip_sip_lock);
613 matchoff = matchoff+diff_len;
614 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
615 matchlen, buffer, buflen) )
618 diff_len += (buflen - matchlen);
619 DEBUGP("(SDP) audio port is changed to %d.\n", newport);
623 /* Find video port */
624 if (isvideoport == 1){
625 getport = find_sdp_video_port(data, datalen, &matchoff, &matchlen);
626 if (getport != newport && matchlen != 0) {
627 sprintf(buffer, "%d", newport);
628 buflen = strlen(buffer);
630 MUST_BE_LOCKED(&ip_sip_lock);
631 matchoff = matchoff+diff_len;
632 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff,
633 matchlen, buffer, buflen) )
636 diff_len += (buflen - matchlen);
637 DEBUGP("(SDP) video port is changed to %d.\n", newport);
641 dir = CTINFO2DIR(ctinfo);
642 if (dir == IP_CT_DIR_ORIGINAL)
645 /* Find Session ID address */
646 found = find_pattern(data, datalen, " IN IP4 ", 8, ' ', '\r',
647 &matchoff, &matchlen);
648 if (found && matchlen != 0) {
649 p = addr = (char *)data + matchoff;
651 /* FQDNs or dotted quads */
652 while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) {
658 sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
659 buflen = strlen(buffer);
661 MUST_BE_LOCKED(&ip_sip_lock);
663 if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data,
664 p - addr, buffer, buflen) )
667 diff_len += (buflen - (p - addr));
668 DEBUGP("(SDP) Session ID is changed to %s.\n", buffer);
674 static int mangle_sip_packet(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo,
675 struct sk_buff **pskb, u_int32_t newip, u_int16_t isvideoport)
677 struct iphdr *iph = (*pskb)->nh.iph;
678 struct udphdr *udph = (void *)iph + iph->ihl * 4;
679 const char *data = (const char *)udph + 8;
681 struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
682 u_int16_t natport = ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port);
684 DEBUGP("nat_sip: %s:(%d)\n", __FUNCTION__, __LINE__);
685 if (isvideoport == 0){
686 ct_sip_info->mangled = 1;
689 /* Changes the via, if this is a request */
690 if (strnicmp(data,"SIP/2.0",7) != 0) {
691 mangle_sip_via(ct, ctinfo, pskb, newip, natport);
694 /*SIP ALG can't change contact field in 3xx response packets*/
695 if (strnicmp(data, "SIP/2.0 3", 9) != 0) {//This packet is not 3xx response
696 mangle_sip_contact(ct, ctinfo, pskb, newip, natport);
699 if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, newip, ct_sip_info->rtpport, isvideoport)) != 0)
700 mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
705 static int sip_out_data_fixup(struct ip_conntrack *ct,
706 struct sk_buff **pskb,
707 enum ip_conntrack_info ctinfo,
708 struct ip_conntrack_expect *expect)
710 struct ip_conntrack_tuple newtuple;
711 struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
712 struct ip_ct_sip_expect *exp_sip_info;
713 u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; // NAT wan ip
715 u_int16_t videoport = 0;
716 u_int16_t isvideoport = 2;
718 struct ip_conntrack_expect *rtcp_exp;
722 MUST_BE_LOCKED(&ip_sip_lock);
725 DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
727 exp_sip_info = &expect->help.exp_sip_info;
728 if (exp_sip_info->nated) {
729 DEBUGP("nat_sip: %s: The exp %p had been changed.\n", __FUNCTION__, expect);
733 DEBUGP("nat_sip: %s: The exp type is %d.\n", __FUNCTION__, exp_sip_info->type);
735 if (exp_sip_info->type == CONN_SIP) {
736 exp_sip_info->nated = 1;
737 DEBUGP("nat_sip: %s: There is a SIP exp %p.\n", __FUNCTION__, expect);
738 } else if (exp_sip_info->type == CONN_RTP) {
739 DEBUGP("nat_sip: %s: There is a RTP exp %p.\n", __FUNCTION__, expect);
742 port = ntohs(expect->tuple.dst.u.udp.port);
744 rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1);
746 /* RFC1889 - If an application is supplied with an odd number
747 * for use as the RTP port, it should replace this number with
748 * the next lower (even) number. */
752 /* fullfill newtuple */
753 memset(&newtuple, 0, sizeof(struct ip_conntrack_tuple));
754 newtuple.dst.ip = wanip;
755 newtuple.src.ip = expect->tuple.src.ip;
756 newtuple.src.u.all = 0;
757 newtuple.dst.protonum = expect->tuple.dst.protonum;
758 /* Try to get same port: if not, try to change it. */
759 for (; port != 0; port += 2) {
760 newtuple.dst.u.udp.port = htons(port);
761 if (ip_conntrack_change_expect(expect, &newtuple) == 0) {
765 DEBUGP("nat_sip: %s: RTCP exp %p found.\n",
766 __FUNCTION__, rtcp_exp);
767 newtuple.dst.u.udp.port = htons(port + 1);
768 if (ip_conntrack_change_expect(rtcp_exp, &newtuple) != 0) {
769 DEBUGP("nat_sip: %s: Can't change RTCP exp %p.\n",
770 __FUNCTION__, rtcp_exp);
773 rtcp_exp->help.exp_sip_info.nated = 1;
782 exp_sip_info->nated = 1;
783 ct_sip_info->rtpport = port;
784 DEBUGP("nat_sip: %s: RTP exp %p, masq port=%d\n", __FUNCTION__, expect, port);
785 } else if (exp_sip_info->type == CONN_RTPVIDEO){
786 DEBUGP("nat_sip: %s: There is a RTP exp %p.\n", __FUNCTION__, expect);
787 /* RTP Video expect */
789 videoport = ntohs(expect->tuple.dst.u.udp.port);
791 rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1);
793 /* RFC1889 - If an application is supplied with an odd number
794 * for use as the RTP port, it should replace this number with
795 * the next lower (even) number. */
796 if (videoport & 0x01)
798 /* fullfill newtuple */
799 memset(&newtuple, 0, sizeof(struct ip_conntrack_tuple));
800 newtuple.dst.ip = wanip;
801 newtuple.src.ip = expect->tuple.src.ip;
802 newtuple.src.u.all = 0;
803 newtuple.dst.protonum = expect->tuple.dst.protonum;
804 /* Try to get same port: if not, try to change it. */
805 for (; videoport != 0; videoport += 2) {
806 newtuple.dst.u.udp.port = htons(videoport);
807 if (ip_conntrack_change_expect(expect, &newtuple) == 0) {
811 DEBUGP("nat_sip: %s: RTCP exp %p found.\n",
812 __FUNCTION__, rtcp_exp);
813 newtuple.dst.u.udp.port = htons(videoport + 1);
814 if (ip_conntrack_change_expect(rtcp_exp, &newtuple) != 0) {
815 DEBUGP("nat_sip: %s: Can't change RTCP exp %p.\n",
816 __FUNCTION__, rtcp_exp);
819 rtcp_exp->help.exp_sip_info.nated = 1;
828 exp_sip_info->nated = 1;
829 ct_sip_info->rtpport = videoport;
830 DEBUGP("nat_sip: %s: RTP video exp %p, masq port=%d\n", __FUNCTION__, expect, videoport);
834 /* We ignore the RTCP expect, and will adjust it later
835 * during RTP expect */
836 DEBUGP("nat_sip: %s: There is a RTCP exp %p, by-pass.\n", __FUNCTION__, expect);
843 /* Change address inside packet to match way we're mapping
845 if (!ct_sip_info->mangled){
846 if (!mangle_sip_packet(ct, ctinfo, pskb, wanip, isvideoport))
853 static int sip_in_data_fixup(struct ip_conntrack *ct,
854 struct sk_buff **pskb,
855 enum ip_conntrack_info ctinfo,
856 struct ip_conntrack_expect *expect)
858 struct iphdr *iph = (*pskb)->nh.iph;
859 struct udphdr *udph = (void *)iph + iph->ihl * 4;
860 const char *data = (const char *)udph + 8;
861 unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4);
862 unsigned int datalen = udplen - 8;
863 struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info;
864 u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; // NAT wan ip
865 unsigned int matchlen, matchoff;
866 int found, diff_len = 0;
867 u_int32_t ipaddr = 0, vip = 0;
868 u_int16_t port = 0, vport = 0, aport = 0;
869 u_int16_t videoport = 0, rport = 0;
870 struct ip_conntrack_expect *exp;
872 struct ip_conntrack_expect *rtcpexp;
876 DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect);
880 DEBUGP("nat_sip: ct_sip_info->mangled=[%d]\n", ct_sip_info->mangled);
882 /* Prevent from mangling the packet or expect twice */
883 if (ct_sip_info->mangled) {
884 DEBUGP("nat_sip: %s: the conntrack %p had been mangled.\n", __FUNCTION__, ct);
887 //u_int32_t srcaddr = iph->daddr;//source address of ip field in packet
889 ct_sip_info->mangled = 1;
890 //if (srcaddr != wanip){ //private ip
891 if (strnicmp(data, "SIP/2.0 ", 8) != 0) {//This packet is request
893 /* Find CSeq field */
894 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
895 &matchoff, &matchlen);
896 if (found && matchlen != 0) {
897 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
898 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
899 mangle_sip_requestline(ct, ctinfo, pskb, vip, vport);
904 if (strnicmp(data, "SIP/2.0 200", 11) == 0) {
905 /* Find CSeq field */
906 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
907 &matchoff, &matchlen);
908 if (found && matchlen != 0) {
909 char *p = (char *)data + matchoff;
911 simple_strtoul(p, &p, 10);
912 if (strnicmp(p, " REGISTER", 9) == 0) {
913 DEBUGP("nat_sip: 200 OK - REGISTER\n");
914 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
915 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
916 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
917 mangle_sip_contact_in(ct, ctinfo, pskb, vip, vport);
919 } else if (strnicmp(p, " INVITE", 7) == 0){
920 DEBUGP("nat_sip: 200 OK - INVITE\n");
921 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
922 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
923 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
925 } else {//Don't care SDP session
926 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
927 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
928 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
934 if (strnicmp(data, "SIP/2.0 1", 9) == 0) {//This packet is 1xx response
936 /* Find CSeq field */
937 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
938 &matchoff, &matchlen);
939 if (found && matchlen != 0) {
940 //char *p = (char *)data + matchoff;
941 //simple_strtoul(p, &p, 8);
942 DEBUGP("nat_sip: pre change via and contact field\n");
943 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
944 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
945 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
946 mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
951 if (strnicmp(data, "SIP/2.0 3", 9) == 0) {//This packet is 3xx response
953 /* Find CSeq field */
954 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
955 &matchoff, &matchlen);
956 if (found && matchlen != 0) {
957 //char *p = (char *)data + matchoff;
958 //simple_strtoul(p, &p, 8);
959 DEBUGP("nat_sip: pre change via and contact field\n");
960 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
961 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
962 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
967 if (strnicmp(data, "SIP/2.0 4", 9) == 0) {//This packet is 4xx response
969 /* Find CSeq field */
970 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
971 &matchoff, &matchlen);
972 if (found && matchlen != 0) {
973 //char *p = (char *)data + matchoff;
974 //simple_strtoul(p, &p, 8);
975 DEBUGP("nat_sip: pre change via and contact field\n");
976 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
977 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
978 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
979 mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
984 if (strnicmp(data, "SIP/2.0 5", 9) == 0) {//This packet is 5xx response
986 /* Find CSeq field */
987 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
988 &matchoff, &matchlen);
989 if (found && matchlen != 0) {
990 //char *p = (char *)data + matchoff;
991 //simple_strtoul(p, &p, 8);
992 DEBUGP("nat_sip: pre change via and contact field\n");
993 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
994 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
995 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
996 mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
1001 if (strnicmp(data, "SIP/2.0 6", 9) == 0) {//This packet is 6xx response
1003 /* Find CSeq field */
1004 found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r',
1005 &matchoff, &matchlen);
1006 if (found && matchlen != 0) {
1007 //char *p = (char *)data + matchoff;
1008 //simple_strtoul(p, &p, 8);
1009 DEBUGP("nat_sip: pre change via and contact field\n");
1010 vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1011 vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port);
1012 mangle_sip_via(ct, ctinfo, pskb, vip, vport);
1013 mangle_sip_contact(ct, ctinfo, pskb, vip, vport);
1020 /* Only interesting the SDP content. */
1021 if (strnicmp(data, "INVITE", 6) != 0 && strnicmp(data, "SIP/2.0 200", 11) != 0)
1024 /* Find RTP address */
1025 found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr);
1027 DEBUGP("nat_sip: sdp address found = %d, ipaddr = %u.%u.%u.%u\n", found, NIPQUAD(ipaddr));
1031 DEBUGP("nat_sip: wanip = %u.%u.%u.%u\n", NIPQUAD(wanip));
1032 /* Is it a null address or our WAN address? */
1033 if (ipaddr == 0 || (htonl(ipaddr) != wanip))
1036 DEBUGP("nat_sip: %s: This is a loopback RTP connection.\n", __FUNCTION__);
1038 /* Find audio port, and we don't like the well-known ports,
1039 * which is less than 1024 */
1040 port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen);
1044 DEBUGP("nat_sip: RTP audio port = %u\n", port);
1046 exp = expect_find(ct, wanip, port);
1048 DEBUGP("nat_sip: %s: Found exp %p, tuple.dst=%u.%u.%u.%u:%u.\n",
1049 __FUNCTION__, exp, NIPQUAD(ipaddr), port);
1051 /* Restore masq-ed SDP */
1052 vip = exp->expectant->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1053 aport = exp->help.exp_sip_info.port;
1054 if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, vip, aport, 0)) != 0)
1055 mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
1057 /*************************************************************
1058 * linux kernel 2.4 need to unexpect the related expectation *
1059 * but in kernel 2.6, the function seem don't need anymore *
1060 * I still need to find why? but anyway, comment it now *
1061 * Andrew (2005/08/01) *
1062 *************************************************************/
1064 /* Unset RTP, RTCP expect, respectively */
1065 //ip_conntrack_unexpect_related(exp);
1067 rtcpexp = expect_find(ct, wanip, port + 1);
1068 if (rtcpexp && ct != rtcpexp->expectant)
1069 ip_conntrack_unexpect_related(rtcpexp);
1070 #endif //#ifdef RTCP_SUPPORT
1073 DEBUGP("nat_sip: %s: Can't find exp for tuple.dst=%u.%u.%u.%u:%u.\n",
1074 __FUNCTION__, NIPQUAD(ipaddr), port);
1078 /* Find video port, and we don't like the well-known ports,
1079 * which is less than 1024 */
1080 videoport = find_sdp_video_port(data, datalen, &matchoff, &matchlen);
1081 if (videoport < 1024)
1083 DEBUGP("nat_sip: RTP video port = %u\n", videoport);
1084 if (videoport != port){
1085 exp = expect_find(ct, wanip, videoport);
1087 DEBUGP("nat_sip: %s: Found video exp %p, tuple.dst=%u.%u.%u.%u:%u.\n",
1088 __FUNCTION__, exp, NIPQUAD(ipaddr), videoport);
1090 /* Restore masq-ed SDP */
1091 vip = exp->expectant->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip;
1092 rport = exp->help.exp_sip_info.port;
1093 if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, vip, rport, 1)) != 0)
1094 mangle_sip_content_length(ct, ctinfo, pskb, diff_len);
1095 /* Unset RTP, RTCP expect, respectively */
1096 //ip_conntrack_unexpect_related(exp);
1098 rtcpexp = expect_find(ct, wanip, videoport + 1);
1099 if (rtcpexp && ct != rtcpexp->expectant)
1100 ip_conntrack_unexpect_related(rtcpexp);
1101 #endif //#ifdef RTCP_SUPPORT
1103 DEBUGP("nat_sip: %s: Can't find exp for tuple.dst=%u.%u.%u.%u:%u.\n",
1104 __FUNCTION__, NIPQUAD(ipaddr), videoport);
1113 static unsigned int nat_help(struct ip_conntrack *ct,
1114 struct ip_conntrack_expect *exp,
1115 struct ip_nat_info *info,
1116 enum ip_conntrack_info ctinfo,
1117 unsigned int hooknum,
1118 struct sk_buff **pskb)
1122 /* Only mangle things once: original direction in POST_ROUTING
1123 and reply direction on PRE_ROUTING. */
1124 dir = CTINFO2DIR(ctinfo);
1125 if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
1126 || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) {
1127 DEBUGP("nat_sip: Not touching dir %s at hook %s\n",
1128 dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY",
1129 hooknum == NF_IP_POST_ROUTING ? "POSTROUTING"
1130 : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING"
1131 : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???");
1136 struct iphdr *iph = (*pskb)->nh.iph;
1137 struct udphdr *udph = (void *)iph + iph->ihl * 4;
1138 const char *data = (const char *)udph + 8;
1140 if (strnicmp(data, "REGISTER" , 8) == 0)
1141 DEBUGP("nat_sip: REGISTER\n");
1142 else if (strnicmp(data, "INVITE" , 6) == 0)
1143 DEBUGP("nat_sip: INVITE\n");
1144 else if (strnicmp(data, "ACK" , 3) == 0)
1145 DEBUGP("nat_sip: ACK\n");
1146 else if (strnicmp(data, "BYE", 3) == 0)
1147 DEBUGP("nat_sip: BYE\n");
1148 else if (strnicmp(data, "CANCEL", 6) == 0)
1149 DEBUGP("nat_sip: CANCEL\n");
1150 else if (strnicmp(data, "SIP/2.0 200", 11) == 0)
1151 DEBUGP("nat_sip: 200 OK\n");
1152 else if (strnicmp(data, "SIP/2.0 100", 11) == 0)
1153 DEBUGP("nat_sip: 100 Trying\n");
1154 else if (strnicmp(data, "SIP/2.0 180", 11) == 0)
1155 DEBUGP("nat_sip: 180 Ringing\n");
1156 else if (strnicmp(data, "SIP/2.0 401", 11) == 0)
1157 DEBUGP("nat_sip: 401 Unauthorized\n");
1160 LOCK_BH(&ip_sip_lock);
1162 if (dir == IP_CT_DIR_ORIGINAL) {
1163 DEBUGP("call sip_out_data_fixup\n");
1164 sip_out_data_fixup(ct, pskb, ctinfo, exp);
1165 DEBUGP("exit sip_out_data_fixup\n");
1167 DEBUGP("call sip_in_data_fixup\n");
1168 sip_in_data_fixup(ct, pskb, ctinfo, exp);
1169 DEBUGP("exit sip_in_data_fixup\n");
1172 UNLOCK_BH(&ip_sip_lock);
1177 static struct ip_nat_helper sip[MAX_PORTS];
1178 static char sip_names[MAX_PORTS][6];
1180 /* Not __exit: called from init() */
1181 static void fini(void)
1184 for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1185 DEBUGP("ip_nat_sip: unregistering port %d\n", ports[i]);
1186 ip_nat_helper_unregister(&sip[i]);
1190 static int __init init(void)
1195 //printk("ip_nat_sip v0.01 loading\n");
1198 ports[0] = SIP_PORT;
1200 for (i = 0; (i < MAX_PORTS) && ports[i]; i++) {
1202 memset(&sip[i], 0, sizeof(struct ip_nat_helper));
1204 sip[i].tuple.src.u.udp.port = htons(ports[i]);
1205 sip[i].tuple.dst.protonum = IPPROTO_UDP;
1206 sip[i].mask.src.u.udp.port = 0xFFFF;
1207 sip[i].mask.dst.protonum = 0xFFFF;
1208 sip[i].help = nat_help;
1209 sip[i].expect = sip_nat_expected;
1210 sip[i].flags = IP_NAT_HELPER_F_ALWAYS;
1212 tmpname = &sip_names[i][0];
1213 sprintf(tmpname, "sip%2.2d", i);
1214 sip[i].name = tmpname;
1216 DEBUGP("ip_nat_sip: Trying to register for port %d\n",
1218 ret = ip_nat_helper_register(&sip[i]);
1221 printk("ip_nat_sip: error registering "
1222 "helper for port %d\n", ports[i]);