diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2013-06-04 19:08:00 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2013-06-04 19:08:00 +0000 |
commit | cfc344e2f6251c9ba4a4d9ae67687414c1925c78 (patch) | |
tree | 75479fbc88dce37e9eaa7af5a1bb7948907c9e0b /sys/net/pf.c | |
parent | baaaf98da60f3ff53a511f3ebf0725e2092010b6 (diff) |
fold pf_test_state_{tcp,udp,other} into one pf_test_state.
the _icmp variant stays because it is completely different.
factor out the synproxy code into a new pf_synproxy() for readability.
pf_setup_pdesc sets us up with access to ports, cksum etc in a protocol
independent matter, so we don't need many protocol switches here.
tcp and udp were almost identical, the _other case changes significantly -
not too unlikely this fixes a subtle bug or two in that case.
ok ryan benno bluhm mikeb
Diffstat (limited to 'sys/net/pf.c')
-rw-r--r-- | sys/net/pf.c | 347 |
1 files changed, 101 insertions, 246 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c index c2c690dc674..55b4ffd01ac 100644 --- a/sys/net/pf.c +++ b/sys/net/pf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pf.c,v 1.832 2013/06/04 19:03:11 henning Exp $ */ +/* $OpenBSD: pf.c,v 1.833 2013/06/04 19:07:59 henning Exp $ */ /* * Copyright (c) 2001 Daniel Hartmeier @@ -198,17 +198,15 @@ int pf_tcp_track_full(struct pf_pdesc *, int pf_tcp_track_sloppy(struct pf_pdesc *, struct pf_state_peer *, struct pf_state_peer *, struct pf_state **, u_short *); -int pf_test_state_tcp(struct pf_pdesc *, - struct pf_state **, u_short *); -int pf_test_state_udp( struct pf_pdesc *, - struct pf_state **); +static __inline int pf_synproxy(struct pf_pdesc *, struct pf_state **, + u_short *); +int pf_test_state(struct pf_pdesc *, struct pf_state **, + u_short *); int pf_icmp_state_lookup(struct pf_pdesc *, struct pf_state_key_cmp *, struct pf_state **, u_int16_t, u_int16_t, int, int *, int, int); int pf_test_state_icmp(struct pf_pdesc *, struct pf_state **, u_short *); -int pf_test_state_other( struct pf_pdesc *, - struct pf_state **); u_int8_t pf_get_wscale(struct pf_pdesc *); u_int16_t pf_get_mss(struct pf_pdesc *); u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t, int, @@ -4410,37 +4408,14 @@ pf_tcp_track_sloppy(struct pf_pdesc *pd, struct pf_state_peer *src, return (PF_PASS); } -int -pf_test_state_tcp(struct pf_pdesc *pd, struct pf_state **state, u_short *reason) +static __inline int +pf_synproxy(struct pf_pdesc *pd, struct pf_state **state, u_short *reason) { - struct pf_state_key_cmp key; - struct tcphdr *th = pd->hdr.tcp; - int copyback = 0; - struct pf_state_peer *src, *dst; - struct pf_state_key *sk; - int action = PF_PASS; - - key.af = pd->af; - key.proto = IPPROTO_TCP; - key.rdomain = pd->rdomain; - PF_ACPY(&key.addr[pd->sidx], pd->src, key.af); - PF_ACPY(&key.addr[pd->didx], pd->dst, key.af); - key.port[pd->sidx] = th->th_sport; - key.port[pd->didx] = th->th_dport; - - STATE_LOOKUP(pd->kif, &key, pd->dir, *state, pd->m); - - if (pd->dir == (*state)->direction) { - src = &(*state)->src; - dst = &(*state)->dst; - } else { - src = &(*state)->dst; - dst = &(*state)->src; - } - - sk = (*state)->key[pd->didx]; + struct pf_state_key *sk = (*state)->key[pd->didx]; if ((*state)->src.state == PF_TCPS_PROXY_SRC) { + struct tcphdr *th = pd->hdr.tcp; + if (pd->dir != (*state)->direction) { REASON_SET(reason, PFRES_SYNPROXY); return (PF_SYNPROXY_DROP); @@ -4470,6 +4445,8 @@ pf_test_state_tcp(struct pf_pdesc *pd, struct pf_state **state, u_short *reason) (*state)->src.state = PF_TCPS_PROXY_DST; } if ((*state)->src.state == PF_TCPS_PROXY_DST) { + struct tcphdr *th = pd->hdr.tcp; + if (pd->dir == (*state)->direction) { if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) || (ntohl(th->th_ack) != (*state)->src.seqhi + 1) || @@ -4522,102 +4499,24 @@ pf_test_state_tcp(struct pf_pdesc *pd, struct pf_state **state, u_short *reason) return (PF_SYNPROXY_DROP); } } - - if (((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) && - dst->state >= TCPS_FIN_WAIT_2 && - src->state >= TCPS_FIN_WAIT_2) { - if (pf_status.debug >= LOG_NOTICE) { - log(LOG_NOTICE, "pf: state reuse "); - pf_print_state(*state); - pf_print_flags(th->th_flags); - addlog("\n"); - } - /* XXX make sure it's the same direction ?? */ - (*state)->src.state = (*state)->dst.state = TCPS_CLOSED; - pf_unlink_state(*state); - *state = NULL; - return (PF_DROP); - } - - if ((*state)->state_flags & PFSTATE_SLOPPY) { - if (pf_tcp_track_sloppy(pd, src, dst, state, reason) == PF_DROP) - return (PF_DROP); - } else { - int ret; - - if (PF_REVERSED_KEY((*state)->key, pd->af)) - ret = pf_tcp_track_full(pd, dst, src, state, - reason, ©back); - else - ret = pf_tcp_track_full(pd, src, dst, state, - reason, ©back); - if (ret == PF_DROP) - return (PF_DROP); - } - - /* translate source/destination address, if necessary */ - if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { - struct pf_state_key *nk; - int afto, sidx, didx; - - if (PF_REVERSED_KEY((*state)->key, pd->af)) - nk = (*state)->key[pd->sidx]; - else - nk = (*state)->key[pd->didx]; - - afto = pd->af != nk->af; - sidx = afto ? pd->didx : pd->sidx; - didx = afto ? pd->sidx : pd->didx; - - if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) || - nk->port[sidx] != th->th_sport) - pf_change_ap(pd->src, &th->th_sport, &th->th_sum, - &nk->addr[sidx], nk->port[sidx], 0, pd->af, nk->af); - - if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || - pd->rdomain != nk->rdomain) - pd->destchg = 1; - if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || - nk->port[didx] != th->th_dport) - pf_change_ap(pd->dst, &th->th_dport, &th->th_sum, - &nk->addr[didx], nk->port[didx], 0, pd->af, - nk->af); - pd->m->m_pkthdr.rdomain = nk->rdomain; - -#if INET && INET6 - if (afto) { - PF_ACPY(&pd->nsaddr, &nk->addr[sidx], nk->af); - PF_ACPY(&pd->ndaddr, &nk->addr[didx], nk->af); - pd->naf = nk->af; - action = PF_AFRT; - } -#endif /* INET && INET6 */ - - copyback = 1; - } - - /* Copyback sequence modulation or stateful scrub changes if needed */ - if (copyback) - m_copyback(pd->m, pd->off, sizeof(*th), th, M_NOWAIT); - - return (action); + return (PF_PASS); } int -pf_test_state_udp(struct pf_pdesc *pd, struct pf_state **state) +pf_test_state(struct pf_pdesc *pd, struct pf_state **state, u_short *reason) { - struct pf_state_peer *src, *dst; struct pf_state_key_cmp key; - struct udphdr *uh = pd->hdr.udp; + int copyback = 0; + struct pf_state_peer *src, *dst; int action = PF_PASS; key.af = pd->af; - key.proto = IPPROTO_UDP; + key.proto = pd->virtual_proto; key.rdomain = pd->rdomain; PF_ACPY(&key.addr[pd->sidx], pd->src, key.af); PF_ACPY(&key.addr[pd->didx], pd->dst, key.af); - key.port[pd->sidx] = uh->uh_sport; - key.port[pd->didx] = uh->uh_dport; + key.port[pd->sidx] = pd->osport; + key.port[pd->didx] = pd->odport; STATE_LOOKUP(pd->kif, &key, pd->dir, *state, pd->m); @@ -4629,18 +4528,74 @@ pf_test_state_udp(struct pf_pdesc *pd, struct pf_state **state) dst = &(*state)->src; } - /* update states */ - if (src->state < PFUDPS_SINGLE) - src->state = PFUDPS_SINGLE; - if (dst->state == PFUDPS_SINGLE) - dst->state = PFUDPS_MULTIPLE; + switch (pd->virtual_proto) { + case IPPROTO_TCP: + if ((action = pf_synproxy(pd, state, reason)) != PF_PASS) + return (action); + if (((pd->hdr.tcp->th_flags & (TH_SYN|TH_ACK)) == TH_SYN) && + dst->state >= TCPS_FIN_WAIT_2 && + src->state >= TCPS_FIN_WAIT_2) { + if (pf_status.debug >= LOG_NOTICE) { + log(LOG_NOTICE, "pf: state reuse "); + pf_print_state(*state); + pf_print_flags(pd->hdr.tcp->th_flags); + addlog("\n"); + } + /* XXX make sure it's the same direction ?? */ + (*state)->src.state = (*state)->dst.state = TCPS_CLOSED; + pf_unlink_state(*state); + *state = NULL; + return (PF_DROP); + } - /* update expire time */ - (*state)->expire = time_uptime; - if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE) - (*state)->timeout = PFTM_UDP_MULTIPLE; - else - (*state)->timeout = PFTM_UDP_SINGLE; + if ((*state)->state_flags & PFSTATE_SLOPPY) { + if (pf_tcp_track_sloppy(pd, src, dst, state, reason) == + PF_DROP) + return (PF_DROP); + } else { + int ret; + + if (PF_REVERSED_KEY((*state)->key, pd->af)) + ret = pf_tcp_track_full(pd, dst, src, state, + reason, ©back); + else + ret = pf_tcp_track_full(pd, src, dst, state, + reason, ©back); + if (ret == PF_DROP) + return (PF_DROP); + } + break; + case IPPROTO_UDP: + /* update states */ + if (src->state < PFUDPS_SINGLE) + src->state = PFUDPS_SINGLE; + if (dst->state == PFUDPS_SINGLE) + dst->state = PFUDPS_MULTIPLE; + + /* update expire time */ + (*state)->expire = time_uptime; + if (src->state == PFUDPS_MULTIPLE && + dst->state == PFUDPS_MULTIPLE) + (*state)->timeout = PFTM_UDP_MULTIPLE; + else + (*state)->timeout = PFTM_UDP_SINGLE; + break; + default: + /* update states */ + if (src->state < PFOTHERS_SINGLE) + src->state = PFOTHERS_SINGLE; + if (dst->state == PFOTHERS_SINGLE) + dst->state = PFOTHERS_MULTIPLE; + + /* update expire time */ + (*state)->expire = time_uptime; + if (src->state == PFOTHERS_MULTIPLE && + dst->state == PFOTHERS_MULTIPLE) + (*state)->timeout = PFTM_OTHER_MULTIPLE; + else + (*state)->timeout = PFTM_OTHER_SINGLE; + break; + } /* translate source/destination address, if necessary */ if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { @@ -4657,17 +4612,19 @@ pf_test_state_udp(struct pf_pdesc *pd, struct pf_state **state) didx = afto ? pd->sidx : pd->didx; if (afto || PF_ANEQ(pd->src, &nk->addr[sidx], pd->af) || - nk->port[sidx] != uh->uh_sport) - pf_change_ap(pd->src, &uh->uh_sport, &uh->uh_sum, - &nk->addr[sidx], nk->port[sidx], 1, pd->af, nk->af); + nk->port[sidx] != pd->osport) + pf_change_ap(pd->src, pd->sport, pd->pcksum, + &nk->addr[sidx], nk->port[sidx], + pd->virtual_proto == IPPROTO_UDP, pd->af, nk->af); if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || pd->rdomain != nk->rdomain) pd->destchg = 1; if (afto || PF_ANEQ(pd->dst, &nk->addr[didx], pd->af) || - nk->port[didx] != uh->uh_dport) - pf_change_ap(pd->dst, &uh->uh_dport, &uh->uh_sum, - &nk->addr[didx], nk->port[didx], 1, pd->af, nk->af); + nk->port[didx] != pd->odport) + pf_change_ap(pd->dst, pd->dport, pd->pcksum, + &nk->addr[didx], nk->port[didx], + pd->virtual_proto == IPPROTO_UDP, pd->af, nk->af); pd->m->m_pkthdr.rdomain = nk->rdomain; #if INET && INET6 @@ -4679,9 +4636,12 @@ pf_test_state_udp(struct pf_pdesc *pd, struct pf_state **state) } #endif /* INET && INET6 */ - m_copyback(pd->m, pd->off, sizeof(*uh), uh, M_NOWAIT); + copyback = 1; } + if (copyback && pd->hdrlen > 0) + m_copyback(pd->m, pd->off, pd->hdrlen, pd->hdr.any, M_NOWAIT); + return (action); } @@ -5558,111 +5518,6 @@ pf_test_state_icmp(struct pf_pdesc *pd, struct pf_state **state, } } -int -pf_test_state_other(struct pf_pdesc *pd, struct pf_state **state) -{ - struct pf_state_peer *src, *dst; - struct pf_state_key_cmp key; - int action = PF_PASS; - - key.af = pd->af; - key.proto = pd->proto; - key.rdomain = pd->rdomain; - PF_ACPY(&key.addr[pd->sidx], pd->src, key.af); - PF_ACPY(&key.addr[pd->didx], pd->dst, key.af); - key.port[0] = key.port[1] = 0; - - STATE_LOOKUP(pd->kif, &key, pd->dir, *state, pd->m); - - if (pd->dir == (*state)->direction) { - src = &(*state)->src; - dst = &(*state)->dst; - } else { - src = &(*state)->dst; - dst = &(*state)->src; - } - - /* update states */ - if (src->state < PFOTHERS_SINGLE) - src->state = PFOTHERS_SINGLE; - if (dst->state == PFOTHERS_SINGLE) - dst->state = PFOTHERS_MULTIPLE; - - /* update expire time */ - (*state)->expire = time_uptime; - if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE) - (*state)->timeout = PFTM_OTHER_MULTIPLE; - else - (*state)->timeout = PFTM_OTHER_SINGLE; - - /* translate source/destination address, if necessary */ - if ((*state)->key[PF_SK_WIRE] != (*state)->key[PF_SK_STACK]) { - struct pf_state_key *nk; - int afto; - - if (PF_REVERSED_KEY((*state)->key, pd->af)) - nk = (*state)->key[pd->sidx]; - else - nk = (*state)->key[pd->didx]; - - afto = pd->af != nk->af; - - KASSERT(nk); - KASSERT(pd); - KASSERT(pd->src); - KASSERT(pd->dst); - - switch (pd->af) { -#ifdef INET - case AF_INET: - if (!afto && - PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET)) - pf_change_a(&pd->src->v4.s_addr, NULL, - nk->addr[pd->sidx].v4.s_addr, - 0); - if (!afto && - PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET)) { - pf_change_a(&pd->dst->v4.s_addr, NULL, - nk->addr[pd->didx].v4.s_addr, - 0); - pd->destchg = 1; - } - break; -#endif /* INET */ -#ifdef INET6 - case AF_INET6: - if (!afto && - PF_ANEQ(pd->src, &nk->addr[pd->sidx], AF_INET6)) - PF_ACPY(pd->src, &nk->addr[pd->sidx], pd->af); - - if (!afto && - PF_ANEQ(pd->dst, &nk->addr[pd->didx], AF_INET6)) { - PF_ACPY(pd->dst, &nk->addr[pd->didx], pd->af); - pd->destchg = 1; - } - break; -#endif /* INET6 */ - } - if (pd->rdomain != nk->rdomain) - pd->destchg = 1; - -#if INET && INET6 - if (afto) { - PF_ACPY(&pd->nsaddr, - &nk->addr[afto ? pd->didx : pd->sidx], nk->af); - PF_ACPY(&pd->ndaddr, - &nk->addr[afto ? pd->sidx : pd->didx], nk->af); - pd->destchg = 1; - pd->naf = nk->af; - action = PF_AFRT; - } -#endif /* INET && INET6 */ - - pd->m->m_pkthdr.rdomain = nk->rdomain; - } - return (action); -} - /* * ipoff and off are measured from the start of the mbuf chain. * h must be at "ipoff" on the mbuf chain. @@ -6794,7 +6649,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, struct mbuf **m0, action = pf_normalize_tcp(&pd); if (action == PF_DROP) goto done; - action = pf_test_state_tcp(&pd, &s, &reason); + action = pf_test_state(&pd, &s, &reason); if (action == PF_PASS || action == PF_AFRT) { #if NPFSYNC > 0 pfsync_update_state(s); @@ -6815,7 +6670,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, struct mbuf **m0, } case IPPROTO_UDP: { - action = pf_test_state_udp(&pd, &s); + action = pf_test_state(&pd, &s, &reason); if (action == PF_PASS || action == PF_AFRT) { #if NPFSYNC > 0 pfsync_update_state(s); @@ -6873,7 +6728,7 @@ pf_test(sa_family_t af, int fwdir, struct ifnet *ifp, struct mbuf **m0, #endif /* INET6 */ default: - action = pf_test_state_other(&pd, &s); + action = pf_test_state(&pd, &s, &reason); if (action == PF_PASS || action == PF_AFRT) { #if NPFSYNC > 0 pfsync_update_state(s); |