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