Re: [BUG] Conntrack SIP Problem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Michael,

I am not the maintainer of the NAT-SIP module. In the future, you should post similar requests to the linux-net mailinglist where it can be picked up by more skilled people. I have cross-posted my reply there too.

The problem you describe is one of the reasons why, in general, you shouldn't run SIP over NAT. However, I have attached a crude patch that you can try that solved a similar problem for me. The patch applies against current 2.6.21.5 source. If you want to use the patch for anything earlier than 2.6.21.5, then you also need the patch that I included at the very end of this reply.

Regards,
Jerome Borsboom


--- linux-2.6.21.5/net/ipv4/netfilter/nf_nat_sip.c	2007-01-18 21:09:30.000000000 +0100
+++ linux-2.6.21.5.new/net/ipv4/netfilter/nf_nat_sip.c	2007-01-20 13:44:14.000000000 +0100
@@ -67,7 +67,8 @@

 static int map_sip_addr(struct sk_buff **pskb, enum ip_conntrack_info ctinfo,
 			struct nf_conn *ct, const char **dptr, size_t dlen,
-			enum sip_header_pos pos, struct addr_map *map)
+			enum sip_header_pos pos, struct addr_map *map,
+			struct nf_conntrack_expect *exp)
 {
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	unsigned int matchlen, matchoff, addrlen;
@@ -81,6 +82,8 @@
 	    memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) {
 		addr    = map->addr[!dir].dst;
 		addrlen = map->addr[!dir].dstlen;
+		if (exp)
+			exp->tuple.dst.u3.ip  = ct->tuplehash[!dir].tuple.dst.u3.ip;
 	} else if ((matchlen == map->addr[dir].dstiplen ||
 		    matchlen == map->addr[dir].dstlen) &&
 		   memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) {
@@ -126,14 +129,14 @@
 		else
 			pos = POS_REQ_URI;

-		if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map))
+		if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, pos, &map, NULL))
 			return NF_DROP;
 	}

-	if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map) ||
-	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map) ||
-	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map) ||
-	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map))
+	if (!map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_FROM, &map, NULL) ||
+	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_TO, &map, NULL) ||
+	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_VIA, &map, NULL) ||
+	    !map_sip_addr(pskb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map, NULL))
 		return NF_DROP;
 	return NF_ACCEPT;
 }
@@ -194,23 +197,35 @@
 static unsigned int mangle_sdp(struct sk_buff **pskb,
 			       enum ip_conntrack_info ctinfo,
 			       struct nf_conn *ct,
-			       __be32 newip, u_int16_t port,
-			       const char *dptr)
+			       const char *dptr,
+			       struct nf_conntrack_expect *exp)
 {
-	char buffer[sizeof("nnn.nnn.nnn.nnn")];
-	unsigned int dataoff, bufflen;
+	struct addr_map map;
+	unsigned int dataoff, datalen;

 	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
+	datalen = (*pskb)->len - dataoff;
+
+	addr_map_init(ct, &map);

 	/* Mangle owner and contact info. */
-	bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
-	if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
-			       buffer, bufflen, POS_OWNER_IP4))
+	if (!map_sip_addr(pskb, ctinfo, ct, &dptr, datalen, POS_OWNER_IP4, &map, NULL) ||
+	    !map_sip_addr(pskb, ctinfo, ct, &dptr, datalen, POS_CONNECTION_IP4, &map, exp))
 		return 0;

-	if (!mangle_sip_packet(pskb, ctinfo, ct, &dptr, (*pskb)->len - dataoff,
-			       buffer, bufflen, POS_CONNECTION_IP4))
-		return 0;
+	return mangle_content_len(pskb, ctinfo, ct, dptr);
+}
+
+static unsigned int mangle_sdp_port(struct sk_buff **pskb,
+			       enum ip_conntrack_info ctinfo,
+			       struct nf_conn *ct,
+			       u_int16_t port,
+			       const char *dptr)
+{
+	char buffer[sizeof("nnnnn")];
+	unsigned int dataoff, bufflen;
+
+	dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);

 	/* Mangle media port. */
 	bufflen = sprintf(buffer, "%u", port);
@@ -221,6 +236,36 @@
 	return mangle_content_len(pskb, ctinfo, ct, dptr);
 }

+static void nf_nat_follow_sip(struct nf_conn *ct,
+                          struct nf_conntrack_expect *exp)
+{
+        struct nf_nat_range range;
+
+        /* This must be a fresh one. */
+        BUG_ON(ct->status & IPS_NAT_DONE_MASK);
+
+	if (ct->tuplehash[exp->dir].tuple.src.u3.ip ==
+		ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
+	        /* Change src to where master sends to */
+		range.flags = IP_NAT_RANGE_MAP_IPS;
+		range.min_ip = range.max_ip
+			= ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
+		/* hook doesn't matter, but it has to do source manip */
+		nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING);
+	}
+
+	if (ct->tuplehash[exp->dir].tuple.dst.u3.ip ==
+		ct->master->tuplehash[exp->dir].tuple.dst.u3.ip) {
+		/* For DST manip, map port here to where it's expected. */
+		range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
+		range.min = range.max = exp->saved_proto;
+		range.min_ip = range.max_ip
+			= ct->master->tuplehash[!exp->dir].tuple.src.u3.ip;
+		/* hook doesn't matter, but it has to do destination manip */
+		nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING);
+	}
+}
+
 /* So, this packet has hit the connection tracking matching code.
    Mangle it, and change the expectation to match the new version. */
 static unsigned int ip_nat_sdp(struct sk_buff **pskb,
@@ -230,21 +275,20 @@
 {
 	struct nf_conn *ct = exp->master;
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	__be32 newip;
 	u_int16_t port;

 	DEBUGP("ip_nat_sdp():\n");

-	/* Connection will come from reply */
-	newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
+	if (!mangle_sdp(pskb, ctinfo, ct, dptr, exp))
+		return NF_DROP;

-	exp->tuple.dst.u3.ip = newip;
+	/* Connection will come from reply */
 	exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
 	exp->dir = !dir;

 	/* When you see the packet, we need to NAT it the same as the
 	   this one. */
-	exp->expectfn = nf_nat_follow_master;
+	exp->expectfn = nf_nat_follow_sip;

 	/* Try to get same port: if not, try to change it. */
 	for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
@@ -256,7 +300,7 @@
 	if (port == 0)
 		return NF_DROP;

-	if (!mangle_sdp(pskb, ctinfo, ct, newip, port, dptr)) {
+	if (!mangle_sdp_port(pskb, ctinfo, ct, port, dptr)) {
 		nf_conntrack_unexpect_related(exp);
 		return NF_DROP;
 	}
--- linux-2.6.21.5/net/netfilter/nf_conntrack_sip.c	2007-01-18 21:09:30.000000000 +0100
+++ linux-2.6.21.5.new/net/netfilter/nf_conntrack_sip.c	2007-01-26 22:45:31.000000000 +0100
@@ -376,7 +376,7 @@
 	if (exp == NULL)
 		return NF_DROP;
 	nf_conntrack_expect_init(exp, family,
-				 &ct->tuplehash[!dir].tuple.src.u3, addr,
+				 NULL, addr,
 				 IPPROTO_UDP, NULL, &port);

 	nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);
@@ -436,6 +436,8 @@

 	/* RTP info only in some SDP pkts */
 	if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 &&
+	    memcmp(dptr, "SIP/2.0 180", sizeof("SIP/2.0 180") - 1) != 0 &&
+	    memcmp(dptr, "SIP/2.0 183", sizeof("SIP/2.0 183") - 1) != 0 &&
 	    memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) {
 		goto out;
 	}

On Mon, 11 Jun 2007, Michael Rack wrote:

Dear Mr. Borsboom,

my name is Michael Rack, i'm from Germany. Sorry, if this is not the right place for my bug report. But i hope you can post it on the right place.

*Now to the problem:*
If the SIP-Server is running on (217.10.79.9) and the Audio-Stream-Server on (217.10.79.30), the NAT_SIP Module is get into trouble.

*The SIP-Message from Service-Provider to my GATEWAY look like this (**91.64.xxx.xxx is my gateway):*
00:46:12 IP 217.10.79.9.5060 > 91.64.xxx.xxx.5060: SIP, length: 821
SIP/2.0 200 OK
Via: SIP/2.0/UDP 91.64.xxx.xxx:5060;branch=z9hG4bK12EC1F9F577AE583
Record-Route: <sip:217.10.79.9;lr=on>
From: <sip:xxx8931@xxxxxxxxxx>;tag=ECA70DB358408E40
To: <sip:10005@xxxxxxxxxx>;tag=as0a188b3b
Call-ID: A8D8B17F53CBD739@xxxxxxxxxxxxx
CSeq: 14 INVITE
User-Agent: sipgate GW v.23.42
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY
Supported: replaces
Contact: <sip:10005@xxxxxxxxxxxx>
Content-Type: application/sdp
Content-Length: 334

v=0
o=root 8988 8988 IN IP4 217.10.79.30
s=session
c=IN IP4 217.10.79.30
t=0 0
m=audio 15634 RTP/AVP 8 0 97 2 101
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=30
a=rtpmap:2 G726-32/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=silenceSupp:off - - - -
a=ptime:20
a=sendrecv

*The SIP-Message forwarded to the SIP-DEVICE (10.10.202.2 is my Fritz!Box Fon 5010**):
*01:00:32.638894 IP 217.10.79.9.5060 > 10.10.202.2.5060: SIP, length: 819
SIP/2.0 200 OK
Via: SIP/2.0/UDP 91.64.xxx.xxx:5060;branch=z9hG4bK41AD3D8FB0A8A5F7
Record-Route: <sip:217.10.79.9;lr=on>
From: <sip:xxx8931@xxxxxxxxxx>;tag=F0668B35CFE4136D
To: <sip:10005@xxxxxxxxxx>;tag=as508e8403
Call-ID: 4AEEBF3F8013E8C5@xxxxxxxxxxxxx
CSeq: 17 INVITE
User-Agent: sipgate GW v.23.42
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY
Supported: replaces
Contact: <sip:10005@xxxxxxxxxxxx>
Content-Type: application/sdp
Content-Length: 332

v=0
o=root 8988 8988 IN IP4 217.10.79.9
s=session
c=IN IP4 217.10.79.9
t=0 0
m=audio 15634 RTP/AVP 8 0 97 2 101
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:97 iLBC/8000
a=fmtp:97 mode=30
a=rtpmap:2 G726-32/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=silenceSupp:off - - - -
a=ptime:20
a=sendrecv

Now, you will see, the IP-Address has been changed, while the packet was processed by NAT_SIP Module. The IP-Addresss 217.10.79.9:15634 is not correct. The correct Address is 217.10.79.30:15634 ... What to the hell is there going on?

In this state, any AUDIO-Stream takes the wrong way!

*This is a snapshot of the audio connection beetween SIP-DEVICE and GATEWAY:*
00:46:19.478583 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252
00:46:19.510688 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252
00:46:19.542658 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252
00:46:19.566317 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252
00:46:19.598344 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252
00:46:19.630361 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252
00:46:19.662327 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252
00:46:19.686704 IP 10.10.202.2.7078 > 217.10.79.9.15634: UDP, length 252

*This is a snapshot of the audio connection beetween SIP-PROVIDER and GATEWAY:*
01:08:59.825647 IP 217.10.79.30.15634 > 91.64.105.116.7078: UDP, length 172
01:08:59.837486 IP 91.64.105.116.7078 > 217.10.79.9.15634: UDP, length 252
01:08:59.845643 IP 217.10.79.30.15634 > 91.64.105.116.7078: UDP, length 172
01:08:59.860817 IP 91.64.105.116.7078 > 217.10.79.9.15634: UDP, length 252
01:08:59.865664 IP 217.10.79.30.15634 > 91.64.105.116.7078: UDP, length 172
01:08:59.885723 IP 217.10.79.30.15634 > 91.64.105.116.7078: UDP, length 172
01:08:59.892855 IP 91.64.105.116.7078 > 217.10.79.9.15634: UDP, length 252
01:08:59.905692 IP 217.10.79.30.15634 > 91.64.105.116.7078: UDP, length 172
01:08:59.924852 IP 91.64.105.116.7078 > 217.10.79.9.15634: UDP, length 252
01:08:59.925667 IP 217.10.79.30.15634 > 91.64.105.116.7078: UDP, length 172
01:08:59.945473 IP 217.10.79.30.15634 > 91.64.105.116.7078: UDP, length 172
01:08:59.957156 IP 91.64.105.116.7078 > 217.10.79.9.15634: UDP, length 252

NOW THIS IS A VERY BIG PROBLEM...

Kind regards,
Michael Rack
Germany




--- linux-2.6.20/net/core/utils.c	2007-02-04 19:44:54.000000000 +0100
+++ linux-2.6.20/net/core/utils.c	2007-04-15 21:08:55.000000000 +0200
@@ -137,16 +137,16 @@
 	while(1) {
 		int c;
 		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
-		if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) {
+		if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
 			goto out;
 		}
-		if (c & (IN6PTON_DOT | IN6PTON_DELIM)) {
+		if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
 			if (w == 0)
 				goto out;
 			*d++ = w & 0xff;
 			w = 0;
 			i++;
-			if (c & IN6PTON_DELIM) {
+			if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
 				if (i != 4)
 					goto out;
 				break;
-
To unsubscribe from this list: send the line "unsubscribe linux-net" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux