[NETFILTER]: nf_conntrack_sip: allow media expectations with wildcard source address
Patrick McHardy [Wed, 26 Mar 2008 03:25:32 +0000 (20:25 -0700)]
Media streams can come from anywhere, add a module parameter which
controls whether wildcard expectations or expectations between the
two signalling endpoints are created.

Since the same media description sent on multiple connections may
results in multiple identical expections when using a wildcard source,
we need to check whether a similar expectation already exists for a
different connection before attempting to register it.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

net/netfilter/nf_conntrack_sip.c

index 043aa55..813aa8c 100644 (file)
@@ -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);