summaryrefslogtreecommitdiff
path: root/net/netfilter/nf_conntrack_sip.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/netfilter/nf_conntrack_sip.c')
-rw-r--r--net/netfilter/nf_conntrack_sip.c45
1 files changed, 41 insertions, 4 deletions
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 043aa557e7a..813aa8c67e4 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -42,6 +42,11 @@ module_param(sip_direct_signalling, int, 0600);
MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar "
"only (default 1)");
+static int sip_direct_media __read_mostly = 1;
+module_param(sip_direct_media, int, 0600);
+MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling "
+ "endpoints only (default 1)");
+
unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen) __read_mostly;
@@ -656,21 +661,53 @@ static void flush_expectations(struct nf_conn *ct, bool media)
static int set_expected_rtp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
- union nf_inet_addr *addr, __be16 port)
+ union nf_inet_addr *daddr, __be16 port)
{
struct nf_conntrack_expect *exp;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
+ union nf_inet_addr *saddr;
+ struct nf_conntrack_tuple tuple;
int family = ct->tuplehash[!dir].tuple.src.l3num;
- int ret;
+ int skip_expect = 0, ret;
typeof(nf_nat_sdp_hook) nf_nat_sdp;
+ saddr = NULL;
+ if (sip_direct_media) {
+ if (!nf_inet_addr_cmp(daddr, &ct->tuplehash[dir].tuple.src.u3))
+ return NF_ACCEPT;
+ saddr = &ct->tuplehash[!dir].tuple.src.u3;
+ }
+
+ /* We need to check whether the registration exists before attempting
+ * to register it since we can see the same media description multiple
+ * times on different connections in case multiple endpoints receive
+ * the same call.
+ */
+ memset(&tuple, 0, sizeof(tuple));
+ if (saddr)
+ tuple.src.u3 = *saddr;
+ tuple.src.l3num = family;
+ tuple.dst.protonum = IPPROTO_UDP;
+ tuple.dst.u3 = *daddr;
+ tuple.dst.u.udp.port = port;
+
+ rcu_read_lock();
+ exp = __nf_ct_expect_find(&tuple);
+ if (exp && exp->master != ct &&
+ nfct_help(exp->master)->helper == nfct_help(ct)->helper &&
+ exp->class == SIP_EXPECT_AUDIO)
+ skip_expect = 1;
+ rcu_read_unlock();
+
+ if (skip_expect)
+ return NF_ACCEPT;
+
exp = nf_ct_expect_alloc(ct);
if (exp == NULL)
return NF_DROP;
- nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family,
- &ct->tuplehash[!dir].tuple.src.u3, addr,
+ nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr,
IPPROTO_UDP, NULL, &port);
nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook);