summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/net/pf.c418
1 files changed, 220 insertions, 198 deletions
diff --git a/sys/net/pf.c b/sys/net/pf.c
index e8216a12de2..a47c9e3ffd2 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.594 2008/06/11 03:36:33 henning Exp $ */
+/* $OpenBSD: pf.c,v 1.595 2008/06/11 04:04:19 henning Exp $ */
/*
* Copyright (c) 2001 Daniel Hartmeier
@@ -179,6 +179,14 @@ int pf_test_rule(struct pf_rule **, struct pf_state **,
int, struct pfi_kif *, struct mbuf *, int,
void *, struct pf_pdesc *, struct pf_rule **,
struct pf_ruleset **, struct ifqueue *);
+static __inline int pf_create_state(struct pf_rule *, struct pf_rule *,
+ struct pf_rule *, struct pf_pdesc *,
+ struct pf_src_node *, struct pf_state_key *,
+ struct pf_state_key *, struct pf_state_key *,
+ struct pf_state_key *, struct mbuf *, int,
+ u_int16_t, u_int16_t, int *, struct pfi_kif *,
+ struct pf_state **, int, u_int16_t, u_int16_t,
+ int);
int pf_test_fragment(struct pf_rule **, int,
struct pfi_kif *, struct mbuf *, void *,
struct pf_pdesc *, struct pf_rule **,
@@ -3001,7 +3009,6 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
int asd = 0;
int match = 0;
int state_icmp = 0;
- u_int16_t mss = tcp_mssdflt;
u_int16_t sport, dport;
u_int16_t nport = 0, bport = 0;
u_int16_t bproto_sum = 0, bip_sum;
@@ -3356,221 +3363,236 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
return (PF_DROP);
}
-/* XXX state creation should be really factored out */
if (!state_icmp && (r->keep_state || nr != NULL ||
- (pd->flags & PFDESC_TCP_NORM))) {
- /* create new state */
- struct pf_state *s = NULL;
- struct pf_src_node *sn = NULL;
-
- /* check maximums */
- if (r->max_states && (r->states_cur >= r->max_states)) {
- pf_status.lcounters[LCNT_STATES]++;
- REASON_SET(&reason, PFRES_MAXSTATES);
- goto cleanup;
- }
- /* src node for filter rule */
- if ((r->rule_flag & PFRULE_SRCTRACK ||
- r->rpool.opts & PF_POOL_STICKYADDR) &&
- pf_insert_src_node(&sn, r, saddr, af) != 0) {
- REASON_SET(&reason, PFRES_SRCLIMIT);
+ (pd->flags & PFDESC_TCP_NORM)))
+ if (pf_create_state(r, nr, a, pd, nsn, skw, sks, nk, sk, m,
+ off, sport, dport, &rewrite, kif, sm, tag, bproto_sum,
+ bip_sum, hdrlen) == PF_DROP)
goto cleanup;
- }
- /* src node for translation rule */
- if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
- ((direction == PF_OUT &&
- pf_insert_src_node(&nsn, nr, &sks->addr[0], af) != 0) ||
- (direction == PF_IN &&
- pf_insert_src_node(&nsn, nr, &skw->addr[0], af) != 0))) {
- REASON_SET(&reason, PFRES_SRCLIMIT);
- goto cleanup;
- }
- s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO);
- if (s == NULL) {
- REASON_SET(&reason, PFRES_MEMORY);
+
+ /* copy back packet headers if we performed NAT operations */
+ if (rewrite)
+ m_copyback(m, off, hdrlen, pd->hdr.any);
+
+ return (PF_PASS);
+
cleanup:
- if (sn != NULL && sn->states == 0 && sn->expire == 0) {
- RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, sn);
- }
- if (nsn != sn && nsn != NULL && nsn->states == 0 &&
- nsn->expire == 0) {
- RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
- pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
- pf_status.src_nodes--;
- pool_put(&pf_src_tree_pl, nsn);
- }
- if (sk != NULL)
- pool_put(&pf_state_key_pl, sk);
- if (nk != NULL)
- pool_put(&pf_state_key_pl, nk);
- return (PF_DROP);
- }
- s->rule.ptr = r;
- s->nat_rule.ptr = nr;
- s->anchor.ptr = a;
- STATE_INC_COUNTERS(s);
- if (r->allow_opts)
- s->state_flags |= PFSTATE_ALLOWOPTS;
- if (r->rule_flag & PFRULE_STATESLOPPY)
- s->state_flags |= PFSTATE_SLOPPY;
- s->log = r->log & PF_LOG_ALL;
- if (nr != NULL)
- s->log |= nr->log & PF_LOG_ALL;
- switch (pd->proto) {
- case IPPROTO_TCP:
- s->src.seqlo = ntohl(th->th_seq);
- s->src.seqhi = s->src.seqlo + pd->p_len + 1;
- if ((th->th_flags & (TH_SYN|TH_ACK)) ==
- TH_SYN && r->keep_state == PF_STATE_MODULATE) {
- /* Generate sequence number modulator */
- if ((s->src.seqdiff = pf_tcp_iss(pd) -
- s->src.seqlo) == 0)
- s->src.seqdiff = 1;
- pf_change_a(&th->th_seq, &th->th_sum,
- htonl(s->src.seqlo + s->src.seqdiff), 0);
- rewrite = 1;
- } else
- s->src.seqdiff = 0;
- if (th->th_flags & TH_SYN) {
- s->src.seqhi++;
- s->src.wscale = pf_get_wscale(m, off,
- th->th_off, af);
- }
- s->src.max_win = MAX(ntohs(th->th_win), 1);
- if (s->src.wscale & PF_WSCALE_MASK) {
- /* Remove scale factor from initial window */
- int win = s->src.max_win;
- win += 1 << (s->src.wscale & PF_WSCALE_MASK);
- s->src.max_win = (win - 1) >>
- (s->src.wscale & PF_WSCALE_MASK);
- }
- if (th->th_flags & TH_FIN)
- s->src.seqhi++;
- s->dst.seqhi = 1;
- s->dst.max_win = 1;
- s->src.state = TCPS_SYN_SENT;
- s->dst.state = TCPS_CLOSED;
- s->timeout = PFTM_TCP_FIRST_PACKET;
- break;
- case IPPROTO_UDP:
- s->src.state = PFUDPS_SINGLE;
- s->dst.state = PFUDPS_NO_TRAFFIC;
- s->timeout = PFTM_UDP_FIRST_PACKET;
- break;
- case IPPROTO_ICMP:
-#ifdef INET6
- case IPPROTO_ICMPV6:
-#endif
- s->timeout = PFTM_ICMP_FIRST_PACKET;
- break;
- default:
- s->src.state = PFOTHERS_SINGLE;
- s->dst.state = PFOTHERS_NO_TRAFFIC;
- s->timeout = PFTM_OTHER_FIRST_PACKET;
- }
+ if (sk != NULL)
+ pool_put(&pf_state_key_pl, sk);
+ if (nk != NULL)
+ pool_put(&pf_state_key_pl, nk);
+ return (PF_DROP);
+}
- s->creation = time_second;
- s->expire = time_second;
+static __inline int
+pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a,
+ struct pf_pdesc *pd, struct pf_src_node *nsn, struct pf_state_key *skw,
+ struct pf_state_key *sks, struct pf_state_key *nk, struct pf_state_key *sk,
+ struct mbuf *m, int off, u_int16_t sport, u_int16_t dport, int *rewrite,
+ struct pfi_kif *kif, struct pf_state **sm, int tag, u_int16_t bproto_sum,
+ u_int16_t bip_sum, int hdrlen)
+{
+ struct pf_state *s = NULL;
+ struct pf_src_node *sn = NULL;
+ struct tcphdr *th = pd->hdr.tcp;
+ u_int16_t mss = tcp_mssdflt;
+ u_short reason;
- if (sn != NULL) {
- s->src_node = sn;
- s->src_node->states++;
- }
- if (nsn != NULL) {
- if (direction == PF_IN)
- PF_ACPY(&nsn->raddr, &nk->addr[0], af);
- else
- PF_ACPY(&nsn->raddr, &nk->addr[1], af);
- s->nat_src_node = nsn;
- s->nat_src_node->states++;
+ /* check maximums */
+ if (r->max_states && (r->states_cur >= r->max_states)) {
+ pf_status.lcounters[LCNT_STATES]++;
+ REASON_SET(&reason, PFRES_MAXSTATES);
+ return (PF_DROP);
+ }
+ /* src node for filter rule */
+ if ((r->rule_flag & PFRULE_SRCTRACK ||
+ r->rpool.opts & PF_POOL_STICKYADDR) &&
+ pf_insert_src_node(&sn, r, pd->src, pd->af) != 0) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
+ goto csfailed;
+ }
+ /* src node for translation rule */
+ if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
+ ((pd->dir == PF_OUT && pf_insert_src_node(&nsn, nr,
+ &sks->addr[0], pd->af) != 0) || (pd->dir == PF_IN &&
+ pf_insert_src_node(&nsn, nr, &skw->addr[0], pd->af) != 0))) {
+ REASON_SET(&reason, PFRES_SRCLIMIT);
+ goto csfailed;
+ }
+ s = pool_get(&pf_state_pl, PR_NOWAIT | PR_ZERO);
+ if (s == NULL) {
+ REASON_SET(&reason, PFRES_MEMORY);
+ goto csfailed;
+ }
+ s->rule.ptr = r;
+ s->nat_rule.ptr = nr;
+ s->anchor.ptr = a;
+ STATE_INC_COUNTERS(s);
+ if (r->allow_opts)
+ s->state_flags |= PFSTATE_ALLOWOPTS;
+ if (r->rule_flag & PFRULE_STATESLOPPY)
+ s->state_flags |= PFSTATE_SLOPPY;
+ s->log = r->log & PF_LOG_ALL;
+ if (nr != NULL)
+ s->log |= nr->log & PF_LOG_ALL;
+ switch (pd->proto) {
+ case IPPROTO_TCP:
+ s->src.seqlo = ntohl(th->th_seq);
+ s->src.seqhi = s->src.seqlo + pd->p_len + 1;
+ if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
+ r->keep_state == PF_STATE_MODULATE) {
+ /* Generate sequence number modulator */
+ if ((s->src.seqdiff = pf_tcp_iss(pd) - s->src.seqlo) ==
+ 0)
+ s->src.seqdiff = 1;
+ pf_change_a(&th->th_seq, &th->th_sum,
+ htonl(s->src.seqlo + s->src.seqdiff), 0);
+ *rewrite = 1;
+ } else
+ s->src.seqdiff = 0;
+ if (th->th_flags & TH_SYN) {
+ s->src.seqhi++;
+ s->src.wscale = pf_get_wscale(m, off,
+ th->th_off, pd->af);
}
- if (pd->proto == IPPROTO_TCP) {
- if ((pd->flags & PFDESC_TCP_NORM) &&
- pf_normalize_tcp_init(m, off, pd, th, &s->src,
- &s->dst)) {
- REASON_SET(&reason, PFRES_MEMORY);
- pf_src_tree_remove_state(s);
- STATE_DEC_COUNTERS(s);
- pool_put(&pf_state_pl, s);
- return (PF_DROP);
- }
- if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
- pf_normalize_tcp_stateful(m, off, pd, &reason,
- th, s, &s->src, &s->dst, &rewrite)) {
- /* This really shouldn't happen!!! */
- DPFPRINTF(PF_DEBUG_URGENT,
- ("pf_normalize_tcp_stateful failed on "
- "first pkt"));
- pf_normalize_tcp_cleanup(s);
- pf_src_tree_remove_state(s);
- STATE_DEC_COUNTERS(s);
- pool_put(&pf_state_pl, s);
- return (PF_DROP);
- }
+ s->src.max_win = MAX(ntohs(th->th_win), 1);
+ if (s->src.wscale & PF_WSCALE_MASK) {
+ /* Remove scale factor from initial window */
+ int win = s->src.max_win;
+ win += 1 << (s->src.wscale & PF_WSCALE_MASK);
+ s->src.max_win = (win - 1) >>
+ (s->src.wscale & PF_WSCALE_MASK);
}
- s->direction = direction;
+ if (th->th_flags & TH_FIN)
+ s->src.seqhi++;
+ s->dst.seqhi = 1;
+ s->dst.max_win = 1;
+ s->src.state = TCPS_SYN_SENT;
+ s->dst.state = TCPS_CLOSED;
+ s->timeout = PFTM_TCP_FIRST_PACKET;
+ break;
+ case IPPROTO_UDP:
+ s->src.state = PFUDPS_SINGLE;
+ s->dst.state = PFUDPS_NO_TRAFFIC;
+ s->timeout = PFTM_UDP_FIRST_PACKET;
+ break;
+ case IPPROTO_ICMP:
+#ifdef INET6
+ case IPPROTO_ICMPV6:
+#endif
+ s->timeout = PFTM_ICMP_FIRST_PACKET;
+ break;
+ default:
+ s->src.state = PFOTHERS_SINGLE;
+ s->dst.state = PFOTHERS_NO_TRAFFIC;
+ s->timeout = PFTM_OTHER_FIRST_PACKET;
+ }
- if (sk == NULL && pf_state_key_setup(pd, nr,
- &skw, &sks, &sk, &nk, saddr, daddr, sport, dport))
- goto cleanup;
+ s->creation = time_second;
+ s->expire = time_second;
- if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, s)) {
- if (pd->proto == IPPROTO_TCP)
- pf_normalize_tcp_cleanup(s);
- REASON_SET(&reason, PFRES_STATEINS);
+ if (sn != NULL) {
+ s->src_node = sn;
+ s->src_node->states++;
+ }
+ if (nsn != NULL) {
+ if (pd->dir == PF_IN)
+ PF_ACPY(&nsn->raddr, &nk->addr[0], pd->af);
+ else
+ PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af);
+ s->nat_src_node = nsn;
+ s->nat_src_node->states++;
+ }
+ if (pd->proto == IPPROTO_TCP) {
+ if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
+ off, pd, th, &s->src, &s->dst)) {
+ REASON_SET(&reason, PFRES_MEMORY);
pf_src_tree_remove_state(s);
STATE_DEC_COUNTERS(s);
pool_put(&pf_state_pl, s);
return (PF_DROP);
- } else
- *sm = s;
-
- pf_set_rt_ifp(s, saddr); /* needs s->state_key set */
-
- if (tag > 0) {
- pf_tag_ref(tag);
- s->tag = tag;
}
- if (pd->proto == IPPROTO_TCP &&
- (th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
- r->keep_state == PF_STATE_SYNPROXY) {
- s->src.state = PF_TCPS_PROXY_SRC;
- /* undo NAT changes, if they have taken place */
- if (nr != NULL) {
- PF_ACPY(saddr, &sk->addr[pd->sidx], af);
- PF_ACPY(daddr, &sk->addr[pd->didx], af);
- if (pd->sport)
- *pd->sport = sk->port[pd->sidx];
- if (pd->dport)
- *pd->dport = sk->port[pd->didx];
- if (pd->proto_sum)
- *pd->proto_sum = bproto_sum;
- if (pd->ip_sum)
- *pd->ip_sum = bip_sum;
- m_copyback(m, off, hdrlen, pd->hdr.any);
- }
- s->src.seqhi = htonl(arc4random());
- /* Find mss option */
- mss = pf_get_mss(m, off, th->th_off, af);
- mss = pf_calc_mss(saddr, af, mss);
- mss = pf_calc_mss(daddr, af, mss);
- s->src.mss = mss;
- pf_send_tcp(r, af, daddr, saddr, th->th_dport,
- th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
- TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
- REASON_SET(&reason, PFRES_SYNPROXY);
- return (PF_SYNPROXY_DROP);
+ if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
+ pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
+ &s->src, &s->dst, rewrite)) {
+ /* This really shouldn't happen!!! */
+ DPFPRINTF(PF_DEBUG_URGENT,
+ ("pf_normalize_tcp_stateful failed on first pkt"));
+ pf_normalize_tcp_cleanup(s);
+ pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
+ pool_put(&pf_state_pl, s);
+ return (PF_DROP);
}
}
+ s->direction = pd->dir;
- /* copy back packet headers if we performed NAT operations */
- if (rewrite)
- m_copyback(m, off, hdrlen, pd->hdr.any);
+ if (sk == NULL && pf_state_key_setup(pd, nr, &skw, &sks, &sk, &nk,
+ pd->src, pd->dst, sport, dport))
+ goto csfailed;
+
+ if (pf_state_insert(BOUND_IFACE(r, kif), skw, sks, s)) {
+ if (pd->proto == IPPROTO_TCP)
+ pf_normalize_tcp_cleanup(s);
+ REASON_SET(&reason, PFRES_STATEINS);
+ pf_src_tree_remove_state(s);
+ STATE_DEC_COUNTERS(s);
+ pool_put(&pf_state_pl, s);
+ return (PF_DROP);
+ } else
+ *sm = s;
+
+ pf_set_rt_ifp(s, pd->src); /* needs s->state_key set */
+ if (tag > 0) {
+ pf_tag_ref(tag);
+ s->tag = tag;
+ }
+ if (pd->proto == IPPROTO_TCP && (th->th_flags & (TH_SYN|TH_ACK)) ==
+ TH_SYN && r->keep_state == PF_STATE_SYNPROXY) {
+ s->src.state = PF_TCPS_PROXY_SRC;
+ /* undo NAT changes, if they have taken place */
+ if (nr != NULL) {
+ PF_ACPY(pd->src, &sk->addr[pd->sidx], pd->af);
+ PF_ACPY(pd->dst, &sk->addr[pd->didx], pd->af);
+ if (pd->sport)
+ *pd->sport = sk->port[pd->sidx];
+ if (pd->dport)
+ *pd->dport = sk->port[pd->didx];
+ if (pd->proto_sum)
+ *pd->proto_sum = bproto_sum;
+ if (pd->ip_sum)
+ *pd->ip_sum = bip_sum;
+ m_copyback(m, off, hdrlen, pd->hdr.any);
+ }
+ s->src.seqhi = htonl(arc4random());
+ /* Find mss option */
+ mss = pf_get_mss(m, off, th->th_off, pd->af);
+ mss = pf_calc_mss(pd->src, pd->af, mss);
+ mss = pf_calc_mss(pd->dst, pd->af, mss);
+ s->src.mss = mss;
+ pf_send_tcp(r, pd->af, pd->dst, pd->src, th->th_dport,
+ th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
+ TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, 0, NULL, NULL);
+ REASON_SET(&reason, PFRES_SYNPROXY);
+ return (PF_SYNPROXY_DROP);
+ }
return (PF_PASS);
+
+csfailed:
+ if (sn != NULL && sn->states == 0 && sn->expire == 0) {
+ RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
+ pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
+ pf_status.src_nodes--;
+ pool_put(&pf_src_tree_pl, sn);
+ }
+ if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) {
+ RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
+ pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
+ pf_status.src_nodes--;
+ pool_put(&pf_src_tree_pl, nsn);
+ }
+ return (PF_DROP);
}
int