The function pf_get_sport() did work for out rules only. Make it
authorbluhm <bluhm@openbsd.org>
Fri, 24 Jun 2016 13:55:57 +0000 (13:55 +0000)
committerbluhm <bluhm@openbsd.org>
Fri, 24 Jun 2016 13:55:57 +0000 (13:55 +0000)
aware of the direction of the packet.  Now nat-to can be used by
in rules and together with divert-to.  Collisions with existing
states are found and produce a "NAT proxy port allocation failed"
message.
OK henning@ mikeb@

sys/net/pf_lb.c

index 6ac7476..1639779 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pf_lb.c,v 1.53 2016/06/15 11:36:06 mikeb Exp $ */
+/*     $OpenBSD: pf_lb.c,v 1.54 2016/06/24 13:55:57 bluhm Exp $ */
 
 /*
  * Copyright (c) 2001 Daniel Hartmeier
@@ -155,6 +155,9 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r,
        struct pf_state_key_cmp key;
        struct pf_addr          init_addr;
        u_int16_t               cut;
+       int                     dir = (pd->dir == PF_IN) ? PF_OUT : PF_IN;
+       int                     sidx = pd->sidx;
+       int                     didx = pd->didx;
 
        bzero(&init_addr, sizeof(init_addr));
        if (pf_map_addr(pd->naf, r, &pd->nsaddr, naddr, &init_addr, sn, &r->nat,
@@ -182,9 +185,9 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r,
                key.af = pd->naf;
                key.proto = pd->proto;
                key.rdomain = pd->rdomain;
-               PF_ACPY(&key.addr[0], &pd->ndaddr, key.af);
-               PF_ACPY(&key.addr[1], naddr, key.af);
-               key.port[0] = pd->ndport;
+               PF_ACPY(&key.addr[didx], &pd->ndaddr, key.af);
+               PF_ACPY(&key.addr[sidx], naddr, key.af);
+               key.port[didx] = pd->ndport;
 
                /*
                 * port search; start random, step;
@@ -194,20 +197,20 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r,
                    pd->proto == IPPROTO_ICMP || pd->proto == IPPROTO_ICMPV6)) {
                        /* XXX bug: icmp states dont use the id on both
                         * XXX sides (traceroute -I through nat) */
-                       key.port[1] = pd->nsport;
-                       if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
+                       key.port[sidx] = pd->nsport;
+                       if (pf_find_state_all(&key, dir, NULL) == NULL) {
                                *nport = pd->nsport;
                                return (0);
                        }
                } else if (low == 0 && high == 0) {
-                       key.port[1] = pd->nsport;
-                       if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
+                       key.port[sidx] = pd->nsport;
+                       if (pf_find_state_all(&key, dir, NULL) == NULL) {
                                *nport = pd->nsport;
                                return (0);
                        }
                } else if (low == high) {
-                       key.port[1] = htons(low);
-                       if (pf_find_state_all(&key, PF_IN, NULL) == NULL) {
+                       key.port[sidx] = htons(low);
+                       if (pf_find_state_all(&key, dir, NULL) == NULL) {
                                *nport = htons(low);
                                return (0);
                        }
@@ -223,16 +226,16 @@ pf_get_sport(struct pf_pdesc *pd, struct pf_rule *r,
                        cut = arc4random_uniform(1 + high - low) + low;
                        /* low <= cut <= high */
                        for (tmp = cut; tmp <= high; ++(tmp)) {
-                               key.port[1] = htons(tmp);
-                               if (pf_find_state_all(&key, PF_IN, NULL) ==
+                               key.port[sidx] = htons(tmp);
+                               if (pf_find_state_all(&key, dir, NULL) ==
                                    NULL && !in_baddynamic(tmp, pd->proto)) {
                                        *nport = htons(tmp);
                                        return (0);
                                }
                        }
                        for (tmp = cut - 1; tmp >= low; --(tmp)) {
-                               key.port[1] = htons(tmp);
-                               if (pf_find_state_all(&key, PF_IN, NULL) ==
+                               key.port[sidx] = htons(tmp);
+                               if (pf_find_state_all(&key, dir, NULL) ==
                                    NULL && !in_baddynamic(tmp, pd->proto)) {
                                        *nport = htons(tmp);
                                        return (0);