Author: glebius
Date: Mon Sep  2 10:14:25 2013
New Revision: 255143
URL: http://svnweb.freebsd.org/changeset/base/255143

Log:
  Merge 1.12 of pf_lb.c from OpenBSD, with some changes. Original commit:
  
    date: 2010/02/04 14:10:12;  author: sthen;  state: Exp;  lines: +24 -19;
    pf_get_sport() picks a random port from the port range specified in a
    nat rule. It should check to see if it's in-use (i.e. matches an existing
    PF state), if it is, it cycles sequentially through other ports until
    it finds a free one. However the check was being done with the state
    keys the wrong way round so it was never actually finding the state
    to be in-use.
  
    - switch the keys to correct this, avoiding random state collisions
    with nat. Fixes PR 6300 and problems reported by robert@ and viq.
  
    - check pf_get_sport() return code in pf_test(); if port allocation
    fails the packet should be dropped rather than sent out untranslated.
  
    Help/ok claudio@.
  
  Some additional changes to 1.12:
  
  - We also need to bzero() the key to zero padding, otherwise key
    won't match.
  - Collapse two if blocks into one with ||, since both conditions
    lead to the same processing.
  - Only naddr changes in the cycle, so move initialization of other
    fields above the cycle.
  - s/u_intXX_t/uintXX_t/g
  
  PR:           kern/181690
  Submitted by: Olivier Cochard-Labbé <olivier cochard.me>
  Sponsored by: Nginx, Inc.

Modified:
  head/sys/netpfil/pf/pf_lb.c

Modified: head/sys/netpfil/pf/pf_lb.c
==============================================================================
--- head/sys/netpfil/pf/pf_lb.c Mon Sep  2 06:41:54 2013        (r255142)
+++ head/sys/netpfil/pf/pf_lb.c Mon Sep  2 10:14:25 2013        (r255143)
@@ -58,10 +58,9 @@ static struct pf_rule        *pf_match_translat
                            int, int, struct pfi_kif *,
                            struct pf_addr *, u_int16_t, struct pf_addr *,
                            uint16_t, int, struct pf_anchor_stackframe *);
-static int              pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
-                           struct pf_addr *, struct pf_addr *, u_int16_t,
-                           struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
-                           struct pf_src_node **);
+static int pf_get_sport(sa_family_t, uint8_t, struct pf_rule *,
+    struct pf_addr *, uint16_t, struct pf_addr *, uint16_t, struct pf_addr *,
+    uint16_t *, uint16_t, uint16_t, struct pf_src_node **);
 
 #define mix(a,b,c) \
        do {                                    \
@@ -210,13 +209,13 @@ pf_match_translation(struct pf_pdesc *pd
 
 static int
 pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
-    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
-    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
-    struct pf_src_node **sn)
+    struct pf_addr *saddr, uint16_t sport, struct pf_addr *daddr,
+    uint16_t dport, struct pf_addr *naddr, uint16_t *nport, uint16_t low,
+    uint16_t high, struct pf_src_node **sn)
 {
        struct pf_state_key_cmp key;
        struct pf_addr          init_addr;
-       u_int16_t               cut;
+       uint16_t                cut;
 
        bzero(&init_addr, sizeof(init_addr));
        if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
@@ -227,34 +226,38 @@ pf_get_sport(sa_family_t af, u_int8_t pr
                high = 65535;
        }
 
+       bzero(&key, sizeof(key));
+       key.af = af;
+       key.proto = proto;
+       key.port[0] = dport;
+       PF_ACPY(&key.addr[0], daddr, key.af);
+
        do {
-               key.af = af;
-               key.proto = proto;
-               PF_ACPY(&key.addr[1], daddr, key.af);
-               PF_ACPY(&key.addr[0], naddr, key.af);
-               key.port[1] = dport;
+               PF_ACPY(&key.addr[1], naddr, key.af);
 
                /*
                 * port search; start random, step;
                 * similar 2 portloop in in_pcbbind
                 */
                if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
-                   proto == IPPROTO_ICMP)) {
-                       key.port[0] = dport;
-                       if (pf_find_state_all(&key, PF_IN, NULL) == NULL)
-                               return (0);
-               } else if (low == 0 && high == 0) {
-                       key.port[0] = *nport;
-                       if (pf_find_state_all(&key, PF_IN, NULL) == NULL)
+                   proto == IPPROTO_ICMP) || (low == 0 && high == 0)) {
+                       /*
+                        * XXX bug: icmp states don't use the id on both sides.
+                        * (traceroute -I through nat)
+                        */
+                       key.port[1] = sport;
+                       if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
+                               *nport = sport;
                                return (0);
+                       }
                } else if (low == high) {
-                       key.port[0] = htons(low);
+                       key.port[1] = htons(low);
                        if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
                                *nport = htons(low);
                                return (0);
                        }
                } else {
-                       u_int16_t tmp;
+                       uint16_t tmp;
 
                        if (low > high) {
                                tmp = low;
@@ -265,7 +268,7 @@ pf_get_sport(sa_family_t af, u_int8_t pr
                        cut = htonl(arc4random()) % (1 + high - low) + low;
                        /* low <= cut <= high */
                        for (tmp = cut; tmp <= high; ++(tmp)) {
-                               key.port[0] = htons(tmp);
+                               key.port[1] = htons(tmp);
                                if (pf_find_state_all(&key, PF_IN, NULL) ==
                                    NULL) {
                                        *nport = htons(tmp);
@@ -273,7 +276,7 @@ pf_get_sport(sa_family_t af, u_int8_t pr
                                }
                        }
                        for (tmp = cut - 1; tmp >= low; --(tmp)) {
-                               key.port[0] = htons(tmp);
+                               key.port[1] = htons(tmp);
                                if (pf_find_state_all(&key, PF_IN, NULL) ==
                                    NULL) {
                                        *nport = htons(tmp);
@@ -551,8 +554,8 @@ pf_get_translation(struct pf_pdesc *pd, 
 
        switch (r->action) {
        case PF_NAT:
-               if (pf_get_sport(pd->af, pd->proto, r, saddr, daddr, dport,
-                   naddr, nport, r->rpool.proxy_port[0],
+               if (pf_get_sport(pd->af, pd->proto, r, saddr, sport, daddr,
+                   dport, naddr, nport, r->rpool.proxy_port[0],
                    r->rpool.proxy_port[1], sn)) {
                        DPFPRINTF(PF_DEBUG_MISC,
                            ("pf: NAT proxy port allocation (%u-%u) failed\n",
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to