Perform the same SNAT translation on RTP/RTCP conntracks regardless of
who sends the first datagram.

Prior to this change, RTP packets send by the peer who required source
port translation were forwarded with unmodified source port when this
peer started its voice/video stream first.

Signed-off-by: Alin Nastac <alin.nas...@gmail.com>
---
 net/netfilter/nf_nat_sip.c | 35 +++++++++++++++++++++++++++++++----
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c
index 1f30860..a1e23cc 100644
--- a/net/netfilter/nf_nat_sip.c
+++ b/net/netfilter/nf_nat_sip.c
@@ -18,6 +18,7 @@
 
 #include <net/netfilter/nf_nat.h>
 #include <net/netfilter/nf_nat_helper.h>
+#include <net/netfilter/nf_conntrack_core.h>
 #include <net/netfilter/nf_conntrack_helper.h>
 #include <net/netfilter/nf_conntrack_expect.h>
 #include <net/netfilter/nf_conntrack_seqadj.h>
@@ -316,6 +317,9 @@ static void nf_nat_sip_seq_adjust(struct sk_buff *skb, 
unsigned int protoff,
 static void nf_nat_sip_expected(struct nf_conn *ct,
                                struct nf_conntrack_expect *exp)
 {
+       struct nf_conn_help *help = nfct_help(ct->master);
+       struct nf_conntrack_expect *pair_exp;
+       int range_set_for_snat = 0;
        struct nf_nat_range2 range;
 
        /* This must be a fresh one. */
@@ -327,15 +331,38 @@ static void nf_nat_sip_expected(struct nf_conn *ct,
        range.min_addr = range.max_addr = exp->saved_addr;
        nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
 
-       /* Change src to where master sends to, but only if the connection
-        * actually came from the same source. */
-       if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
+       /* Do SRC manip according with the parameters found in the
+        * paired expected conntrack. */
+       spin_lock_bh(&nf_conntrack_expect_lock);
+       hlist_for_each_entry(pair_exp, &help->expectations, lnode) {
+               if (pair_exp->tuple.src.l3num == nf_ct_l3num(ct) &&
+                   pair_exp->tuple.dst.protonum == 
ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum &&
+                   
nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3, 
&pair_exp->saved_addr) &&
+                   ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.all == 
pair_exp->saved_proto.all) {
+                       range.flags = (NF_NAT_RANGE_MAP_IPS | 
NF_NAT_RANGE_PROTO_SPECIFIED);
+                       range.min_proto.all = range.max_proto.all = 
pair_exp->tuple.dst.u.all;
+                       range.min_addr = range.max_addr = 
pair_exp->tuple.dst.u3;
+                       range_set_for_snat = 1;
+                       break;
+               }
+       }
+       spin_unlock_bh(&nf_conntrack_expect_lock);
+
+       /* When no paired expected conntrack has been found, change src to
+        * where master sends to, but only if the connection actually came
+        * from the same source. */
+       if (!range_set_for_snat &&
+           nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
                             &ct->master->tuplehash[exp->dir].tuple.src.u3)) {
                range.flags = NF_NAT_RANGE_MAP_IPS;
                range.min_addr = range.max_addr
                        = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
-               nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
+               range_set_for_snat = 1;
        }
+
+       /* Perform SRC manip. */
+       if (range_set_for_snat)
+               nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
 }
 
 static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int 
protoff,
-- 
2.7.4

Reply via email to