diff options
author | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2007-05-31 04:11:43 +0000 |
---|---|---|
committer | Ryan Thomas McBride <mcbride@cvs.openbsd.org> | 2007-05-31 04:11:43 +0000 |
commit | 8ed7c1731b5bd668dfc182b9ac3e5723d45f030b (patch) | |
tree | 167c59edf4ee1a321a20d6b6750c1c691eabfec0 /sys/net/pf_ioctl.c | |
parent | 457178550d6d623e3bdb779fb56c93ec291aa971 (diff) |
First step of rearranging pf's state table internals...
- Split pf_state into pf_state (used for tracking connection information),
and pf_state_key (used for searching the state table)
- Use pfsync_state in the ioctl for userland access to the state
table. This will sheild userland somewhat from future changes.
ok henning@ toby@ pyr@
Diffstat (limited to 'sys/net/pf_ioctl.c')
-rw-r--r-- | sys/net/pf_ioctl.c | 264 |
1 files changed, 166 insertions, 98 deletions
diff --git a/sys/net/pf_ioctl.c b/sys/net/pf_ioctl.c index f6a20e71751..2fc576c00d4 100644 --- a/sys/net/pf_ioctl.c +++ b/sys/net/pf_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_ioctl.c,v 1.176 2007/05/29 00:17:32 thib Exp $ */ +/* $OpenBSD: pf_ioctl.c,v 1.177 2007/05/31 04:11:42 mcbride Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -109,6 +109,10 @@ int pf_setup_pfsync_matching(struct pf_ruleset *); void pf_hash_rule(MD5_CTX *, struct pf_rule *); void pf_hash_rule_addr(MD5_CTX *, struct pf_rule_addr *); int pf_commit_rules(u_int32_t, int, char *); +void pf_state_export(struct pfsync_state *, + struct pf_state_key *, struct pf_state *); +void pf_state_import(struct pfsync_state *, + struct pf_state_key *, struct pf_state *); struct pf_rule pf_default_rule; struct rwlock pf_consistency_lock = RWLOCK_INITIALIZER("pfcnslk"); @@ -143,6 +147,8 @@ pfattach(int num) "pfsrctrpl", NULL); pool_init(&pf_state_pl, sizeof(struct pf_state), 0, 0, 0, "pfstatepl", NULL); + pool_init(&pf_state_key_pl, sizeof(struct pf_state_key), 0, 0, 0, + "pfstatekeypl", NULL); pool_init(&pf_altq_pl, sizeof(struct pf_altq), 0, 0, 0, "pfaltqpl", &pool_allocator_nointr); pool_init(&pf_pooladdr_pl, sizeof(struct pf_pooladdr), 0, 0, 0, @@ -837,6 +843,94 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor) return (0); } +void +pf_state_export(struct pfsync_state *sp, struct pf_state_key *sk, + struct pf_state *s) +{ + int secs = time_second; + bzero(sp, sizeof(struct pfsync_state)); + + /* copy from state key */ + memcpy(&sp->id, &sk->id, sizeof(sp->id)); + sp->creatorid = sk->creatorid; + sp->lan.addr = sk->lan.addr; + sp->lan.port = sk->lan.port; + sp->gwy.addr = sk->gwy.addr; + sp->gwy.port = sk->gwy.port; + sp->ext.addr = sk->ext.addr; + sp->ext.port = sk->ext.port; + sp->proto = sk->proto; + sp->af = sk->af; + sp->direction = sk->direction; + + /* copy from state */ + strlcpy(sp->ifname, s->u.s.kif->pfik_name, sizeof(sp->ifname)); + pf_state_peer_to_pfsync(&s->src, &sp->src); + pf_state_peer_to_pfsync(&s->dst, &sp->dst); + + sp->rule = s->rule.ptr->nr; + sp->nat_rule = (s->nat_rule.ptr == NULL) ? -1 : s->nat_rule.ptr->nr; + sp->anchor = (s->anchor.ptr == NULL) ? -1 : s->anchor.ptr->nr; + + pf_state_counter_to_pfsync(s->bytes[0], sp->bytes[0]); + pf_state_counter_to_pfsync(s->bytes[1], sp->bytes[1]); + pf_state_counter_to_pfsync(s->packets[0], sp->packets[0]); + pf_state_counter_to_pfsync(s->packets[1], sp->packets[1]); + sp->creation = secs - s->creation; + sp->expire = pf_state_expires(s); + sp->log = s->log; + sp->allow_opts = s->allow_opts; + sp->timeout = s->timeout; + + if (s->src_node) + sp->sync_flags |= PFSYNC_FLAG_SRCNODE; + if (s->nat_src_node) + sp->sync_flags |= PFSYNC_FLAG_NATSRCNODE; + + if (sp->expire > secs) + sp->expire -= secs; + else + sp->expire = 0; + +} + +void +pf_state_import(struct pfsync_state *sp, struct pf_state_key *sk, + struct pf_state *s) +{ + bzero(sk, sizeof(struct pf_state_key)); + bzero(s, sizeof(struct pf_state)); + sk->state = s; + s->state_key = sk; + + /* copy to state key */ + memcpy(&sk->id, &sp->id, sizeof(sp->id)); + sk->creatorid = sp->creatorid; + sk->lan.addr = sp->lan.addr; + sk->lan.port = sp->lan.port; + sk->gwy.addr = sp->gwy.addr; + sk->gwy.port = sp->gwy.port; + sk->ext.addr = sp->ext.addr; + sk->ext.port = sp->ext.port; + sk->proto = sp->proto; + sk->af = sp->af; + sk->direction = sp->direction; + + /* copy to state */ + strlcpy(sp->ifname, s->u.s.kif->pfik_name, sizeof(sp->ifname)); + pf_state_peer_from_pfsync(&sp->src, &s->src); + pf_state_peer_from_pfsync(&sp->dst, &s->dst); + + s->rule.ptr = &pf_default_rule; + s->nat_rule.ptr = NULL; + s->anchor.ptr = NULL; + s->rt_kif = NULL; + s->creation = time_second; + s->pfsync_time = 0; + s->packets[0] = s->packets[1] = 0; + s->bytes[0] = s->bytes[1] = 0; +} + int pf_setup_pfsync_matching(struct pf_ruleset *rs) { @@ -1457,21 +1551,21 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCCLRSTATES: { - struct pf_state *state, *nexts; + struct pf_state_key *sk, *nextsk; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; int killed = 0; - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); + for (sk = RB_MIN(pf_state_tree_id, &tree_id); sk; + sk = nextsk) { + nextsk = RB_NEXT(pf_state_tree_id, &tree_id, sk); if (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, - state->u.s.kif->pfik_name)) { + sk->state->u.s.kif->pfik_name)) { #if NPFSYNC /* don't send out individual delete messages */ - state->sync_flags = PFSTATE_NOSYNC; + sk->state->sync_flags = PFSTATE_NOSYNC; #endif - pf_unlink_state(state); + pf_unlink_state(sk->state); killed++; } } @@ -1483,33 +1577,33 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } case DIOCKILLSTATES: { - struct pf_state *state, *nexts; + struct pf_state_key *sk, *nextsk; struct pf_state_host *src, *dst; struct pfioc_state_kill *psk = (struct pfioc_state_kill *)addr; int killed = 0; - for (state = RB_MIN(pf_state_tree_id, &tree_id); state; - state = nexts) { - nexts = RB_NEXT(pf_state_tree_id, &tree_id, state); + for (sk = RB_MIN(pf_state_tree_id, &tree_id); sk; + sk = nextsk) { + nextsk = RB_NEXT(pf_state_tree_id, &tree_id, sk); - if (state->direction == PF_OUT) { - src = &state->lan; - dst = &state->ext; + if (sk->direction == PF_OUT) { + src = &sk->lan; + dst = &sk->ext; } else { - src = &state->ext; - dst = &state->lan; + src = &sk->ext; + dst = &sk->lan; } - if ((!psk->psk_af || state->af == psk->psk_af) + if ((!psk->psk_af || sk->af == psk->psk_af) && (!psk->psk_proto || psk->psk_proto == - state->proto) && + sk->proto) && PF_MATCHA(psk->psk_src.neg, &psk->psk_src.addr.v.a.addr, &psk->psk_src.addr.v.a.mask, - &src->addr, state->af) && + &src->addr, sk->af) && PF_MATCHA(psk->psk_dst.neg, &psk->psk_dst.addr.v.a.addr, &psk->psk_dst.addr.v.a.mask, - &dst->addr, state->af) && + &dst->addr, sk->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], @@ -1519,13 +1613,13 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) psk->psk_dst.port[0], psk->psk_dst.port[1], dst->port)) && (!psk->psk_ifname[0] || !strcmp(psk->psk_ifname, - state->u.s.kif->pfik_name))) { + sk->state->u.s.kif->pfik_name))) { #if NPFSYNC > 0 /* send immediate delete of state */ - pfsync_delete_state(state); - state->sync_flags |= PFSTATE_NOSYNC; + pfsync_delete_state(sk->state); + sk->state->sync_flags |= PFSTATE_NOSYNC; #endif - pf_unlink_state(state); + pf_unlink_state(sk->state); killed++; } } @@ -1535,39 +1629,38 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCADDSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; - struct pf_state *state; + struct pfsync_state *sp = (struct pfsync_state *)ps->state; + struct pf_state *s; + struct pf_state_key *sk; struct pfi_kif *kif; - if (ps->state.timeout >= PFTM_MAX && - ps->state.timeout != PFTM_UNTIL_PACKET) { + if (sp->timeout >= PFTM_MAX && + sp->timeout != PFTM_UNTIL_PACKET) { error = EINVAL; break; } - state = pool_get(&pf_state_pl, PR_NOWAIT); - if (state == NULL) { + s = pool_get(&pf_state_pl, PR_NOWAIT); + if (s == NULL) { error = ENOMEM; break; } - kif = pfi_kif_get(ps->state.u.ifname); + sk = pool_get(&pf_state_key_pl, PR_NOWAIT); + if (sk == NULL) { + error = ENOMEM; + break; + } + pf_state_import(sp, sk, s); + kif = pfi_kif_get(sp->ifname); if (kif == NULL) { - pool_put(&pf_state_pl, state); + pool_put(&pf_state_pl, s); + pool_put(&pf_state_key_pl, sk); error = ENOENT; break; } - bcopy(&ps->state, state, sizeof(struct pf_state)); - bzero(&state->u, sizeof(state->u)); - state->rule.ptr = &pf_default_rule; - state->nat_rule.ptr = NULL; - state->anchor.ptr = NULL; - state->rt_kif = NULL; - state->creation = time_second; - state->pfsync_time = 0; - state->packets[0] = state->packets[1] = 0; - state->bytes[0] = state->bytes[1] = 0; - - if (pf_insert_state(kif, state)) { + if (pf_insert_state(kif, s)) { pfi_kif_unref(kif, PFI_KIF_REF_NONE); - pool_put(&pf_state_pl, state); + pool_put(&pf_state_pl, s); + pool_put(&pf_state_key_pl, sk); error = ENOMEM; } break; @@ -1575,48 +1668,34 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCGETSTATE: { struct pfioc_state *ps = (struct pfioc_state *)addr; - struct pf_state *state; + struct pf_state_key *sk; u_int32_t nr; - int secs; nr = 0; - RB_FOREACH(state, pf_state_tree_id, &tree_id) { + RB_FOREACH(sk, pf_state_tree_id, &tree_id) { if (nr >= ps->nr) break; nr++; } - if (state == NULL) { + if (sk == NULL) { error = EBUSY; break; } - secs = time_second; - bcopy(state, &ps->state, sizeof(ps->state)); - strlcpy(ps->state.u.ifname, state->u.s.kif->pfik_name, - sizeof(ps->state.u.ifname)); - ps->state.rule.nr = state->rule.ptr->nr; - ps->state.nat_rule.nr = (state->nat_rule.ptr == NULL) ? - -1 : state->nat_rule.ptr->nr; - ps->state.anchor.nr = (state->anchor.ptr == NULL) ? - -1 : state->anchor.ptr->nr; - ps->state.creation = secs - ps->state.creation; - ps->state.expire = pf_state_expires(state); - if (ps->state.expire > secs) - ps->state.expire -= secs; - else - ps->state.expire = 0; + + pf_state_export((struct pfsync_state *)&ps->state, + sk, sk->state); break; } case DIOCGETSTATES: { struct pfioc_states *ps = (struct pfioc_states *)addr; struct pf_state *state; - struct pf_state *p, *pstore; + struct pfsync_state *p, *pstore; u_int32_t nr = 0; - int space = ps->ps_len; - if (space == 0) { + if (ps->ps_len == 0) { nr = pf_status.states; - ps->ps_len = sizeof(struct pf_state) * nr; + ps->ps_len = sizeof(struct pfsync_state) * nr; break; } @@ -1627,26 +1706,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) state = TAILQ_FIRST(&state_list); while (state) { if (state->timeout != PFTM_UNLINKED) { - int secs = time_second; - if ((nr+1) * sizeof(*p) > (unsigned)ps->ps_len) break; - bcopy(state, pstore, sizeof(*pstore)); - strlcpy(pstore->u.ifname, - state->u.s.kif->pfik_name, - sizeof(pstore->u.ifname)); - pstore->rule.nr = state->rule.ptr->nr; - pstore->nat_rule.nr = (state->nat_rule.ptr == - NULL) ? -1 : state->nat_rule.ptr->nr; - pstore->anchor.nr = (state->anchor.ptr == - NULL) ? -1 : state->anchor.ptr->nr; - pstore->creation = secs - pstore->creation; - pstore->expire = pf_state_expires(state); - if (pstore->expire > secs) - pstore->expire -= secs; - else - pstore->expire = 0; + pf_state_export(pstore, + state->state_key, state); error = copyout(pstore, p, sizeof(*p)); if (error) { free(pstore, M_TEMP); @@ -1658,7 +1722,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) state = TAILQ_NEXT(state, u.s.entry_list); } - ps->ps_len = sizeof(struct pf_state) * nr; + ps->ps_len = sizeof(struct pfsync_state) * nr; free(pstore, M_TEMP); break; @@ -1698,8 +1762,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCNATLOOK: { struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr; + struct pf_state_key *sk; struct pf_state *state; - struct pf_state_cmp key; + struct pf_state_key_cmp key; int m = 0, direction = pnl->direction; key.af = pnl->af; @@ -1735,17 +1800,18 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (m > 1) error = E2BIG; /* more than one state */ else if (state != NULL) { + sk = state->state_key; if (direction == PF_IN) { - PF_ACPY(&pnl->rsaddr, &state->lan.addr, - state->af); - pnl->rsport = state->lan.port; + PF_ACPY(&pnl->rsaddr, &sk->lan.addr, + sk->af); + pnl->rsport = sk->lan.port; PF_ACPY(&pnl->rdaddr, &pnl->daddr, pnl->af); pnl->rdport = pnl->dport; } else { - PF_ACPY(&pnl->rdaddr, &state->gwy.addr, - state->af); - pnl->rdport = state->gwy.port; + PF_ACPY(&pnl->rdaddr, &sk->gwy.addr, + sk->af); + pnl->rdport = sk->gwy.port; PF_ACPY(&pnl->rsaddr, &pnl->saddr, pnl->af); pnl->rsport = pnl->sport; @@ -2771,11 +2837,11 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCCLRSRCNODES: { struct pf_src_node *n; - struct pf_state *state; + struct pf_state_key *state_key; - RB_FOREACH(state, pf_state_tree_id, &tree_id) { - state->src_node = NULL; - state->nat_src_node = NULL; + RB_FOREACH(state_key, pf_state_tree_id, &tree_id) { + state_key->state->src_node = NULL; + state_key->state->nat_src_node = NULL; } RB_FOREACH(n, pf_src_tree, &tree_src_tracking) { n->expire = 1; @@ -2789,6 +2855,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) case DIOCKILLSRCNODES: { struct pf_src_node *sn; struct pf_state *s; + struct pf_state_key *sk; struct pfioc_src_node_kill *psnk = \ (struct pfioc_src_node_kill *) addr; int killed = 0; @@ -2804,8 +2871,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) &sn->raddr, sn->af)) { /* Handle state to src_node linkage */ if (sn->states != 0) { - RB_FOREACH(s, pf_state_tree_id, + RB_FOREACH(sk, pf_state_tree_id, &tree_id) { + s = sk->state; if (s->src_node == sn) s->src_node = NULL; if (s->nat_src_node == sn) |