diff options
Diffstat (limited to 'net/if_pfsync.c')
-rw-r--r-- | net/if_pfsync.c | 310 |
1 files changed, 189 insertions, 121 deletions
diff --git a/net/if_pfsync.c b/net/if_pfsync.c index 2d3d3e4443a5..68d3ac40877b 100644 --- a/net/if_pfsync.c +++ b/net/if_pfsync.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pfsync.c,v 1.89 2008/01/12 17:08:33 mpf Exp $ */ +/* $OpenBSD: if_pfsync.c,v 1.98 2008/06/29 08:42:15 mcbride Exp $ */ /* * Copyright (c) 2002 Michael Shalayeff @@ -89,7 +89,6 @@ int pfsync_clone_destroy(struct ifnet *); void pfsync_setmtu(struct pfsync_softc *, int); int pfsync_alloc_scrub_memory(struct pfsync_state_peer *, struct pf_state_peer *); -int pfsync_insert_net_state(struct pfsync_state *, u_int8_t); void pfsync_update_net_tdb(struct pfsync_tdb *); int pfsyncoutput(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *); @@ -224,117 +223,218 @@ pfsync_alloc_scrub_memory(struct pfsync_state_peer *s, struct pf_state_peer *d) { if (s->scrub.scrub_flag && d->scrub == NULL) { - d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT); + d->scrub = pool_get(&pf_state_scrub_pl, PR_NOWAIT | PR_ZERO); if (d->scrub == NULL) return (ENOMEM); - bzero(d->scrub, sizeof(*d->scrub)); } return (0); } +void +pfsync_state_export(struct pfsync_state *sp, struct pf_state *st) +{ + bzero(sp, sizeof(struct pfsync_state)); + + /* copy from state key */ + sp->key[PF_SK_WIRE].addr[0] = st->key[PF_SK_WIRE]->addr[0]; + sp->key[PF_SK_WIRE].addr[1] = st->key[PF_SK_WIRE]->addr[1]; + sp->key[PF_SK_WIRE].port[0] = st->key[PF_SK_WIRE]->port[0]; + sp->key[PF_SK_WIRE].port[1] = st->key[PF_SK_WIRE]->port[1]; + sp->key[PF_SK_STACK].addr[0] = st->key[PF_SK_STACK]->addr[0]; + sp->key[PF_SK_STACK].addr[1] = st->key[PF_SK_STACK]->addr[1]; + sp->key[PF_SK_STACK].port[0] = st->key[PF_SK_STACK]->port[0]; + sp->key[PF_SK_STACK].port[1] = st->key[PF_SK_STACK]->port[1]; + sp->proto = st->key[PF_SK_WIRE]->proto; + sp->af = st->key[PF_SK_WIRE]->af; + + /* copy from state */ + strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); + bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); + sp->creation = htonl(time_second - st->creation); + sp->expire = pf_state_expires(st); + if (sp->expire <= time_second) + sp->expire = htonl(0); + else + sp->expire = htonl(sp->expire - time_second); + + sp->direction = st->direction; + sp->log = st->log; + sp->timeout = st->timeout; + sp->state_flags = st->state_flags; + if (st->src_node) + sp->sync_flags |= PFSYNC_FLAG_SRCNODE; + if (st->nat_src_node) + sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; + + bcopy(&st->id, &sp->id, sizeof(sp->id)); + sp->creatorid = st->creatorid; + pf_state_peer_hton(&st->src, &sp->src); + pf_state_peer_hton(&st->dst, &sp->dst); + + if (st->rule.ptr == NULL) + sp->rule = htonl(-1); + else + sp->rule = htonl(st->rule.ptr->nr); + if (st->anchor.ptr == NULL) + sp->anchor = htonl(-1); + else + sp->anchor = htonl(st->anchor.ptr->nr); + if (st->nat_rule.ptr == NULL) + sp->nat_rule = htonl(-1); + else + sp->nat_rule = htonl(st->nat_rule.ptr->nr); + + pf_state_counter_hton(st->packets[0], sp->packets[0]); + pf_state_counter_hton(st->packets[1], sp->packets[1]); + pf_state_counter_hton(st->bytes[0], sp->bytes[0]); + pf_state_counter_hton(st->bytes[1], sp->bytes[1]); + +} + int -pfsync_insert_net_state(struct pfsync_state *sp, u_int8_t chksum_flag) +pfsync_state_import(struct pfsync_state *sp, u_int8_t flags) { struct pf_state *st = NULL; - struct pf_state_key *sk = NULL; + struct pf_state_key *skw = NULL, *sks = NULL; struct pf_rule *r = NULL; struct pfi_kif *kif; + int pool_flags; + int error; if (sp->creatorid == 0 && pf_status.debug >= PF_DEBUG_MISC) { - printf("pfsync_insert_net_state: invalid creator id:" + printf("pfsync_state_import: invalid creator id:" " %08x\n", ntohl(sp->creatorid)); return (EINVAL); } - kif = pfi_kif_get(sp->ifname); - if (kif == NULL) { + if ((kif = pfi_kif_get(sp->ifname)) == NULL) { if (pf_status.debug >= PF_DEBUG_MISC) - printf("pfsync_insert_net_state: " + printf("pfsync_state_import: " "unknown interface: %s\n", sp->ifname); - /* skip this state */ - return (0); + if (flags & PFSYNC_SI_IOCTL) + return (EINVAL); + return (0); /* skip this state */ } /* - * If the ruleset checksums match, it's safe to associate the state - * with the rule of that number. + * If the ruleset checksums match or the state is coming from the ioctl, + * it's safe to associate the state with the rule of that number. */ - if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && chksum_flag && - ntohl(sp->rule) < + if (sp->rule != htonl(-1) && sp->anchor == htonl(-1) && + (flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->rule) < pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) r = pf_main_ruleset.rules[ PF_RULESET_FILTER].active.ptr_array[ntohl(sp->rule)]; else r = &pf_default_rule; - if (!r->max_states || r->states < r->max_states) - st = pool_get(&pf_state_pl, PR_NOWAIT); - if (st == NULL) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - return (ENOMEM); - } - bzero(st, sizeof(*st)); + if ((r->max_states && r->states_cur >= r->max_states)) + goto cleanup; - if ((sk = pf_alloc_state_key(st)) == NULL) { - pool_put(&pf_state_pl, st); - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - return (ENOMEM); - } + if (flags & PFSYNC_SI_IOCTL) + pool_flags = PR_WAITOK | PR_LIMITFAIL | PR_ZERO; + else + pool_flags = PR_LIMITFAIL | PR_ZERO; + + if ((st = pool_get(&pf_state_pl, pool_flags)) == NULL) + goto cleanup; + + if ((skw = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; + + if (PF_ANEQ(&sp->key[PF_SK_WIRE].addr[0], + &sp->key[PF_SK_STACK].addr[0], sp->af) || + PF_ANEQ(&sp->key[PF_SK_WIRE].addr[1], + &sp->key[PF_SK_STACK].addr[1], sp->af) || + sp->key[PF_SK_WIRE].port[0] != sp->key[PF_SK_STACK].port[0] || + sp->key[PF_SK_WIRE].port[1] != sp->key[PF_SK_STACK].port[1]) { + if ((sks = pf_alloc_state_key(pool_flags)) == NULL) + goto cleanup; + } else + sks = skw; /* allocate memory for scrub info */ if (pfsync_alloc_scrub_memory(&sp->src, &st->src) || - pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); - if (st->src.scrub) - pool_put(&pf_state_scrub_pl, st->src.scrub); - pool_put(&pf_state_pl, st); - pool_put(&pf_state_key_pl, sk); - return (ENOMEM); + pfsync_alloc_scrub_memory(&sp->dst, &st->dst)) + goto cleanup; + + /* copy to state key(s) */ + skw->addr[0] = sp->key[PF_SK_WIRE].addr[0]; + skw->addr[1] = sp->key[PF_SK_WIRE].addr[1]; + skw->port[0] = sp->key[PF_SK_WIRE].port[0]; + skw->port[1] = sp->key[PF_SK_WIRE].port[1]; + skw->proto = sp->proto; + skw->af = sp->af; + if (sks != skw) { + sks->addr[0] = sp->key[PF_SK_STACK].addr[0]; + sks->addr[1] = sp->key[PF_SK_STACK].addr[1]; + sks->port[0] = sp->key[PF_SK_STACK].port[0]; + sks->port[1] = sp->key[PF_SK_STACK].port[1]; + sks->proto = sp->proto; + sks->af = sp->af; } - st->rule.ptr = r; - /* XXX get pointers to nat_rule and anchor */ - - /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ - r->states++; - - /* fill in the rest of the state entry */ - pf_state_host_ntoh(&sp->lan, &sk->lan); - pf_state_host_ntoh(&sp->gwy, &sk->gwy); - pf_state_host_ntoh(&sp->ext, &sk->ext); - - pf_state_peer_ntoh(&sp->src, &st->src); - pf_state_peer_ntoh(&sp->dst, &st->dst); - + /* copy to state */ bcopy(&sp->rt_addr, &st->rt_addr, sizeof(st->rt_addr)); st->creation = time_second - ntohl(sp->creation); - st->expire = ntohl(sp->expire) + time_second; + st->expire = time_second; + if (sp->expire) { + /* XXX No adaptive scaling. */ + st->expire -= r->timeout[sp->timeout] - ntohl(sp->expire); + } - sk->af = sp->af; - sk->proto = sp->proto; - sk->direction = sp->direction; + st->expire = ntohl(sp->expire) + time_second; + st->direction = sp->direction; st->log = sp->log; st->timeout = sp->timeout; - st->allow_opts = sp->allow_opts; + st->state_flags = sp->state_flags; + if (!(flags & PFSYNC_SI_IOCTL)) + st->sync_flags = PFSTATE_FROMSYNC; bcopy(sp->id, &st->id, sizeof(st->id)); st->creatorid = sp->creatorid; - st->sync_flags = PFSTATE_FROMSYNC; + pf_state_peer_ntoh(&sp->src, &st->src); + pf_state_peer_ntoh(&sp->dst, &st->dst); + + st->rule.ptr = r; + st->nat_rule.ptr = NULL; + st->anchor.ptr = NULL; + st->rt_kif = NULL; + + st->pfsync_time = 0; - if (pf_insert_state(kif, st)) { - pfi_kif_unref(kif, PFI_KIF_REF_NONE); + + /* XXX when we have nat_rule/anchors, use STATE_INC_COUNTERS */ + r->states_cur++; + r->states_tot++; + + if ((error = pf_state_insert(kif, skw, sks, st)) != 0) { /* XXX when we have nat_rule/anchors, use STATE_DEC_COUNTERS */ - r->states--; + r->states_cur--; + goto cleanup_state; + } + + return (0); + + cleanup: + error = ENOMEM; + if (skw == sks) + sks = NULL; + if (skw != NULL) + pool_put(&pf_state_key_pl, skw); + if (sks != NULL) + pool_put(&pf_state_key_pl, sks); + + cleanup_state: /* pf_state_insert frees the state keys */ + if (st) { if (st->dst.scrub) pool_put(&pf_state_scrub_pl, st->dst.scrub); if (st->src.scrub) pool_put(&pf_state_scrub_pl, st->src.scrub); pool_put(&pf_state_pl, st); - return (EINVAL); } - - return (0); + return (error); } void @@ -345,6 +445,7 @@ pfsync_input(struct mbuf *m, ...) struct pfsync_softc *sc = pfsyncif; struct pf_state *st; struct pf_state_key *sk; + struct pf_state_item *si; struct pf_state_cmp id_key; struct pfsync_state *sp; struct pfsync_state_upd *up; @@ -358,7 +459,7 @@ pfsync_input(struct mbuf *m, ...) struct in_addr src; struct mbuf *mp; int iplen, action, error, i, s, count, offp, sfail, stale = 0; - u_int8_t chksum_flag = 0; + u_int8_t flags = 0; pfsyncstats.pfsyncs_ipackets++; @@ -413,7 +514,7 @@ pfsync_input(struct mbuf *m, ...) src = ip->ip_src; if (!bcmp(&ph->pf_chksum, &pf_status.pf_chksum, PF_MD5_DIGEST_LENGTH)) - chksum_flag++; + flags |= PFSYNC_SI_CKSUM; switch (action) { case PFSYNC_ACT_CLR: { @@ -444,15 +545,16 @@ pfsync_input(struct mbuf *m, ...) splx(s); return; } - for (sk = RB_MIN(pf_state_tree_lan_ext, - &pf_statetbl_lan_ext); sk; sk = nextsk) { - nextsk = RB_NEXT(pf_state_tree_lan_ext, - &pf_statetbl_lan_ext, sk); - TAILQ_FOREACH(st, &sk->states, next) { - if (st->creatorid == creatorid) { - st->sync_flags |= + /* XXX correct? */ + for (sk = RB_MIN(pf_state_tree, + &pf_statetbl); sk; sk = nextsk) { + nextsk = RB_NEXT(pf_state_tree, + &pf_statetbl, sk); + TAILQ_FOREACH(si, &sk->states, entry) { + if (si->s->creatorid == creatorid) { + si->s->sync_flags |= PFSTATE_FROMSYNC; - pf_unlink_state(st); + pf_unlink_state(si->s); } } } @@ -484,8 +586,7 @@ pfsync_input(struct mbuf *m, ...) continue; } - if ((error = pfsync_insert_net_state(sp, - chksum_flag))) { + if ((error = pfsync_state_import(sp, flags))) { if (error == ENOMEM) { splx(s); goto done; @@ -524,11 +625,11 @@ pfsync_input(struct mbuf *m, ...) st = pf_find_state_byid(&id_key); if (st == NULL) { /* insert the update */ - if (pfsync_insert_net_state(sp, chksum_flag)) + if (pfsync_state_import(sp, flags)) pfsyncstats.pfsyncs_badstate++; continue; } - sk = st->state_key; + sk = st->key[PF_SK_WIRE]; /* XXX right one? */ sfail = 0; if (sk->proto == IPPROTO_TCP) { /* @@ -589,7 +690,7 @@ pfsync_input(struct mbuf *m, ...) } continue; } - pfsync_alloc_scrub_memory(&sp->dst, &st->dst); + pfsync_alloc_scrub_memory(&sp->dst, &st->dst); pf_state_peer_ntoh(&sp->src, &st->src); pf_state_peer_ntoh(&sp->dst, &st->dst); st->expire = ntohl(sp->expire) + time_second; @@ -665,7 +766,7 @@ pfsync_input(struct mbuf *m, ...) pfsyncstats.pfsyncs_badstate++; continue; } - sk = st->state_key; + sk = st->key[PF_SK_WIRE]; /* XXX right one? */ sfail = 0; if (sk->proto == IPPROTO_TCP) { /* @@ -716,7 +817,7 @@ pfsync_input(struct mbuf *m, ...) PFSYNC_FLAG_STALE); continue; } - pfsync_alloc_scrub_memory(&up->dst, &st->dst); + pfsync_alloc_scrub_memory(&up->dst, &st->dst); pf_state_peer_ntoh(&up->src, &st->src); pf_state_peer_ntoh(&up->dst, &st->dst); st->expire = ntohl(up->expire) + time_second; @@ -1117,9 +1218,6 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) struct pfsync_state *sp = NULL; struct pfsync_state_upd *up = NULL; struct pfsync_state_del *dp = NULL; - struct pf_state_key *sk = st->state_key; - struct pf_rule *r; - u_long secs; int s, ret = 0; u_int8_t i = 255, newaction = 0; @@ -1186,8 +1284,6 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) } } - secs = time_second; - st->pfsync_time = time_uptime; if (sp == NULL) { @@ -1199,47 +1295,19 @@ pfsync_pack_state(u_int8_t action, struct pf_state *st, int flags) h->count++; bzero(sp, sizeof(*sp)); - bcopy(&st->id, sp->id, sizeof(sp->id)); - sp->creatorid = st->creatorid; - - strlcpy(sp->ifname, st->kif->pfik_name, sizeof(sp->ifname)); - pf_state_host_hton(&sk->lan, &sp->lan); - pf_state_host_hton(&sk->gwy, &sp->gwy); - pf_state_host_hton(&sk->ext, &sp->ext); - - bcopy(&st->rt_addr, &sp->rt_addr, sizeof(sp->rt_addr)); - - sp->creation = htonl(secs - st->creation); - pf_state_counter_hton(st->packets[0], sp->packets[0]); - pf_state_counter_hton(st->packets[1], sp->packets[1]); - pf_state_counter_hton(st->bytes[0], sp->bytes[0]); - pf_state_counter_hton(st->bytes[1], sp->bytes[1]); - if ((r = st->rule.ptr) == NULL) - sp->rule = htonl(-1); - else - sp->rule = htonl(r->nr); - if ((r = st->anchor.ptr) == NULL) - sp->anchor = htonl(-1); - else - sp->anchor = htonl(r->nr); - sp->af = sk->af; - sp->proto = sk->proto; - sp->direction = sk->direction; - sp->log = st->log; - sp->allow_opts = st->allow_opts; - sp->timeout = st->timeout; + pfsync_state_export(sp, st); if (flags & PFSYNC_FLAG_STALE) sp->sync_flags |= PFSTATE_STALE; - } - - pf_state_peer_hton(&st->src, &sp->src); - pf_state_peer_hton(&st->dst, &sp->dst); + } else { + pf_state_peer_hton(&st->src, &sp->src); + pf_state_peer_hton(&st->dst, &sp->dst); - if (st->expire <= secs) - sp->expire = htonl(0); - else - sp->expire = htonl(st->expire - secs); + if (st->expire <= time_second) + sp->expire = htonl(0); + else + sp->expire = htonl(st->expire - time_second); + } /* do we need to build "compressed" actions for network transfer? */ if (sc->sc_sync_ifp && flags & PFSYNC_FLAG_COMPRESS) { @@ -1715,7 +1783,7 @@ pfsync_update_tdb(struct tdb *tdb, int output) for (i = 0; !pt && i < h->count; i++) { if (tdb->tdb_spi == u->spi && tdb->tdb_sproto == u->sproto && - !bcmp(&tdb->tdb_dst, &u->dst, + !bcmp(&tdb->tdb_dst, &u->dst, SA_LEN(&u->dst.sa))) { pt = u; pt->updates++; |