diff options
author | Patrick McHardy <kaber@trash.net> | 2008-03-25 23:26:08 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-25 23:26:08 -0400 |
commit | 4ab9e64e5e3c0516577818804aaf13a630d67bc9 (patch) | |
tree | 70450c93e83f5038dc14da7614d669109e59a148 /net/ipv4 | |
parent | a9c1d35917c0c95c8f95a8e497fb91e301419693 (diff) |
[NETFILTER]: nf_nat_sip: split up SDP mangling
The SDP connection addresses may be contained in the payload multiple
times (in the session description and/or once per media description),
currently only the session description is properly updated. Split up
SDP mangling so the function setting up expectations only updates the
media port, update connection addresses from media descriptions while
parsing them and at the end update the session description when the
final addresses are known.
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.c | 121 |
1 files changed, 84 insertions, 37 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index f73ab4883b75..4429069d9b42 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -316,45 +316,77 @@ static int mangle_content_len(struct sk_buff *skb, | |||
316 | buffer, buflen); | 316 | buffer, buflen); |
317 | } | 317 | } |
318 | 318 | ||
319 | static unsigned mangle_sdp_packet(struct sk_buff *skb, | 319 | static unsigned mangle_sdp_packet(struct sk_buff *skb, const char **dptr, |
320 | const char **dptr, unsigned int *datalen, | 320 | unsigned int dataoff, unsigned int *datalen, |
321 | enum sdp_header_types type, | 321 | enum sdp_header_types type, |
322 | enum sdp_header_types term, | ||
322 | char *buffer, int buflen) | 323 | char *buffer, int buflen) |
323 | { | 324 | { |
324 | enum ip_conntrack_info ctinfo; | 325 | enum ip_conntrack_info ctinfo; |
325 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 326 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
326 | unsigned int matchlen, matchoff; | 327 | unsigned int matchlen, matchoff; |
327 | 328 | ||
328 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC, | 329 | if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term, |
329 | &matchoff, &matchlen) <= 0) | 330 | &matchoff, &matchlen) <= 0) |
330 | return 0; | 331 | return 0; |
331 | return mangle_packet(skb, dptr, datalen, matchoff, matchlen, | 332 | return mangle_packet(skb, dptr, datalen, matchoff, matchlen, |
332 | buffer, buflen); | 333 | buffer, buflen); |
333 | } | 334 | } |
334 | 335 | ||
335 | static unsigned int mangle_sdp(struct sk_buff *skb, | 336 | static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr, |
336 | enum ip_conntrack_info ctinfo, | 337 | unsigned int dataoff, |
337 | struct nf_conn *ct, | 338 | unsigned int *datalen, |
338 | __be32 newip, u_int16_t port, | 339 | enum sdp_header_types type, |
339 | const char **dptr, unsigned int *datalen) | 340 | enum sdp_header_types term, |
341 | const union nf_inet_addr *addr) | ||
340 | { | 342 | { |
341 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; | 343 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; |
342 | unsigned int bufflen; | 344 | unsigned int buflen; |
343 | 345 | ||
344 | /* Mangle owner and contact info. */ | 346 | buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip)); |
345 | bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); | 347 | if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term, |
346 | if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4, | 348 | buffer, buflen)) |
347 | buffer, bufflen)) | ||
348 | return 0; | 349 | return 0; |
349 | 350 | ||
350 | if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4, | 351 | return mangle_content_len(skb, dptr, datalen); |
351 | buffer, bufflen)) | 352 | } |
353 | |||
354 | static unsigned int ip_nat_sdp_port(struct sk_buff *skb, | ||
355 | const char **dptr, | ||
356 | unsigned int *datalen, | ||
357 | unsigned int matchoff, | ||
358 | unsigned int matchlen, | ||
359 | u_int16_t port) | ||
360 | { | ||
361 | char buffer[sizeof("nnnnn")]; | ||
362 | unsigned int buflen; | ||
363 | |||
364 | buflen = sprintf(buffer, "%u", port); | ||
365 | if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, | ||
366 | buffer, buflen)) | ||
352 | return 0; | 367 | return 0; |
353 | 368 | ||
354 | /* Mangle media port. */ | 369 | return mangle_content_len(skb, dptr, datalen); |
355 | bufflen = sprintf(buffer, "%u", port); | 370 | } |
356 | if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA, | 371 | |
357 | buffer, bufflen)) | 372 | static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, |
373 | unsigned int dataoff, | ||
374 | unsigned int *datalen, | ||
375 | const union nf_inet_addr *addr) | ||
376 | { | ||
377 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; | ||
378 | unsigned int buflen; | ||
379 | |||
380 | /* Mangle session description owner and contact addresses */ | ||
381 | buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip)); | ||
382 | if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, | ||
383 | SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA, | ||
384 | buffer, buflen)) | ||
385 | return 0; | ||
386 | |||
387 | if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, | ||
388 | SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA, | ||
389 | buffer, buflen)) | ||
358 | return 0; | 390 | return 0; |
359 | 391 | ||
360 | return mangle_content_len(skb, dptr, datalen); | 392 | return mangle_content_len(skb, dptr, datalen); |
@@ -362,32 +394,35 @@ static unsigned int mangle_sdp(struct sk_buff *skb, | |||
362 | 394 | ||
363 | /* So, this packet has hit the connection tracking matching code. | 395 | /* So, this packet has hit the connection tracking matching code. |
364 | Mangle it, and change the expectation to match the new version. */ | 396 | Mangle it, and change the expectation to match the new version. */ |
365 | static unsigned int ip_nat_sdp(struct sk_buff *skb, | 397 | static unsigned int ip_nat_sdp_media(struct sk_buff *skb, |
366 | const char **dptr, unsigned int *datalen, | 398 | const char **dptr, |
367 | struct nf_conntrack_expect *rtp_exp, | 399 | unsigned int *datalen, |
368 | struct nf_conntrack_expect *rtcp_exp) | 400 | struct nf_conntrack_expect *rtp_exp, |
401 | struct nf_conntrack_expect *rtcp_exp, | ||
402 | unsigned int mediaoff, | ||
403 | unsigned int medialen, | ||
404 | union nf_inet_addr *rtp_addr) | ||
369 | { | 405 | { |
370 | enum ip_conntrack_info ctinfo; | 406 | enum ip_conntrack_info ctinfo; |
371 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 407 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
372 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 408 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
373 | __be32 newip; | ||
374 | u_int16_t port; | 409 | u_int16_t port; |
375 | 410 | ||
376 | /* Connection will come from reply */ | 411 | /* Connection will come from reply */ |
377 | if (ct->tuplehash[dir].tuple.src.u3.ip == | 412 | if (ct->tuplehash[dir].tuple.src.u3.ip == |
378 | ct->tuplehash[!dir].tuple.dst.u3.ip) | 413 | ct->tuplehash[!dir].tuple.dst.u3.ip) |
379 | newip = rtp_exp->tuple.dst.u3.ip; | 414 | rtp_addr->ip = rtp_exp->tuple.dst.u3.ip; |
380 | else | 415 | else |
381 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; | 416 | rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip; |
382 | 417 | ||
383 | rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; | 418 | rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; |
384 | rtp_exp->tuple.dst.u3.ip = newip; | 419 | rtp_exp->tuple.dst.u3.ip = rtp_addr->ip; |
385 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; | 420 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; |
386 | rtp_exp->dir = !dir; | 421 | rtp_exp->dir = !dir; |
387 | rtp_exp->expectfn = ip_nat_sip_expected; | 422 | rtp_exp->expectfn = ip_nat_sip_expected; |
388 | 423 | ||
389 | rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; | 424 | rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; |
390 | rtcp_exp->tuple.dst.u3.ip = newip; | 425 | rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip; |
391 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | 426 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; |
392 | rtcp_exp->dir = !dir; | 427 | rtcp_exp->dir = !dir; |
393 | rtcp_exp->expectfn = ip_nat_sip_expected; | 428 | rtcp_exp->expectfn = ip_nat_sip_expected; |
@@ -405,21 +440,29 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, | |||
405 | } | 440 | } |
406 | 441 | ||
407 | if (port == 0) | 442 | if (port == 0) |
408 | return NF_DROP; | 443 | goto err1; |
444 | |||
445 | /* Update media port. */ | ||
446 | if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && | ||
447 | !ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port)) | ||
448 | goto err2; | ||
409 | 449 | ||
410 | if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { | ||
411 | nf_ct_unexpect_related(rtp_exp); | ||
412 | nf_ct_unexpect_related(rtcp_exp); | ||
413 | return NF_DROP; | ||
414 | } | ||
415 | return NF_ACCEPT; | 450 | return NF_ACCEPT; |
451 | |||
452 | err2: | ||
453 | nf_ct_unexpect_related(rtp_exp); | ||
454 | nf_ct_unexpect_related(rtcp_exp); | ||
455 | err1: | ||
456 | return NF_DROP; | ||
416 | } | 457 | } |
417 | 458 | ||
418 | static void __exit nf_nat_sip_fini(void) | 459 | static void __exit nf_nat_sip_fini(void) |
419 | { | 460 | { |
420 | rcu_assign_pointer(nf_nat_sip_hook, NULL); | 461 | rcu_assign_pointer(nf_nat_sip_hook, NULL); |
421 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); | 462 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); |
422 | rcu_assign_pointer(nf_nat_sdp_hook, NULL); | 463 | rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); |
464 | rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); | ||
465 | rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); | ||
423 | synchronize_rcu(); | 466 | synchronize_rcu(); |
424 | } | 467 | } |
425 | 468 | ||
@@ -427,10 +470,14 @@ static int __init nf_nat_sip_init(void) | |||
427 | { | 470 | { |
428 | BUG_ON(nf_nat_sip_hook != NULL); | 471 | BUG_ON(nf_nat_sip_hook != NULL); |
429 | BUG_ON(nf_nat_sip_expect_hook != NULL); | 472 | BUG_ON(nf_nat_sip_expect_hook != NULL); |
430 | BUG_ON(nf_nat_sdp_hook != NULL); | 473 | BUG_ON(nf_nat_sdp_addr_hook != NULL); |
474 | BUG_ON(nf_nat_sdp_session_hook != NULL); | ||
475 | BUG_ON(nf_nat_sdp_media_hook != NULL); | ||
431 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); | 476 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); |
432 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); | 477 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); |
433 | rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); | 478 | rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); |
479 | rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); | ||
480 | rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); | ||
434 | return 0; | 481 | return 0; |
435 | } | 482 | } |
436 | 483 | ||