1 /* SIP extension for NAT alteration.
3 * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
4 * based on RR's ip_nat_ftp.c and other modules.
5 * (C) 2007 United Security Providers
6 * (C) 2007, 2008 Patrick McHardy <kaber@trash.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/module.h>
14 #include <linux/skbuff.h>
17 #include <linux/udp.h>
18 #include <linux/tcp.h>
20 #include <net/netfilter/nf_nat.h>
21 #include <net/netfilter/nf_nat_helper.h>
22 #include <net/netfilter/nf_nat_rule.h>
23 #include <net/netfilter/nf_conntrack_helper.h>
24 #include <net/netfilter/nf_conntrack_expect.h>
25 #include <linux/netfilter/nf_conntrack_sip.h>
27 MODULE_LICENSE("GPL");
28 MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
29 MODULE_DESCRIPTION("SIP NAT helper");
30 MODULE_ALIAS("ip_nat_sip");
33 static unsigned int mangle_packet(struct sk_buff
*skb
, unsigned int dataoff
,
34 const char **dptr
, unsigned int *datalen
,
35 unsigned int matchoff
, unsigned int matchlen
,
36 const char *buffer
, unsigned int buflen
)
38 enum ip_conntrack_info ctinfo
;
39 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
43 if (nf_ct_protonum(ct
) == IPPROTO_TCP
) {
44 th
= (struct tcphdr
*)(skb
->data
+ ip_hdrlen(skb
));
45 baseoff
= ip_hdrlen(skb
) + th
->doff
* 4;
46 matchoff
+= dataoff
- baseoff
;
48 if (!__nf_nat_mangle_tcp_packet(skb
, ct
, ctinfo
,
50 buffer
, buflen
, false))
53 baseoff
= ip_hdrlen(skb
) + sizeof(struct udphdr
);
54 matchoff
+= dataoff
- baseoff
;
56 if (!nf_nat_mangle_udp_packet(skb
, ct
, ctinfo
,
62 /* Reload data pointer and adjust datalen value */
63 *dptr
= skb
->data
+ dataoff
;
64 *datalen
+= buflen
- matchlen
;
68 static int map_addr(struct sk_buff
*skb
, unsigned int dataoff
,
69 const char **dptr
, unsigned int *datalen
,
70 unsigned int matchoff
, unsigned int matchlen
,
71 union nf_inet_addr
*addr
, __be16 port
)
73 enum ip_conntrack_info ctinfo
;
74 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
75 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
76 char buffer
[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
81 if (ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
== addr
->ip
&&
82 ct
->tuplehash
[dir
].tuple
.src
.u
.udp
.port
== port
) {
83 newaddr
= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
;
84 newport
= ct
->tuplehash
[!dir
].tuple
.dst
.u
.udp
.port
;
85 } else if (ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
== addr
->ip
&&
86 ct
->tuplehash
[dir
].tuple
.dst
.u
.udp
.port
== port
) {
87 newaddr
= ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
;
88 newport
= ct
->tuplehash
[!dir
].tuple
.src
.u
.udp
.port
;
92 if (newaddr
== addr
->ip
&& newport
== port
)
95 buflen
= sprintf(buffer
, "%pI4:%u", &newaddr
, ntohs(newport
));
97 return mangle_packet(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
101 static int map_sip_addr(struct sk_buff
*skb
, unsigned int dataoff
,
102 const char **dptr
, unsigned int *datalen
,
103 enum sip_header_types type
)
105 enum ip_conntrack_info ctinfo
;
106 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
107 unsigned int matchlen
, matchoff
;
108 union nf_inet_addr addr
;
111 if (ct_sip_parse_header_uri(ct
, *dptr
, NULL
, *datalen
, type
, NULL
,
112 &matchoff
, &matchlen
, &addr
, &port
) <= 0)
114 return map_addr(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
118 static unsigned int ip_nat_sip(struct sk_buff
*skb
, unsigned int dataoff
,
119 const char **dptr
, unsigned int *datalen
)
121 enum ip_conntrack_info ctinfo
;
122 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
123 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
124 unsigned int coff
, matchoff
, matchlen
;
125 enum sip_header_types hdr
;
126 union nf_inet_addr addr
;
128 int request
, in_header
;
130 /* Basic rules: requests and responses. */
131 if (strnicmp(*dptr
, "SIP/2.0", strlen("SIP/2.0")) != 0) {
132 if (ct_sip_parse_request(ct
, *dptr
, *datalen
,
133 &matchoff
, &matchlen
,
135 !map_addr(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
142 if (nf_ct_protonum(ct
) == IPPROTO_TCP
)
143 hdr
= SIP_HDR_VIA_TCP
;
145 hdr
= SIP_HDR_VIA_UDP
;
147 /* Translate topmost Via header and parameters */
148 if (ct_sip_parse_header_uri(ct
, *dptr
, NULL
, *datalen
,
149 hdr
, NULL
, &matchoff
, &matchlen
,
151 unsigned int matchend
, poff
, plen
, buflen
, n
;
152 char buffer
[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
154 /* We're only interested in headers related to this
157 if (addr
.ip
!= ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
||
158 port
!= ct
->tuplehash
[dir
].tuple
.src
.u
.udp
.port
)
161 if (addr
.ip
!= ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
||
162 port
!= ct
->tuplehash
[dir
].tuple
.dst
.u
.udp
.port
)
166 if (!map_addr(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
170 matchend
= matchoff
+ matchlen
;
172 /* The maddr= parameter (RFC 2361) specifies where to send
174 if (ct_sip_parse_address_param(ct
, *dptr
, matchend
, *datalen
,
175 "maddr=", &poff
, &plen
,
177 addr
.ip
== ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
&&
178 addr
.ip
!= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
) {
179 buflen
= sprintf(buffer
, "%pI4",
180 &ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
);
181 if (!mangle_packet(skb
, dataoff
, dptr
, datalen
,
182 poff
, plen
, buffer
, buflen
))
186 /* The received= parameter (RFC 2361) contains the address
187 * from which the server received the request. */
188 if (ct_sip_parse_address_param(ct
, *dptr
, matchend
, *datalen
,
189 "received=", &poff
, &plen
,
191 addr
.ip
== ct
->tuplehash
[dir
].tuple
.dst
.u3
.ip
&&
192 addr
.ip
!= ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
) {
193 buflen
= sprintf(buffer
, "%pI4",
194 &ct
->tuplehash
[!dir
].tuple
.src
.u3
.ip
);
195 if (!mangle_packet(skb
, dataoff
, dptr
, datalen
,
196 poff
, plen
, buffer
, buflen
))
200 /* The rport= parameter (RFC 3581) contains the port number
201 * from which the server received the request. */
202 if (ct_sip_parse_numerical_param(ct
, *dptr
, matchend
, *datalen
,
203 "rport=", &poff
, &plen
,
205 htons(n
) == ct
->tuplehash
[dir
].tuple
.dst
.u
.udp
.port
&&
206 htons(n
) != ct
->tuplehash
[!dir
].tuple
.src
.u
.udp
.port
) {
207 __be16 p
= ct
->tuplehash
[!dir
].tuple
.src
.u
.udp
.port
;
208 buflen
= sprintf(buffer
, "%u", ntohs(p
));
209 if (!mangle_packet(skb
, dataoff
, dptr
, datalen
,
210 poff
, plen
, buffer
, buflen
))
216 /* Translate Contact headers */
219 while (ct_sip_parse_header_uri(ct
, *dptr
, &coff
, *datalen
,
220 SIP_HDR_CONTACT
, &in_header
,
221 &matchoff
, &matchlen
,
223 if (!map_addr(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
228 if (!map_sip_addr(skb
, dataoff
, dptr
, datalen
, SIP_HDR_FROM
) ||
229 !map_sip_addr(skb
, dataoff
, dptr
, datalen
, SIP_HDR_TO
))
235 static void ip_nat_sip_seq_adjust(struct sk_buff
*skb
, s16 off
)
237 enum ip_conntrack_info ctinfo
;
238 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
239 const struct tcphdr
*th
;
241 if (nf_ct_protonum(ct
) != IPPROTO_TCP
|| off
== 0)
244 th
= (struct tcphdr
*)(skb
->data
+ ip_hdrlen(skb
));
245 nf_nat_set_seq_adjust(ct
, ctinfo
, th
->seq
, off
);
248 /* Handles expected signalling connections and media streams */
249 static void ip_nat_sip_expected(struct nf_conn
*ct
,
250 struct nf_conntrack_expect
*exp
)
252 struct nf_nat_range range
;
254 /* This must be a fresh one. */
255 BUG_ON(ct
->status
& IPS_NAT_DONE_MASK
);
257 /* For DST manip, map port here to where it's expected. */
258 range
.flags
= (IP_NAT_RANGE_MAP_IPS
| IP_NAT_RANGE_PROTO_SPECIFIED
);
259 range
.min
= range
.max
= exp
->saved_proto
;
260 range
.min_ip
= range
.max_ip
= exp
->saved_ip
;
261 nf_nat_setup_info(ct
, &range
, IP_NAT_MANIP_DST
);
263 /* Change src to where master sends to, but only if the connection
264 * actually came from the same source. */
265 if (ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.src
.u3
.ip
==
266 ct
->master
->tuplehash
[exp
->dir
].tuple
.src
.u3
.ip
) {
267 range
.flags
= IP_NAT_RANGE_MAP_IPS
;
268 range
.min_ip
= range
.max_ip
269 = ct
->master
->tuplehash
[!exp
->dir
].tuple
.dst
.u3
.ip
;
270 nf_nat_setup_info(ct
, &range
, IP_NAT_MANIP_SRC
);
274 static unsigned int ip_nat_sip_expect(struct sk_buff
*skb
, unsigned int dataoff
,
275 const char **dptr
, unsigned int *datalen
,
276 struct nf_conntrack_expect
*exp
,
277 unsigned int matchoff
,
278 unsigned int matchlen
)
280 enum ip_conntrack_info ctinfo
;
281 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
282 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
285 char buffer
[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
288 /* Connection will come from reply */
289 if (ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
== ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
)
290 newip
= exp
->tuple
.dst
.u3
.ip
;
292 newip
= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
;
294 /* If the signalling port matches the connection's source port in the
295 * original direction, try to use the destination port in the opposite
297 if (exp
->tuple
.dst
.u
.udp
.port
==
298 ct
->tuplehash
[dir
].tuple
.src
.u
.udp
.port
)
299 port
= ntohs(ct
->tuplehash
[!dir
].tuple
.dst
.u
.udp
.port
);
301 port
= ntohs(exp
->tuple
.dst
.u
.udp
.port
);
303 exp
->saved_ip
= exp
->tuple
.dst
.u3
.ip
;
304 exp
->tuple
.dst
.u3
.ip
= newip
;
305 exp
->saved_proto
.udp
.port
= exp
->tuple
.dst
.u
.udp
.port
;
307 exp
->expectfn
= ip_nat_sip_expected
;
309 for (; port
!= 0; port
++) {
312 exp
->tuple
.dst
.u
.udp
.port
= htons(port
);
313 ret
= nf_ct_expect_related(exp
);
316 else if (ret
!= -EBUSY
) {
325 if (exp
->tuple
.dst
.u3
.ip
!= exp
->saved_ip
||
326 exp
->tuple
.dst
.u
.udp
.port
!= exp
->saved_proto
.udp
.port
) {
327 buflen
= sprintf(buffer
, "%pI4:%u", &newip
, port
);
328 if (!mangle_packet(skb
, dataoff
, dptr
, datalen
,
329 matchoff
, matchlen
, buffer
, buflen
))
335 nf_ct_unexpect_related(exp
);
339 static int mangle_content_len(struct sk_buff
*skb
, unsigned int dataoff
,
340 const char **dptr
, unsigned int *datalen
)
342 enum ip_conntrack_info ctinfo
;
343 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
344 unsigned int matchoff
, matchlen
;
345 char buffer
[sizeof("65536")];
348 /* Get actual SDP length */
349 if (ct_sip_get_sdp_header(ct
, *dptr
, 0, *datalen
,
350 SDP_HDR_VERSION
, SDP_HDR_UNSPEC
,
351 &matchoff
, &matchlen
) <= 0)
353 c_len
= *datalen
- matchoff
+ strlen("v=");
355 /* Now, update SDP length */
356 if (ct_sip_get_header(ct
, *dptr
, 0, *datalen
, SIP_HDR_CONTENT_LENGTH
,
357 &matchoff
, &matchlen
) <= 0)
360 buflen
= sprintf(buffer
, "%u", c_len
);
361 return mangle_packet(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
365 static int mangle_sdp_packet(struct sk_buff
*skb
, unsigned int dataoff
,
366 const char **dptr
, unsigned int *datalen
,
368 enum sdp_header_types type
,
369 enum sdp_header_types term
,
370 char *buffer
, int buflen
)
372 enum ip_conntrack_info ctinfo
;
373 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
374 unsigned int matchlen
, matchoff
;
376 if (ct_sip_get_sdp_header(ct
, *dptr
, sdpoff
, *datalen
, type
, term
,
377 &matchoff
, &matchlen
) <= 0)
379 return mangle_packet(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
380 buffer
, buflen
) ? 0 : -EINVAL
;
383 static unsigned int ip_nat_sdp_addr(struct sk_buff
*skb
, unsigned int dataoff
,
384 const char **dptr
, unsigned int *datalen
,
386 enum sdp_header_types type
,
387 enum sdp_header_types term
,
388 const union nf_inet_addr
*addr
)
390 char buffer
[sizeof("nnn.nnn.nnn.nnn")];
393 buflen
= sprintf(buffer
, "%pI4", &addr
->ip
);
394 if (mangle_sdp_packet(skb
, dataoff
, dptr
, datalen
, sdpoff
, type
, term
,
398 return mangle_content_len(skb
, dataoff
, dptr
, datalen
);
401 static unsigned int ip_nat_sdp_port(struct sk_buff
*skb
, unsigned int dataoff
,
402 const char **dptr
, unsigned int *datalen
,
403 unsigned int matchoff
,
404 unsigned int matchlen
,
407 char buffer
[sizeof("nnnnn")];
410 buflen
= sprintf(buffer
, "%u", port
);
411 if (!mangle_packet(skb
, dataoff
, dptr
, datalen
, matchoff
, matchlen
,
415 return mangle_content_len(skb
, dataoff
, dptr
, datalen
);
418 static unsigned int ip_nat_sdp_session(struct sk_buff
*skb
, unsigned int dataoff
,
419 const char **dptr
, unsigned int *datalen
,
421 const union nf_inet_addr
*addr
)
423 char buffer
[sizeof("nnn.nnn.nnn.nnn")];
426 /* Mangle session description owner and contact addresses */
427 buflen
= sprintf(buffer
, "%pI4", &addr
->ip
);
428 if (mangle_sdp_packet(skb
, dataoff
, dptr
, datalen
, sdpoff
,
429 SDP_HDR_OWNER_IP4
, SDP_HDR_MEDIA
,
433 switch (mangle_sdp_packet(skb
, dataoff
, dptr
, datalen
, sdpoff
,
434 SDP_HDR_CONNECTION_IP4
, SDP_HDR_MEDIA
,
440 * Session description
442 * c=* (connection information - not required if included in all media)
450 return mangle_content_len(skb
, dataoff
, dptr
, datalen
);
453 /* So, this packet has hit the connection tracking matching code.
454 Mangle it, and change the expectation to match the new version. */
455 static unsigned int ip_nat_sdp_media(struct sk_buff
*skb
, unsigned int dataoff
,
456 const char **dptr
, unsigned int *datalen
,
457 struct nf_conntrack_expect
*rtp_exp
,
458 struct nf_conntrack_expect
*rtcp_exp
,
459 unsigned int mediaoff
,
460 unsigned int medialen
,
461 union nf_inet_addr
*rtp_addr
)
463 enum ip_conntrack_info ctinfo
;
464 struct nf_conn
*ct
= nf_ct_get(skb
, &ctinfo
);
465 enum ip_conntrack_dir dir
= CTINFO2DIR(ctinfo
);
468 /* Connection will come from reply */
469 if (ct
->tuplehash
[dir
].tuple
.src
.u3
.ip
==
470 ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
)
471 rtp_addr
->ip
= rtp_exp
->tuple
.dst
.u3
.ip
;
473 rtp_addr
->ip
= ct
->tuplehash
[!dir
].tuple
.dst
.u3
.ip
;
475 rtp_exp
->saved_ip
= rtp_exp
->tuple
.dst
.u3
.ip
;
476 rtp_exp
->tuple
.dst
.u3
.ip
= rtp_addr
->ip
;
477 rtp_exp
->saved_proto
.udp
.port
= rtp_exp
->tuple
.dst
.u
.udp
.port
;
479 rtp_exp
->expectfn
= ip_nat_sip_expected
;
481 rtcp_exp
->saved_ip
= rtcp_exp
->tuple
.dst
.u3
.ip
;
482 rtcp_exp
->tuple
.dst
.u3
.ip
= rtp_addr
->ip
;
483 rtcp_exp
->saved_proto
.udp
.port
= rtcp_exp
->tuple
.dst
.u
.udp
.port
;
484 rtcp_exp
->dir
= !dir
;
485 rtcp_exp
->expectfn
= ip_nat_sip_expected
;
487 /* Try to get same pair of ports: if not, try to change them. */
488 for (port
= ntohs(rtp_exp
->tuple
.dst
.u
.udp
.port
);
489 port
!= 0; port
+= 2) {
492 rtp_exp
->tuple
.dst
.u
.udp
.port
= htons(port
);
493 ret
= nf_ct_expect_related(rtp_exp
);
500 rtcp_exp
->tuple
.dst
.u
.udp
.port
= htons(port
+ 1);
501 ret
= nf_ct_expect_related(rtcp_exp
);
504 else if (ret
!= -EBUSY
) {
505 nf_ct_unexpect_related(rtp_exp
);
514 /* Update media port. */
515 if (rtp_exp
->tuple
.dst
.u
.udp
.port
!= rtp_exp
->saved_proto
.udp
.port
&&
516 !ip_nat_sdp_port(skb
, dataoff
, dptr
, datalen
,
517 mediaoff
, medialen
, port
))
523 nf_ct_unexpect_related(rtp_exp
);
524 nf_ct_unexpect_related(rtcp_exp
);
529 static void __exit
nf_nat_sip_fini(void)
531 rcu_assign_pointer(nf_nat_sip_hook
, NULL
);
532 rcu_assign_pointer(nf_nat_sip_seq_adjust_hook
, NULL
);
533 rcu_assign_pointer(nf_nat_sip_expect_hook
, NULL
);
534 rcu_assign_pointer(nf_nat_sdp_addr_hook
, NULL
);
535 rcu_assign_pointer(nf_nat_sdp_port_hook
, NULL
);
536 rcu_assign_pointer(nf_nat_sdp_session_hook
, NULL
);
537 rcu_assign_pointer(nf_nat_sdp_media_hook
, NULL
);
541 static int __init
nf_nat_sip_init(void)
543 BUG_ON(nf_nat_sip_hook
!= NULL
);
544 BUG_ON(nf_nat_sip_seq_adjust_hook
!= NULL
);
545 BUG_ON(nf_nat_sip_expect_hook
!= NULL
);
546 BUG_ON(nf_nat_sdp_addr_hook
!= NULL
);
547 BUG_ON(nf_nat_sdp_port_hook
!= NULL
);
548 BUG_ON(nf_nat_sdp_session_hook
!= NULL
);
549 BUG_ON(nf_nat_sdp_media_hook
!= NULL
);
550 rcu_assign_pointer(nf_nat_sip_hook
, ip_nat_sip
);
551 rcu_assign_pointer(nf_nat_sip_seq_adjust_hook
, ip_nat_sip_seq_adjust
);
552 rcu_assign_pointer(nf_nat_sip_expect_hook
, ip_nat_sip_expect
);
553 rcu_assign_pointer(nf_nat_sdp_addr_hook
, ip_nat_sdp_addr
);
554 rcu_assign_pointer(nf_nat_sdp_port_hook
, ip_nat_sdp_port
);
555 rcu_assign_pointer(nf_nat_sdp_session_hook
, ip_nat_sdp_session
);
556 rcu_assign_pointer(nf_nat_sdp_media_hook
, ip_nat_sdp_media
);
560 module_init(nf_nat_sip_init
);
561 module_exit(nf_nat_sip_fini
);