netfilter: nf_nat: better error handling of nf_ct_expect_related() in helpers
authorPablo Neira Ayuso <pablo@netfilter.org>
Wed, 22 Sep 2010 06:34:12 +0000 (08:34 +0200)
committerPatrick McHardy <kaber@trash.net>
Wed, 22 Sep 2010 06:34:12 +0000 (08:34 +0200)
This patch improves the situation in which the expectation table is
full for conntrack NAT helpers. Basically, we give up if we don't
find a place in the table instead of looping over nf_ct_expect_related()
with a different port (we should only do this if it returns -EBUSY, for
-EMFILE or -ESHUTDOWN I think that it's better to skip this).

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Patrick McHardy <kaber@trash.net>
net/ipv4/netfilter/nf_nat_amanda.c
net/ipv4/netfilter/nf_nat_ftp.c
net/ipv4/netfilter/nf_nat_h323.c
net/ipv4/netfilter/nf_nat_irc.c
net/ipv4/netfilter/nf_nat_sip.c

index c31b876682502c5d6c13523ff086103e49c5fd7f..0f23b3f06df05e7643e1cd337325955dc6942794 100644 (file)
@@ -44,9 +44,16 @@ static unsigned int help(struct sk_buff *skb,
 
        /* Try to get same port: if not, try to change it. */
        for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+               int ret;
+
                exp->tuple.dst.u.tcp.port = htons(port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
+                       break;
+               else if (ret != -EBUSY) {
+                       port = 0;
                        break;
+               }
        }
 
        if (port == 0)
index 86e0e84ff0a04fe09cd3b5d67dddcf93457ffa15..dc73abb3fe27ecea0537ab8fa2a5e029435fb783 100644 (file)
@@ -79,9 +79,16 @@ static unsigned int nf_nat_ftp(struct sk_buff *skb,
 
        /* Try to get same port: if not, try to change it. */
        for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+               int ret;
+
                exp->tuple.dst.u.tcp.port = htons(port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
+                       break;
+               else if (ret != -EBUSY) {
+                       port = 0;
                        break;
+               }
        }
 
        if (port == 0)
index 5045196d853c7878050161ea5e43e1aac26eff83..790f3160e0121c19ed5f2bef07388656ae7310a6 100644 (file)
@@ -222,13 +222,24 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
        /* Try to get a pair of ports. */
        for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
             nated_port != 0; nated_port += 2) {
+               int ret;
+
                rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
-               if (nf_ct_expect_related(rtp_exp) == 0) {
+               ret = nf_ct_expect_related(rtp_exp);
+               if (ret == 0) {
                        rtcp_exp->tuple.dst.u.udp.port =
                            htons(nated_port + 1);
-                       if (nf_ct_expect_related(rtcp_exp) == 0)
+                       ret = nf_ct_expect_related(rtcp_exp);
+                       if (ret == 0)
+                               break;
+                       else if (ret != -EBUSY) {
+                               nf_ct_unexpect_related(rtp_exp);
+                               nated_port = 0;
                                break;
-                       nf_ct_unexpect_related(rtp_exp);
+                       }
+               } else if (ret != -EBUSY) {
+                       nated_port = 0;
+                       break;
                }
        }
 
@@ -284,9 +295,16 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
 
        /* Try to get same port: if not, try to change it. */
        for (; nated_port != 0; nated_port++) {
+               int ret;
+
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
+                       break;
+               else if (ret != -EBUSY) {
+                       nated_port = 0;
                        break;
+               }
        }
 
        if (nated_port == 0) {  /* No port available */
@@ -334,9 +352,16 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
 
        /* Try to get same port: if not, try to change it. */
        for (; nated_port != 0; nated_port++) {
+               int ret;
+
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
                        break;
+               else if (ret != -EBUSY) {
+                       nated_port = 0;
+                       break;
+               }
        }
 
        if (nated_port == 0) {  /* No port available */
@@ -418,9 +443,16 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
 
        /* Try to get same port: if not, try to change it. */
        for (; nated_port != 0; nated_port++) {
+               int ret;
+
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
+                       break;
+               else if (ret != -EBUSY) {
+                       nated_port = 0;
                        break;
+               }
        }
 
        if (nated_port == 0) {  /* No port available */
@@ -500,9 +532,16 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
 
        /* Try to get same port: if not, try to change it. */
        for (nated_port = ntohs(port); nated_port != 0; nated_port++) {
+               int ret;
+
                exp->tuple.dst.u.tcp.port = htons(nated_port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
                        break;
+               else if (ret != -EBUSY) {
+                       nated_port = 0;
+                       break;
+               }
        }
 
        if (nated_port == 0) {  /* No port available */
index ea83a886b03e6ac3204f410047542a9edea8c4dc..535e1a80235688480bb9b58d2492291183e7703a 100644 (file)
@@ -45,9 +45,16 @@ static unsigned int help(struct sk_buff *skb,
 
        /* Try to get same port: if not, try to change it. */
        for (port = ntohs(exp->saved_proto.tcp.port); port != 0; port++) {
+               int ret;
+
                exp->tuple.dst.u.tcp.port = htons(port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
+                       break;
+               else if (ret != -EBUSY) {
+                       port = 0;
                        break;
+               }
        }
 
        if (port == 0)
index 11b538deaaec1f996505d387d549b3de6dd4bb37..e40cf7816fdbb4e0088efd200a46cbd3a9041ed2 100644 (file)
@@ -307,9 +307,16 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
        exp->expectfn = ip_nat_sip_expected;
 
        for (; port != 0; port++) {
+               int ret;
+
                exp->tuple.dst.u.udp.port = htons(port);
-               if (nf_ct_expect_related(exp) == 0)
+               ret = nf_ct_expect_related(exp);
+               if (ret == 0)
+                       break;
+               else if (ret != -EBUSY) {
+                       port = 0;
                        break;
+               }
        }
 
        if (port == 0)
@@ -480,13 +487,25 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
        /* Try to get same pair of ports: if not, try to change them. */
        for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
             port != 0; port += 2) {
+               int ret;
+
                rtp_exp->tuple.dst.u.udp.port = htons(port);
-               if (nf_ct_expect_related(rtp_exp) != 0)
+               ret = nf_ct_expect_related(rtp_exp);
+               if (ret == -EBUSY)
                        continue;
+               else if (ret < 0) {
+                       port = 0;
+                       break;
+               }
                rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
-               if (nf_ct_expect_related(rtcp_exp) == 0)
+               ret = nf_ct_expect_related(rtcp_exp);
+               if (ret == 0)
                        break;
-               nf_ct_unexpect_related(rtp_exp);
+               else if (ret != -EBUSY) {
+                       nf_ct_unexpect_related(rtp_exp);
+                       port = 0;
+                       break;
+               }
        }
 
        if (port == 0)