diff options
author | Patrick McHardy <kaber@trash.net> | 2008-03-25 23:25:49 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-25 23:25:49 -0400 |
commit | a9c1d35917c0c95c8f95a8e497fb91e301419693 (patch) | |
tree | 5727524a97424f03882e4b37c49073ea4270d8a6 /net | |
parent | d901a9369e6e7d07a7eb4ddb315c6fcbaf8b24d3 (diff) |
[NETFILTER]: nf_conntrack_sip: create RTCP expectations
Create expectations for the RTCP connections in addition to RTP connections.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 42 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 58 |
2 files changed, 64 insertions, 36 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 4b85e21a2a4a..f73ab4883b75 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -364,7 +364,8 @@ static unsigned int mangle_sdp(struct sk_buff *skb, | |||
364 | Mangle it, and change the expectation to match the new version. */ | 364 | Mangle it, and change the expectation to match the new version. */ |
365 | static unsigned int ip_nat_sdp(struct sk_buff *skb, | 365 | static unsigned int ip_nat_sdp(struct sk_buff *skb, |
366 | const char **dptr, unsigned int *datalen, | 366 | const char **dptr, unsigned int *datalen, |
367 | struct nf_conntrack_expect *exp) | 367 | struct nf_conntrack_expect *rtp_exp, |
368 | struct nf_conntrack_expect *rtcp_exp) | ||
368 | { | 369 | { |
369 | enum ip_conntrack_info ctinfo; | 370 | enum ip_conntrack_info ctinfo; |
370 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 371 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
@@ -375,31 +376,40 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, | |||
375 | /* Connection will come from reply */ | 376 | /* Connection will come from reply */ |
376 | if (ct->tuplehash[dir].tuple.src.u3.ip == | 377 | if (ct->tuplehash[dir].tuple.src.u3.ip == |
377 | ct->tuplehash[!dir].tuple.dst.u3.ip) | 378 | ct->tuplehash[!dir].tuple.dst.u3.ip) |
378 | newip = exp->tuple.dst.u3.ip; | 379 | newip = rtp_exp->tuple.dst.u3.ip; |
379 | else | 380 | else |
380 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; | 381 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; |
381 | 382 | ||
382 | exp->saved_ip = exp->tuple.dst.u3.ip; | 383 | rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; |
383 | exp->tuple.dst.u3.ip = newip; | 384 | rtp_exp->tuple.dst.u3.ip = newip; |
384 | exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; | 385 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; |
385 | exp->dir = !dir; | 386 | rtp_exp->dir = !dir; |
386 | 387 | rtp_exp->expectfn = ip_nat_sip_expected; | |
387 | /* When you see the packet, we need to NAT it the same as the | 388 | |
388 | this one. */ | 389 | rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; |
389 | exp->expectfn = ip_nat_sip_expected; | 390 | rtcp_exp->tuple.dst.u3.ip = newip; |
390 | 391 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | |
391 | /* Try to get same port: if not, try to change it. */ | 392 | rtcp_exp->dir = !dir; |
392 | for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { | 393 | rtcp_exp->expectfn = ip_nat_sip_expected; |
393 | exp->tuple.dst.u.udp.port = htons(port); | 394 | |
394 | if (nf_ct_expect_related(exp) == 0) | 395 | /* Try to get same pair of ports: if not, try to change them. */ |
396 | for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); | ||
397 | port != 0; port += 2) { | ||
398 | rtp_exp->tuple.dst.u.udp.port = htons(port); | ||
399 | if (nf_ct_expect_related(rtp_exp) != 0) | ||
400 | continue; | ||
401 | rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); | ||
402 | if (nf_ct_expect_related(rtcp_exp) == 0) | ||
395 | break; | 403 | break; |
404 | nf_ct_unexpect_related(rtp_exp); | ||
396 | } | 405 | } |
397 | 406 | ||
398 | if (port == 0) | 407 | if (port == 0) |
399 | return NF_DROP; | 408 | return NF_DROP; |
400 | 409 | ||
401 | if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { | 410 | if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { |
402 | nf_ct_unexpect_related(exp); | 411 | nf_ct_unexpect_related(rtp_exp); |
412 | nf_ct_unexpect_related(rtcp_exp); | ||
403 | return NF_DROP; | 413 | return NF_DROP; |
404 | } | 414 | } |
405 | return NF_ACCEPT; | 415 | return NF_ACCEPT; |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 813aa8c67e4c..217262e23403 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -63,7 +63,9 @@ EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); | |||
63 | unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, | 63 | unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, |
64 | const char **dptr, | 64 | const char **dptr, |
65 | unsigned int *datalen, | 65 | unsigned int *datalen, |
66 | struct nf_conntrack_expect *exp) __read_mostly; | 66 | struct nf_conntrack_expect *rtp_exp, |
67 | struct nf_conntrack_expect *rtcp_exp) | ||
68 | __read_mostly; | ||
67 | EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); | 69 | EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); |
68 | 70 | ||
69 | static int string_len(const struct nf_conn *ct, const char *dptr, | 71 | static int string_len(const struct nf_conn *ct, const char *dptr, |
@@ -659,18 +661,20 @@ static void flush_expectations(struct nf_conn *ct, bool media) | |||
659 | spin_unlock_bh(&nf_conntrack_lock); | 661 | spin_unlock_bh(&nf_conntrack_lock); |
660 | } | 662 | } |
661 | 663 | ||
662 | static int set_expected_rtp(struct sk_buff *skb, | 664 | static int set_expected_rtp_rtcp(struct sk_buff *skb, |
663 | const char **dptr, unsigned int *datalen, | 665 | const char **dptr, unsigned int *datalen, |
664 | union nf_inet_addr *daddr, __be16 port) | 666 | union nf_inet_addr *daddr, __be16 port) |
665 | { | 667 | { |
666 | struct nf_conntrack_expect *exp; | 668 | struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; |
667 | enum ip_conntrack_info ctinfo; | 669 | enum ip_conntrack_info ctinfo; |
668 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 670 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
669 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 671 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
670 | union nf_inet_addr *saddr; | 672 | union nf_inet_addr *saddr; |
671 | struct nf_conntrack_tuple tuple; | 673 | struct nf_conntrack_tuple tuple; |
672 | int family = ct->tuplehash[!dir].tuple.src.l3num; | 674 | int family = ct->tuplehash[!dir].tuple.src.l3num; |
673 | int skip_expect = 0, ret; | 675 | int skip_expect = 0, ret = NF_DROP; |
676 | u_int16_t base_port; | ||
677 | __be16 rtp_port, rtcp_port; | ||
674 | typeof(nf_nat_sdp_hook) nf_nat_sdp; | 678 | typeof(nf_nat_sdp_hook) nf_nat_sdp; |
675 | 679 | ||
676 | saddr = NULL; | 680 | saddr = NULL; |
@@ -704,23 +708,37 @@ static int set_expected_rtp(struct sk_buff *skb, | |||
704 | if (skip_expect) | 708 | if (skip_expect) |
705 | return NF_ACCEPT; | 709 | return NF_ACCEPT; |
706 | 710 | ||
707 | exp = nf_ct_expect_alloc(ct); | 711 | base_port = ntohs(tuple.dst.u.udp.port) & ~1; |
708 | if (exp == NULL) | 712 | rtp_port = htons(base_port); |
709 | return NF_DROP; | 713 | rtcp_port = htons(base_port + 1); |
710 | nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr, | 714 | |
711 | IPPROTO_UDP, NULL, &port); | 715 | rtp_exp = nf_ct_expect_alloc(ct); |
716 | if (rtp_exp == NULL) | ||
717 | goto err1; | ||
718 | nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, | ||
719 | IPPROTO_UDP, NULL, &rtp_port); | ||
720 | |||
721 | rtcp_exp = nf_ct_expect_alloc(ct); | ||
722 | if (rtcp_exp == NULL) | ||
723 | goto err2; | ||
724 | nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, | ||
725 | IPPROTO_UDP, NULL, &rtcp_port); | ||
712 | 726 | ||
713 | nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); | 727 | nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); |
714 | if (nf_nat_sdp && ct->status & IPS_NAT_MASK) | 728 | if (nf_nat_sdp && ct->status & IPS_NAT_MASK) |
715 | ret = nf_nat_sdp(skb, dptr, datalen, exp); | 729 | ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp); |
716 | else { | 730 | else { |
717 | if (nf_ct_expect_related(exp) != 0) | 731 | if (nf_ct_expect_related(rtp_exp) == 0) { |
718 | ret = NF_DROP; | 732 | if (nf_ct_expect_related(rtcp_exp) != 0) |
719 | else | 733 | nf_ct_unexpect_related(rtp_exp); |
720 | ret = NF_ACCEPT; | 734 | else |
735 | ret = NF_ACCEPT; | ||
736 | } | ||
721 | } | 737 | } |
722 | nf_ct_expect_put(exp); | 738 | nf_ct_expect_put(rtcp_exp); |
723 | 739 | err2: | |
740 | nf_ct_expect_put(rtp_exp); | ||
741 | err1: | ||
724 | return ret; | 742 | return ret; |
725 | } | 743 | } |
726 | 744 | ||
@@ -758,7 +776,7 @@ static int process_sdp(struct sk_buff *skb, | |||
758 | if (port < 1024 || port > 65535) | 776 | if (port < 1024 || port > 65535) |
759 | return NF_DROP; | 777 | return NF_DROP; |
760 | 778 | ||
761 | return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); | 779 | return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port)); |
762 | } | 780 | } |
763 | static int process_invite_response(struct sk_buff *skb, | 781 | static int process_invite_response(struct sk_buff *skb, |
764 | const char **dptr, unsigned int *datalen, | 782 | const char **dptr, unsigned int *datalen, |
@@ -1101,7 +1119,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1 | |||
1101 | .timeout = 3 * 60, | 1119 | .timeout = 3 * 60, |
1102 | }, | 1120 | }, |
1103 | [SIP_EXPECT_AUDIO] = { | 1121 | [SIP_EXPECT_AUDIO] = { |
1104 | .max_expected = IP_CT_DIR_MAX, | 1122 | .max_expected = 2 * IP_CT_DIR_MAX, |
1105 | .timeout = 3 * 60, | 1123 | .timeout = 3 * 60, |
1106 | }, | 1124 | }, |
1107 | }; | 1125 | }; |