summaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorRyan Thomas McBride <mcbride@cvs.openbsd.org>2002-11-23 05:16:59 +0000
committerRyan Thomas McBride <mcbride@cvs.openbsd.org>2002-11-23 05:16:59 +0000
commit1691df433770a29ad8547bf930bf7b9429c95b7c (patch)
tree24ac668979a5ffd2d01a44df047124d1fd917bf3 /sys/net
parent8fe184e0dc67bbb715ddc837a35dc2877a2eb0c5 (diff)
kernel code to allow multiple redirection addresses to be specified for nat
and rdr, as well as route-to, dup-to and reply-to. Addresses can be allocated in a number of ways: - masking out the network portion of the address and replacing it - randomly assigning an address in the block - hashing the source address and a key to determine the redirection address - iterating through the addresses sequentially (this is the only allocation scheme which works when a list of addresses is specified) ok dhartmei@ henning@
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/pf.c545
-rw-r--r--sys/net/pf_ioctl.c540
-rw-r--r--sys/net/pf_norm.c18
-rw-r--r--sys/net/pfvar.h115
4 files changed, 970 insertions, 248 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index 7c39448b572..99b481c6de6 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.259 2002/11/22 09:54:35 henning Exp $ */
+/* $OpenBSD: pf.c,v 1.260 2002/11/23 05:16:58 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -46,6 +46,7 @@
#include <sys/kernel.h>
#include <sys/time.h>
#include <sys/pool.h>
+#include <sys/md5k.h>
#include <net/if.h>
#include <net/if_types.h>
@@ -113,6 +114,7 @@ u_int32_t ticket_rdrs_active;
u_int32_t ticket_rdrs_inactive;
u_int32_t ticket_altqs_active;
u_int32_t ticket_altqs_inactive;
+u_int32_t ticket_pabuf;
/* Timeouts */
int pftm_tcp_first_packet = 120; /* First TCP packet */
@@ -150,7 +152,7 @@ int *pftm_timeouts[PFTM_MAX] = { &pftm_tcp_first_packet,
struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl, pf_sport_pl;
struct pool pf_rdr_pl, pf_state_pl, pf_binat_pl, pf_addr_pl;
-struct pool pf_altq_pl;
+struct pool pf_altq_pl, pf_pooladdr_pl;
void pf_addrcpy(struct pf_addr *, struct pf_addr *,
sa_family_t);
@@ -188,13 +190,14 @@ void pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
u_int16_t pf_map_port_range(struct pf_rdr *, u_int16_t);
struct pf_nat *pf_get_nat(struct ifnet *, u_int8_t,
struct pf_addr *, u_int16_t,
- struct pf_addr *, u_int16_t, sa_family_t);
+ struct pf_addr *, u_int16_t,
+ struct pf_addr *, u_int16_t *, sa_family_t);
struct pf_binat *pf_get_binat(int, struct ifnet *, u_int8_t,
struct pf_addr *, struct pf_addr *,
struct pf_addr *, sa_family_t);
struct pf_rdr *pf_get_rdr(struct ifnet *, u_int8_t,
struct pf_addr *, struct pf_addr *, u_int16_t,
- sa_family_t);
+ struct pf_addr *, sa_family_t);
int pf_test_tcp(struct pf_rule **, int, struct ifnet *,
struct mbuf *, int, int, void *, struct pf_pdesc *);
int pf_test_udp(struct pf_rule **, int, struct ifnet *,
@@ -221,17 +224,22 @@ void *pf_pull_hdr(struct mbuf *, int, void *, int,
void pf_calc_skip_steps(struct pf_rulequeue *);
#ifdef INET6
void pf_poolmask(struct pf_addr *, struct pf_addr*,
- struct pf_addr *, struct pf_addr *, sa_family_t);
+ struct pf_addr *, struct pf_addr *, u_int8_t);
+void pf_addr_inc(struct pf_addr *, sa_family_t);
#endif /* INET6 */
-int pf_get_sport(sa_family_t, u_int8_t,
+int pf_map_addr(u_int8_t, struct pf_pool *,
struct pf_addr *, struct pf_addr *,
- u_int16_t, u_int16_t *, u_int16_t, u_int16_t);
+ struct pf_addr *);
+int pf_get_sport(sa_family_t, u_int8_t,
+ struct pf_pool *, struct pf_addr *, u_int16_t,
+ struct pf_addr *, u_int16_t, struct pf_addr *,
+ u_int16_t*, u_int16_t, u_int16_t);
int pf_normalize_tcp(int, struct ifnet *, struct mbuf *,
int, int, void *, struct pf_pdesc *);
void pf_route(struct mbuf **, struct pf_rule *, int,
- struct ifnet *);
+ struct ifnet *, struct pf_state *);
void pf_route6(struct mbuf **, struct pf_rule *, int,
- struct ifnet *);
+ struct ifnet *, struct pf_state *);
int pf_socket_lookup(uid_t *, gid_t *, int, sa_family_t,
int, struct pf_pdesc *);
struct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = { { &pf_state_pl, UINT_MAX },
@@ -260,6 +268,7 @@ struct pf_natqueue pf_nats[2];
struct pf_binatqueue pf_binats[2];
struct pf_rdrqueue pf_rdrs[2];
struct pf_altqqueue pf_altqs[2];
+struct pf_palist pf_pabuf;
static __inline int
pf_state_compare(struct pf_tree_node *a, struct pf_tree_node *b)
@@ -739,7 +748,7 @@ pf_calc_skip_steps(struct pf_rulequeue *rules)
s->src.addr.addr_dyn == NULL &&
r->src.addr.addr_dyn == NULL &&
PF_AEQ(&s->src.addr.addr, &r->src.addr.addr, r->af) &&
- PF_AEQ(&s->src.mask, &r->src.mask, r->af) &&
+ PF_AEQ(&s->src.addr.mask, &r->src.addr.mask, r->af) &&
s->src.not == r->src.not);
PF_CALC_SKIP_STEP(PF_SKIP_SRC_PORT,
s->src.port[0] == r->src.port[0] &&
@@ -749,7 +758,7 @@ pf_calc_skip_steps(struct pf_rulequeue *rules)
s->dst.addr.addr_dyn == NULL &&
r->dst.addr.addr_dyn == NULL &&
PF_AEQ(&s->dst.addr.addr, &r->dst.addr.addr, r->af) &&
- PF_AEQ(&s->dst.mask, &r->dst.mask, r->af) &&
+ PF_AEQ(&s->dst.addr.mask, &r->dst.addr.mask, r->af) &&
s->dst.not == r->dst.not);
PF_CALC_SKIP_STEP(PF_SKIP_DST_PORT,
s->dst.port[0] == r->dst.port[0] &&
@@ -1240,74 +1249,246 @@ pf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
break;
}
}
+
+void
+pf_addr_inc(struct pf_addr *addr, u_int8_t af)
+{
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
+ break;
+#endif /* INET */
+ case AF_INET6:
+ if (addr->addr32[3] == 0xffffffff) {
+ addr->addr32[3] = 0;
+ if (addr->addr32[2] == 0xffffffff) {
+ addr->addr32[2] = 0;
+ if (addr->addr32[1] == 0xffffffff) {
+ addr->addr32[1] = 0;
+ addr->addr32[0] =
+ htonl(ntohl(addr->addr32[0]) + 1);
+ } else
+ addr->addr32[1] =
+ htonl(ntohl(addr->addr32[1]) + 1);
+ } else
+ addr->addr32[2] =
+ htonl(ntohl(addr->addr32[2]) + 1);
+ } else
+ addr->addr32[3] =
+ htonl(ntohl(addr->addr32[3]) + 1);
+
+ break;
+ }
+}
#endif /* INET6 */
int
-pf_get_sport(sa_family_t af, u_int8_t proto,
- struct pf_addr *daddr, struct pf_addr *raddr,
- u_int16_t dport, u_int16_t *port, u_int16_t low, u_int16_t high)
+pf_map_addr(u_int8_t af, struct pf_pool *rpool, struct pf_addr *saddr,
+ struct pf_addr *naddr, struct pf_addr *init_addr)
+{
+ MD5_CTX context;
+ unsigned char hash[16];
+ struct pf_pooladdr *cur = rpool->cur;
+ struct pf_addr *raddr = &rpool->cur->addr.addr;
+ struct pf_addr *rmask = &rpool->cur->addr.mask;
+
+ if (cur->addr.addr_dyn != NULL && cur->addr.addr_dyn->undefined)
+ return (1);
+
+
+ switch (rpool->opts & PF_POOL_TYPEMASK) {
+ case PF_POOL_NONE:
+ PF_ACPY(naddr, raddr, af);
+ break;
+ case PF_POOL_BITMASK:
+ PF_POOLMASK(naddr, raddr, rmask, saddr, af);
+ break;
+ case PF_POOL_RANDOM:
+ if (init_addr != NULL && PF_AZERO(init_addr, af)) {
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ rpool->counter.addr32[0] = arc4random();
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ if (rmask->addr32[3] != 0xffffffff)
+ rpool->counter.addr32[3] = arc4random();
+ else
+ break;
+ if (rmask->addr32[2] != 0xffffffff)
+ rpool->counter.addr32[2] = arc4random();
+ else
+ break;
+ if (rmask->addr32[1] != 0xffffffff)
+ rpool->counter.addr32[1] = arc4random();
+ else
+ break;
+ if (rmask->addr32[0] != 0xffffffff)
+ rpool->counter.addr32[0] = arc4random();
+ break;
+ }
+#endif /* INET6 */
+ PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
+ PF_ACPY(init_addr, naddr, af);
+
+ } else {
+ PF_AINC(&rpool->counter, af);
+ PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
+ }
+ break;
+ case PF_POOL_SRCHASH:
+ case PF_POOL_SRCKEYHASH:
+ bzero(&context, sizeof(context));
+ MD5Init(&context);
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ MD5Update(&context, (unsigned char *)&saddr->v4,
+ sizeof(saddr->v4));
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ MD5Update(&context, (unsigned char *)&saddr->v6,
+ sizeof(saddr->v6));
+ break;
+#endif /* INET6 */
+ }
+ if ((rpool->opts & PF_POOL_TYPEMASK) ==
+ PF_POOL_SRCKEYHASH)
+ MD5Update(&context, (unsigned char *)&rpool->key,
+ sizeof(rpool->key));
+ MD5Final(hash, &context);
+ PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)hash, af);
+ break;
+ case PF_POOL_ROUNDROBIN:
+ if (pf_match_addr(0, &cur->addr.addr, &cur->addr.mask,
+ &rpool->counter, af)) {
+ PF_ACPY(naddr, &rpool->counter, af);
+ PF_AINC(&rpool->counter, af);
+ } else {
+ if ((rpool->cur =
+ TAILQ_NEXT(rpool->cur, entries)) == NULL)
+ rpool->cur = TAILQ_FIRST(&rpool->list);
+ PF_ACPY(naddr, &cur->addr.addr, af);
+ PF_ACPY(&rpool->counter, &cur->addr.addr, af);
+ PF_AINC(&rpool->counter, af);
+ }
+ break;
+ }
+
+ if (pf_status.debug >= PF_DEBUG_MISC) {
+ printf("pf_map_addr: selected address:");
+ pf_print_host(naddr, 0, af);
+ printf("\n");
+ }
+
+ return (0);
+}
+
+int
+pf_get_sport(sa_family_t af, u_int8_t proto, struct pf_pool *rpool,
+ struct pf_addr *saddr, u_int16_t sport, 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_tree_node key;
+ struct pf_addr init_addr;
int step;
u_int16_t cut;
- if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP))
- return (EINVAL);
- if (low == 0 && high == 0) {
- NTOHS(*port);
- return (0);
- }
- if (low == high) {
- *port = low;
- return (0);
- }
-
- key.af = af;
- key.proto = proto;
- PF_ACPY(&key.addr[0], daddr, key.af);
- PF_ACPY(&key.addr[1], raddr, key.af);
- key.port[0] = dport;
-
- /* port search; start random, step; similar 2 portloop in in_pcbbind */
- if (low == high) {
- key.port[1] = htons(low);
- if (pf_find_state(&tree_ext_gwy, &key) == NULL) {
- *port = low;
- return (0);
- }
+ bzero(&init_addr, sizeof(init_addr));
+ if (pf_map_addr(af, rpool, saddr, naddr, &init_addr))
return (1);
- } else if (low < high) {
- step = 1;
- cut = arc4random() % (1 + high - low) + low;
- } else {
- step = -1;
- cut = arc4random() % (1 + low - high) + high;
- }
- *port = cut - step;
do {
- *port += step;
- key.port[1] = htons(*port);
- if (pf_find_state(&tree_ext_gwy, &key) == NULL)
- return (0);
- } while (*port != low && *port != high);
- step = -step;
- *port = cut;
- do {
- *port += step;
- key.port[1] = htons(*port);
- if (pf_find_state(&tree_ext_gwy, &key) == NULL)
- return (0);
- } while (*port != low && *port != high);
+ key.af = af;
+ key.proto = proto;
+ PF_ACPY(&key.addr[0], daddr, key.af);
+ PF_ACPY(&key.addr[1], naddr, key.af);
+ key.port[0] = dport;
+
+ /*
+ * port search; start random, step;
+ * similar 2 portloop in in_pcbbind
+ */
+ if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
+ key.port[1] = 0;
+ if (pf_find_state(&tree_ext_gwy, &key) == NULL)
+ return (0);
+ } else if (rpool->opts & PF_POOL_STATICPORT) {
+ key.port[1] = sport;
+ if (pf_find_state(&tree_ext_gwy, &key) == NULL) {
+ *nport = ntohs(sport);
+ return (0);
+ }
+ } else if (low == 0 && high == 0) {
+ key.port[1] = *nport;
+ if (pf_find_state(&tree_ext_gwy, &key) == NULL) {
+ NTOHS(*nport);
+ return (0);
+ }
+ } else if (low == high) {
+ key.port[1] = htons(low);
+ if (pf_find_state(&tree_ext_gwy, &key) == NULL) {
+ *nport = low;
+ return (0);
+ }
+ } else {
+ if (low < high) {
+ step = 1;
+ cut = arc4random() % (1 + high - low) + low;
+ } else {
+ step = -1;
+ cut = arc4random() % (1 + low - high) + high;
+ }
+
+ *nport = cut - step;
+ do {
+ *nport += step;
+ key.port[1] = htons(*nport);
+ if (pf_find_state(&tree_ext_gwy, &key) == NULL)
+ return (0);
+ } while (*nport != low && *nport != high);
+
+ step = -step;
+ *nport = cut;
+ do {
+ *nport += step;
+ key.port[1] = htons(*nport);
+ if (pf_find_state(&tree_ext_gwy, &key) == NULL)
+ return (0);
+ } while (*nport != low && *nport != high);
+ }
+
+ switch (rpool->opts & PF_POOL_TYPEMASK) {
+ case PF_POOL_RANDOM:
+ case PF_POOL_ROUNDROBIN:
+ if (pf_map_addr(af, rpool, saddr, naddr, &init_addr))
+ return (1);
+ break;
+ case PF_POOL_NONE:
+ case PF_POOL_SRCHASH:
+ case PF_POOL_SRCKEYHASH:
+ case PF_POOL_BITMASK:
+ default:
+ return (1);
+ break;
+ }
+ } while (! PF_AEQ(&init_addr, naddr, af) );
return (1); /* none available */
}
struct pf_nat *
pf_get_nat(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
- u_int16_t sport, struct pf_addr *daddr, u_int16_t dport, sa_family_t af)
+ u_int16_t sport, struct pf_addr *daddr, u_int16_t dport,
+ struct pf_addr *naddr, u_int16_t *nport, sa_family_t af)
{
struct pf_nat *n, *nm = NULL;
@@ -1319,7 +1500,7 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
(!n->af || n->af == af) &&
(n->src.addr.addr_dyn == NULL ||
!n->src.addr.addr_dyn->undefined) &&
- PF_MATCHA(n->src.not, &n->src.addr.addr, &n->src.mask,
+ PF_MATCHA(n->src.not, &n->src.addr.addr, &n->src.addr.mask,
saddr, af) &&
(!n->src.port_op ||
(proto != IPPROTO_TCP && proto != IPPROTO_UDP) ||
@@ -1327,7 +1508,7 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
n->src.port[1], sport)) &&
(n->dst.addr.addr_dyn == NULL ||
!n->dst.addr.addr_dyn->undefined) &&
- PF_MATCHA(n->dst.not, &n->dst.addr.addr, &n->dst.mask,
+ PF_MATCHA(n->dst.not, &n->dst.addr.addr, &n->dst.addr.mask,
daddr, af) &&
(!n->dst.port_op ||
(proto != IPPROTO_TCP && proto != IPPROTO_UDP) ||
@@ -1337,9 +1518,23 @@ pf_get_nat(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
else
n = TAILQ_NEXT(n, entries);
}
- if (nm && (nm->no || (nm->raddr.addr_dyn != NULL &&
- nm->raddr.addr_dyn->undefined)))
- return (NULL);
+ if (nm) {
+ if (nm->no)
+ return (NULL);
+ else {
+ if (pf_get_sport(af, proto,
+ &nm->rpool, saddr, sport, daddr,
+ dport, naddr, nport, nm->proxy_port[0],
+ nm->proxy_port[1])) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ ("pf: NAT proxy port allocation "
+ "(%u-%u) failed\n",
+ nm->proxy_port[0],
+ nm->proxy_port[1]));
+ }
+ }
+ }
+
return (nm);
}
@@ -1357,24 +1552,27 @@ pf_get_binat(int direction, struct ifnet *ifp, u_int8_t proto,
(!b->af || b->af == af) &&
(b->saddr.addr_dyn == NULL ||
!b->saddr.addr_dyn->undefined) &&
- PF_MATCHA(0, &b->saddr.addr, &b->smask, saddr, af) &&
+ PF_MATCHA(0, &b->saddr.addr, &b->saddr.mask, saddr, af) &&
(b->daddr.addr_dyn == NULL ||
!b->daddr.addr_dyn->undefined) &&
- PF_MATCHA(b->dnot, &b->daddr.addr, &b->dmask, daddr, af))
+ PF_MATCHA(b->dnot, &b->daddr.addr, &b->daddr.mask,
+ daddr, af))
bm = b;
else if (direction == PF_IN && b->ifp == ifp &&
(!b->proto || b->proto == proto) &&
(!b->af || b->af == af) &&
(b->raddr.addr_dyn == NULL ||
!b->raddr.addr_dyn->undefined) &&
- PF_MATCHA(0, &b->raddr.addr, &b->rmask, saddr, af) &&
+ PF_MATCHA(0, &b->raddr.addr, &b->raddr.mask, saddr, af) &&
(b->daddr.addr_dyn == NULL ||
!b->daddr.addr_dyn->undefined) &&
- PF_MATCHA(b->dnot, &b->daddr.addr, &b->dmask, daddr, af))
+ PF_MATCHA(b->dnot, &b->daddr.addr, &b->daddr.mask,
+ daddr, af))
bm = b;
else
b = TAILQ_NEXT(b, entries);
}
+
if (bm) {
if (bm->no)
return (NULL);
@@ -1385,7 +1583,7 @@ pf_get_binat(int direction, struct ifnet *ifp, u_int8_t proto,
return (NULL);
else
PF_POOLMASK(naddr, &bm->raddr.addr,
- &bm->rmask, saddr, af);
+ &bm->raddr.mask, saddr, af);
break;
case PF_IN:
if (bm->saddr.addr_dyn != NULL &&
@@ -1393,17 +1591,18 @@ pf_get_binat(int direction, struct ifnet *ifp, u_int8_t proto,
return (NULL);
else
PF_POOLMASK(naddr, &bm->saddr.addr,
- &bm->smask, saddr, af);
+ &bm->saddr.mask, saddr, af);
break;
}
}
-
+
return (bm);
}
struct pf_rdr *
pf_get_rdr(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
- struct pf_addr *daddr, u_int16_t dport, sa_family_t af)
+ struct pf_addr *daddr, u_int16_t dport, struct pf_addr *naddr,
+ sa_family_t af)
{
struct pf_rdr *r, *rm = NULL;
@@ -1415,10 +1614,12 @@ pf_get_rdr(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
(!r->af || r->af == af) &&
(r->saddr.addr_dyn == NULL ||
!r->saddr.addr_dyn->undefined) &&
- PF_MATCHA(r->snot, &r->saddr.addr, &r->smask, saddr, af) &&
+ PF_MATCHA(r->snot, &r->saddr.addr, &r->saddr.mask,
+ saddr, af) &&
(r->daddr.addr_dyn == NULL ||
!r->daddr.addr_dyn->undefined) &&
- PF_MATCHA(r->dnot, &r->daddr.addr, &r->dmask, daddr, af) &&
+ PF_MATCHA(r->dnot, &r->daddr.addr, &r->daddr.mask,
+ daddr, af) &&
((!r->dport2 && (!r->dport || dport == r->dport)) ||
(r->dport2 && (ntohs(dport) >= ntohs(r->dport)) &&
ntohs(dport) <= ntohs(r->dport2))))
@@ -1426,9 +1627,12 @@ pf_get_rdr(struct ifnet *ifp, u_int8_t proto, struct pf_addr *saddr,
else
r = TAILQ_NEXT(r, entries);
}
- if (rm && (rm->no || (rm->raddr.addr_dyn != NULL &&
- rm->raddr.addr_dyn->undefined)))
- return (NULL);
+ if (rm) {
+ if (rm->no || pf_map_addr(rm->af, &rm->rpool,
+ &rm->saddr.addr, naddr, NULL))
+ return (NULL);
+ }
+
return (rm);
}
@@ -1511,44 +1715,34 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp,
gid_t gid;
struct pf_rule *r;
u_short reason;
- int rewrite = 0, error;
+ int rewrite = 0;
*rm = NULL;
if (direction == PF_OUT) {
+ bport = nport = th->th_sport;
/* check outgoing packet for BINAT */
if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_TCP,
saddr, daddr, &naddr, af)) != NULL) {
PF_ACPY(&baddr, saddr, af);
- bport = th->th_sport;
pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
&th->th_sum, &naddr, th->th_sport, 0, af);
rewrite++;
}
/* check outgoing packet for NAT */
else if ((nat = pf_get_nat(ifp, IPPROTO_TCP,
- saddr, th->th_sport, daddr, th->th_dport, af)) != NULL) {
- bport = nport = th->th_sport;
- error = pf_get_sport(af, IPPROTO_TCP, daddr,
- &nat->raddr.addr, th->th_dport, &nport,
- nat->proxy_port[0], nat->proxy_port[1]);
- if (error) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: NAT proxy port allocation "
- "(tcp %u-%u) failed\n",
- nat->proxy_port[0], nat->proxy_port[1]));
- return (PF_DROP);
- }
+ saddr, th->th_sport, daddr, th->th_dport,
+ &naddr, &nport, af)) != NULL) {
PF_ACPY(&baddr, saddr, af);
pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
- &th->th_sum, &nat->raddr.addr, htons(nport),
+ &th->th_sum, &naddr, htons(nport),
0, af);
rewrite++;
}
} else {
/* check incoming packet for RDR */
if ((rdr = pf_get_rdr(ifp, IPPROTO_TCP, saddr, daddr,
- th->th_dport, af)) != NULL) {
+ th->th_dport, &naddr, af)) != NULL) {
bport = th->th_dport;
if (rdr->opts & PF_RPORT_RANGE)
nport = pf_map_port_range(rdr, th->th_dport);
@@ -1558,7 +1752,7 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp,
nport = bport;
PF_ACPY(&baddr, daddr, af);
pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
- &th->th_sum, &rdr->raddr.addr, nport, 0, af);
+ &th->th_sum, &naddr, nport, 0, af);
rewrite++;
}
/* check incoming packet for BINAT */
@@ -1589,8 +1783,8 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->src.noroute && pf_routable(saddr, af))
r = TAILQ_NEXT(r, entries);
else if (!r->src.noroute &&
- !PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not,
- &r->src.addr.addr, &r->src.mask, saddr, af))
+ !PF_AZERO(&r->src.addr.mask, af) && !PF_MATCHA(r->src.not,
+ &r->src.addr.addr, &r->src.addr.mask, saddr, af))
r = r->skip[PF_SKIP_SRC_ADDR];
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], th->th_sport))
@@ -1598,8 +1792,8 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->dst.noroute && pf_routable(daddr, af))
r = TAILQ_NEXT(r, entries);
else if (!r->dst.noroute &&
- !PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not,
- &r->dst.addr.addr, &r->dst.mask, daddr, af))
+ !PF_AZERO(&r->dst.addr.mask, af) && !PF_MATCHA(r->dst.not,
+ &r->dst.addr.addr, &r->dst.addr.mask, daddr, af))
r = r->skip[PF_SKIP_DST_ADDR];
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], th->th_dport))
@@ -1778,44 +1972,34 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp,
gid_t gid;
struct pf_rule *r;
u_short reason;
- int rewrite = 0, error;
+ int rewrite = 0;
*rm = NULL;
if (direction == PF_OUT) {
+ bport = nport = uh->uh_sport;
/* check outgoing packet for BINAT */
if ((binat = pf_get_binat(PF_OUT, ifp, IPPROTO_UDP,
saddr, daddr, &naddr, af)) != NULL) {
PF_ACPY(&baddr, saddr, af);
- bport = uh->uh_sport;
pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
&uh->uh_sum, &naddr, uh->uh_sport, 1, af);
rewrite++;
}
/* check outgoing packet for NAT */
else if ((nat = pf_get_nat(ifp, IPPROTO_UDP,
- saddr, uh->uh_sport, daddr, uh->uh_dport, af)) != NULL) {
- bport = nport = uh->uh_sport;
- error = pf_get_sport(af, IPPROTO_UDP, daddr,
- &nat->raddr.addr, uh->uh_dport, &nport,
- nat->proxy_port[0], nat->proxy_port[1]);
- if (error) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("pf: NAT proxy port allocation "
- "(udp %u-%u) failed\n",
- nat->proxy_port[0], nat->proxy_port[1]));
- return (PF_DROP);
- }
+ saddr, uh->uh_sport, daddr, uh->uh_dport,
+ &naddr, &nport, af)) != NULL) {
PF_ACPY(&baddr, saddr, af);
pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
- &uh->uh_sum, &nat->raddr.addr, htons(nport),
+ &uh->uh_sum, &naddr, htons(nport),
1, af);
rewrite++;
}
} else {
/* check incoming packet for RDR */
if ((rdr = pf_get_rdr(ifp, IPPROTO_UDP, saddr, daddr,
- uh->uh_dport, af)) != NULL) {
+ uh->uh_dport, &naddr, af)) != NULL) {
bport = uh->uh_dport;
if (rdr->opts & PF_RPORT_RANGE)
nport = pf_map_port_range(rdr, uh->uh_dport);
@@ -1826,7 +2010,7 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp,
PF_ACPY(&baddr, daddr, af);
pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
- &uh->uh_sum, &rdr->raddr.addr, nport, 1, af);
+ &uh->uh_sum, &naddr, nport, 1, af);
rewrite++;
}
/* check incoming packet for BINAT */
@@ -1857,8 +2041,8 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->src.noroute && pf_routable(saddr, af))
r = TAILQ_NEXT(r, entries);
else if (!r->src.noroute &&
- !PF_AZERO(&r->src.mask, af) &&
- !PF_MATCHA(r->src.not, &r->src.addr.addr, &r->src.mask,
+ !PF_AZERO(&r->src.addr.mask, af) &&
+ !PF_MATCHA(r->src.not, &r->src.addr.addr, &r->src.addr.mask,
saddr, af))
r = r->skip[PF_SKIP_SRC_ADDR];
else if (r->src.port_op && !pf_match_port(r->src.port_op,
@@ -1867,8 +2051,8 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->dst.noroute && pf_routable(daddr, af))
r = TAILQ_NEXT(r, entries);
else if (!r->dst.noroute &&
- !PF_AZERO(&r->dst.mask, af) &&
- !PF_MATCHA(r->dst.not, &r->dst.addr.addr, &r->dst.mask,
+ !PF_AZERO(&r->dst.addr.mask, af) &&
+ !PF_MATCHA(r->dst.not, &r->dst.addr.addr, &r->dst.addr.mask,
daddr, af))
r = r->skip[PF_SKIP_DST_ADDR];
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
@@ -2079,19 +2263,19 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
}
/* check outgoing packet for NAT */
else if ((nat = pf_get_nat(ifp, pd->proto,
- saddr, 0, daddr, 0, af)) != NULL) {
+ saddr, 0, daddr, 0, &naddr, NULL, af)) != NULL) {
PF_ACPY(&baddr, saddr, af);
switch (af) {
#ifdef INET
case AF_INET:
pf_change_a(&saddr->v4.s_addr,
- pd->ip_sum, nat->raddr.addr.v4.s_addr, 0);
+ pd->ip_sum, naddr.v4.s_addr, 0);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
- &nat->raddr.addr, 0);
+ &naddr, 0);
rewrite++;
break;
#endif /* INET6 */
@@ -2100,19 +2284,19 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
} else {
/* check incoming packet for RDR */
if ((rdr = pf_get_rdr(ifp, pd->proto,
- saddr, daddr, 0, af)) != NULL) {
+ saddr, daddr, 0, &naddr, af)) != NULL) {
PF_ACPY(&baddr, daddr, af);
switch (af) {
#ifdef INET
case AF_INET:
pf_change_a(&daddr->v4.s_addr,
- pd->ip_sum, rdr->raddr.addr.v4.s_addr, 0);
+ pd->ip_sum, naddr.v4.s_addr, 0);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
- &rdr->raddr.addr, 0);
+ &naddr, 0);
rewrite++;
break;
#endif /* INET6 */
@@ -2157,14 +2341,14 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->src.noroute && pf_routable(saddr, af))
r = TAILQ_NEXT(r, entries);
else if (!r->src.noroute &&
- !PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not,
- &r->src.addr.addr, &r->src.mask, saddr, af))
+ !PF_AZERO(&r->src.addr.mask, af) && !PF_MATCHA(r->src.not,
+ &r->src.addr.addr, &r->src.addr.mask, saddr, af))
r = r->skip[PF_SKIP_SRC_ADDR];
else if (r->dst.noroute && pf_routable(daddr, af))
r = TAILQ_NEXT(r, entries);
else if (!r->dst.noroute &&
- !PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not,
- &r->dst.addr.addr, &r->dst.mask, daddr, af))
+ !PF_AZERO(&r->dst.addr.mask, af) && !PF_MATCHA(r->dst.not,
+ &r->dst.addr.addr, &r->dst.addr.mask, daddr, af))
r = r->skip[PF_SKIP_DST_ADDR];
else if (r->type && r->type != icmptype + 1)
r = TAILQ_NEXT(r, entries);
@@ -2307,18 +2491,18 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
}
/* check outgoing packet for NAT */
else if ((nat = pf_get_nat(ifp, pd->proto,
- saddr, 0, daddr, 0, af)) != NULL) {
+ saddr, 0, daddr, 0, &naddr, NULL, af)) != NULL) {
PF_ACPY(&baddr, saddr, af);
switch (af) {
#ifdef INET
case AF_INET:
pf_change_a(&saddr->v4.s_addr,
- pd->ip_sum, nat->raddr.addr.v4.s_addr, 0);
+ pd->ip_sum, naddr.v4.s_addr, 0);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- PF_ACPY(saddr, &nat->raddr.addr, af);
+ PF_ACPY(saddr, &naddr, af);
break;
#endif /* INET6 */
}
@@ -2326,18 +2510,18 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
} else {
/* check incoming packet for RDR */
if ((rdr = pf_get_rdr(ifp, pd->proto,
- saddr, daddr, 0, af)) != NULL) {
+ saddr, daddr, 0, &naddr, af)) != NULL) {
PF_ACPY(&baddr, daddr, af);
switch (af) {
#ifdef INET
case AF_INET:
pf_change_a(&daddr->v4.s_addr,
- pd->ip_sum, rdr->raddr.addr.v4.s_addr, 0);
+ pd->ip_sum, naddr.v4.s_addr, 0);
break;
#endif /* INET */
#ifdef INET6
case AF_INET6:
- PF_ACPY(daddr, &rdr->raddr.addr, af);
+ PF_ACPY(daddr, &naddr, af);
break;
#endif /* INET6 */
}
@@ -2379,14 +2563,14 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->src.noroute && pf_routable(pd->src, af))
r = TAILQ_NEXT(r, entries);
else if (!r->src.noroute &&
- !PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not,
- &r->src.addr.addr, &r->src.mask, pd->src, af))
+ !PF_AZERO(&r->src.addr.mask, af) && !PF_MATCHA(r->src.not,
+ &r->src.addr.addr, &r->src.addr.mask, pd->src, af))
r = r->skip[PF_SKIP_SRC_ADDR];
else if (r->dst.noroute && pf_routable(pd->dst, af))
r = TAILQ_NEXT(r, entries);
else if (!r->src.noroute &&
- !PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not,
- &r->dst.addr.addr, &r->dst.mask, pd->dst, af))
+ !PF_AZERO(&r->dst.addr.mask, af) && !PF_MATCHA(r->dst.not,
+ &r->dst.addr.addr, &r->dst.addr.mask, pd->dst, af))
r = r->skip[PF_SKIP_DST_ADDR];
else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
@@ -2504,14 +2688,14 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct ifnet *ifp,
else if (r->src.noroute && pf_routable(pd->src, af))
r = TAILQ_NEXT(r, entries);
else if (!r->src.noroute &&
- !PF_AZERO(&r->src.mask, af) && !PF_MATCHA(r->src.not,
- &r->src.addr.addr, &r->src.mask, pd->src, af))
+ !PF_AZERO(&r->src.addr.mask, af) && !PF_MATCHA(r->src.not,
+ &r->src.addr.addr, &r->src.addr.mask, pd->src, af))
r = r->skip[PF_SKIP_SRC_ADDR];
else if (r->dst.noroute && pf_routable(pd->dst, af))
r = TAILQ_NEXT(r, entries);
else if (!r->src.noroute &&
- !PF_AZERO(&r->dst.mask, af) && !PF_MATCHA(r->dst.not,
- &r->dst.addr.addr, &r->dst.mask, pd->dst, af))
+ !PF_AZERO(&r->dst.addr.mask, af) && !PF_MATCHA(r->dst.not,
+ &r->dst.addr.addr, &r->dst.addr.mask, pd->dst, af))
r = r->skip[PF_SKIP_DST_ADDR];
else if (r->tos && !(r->tos & pd->tos))
r = TAILQ_NEXT(r, entries);
@@ -3533,15 +3717,17 @@ pf_routable(addr, af)
#ifdef INET
void
-pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp)
+pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
+ struct pf_state *s)
{
struct mbuf *m0, *m1;
struct route iproute;
struct route *ro;
struct sockaddr_in *dst;
struct ip *ip;
- struct ifnet *ifp = r->rt_ifp;
+ struct ifnet *ifp;
struct m_tag *mtag;
+ struct pf_addr naddr;
int hlen;
int error = 0;
@@ -3578,8 +3764,30 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp)
if (ro->ro_rt->rt_flags & RTF_GATEWAY)
dst = satosin(ro->ro_rt->rt_gateway);
} else {
- if (!PF_AZERO(&r->rt_addr, AF_INET))
- dst->sin_addr.s_addr = r->rt_addr.v4.s_addr;
+ if (!TAILQ_EMPTY(&r->rt_pool.list)) {
+ if (s == NULL) {
+ pf_map_addr(AF_INET, &r->rt_pool,
+ (struct pf_addr *)&ip->ip_src,
+ &naddr, NULL);
+ if (!PF_AZERO(&naddr, AF_INET))
+ dst->sin_addr.s_addr = naddr.v4.s_addr;
+ ifp = r->rt_pool.cur->ifp;
+ } else {
+ if (s->rt_ifp == NULL) {
+ s->rt_ifp = r->rt_pool.cur->ifp;
+ pf_map_addr(AF_INET, &r->rt_pool,
+ (struct pf_addr *)&ip->ip_src,
+ &naddr, NULL);
+ if (!PF_AZERO(&naddr, AF_INET))
+ PF_ACPY(&s->rt_addr, &naddr,
+ AF_INET);
+ }
+ if (!PF_AZERO(&s->rt_addr, AF_INET))
+ dst->sin_addr.s_addr =
+ s->rt_addr.v4.s_addr;
+ ifp = s->rt_ifp;
+ }
+ }
}
if (ifp == NULL)
@@ -3670,7 +3878,8 @@ bad:
#ifdef INET6
void
-pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp)
+pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
+ struct pf_state *s)
{
struct mbuf *m0;
struct m_tag *mtag;
@@ -3678,7 +3887,8 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp)
struct route_in6 *ro;
struct sockaddr_in6 *dst;
struct ip6_hdr *ip6;
- struct ifnet *ifp = r->rt_ifp;
+ struct ifnet *ifp;
+ struct pf_addr naddr;
int error = 0;
if (m == NULL)
@@ -3703,8 +3913,33 @@ pf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp)
dst->sin6_len = sizeof(*dst);
dst->sin6_addr = ip6->ip6_dst;
- if (!PF_AZERO(&r->rt_addr, AF_INET6))
- dst->sin6_addr = r->rt_addr.v6;
+ if (!TAILQ_EMPTY(&r->rt_pool.list)) {
+ if (s == NULL) {
+ pf_map_addr(AF_INET6, &r->rt_pool,
+ (struct pf_addr *)&ip6->ip6_src, &naddr, NULL);
+ if (!PF_AZERO(&naddr, AF_INET6)) {
+ PF_ACPY(
+ (struct pf_addr *)&dst->sin6_addr,
+ &naddr, AF_INET6);
+ }
+ ifp = r->rt_pool.cur->ifp;
+ } else {
+ if (s->rt_ifp == NULL) {
+ s->rt_ifp = r->rt_pool.cur->ifp;
+ pf_map_addr(AF_INET6, &r->rt_pool,
+ (struct pf_addr *)&ip6->ip6_src,
+ &naddr, NULL);
+ if (!PF_AZERO(&naddr, AF_INET6))
+ PF_ACPY(&s->rt_addr, &naddr, AF_INET6);
+ }
+ if (!PF_AZERO(&s->rt_addr, AF_INET6)) {
+ PF_ACPY(
+ (struct pf_addr *)&dst->sin6_addr,
+ &naddr, AF_INET6);
+ }
+ ifp = s->rt_ifp;
+ }
+ }
/* Cheat. */
if (r->rt == PF_FASTROUTE) {
@@ -3938,8 +4173,8 @@ done:
}
/* pf_route can free the mbuf causing *m0 to become NULL */
- if (r && r->rt)
- pf_route(m0, r, dir, ifp);
+ if (r && r->rt)
+ pf_route(m0, r, dir, ifp, s);
return (action);
}
@@ -4112,7 +4347,7 @@ done:
/* pf_route6 can free the mbuf causing *m0 to become NULL */
if (r && r->rt)
- pf_route6(m0, r, dir, ifp);
+ pf_route6(m0, r, dir, ifp, s);
return (action);
}
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c
index 68580e5c02b..633f06f062d 100644
--- a/sys/net/pf_ioctl.c
+++ b/sys/net/pf_ioctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_ioctl.c,v 1.16 2002/11/12 15:38:36 mpech Exp $ */
+/* $OpenBSD: pf_ioctl.c,v 1.17 2002/11/23 05:16:58 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -70,13 +70,21 @@
void pfattach(int);
int pfopen(dev_t, int, int, struct proc *);
int pfclose(dev_t, int, int, struct proc *);
+struct pf_pool *pf_get_pool(u_int32_t, u_int8_t, u_int8_t,
+ u_int8_t, u_int8_t);
+int pf_add_addr(struct pf_pool *, struct pf_pooladdr *,
+ u_int8_t);
int pf_compare_addr_wrap(struct pf_addr_wrap *,
- struct pf_addr_wrap *, sa_family_t af);
+ struct pf_addr_wrap *, sa_family_t);
+int pf_compare_pool(struct pf_pool *, struct pf_pool *,
+ sa_family_t);
int pf_compare_rules(struct pf_rule *,
struct pf_rule *);
int pf_compare_nats(struct pf_nat *, struct pf_nat *);
int pf_compare_binats(struct pf_binat *,
struct pf_binat *);
+int pf_compare_pooladdrs(struct pf_pooladdr *,
+ struct pf_pooladdr *, sa_family_t);
int pf_compare_rdrs(struct pf_rdr *, struct pf_rdr *);
int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
@@ -103,6 +111,8 @@ pfattach(int num)
NULL);
pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl",
NULL);
+ pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0,
+ "pfpooladdrpl", NULL);
TAILQ_INIT(&pf_rules[0]);
TAILQ_INIT(&pf_rules[1]);
@@ -114,6 +124,7 @@ pfattach(int num)
TAILQ_INIT(&pf_rdrs[1]);
TAILQ_INIT(&pf_altqs[0]);
TAILQ_INIT(&pf_altqs[1]);
+ TAILQ_INIT(&pf_pabuf);
pf_rules_active = &pf_rules[0];
pf_rules_inactive = &pf_rules[1];
pf_nats_active = &pf_nats[0];
@@ -148,6 +159,132 @@ pfclose(dev_t dev, int flags, int fmt, struct proc *p)
return (0);
}
+struct pf_pool *
+pf_get_pool(u_int32_t ticket, u_int8_t r_id, u_int8_t r_num, u_int8_t active,
+ u_int8_t check_ticket)
+{
+ struct pf_rule *rule;
+ struct pf_nat *nat;
+ struct pf_rdr *rdr;
+ u_int32_t nr = 0;
+
+ switch (r_id & PF_POOL_IDMASK) {
+ case PF_POOL_RULE_RT:
+ if (active) {
+ if (check_ticket && ticket != ticket_rules_active)
+ break;
+ if (r_id & PF_POOL_LAST)
+ rule = TAILQ_LAST(pf_rules_active,
+ pf_rulequeue);
+ else
+ rule = TAILQ_FIRST(pf_rules_active);
+ } else {
+ if (check_ticket && ticket != ticket_rules_inactive)
+ break;
+ if (r_id & PF_POOL_LAST)
+ rule = TAILQ_LAST(pf_rules_inactive,
+ pf_rulequeue);
+ else
+ rule = TAILQ_FIRST(pf_rules_inactive);
+ }
+ if (!(r_id & PF_POOL_LAST)) {
+ while ((rule != NULL) && (rule->nr < r_num))
+ rule = TAILQ_NEXT(rule, entries);
+ }
+ if (rule == NULL)
+ break;
+ return(&rule->rt_pool);
+ break;
+
+ case PF_POOL_NAT_R:
+ if (active) {
+ if (check_ticket && ticket != ticket_nats_active)
+ break;
+ if (r_id & PF_POOL_LAST)
+ nat = TAILQ_LAST(pf_nats_active, pf_natqueue);
+ else
+ nat = TAILQ_FIRST(pf_nats_active);
+ } else {
+ if (check_ticket && ticket != ticket_nats_inactive)
+ break;
+ if (r_id & PF_POOL_LAST)
+ nat = TAILQ_LAST(pf_nats_inactive, pf_natqueue);
+ else
+ nat = TAILQ_FIRST(pf_nats_inactive);
+ }
+ if (!(r_id & PF_POOL_LAST)) {
+ while ((nat != NULL) && (nr < r_num)) {
+ nat = TAILQ_NEXT(nat, entries);
+ nr++;
+ }
+ }
+ if (nat == NULL)
+ break;
+ return(&nat->rpool);
+ break;
+
+ case PF_POOL_RDR_R:
+ if (active) {
+ if (check_ticket && ticket != ticket_rdrs_active)
+ break;
+ if (r_id & PF_POOL_LAST)
+ rdr = TAILQ_LAST(pf_rdrs_active, pf_rdrqueue);
+ else
+ rdr = TAILQ_FIRST(pf_rdrs_active);
+ } else {
+ if (check_ticket && ticket != ticket_rdrs_inactive)
+ break;
+ if (r_id & PF_POOL_LAST)
+ rdr = TAILQ_LAST(pf_rdrs_inactive, pf_rdrqueue);
+ else
+ rdr = TAILQ_FIRST(pf_rdrs_inactive);
+ }
+ if (!(r_id & PF_POOL_LAST)) {
+ while ((rdr != NULL) && (nr < r_num)) {
+ rdr = TAILQ_NEXT(rdr, entries);
+ nr++;
+ }
+ }
+ if (rdr == NULL)
+ break;
+ return(&rdr->rpool);
+ break;
+ }
+ return (NULL);
+}
+
+int
+pf_add_addr(struct pf_pool *pool, struct pf_pooladdr *addr, u_int8_t af)
+{
+ struct pf_pooladdr *pa;
+
+ pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
+ if (pa == NULL) {
+ return (ENOMEM);
+ }
+ bcopy(addr, pa, sizeof(struct pf_pooladdr));
+ if (pa->ifname[0]) {
+ pa->ifp = ifunit((char *)&pa->ifname);
+ if (pa->ifp == NULL) {
+ pool_put(&pf_pooladdr_pl, pa);
+ return (EINVAL);
+ }
+ } else
+ pa->ifp = NULL;
+ if (pf_dynaddr_setup(&pa->addr, af)) {
+ pf_dynaddr_remove(&pa->addr);
+ pool_put(&pf_pooladdr_pl, pa);
+ return (EBUSY);
+ }
+ if (TAILQ_EMPTY(&pool->list)) {
+ pool->cur = pa;
+ PF_ACPY(&pool->counter, &pa->addr.addr, af);
+ }
+ TAILQ_INSERT_TAIL(&pool->list, pa, entries);
+
+ return (0);
+}
+
int
pf_compare_addr_wrap(struct pf_addr_wrap *a, struct pf_addr_wrap *b,
sa_family_t af)
@@ -161,6 +298,32 @@ pf_compare_addr_wrap(struct pf_addr_wrap *a, struct pf_addr_wrap *b,
if (PF_ANEQ(&a->addr, &b->addr, af))
return (1);
}
+ if (PF_ANEQ(&a->mask, &b->mask, af))
+ return (1);
+ return (0);
+}
+
+int
+pf_compare_pool(struct pf_pool *a, struct pf_pool *b, sa_family_t af)
+{
+ struct pf_pooladdr *pa_a, *pa_b;
+
+ if (a->key.key32[0] != b->key.key32[0] ||
+ a->key.key32[0] != b->key.key32[0] ||
+ a->key.key32[0] != b->key.key32[0] ||
+ a->key.key32[0] != b->key.key32[0] ||
+ a->opts != b->opts)
+ return(1);
+ pa_a = TAILQ_FIRST(&a->list);
+ pa_b = TAILQ_FIRST(&b->list);
+ while (pa_a != NULL && pa_b != NULL) {
+ if (pf_compare_addr_wrap(&pa_a->addr, &pa_b->addr, af))
+ return (1);
+ if (strcmp(pa_a->ifname, pa_b->ifname))
+ return (1);
+ pa_a = TAILQ_NEXT(pa_a, entries);
+ pa_b = TAILQ_NEXT(pa_b, entries);
+ }
return (0);
}
@@ -188,20 +351,20 @@ pf_compare_rules(struct pf_rule *a, struct pf_rule *b)
return (1);
if (pf_compare_addr_wrap(&a->src.addr, &b->src.addr, a->af))
return (1);
- if (PF_ANEQ(&a->src.mask, &b->src.mask, a->af) ||
- a->src.port[0] != b->src.port[0] ||
+ if (a->src.port[0] != b->src.port[0] ||
a->src.port[1] != b->src.port[1] ||
a->src.not != b->src.not ||
a->src.port_op != b->src.port_op)
return (1);
if (pf_compare_addr_wrap(&a->dst.addr, &b->dst.addr, a->af))
return (1);
- if (PF_ANEQ(&a->dst.mask, &b->dst.mask, a->af) ||
- a->dst.port[0] != b->dst.port[0] ||
+ if (a->dst.port[0] != b->dst.port[0] ||
a->dst.port[1] != b->dst.port[1] ||
a->dst.not != b->dst.not ||
a->dst.port_op != b->dst.port_op)
return (1);
+ if (pf_compare_pool(&a->rt_pool, &b->rt_pool, a->af))
+ return (1);
if (strcmp(a->ifname, b->ifname) ||
strcmp(a->label, b->label))
return (1);
@@ -218,21 +381,19 @@ pf_compare_nats(struct pf_nat *a, struct pf_nat *b)
return (1);
if (pf_compare_addr_wrap(&a->src.addr, &b->src.addr, a->af))
return (1);
- if (PF_ANEQ(&a->src.mask, &b->src.mask, a->af) ||
- a->src.port[0] != b->src.port[0] ||
+ if (a->src.port[0] != b->src.port[0] ||
a->src.port[1] != b->src.port[1] ||
a->src.not != b->src.not ||
a->src.port_op != b->src.port_op)
return (1);
if (pf_compare_addr_wrap(&a->dst.addr, &b->dst.addr, a->af))
return (1);
- if (PF_ANEQ(&a->dst.mask, &b->dst.mask, a->af) ||
- a->dst.port[0] != b->dst.port[0] ||
+ if (a->dst.port[0] != b->dst.port[0] ||
a->dst.port[1] != b->dst.port[1] ||
a->dst.not != b->dst.not ||
a->dst.port_op != b->dst.port_op)
return (1);
- if (pf_compare_addr_wrap(&a->raddr, &b->raddr, a->af))
+ if (pf_compare_pool(&a->rpool, &b->rpool, a->af))
return (1);
if (strcmp(a->ifname, b->ifname))
return (1);
@@ -249,13 +410,11 @@ pf_compare_binats(struct pf_binat *a, struct pf_binat *b)
return (1);
if (pf_compare_addr_wrap(&a->saddr, &b->saddr, a->af))
return (1);
- if (PF_ANEQ(&a->smask, &b->smask, a->af))
+ if (PF_ANEQ(&a->saddr.mask, &b->saddr.mask, a->af))
return (1);
if (pf_compare_addr_wrap(&a->daddr, &b->daddr, a->af))
return (1);
- if (PF_ANEQ(&a->dmask, &b->dmask, a->af))
- return (1);
- if (pf_compare_addr_wrap(&a->raddr, &b->raddr, a->af))
+ if (PF_ANEQ(&a->daddr.mask, &b->daddr.mask, a->af))
return (1);
if (strcmp(a->ifname, b->ifname))
return (1);
@@ -278,13 +437,20 @@ pf_compare_rdrs(struct pf_rdr *a, struct pf_rdr *b)
return (1);
if (pf_compare_addr_wrap(&a->saddr, &b->saddr, a->af))
return (1);
- if (PF_ANEQ(&a->smask, &b->smask, a->af))
- return (1);
if (pf_compare_addr_wrap(&a->daddr, &b->daddr, a->af))
return (1);
- if (PF_ANEQ(&a->dmask, &b->dmask, a->af))
+ if (pf_compare_pool(&a->rpool, &b->rpool, a->af))
return (1);
- if (pf_compare_addr_wrap(&a->raddr, &b->raddr, a->af))
+ if (strcmp(a->ifname, b->ifname))
+ return (1);
+ return (0);
+}
+
+int
+pf_compare_pooladdrs(struct pf_pooladdr *a, struct pf_pooladdr *b,
+ sa_family_t af)
+{
+ if (pf_compare_addr_wrap(&a->addr, &b->addr, af))
return (1);
if (strcmp(a->ifname, b->ifname))
return (1);
@@ -295,6 +461,8 @@ int
pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
{
int error = 0;
+ struct pf_pooladdr *pa = NULL;
+ struct pf_pool *pool = NULL;
int s;
/* XXX keep in sync with switch() below */
@@ -308,6 +476,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETBINAT:
case DIOCGETRDRS:
case DIOCGETRDR:
+ case DIOCGETADDRS:
+ case DIOCGETADDR:
case DIOCGETSTATE:
case DIOCSETSTATUSIF:
case DIOCGETSTATUS:
@@ -334,6 +504,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
case DIOCGETNAT:
case DIOCGETRDRS:
case DIOCGETRDR:
+ case DIOCGETADDRS:
+ case DIOCGETADDR:
case DIOCGETSTATE:
case DIOCGETSTATUS:
case DIOCGETSTATES:
@@ -384,6 +556,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(pf_rules_inactive, rule, entries);
pf_dynaddr_remove(&rule->src.addr);
pf_dynaddr_remove(&rule->dst.addr);
+ while ((pa = TAILQ_FIRST(&rule->rt_pool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&rule->rt_pool.list, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
pool_put(&pf_rule_pl, rule);
}
*ticket = ++ticket_rules_inactive;
@@ -394,16 +571,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
struct pfioc_rule *pr = (struct pfioc_rule *)addr;
struct pf_rule *rule, *tail;
- if (pr->ticket != ticket_rules_inactive) {
- error = EBUSY;
- break;
- }
rule = pool_get(&pf_rule_pl, PR_NOWAIT);
if (rule == NULL) {
error = ENOMEM;
break;
}
bcopy(&pr->rule, rule, sizeof(struct pf_rule));
+ TAILQ_INIT(&rule->rt_pool.list);
#ifndef INET
if (rule->af == AF_INET) {
pool_put(&pf_rule_pl, rule);
@@ -432,15 +606,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
} else
rule->ifp = NULL;
- if (rule->rt_ifname[0]) {
- rule->rt_ifp = ifunit(rule->rt_ifname);
- if (rule->rt_ifp == NULL) {
- pool_put(&pf_rule_pl, rule);
- error = EINVAL;
- break;
- }
- } else
- rule->rt_ifp = NULL;
+
if (pf_dynaddr_setup(&rule->src.addr, rule->af))
error = EINVAL;
if (pf_dynaddr_setup(&rule->dst.addr, rule->af))
@@ -451,6 +617,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pool_put(&pf_rule_pl, rule);
break;
}
+ while ((pa = TAILQ_FIRST(&pf_pabuf)) != NULL) {
+ TAILQ_REMOVE(&pf_pabuf, pa, entries);
+ TAILQ_INSERT_TAIL(&rule->rt_pool.list, pa, entries);
+ }
+ rule->rt_pool.cur = TAILQ_FIRST(&rule->rt_pool.list);
rule->evaluations = rule->packets = rule->bytes = 0;
TAILQ_INSERT_TAIL(pf_rules_inactive, rule, entries);
break;
@@ -486,6 +657,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(old_rules, rule, entries);
pf_dynaddr_remove(&rule->src.addr);
pf_dynaddr_remove(&rule->dst.addr);
+ while ((pa = TAILQ_FIRST(&rule->rt_pool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&rule->rt_pool.list, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
pool_put(&pf_rule_pl, rule);
}
break;
@@ -548,6 +724,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pcr->newrule, newrule, sizeof(struct pf_rule));
+ TAILQ_INIT(&newrule->rt_pool.list);
#ifndef INET
if (newrule->af == AF_INET) {
pool_put(&pf_rule_pl, newrule);
@@ -571,15 +748,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
} else
newrule->ifp = NULL;
- if (newrule->rt_ifname[0]) {
- newrule->rt_ifp = ifunit(newrule->rt_ifname);
- if (newrule->rt_ifp == NULL) {
- pool_put(&pf_rule_pl, newrule);
- error = EINVAL;
- break;
- }
- } else
- newrule->rt_ifp = NULL;
+
if (pf_dynaddr_setup(&newrule->src.addr, newrule->af))
error = EINVAL;
if (pf_dynaddr_setup(&newrule->dst.addr, newrule->af))
@@ -590,6 +759,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
pool_put(&pf_rule_pl, newrule);
break;
}
+ while ((pa = TAILQ_FIRST(&pf_pabuf)) != NULL) {
+ TAILQ_REMOVE(&pf_pabuf, pa, entries);
+ TAILQ_INSERT_TAIL(&newrule->rt_pool.list,
+ pa, entries);
+ }
newrule->evaluations = newrule->packets = 0;
newrule->bytes = 0;
}
@@ -621,6 +795,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(pf_rules_active, oldrule, entries);
pf_dynaddr_remove(&oldrule->src.addr);
pf_dynaddr_remove(&oldrule->dst.addr);
+ while ((pa =
+ TAILQ_FIRST(&oldrule->rt_pool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&oldrule->rt_pool.list,
+ pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
pool_put(&pf_rule_pl, oldrule);
} else {
if (oldrule == NULL)
@@ -651,7 +832,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
while ((nat = TAILQ_FIRST(pf_nats_inactive)) != NULL) {
pf_dynaddr_remove(&nat->src.addr);
pf_dynaddr_remove(&nat->dst.addr);
- pf_dynaddr_remove(&nat->raddr);
+ while ((pa = TAILQ_FIRST(&nat->rpool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&nat->rpool.list,
+ pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
TAILQ_REMOVE(pf_nats_inactive, nat, entries);
pool_put(&pf_nat_pl, nat);
}
@@ -673,6 +859,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pn->nat, nat, sizeof(struct pf_nat));
+ TAILQ_INIT(&nat->rpool.list);
#ifndef INET
if (nat->af == AF_INET) {
pool_put(&pf_nat_pl, nat);
@@ -696,19 +883,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
} else
nat->ifp = NULL;
+
if (pf_dynaddr_setup(&nat->src.addr, nat->af))
error = EINVAL;
if (pf_dynaddr_setup(&nat->dst.addr, nat->af))
error = EINVAL;
- if (pf_dynaddr_setup(&nat->raddr, nat->af))
- error = EINVAL;
if (error) {
pf_dynaddr_remove(&nat->src.addr);
pf_dynaddr_remove(&nat->dst.addr);
- pf_dynaddr_remove(&nat->raddr);
pool_put(&pf_nat_pl, nat);
break;
}
+ while ((pa = TAILQ_FIRST(&pf_pabuf)) != NULL) {
+ TAILQ_REMOVE(&pf_pabuf, pa, entries);
+ TAILQ_INSERT_TAIL(&nat->rpool.list, pa, entries);
+ }
+ nat->rpool.cur = TAILQ_FIRST(&nat->rpool.list);
TAILQ_INSERT_TAIL(pf_nats_inactive, nat, entries);
break;
}
@@ -735,7 +925,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
while ((nat = TAILQ_FIRST(old_nats)) != NULL) {
pf_dynaddr_remove(&nat->src.addr);
pf_dynaddr_remove(&nat->dst.addr);
- pf_dynaddr_remove(&nat->raddr);
+ while ((pa = TAILQ_FIRST(&nat->rpool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&nat->rpool.list, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
TAILQ_REMOVE(old_nats, nat, entries);
pool_put(&pf_nat_pl, nat);
}
@@ -779,7 +973,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
bcopy(nat, &pn->nat, sizeof(struct pf_nat));
pf_dynaddr_copyout(&pn->nat.src.addr);
pf_dynaddr_copyout(&pn->nat.dst.addr);
- pf_dynaddr_copyout(&pn->nat.raddr);
splx(s);
break;
}
@@ -801,6 +994,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pcn->newnat, newnat, sizeof(struct pf_nat));
+ TAILQ_INIT(&newnat->rpool.list);
#ifndef INET
if (newnat->af == AF_INET) {
pool_put(&pf_nat_pl, newnat);
@@ -824,19 +1018,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
} else
newnat->ifp = NULL;
+
if (pf_dynaddr_setup(&newnat->src.addr, newnat->af))
error = EINVAL;
if (pf_dynaddr_setup(&newnat->dst.addr, newnat->af))
error = EINVAL;
- if (pf_dynaddr_setup(&newnat->raddr, newnat->af))
- error = EINVAL;
if (error) {
pf_dynaddr_remove(&newnat->src.addr);
pf_dynaddr_remove(&newnat->dst.addr);
- pf_dynaddr_remove(&newnat->raddr);
pool_put(&pf_nat_pl, newnat);
break;
}
+ while ((pa = TAILQ_FIRST(&pf_pabuf)) != NULL) {
+ TAILQ_REMOVE(&pf_pabuf, pa, entries);
+ TAILQ_INSERT_TAIL(&newnat->rpool.list,
+ pa, entries);
+ }
}
s = splsoftnet();
@@ -860,7 +1057,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (pcn->action == PF_CHANGE_REMOVE) {
pf_dynaddr_remove(&oldnat->src.addr);
pf_dynaddr_remove(&oldnat->dst.addr);
- pf_dynaddr_remove(&oldnat->raddr);
+ while ((pa =
+ TAILQ_FIRST(&oldnat->rpool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&oldnat->rpool.list, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
TAILQ_REMOVE(pf_nats_active, oldnat, entries);
pool_put(&pf_nat_pl, oldnat);
} else {
@@ -936,8 +1138,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
error = EINVAL;
if (pf_dynaddr_setup(&binat->daddr, binat->af))
error = EINVAL;
- if (pf_dynaddr_setup(&binat->raddr, binat->af))
- error = EINVAL;
if (error) {
pf_dynaddr_remove(&binat->saddr);
pf_dynaddr_remove(&binat->daddr);
@@ -1126,7 +1326,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(pf_rdrs_inactive, rdr, entries);
pf_dynaddr_remove(&rdr->saddr);
pf_dynaddr_remove(&rdr->daddr);
- pf_dynaddr_remove(&rdr->raddr);
+ while ((pa = TAILQ_FIRST(&rdr->rpool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&rdr->rpool.list, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
pool_put(&pf_rdr_pl, rdr);
}
*ticket = ++ticket_rdrs_inactive;
@@ -1147,6 +1351,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pr->rdr, rdr, sizeof(struct pf_rdr));
+ TAILQ_INIT(&rdr->rpool.list);
#ifndef INET
if (rdr->af == AF_INET) {
pool_put(&pf_rdr_pl, rdr);
@@ -1170,19 +1375,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
} else
rdr->ifp = NULL;
+
if (pf_dynaddr_setup(&rdr->saddr, rdr->af))
error = EINVAL;
if (pf_dynaddr_setup(&rdr->daddr, rdr->af))
error = EINVAL;
- if (pf_dynaddr_setup(&rdr->raddr, rdr->af))
- error = EINVAL;
if (error) {
pf_dynaddr_remove(&rdr->saddr);
pf_dynaddr_remove(&rdr->daddr);
- pf_dynaddr_remove(&rdr->raddr);
pool_put(&pf_rdr_pl, rdr);
break;
}
+ while ((pa = TAILQ_FIRST(&pf_pabuf)) != NULL) {
+ TAILQ_REMOVE(&pf_pabuf, pa, entries);
+ TAILQ_INSERT_TAIL(&rdr->rpool.list, pa, entries);
+ }
+ rdr->rpool.cur = TAILQ_FIRST(&rdr->rpool.list);
TAILQ_INSERT_TAIL(pf_rdrs_inactive, rdr, entries);
break;
}
@@ -1210,7 +1418,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(old_rdrs, rdr, entries);
pf_dynaddr_remove(&rdr->saddr);
pf_dynaddr_remove(&rdr->daddr);
- pf_dynaddr_remove(&rdr->raddr);
+ while ((pa = TAILQ_FIRST(&rdr->rpool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&rdr->rpool.list, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
pool_put(&pf_rdr_pl, rdr);
}
break;
@@ -1253,7 +1465,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
bcopy(rdr, &pr->rdr, sizeof(struct pf_rdr));
pf_dynaddr_copyout(&pr->rdr.saddr);
pf_dynaddr_copyout(&pr->rdr.daddr);
- pf_dynaddr_copyout(&pr->rdr.raddr);
splx(s);
break;
}
@@ -1275,6 +1486,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
bcopy(&pcn->newrdr, newrdr, sizeof(struct pf_rdr));
+ TAILQ_INIT(&newrdr->rpool.list);
#ifndef INET
if (newrdr->af == AF_INET) {
pool_put(&pf_rdr_pl, newrdr);
@@ -1298,19 +1510,22 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
} else
newrdr->ifp = NULL;
+
if (pf_dynaddr_setup(&newrdr->saddr, newrdr->af))
error = EINVAL;
if (pf_dynaddr_setup(&newrdr->daddr, newrdr->af))
error = EINVAL;
- if (pf_dynaddr_setup(&newrdr->raddr, newrdr->af))
- error = EINVAL;
if (error) {
pf_dynaddr_remove(&newrdr->saddr);
pf_dynaddr_remove(&newrdr->daddr);
- pf_dynaddr_remove(&newrdr->raddr);
pool_put(&pf_rdr_pl, newrdr);
break;
}
+ while ((pa = TAILQ_FIRST(&pf_pabuf)) != NULL) {
+ TAILQ_REMOVE(&pf_pabuf, pa, entries);
+ TAILQ_INSERT_TAIL(&newrdr->rpool.list,
+ pa, entries);
+ }
}
s = splsoftnet();
@@ -1335,7 +1550,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
TAILQ_REMOVE(pf_rdrs_active, oldrdr, entries);
pf_dynaddr_remove(&oldrdr->saddr);
pf_dynaddr_remove(&oldrdr->daddr);
- pf_dynaddr_remove(&oldrdr->raddr);
+ while ((pa =
+ TAILQ_FIRST(&oldrdr->rpool.list)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&oldrdr->rpool.list, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
pool_put(&pf_rdr_pl, oldrdr);
} else {
if (oldrdr == NULL)
@@ -1379,9 +1599,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if ((!psk->psk_af || st->af == psk->psk_af) &&
(!psk->psk_proto || psk->psk_proto == st->proto) &&
PF_MATCHA(psk->psk_src.not, &psk->psk_src.addr.addr,
- &psk->psk_src.mask, &st->lan.addr, st->af) &&
+ &psk->psk_src.addr.mask, &st->lan.addr, st->af) &&
PF_MATCHA(psk->psk_dst.not, &psk->psk_dst.addr.addr,
- &psk->psk_dst.mask, &st->ext.addr, st->af) &&
+ &psk->psk_dst.addr.mask, &st->ext.addr, st->af) &&
(psk->psk_src.port_op == 0 ||
pf_match_port(psk->psk_src.port_op,
psk->psk_src.port[0], psk->psk_src.port[1],
@@ -1920,6 +2140,196 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
#endif /* ALTQ */
+ case DIOCBEGINADDRS: {
+ u_int32_t *ticket = (u_int32_t *)addr;
+
+ while ((pa = TAILQ_FIRST(&pf_pabuf)) != NULL) {
+ pf_dynaddr_remove(&pa->addr);
+ TAILQ_REMOVE(&pf_pabuf, pa, entries);
+ pool_put(&pf_pooladdr_pl, pa);
+ }
+ *ticket = ++ticket_pabuf;
+
+ break;
+ }
+
+ case DIOCADDADDR: {
+ struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
+
+#ifndef INET
+ if (pp->af == AF_INET) {
+ error = EAFNOSUPPORT;
+ break;
+ }
+#endif /* INET */
+#ifndef INET6
+ if (pp->af == AF_INET6) {
+ error = EAFNOSUPPORT;
+ break;
+ }
+#endif /* INET6 */
+ pa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
+ if (pa == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bcopy(&pp->addr, pa, sizeof(struct pf_pooladdr));
+ if (pa->ifname[0]) {
+ pa->ifp = ifunit(pa->ifname);
+ if (pa->ifp == NULL) {
+ pool_put(&pf_pooladdr_pl, pa);
+ error = EINVAL;
+ break;
+ }
+ }
+ if (pf_dynaddr_setup(&pa->addr, pp->af)) {
+ pf_dynaddr_remove(&pa->addr);
+ pool_put(&pf_pooladdr_pl, pa);
+ error = EINVAL;
+ break;
+ }
+ TAILQ_INSERT_TAIL(&pf_pabuf, pa, entries);
+
+ break;
+ }
+
+ case DIOCGETADDRS: {
+ struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
+
+ pp->nr = 0;
+ s = splsoftnet();
+ pool = pf_get_pool(pp->ticket, pp->r_id, pp->r_num, 1, 0);
+ if (pool == NULL) {
+ error = EBUSY;
+ splx(s);
+ break;
+ }
+ TAILQ_FOREACH(pa, &pool->list, entries)
+ pp->nr++;
+ splx(s);
+ break;
+ }
+
+ case DIOCGETADDR: {
+ struct pfioc_pooladdr *pp = (struct pfioc_pooladdr *)addr;
+ u_int32_t nr = 0;
+
+ s = splsoftnet();
+ pool = pf_get_pool(pp->ticket, pp->r_id, pp->r_num, 1, 1);
+ if (pool == NULL) {
+ error = EBUSY;
+ splx(s);
+ break;
+ }
+ pa = TAILQ_FIRST(&pool->list);
+ while ((pa != NULL) && (nr < pp->nr)) {
+ pa = TAILQ_NEXT(pa, entries);
+ nr++;
+ }
+ if (pa == NULL) {
+ error = EBUSY;
+ splx(s);
+ break;
+ }
+ bcopy(pa, &pp->addr, sizeof(struct pf_pooladdr));
+ pf_dynaddr_copyout(&pp->addr.addr);
+ splx(s);
+ break;
+ }
+
+ case DIOCCHANGEADDR: {
+ struct pfioc_changeaddr *pca = (struct pfioc_changeaddr *)addr;
+ struct pf_pooladdr *oldpa = NULL, *newpa = NULL;
+
+ if (pca->action < PF_CHANGE_ADD_HEAD ||
+ pca->action > PF_CHANGE_REMOVE) {
+ error = EINVAL;
+ break;
+ }
+
+ if (pca->action != PF_CHANGE_REMOVE) {
+ pool = pf_get_pool(0, pca->r_id, pca->r_num, 1, 0);
+ if (pool == NULL) {
+ error = EBUSY;
+ break;
+ }
+ newpa = pool_get(&pf_pooladdr_pl, PR_NOWAIT);
+ if (newpa == NULL) {
+ error = ENOMEM;
+ break;
+ }
+ bcopy(&pca->newaddr, newpa, sizeof(struct pf_pooladdr));
+#ifndef INET
+ if (pca->af == AF_INET) {
+ pool_put(&pf_pooladdr_pl, newpa);
+ error = EAFNOSUPPORT;
+ break;
+ }
+#endif /* INET */
+#ifndef INET6
+ if (pca->af == AF_INET6) {
+ pool_put(&pf_pooladdr_pl, newpa);
+ error = EAFNOSUPPORT;
+ break;
+ }
+#endif /* INET6 */
+ if (newpa->ifname[0]) {
+ newpa->ifp = ifunit(newpa->ifname);
+ if (newpa->ifp == NULL) {
+ pool_put(&pf_pooladdr_pl, newpa);
+ error = EINVAL;
+ break;
+ }
+ } else
+ newpa->ifp = NULL;
+ if (pf_dynaddr_setup(&newpa->addr, pca->af)) {
+ pf_dynaddr_remove(&newpa->addr);
+ pool_put(&pf_pooladdr_pl, newpa);
+ error = EINVAL;
+ break;
+ }
+ }
+
+ s = splsoftnet();
+
+ if (pca->action == PF_CHANGE_ADD_HEAD)
+ oldpa = TAILQ_FIRST(&pool->list);
+ else if (pca->action == PF_CHANGE_ADD_TAIL)
+ oldpa = TAILQ_LAST(&pool->list, pf_palist);
+ else {
+ oldpa = TAILQ_FIRST(&pool->list);
+ while ((oldpa != NULL) && pf_compare_pooladdrs(oldpa,
+ &pca->oldaddr, pca->af))
+ oldpa = TAILQ_NEXT(oldpa, entries);
+ if (oldpa == NULL) {
+ error = EINVAL;
+ splx(s);
+ break;
+ }
+ }
+
+ if (pca->action == PF_CHANGE_REMOVE) {
+ TAILQ_REMOVE(&pool->list, oldpa, entries);
+ pf_dynaddr_remove(&oldpa->addr);
+ pool_put(&pf_pooladdr_pl, oldpa);
+ } else {
+ if (oldpa == NULL)
+ TAILQ_INSERT_TAIL(&pool->list, newpa, entries);
+ else if (pca->action == PF_CHANGE_ADD_HEAD ||
+ pca->action == PF_CHANGE_ADD_BEFORE)
+ TAILQ_INSERT_BEFORE(oldpa, newpa, entries);
+ else
+ TAILQ_INSERT_AFTER(&pool->list, oldpa,
+ newpa, entries);
+ }
+
+ pool->cur = TAILQ_FIRST(&pool->list);
+ PF_ACPY(&pool->counter, &pool->cur->addr.addr, pca->af);
+
+ splx(s);
+ break;
+ }
+
default:
error = ENODEV;
break;
diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c
index 54bd300ade0..3c45dbd6cb8 100644
--- a/sys/net/pf_norm.c
+++ b/sys/net/pf_norm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf_norm.c,v 1.38 2002/10/29 19:51:04 mickey Exp $ */
+/* $OpenBSD: pf_norm.c,v 1.39 2002/11/23 05:16:58 mcbride Exp $ */
/*
* Copyright 2001 Niels Provos <provos@citi.umich.edu>
@@ -809,12 +809,12 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason)
r = r->skip[PF_SKIP_AF];
else if (r->proto && r->proto != h->ip_p)
r = r->skip[PF_SKIP_PROTO];
- else if (!PF_AZERO(&r->src.mask, AF_INET) &&
- !PF_MATCHA(r->src.not, &r->src.addr.addr, &r->src.mask,
+ else if (!PF_AZERO(&r->src.addr.mask, AF_INET) &&
+ !PF_MATCHA(r->src.not, &r->src.addr.addr, &r->src.addr.mask,
(struct pf_addr *)&h->ip_src.s_addr, AF_INET))
r = r->skip[PF_SKIP_SRC_ADDR];
- else if (!PF_AZERO(&r->dst.mask, AF_INET) &&
- !PF_MATCHA(r->dst.not, &r->dst.addr.addr, &r->dst.mask,
+ else if (!PF_AZERO(&r->dst.addr.mask, AF_INET) &&
+ !PF_MATCHA(r->dst.not, &r->dst.addr.addr, &r->dst.addr.mask,
(struct pf_addr *)&h->ip_dst.s_addr, AF_INET))
r = r->skip[PF_SKIP_DST_ADDR];
else
@@ -1012,8 +1012,8 @@ pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff,
r = r->skip[PF_SKIP_PROTO];
else if (r->src.noroute && pf_routable(pd->src, af))
r = TAILQ_NEXT(r, entries);
- else if (!r->src.noroute && !PF_AZERO(&r->src.mask, af) &&
- !PF_MATCHA(r->src.not, &r->src.addr.addr, &r->src.mask,
+ else if (!r->src.noroute && !PF_AZERO(&r->src.addr.mask, af) &&
+ !PF_MATCHA(r->src.not, &r->src.addr.addr, &r->src.addr.mask,
pd->src, af))
r = r->skip[PF_SKIP_SRC_ADDR];
else if (r->src.port_op && !pf_match_port(r->src.port_op,
@@ -1021,8 +1021,8 @@ pf_normalize_tcp(int dir, struct ifnet *ifp, struct mbuf *m, int ipoff,
r = r->skip[PF_SKIP_SRC_PORT];
else if (r->dst.noroute && pf_routable(pd->dst, af))
r = TAILQ_NEXT(r, entries);
- else if (!r->dst.noroute && !PF_AZERO(&r->dst.mask, af) &&
- !PF_MATCHA(r->dst.not, &r->dst.addr.addr, &r->dst.mask,
+ else if (!r->dst.noroute && !PF_AZERO(&r->dst.addr.mask, af) &&
+ !PF_MATCHA(r->dst.not, &r->dst.addr.addr, &r->dst.addr.mask,
pd->dst, af))
r = r->skip[PF_SKIP_DST_ADDR];
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 59e1ccb00bb..8c689c0e1bf 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.101 2002/11/02 16:56:50 mcbride Exp $ */
+/* $OpenBSD: pfvar.h,v 1.102 2002/11/23 05:16:58 mcbride Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -53,6 +53,13 @@ enum { PFTM_TCP_FIRST_PACKET=0, PFTM_TCP_OPENING=1, PFTM_TCP_ESTABLISHED=2,
PFTM_OTHER_MULTIPLE=13, PFTM_FRAG=14, PFTM_INTERVAL=15, PFTM_MAX=16 };
enum { PF_FASTROUTE=1, PF_ROUTETO=2, PF_DUPTO=3, PF_REPLYTO=4 };
enum { PF_LIMIT_STATES=0, PF_LIMIT_FRAGS=1, PF_LIMIT_MAX=2 };
+enum { PF_POOL_RULE_RT=0, PF_POOL_NAT_R=1, PF_POOL_RDR_R=2 };
+#define PF_POOL_IDMASK 0x0f
+#define PF_POOL_LAST 0x10
+enum { PF_POOL_NONE=0, PF_POOL_BITMASK=1, PF_POOL_RANDOM=2,
+ PF_POOL_SRCHASH=3, PF_POOL_SRCKEYHASH=4, PF_POOL_ROUNDROBIN=5 };
+#define PF_POOL_TYPEMASK 0x0f
+#define PF_POOL_STATICPORT 0x10
struct pf_addr {
union {
@@ -72,6 +79,7 @@ struct pf_addr {
struct pf_addr_wrap {
struct pf_addr addr;
+ struct pf_addr mask;
struct pf_addr_dyn *addr_dyn;
};
@@ -142,12 +150,16 @@ struct pf_addr_dyn {
#define PF_ACPY(a, b, f) \
pf_addrcpy(a, b, f)
+#define PF_AINC(a, f) \
+ pf_addr_inc(a, f)
+
#define PF_POOLMASK(a, b, c, d, f) \
pf_poolmask(a, b, c, d, f)
#else
/* Just IPv6 */
+
#ifdef PF_INET6_ONLY
#define PF_AEQ(a, b, c) \
@@ -174,6 +186,9 @@ struct pf_addr_dyn {
#define PF_ACPY(a, b, f) \
pf_addrcpy(a, b, f)
+#define PF_AINC(a, f) \
+ pf_addr_inc(a, f)
+
#define PF_POOLMASK(a, b, c, d, f) \
pf_poolmask(a, b, c, d, f)
@@ -197,11 +212,16 @@ struct pf_addr_dyn {
#define PF_ACPY(a, b, f) \
(a)->v4.s_addr = (b)->v4.s_addr
+#define PF_AINC(a, f) \
+ do { \
+ (a)->addr32[0] = htonl(ntohl((a)->addr32[0]) + 1); \
+ } while (0)
+
#define PF_POOLMASK(a, b, c, d, f) \
- do { \
- (a)->addr32[0] = ((b)->addr32[0] & (c)->addr32[0]) | \
- (((c)->addr32[0] ^ 0xffffffff ) & (d)->addr32[0]); \
- } while (0)
+ do { \
+ (a)->addr32[0] = ((b)->addr32[0] & (c)->addr32[0]) | \
+ (((c)->addr32[0] ^ 0xffffffff ) & (d)->addr32[0]); \
+ } while (0)
#endif /* PF_INET_ONLY */
#endif /* PF_INET6_ONLY */
@@ -219,13 +239,40 @@ struct pf_rule_gid {
struct pf_rule_addr {
struct pf_addr_wrap addr;
- struct pf_addr mask;
u_int16_t port[2];
u_int8_t not;
u_int8_t port_op;
u_int8_t noroute;
};
+struct pf_pooladdr {
+ struct pf_addr_wrap addr;
+ TAILQ_ENTRY(pf_pooladdr) entries;
+ char ifname[IFNAMSIZ];
+ struct ifnet *ifp;
+};
+
+TAILQ_HEAD(pf_palist, pf_pooladdr);
+
+struct pf_poolhashkey {
+ union {
+ u_int8_t key8[16];
+ u_int16_t key16[8];
+ u_int32_t key32[4];
+ } pfk; /* 128-bit hash key */
+#define key8 pfk.key8
+#define key16 pfk.key16
+#define key32 pfk.key32
+};
+
+struct pf_pool {
+ struct pf_palist list;
+ struct pf_pooladdr *cur;
+ struct pf_poolhashkey key;
+ struct pf_addr counter;
+ u_int8_t opts;
+};
+
struct pf_rule {
struct pf_rule_addr src;
struct pf_rule_addr dst;
@@ -243,23 +290,22 @@ struct pf_rule {
#define PF_RULE_LABEL_SIZE 64
char label[PF_RULE_LABEL_SIZE];
u_int32_t timeout[PFTM_MAX];
- struct pf_addr rt_addr;
#define PF_QNAME_SIZE 16
char ifname[IFNAMSIZ];
- char rt_ifname[IFNAMSIZ];
char qname[PF_QNAME_SIZE];
TAILQ_ENTRY(pf_rule) entries;
+ struct pf_pool rt_pool;
u_int64_t evaluations;
u_int64_t packets;
u_int64_t bytes;
struct ifnet *ifp;
- struct ifnet *rt_ifp;
u_int32_t states;
u_int32_t max_states;
u_int32_t qid;
+ u_int32_t rt_listid;
u_int16_t nr;
u_int16_t return_icmp;
@@ -327,6 +373,8 @@ struct pf_state {
struct pf_rule *ptr;
u_int16_t nr;
} rule;
+ struct pf_addr rt_addr;
+ struct ifnet *rt_ifp;
u_int32_t creation;
u_int32_t expire;
u_int32_t packets;
@@ -352,10 +400,12 @@ struct pf_tree_node {
struct pf_nat {
struct pf_rule_addr src;
struct pf_rule_addr dst;
- struct pf_addr_wrap raddr;
+ struct pf_pool rpool;
+ struct pf_pooladdr *rcur;
char ifname[IFNAMSIZ];
struct ifnet *ifp;
TAILQ_ENTRY(pf_nat) entries;
+ u_int32_t rlistid;
u_int16_t proxy_port[2];
sa_family_t af;
u_int8_t proto;
@@ -370,9 +420,6 @@ struct pf_binat {
struct pf_addr_wrap saddr;
struct pf_addr_wrap daddr;
struct pf_addr_wrap raddr;
- struct pf_addr smask;
- struct pf_addr dmask;
- struct pf_addr rmask;
sa_family_t af;
u_int8_t proto;
u_int8_t dnot;
@@ -385,9 +432,9 @@ struct pf_rdr {
TAILQ_ENTRY(pf_rdr) entries;
struct pf_addr_wrap saddr;
struct pf_addr_wrap daddr;
- struct pf_addr_wrap raddr;
- struct pf_addr smask;
- struct pf_addr dmask;
+ struct pf_pool rpool;
+ struct pf_pooladdr *rcur;
+ u_int32_t rlistid;
u_int16_t dport;
u_int16_t dport2;
u_int16_t rport;
@@ -566,6 +613,24 @@ struct pf_altq {
* ioctl parameter structures
*/
+struct pfioc_pooladdr {
+ u_int32_t ticket;
+ u_int32_t nr;
+ u_int32_t r_num;
+ u_int8_t r_id;
+ u_int8_t af;
+ struct pf_pooladdr addr;
+};
+
+struct pfioc_changeaddr {
+ u_int32_t action;
+ u_int32_t r_num;
+ u_int8_t r_id;
+ u_int8_t af;
+ struct pf_pooladdr newaddr;
+ struct pf_pooladdr oldaddr;
+};
+
struct pfioc_rule {
u_int32_t ticket;
u_int32_t nr;
@@ -573,9 +638,9 @@ struct pfioc_rule {
};
struct pfioc_changerule {
- u_int32_t action;
- struct pf_rule oldrule;
- struct pf_rule newrule;
+ u_int32_t action;
+ struct pf_rule oldrule;
+ struct pf_rule newrule;
};
struct pfioc_nat {
@@ -739,6 +804,11 @@ struct pfioc_qstats {
#define DIOCGETALTQ _IOWR('D', 48, struct pfioc_altq)
#define DIOCCHANGEALTQ _IOWR('D', 49, struct pfioc_altq)
#define DIOCGETQSTATS _IOWR('D', 50, struct pfioc_qstats)
+#define DIOCBEGINADDRS _IOWR('D', 51, u_int32_t)
+#define DIOCADDADDR _IOWR('D', 52, struct pfioc_pooladdr)
+#define DIOCGETADDRS _IOWR('D', 53, struct pfioc_pooladdr)
+#define DIOCGETADDR _IOWR('D', 54, struct pfioc_pooladdr)
+#define DIOCCHANGEADDR _IOWR('D', 55, struct pfioc_pooladdr)
#ifdef _KERNEL
@@ -753,8 +823,11 @@ TAILQ_HEAD(pf_binatqueue, pf_binat);
extern struct pf_binatqueue pf_binats[2];
TAILQ_HEAD(pf_rdrqueue, pf_rdr);
extern struct pf_rdrqueue pf_rdrs[2];
+TAILQ_HEAD(pf_poolqueue, pf_pool);
+extern struct pf_poolqueue pf_pools[2];
TAILQ_HEAD(pf_altqqueue, pf_altq);
extern struct pf_altqqueue pf_altqs[2];
+extern struct pf_palist pf_pabuf;
extern u_int32_t ticket_rules_active;
@@ -769,6 +842,7 @@ extern u_int32_t ticket_rdrs_inactive;
extern u_int32_t ticket_rules_inactive;
extern u_int32_t ticket_altqs_active;
extern u_int32_t ticket_altqs_inactive;
+extern u_int32_t ticket_pabuf;
extern struct pf_rulequeue *pf_rules_active;
extern struct pf_rulequeue *pf_rules_inactive;
extern struct pf_natqueue *pf_nats_active;
@@ -779,6 +853,8 @@ extern struct pf_rdrqueue *pf_rdrs_active;
extern struct pf_rdrqueue *pf_rdrs_inactive;
extern struct pf_altqqueue *pf_altqs_active;
extern struct pf_altqqueue *pf_altqs_inactive;
+extern struct pf_poolqueue *pf_pools_active;
+extern struct pf_poolqueue *pf_pools_inactive;
extern void pf_dynaddr_remove(struct pf_addr_wrap *);
extern int pf_dynaddr_setup(struct pf_addr_wrap *,
u_int8_t);
@@ -788,6 +864,7 @@ extern struct pool pf_tree_pl, pf_rule_pl, pf_nat_pl;
extern struct pool pf_rdr_pl, pf_state_pl, pf_binat_pl,
pf_addr_pl;
extern struct pool pf_altq_pl;
+extern struct pool pf_pooladdr_pl;
extern void pf_purge_timeout(void *);
extern int pftm_interval;
extern void pf_purge_expired_states(void);