diff options
author | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2002-11-23 05:16:59 +0000 |
---|---|---|
committer | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2002-11-23 05:16:59 +0000 |
commit | 1691df433770a29ad8547bf930bf7b9429c95b7c (patch) | |
tree | 24ac668979a5ffd2d01a44df047124d1fd917bf3 /sys/net | |
parent | 8fe184e0dc67bbb715ddc837a35dc2877a2eb0c5 (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.c | 545 | ||||
-rw-r--r-- | sys/net/pf_ioctl.c | 540 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 18 | ||||
-rw-r--r-- | sys/net/pfvar.h | 115 |
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); |