aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2008-03-25 23:25:13 -0400
committerDavid S. Miller <davem@davemloft.net>2008-03-25 23:25:13 -0400
commit0f32a40fc91a9ebbbf66e826ac2a829ab37d9cf8 (patch)
tree0c221d19a91fa5ab4d746480438ea0f47031062d /net/ipv4
parentc978cd3a937141deaf7995b849824af6dacdeae7 (diff)
[NETFILTER]: nf_conntrack_sip: create signalling expectations
Create expectations for incoming signalling connections when seeing a REGISTER request. This is needed when the registrar uses a different source port number for signalling messages and for receiving incoming calls from other endpoints than the registrar. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/netfilter/nf_nat_sip.c111
1 files changed, 89 insertions, 22 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c
index b443618a85..4b85e21a2a 100644
--- a/net/ipv4/netfilter/nf_nat_sip.c
+++ b/net/ipv4/netfilter/nf_nat_sip.c
@@ -205,6 +205,91 @@ next:
205 return NF_ACCEPT; 205 return NF_ACCEPT;
206} 206}
207 207
208/* Handles expected signalling connections and media streams */
209static void ip_nat_sip_expected(struct nf_conn *ct,
210 struct nf_conntrack_expect *exp)
211{
212 struct nf_nat_range range;
213
214 /* This must be a fresh one. */
215 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
216
217 /* For DST manip, map port here to where it's expected. */
218 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
219 range.min = range.max = exp->saved_proto;
220 range.min_ip = range.max_ip = exp->saved_ip;
221 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
222
223 /* Change src to where master sends to, but only if the connection
224 * actually came from the same source. */
225 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
226 ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
227 range.flags = IP_NAT_RANGE_MAP_IPS;
228 range.min_ip = range.max_ip
229 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
230 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
231 }
232}
233
234static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
235 const char **dptr, unsigned int *datalen,
236 struct nf_conntrack_expect *exp,
237 unsigned int matchoff,
238 unsigned int matchlen)
239{
240 enum ip_conntrack_info ctinfo;
241 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
242 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
243 __be32 newip;
244 u_int16_t port;
245 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
246 unsigned buflen;
247
248 /* Connection will come from reply */
249 if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
250 newip = exp->tuple.dst.u3.ip;
251 else
252 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
253
254 /* If the signalling port matches the connection's source port in the
255 * original direction, try to use the destination port in the opposite
256 * direction. */
257 if (exp->tuple.dst.u.udp.port ==
258 ct->tuplehash[dir].tuple.src.u.udp.port)
259 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
260 else
261 port = ntohs(exp->tuple.dst.u.udp.port);
262
263 exp->saved_ip = exp->tuple.dst.u3.ip;
264 exp->tuple.dst.u3.ip = newip;
265 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
266 exp->dir = !dir;
267 exp->expectfn = ip_nat_sip_expected;
268
269 for (; port != 0; port++) {
270 exp->tuple.dst.u.udp.port = htons(port);
271 if (nf_ct_expect_related(exp) == 0)
272 break;
273 }
274
275 if (port == 0)
276 return NF_DROP;
277
278 if (exp->tuple.dst.u3.ip != exp->saved_ip ||
279 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
280 buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
281 NIPQUAD(newip), port);
282 if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
283 buffer, buflen))
284 goto err;
285 }
286 return NF_ACCEPT;
287
288err:
289 nf_ct_unexpect_related(exp);
290 return NF_DROP;
291}
292
208static int mangle_content_len(struct sk_buff *skb, 293static int mangle_content_len(struct sk_buff *skb,
209 const char **dptr, unsigned int *datalen) 294 const char **dptr, unsigned int *datalen)
210{ 295{
@@ -275,27 +360,6 @@ static unsigned int mangle_sdp(struct sk_buff *skb,
275 return mangle_content_len(skb, dptr, datalen); 360 return mangle_content_len(skb, dptr, datalen);
276} 361}
277 362
278static void ip_nat_sdp_expect(struct nf_conn *ct,
279 struct nf_conntrack_expect *exp)
280{
281 struct nf_nat_range range;
282
283 /* This must be a fresh one. */
284 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
285
286 /* For DST manip, map port here to where it's expected. */
287 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
288 range.min = range.max = exp->saved_proto;
289 range.min_ip = range.max_ip = exp->saved_ip;
290 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
291
292 /* Change src to where master sends to */
293 range.flags = IP_NAT_RANGE_MAP_IPS;
294 range.min_ip = range.max_ip
295 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
296 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
297}
298
299/* So, this packet has hit the connection tracking matching code. 363/* So, this packet has hit the connection tracking matching code.
300 Mangle it, and change the expectation to match the new version. */ 364 Mangle it, and change the expectation to match the new version. */
301static unsigned int ip_nat_sdp(struct sk_buff *skb, 365static unsigned int ip_nat_sdp(struct sk_buff *skb,
@@ -322,7 +386,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
322 386
323 /* When you see the packet, we need to NAT it the same as the 387 /* When you see the packet, we need to NAT it the same as the
324 this one. */ 388 this one. */
325 exp->expectfn = ip_nat_sdp_expect; 389 exp->expectfn = ip_nat_sip_expected;
326 390
327 /* Try to get same port: if not, try to change it. */ 391 /* Try to get same port: if not, try to change it. */
328 for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { 392 for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) {
@@ -344,6 +408,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
344static void __exit nf_nat_sip_fini(void) 408static void __exit nf_nat_sip_fini(void)
345{ 409{
346 rcu_assign_pointer(nf_nat_sip_hook, NULL); 410 rcu_assign_pointer(nf_nat_sip_hook, NULL);
411 rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
347 rcu_assign_pointer(nf_nat_sdp_hook, NULL); 412 rcu_assign_pointer(nf_nat_sdp_hook, NULL);
348 synchronize_rcu(); 413 synchronize_rcu();
349} 414}
@@ -351,8 +416,10 @@ static void __exit nf_nat_sip_fini(void)
351static int __init nf_nat_sip_init(void) 416static int __init nf_nat_sip_init(void)
352{ 417{
353 BUG_ON(nf_nat_sip_hook != NULL); 418 BUG_ON(nf_nat_sip_hook != NULL);
419 BUG_ON(nf_nat_sip_expect_hook != NULL);
354 BUG_ON(nf_nat_sdp_hook != NULL); 420 BUG_ON(nf_nat_sdp_hook != NULL);
355 rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); 421 rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
422 rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
356 rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); 423 rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp);
357 return 0; 424 return 0;
358} 425}