diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/pf.c | 557 | ||||
-rw-r--r-- | sys/net/pf_norm.c | 72 | ||||
-rw-r--r-- | sys/net/pfvar.h | 29 |
3 files changed, 218 insertions, 440 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index 88f17d3d62c..676a54dfebc 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.215 2002/06/07 20:59:20 dhartmei Exp $ */ +/* $OpenBSD: pf.c,v 1.216 2002/06/07 21:14:02 frantzen Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -81,19 +81,7 @@ #define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x - -/* - * Tree data structure - */ - -struct pf_tree_node { - struct pf_tree_key key; - struct pf_state *state; - struct pf_tree_node *parent; - struct pf_tree_node *left; - struct pf_tree_node *right; - int balance; -}; +struct pf_state_tree; struct pf_port_node { LIST_ENTRY(pf_port_node) next; @@ -117,7 +105,6 @@ struct pf_binatqueue *pf_binats_active; struct pf_binatqueue *pf_binats_inactive; struct pf_rdrqueue *pf_rdrs_active; struct pf_rdrqueue *pf_rdrs_inactive; -struct pf_tree_node *tree_lan_ext, *tree_ext_gwy; struct pf_status pf_status; struct ifnet *status_ifp; @@ -175,8 +162,6 @@ struct pf_pool_limit { } pf_pool_limits[PF_LIMIT_MAX] = { { &pf_state_pl, UINT_MAX }, { &pf_frent_pl, PFFRAG_FRENT_HIWAT } }; -int pf_tree_key_compare(struct pf_tree_key *, - struct pf_tree_key *); void pf_addrcpy(struct pf_addr *, struct pf_addr *, u_int8_t); int pf_compare_rules(struct pf_rule *, @@ -185,13 +170,9 @@ int pf_compare_nats(struct pf_nat *, struct pf_nat *); int pf_compare_binats(struct pf_binat *, struct pf_binat *); int pf_compare_rdrs(struct pf_rdr *, struct pf_rdr *); -void pf_tree_rotate_left(struct pf_tree_node **); -void pf_tree_rotate_right(struct pf_tree_node **); -struct pf_tree_node *pf_tree_first(struct pf_tree_node *); -struct pf_tree_node *pf_tree_next(struct pf_tree_node *); -struct pf_tree_node *pf_tree_search(struct pf_tree_node *, - struct pf_tree_key *); -void pf_insert_state(struct pf_state *); +int pf_insert_state(struct pf_state *); +struct pf_state *pf_find_state(struct pf_state_tree *, + struct pf_tree_node *); void pf_purge_expired_states(void); void pf_purge_timeout(void *); int pf_dynaddr_setup(struct pf_addr_wrap *, u_int8_t); @@ -296,10 +277,18 @@ int pf_socket_lookup(uid_t *, gid_t *, int, int, int, (s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \ (s)->lan.port != (s)->gwy.port -int -pf_tree_key_compare(struct pf_tree_key *a, struct pf_tree_key *b) + + +static __inline int pf_state_compare(struct pf_tree_node *, + struct pf_tree_node *); +RB_HEAD(pf_state_tree, pf_tree_node) tree_lan_ext, tree_ext_gwy; +RB_PROTOTYPE(pf_state_tree, pf_tree_node, entry, pf_state_compare); +RB_GENERATE(pf_state_tree, pf_tree_node, entry, pf_state_compare); + +static __inline int +pf_state_compare(struct pf_tree_node *a, struct pf_tree_node *b) { - register int diff; + int diff; if ((diff = a->proto - b->proto) != 0) return (diff); @@ -497,168 +486,6 @@ pf_compare_rdrs(struct pf_rdr *a, struct pf_rdr *b) return (0); } -void -pf_tree_rotate_left(struct pf_tree_node **n) -{ - struct pf_tree_node *q = *n, *p = (*n)->parent; - - (*n)->parent = (*n)->right; - *n = (*n)->right; - (*n)->parent = p; - q->right = (*n)->left; - if (q->right) - q->right->parent = q; - (*n)->left = q; - q->balance--; - if ((*n)->balance > 0) - q->balance -= (*n)->balance; - (*n)->balance--; - if (q->balance < 0) - (*n)->balance += q->balance; -} - -void -pf_tree_rotate_right(struct pf_tree_node **n) -{ - struct pf_tree_node *q = *n, *p = (*n)->parent; - - (*n)->parent = (*n)->left; - *n = (*n)->left; - (*n)->parent = p; - q->left = (*n)->right; - if (q->left) - q->left->parent = q; - (*n)->right = q; - q->balance++; - if ((*n)->balance < 0) - q->balance -= (*n)->balance; - (*n)->balance++; - if (q->balance > 0) - (*n)->balance += q->balance; -} - -int -pf_tree_insert(struct pf_tree_node **n, struct pf_tree_node *p, - struct pf_tree_key *key, struct pf_state *state) -{ - int deltaH = 0; - - if (*n == NULL) { - *n = pool_get(&pf_tree_pl, PR_NOWAIT); - if (*n == NULL) - return (0); - bcopy(key, &(*n)->key, sizeof(struct pf_tree_key)); - (*n)->state = state; - (*n)->balance = 0; - (*n)->parent = p; - (*n)->left = (*n)->right = NULL; - deltaH = 1; - } else if (pf_tree_key_compare(key, &(*n)->key) > 0) { - if (pf_tree_insert(&(*n)->right, *n, key, state)) { - (*n)->balance++; - if ((*n)->balance == 1) - deltaH = 1; - else if ((*n)->balance == 2) { - if ((*n)->right->balance == -1) - pf_tree_rotate_right(&(*n)->right); - pf_tree_rotate_left(n); - } - } - } else { - if (pf_tree_insert(&(*n)->left, *n, key, state)) { - (*n)->balance--; - if ((*n)->balance == -1) - deltaH = 1; - else if ((*n)->balance == -2) { - if ((*n)->left->balance == 1) - pf_tree_rotate_left(&(*n)->left); - pf_tree_rotate_right(n); - } - } - } - return (deltaH); -} - -int -pf_tree_remove(struct pf_tree_node **n, struct pf_tree_node *p, - struct pf_tree_key *key) -{ - int deltaH = 0; - int c; - - if (*n == NULL) - return (0); - c = pf_tree_key_compare(key, &(*n)->key); - if (c < 0) { - if (pf_tree_remove(&(*n)->left, *n, key)) { - (*n)->balance++; - if ((*n)->balance == 0) - deltaH = 1; - else if ((*n)->balance == 2) { - if ((*n)->right->balance == -1) - pf_tree_rotate_right(&(*n)->right); - pf_tree_rotate_left(n); - if ((*n)->balance == 0) - deltaH = 1; - } - } - } else if (c > 0) { - if (pf_tree_remove(&(*n)->right, *n, key)) { - (*n)->balance--; - if ((*n)->balance == 0) - deltaH = 1; - else if ((*n)->balance == -2) { - if ((*n)->left->balance == 1) - pf_tree_rotate_left(&(*n)->left); - pf_tree_rotate_right(n); - if ((*n)->balance == 0) - deltaH = 1; - } - } - } else { - if ((*n)->right == NULL) { - struct pf_tree_node *n0 = *n; - - *n = (*n)->left; - if (*n != NULL) - (*n)->parent = p; - pool_put(&pf_tree_pl, n0); - deltaH = 1; - } else if ((*n)->left == NULL) { - struct pf_tree_node *n0 = *n; - - *n = (*n)->right; - if (*n != NULL) - (*n)->parent = p; - pool_put(&pf_tree_pl, n0); - deltaH = 1; - } else { - struct pf_tree_node **qq = &(*n)->left; - - while ((*qq)->right != NULL) - qq = &(*qq)->right; - bcopy(&(*qq)->key, &(*n)->key, - sizeof(struct pf_tree_key)); - (*n)->state = (*qq)->state; - bcopy(key, &(*qq)->key, sizeof(struct pf_tree_key)); - if (pf_tree_remove(&(*n)->left, *n, key)) { - (*n)->balance++; - if ((*n)->balance == 0) - deltaH = 1; - else if ((*n)->balance == 2) { - if ((*n)->right->balance == -1) - pf_tree_rotate_right( - &(*n)->right); - pf_tree_rotate_left(n); - if ((*n)->balance == 0) - deltaH = 1; - } - } - } - } - return (deltaH); -} - int pflog_packet(struct ifnet *ifp, struct mbuf *m, int af, u_short dir, u_short reason, struct pf_rule *rm) @@ -702,121 +529,61 @@ pflog_packet(struct ifnet *ifp, struct mbuf *m, int af, u_short dir, return (0); } -struct pf_tree_node * -pf_tree_first(struct pf_tree_node *n) -{ - if (n == NULL) - return (NULL); - while (n->parent) - n = n->parent; - while (n->left) - n = n->left; - return (n); -} - -struct pf_tree_node * -pf_tree_next(struct pf_tree_node *n) -{ - if (n == NULL) - return (NULL); - if (n->right) { - n = n->right; - while (n->left) - n = n->left; - } else { - if (n->parent && (n == n->parent->left)) - n = n->parent; - else { - while (n->parent && (n == n->parent->right)) - n = n->parent; - n = n->parent; - } - } - return (n); -} - -struct pf_tree_node * -pf_tree_search(struct pf_tree_node *n, struct pf_tree_key *key) +struct pf_state * +pf_find_state(struct pf_state_tree *tree, struct pf_tree_node *key) { - int c; + struct pf_tree_node *k; - while (n && (c = pf_tree_key_compare(&n->key, key))) - if (c > 0) - n = n->left; - else - n = n->right; pf_status.fcounters[FCNT_STATE_SEARCH]++; - return (n); -} - -struct pf_state * -pf_find_state(struct pf_tree_node *n, struct pf_tree_key *key) -{ - n = pf_tree_search(n, key); - if (n) - return (n->state); + k = RB_FIND(pf_state_tree, tree, key); + if (k) + return (k->state); else return (NULL); } -void +int pf_insert_state(struct pf_state *state) { - struct pf_tree_key key; - struct pf_state *s; - - key.af = state->af; - key.proto = state->proto; - PF_ACPY(&key.addr[0], &state->lan.addr, state->af); - key.port[0] = state->lan.port; - PF_ACPY(&key.addr[1], &state->ext.addr, state->af); - key.port[1] = state->ext.port; - /* sanity checks can be removed later, should never occur */ - if ((s = pf_find_state(tree_lan_ext, &key)) != NULL) { - if (pf_status.debug >= PF_DEBUG_URGENT) { - printf("pf: ERROR! insert invalid\n"); - printf(" key already in tree_lan_ext\n"); - printf(" key: proto = %u, lan = ", state->proto); - pf_print_host(&key.addr[0], key.port[0], key.af); - printf(", ext = "); - pf_print_host(&key.addr[1], key.port[1], key.af); - printf("\n state: "); - pf_print_state(s); - printf("\n"); - } - } else { - pf_tree_insert(&tree_lan_ext, NULL, &key, state); - if (pf_find_state(tree_lan_ext, &key) != state) - DPFPRINTF(PF_DEBUG_URGENT, - ("pf: ERROR! insert failed\n")); - } - - key.af = state->af; - key.proto = state->proto; - PF_ACPY(&key.addr[0], &state->ext.addr, state->af); - key.port[0] = state->ext.port; - PF_ACPY(&key.addr[1], &state->gwy.addr, state->af); - key.port[1] = state->gwy.port; - if ((s = pf_find_state(tree_ext_gwy, &key)) != NULL) { - if (pf_status.debug >= PF_DEBUG_URGENT) { - printf("pf: ERROR! insert invalid\n"); - printf(" key already in tree_ext_gwy\n"); - printf(" key: proto = %u, ext = ", state->proto); - pf_print_host(&key.addr[0], key.port[0], key.af); - printf(", gwy = "); - pf_print_host(&key.addr[1], key.port[1], key.af); - printf("\n state: "); - pf_print_state(s); - printf("\n"); - } - } else { - pf_tree_insert(&tree_ext_gwy, NULL, &key, state); - if (pf_find_state(tree_ext_gwy, &key) != state) - DPFPRINTF(PF_DEBUG_URGENT, - ("pf: ERROR! insert failed\n")); - } + struct pf_tree_node *keya, *keyb; + + keya = pool_get(&pf_tree_pl, PR_NOWAIT); + if (keya == NULL) + return -1; + keya->state = state; + keya->proto = state->proto; + keya->af = state->af; + PF_ACPY(&keya->addr[0], &state->lan.addr, state->af); + keya->port[0] = state->lan.port; + PF_ACPY(&keya->addr[1], &state->ext.addr, state->af); + keya->port[1] = state->ext.port; + + /* Thou MUST NOT insert multiple duplicate keys */ + if (RB_INSERT(pf_state_tree, &tree_lan_ext, keya) != NULL) + panic("Multiple identical states in PF state table"); + + + keyb = pool_get(&pf_tree_pl, PR_NOWAIT); + if (keyb == NULL) { + /* Need to pull out the other state */ + RB_REMOVE(pf_state_tree, &tree_lan_ext, keya); + pool_put(&pf_tree_pl, keya); + return -1; + } + keyb->state = state; + keyb->proto = state->proto; + keyb->af = state->af; + PF_ACPY(&keyb->addr[0], &state->ext.addr, state->af); + keyb->port[0] = state->ext.port; + PF_ACPY(&keyb->addr[1], &state->gwy.addr, state->af); + keyb->port[1] = state->gwy.port; + + if (RB_INSERT(pf_state_tree, &tree_ext_gwy, keyb) != NULL) + panic("Multiple identical states in PF state table"); + pf_status.fcounters[FCNT_STATE_INSERT]++; pf_status.states++; + return 0; } void @@ -836,54 +603,43 @@ pf_purge_timeout(void *arg) void pf_purge_expired_states(void) { - struct pf_tree_node *cur, *next; - struct pf_tree_key key; + struct pf_tree_node *cur, *peer, *next; + struct pf_tree_node key; + + for (cur = RB_MIN(pf_state_tree, &tree_ext_gwy); cur; cur = next) { + next = RB_NEXT(pf_state_tree, &tree_ext_gwy, cur); - cur = pf_tree_first(tree_ext_gwy); - while (cur != NULL) { if (cur->state->expire <= time.tv_sec) { - key.af = cur->state->af; + RB_REMOVE(pf_state_tree, &tree_ext_gwy, cur); + + /* Need this key's peer (in the other tree) */ + key.state = cur->state; key.proto = cur->state->proto; + key.af = cur->state->af; PF_ACPY(&key.addr[0], &cur->state->lan.addr, cur->state->af); key.port[0] = cur->state->lan.port; PF_ACPY(&key.addr[1], &cur->state->ext.addr, cur->state->af); key.port[1] = cur->state->ext.port; - /* remove state from second tree */ - if (pf_find_state(tree_lan_ext, &key) != cur->state) - DPFPRINTF(PF_DEBUG_URGENT, - ("pf: ERROR: remove invalid!\n")); - pf_tree_remove(&tree_lan_ext, NULL, &key); - if (pf_find_state(tree_lan_ext, &key) != NULL) - DPFPRINTF(PF_DEBUG_URGENT, - ("pf: ERROR: remove failed\n")); + + peer = RB_FIND(pf_state_tree, &tree_lan_ext, &key); + KASSERT(peer); + KASSERT(peer->state == cur->state); + RB_REMOVE(pf_state_tree, &tree_lan_ext, peer); + + + /* release NAT resources */ if (STATE_TRANSLATE(cur->state)) pf_put_sport(cur->state->proto, htons(cur->state->gwy.port)); - /* free state */ + pool_put(&pf_state_pl, cur->state); - /* - * remove state from tree being traversed, use next - * state's key to search after removal, since removal - * can invalidate pointers. - */ - next = pf_tree_next(cur); - if (next) { - key = next->key; - pf_tree_remove(&tree_ext_gwy, NULL, &cur->key); - cur = pf_tree_search(tree_ext_gwy, &key); - if (cur == NULL) - DPFPRINTF(PF_DEBUG_URGENT, - ("pf: ERROR: next not found\n")); - } else { - pf_tree_remove(&tree_ext_gwy, NULL, &cur->key); - cur = NULL; - } + pool_put(&pf_tree_pl, cur); + pool_put(&pf_tree_pl, peer); pf_status.fcounters[FCNT_STATE_REMOVALS]++; pf_status.states--; - } else - cur = pf_tree_next(cur); + } } } @@ -1328,8 +1084,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) /* * Rules are about to get freed, clear rule pointers in states */ - for (n = pf_tree_first(tree_ext_gwy); n != NULL; - n = pf_tree_next(n)) + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) n->state->rule.ptr = NULL; old_rules = pf_rules_active; pf_rules_active = pf_rules_inactive; @@ -1470,8 +1225,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (pcr->action == PF_CHANGE_REMOVE) { struct pf_tree_node *n; - for (n = pf_tree_first(tree_ext_gwy); n != NULL; - n = pf_tree_next(n)) + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) if (n->state->rule.ptr == oldrule) n->state->rule.ptr = NULL; TAILQ_REMOVE(pf_rules_active, oldrule, entries); @@ -2196,8 +1950,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) struct pf_tree_node *n; s = splsoftnet(); - for (n = pf_tree_first(tree_ext_gwy); n != NULL; - n = pf_tree_next(n)) + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) n->state->expire = 0; pf_purge_expired_states(); pf_status.states = 0; @@ -2213,8 +1966,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) int killed = 0; s = splsoftnet(); - for (n = pf_tree_first(tree_ext_gwy); n != NULL; - n = pf_tree_next(n)) { + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { st = n->state; if ((!psk->psk_af || st->af == psk->psk_af) && (!psk->psk_proto || psk->psk_proto == st->proto) && @@ -2256,7 +2008,10 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) state->expire += state->creation; state->packets = 0; state->bytes = 0; - pf_insert_state(state); + if (pf_insert_state(state)) { + pool_put(&pf_state_pl, state); + error = ENOMEM; + } splx(s); } @@ -2268,9 +2023,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) nr = 0; s = splsoftnet(); - n = pf_tree_first(tree_ext_gwy); - while ((n != NULL) && (nr < ps->nr)) { - n = pf_tree_next(n); + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { + if (nr >= ps->nr) + break; nr++; } if (n == NULL) { @@ -2302,11 +2057,8 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) if (space == 0) { s = splsoftnet(); - n = pf_tree_first(tree_ext_gwy); - while (n != NULL) { - n = pf_tree_next(n); + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) nr++; - } splx(s); ps->ps_len = sizeof(struct pf_state) * nr; return (0); @@ -2314,10 +2066,12 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) s = splsoftnet(); p = ps->ps_states; - n = pf_tree_first(tree_ext_gwy); - while (n && (nr + 1) * sizeof(*p) <= ps->ps_len) { + RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) { int secs = time.tv_sec; + if ((nr + 1) * sizeof(*p) > ps->ps_len) + break; + bcopy(n->state, &pstore, sizeof(pstore)); if (n->state->rule.ptr == NULL) pstore.rule.nr = -1; @@ -2335,7 +2089,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) } p++; nr++; - n = pf_tree_next(n); } ps->ps_len = sizeof(struct pf_state) * nr; splx(s); @@ -2376,7 +2129,7 @@ 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 *st; - struct pf_tree_key key; + struct pf_tree_node key; int direction = pnl->direction; key.af = pnl->af; @@ -2400,9 +2153,9 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p) else { s = splsoftnet(); if (direction == PF_IN) - st = pf_find_state(tree_ext_gwy, &key); + st = pf_find_state(&tree_ext_gwy, &key); else - st = pf_find_state(tree_lan_ext, &key); + st = pf_find_state(&tree_lan_ext, &key); if (st != NULL) { if (direction == PF_IN) { PF_ACPY(&pnl->rsaddr, &st->lan.addr, @@ -3422,6 +3175,7 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, if (s == NULL) { if (nport && nat != NULL) pf_put_sport(IPPROTO_TCP, nport); + REASON_SET(&reason, PFRES_MEMORY); return (PF_DROP); } @@ -3485,7 +3239,13 @@ pf_test_tcp(struct pf_rule **rm, int direction, struct ifnet *ifp, s->expire = s->creation + pftm_tcp_first_packet; s->packets = 1; s->bytes = pd->tot_len; - pf_insert_state(s); + if (pf_insert_state(s)) { + if (nport && nat != NULL) + pf_put_sport(IPPROTO_TCP, nport); + REASON_SET(&reason, PFRES_MEMORY); + pool_put(&pf_state_pl, s); + return (PF_DROP); + } } /* copy back packet headers if we performed NAT operations */ @@ -3711,7 +3471,13 @@ pf_test_udp(struct pf_rule **rm, int direction, struct ifnet *ifp, s->expire = s->creation + pftm_udp_first_packet; s->packets = 1; s->bytes = pd->tot_len; - pf_insert_state(s); + if (pf_insert_state(s)) { + if (nport && nat != NULL) + pf_put_sport(IPPROTO_UDP, nport); + REASON_SET(&reason, PFRES_MEMORY); + pool_put(&pf_state_pl, s); + return (PF_DROP); + } } /* copy back packet headers if we performed NAT operations */ @@ -3963,7 +3729,11 @@ pf_test_icmp(struct pf_rule **rm, int direction, struct ifnet *ifp, s->expire = s->creation + pftm_icmp_first_packet; s->packets = 1; s->bytes = pd->tot_len; - pf_insert_state(s); + if (pf_insert_state(s)) { + REASON_SET(&reason, PFRES_MEMORY); + pool_put(&pf_state_pl, s); + return (PF_DROP); + } } #ifdef INET6 @@ -3986,6 +3756,8 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, struct pf_rdr *rdr = NULL; struct pf_addr *saddr = pd->src, *daddr = pd->dst, baddr; u_int8_t af = pd->af; + u_short reason; + *rm = NULL; @@ -4101,8 +3873,6 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, } if (*rm != NULL) { - u_short reason; - (*rm)->packets++; (*rm)->bytes += pd->tot_len; REASON_SET(&reason, PFRES_MATCH); @@ -4163,7 +3933,14 @@ pf_test_other(struct pf_rule **rm, int direction, struct ifnet *ifp, s->expire = s->creation + pftm_other_first_packet; s->packets = 1; s->bytes = pd->tot_len; - pf_insert_state(s); + if (pf_insert_state(s)) { + REASON_SET(&reason, PFRES_MEMORY); + if (*rm && (*rm)->log) + PFLOG_PACKET(ifp, h, m, af, direction, reason, + *rm); + pool_put(&pf_state_pl, s); + return (PF_DROP); + } } return (PF_PASS); @@ -4234,24 +4011,24 @@ int pf_test_state_tcp(struct pf_state **state, int direction, struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { - struct pf_tree_key key; + struct pf_tree_node key; struct tcphdr *th = pd->hdr.tcp; u_int16_t win = ntohs(th->th_win); u_int32_t ack, end, seq; int ackskew; struct pf_state_peer *src, *dst; - key.af = pd->af; - key.proto = IPPROTO_TCP; + key.af = pd->af; + key.proto = IPPROTO_TCP; PF_ACPY(&key.addr[0], pd->src, key.af); PF_ACPY(&key.addr[1], pd->dst, key.af); key.port[0] = th->th_sport; key.port[1] = th->th_dport; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); @@ -4514,20 +4291,20 @@ pf_test_state_udp(struct pf_state **state, int direction, struct ifnet *ifp, struct mbuf *m, int ipoff, int off, void *h, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_tree_key key; + struct pf_tree_node key; struct udphdr *uh = pd->hdr.udp; - key.af = pd->af; - key.proto = IPPROTO_UDP; + key.af = pd->af; + key.proto = IPPROTO_UDP; PF_ACPY(&key.addr[0], pd->src, key.af); PF_ACPY(&key.addr[1], pd->dst, key.af); key.port[0] = pd->hdr.udp->uh_sport; key.port[1] = pd->hdr.udp->uh_dport; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); @@ -4619,19 +4396,19 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, * ICMP query/reply message not related to a TCP/UDP packet. * Search for an ICMP state. */ - struct pf_tree_key key; + struct pf_tree_node key; - key.af = pd->af; - key.proto = pd->proto; + key.af = pd->af; + key.proto = pd->proto; PF_ACPY(&key.addr[0], saddr, key.af); PF_ACPY(&key.addr[1], daddr, key.af); key.port[0] = icmpid; key.port[1] = icmpid; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); @@ -4781,7 +4558,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, case IPPROTO_TCP: { struct tcphdr th; u_int32_t seq; - struct pf_tree_key key; + struct pf_tree_node key; struct pf_state_peer *src, *dst; /* @@ -4796,16 +4573,16 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, } key.af = pd2.af; - key.proto = IPPROTO_TCP; + key.proto = IPPROTO_TCP; PF_ACPY(&key.addr[0], pd2.dst, pd2.af); key.port[0] = th.th_dport; PF_ACPY(&key.addr[1], pd2.src, pd2.af); key.port[1] = th.th_sport; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); @@ -4875,7 +4652,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, } case IPPROTO_UDP: { struct udphdr uh; - struct pf_tree_key key; + struct pf_tree_node key; if (!pf_pull_hdr(m, off2, &uh, sizeof(uh), NULL, NULL, pd2.af)) { @@ -4885,16 +4662,16 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, } key.af = pd2.af; - key.proto = IPPROTO_UDP; + key.proto = IPPROTO_UDP; PF_ACPY(&key.addr[0], pd2.dst, pd2.af); key.port[0] = uh.uh_dport; PF_ACPY(&key.addr[1], pd2.src, pd2.af); key.port[1] = uh.uh_sport; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); @@ -4940,7 +4717,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, #ifdef INET case IPPROTO_ICMP: { struct icmp iih; - struct pf_tree_key key; + struct pf_tree_node key; if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, NULL, NULL, pd2.af)) { @@ -4950,16 +4727,16 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, } key.af = pd2.af; - key.proto = IPPROTO_ICMP; + key.proto = IPPROTO_ICMP; PF_ACPY(&key.addr[0], pd2.dst, pd2.af); key.port[0] = iih.icmp_id; PF_ACPY(&key.addr[1], pd2.src, pd2.af); key.port[1] = iih.icmp_id; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); @@ -4992,7 +4769,7 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, #ifdef INET6 case IPPROTO_ICMPV6: { struct icmp6_hdr iih; - struct pf_tree_key key; + struct pf_tree_node key; if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN, NULL, NULL, pd2.af)) { @@ -5002,16 +4779,16 @@ pf_test_state_icmp(struct pf_state **state, int direction, struct ifnet *ifp, } key.af = pd2.af; - key.proto = IPPROTO_ICMPV6; + key.proto = IPPROTO_ICMPV6; PF_ACPY(&key.addr[0], pd2.dst, pd2.af); key.port[0] = iih.icmp6_id; PF_ACPY(&key.addr[1], pd2.src, pd2.af); key.port[1] = iih.icmp6_id; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); @@ -5055,19 +4832,19 @@ pf_test_state_other(struct pf_state **state, int direction, struct ifnet *ifp, struct pf_pdesc *pd) { struct pf_state_peer *src, *dst; - struct pf_tree_key key; + struct pf_tree_node key; - key.af = pd->af; - key.proto = pd->proto; + key.af = pd->af; + key.proto = pd->proto; PF_ACPY(&key.addr[0], pd->src, key.af); PF_ACPY(&key.addr[1], pd->dst, key.af); key.port[0] = 0; key.port[1] = 0; if (direction == PF_IN) - *state = pf_find_state(tree_ext_gwy, &key); + *state = pf_find_state(&tree_ext_gwy, &key); else - *state = pf_find_state(tree_lan_ext, &key); + *state = pf_find_state(&tree_lan_ext, &key); if (*state == NULL) return (PF_DROP); diff --git a/sys/net/pf_norm.c b/sys/net/pf_norm.c index 9fc60f91a06..3fb67ef6a95 100644 --- a/sys/net/pf_norm.c +++ b/sys/net/pf_norm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf_norm.c,v 1.28 2002/05/21 08:42:35 espie Exp $ */ +/* $OpenBSD: pf_norm.c,v 1.29 2002/06/07 21:14:02 frantzen Exp $ */ /* * Copyright 2001 Niels Provos <provos@citi.umich.edu> @@ -65,6 +65,7 @@ struct pf_frent { #define PFFRAG_SEENLAST 0x0001 /* Seen the last fragment for this */ struct pf_fragment { + RB_ENTRY(pf_fragment) fr_entry; TAILQ_ENTRY(pf_fragment) frag_next; struct in_addr fr_src; struct in_addr fr_dst; @@ -78,8 +79,14 @@ struct pf_fragment { TAILQ_HEAD(pf_fragqueue, pf_fragment) pf_fragqueue; +static __inline int pf_frag_compare(struct pf_fragment *, + struct pf_fragment *); +RB_HEAD(pf_frag_tree, pf_fragment) pf_frag_tree; +RB_PROTOTYPE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); +RB_GENERATE(pf_frag_tree, pf_fragment, fr_entry, pf_frag_compare); + /* Private prototypes */ -void pf_ip2key(struct pf_tree_key *, struct ip *); +void pf_ip2key(struct pf_fragment *, struct ip *); void pf_remove_fragment(struct pf_fragment *); void pf_flush_fragments(void); void pf_free_fragment(struct pf_fragment *); @@ -112,7 +119,6 @@ int pf_normalize_tcpopt(struct pf_rule *, struct mbuf *, #endif /* Globals */ -struct pf_tree_node *tree_fragment; struct pool pf_frent_pl, pf_frag_pl; int pf_nfrents; extern int pftm_frag; /* Fragment expire timeout */ @@ -131,6 +137,25 @@ pf_normalize_init(void) TAILQ_INIT(&pf_fragqueue); } +static __inline int +pf_frag_compare(struct pf_fragment *a, struct pf_fragment *b) +{ + int diff; + if ((diff = a->fr_id - b->fr_id)) + return (diff); + else if ((diff = a->fr_p - b->fr_p)) + return (diff); + else if (a->fr_src.s_addr < b->fr_src.s_addr) + return (-1); + else if (a->fr_src.s_addr > b->fr_src.s_addr) + return (1); + else if (a->fr_dst.s_addr < b->fr_dst.s_addr) + return (-1); + else if (a->fr_dst.s_addr > b->fr_dst.s_addr) + return (1); + return 0; +} + void pf_purge_expired_fragments(void) { @@ -141,7 +166,7 @@ pf_purge_expired_fragments(void) if (frag->fr_timeout > expire) break; - DPFPRINTF(("expiring %p\n", frag)); + DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag)); pf_free_fragment(frag); } } @@ -188,26 +213,23 @@ pf_free_fragment(struct pf_fragment *frag) } void -pf_ip2key(struct pf_tree_key *key, struct ip *ip) +pf_ip2key(struct pf_fragment *key, struct ip *ip) { - key->proto = ip->ip_p; - key->af = AF_INET; - key->addr[0].addr32[0] = ip->ip_src.s_addr; - key->addr[1].addr32[0] = ip->ip_dst.s_addr; - key->port[0] = ip->ip_id; - key->port[1] = 0; + key->fr_p = ip->ip_p; + key->fr_id = ip->ip_id; + key->fr_src.s_addr = ip->ip_src.s_addr; + key->fr_dst.s_addr = ip->ip_dst.s_addr; } struct pf_fragment * pf_find_fragment(struct ip *ip) { - struct pf_tree_key key; + struct pf_fragment key; struct pf_fragment *frag; pf_ip2key(&key, ip); - frag = (struct pf_fragment *)pf_find_state(tree_fragment, &key); - + frag = RB_FIND(pf_frag_tree, &pf_frag_tree, &key); if (frag != NULL) { frag->fr_timeout = time.tv_sec; TAILQ_REMOVE(&pf_fragqueue, frag, frag_next); @@ -222,19 +244,8 @@ pf_find_fragment(struct ip *ip) void pf_remove_fragment(struct pf_fragment *frag) { - struct pf_tree_key key; - - /* XXX keep in sync with pf_ip2key */ - key.proto = frag->fr_p; - key.af = AF_INET; - key.addr[0].addr32[0] = frag->fr_src.s_addr; - key.addr[1].addr32[0] = frag->fr_dst.s_addr; - key.port[0] = frag->fr_id; - key.port[1] = 0; - - pf_tree_remove(&tree_fragment, NULL, &key); + RB_REMOVE(pf_frag_tree, &pf_frag_tree, frag); TAILQ_REMOVE(&pf_fragqueue, frag, frag_next); - pool_put(&pf_frag_pl, frag); } @@ -256,8 +267,6 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment *frag, /* Create a new reassembly queue for this packet */ if (frag == NULL) { - struct pf_tree_key key; - frag = pool_get(&pf_frag_pl, PR_NOWAIT); if (frag == NULL) { pf_flush_fragments(); @@ -275,10 +284,7 @@ pf_reassemble(struct mbuf **m0, struct pf_fragment *frag, frag->fr_timeout = time.tv_sec; LIST_INIT(&frag->fr_queue); - pf_ip2key(&key, frent->fr_ip); - - pf_tree_insert(&tree_fragment, NULL, &key, - (struct pf_state *)frag); + RB_INSERT(pf_frag_tree, &pf_frag_tree, frag); TAILQ_INSERT_HEAD(&pf_fragqueue, frag, frag_next); /* We do not have a previous fragment */ @@ -522,7 +528,7 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct ifnet *ifp, u_short *reason) frent->fr_m = m; /* Might return a completely reassembled mbuf, or NULL */ - DPFPRINTF(("reass frag %d @ %d\n", h->ip_id, fragoff)); + DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max)); *m0 = m = pf_reassemble(m0, frag, frent, mff); if (m == NULL) diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h index 14faf009c44..5f500e768e9 100644 --- a/sys/net/pfvar.h +++ b/sys/net/pfvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pfvar.h,v 1.73 2002/05/19 22:31:28 deraadt Exp $ */ +/* $OpenBSD: pfvar.h,v 1.74 2002/06/07 21:14:02 frantzen Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -35,6 +35,7 @@ #include <sys/types.h> #include <sys/queue.h> +#include <sys/tree.h> enum { PF_IN=0, PF_OUT=1 }; enum { PF_PASS=0, PF_DROP=1, PF_SCRUB=2 }; @@ -292,7 +293,6 @@ struct pf_state_peer { }; struct pf_state { - TAILQ_ENTRY(pf_state) entries; struct pf_state_host lan; struct pf_state_host gwy; struct pf_state_host ext; @@ -313,6 +313,16 @@ struct pf_state { u_int8_t allow_opts; }; +struct pf_tree_node { + RB_ENTRY(pf_tree_node) entry; + struct pf_state *state; + struct pf_addr addr[2]; + u_int16_t port[2]; + u_int8_t af; + u_int8_t proto; +}; + + struct pf_nat { char ifname[IFNAMSIZ]; struct ifnet *ifp; @@ -365,13 +375,6 @@ struct pf_rdr { u_int8_t no; }; -struct pf_tree_key { - struct pf_addr addr[2]; - u_int16_t port[2]; - u_int8_t proto; - u_int8_t af; -}; - TAILQ_HEAD(pf_rulequeue, pf_rule); struct pf_pdesc { @@ -617,14 +620,6 @@ int pf_test(int, struct ifnet *, struct mbuf **); int pf_test6(int, struct ifnet *, struct mbuf **); #endif /* INET */ -struct pf_tree_node; -struct pf_state - *pf_find_state(struct pf_tree_node *, struct pf_tree_key *); -int pf_tree_insert(struct pf_tree_node **, struct pf_tree_node *, - struct pf_tree_key *, struct pf_state *); -int pf_tree_remove(struct pf_tree_node **, struct pf_tree_node *, - struct pf_tree_key *); - int pflog_packet(struct ifnet *, struct mbuf *, int, u_short, u_short, struct pf_rule *); int pf_match_addr(u_int8_t, struct pf_addr *, struct pf_addr *, |