diff options
Diffstat (limited to 'sys/contrib/pf/net/pf_table.c')
-rw-r--r-- | sys/contrib/pf/net/pf_table.c | 200 |
1 files changed, 175 insertions, 25 deletions
diff --git a/sys/contrib/pf/net/pf_table.c b/sys/contrib/pf/net/pf_table.c index a79ed37..033616e 100644 --- a/sys/contrib/pf/net/pf_table.c +++ b/sys/contrib/pf/net/pf_table.c @@ -1,4 +1,5 @@ -/* $OpenBSD: pf_table.c,v 1.68 2006/05/02 10:08:45 dhartmei Exp $ */ +/* $FreeBSD$ */ +/* $OpenBSD: pf_table.c,v 1.62 2004/12/07 18:02:04 mcbride Exp $ */ /* * Copyright (c) 2002 Cedric Berger @@ -30,16 +31,27 @@ * */ +#ifdef __FreeBSD__ +#include "opt_inet.h" +#include "opt_inet6.h" +#endif + #include <sys/param.h> #include <sys/systm.h> #include <sys/socket.h> #include <sys/mbuf.h> #include <sys/kernel.h> +#ifdef __FreeBSD__ +#include <sys/malloc.h> +#endif #include <net/if.h> #include <net/route.h> #include <netinet/in.h> +#ifndef __FreeBSD__ #include <netinet/ip_ipsp.h> +#endif + #include <net/pfvar.h> #define ACCEPT_FLAGS(oklist) \ @@ -49,6 +61,43 @@ return (EINVAL); \ } while (0) +#ifdef __FreeBSD__ +static inline int +_copyin(const void *uaddr, void *kaddr, size_t len) +{ + int r; + + PF_UNLOCK(); + r = copyin(uaddr, kaddr, len); + PF_LOCK(); + + return (r); +} + +static inline int +_copyout(const void *uaddr, void *kaddr, size_t len) +{ + int r; + + PF_UNLOCK(); + r = copyout(uaddr, kaddr, len); + PF_LOCK(); + + return (r); +} + +#define COPYIN(from, to, size) \ + ((flags & PFR_FLAG_USERIOCTL) ? \ + _copyin((from), (to), (size)) : \ + (bcopy((from), (to), (size)), 0)) + +#define COPYOUT(from, to, size) \ + ((flags & PFR_FLAG_USERIOCTL) ? \ + _copyout((from), (to), (size)) : \ + (bcopy((from), (to), (size)), 0)) + +#else + #define COPYIN(from, to, size) \ ((flags & PFR_FLAG_USERIOCTL) ? \ copyin((from), (to), (size)) : \ @@ -59,6 +108,8 @@ copyout((from), (to), (size)) : \ (bcopy((from), (to), (size)), 0)) +#endif + #define FILLIN_SIN(sin, addr) \ do { \ (sin).sin_len = sizeof(sin); \ @@ -123,9 +174,15 @@ struct pfr_walktree { #define senderr(e) do { rv = (e); goto _bad; } while (0) +#ifdef __FreeBSD__ +uma_zone_t pfr_ktable_pl; +uma_zone_t pfr_kentry_pl; +uma_zone_t pfr_kentry_pl2; +#else struct pool pfr_ktable_pl; struct pool pfr_kentry_pl; struct pool pfr_kentry_pl2; +#endif struct sockaddr_in pfr_sin; struct sockaddr_in6 pfr_sin6; union sockaddr_union pfr_mask; @@ -188,12 +245,14 @@ int pfr_ktable_cnt; void pfr_initialize(void) { +#ifndef __FreeBSD__ pool_init(&pfr_ktable_pl, sizeof(struct pfr_ktable), 0, 0, 0, "pfrktable", &pool_allocator_oldnointr); pool_init(&pfr_kentry_pl, sizeof(struct pfr_kentry), 0, 0, 0, "pfrkentry", &pool_allocator_oldnointr); pool_init(&pfr_kentry_pl2, sizeof(struct pfr_kentry), 0, 0, 0, "pfrkentry2", NULL); +#endif pfr_sin.sin_len = sizeof(pfr_sin); pfr_sin.sin_family = AF_INET; @@ -221,6 +280,7 @@ pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) pfr_enqueue_addrs(kt, &workq, ndel, 0); if (!(flags & PFR_FLAG_DUMMY)) { + s = 0; if (flags & PFR_FLAG_ATOMIC) s = splsoftnet(); pfr_remove_kentries(kt, &workq); @@ -243,7 +303,7 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s, xadd = 0; + int i, rv, s = 0, xadd = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); @@ -287,9 +347,10 @@ pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, xadd++; } } - if (flags & PFR_FLAG_FEEDBACK) + if (flags & PFR_FLAG_FEEDBACK) { if (COPYOUT(&ad, addr+i, sizeof(ad))) senderr(EFAULT); + } } pfr_clean_node_mask(tmpkt, &workq); if (!(flags & PFR_FLAG_DUMMY)) { @@ -321,7 +382,7 @@ pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p; struct pfr_addr ad; - int i, rv, s, xdel = 0, log = 1; + int i, rv, s = 0, xdel = 0, log = 1; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) @@ -404,19 +465,17 @@ _bad: int pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, - int *size2, int *nadd, int *ndel, int *nchange, int flags, - u_int32_t ignore_pfrt_flags) + int *size2, int *nadd, int *ndel, int *nchange, int flags) { struct pfr_ktable *kt, *tmpkt; struct pfr_kentryworkq addq, delq, changeq; struct pfr_kentry *p, *q; struct pfr_addr ad; - int i, rv, s, xadd = 0, xdel = 0, xchange = 0; + int i, rv, s = 0, xadd = 0, xdel = 0, xchange = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); - if (pfr_validate_table(tbl, ignore_pfrt_flags, flags & - PFR_FLAG_USERIOCTL)) + if (pfr_validate_table(tbl, 0, flags & PFR_FLAG_USERIOCTL)) return (EINVAL); kt = pfr_lookup_table(tbl); if (kt == NULL || !(kt->pfrkt_flags & PFR_TFLAG_ACTIVE)) @@ -578,9 +637,18 @@ pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, w.pfrw_addr = addr; w.pfrw_free = kt->pfrkt_cnt; w.pfrw_flags = flags; +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif if (!rv) +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, + &w); +#else rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif if (rv) return (rv); @@ -600,7 +668,7 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, struct pfr_ktable *kt; struct pfr_walktree w; struct pfr_kentryworkq workq; - int rv, s; + int rv, s = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC); /* XXX PFR_FLAG_CLSTATS disabled */ @@ -621,9 +689,18 @@ pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, w.pfrw_flags = flags; if (flags & PFR_FLAG_ATOMIC) s = splsoftnet(); +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rv = rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif if (!rv) +#ifdef __FreeBSD__ + rv = kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, + &w); +#else rv = rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif if (!rv && (flags & PFR_FLAG_CLSTATS)) { pfr_enqueue_addrs(kt, &workq, NULL, 0); pfr_clstats_kentries(&workq, tzero, 0); @@ -650,7 +727,7 @@ pfr_clr_astats(struct pfr_table *tbl, struct pfr_addr *addr, int size, struct pfr_kentryworkq workq; struct pfr_kentry *p; struct pfr_addr ad; - int i, rv, s, xzero = 0; + int i, rv, s = 0, xzero = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_FEEDBACK); if (pfr_validate_table(tbl, 0, 0)) @@ -738,10 +815,20 @@ pfr_enqueue_addrs(struct pfr_ktable *kt, struct pfr_kentryworkq *workq, w.pfrw_op = sweep ? PFRW_SWEEP : PFRW_ENQUEUE; w.pfrw_workq = workq; if (kt->pfrkt_ip4 != NULL) +#ifdef __FreeBSD__ + if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, + &w)) +#else if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) +#endif printf("pfr_enqueue_addrs: IPv4 walktree failed.\n"); if (kt->pfrkt_ip6 != NULL) +#ifdef __FreeBSD__ + if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, + &w)) +#else if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) +#endif printf("pfr_enqueue_addrs: IPv6 walktree failed.\n"); if (naddr != NULL) *naddr = w.pfrw_cnt; @@ -754,9 +841,17 @@ pfr_mark_addrs(struct pfr_ktable *kt) bzero(&w, sizeof(w)); w.pfrw_op = PFRW_MARK; +#ifdef __FreeBSD__ + if (kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) +#else if (rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w)) +#endif printf("pfr_mark_addrs: IPv4 walktree failed.\n"); +#ifdef __FreeBSD__ + if (kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) +#else if (rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w)) +#endif printf("pfr_mark_addrs: IPv6 walktree failed.\n"); } @@ -765,7 +860,7 @@ struct pfr_kentry * pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) { union sockaddr_union sa, mask; - struct radix_node_head *head; + struct radix_node_head *head = NULL; /* make the compiler happy */ struct pfr_kentry *ke; int s; @@ -780,7 +875,13 @@ pfr_lookup_addr(struct pfr_ktable *kt, struct pfr_addr *ad, int exact) if (ADDR_NETWORK(ad)) { pfr_prepare_network(&mask, ad->pfra_af, ad->pfra_net); s = splsoftnet(); /* rn_lookup makes use of globals */ +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_LOCK(head); +#endif ke = (struct pfr_kentry *)rn_lookup(&sa, &mask, head); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_UNLOCK(head); +#endif splx(s); if (ke && KENTRY_RNF_ROOT(ke)) ke = NULL; @@ -968,7 +1069,7 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head; + struct radix_node_head *head = NULL; /* make the compiler happy */ int s; bzero(ke->pfrke_node, sizeof(ke->pfrke_node)); @@ -978,11 +1079,17 @@ pfr_route_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) head = kt->pfrkt_ip6; s = splsoftnet(); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_LOCK(head); +#endif if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); rn = rn_addroute(&ke->pfrke_sa, &mask, head, ke->pfrke_node); } else rn = rn_addroute(&ke->pfrke_sa, NULL, head, ke->pfrke_node); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_UNLOCK(head); +#endif splx(s); return (rn == NULL ? -1 : 0); @@ -993,7 +1100,7 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) { union sockaddr_union mask; struct radix_node *rn; - struct radix_node_head *head; + struct radix_node_head *head = NULL; /* make the compiler happy */ int s; if (ke->pfrke_af == AF_INET) @@ -1002,11 +1109,25 @@ pfr_unroute_kentry(struct pfr_ktable *kt, struct pfr_kentry *ke) head = kt->pfrkt_ip6; s = splsoftnet(); +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_LOCK(head); +#endif if (KENTRY_NETWORK(ke)) { pfr_prepare_network(&mask, ke->pfrke_af, ke->pfrke_net); +#ifdef __FreeBSD__ + rn = rn_delete(&ke->pfrke_sa, &mask, head); +#else rn = rn_delete(&ke->pfrke_sa, &mask, head, NULL); +#endif } else +#ifdef __FreeBSD__ + rn = rn_delete(&ke->pfrke_sa, NULL, head); +#else rn = rn_delete(&ke->pfrke_sa, NULL, head, NULL); +#endif +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + RADIX_NODE_HEAD_UNLOCK(head); +#endif splx(s); if (rn == NULL) { @@ -1115,7 +1236,7 @@ pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p; - int s, xdel = 0; + int s = 0, xdel = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ALLRSETS); if (pfr_fix_anchor(filter->pfrt_anchor)) @@ -1152,7 +1273,7 @@ pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) { struct pfr_ktableworkq addq, changeq; struct pfr_ktable *p, *q, *r, key; - int i, rv, s, xadd = 0; + int i, rv, s = 0, xadd = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); @@ -1232,7 +1353,7 @@ pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p, *q, key; - int i, s, xdel = 0; + int i, s = 0, xdel = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); SLIST_INIT(&workq); @@ -1306,7 +1427,7 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, { struct pfr_ktable *p; struct pfr_ktableworkq workq; - int s, n, nn; + int s = 0, n, nn; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC|PFR_FLAG_ALLRSETS); @@ -1331,7 +1452,8 @@ pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, if (!(flags & PFR_FLAG_ATOMIC)) s = splsoftnet(); if (COPYOUT(&p->pfrkt_ts, tbl++, sizeof(*tbl))) { - splx(s); + if (!(flags & PFR_FLAG_ATOMIC)) + splx(s); return (EFAULT); } if (!(flags & PFR_FLAG_ATOMIC)) @@ -1356,7 +1478,7 @@ pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) { struct pfr_ktableworkq workq; struct pfr_ktable *p, key; - int i, s, xzero = 0; + int i, s = 0, xzero = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY+PFR_FLAG_ADDRSTOO); @@ -1390,7 +1512,7 @@ pfr_set_tflags(struct pfr_table *tbl, int size, int setflag, int clrflag, { struct pfr_ktableworkq workq; struct pfr_ktable *p, *q, key; - int i, s, xchange = 0, xdel = 0; + int i, s = 0, xchange = 0, xdel = 0; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); if ((setflag & ~PFR_TFLAG_USRMASK) || @@ -1609,7 +1731,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd, struct pfr_ktable *p, *q; struct pfr_ktableworkq workq; struct pf_ruleset *rs; - int s, xadd = 0, xchange = 0; + int s = 0, xadd = 0, xchange = 0; long tzero = time_second; ACCEPT_FLAGS(PFR_FLAG_ATOMIC+PFR_FLAG_DUMMY); @@ -1927,10 +2049,21 @@ pfr_destroy_ktable(struct pfr_ktable *kt, int flushaddr) pfr_clean_node_mask(kt, &addrq); pfr_destroy_kentries(&addrq); } +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500100) + if (kt->pfrkt_ip4 != NULL) { + RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip4); + free((caddr_t)kt->pfrkt_ip4, M_RTABLE); + } + if (kt->pfrkt_ip6 != NULL) { + RADIX_NODE_HEAD_DESTROY(kt->pfrkt_ip6); + free((caddr_t)kt->pfrkt_ip6, M_RTABLE); + } +#else if (kt->pfrkt_ip4 != NULL) free((caddr_t)kt->pfrkt_ip4, M_RTABLE); if (kt->pfrkt_ip6 != NULL) free((caddr_t)kt->pfrkt_ip6, M_RTABLE); +#endif if (kt->pfrkt_shadow != NULL) pfr_destroy_ktable(kt->pfrkt_shadow, flushaddr); if (kt->pfrkt_rs != NULL) { @@ -2049,7 +2182,7 @@ pfr_attach_table(struct pf_ruleset *rs, char *name) bzero(&tbl, sizeof(tbl)); strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)); if (ac != NULL) - strlcpy(tbl.pfrt_anchor, ac->path, sizeof(tbl.pfrt_anchor)); + strlcpy(tbl.pfrt_anchor, ac->name, sizeof(tbl.pfrt_anchor)); kt = pfr_lookup_table(&tbl); if (kt == NULL) { kt = pfr_create_ktable(&tbl, time_second, 1); @@ -2085,12 +2218,13 @@ pfr_detach_table(struct pfr_ktable *kt) pfr_setflags_ktable(kt, kt->pfrkt_flags&~PFR_TFLAG_REFERENCED); } + int pfr_pool_get(struct pfr_ktable *kt, int *pidx, struct pf_addr *counter, struct pf_addr **raddr, struct pf_addr **rmask, sa_family_t af) { - struct pfr_kentry *ke, *ke2; - struct pf_addr *addr; + struct pfr_kentry *ke, *ke2 = NULL; + struct pf_addr *addr = NULL; union sockaddr_union mask; int idx = -1, use_counter = 0; @@ -2180,12 +2314,20 @@ pfr_kentry_byidx(struct pfr_ktable *kt, int idx, int af) switch (af) { #ifdef INET case AF_INET: +#ifdef __FreeBSD__ + kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif return (w.pfrw_kentry); #endif /* INET */ #ifdef INET6 case AF_INET6: +#ifdef __FreeBSD__ + kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif return (w.pfrw_kentry); #endif /* INET6 */ default: @@ -2207,8 +2349,16 @@ pfr_dynaddr_update(struct pfr_ktable *kt, struct pfi_dynaddr *dyn) dyn->pfid_acnt4 = 0; dyn->pfid_acnt6 = 0; if (!dyn->pfid_af || dyn->pfid_af == AF_INET) +#ifdef __FreeBSD__ + kt->pfrkt_ip4->rnh_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip4, pfr_walktree, &w); +#endif if (!dyn->pfid_af || dyn->pfid_af == AF_INET6) +#ifdef __FreeBSD__ + kt->pfrkt_ip6->rnh_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#else rn_walktree(kt->pfrkt_ip6, pfr_walktree, &w); +#endif splx(s); } |