pf.c revision 145886
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/pf.c 145886 2005-05-04 19:51:06Z mlaier $	*/
2145836Smlaier/*	$OpenBSD: pf.c,v 1.483 2005/03/15 17:38:43 dhartmei Exp $ */
3126258Smlaier
4126258Smlaier/*
5126258Smlaier * Copyright (c) 2001 Daniel Hartmeier
6130613Smlaier * Copyright (c) 2002,2003 Henning Brauer
7126258Smlaier * All rights reserved.
8126258Smlaier *
9126258Smlaier * Redistribution and use in source and binary forms, with or without
10126258Smlaier * modification, are permitted provided that the following conditions
11126258Smlaier * are met:
12126258Smlaier *
13126258Smlaier *    - Redistributions of source code must retain the above copyright
14126258Smlaier *      notice, this list of conditions and the following disclaimer.
15126258Smlaier *    - Redistributions in binary form must reproduce the above
16126258Smlaier *      copyright notice, this list of conditions and the following
17126258Smlaier *      disclaimer in the documentation and/or other materials provided
18126258Smlaier *      with the distribution.
19126258Smlaier *
20126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21126258Smlaier * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22126258Smlaier * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23126258Smlaier * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24126258Smlaier * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26126258Smlaier * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27126258Smlaier * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28126258Smlaier * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29126258Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30126258Smlaier * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31126258Smlaier * POSSIBILITY OF SUCH DAMAGE.
32126258Smlaier *
33126258Smlaier * Effort sponsored in part by the Defense Advanced Research Projects
34126258Smlaier * Agency (DARPA) and Air Force Research Laboratory, Air Force
35126258Smlaier * Materiel Command, USAF, under agreement number F30602-01-2-0537.
36126258Smlaier *
37126258Smlaier */
38126258Smlaier
39127145Smlaier#ifdef __FreeBSD__
40126261Smlaier#include "opt_inet.h"
41126261Smlaier#include "opt_inet6.h"
42126261Smlaier#endif
43126261Smlaier
44127145Smlaier#ifdef __FreeBSD__
45126261Smlaier#include "opt_bpf.h"
46126261Smlaier#include "opt_pf.h"
47127145Smlaier#define	NBPFILTER	DEV_BPF
48127145Smlaier#define	NPFLOG		DEV_PFLOG
49127145Smlaier#define	NPFSYNC		DEV_PFSYNC
50126261Smlaier#else
51126258Smlaier#include "bpfilter.h"
52126258Smlaier#include "pflog.h"
53126258Smlaier#include "pfsync.h"
54126261Smlaier#endif
55126258Smlaier
56126258Smlaier#include <sys/param.h>
57126258Smlaier#include <sys/systm.h>
58126258Smlaier#include <sys/mbuf.h>
59126258Smlaier#include <sys/filio.h>
60126258Smlaier#include <sys/socket.h>
61126258Smlaier#include <sys/socketvar.h>
62126258Smlaier#include <sys/kernel.h>
63126258Smlaier#include <sys/time.h>
64127145Smlaier#ifdef __FreeBSD__
65126261Smlaier#include <sys/sysctl.h>
66130613Smlaier#include <sys/endian.h>
67126261Smlaier#else
68126258Smlaier#include <sys/pool.h>
69126261Smlaier#endif
70126258Smlaier
71126258Smlaier#include <net/if.h>
72126258Smlaier#include <net/if_types.h>
73126258Smlaier#include <net/bpf.h>
74126258Smlaier#include <net/route.h>
75126258Smlaier
76126258Smlaier#include <netinet/in.h>
77126258Smlaier#include <netinet/in_var.h>
78126258Smlaier#include <netinet/in_systm.h>
79126258Smlaier#include <netinet/ip.h>
80126258Smlaier#include <netinet/ip_var.h>
81126258Smlaier#include <netinet/tcp.h>
82126258Smlaier#include <netinet/tcp_seq.h>
83126258Smlaier#include <netinet/udp.h>
84126258Smlaier#include <netinet/ip_icmp.h>
85126258Smlaier#include <netinet/in_pcb.h>
86126258Smlaier#include <netinet/tcp_timer.h>
87126258Smlaier#include <netinet/tcp_var.h>
88126258Smlaier#include <netinet/udp_var.h>
89126258Smlaier#include <netinet/icmp_var.h>
90145836Smlaier#include <netinet/if_ether.h>
91126258Smlaier
92127145Smlaier#ifndef __FreeBSD__
93126258Smlaier#include <dev/rndvar.h>
94126261Smlaier#endif
95126258Smlaier#include <net/pfvar.h>
96126258Smlaier#include <net/if_pflog.h>
97130613Smlaier
98130613Smlaier#if NPFSYNC > 0
99126258Smlaier#include <net/if_pfsync.h>
100130613Smlaier#endif /* NPFSYNC > 0 */
101126258Smlaier
102126258Smlaier#ifdef INET6
103126258Smlaier#include <netinet/ip6.h>
104126258Smlaier#include <netinet/in_pcb.h>
105126258Smlaier#include <netinet/icmp6.h>
106126258Smlaier#include <netinet6/nd6.h>
107127145Smlaier#ifdef __FreeBSD__
108126261Smlaier#include <netinet6/ip6_var.h>
109126261Smlaier#include <netinet6/in6_pcb.h>
110126261Smlaier#endif
111126258Smlaier#endif /* INET6 */
112126258Smlaier
113127145Smlaier#ifdef __FreeBSD__
114126261Smlaier#include <machine/in_cksum.h>
115126261Smlaier#include <sys/limits.h>
116126261Smlaier#include <sys/ucred.h>
117126258Smlaier
118126261Smlaierextern int ip_optcopy(struct ip *, struct ip *);
119126261Smlaier#endif
120126261Smlaier
121126258Smlaier#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
122126258Smlaier
123126258Smlaier/*
124126258Smlaier * Global variables
125126258Smlaier */
126126258Smlaier
127145836Smlaierstruct pf_anchor_global	 pf_anchors;
128126258Smlaierstruct pf_ruleset	 pf_main_ruleset;
129126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
130126258Smlaierstruct pf_palist	 pf_pabuf;
131126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
132126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
133126258Smlaierstruct pf_status	 pf_status;
134126258Smlaier
135126258Smlaieru_int32_t		 ticket_altqs_active;
136126258Smlaieru_int32_t		 ticket_altqs_inactive;
137130613Smlaierint			 altqs_inactive_open;
138126258Smlaieru_int32_t		 ticket_pabuf;
139126258Smlaier
140127145Smlaier#ifdef __FreeBSD__
141126261Smlaierstruct callout	 	 pf_expire_to;			/* expire timeout */
142126261Smlaier#else
143126258Smlaierstruct timeout		 pf_expire_to;			/* expire timeout */
144126261Smlaier#endif
145126258Smlaier
146145836Smlaierstruct pf_anchor_stackframe {
147145836Smlaier	struct pf_ruleset			*rs;
148145836Smlaier	struct pf_rule				*r;
149145836Smlaier	struct pf_anchor_node			*parent;
150145836Smlaier	struct pf_anchor			*child;
151145836Smlaier} pf_anchor_stack[64];
152126261Smlaier
153127145Smlaier#ifdef __FreeBSD__
154130613Smlaieruma_zone_t		 pf_src_tree_pl, pf_rule_pl;
155126261Smlaieruma_zone_t		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
156126261Smlaier#else
157130613Smlaierstruct pool		 pf_src_tree_pl, pf_rule_pl;
158126258Smlaierstruct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
159126261Smlaier#endif
160126258Smlaier
161126258Smlaiervoid			 pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
162126258Smlaier
163145836Smlaiervoid			 pf_init_threshold(struct pf_threshold *, u_int32_t,
164145836Smlaier			    u_int32_t);
165145836Smlaiervoid			 pf_add_threshold(struct pf_threshold *);
166145836Smlaierint			 pf_check_threshold(struct pf_threshold *);
167145836Smlaier
168126258Smlaiervoid			 pf_change_ap(struct pf_addr *, u_int16_t *,
169126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
170126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
171126258Smlaier#ifdef INET6
172126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
173126258Smlaier			    struct pf_addr *, u_int8_t);
174126258Smlaier#endif /* INET6 */
175126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
176126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
177126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
178126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
179126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
180126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
181126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
182145836Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
183145836Smlaier			    struct ether_header *, struct ifnet *);
184126258Smlaiervoid			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
185126258Smlaier			    sa_family_t, struct pf_rule *);
186126258Smlaierstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
187130613Smlaier			    int, int, struct pfi_kif *,
188126258Smlaier			    struct pf_addr *, u_int16_t, struct pf_addr *,
189126258Smlaier			    u_int16_t, int);
190126258Smlaierstruct pf_rule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
191130613Smlaier			    int, int, struct pfi_kif *, struct pf_src_node **,
192126258Smlaier			    struct pf_addr *, u_int16_t,
193126258Smlaier			    struct pf_addr *, u_int16_t,
194126258Smlaier			    struct pf_addr *, u_int16_t *);
195126258Smlaierint			 pf_test_tcp(struct pf_rule **, struct pf_state **,
196130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
197126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
198135920Smlaier#ifdef __FreeBSD__
199145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
200145836Smlaier			    struct inpcb *);
201135920Smlaier#else
202145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
203135920Smlaier#endif
204126258Smlaierint			 pf_test_udp(struct pf_rule **, struct pf_state **,
205130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
206126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
207135920Smlaier#ifdef __FreeBSD__
208145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
209145836Smlaier			    struct inpcb *);
210135920Smlaier#else
211145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
212135920Smlaier#endif
213126258Smlaierint			 pf_test_icmp(struct pf_rule **, struct pf_state **,
214130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
215126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
216145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
217126258Smlaierint			 pf_test_other(struct pf_rule **, struct pf_state **,
218130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int, void *,
219126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
220145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
221126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
222130613Smlaier			    struct pfi_kif *, struct mbuf *, void *,
223126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
224126258Smlaier			    struct pf_ruleset **);
225126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
226130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
227126258Smlaier			    void *, struct pf_pdesc *, u_short *);
228126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
229130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
230126258Smlaier			    void *, struct pf_pdesc *);
231126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
232130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
233145836Smlaier			    void *, struct pf_pdesc *, u_short *);
234126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
235130613Smlaier			    struct pfi_kif *, struct pf_pdesc *);
236126258Smlaierstruct pf_tag		*pf_get_tag(struct mbuf *);
237126258Smlaierint			 pf_match_tag(struct mbuf *, struct pf_rule *,
238145836Smlaier			     struct pf_tag **, int *);
239126258Smlaiervoid			 pf_hash(struct pf_addr *, struct pf_addr *,
240126258Smlaier			    struct pf_poolhashkey *, sa_family_t);
241130613Smlaierint			 pf_map_addr(u_int8_t, struct pf_rule *,
242126258Smlaier			    struct pf_addr *, struct pf_addr *,
243130613Smlaier			    struct pf_addr *, struct pf_src_node **);
244130613Smlaierint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
245126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
246130613Smlaier			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
247130613Smlaier			    struct pf_src_node **);
248126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
249126258Smlaier			    struct ifnet *, struct pf_state *);
250126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
251126258Smlaier			    struct ifnet *, struct pf_state *);
252135920Smlaier#ifdef __FreeBSD__
253130613Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
254135920Smlaier			    int, struct pf_pdesc *, struct inpcb *);
255135920Smlaier#else
256135920Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
257126258Smlaier			    int, struct pf_pdesc *);
258135920Smlaier#endif
259126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
260126258Smlaier			    sa_family_t);
261126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
262126258Smlaier			    sa_family_t);
263126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
264126258Smlaier				u_int16_t);
265126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
266126258Smlaier			    struct pf_addr *);
267126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
268126258Smlaier			    u_int8_t, sa_family_t);
269126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
270126258Smlaier			    struct pf_addr_wrap *);
271130613Smlaierstatic int		 pf_add_mbuf_tag(struct mbuf *, u_int);
272130613Smlaierstruct pf_state		*pf_find_state_recurse(struct pfi_kif *,
273130613Smlaier			    struct pf_state *, u_int8_t);
274145836Smlaierint			 pf_src_connlimit(struct pf_state **);
275145836Smlaierint			 pf_check_congestion(struct ifqueue *);
276126258Smlaier
277127145Smlaier#ifdef __FreeBSD__
278126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
279126258Smlaier
280126261Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
281145836Smlaier
282126261Smlaier#else
283130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
284130613Smlaier	{ &pf_state_pl, PFSTATE_HIWAT },
285130613Smlaier	{ &pf_src_tree_pl, PFSNODE_HIWAT },
286130613Smlaier	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT }
287130613Smlaier};
288126261Smlaier#endif
289126258Smlaier
290126258Smlaier#define STATE_LOOKUP()							\
291126258Smlaier	do {								\
292126258Smlaier		if (direction == PF_IN)					\
293145836Smlaier			*state = pf_find_state_recurse(			\
294130613Smlaier			    kif, &key, PF_EXT_GWY);			\
295126258Smlaier		else							\
296145836Smlaier			*state = pf_find_state_recurse(			\
297130613Smlaier			    kif, &key, PF_LAN_EXT);			\
298145836Smlaier		if (*state == NULL || (*state)->timeout == PFTM_PURGE)	\
299126258Smlaier			return (PF_DROP);				\
300126258Smlaier		if (direction == PF_OUT &&				\
301126258Smlaier		    (((*state)->rule.ptr->rt == PF_ROUTETO &&		\
302126258Smlaier		    (*state)->rule.ptr->direction == PF_OUT) ||		\
303126258Smlaier		    ((*state)->rule.ptr->rt == PF_REPLYTO &&		\
304126258Smlaier		    (*state)->rule.ptr->direction == PF_IN)) &&		\
305130613Smlaier		    (*state)->rt_kif != NULL &&				\
306130613Smlaier		    (*state)->rt_kif != kif)				\
307126258Smlaier			return (PF_PASS);				\
308126258Smlaier	} while (0)
309126258Smlaier
310126258Smlaier#define	STATE_TRANSLATE(s) \
311126258Smlaier	(s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
312126258Smlaier	((s)->af == AF_INET6 && \
313126258Smlaier	((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
314126258Smlaier	(s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
315126258Smlaier	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
316126258Smlaier	(s)->lan.port != (s)->gwy.port
317126258Smlaier
318130613Smlaier#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) :   \
319130613Smlaier	((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent :	       \
320130613Smlaier	(k)->pfik_parent->pfik_parent)
321126258Smlaier
322145836Smlaier#define STATE_INC_COUNTERS(s)				\
323145836Smlaier	do {						\
324145836Smlaier		s->rule.ptr->states++;			\
325145836Smlaier		if (s->anchor.ptr != NULL)		\
326145836Smlaier			s->anchor.ptr->states++;	\
327145836Smlaier		if (s->nat_rule.ptr != NULL)		\
328145836Smlaier			s->nat_rule.ptr->states++;	\
329145836Smlaier	} while (0)
330145836Smlaier
331145836Smlaier#define STATE_DEC_COUNTERS(s)				\
332145836Smlaier	do {						\
333145836Smlaier		if (s->nat_rule.ptr != NULL)		\
334145836Smlaier			s->nat_rule.ptr->states--;	\
335145836Smlaier		if (s->anchor.ptr != NULL)		\
336145836Smlaier			s->anchor.ptr->states--;	\
337145836Smlaier		s->rule.ptr->states--;			\
338145836Smlaier	} while (0)
339145836Smlaier
340132767Skan#ifndef __FreeBSD__
341130613Smlaierstatic __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
342130613Smlaierstatic __inline int pf_state_compare_lan_ext(struct pf_state *,
343130613Smlaier	struct pf_state *);
344130613Smlaierstatic __inline int pf_state_compare_ext_gwy(struct pf_state *,
345130613Smlaier	struct pf_state *);
346130613Smlaierstatic __inline int pf_state_compare_id(struct pf_state *,
347130613Smlaier	struct pf_state *);
348145836Smlaierstatic __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
349132767Skan#else
350132767Skanstatic int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
351132767Skanstatic int pf_state_compare_lan_ext(struct pf_state *,
352132767Skan	struct pf_state *);
353132767Skanstatic int pf_state_compare_ext_gwy(struct pf_state *,
354132767Skan	struct pf_state *);
355132767Skanstatic int pf_state_compare_id(struct pf_state *,
356132767Skan	struct pf_state *);
357145836Smlaierstatic int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
358132767Skan#endif
359126258Smlaier
360130613Smlaierstruct pf_src_tree tree_src_tracking;
361130613Smlaier
362130613Smlaierstruct pf_state_tree_id tree_id;
363130613Smlaierstruct pf_state_queue state_updates;
364130613Smlaier
365130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
366130613SmlaierRB_GENERATE(pf_state_tree_lan_ext, pf_state,
367130613Smlaier    u.s.entry_lan_ext, pf_state_compare_lan_ext);
368130613SmlaierRB_GENERATE(pf_state_tree_ext_gwy, pf_state,
369130613Smlaier    u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
370130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state,
371130613Smlaier    u.s.entry_id, pf_state_compare_id);
372145836SmlaierRB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
373145836SmlaierRB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
374130613Smlaier
375127145Smlaier#ifdef __FreeBSD__
376126409Smlaierstatic int
377126409Smlaier#else
378126258Smlaierstatic __inline int
379126409Smlaier#endif
380130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
381126258Smlaier{
382126258Smlaier	int	diff;
383126258Smlaier
384130613Smlaier	if (a->rule.ptr > b->rule.ptr)
385130613Smlaier		return (1);
386130613Smlaier	if (a->rule.ptr < b->rule.ptr)
387130613Smlaier		return (-1);
388130613Smlaier	if ((diff = a->af - b->af) != 0)
389130613Smlaier		return (diff);
390130613Smlaier	switch (a->af) {
391130613Smlaier#ifdef INET
392130613Smlaier	case AF_INET:
393130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
394130613Smlaier			return (1);
395130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
396130613Smlaier			return (-1);
397130613Smlaier		break;
398130613Smlaier#endif /* INET */
399130613Smlaier#ifdef INET6
400130613Smlaier	case AF_INET6:
401130613Smlaier		if (a->addr.addr32[3] > b->addr.addr32[3])
402130613Smlaier			return (1);
403130613Smlaier		if (a->addr.addr32[3] < b->addr.addr32[3])
404130613Smlaier			return (-1);
405130613Smlaier		if (a->addr.addr32[2] > b->addr.addr32[2])
406130613Smlaier			return (1);
407130613Smlaier		if (a->addr.addr32[2] < b->addr.addr32[2])
408130613Smlaier			return (-1);
409130613Smlaier		if (a->addr.addr32[1] > b->addr.addr32[1])
410130613Smlaier			return (1);
411130613Smlaier		if (a->addr.addr32[1] < b->addr.addr32[1])
412130613Smlaier			return (-1);
413130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
414130613Smlaier			return (1);
415130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
416130613Smlaier			return (-1);
417130613Smlaier		break;
418130613Smlaier#endif /* INET6 */
419130613Smlaier	}
420130613Smlaier	return (0);
421130613Smlaier}
422130613Smlaier
423130613Smlaier#ifdef __FreeBSD__
424130613Smlaierstatic int
425130613Smlaier#else
426130613Smlaierstatic __inline int
427130613Smlaier#endif
428130613Smlaierpf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
429130613Smlaier{
430130613Smlaier	int	diff;
431130613Smlaier
432126258Smlaier	if ((diff = a->proto - b->proto) != 0)
433126258Smlaier		return (diff);
434126258Smlaier	if ((diff = a->af - b->af) != 0)
435126258Smlaier		return (diff);
436126258Smlaier	switch (a->af) {
437126258Smlaier#ifdef INET
438126258Smlaier	case AF_INET:
439130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
440126258Smlaier			return (1);
441130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
442126258Smlaier			return (-1);
443130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
444126258Smlaier			return (1);
445130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
446126258Smlaier			return (-1);
447126258Smlaier		break;
448126258Smlaier#endif /* INET */
449126258Smlaier#ifdef INET6
450126258Smlaier	case AF_INET6:
451130613Smlaier		if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3])
452126258Smlaier			return (1);
453130613Smlaier		if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3])
454126258Smlaier			return (-1);
455130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
456126258Smlaier			return (1);
457130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
458126258Smlaier			return (-1);
459130613Smlaier		if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2])
460126258Smlaier			return (1);
461130613Smlaier		if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2])
462126258Smlaier			return (-1);
463130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
464126258Smlaier			return (1);
465130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
466126258Smlaier			return (-1);
467130613Smlaier		if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1])
468126258Smlaier			return (1);
469130613Smlaier		if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1])
470126258Smlaier			return (-1);
471130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
472126258Smlaier			return (1);
473130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
474126258Smlaier			return (-1);
475130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
476126258Smlaier			return (1);
477130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
478126258Smlaier			return (-1);
479130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
480126258Smlaier			return (1);
481130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
482126258Smlaier			return (-1);
483126258Smlaier		break;
484126258Smlaier#endif /* INET6 */
485126258Smlaier	}
486126258Smlaier
487130613Smlaier	if ((diff = a->lan.port - b->lan.port) != 0)
488126258Smlaier		return (diff);
489130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
490126258Smlaier		return (diff);
491126258Smlaier
492126258Smlaier	return (0);
493126258Smlaier}
494126258Smlaier
495130613Smlaier#ifdef __FreeBSD__
496130613Smlaierstatic int
497130613Smlaier#else
498130613Smlaierstatic __inline int
499130613Smlaier#endif
500130613Smlaierpf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
501130613Smlaier{
502130613Smlaier	int	diff;
503130613Smlaier
504130613Smlaier	if ((diff = a->proto - b->proto) != 0)
505130613Smlaier		return (diff);
506130613Smlaier	if ((diff = a->af - b->af) != 0)
507130613Smlaier		return (diff);
508130613Smlaier	switch (a->af) {
509130613Smlaier#ifdef INET
510130613Smlaier	case AF_INET:
511130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
512130613Smlaier			return (1);
513130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
514130613Smlaier			return (-1);
515130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
516130613Smlaier			return (1);
517130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
518130613Smlaier			return (-1);
519130613Smlaier		break;
520130613Smlaier#endif /* INET */
521126258Smlaier#ifdef INET6
522130613Smlaier	case AF_INET6:
523130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
524130613Smlaier			return (1);
525130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
526130613Smlaier			return (-1);
527130613Smlaier		if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3])
528130613Smlaier			return (1);
529130613Smlaier		if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3])
530130613Smlaier			return (-1);
531130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
532130613Smlaier			return (1);
533130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
534130613Smlaier			return (-1);
535130613Smlaier		if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2])
536130613Smlaier			return (1);
537130613Smlaier		if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2])
538130613Smlaier			return (-1);
539130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
540130613Smlaier			return (1);
541130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
542130613Smlaier			return (-1);
543130613Smlaier		if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1])
544130613Smlaier			return (1);
545130613Smlaier		if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1])
546130613Smlaier			return (-1);
547130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
548130613Smlaier			return (1);
549130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
550130613Smlaier			return (-1);
551130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
552130613Smlaier			return (1);
553130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
554130613Smlaier			return (-1);
555130613Smlaier		break;
556130613Smlaier#endif /* INET6 */
557130613Smlaier	}
558130613Smlaier
559130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
560130613Smlaier		return (diff);
561130613Smlaier	if ((diff = a->gwy.port - b->gwy.port) != 0)
562130613Smlaier		return (diff);
563130613Smlaier
564130613Smlaier	return (0);
565130613Smlaier}
566130613Smlaier
567130613Smlaier#ifdef __FreeBSD__
568130613Smlaierstatic int
569130613Smlaier#else
570130613Smlaierstatic __inline int
571130613Smlaier#endif
572130613Smlaierpf_state_compare_id(struct pf_state *a, struct pf_state *b)
573130613Smlaier{
574130613Smlaier	if (a->id > b->id)
575130613Smlaier		return (1);
576130613Smlaier	if (a->id < b->id)
577130613Smlaier		return (-1);
578130613Smlaier	if (a->creatorid > b->creatorid)
579130613Smlaier		return (1);
580130613Smlaier	if (a->creatorid < b->creatorid)
581130613Smlaier		return (-1);
582130613Smlaier
583130613Smlaier	return (0);
584130613Smlaier}
585130613Smlaier
586145836Smlaier#ifdef __FreeBSD__
587145836Smlaierstatic int
588145836Smlaier#else
589145836Smlaierstatic __inline int
590145836Smlaier#endif
591145836Smlaierpf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
592145836Smlaier{
593145836Smlaier	int c = strcmp(a->path, b->path);
594145836Smlaier
595145836Smlaier	return (c ? (c < 0 ? -1 : 1) : 0);
596145836Smlaier}
597145836Smlaier
598130613Smlaier#ifdef INET6
599126258Smlaiervoid
600126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
601126258Smlaier{
602126258Smlaier	switch (af) {
603126258Smlaier#ifdef INET
604126258Smlaier	case AF_INET:
605126258Smlaier		dst->addr32[0] = src->addr32[0];
606126258Smlaier		break;
607126258Smlaier#endif /* INET */
608126258Smlaier	case AF_INET6:
609126258Smlaier		dst->addr32[0] = src->addr32[0];
610126258Smlaier		dst->addr32[1] = src->addr32[1];
611126258Smlaier		dst->addr32[2] = src->addr32[2];
612126258Smlaier		dst->addr32[3] = src->addr32[3];
613126258Smlaier		break;
614126258Smlaier	}
615126258Smlaier}
616145836Smlaier#endif /* INET6 */
617126258Smlaier
618126258Smlaierstruct pf_state *
619130613Smlaierpf_find_state_byid(struct pf_state *key)
620126258Smlaier{
621130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
622130613Smlaier	return (RB_FIND(pf_state_tree_id, &tree_id, key));
623130613Smlaier}
624126258Smlaier
625130613Smlaierstruct pf_state *
626130613Smlaierpf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree)
627130613Smlaier{
628130613Smlaier	struct pf_state *s;
629130613Smlaier
630126258Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
631130613Smlaier
632130613Smlaier	switch (tree) {
633130613Smlaier	case PF_LAN_EXT:
634130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
635130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
636130613Smlaier			    &kif->pfik_lan_ext, key);
637130613Smlaier			if (s != NULL)
638130613Smlaier				return (s);
639130613Smlaier		}
640126258Smlaier		return (NULL);
641130613Smlaier	case PF_EXT_GWY:
642130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
643130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
644130613Smlaier			    &kif->pfik_ext_gwy, key);
645130613Smlaier			if (s != NULL)
646130613Smlaier				return (s);
647130613Smlaier		}
648130613Smlaier		return (NULL);
649130613Smlaier	default:
650130613Smlaier		panic("pf_find_state_recurse");
651130613Smlaier	}
652126258Smlaier}
653126258Smlaier
654130613Smlaierstruct pf_state *
655130613Smlaierpf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
656130613Smlaier{
657130613Smlaier	struct pf_state *s, *ss = NULL;
658130613Smlaier	struct pfi_kif	*kif;
659130613Smlaier
660130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
661130613Smlaier
662130613Smlaier	switch (tree) {
663130613Smlaier	case PF_LAN_EXT:
664130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
665130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
666130613Smlaier			    &kif->pfik_lan_ext, key);
667130613Smlaier			if (s == NULL)
668130613Smlaier				continue;
669130613Smlaier			if (more == NULL)
670130613Smlaier				return (s);
671130613Smlaier			ss = s;
672130613Smlaier			(*more)++;
673130613Smlaier		}
674130613Smlaier		return (ss);
675130613Smlaier	case PF_EXT_GWY:
676130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
677130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
678130613Smlaier			    &kif->pfik_ext_gwy, key);
679130613Smlaier			if (s == NULL)
680130613Smlaier				continue;
681130613Smlaier			if (more == NULL)
682130613Smlaier				return (s);
683130613Smlaier			ss = s;
684130613Smlaier			(*more)++;
685130613Smlaier		}
686130613Smlaier		return (ss);
687130613Smlaier	default:
688130613Smlaier		panic("pf_find_state_all");
689130613Smlaier	}
690130613Smlaier}
691130613Smlaier
692145836Smlaiervoid
693145836Smlaierpf_init_threshold(struct pf_threshold *threshold,
694145836Smlaier    u_int32_t limit, u_int32_t seconds)
695145836Smlaier{
696145836Smlaier	threshold->limit = limit * PF_THRESHOLD_MULT;
697145836Smlaier	threshold->seconds = seconds;
698145836Smlaier	threshold->count = 0;
699145836Smlaier	threshold->last = time_second;
700145836Smlaier}
701145836Smlaier
702145836Smlaiervoid
703145836Smlaierpf_add_threshold(struct pf_threshold *threshold)
704145836Smlaier{
705145836Smlaier	u_int32_t t = time_second, diff = t - threshold->last;
706145836Smlaier
707145836Smlaier	if (diff >= threshold->seconds)
708145836Smlaier		threshold->count = 0;
709145836Smlaier	else
710145836Smlaier		threshold->count -= threshold->count * diff /
711145836Smlaier		    threshold->seconds;
712145836Smlaier	threshold->count += PF_THRESHOLD_MULT;
713145836Smlaier	threshold->last = t;
714145836Smlaier}
715145836Smlaier
716126258Smlaierint
717145836Smlaierpf_check_threshold(struct pf_threshold *threshold)
718145836Smlaier{
719145836Smlaier	return (threshold->count > threshold->limit);
720145836Smlaier}
721145836Smlaier
722145836Smlaierint
723145836Smlaierpf_src_connlimit(struct pf_state **state)
724145836Smlaier{
725145836Smlaier	struct pf_state	*s;
726145836Smlaier	int bad = 0;
727145836Smlaier
728145836Smlaier	(*state)->src_node->conn++;
729145836Smlaier	pf_add_threshold(&(*state)->src_node->conn_rate);
730145836Smlaier
731145836Smlaier	if ((*state)->rule.ptr->max_src_conn &&
732145836Smlaier	    (*state)->rule.ptr->max_src_conn <
733145836Smlaier	    (*state)->src_node->conn) {
734145836Smlaier		pf_status.lcounters[LCNT_SRCCONN]++;
735145836Smlaier		bad++;
736145836Smlaier	}
737145836Smlaier
738145836Smlaier	if ((*state)->rule.ptr->max_src_conn_rate.limit &&
739145836Smlaier	    pf_check_threshold(&(*state)->src_node->conn_rate)) {
740145836Smlaier		pf_status.lcounters[LCNT_SRCCONNRATE]++;
741145836Smlaier		bad++;
742145836Smlaier	}
743145836Smlaier
744145836Smlaier	if (!bad)
745145836Smlaier		return (0);
746145836Smlaier
747145836Smlaier	if ((*state)->rule.ptr->overload_tbl) {
748145836Smlaier		struct pfr_addr p;
749145836Smlaier		u_int32_t	killed = 0;
750145836Smlaier
751145836Smlaier		pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
752145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
753145836Smlaier			printf("pf_src_connlimit: blocking address ");
754145836Smlaier			pf_print_host(&(*state)->src_node->addr, 0,
755145836Smlaier			    (*state)->af);
756145836Smlaier		}
757145836Smlaier
758145836Smlaier		bzero(&p, sizeof(p));
759145836Smlaier		p.pfra_af = (*state)->af;
760145836Smlaier		switch ((*state)->af) {
761145836Smlaier#ifdef INET
762145836Smlaier		case AF_INET:
763145836Smlaier			p.pfra_net = 32;
764145836Smlaier			p.pfra_ip4addr = (*state)->src_node->addr.v4;
765145836Smlaier			break;
766145836Smlaier#endif /* INET */
767145836Smlaier#ifdef INET6
768145836Smlaier		case AF_INET6:
769145836Smlaier			p.pfra_net = 128;
770145836Smlaier			p.pfra_ip6addr = (*state)->src_node->addr.v6;
771145836Smlaier			break;
772145836Smlaier#endif /* INET6 */
773145836Smlaier		}
774145836Smlaier
775145836Smlaier		pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
776145836Smlaier		    &p, time_second);
777145836Smlaier
778145836Smlaier		/* kill existing states if that's required. */
779145836Smlaier		if ((*state)->rule.ptr->flush) {
780145836Smlaier			pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
781145836Smlaier
782145836Smlaier			RB_FOREACH(s, pf_state_tree_id, &tree_id) {
783145836Smlaier				/*
784145836Smlaier				 * Kill states from this source.  (Only those
785145836Smlaier				 * from the same rule if PF_FLUSH_GLOBAL is not
786145836Smlaier				 * set)
787145836Smlaier				 */
788145836Smlaier				if (s->af == (*state)->af &&
789145836Smlaier				    (((*state)->direction == PF_OUT &&
790145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
791145836Smlaier				    &s->lan.addr, s->af)) ||
792145836Smlaier				    ((*state)->direction == PF_IN &&
793145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
794145836Smlaier				    &s->ext.addr, s->af))) &&
795145836Smlaier				    ((*state)->rule.ptr->flush &
796145836Smlaier				    PF_FLUSH_GLOBAL ||
797145836Smlaier				    (*state)->rule.ptr == s->rule.ptr)) {
798145836Smlaier					s->timeout = PFTM_PURGE;
799145836Smlaier					s->src.state = s->dst.state =
800145836Smlaier					    TCPS_CLOSED;
801145836Smlaier					killed++;
802145836Smlaier				}
803145836Smlaier			}
804145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
805145836Smlaier				printf(", %u states killed", killed);
806145836Smlaier		}
807145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
808145836Smlaier			printf("\n");
809145836Smlaier	}
810145836Smlaier
811145836Smlaier	/* kill this state */
812145836Smlaier	(*state)->timeout = PFTM_PURGE;
813145836Smlaier	(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
814145836Smlaier	return (1);
815145836Smlaier}
816145836Smlaier
817145836Smlaierint
818130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
819130613Smlaier    struct pf_addr *src, sa_family_t af)
820126258Smlaier{
821130613Smlaier	struct pf_src_node	k;
822126258Smlaier
823130613Smlaier	if (*sn == NULL) {
824130613Smlaier		k.af = af;
825130613Smlaier		PF_ACPY(&k.addr, src, af);
826130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
827130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
828130613Smlaier			k.rule.ptr = rule;
829130613Smlaier		else
830130613Smlaier			k.rule.ptr = NULL;
831130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
832130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
833130613Smlaier	}
834130613Smlaier	if (*sn == NULL) {
835130613Smlaier		if (!rule->max_src_nodes ||
836130613Smlaier		    rule->src_nodes < rule->max_src_nodes)
837130613Smlaier			(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
838145836Smlaier		else
839145836Smlaier			pf_status.lcounters[LCNT_SRCNODES]++;
840130613Smlaier		if ((*sn) == NULL)
841130613Smlaier			return (-1);
842130613Smlaier		bzero(*sn, sizeof(struct pf_src_node));
843145836Smlaier
844145836Smlaier		pf_init_threshold(&(*sn)->conn_rate,
845145836Smlaier		    rule->max_src_conn_rate.limit,
846145836Smlaier		    rule->max_src_conn_rate.seconds);
847145836Smlaier
848130613Smlaier		(*sn)->af = af;
849130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
850130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
851130613Smlaier			(*sn)->rule.ptr = rule;
852130613Smlaier		else
853130613Smlaier			(*sn)->rule.ptr = NULL;
854130613Smlaier		PF_ACPY(&(*sn)->addr, src, af);
855130613Smlaier		if (RB_INSERT(pf_src_tree,
856130613Smlaier		    &tree_src_tracking, *sn) != NULL) {
857130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
858130613Smlaier				printf("pf: src_tree insert failed: ");
859130613Smlaier				pf_print_host(&(*sn)->addr, 0, af);
860130613Smlaier				printf("\n");
861130613Smlaier			}
862130613Smlaier			pool_put(&pf_src_tree_pl, *sn);
863130613Smlaier			return (-1);
864130613Smlaier		}
865130613Smlaier		(*sn)->creation = time_second;
866130613Smlaier		(*sn)->ruletype = rule->action;
867130613Smlaier		if ((*sn)->rule.ptr != NULL)
868130613Smlaier			(*sn)->rule.ptr->src_nodes++;
869130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
870130613Smlaier		pf_status.src_nodes++;
871130613Smlaier	} else {
872130613Smlaier		if (rule->max_src_states &&
873145836Smlaier		    (*sn)->states >= rule->max_src_states) {
874145836Smlaier			pf_status.lcounters[LCNT_SRCSTATES]++;
875130613Smlaier			return (-1);
876145836Smlaier		}
877130613Smlaier	}
878130613Smlaier	return (0);
879130613Smlaier}
880126258Smlaier
881130613Smlaierint
882130613Smlaierpf_insert_state(struct pfi_kif *kif, struct pf_state *state)
883130613Smlaier{
884126258Smlaier	/* Thou MUST NOT insert multiple duplicate keys */
885130613Smlaier	state->u.s.kif = kif;
886130613Smlaier	if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
887126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
888126258Smlaier			printf("pf: state insert failed: tree_lan_ext");
889126258Smlaier			printf(" lan: ");
890126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
891126258Smlaier			    state->af);
892126258Smlaier			printf(" gwy: ");
893126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
894126258Smlaier			    state->af);
895126258Smlaier			printf(" ext: ");
896126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
897126258Smlaier			    state->af);
898130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
899130613Smlaier				printf(" (from sync)");
900126258Smlaier			printf("\n");
901126258Smlaier		}
902126258Smlaier		return (-1);
903126258Smlaier	}
904126258Smlaier
905130613Smlaier	if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
906126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
907126258Smlaier			printf("pf: state insert failed: tree_ext_gwy");
908126258Smlaier			printf(" lan: ");
909126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
910126258Smlaier			    state->af);
911126258Smlaier			printf(" gwy: ");
912126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
913126258Smlaier			    state->af);
914126258Smlaier			printf(" ext: ");
915126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
916126258Smlaier			    state->af);
917130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
918130613Smlaier				printf(" (from sync)");
919126258Smlaier			printf("\n");
920126258Smlaier		}
921130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
922126258Smlaier		return (-1);
923126258Smlaier	}
924126258Smlaier
925130613Smlaier	if (state->id == 0 && state->creatorid == 0) {
926130613Smlaier		state->id = htobe64(pf_status.stateid++);
927130613Smlaier		state->creatorid = pf_status.hostid;
928130613Smlaier	}
929130613Smlaier	if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
930130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
931130613Smlaier#ifdef __FreeBSD__
932130613Smlaier			printf("pf: state insert failed: "
933130613Smlaier			    "id: %016llx creatorid: %08x",
934130613Smlaier			    (long long)be64toh(state->id),
935130613Smlaier			    ntohl(state->creatorid));
936130613Smlaier#else
937130613Smlaier			printf("pf: state insert failed: "
938130613Smlaier			    "id: %016llx creatorid: %08x",
939130613Smlaier			    betoh64(state->id), ntohl(state->creatorid));
940130613Smlaier#endif
941130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
942130613Smlaier				printf(" (from sync)");
943130613Smlaier			printf("\n");
944130613Smlaier		}
945130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
946130613Smlaier		RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
947130613Smlaier		return (-1);
948130613Smlaier	}
949130613Smlaier	TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates);
950130613Smlaier
951126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
952126258Smlaier	pf_status.states++;
953130613Smlaier	pfi_attach_state(kif);
954126258Smlaier#if NPFSYNC
955126258Smlaier	pfsync_insert_state(state);
956126258Smlaier#endif
957126258Smlaier	return (0);
958126258Smlaier}
959126258Smlaier
960126258Smlaiervoid
961126258Smlaierpf_purge_timeout(void *arg)
962126258Smlaier{
963127145Smlaier#ifdef __FreeBSD__
964126261Smlaier	struct callout  *to = arg;
965126261Smlaier#else
966126258Smlaier	struct timeout	*to = arg;
967126261Smlaier#endif
968126258Smlaier	int		 s;
969126258Smlaier
970127145Smlaier#ifdef __FreeBSD__
971126261Smlaier	PF_LOCK();
972126261Smlaier#endif
973126258Smlaier	s = splsoftnet();
974126258Smlaier	pf_purge_expired_states();
975126258Smlaier	pf_purge_expired_fragments();
976130613Smlaier	pf_purge_expired_src_nodes();
977126258Smlaier	splx(s);
978127145Smlaier#ifdef __FreeBSD__
979126261Smlaier	PF_UNLOCK();
980126261Smlaier#endif
981126258Smlaier
982127145Smlaier#ifdef __FreeBSD__
983126261Smlaier	callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz,
984126261Smlaier	    pf_purge_timeout, to);
985126261Smlaier#else
986126258Smlaier	timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
987126261Smlaier#endif
988126258Smlaier}
989126258Smlaier
990126258Smlaieru_int32_t
991126258Smlaierpf_state_expires(const struct pf_state *state)
992126258Smlaier{
993126258Smlaier	u_int32_t	timeout;
994126258Smlaier	u_int32_t	start;
995126258Smlaier	u_int32_t	end;
996126258Smlaier	u_int32_t	states;
997126258Smlaier
998126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
999126258Smlaier	if (state->timeout == PFTM_PURGE)
1000126261Smlaier		return (time_second);
1001126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
1002126258Smlaier		return (0);
1003127145Smlaier#ifdef __FreeBSD__
1004126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
1005126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
1006126261Smlaier#else
1007126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
1008126261Smlaier#endif
1009126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
1010126258Smlaier	if (!timeout)
1011126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
1012126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
1013126258Smlaier	if (start) {
1014126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
1015126258Smlaier		states = state->rule.ptr->states;
1016126258Smlaier	} else {
1017126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1018126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1019126258Smlaier		states = pf_status.states;
1020126258Smlaier	}
1021126258Smlaier	if (end && states > start && start < end) {
1022126258Smlaier		if (states < end)
1023126258Smlaier			return (state->expire + timeout * (end - states) /
1024126258Smlaier			    (end - start));
1025126258Smlaier		else
1026126261Smlaier			return (time_second);
1027126258Smlaier	}
1028126258Smlaier	return (state->expire + timeout);
1029126258Smlaier}
1030126258Smlaier
1031126258Smlaiervoid
1032130613Smlaierpf_purge_expired_src_nodes(void)
1033126258Smlaier{
1034130613Smlaier	 struct pf_src_node		*cur, *next;
1035126258Smlaier
1036130613Smlaier	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
1037130613Smlaier		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
1038126258Smlaier
1039130613Smlaier		 if (cur->states <= 0 && cur->expire <= time_second) {
1040130613Smlaier			 if (cur->rule.ptr != NULL) {
1041130613Smlaier				 cur->rule.ptr->src_nodes--;
1042130613Smlaier				 if (cur->rule.ptr->states <= 0 &&
1043130613Smlaier				     cur->rule.ptr->max_src_nodes <= 0)
1044130613Smlaier					 pf_rm_rule(NULL, cur->rule.ptr);
1045130613Smlaier			 }
1046130613Smlaier			 RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
1047130613Smlaier			 pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1048130613Smlaier			 pf_status.src_nodes--;
1049130613Smlaier			 pool_put(&pf_src_tree_pl, cur);
1050130613Smlaier		 }
1051130613Smlaier	 }
1052130613Smlaier}
1053126258Smlaier
1054130613Smlaiervoid
1055130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
1056130613Smlaier{
1057130613Smlaier	u_int32_t timeout;
1058126258Smlaier
1059130613Smlaier	if (s->src_node != NULL) {
1060145836Smlaier		if (s->proto == IPPROTO_TCP) {
1061145836Smlaier			if (s->src.state == PF_TCPS_PROXY_DST ||
1062145836Smlaier			    s->timeout >= PFTM_TCP_ESTABLISHED)
1063145836Smlaier				--s->src_node->conn;
1064145836Smlaier		}
1065130613Smlaier		if (--s->src_node->states <= 0) {
1066130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1067130613Smlaier			if (!timeout)
1068130613Smlaier				timeout =
1069130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1070130613Smlaier			s->src_node->expire = time_second + timeout;
1071130613Smlaier		}
1072130613Smlaier	}
1073130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
1074130613Smlaier		if (--s->nat_src_node->states <= 0) {
1075130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1076130613Smlaier			if (!timeout)
1077130613Smlaier				timeout =
1078130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1079130613Smlaier			s->nat_src_node->expire = time_second + timeout;
1080130613Smlaier		}
1081130613Smlaier	}
1082130613Smlaier	s->src_node = s->nat_src_node = NULL;
1083130613Smlaier}
1084126258Smlaier
1085130613Smlaiervoid
1086145836Smlaierpf_purge_expired_state(struct pf_state *cur)
1087145836Smlaier{
1088145836Smlaier	if (cur->src.state == PF_TCPS_PROXY_DST)
1089145836Smlaier		pf_send_tcp(cur->rule.ptr, cur->af,
1090145836Smlaier		    &cur->ext.addr, &cur->lan.addr,
1091145836Smlaier		    cur->ext.port, cur->lan.port,
1092145836Smlaier		    cur->src.seqhi, cur->src.seqlo + 1,
1093145836Smlaier		    TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL);
1094145836Smlaier	RB_REMOVE(pf_state_tree_ext_gwy,
1095145836Smlaier	    &cur->u.s.kif->pfik_ext_gwy, cur);
1096145836Smlaier	RB_REMOVE(pf_state_tree_lan_ext,
1097145836Smlaier	    &cur->u.s.kif->pfik_lan_ext, cur);
1098145836Smlaier	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
1099145836Smlaier#if NPFSYNC
1100145836Smlaier	pfsync_delete_state(cur);
1101145836Smlaier#endif
1102145836Smlaier	pf_src_tree_remove_state(cur);
1103145836Smlaier	if (--cur->rule.ptr->states <= 0 &&
1104145836Smlaier	    cur->rule.ptr->src_nodes <= 0)
1105145836Smlaier		pf_rm_rule(NULL, cur->rule.ptr);
1106145836Smlaier	if (cur->nat_rule.ptr != NULL)
1107145836Smlaier		if (--cur->nat_rule.ptr->states <= 0 &&
1108145836Smlaier			cur->nat_rule.ptr->src_nodes <= 0)
1109145836Smlaier			pf_rm_rule(NULL, cur->nat_rule.ptr);
1110145836Smlaier	if (cur->anchor.ptr != NULL)
1111145836Smlaier		if (--cur->anchor.ptr->states <= 0)
1112145836Smlaier			pf_rm_rule(NULL, cur->anchor.ptr);
1113145836Smlaier	pf_normalize_tcp_cleanup(cur);
1114145836Smlaier	pfi_detach_state(cur->u.s.kif);
1115145836Smlaier	TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
1116145836Smlaier	if (cur->tag)
1117145836Smlaier		pf_tag_unref(cur->tag);
1118145836Smlaier	pool_put(&pf_state_pl, cur);
1119145836Smlaier	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1120145836Smlaier	pf_status.states--;
1121145836Smlaier}
1122145836Smlaier
1123145836Smlaiervoid
1124130613Smlaierpf_purge_expired_states(void)
1125130613Smlaier{
1126130613Smlaier	struct pf_state		*cur, *next;
1127130613Smlaier
1128130613Smlaier	for (cur = RB_MIN(pf_state_tree_id, &tree_id);
1129130613Smlaier	    cur; cur = next) {
1130130613Smlaier		next = RB_NEXT(pf_state_tree_id, &tree_id, cur);
1131145836Smlaier		if (pf_state_expires(cur) <= time_second)
1132145836Smlaier			pf_purge_expired_state(cur);
1133126258Smlaier	}
1134126258Smlaier}
1135126258Smlaier
1136126258Smlaierint
1137126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
1138126258Smlaier{
1139126258Smlaier	if (aw->type != PF_ADDR_TABLE)
1140126258Smlaier		return (0);
1141126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
1142126258Smlaier		return (1);
1143126258Smlaier	return (0);
1144126258Smlaier}
1145126258Smlaier
1146126258Smlaiervoid
1147126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
1148126258Smlaier{
1149126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
1150126258Smlaier		return;
1151126258Smlaier	pfr_detach_table(aw->p.tbl);
1152126258Smlaier	aw->p.tbl = NULL;
1153126258Smlaier}
1154126258Smlaier
1155126258Smlaiervoid
1156126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
1157126258Smlaier{
1158126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
1159126258Smlaier
1160126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
1161126258Smlaier		return;
1162126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
1163126258Smlaier		kt = kt->pfrkt_root;
1164126258Smlaier	aw->p.tbl = NULL;
1165126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1166126258Smlaier		kt->pfrkt_cnt : -1;
1167126258Smlaier}
1168126258Smlaier
1169126258Smlaiervoid
1170126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1171126258Smlaier{
1172126258Smlaier	switch (af) {
1173126258Smlaier#ifdef INET
1174126258Smlaier	case AF_INET: {
1175126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1176126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1177126258Smlaier		    (a>>8)&255, a&255);
1178126258Smlaier		if (p) {
1179126258Smlaier			p = ntohs(p);
1180126258Smlaier			printf(":%u", p);
1181126258Smlaier		}
1182126258Smlaier		break;
1183126258Smlaier	}
1184126258Smlaier#endif /* INET */
1185126258Smlaier#ifdef INET6
1186126258Smlaier	case AF_INET6: {
1187126258Smlaier		u_int16_t b;
1188126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
1189126258Smlaier		    maxstart = 0, maxend = 0;
1190126258Smlaier		for (i = 0; i < 8; i++) {
1191126258Smlaier			if (!addr->addr16[i]) {
1192126258Smlaier				if (curstart == 255)
1193126258Smlaier					curstart = i;
1194126258Smlaier				else
1195126258Smlaier					curend = i;
1196126258Smlaier			} else {
1197126258Smlaier				if (curstart) {
1198126258Smlaier					if ((curend - curstart) >
1199126258Smlaier					    (maxend - maxstart)) {
1200126258Smlaier						maxstart = curstart;
1201126258Smlaier						maxend = curend;
1202126258Smlaier						curstart = 255;
1203126258Smlaier					}
1204126258Smlaier				}
1205126258Smlaier			}
1206126258Smlaier		}
1207126258Smlaier		for (i = 0; i < 8; i++) {
1208126258Smlaier			if (i >= maxstart && i <= maxend) {
1209126258Smlaier				if (maxend != 7) {
1210126258Smlaier					if (i == maxstart)
1211126258Smlaier						printf(":");
1212126258Smlaier				} else {
1213126258Smlaier					if (i == maxend)
1214126258Smlaier						printf(":");
1215126258Smlaier				}
1216126258Smlaier			} else {
1217126258Smlaier				b = ntohs(addr->addr16[i]);
1218126258Smlaier				printf("%x", b);
1219126258Smlaier				if (i < 7)
1220126258Smlaier					printf(":");
1221126258Smlaier			}
1222126258Smlaier		}
1223126258Smlaier		if (p) {
1224126258Smlaier			p = ntohs(p);
1225126258Smlaier			printf("[%u]", p);
1226126258Smlaier		}
1227126258Smlaier		break;
1228126258Smlaier	}
1229126258Smlaier#endif /* INET6 */
1230126258Smlaier	}
1231126258Smlaier}
1232126258Smlaier
1233126258Smlaiervoid
1234126258Smlaierpf_print_state(struct pf_state *s)
1235126258Smlaier{
1236126258Smlaier	switch (s->proto) {
1237126258Smlaier	case IPPROTO_TCP:
1238126258Smlaier		printf("TCP ");
1239126258Smlaier		break;
1240126258Smlaier	case IPPROTO_UDP:
1241126258Smlaier		printf("UDP ");
1242126258Smlaier		break;
1243126258Smlaier	case IPPROTO_ICMP:
1244126258Smlaier		printf("ICMP ");
1245126258Smlaier		break;
1246126258Smlaier	case IPPROTO_ICMPV6:
1247126258Smlaier		printf("ICMPV6 ");
1248126258Smlaier		break;
1249126258Smlaier	default:
1250126258Smlaier		printf("%u ", s->proto);
1251126258Smlaier		break;
1252126258Smlaier	}
1253126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
1254126258Smlaier	printf(" ");
1255126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
1256126258Smlaier	printf(" ");
1257126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
1258126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
1259126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
1260126258Smlaier	if (s->src.wscale && s->dst.wscale)
1261126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
1262126258Smlaier	printf("]");
1263126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
1264126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
1265126258Smlaier	if (s->src.wscale && s->dst.wscale)
1266126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
1267126258Smlaier	printf("]");
1268126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
1269126258Smlaier}
1270126258Smlaier
1271126258Smlaiervoid
1272126258Smlaierpf_print_flags(u_int8_t f)
1273126258Smlaier{
1274126258Smlaier	if (f)
1275126258Smlaier		printf(" ");
1276126258Smlaier	if (f & TH_FIN)
1277126258Smlaier		printf("F");
1278126258Smlaier	if (f & TH_SYN)
1279126258Smlaier		printf("S");
1280126258Smlaier	if (f & TH_RST)
1281126258Smlaier		printf("R");
1282126258Smlaier	if (f & TH_PUSH)
1283126258Smlaier		printf("P");
1284126258Smlaier	if (f & TH_ACK)
1285126258Smlaier		printf("A");
1286126258Smlaier	if (f & TH_URG)
1287126258Smlaier		printf("U");
1288126258Smlaier	if (f & TH_ECE)
1289126258Smlaier		printf("E");
1290126258Smlaier	if (f & TH_CWR)
1291126258Smlaier		printf("W");
1292126258Smlaier}
1293126258Smlaier
1294126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1295126258Smlaier	do {							\
1296126258Smlaier		while (head[i] != cur) {			\
1297126258Smlaier			head[i]->skip[i].ptr = cur;		\
1298126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1299126258Smlaier		}						\
1300126258Smlaier	} while (0)
1301126258Smlaier
1302126258Smlaiervoid
1303126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1304126258Smlaier{
1305126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1306126258Smlaier	int i;
1307126258Smlaier
1308126258Smlaier	cur = TAILQ_FIRST(rules);
1309126258Smlaier	prev = cur;
1310126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1311126258Smlaier		head[i] = cur;
1312126258Smlaier	while (cur != NULL) {
1313126258Smlaier
1314130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1315126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1316126258Smlaier		if (cur->direction != prev->direction)
1317126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1318126258Smlaier		if (cur->af != prev->af)
1319126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1320126258Smlaier		if (cur->proto != prev->proto)
1321126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1322145836Smlaier		if (cur->src.neg != prev->src.neg ||
1323126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1324126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1325126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1326126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1327126258Smlaier		    cur->src.port_op != prev->src.port_op)
1328126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1329145836Smlaier		if (cur->dst.neg != prev->dst.neg ||
1330126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1331126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1332126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1333126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1334126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1335126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1336126258Smlaier
1337126258Smlaier		prev = cur;
1338126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1339126258Smlaier	}
1340126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1341126258Smlaier		PF_SET_SKIP_STEPS(i);
1342126258Smlaier}
1343126258Smlaier
1344126258Smlaierint
1345126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1346126258Smlaier{
1347126258Smlaier	if (aw1->type != aw2->type)
1348126258Smlaier		return (1);
1349126258Smlaier	switch (aw1->type) {
1350126258Smlaier	case PF_ADDR_ADDRMASK:
1351126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1352126258Smlaier			return (1);
1353126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1354126258Smlaier			return (1);
1355126258Smlaier		return (0);
1356126258Smlaier	case PF_ADDR_DYNIFTL:
1357130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1358126258Smlaier	case PF_ADDR_NOROUTE:
1359126258Smlaier		return (0);
1360126258Smlaier	case PF_ADDR_TABLE:
1361126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
1362126258Smlaier	default:
1363126258Smlaier		printf("invalid address type: %d\n", aw1->type);
1364126258Smlaier		return (1);
1365126258Smlaier	}
1366126258Smlaier}
1367126258Smlaier
1368126258Smlaieru_int16_t
1369126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
1370126258Smlaier{
1371126258Smlaier	u_int32_t	l;
1372126258Smlaier
1373126258Smlaier	if (udp && !cksum)
1374126258Smlaier		return (0x0000);
1375126258Smlaier	l = cksum + old - new;
1376126258Smlaier	l = (l >> 16) + (l & 65535);
1377126258Smlaier	l = l & 65535;
1378126258Smlaier	if (udp && !l)
1379126258Smlaier		return (0xFFFF);
1380126258Smlaier	return (l);
1381126258Smlaier}
1382126258Smlaier
1383126258Smlaiervoid
1384126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
1385126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
1386126258Smlaier{
1387126258Smlaier	struct pf_addr	ao;
1388126258Smlaier	u_int16_t	po = *p;
1389126258Smlaier
1390126258Smlaier	PF_ACPY(&ao, a, af);
1391126258Smlaier	PF_ACPY(a, an, af);
1392126258Smlaier
1393126258Smlaier	*p = pn;
1394126258Smlaier
1395126258Smlaier	switch (af) {
1396126258Smlaier#ifdef INET
1397126258Smlaier	case AF_INET:
1398126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1399126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
1400126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
1401126258Smlaier		*p = pn;
1402126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1403126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1404126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1405126258Smlaier		    po, pn, u);
1406126258Smlaier		break;
1407126258Smlaier#endif /* INET */
1408126258Smlaier#ifdef INET6
1409126258Smlaier	case AF_INET6:
1410126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1411126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1412126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1413126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1414126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1415126258Smlaier		    ao.addr16[2], an->addr16[2], u),
1416126258Smlaier		    ao.addr16[3], an->addr16[3], u),
1417126258Smlaier		    ao.addr16[4], an->addr16[4], u),
1418126258Smlaier		    ao.addr16[5], an->addr16[5], u),
1419126258Smlaier		    ao.addr16[6], an->addr16[6], u),
1420126258Smlaier		    ao.addr16[7], an->addr16[7], u),
1421126258Smlaier		    po, pn, u);
1422126258Smlaier		break;
1423126258Smlaier#endif /* INET6 */
1424126258Smlaier	}
1425126258Smlaier}
1426126258Smlaier
1427126258Smlaier
1428126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
1429126258Smlaiervoid
1430126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
1431126258Smlaier{
1432126258Smlaier	u_int32_t	ao;
1433126258Smlaier
1434126258Smlaier	memcpy(&ao, a, sizeof(ao));
1435126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
1436126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
1437126258Smlaier	    ao % 65536, an % 65536, u);
1438126258Smlaier}
1439126258Smlaier
1440126258Smlaier#ifdef INET6
1441126258Smlaiervoid
1442126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
1443126258Smlaier{
1444126258Smlaier	struct pf_addr	ao;
1445126258Smlaier
1446126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
1447126258Smlaier	PF_ACPY(a, an, AF_INET6);
1448126258Smlaier
1449126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1450126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1451126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
1452126258Smlaier	    ao.addr16[0], an->addr16[0], u),
1453126258Smlaier	    ao.addr16[1], an->addr16[1], u),
1454126258Smlaier	    ao.addr16[2], an->addr16[2], u),
1455126258Smlaier	    ao.addr16[3], an->addr16[3], u),
1456126258Smlaier	    ao.addr16[4], an->addr16[4], u),
1457126258Smlaier	    ao.addr16[5], an->addr16[5], u),
1458126258Smlaier	    ao.addr16[6], an->addr16[6], u),
1459126258Smlaier	    ao.addr16[7], an->addr16[7], u);
1460126258Smlaier}
1461126258Smlaier#endif /* INET6 */
1462126258Smlaier
1463126258Smlaiervoid
1464126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1465126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1466126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1467126258Smlaier{
1468126258Smlaier	struct pf_addr	oia, ooa;
1469126258Smlaier
1470126258Smlaier	PF_ACPY(&oia, ia, af);
1471126258Smlaier	PF_ACPY(&ooa, oa, af);
1472126258Smlaier
1473126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1474126258Smlaier	if (ip != NULL) {
1475126258Smlaier		u_int16_t	oip = *ip;
1476127629Smlaier		u_int32_t	opc = 0;	/* make the compiler happy */
1477126258Smlaier
1478126258Smlaier		if (pc != NULL)
1479126258Smlaier			opc = *pc;
1480126258Smlaier		*ip = np;
1481126258Smlaier		if (pc != NULL)
1482126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1483126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1484126258Smlaier		if (pc != NULL)
1485126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1486126258Smlaier	}
1487126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1488126258Smlaier	PF_ACPY(ia, na, af);
1489126258Smlaier	switch (af) {
1490126258Smlaier#ifdef INET
1491126258Smlaier	case AF_INET: {
1492126258Smlaier		u_int32_t	 oh2c = *h2c;
1493126258Smlaier
1494126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1495126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1496126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1497126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1498126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1499126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1500126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1501126258Smlaier		break;
1502126258Smlaier	}
1503126258Smlaier#endif /* INET */
1504126258Smlaier#ifdef INET6
1505126258Smlaier	case AF_INET6:
1506126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1507126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1508126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1509126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1510126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1511126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1512126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1513126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1514126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1515126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1516126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1517126258Smlaier		break;
1518126258Smlaier#endif /* INET6 */
1519126258Smlaier	}
1520126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1521126258Smlaier	PF_ACPY(oa, na, af);
1522126258Smlaier	switch (af) {
1523126258Smlaier#ifdef INET
1524126258Smlaier	case AF_INET:
1525126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1526126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1527126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1528126258Smlaier		break;
1529126258Smlaier#endif /* INET */
1530126258Smlaier#ifdef INET6
1531126258Smlaier	case AF_INET6:
1532126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1533126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1534126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1535126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1536126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1537126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1538126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1539126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1540126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1541126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1542126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1543126258Smlaier		break;
1544126258Smlaier#endif /* INET6 */
1545126258Smlaier	}
1546126258Smlaier}
1547126258Smlaier
1548126258Smlaiervoid
1549126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1550126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1551126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1552145836Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
1553145836Smlaier    struct ether_header *eh, struct ifnet *ifp)
1554126258Smlaier{
1555126258Smlaier	struct mbuf	*m;
1556127629Smlaier	int		 len = 0, tlen;		/* make the compiler happy */
1557126258Smlaier#ifdef INET
1558127629Smlaier	struct ip	*h = NULL;		/* make the compiler happy */
1559126258Smlaier#endif /* INET */
1560126258Smlaier#ifdef INET6
1561127629Smlaier	struct ip6_hdr	*h6 = NULL;		/* make the compiler happy */
1562126258Smlaier#endif /* INET6 */
1563127629Smlaier	struct tcphdr	*th = NULL;		/* make the compiler happy */
1564126258Smlaier	char *opt;
1565126258Smlaier
1566126258Smlaier	/* maximum segment size tcp option */
1567126258Smlaier	tlen = sizeof(struct tcphdr);
1568126258Smlaier	if (mss)
1569126258Smlaier		tlen += 4;
1570126258Smlaier
1571126258Smlaier	switch (af) {
1572126258Smlaier#ifdef INET
1573126258Smlaier	case AF_INET:
1574126258Smlaier		len = sizeof(struct ip) + tlen;
1575126258Smlaier		break;
1576126258Smlaier#endif /* INET */
1577126258Smlaier#ifdef INET6
1578126258Smlaier	case AF_INET6:
1579126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1580126258Smlaier		break;
1581126258Smlaier#endif /* INET6 */
1582126258Smlaier	}
1583126258Smlaier
1584126258Smlaier	/* create outgoing mbuf */
1585132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1586132280Smlaier	if (m == NULL)
1587132280Smlaier		return;
1588145836Smlaier	if (tag) {
1589145836Smlaier#ifdef __FreeBSD__
1590145836Smlaier		m->m_flags |= M_SKIP_FIREWALL;
1591132280Smlaier#else
1592145836Smlaier		struct m_tag	*mtag;
1593145836Smlaier
1594145836Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1595145836Smlaier		if (mtag == NULL) {
1596145836Smlaier			m_freem(m);
1597145836Smlaier			return;
1598145836Smlaier		}
1599145836Smlaier		m_tag_prepend(m, mtag);
1600145836Smlaier#endif
1601126258Smlaier	}
1602126258Smlaier#ifdef ALTQ
1603126258Smlaier	if (r != NULL && r->qid) {
1604145836Smlaier		struct m_tag	*mtag;
1605126258Smlaier		struct altq_tag *atag;
1606126258Smlaier
1607126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1608126258Smlaier		if (mtag != NULL) {
1609126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1610126258Smlaier			atag->qid = r->qid;
1611126258Smlaier			/* add hints for ecn */
1612126258Smlaier			atag->af = af;
1613126258Smlaier			atag->hdr = mtod(m, struct ip *);
1614126258Smlaier			m_tag_prepend(m, mtag);
1615126258Smlaier		}
1616126258Smlaier	}
1617145836Smlaier#endif /* ALTQ */
1618126258Smlaier	m->m_data += max_linkhdr;
1619126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1620126258Smlaier	m->m_pkthdr.rcvif = NULL;
1621126258Smlaier	bzero(m->m_data, len);
1622126258Smlaier	switch (af) {
1623126258Smlaier#ifdef INET
1624126258Smlaier	case AF_INET:
1625126258Smlaier		h = mtod(m, struct ip *);
1626126258Smlaier
1627126258Smlaier		/* IP header fields included in the TCP checksum */
1628126258Smlaier		h->ip_p = IPPROTO_TCP;
1629126258Smlaier		h->ip_len = htons(tlen);
1630126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1631126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1632126258Smlaier
1633126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1634126258Smlaier		break;
1635126258Smlaier#endif /* INET */
1636126258Smlaier#ifdef INET6
1637126258Smlaier	case AF_INET6:
1638126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1639126258Smlaier
1640126258Smlaier		/* IP header fields included in the TCP checksum */
1641126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1642126258Smlaier		h6->ip6_plen = htons(tlen);
1643126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1644126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1645126258Smlaier
1646126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1647126258Smlaier		break;
1648126258Smlaier#endif /* INET6 */
1649126258Smlaier	}
1650126258Smlaier
1651126258Smlaier	/* TCP header */
1652126258Smlaier	th->th_sport = sport;
1653126258Smlaier	th->th_dport = dport;
1654126258Smlaier	th->th_seq = htonl(seq);
1655126258Smlaier	th->th_ack = htonl(ack);
1656126258Smlaier	th->th_off = tlen >> 2;
1657126258Smlaier	th->th_flags = flags;
1658126258Smlaier	th->th_win = htons(win);
1659126258Smlaier
1660126258Smlaier	if (mss) {
1661126258Smlaier		opt = (char *)(th + 1);
1662126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1663126258Smlaier		opt[1] = 4;
1664126258Smlaier		HTONS(mss);
1665126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1666126258Smlaier	}
1667126258Smlaier
1668126258Smlaier	switch (af) {
1669126258Smlaier#ifdef INET
1670126258Smlaier	case AF_INET:
1671126258Smlaier		/* TCP checksum */
1672126258Smlaier		th->th_sum = in_cksum(m, len);
1673126258Smlaier
1674126258Smlaier		/* Finish the IP header */
1675126258Smlaier		h->ip_v = 4;
1676126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1677126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1678127145Smlaier#ifdef __FreeBSD__
1679130613Smlaier		h->ip_off = path_mtu_discovery ? IP_DF : 0;
1680130613Smlaier		h->ip_len = len;
1681126261Smlaier#else
1682126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1683130613Smlaier		h->ip_len = htons(len);
1684126261Smlaier#endif
1685126258Smlaier		h->ip_ttl = ttl ? ttl : ip_defttl;
1686126258Smlaier		h->ip_sum = 0;
1687145836Smlaier		if (eh == NULL) {
1688127145Smlaier#ifdef __FreeBSD__
1689145836Smlaier			PF_UNLOCK();
1690145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1691145836Smlaier			    (void *)NULL, (void *)NULL);
1692145836Smlaier			PF_LOCK();
1693126261Smlaier#else /* ! __FreeBSD__ */
1694145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1695145836Smlaier			    (void *)NULL, (void *)NULL);
1696126261Smlaier#endif
1697145836Smlaier		} else {
1698145836Smlaier			struct route		 ro;
1699145836Smlaier			struct rtentry		 rt;
1700145836Smlaier			struct ether_header	*e = (void *)ro.ro_dst.sa_data;
1701145836Smlaier
1702145836Smlaier			if (ifp == NULL) {
1703145836Smlaier				m_freem(m);
1704145836Smlaier				return;
1705145836Smlaier			}
1706145836Smlaier			rt.rt_ifp = ifp;
1707145836Smlaier			ro.ro_rt = &rt;
1708145836Smlaier			ro.ro_dst.sa_len = sizeof(ro.ro_dst);
1709145836Smlaier			ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
1710145836Smlaier			bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
1711145836Smlaier			bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
1712145836Smlaier			e->ether_type = eh->ether_type;
1713145836Smlaier#ifdef __FreeBSD__
1714145836Smlaier			PF_UNLOCK();
1715145836Smlaier			/* XXX_IMPORT: later */
1716145836Smlaier			ip_output(m, (void *)NULL, &ro, 0,
1717145836Smlaier			    (void *)NULL, (void *)NULL);
1718145836Smlaier			PF_LOCK();
1719145836Smlaier#else /* ! __FreeBSD__ */
1720145836Smlaier			ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
1721145836Smlaier			    (void *)NULL, (void *)NULL);
1722145836Smlaier#endif
1723145836Smlaier		}
1724126258Smlaier		break;
1725126258Smlaier#endif /* INET */
1726126258Smlaier#ifdef INET6
1727126258Smlaier	case AF_INET6:
1728126258Smlaier		/* TCP checksum */
1729126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
1730126258Smlaier		    sizeof(struct ip6_hdr), tlen);
1731126258Smlaier
1732126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
1733126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
1734126258Smlaier
1735127145Smlaier#ifdef __FreeBSD__
1736126261Smlaier		PF_UNLOCK();
1737126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
1738126261Smlaier		PF_LOCK();
1739126261Smlaier#else
1740126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
1741126261Smlaier#endif
1742126258Smlaier		break;
1743126258Smlaier#endif /* INET6 */
1744126258Smlaier	}
1745126258Smlaier}
1746126258Smlaier
1747126258Smlaiervoid
1748126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
1749126258Smlaier    struct pf_rule *r)
1750126258Smlaier{
1751132280Smlaier#ifdef ALTQ
1752126258Smlaier	struct m_tag	*mtag;
1753132280Smlaier#endif
1754126258Smlaier	struct mbuf	*m0;
1755127145Smlaier#ifdef __FreeBSD__
1756126261Smlaier	struct ip *ip;
1757126261Smlaier#endif
1758126258Smlaier
1759132280Smlaier#ifdef __FreeBSD__
1760132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
1761132280Smlaier	if (m0 == NULL)
1762132280Smlaier		return;
1763132280Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
1764132280Smlaier#else
1765126258Smlaier	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1766126258Smlaier	if (mtag == NULL)
1767126258Smlaier		return;
1768126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
1769126258Smlaier	if (m0 == NULL) {
1770126258Smlaier		m_tag_free(mtag);
1771126258Smlaier		return;
1772126258Smlaier	}
1773126258Smlaier	m_tag_prepend(m0, mtag);
1774132280Smlaier#endif
1775126258Smlaier
1776126258Smlaier#ifdef ALTQ
1777126258Smlaier	if (r->qid) {
1778126258Smlaier		struct altq_tag *atag;
1779126258Smlaier
1780126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1781126258Smlaier		if (mtag != NULL) {
1782126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1783126258Smlaier			atag->qid = r->qid;
1784126258Smlaier			/* add hints for ecn */
1785126258Smlaier			atag->af = af;
1786126258Smlaier			atag->hdr = mtod(m0, struct ip *);
1787126258Smlaier			m_tag_prepend(m0, mtag);
1788126258Smlaier		}
1789126258Smlaier	}
1790145836Smlaier#endif /* ALTQ */
1791126258Smlaier
1792126258Smlaier	switch (af) {
1793126258Smlaier#ifdef INET
1794126258Smlaier	case AF_INET:
1795127145Smlaier#ifdef __FreeBSD__
1796126261Smlaier		/* icmp_error() expects host byte ordering */
1797126261Smlaier		ip = mtod(m0, struct ip *);
1798126261Smlaier		NTOHS(ip->ip_len);
1799126261Smlaier		NTOHS(ip->ip_off);
1800126261Smlaier		PF_UNLOCK();
1801145863Sandre		icmp_error(m0, type, code, 0, 0);
1802126261Smlaier		PF_LOCK();
1803145874Smlaier#else
1804145874Smlaier		icmp_error(m0, type, code, 0, (void *)NULL);
1805126261Smlaier#endif
1806126258Smlaier		break;
1807126258Smlaier#endif /* INET */
1808126258Smlaier#ifdef INET6
1809126258Smlaier	case AF_INET6:
1810127145Smlaier#ifdef __FreeBSD__
1811126261Smlaier		PF_UNLOCK();
1812126261Smlaier#endif
1813126258Smlaier		icmp6_error(m0, type, code, 0);
1814127145Smlaier#ifdef __FreeBSD__
1815126261Smlaier		PF_LOCK();
1816126261Smlaier#endif
1817126258Smlaier		break;
1818126258Smlaier#endif /* INET6 */
1819126258Smlaier	}
1820126258Smlaier}
1821126258Smlaier
1822126258Smlaier/*
1823126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
1824126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
1825126258Smlaier * are different.
1826126258Smlaier */
1827126258Smlaierint
1828126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
1829126258Smlaier    struct pf_addr *b, sa_family_t af)
1830126258Smlaier{
1831126258Smlaier	int	match = 0;
1832126258Smlaier
1833126258Smlaier	switch (af) {
1834126258Smlaier#ifdef INET
1835126258Smlaier	case AF_INET:
1836126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
1837126258Smlaier		    (b->addr32[0] & m->addr32[0]))
1838126258Smlaier			match++;
1839126258Smlaier		break;
1840126258Smlaier#endif /* INET */
1841126258Smlaier#ifdef INET6
1842126258Smlaier	case AF_INET6:
1843126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
1844126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
1845126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
1846126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
1847126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
1848126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
1849126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
1850126258Smlaier		     (b->addr32[3] & m->addr32[3])))
1851126258Smlaier			match++;
1852126258Smlaier		break;
1853126258Smlaier#endif /* INET6 */
1854126258Smlaier	}
1855126258Smlaier	if (match) {
1856126258Smlaier		if (n)
1857126258Smlaier			return (0);
1858126258Smlaier		else
1859126258Smlaier			return (1);
1860126258Smlaier	} else {
1861126258Smlaier		if (n)
1862126258Smlaier			return (1);
1863126258Smlaier		else
1864126258Smlaier			return (0);
1865126258Smlaier	}
1866126258Smlaier}
1867126258Smlaier
1868126258Smlaierint
1869126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
1870126258Smlaier{
1871126258Smlaier	switch (op) {
1872126258Smlaier	case PF_OP_IRG:
1873126258Smlaier		return ((p > a1) && (p < a2));
1874126258Smlaier	case PF_OP_XRG:
1875126258Smlaier		return ((p < a1) || (p > a2));
1876126258Smlaier	case PF_OP_RRG:
1877126258Smlaier		return ((p >= a1) && (p <= a2));
1878126258Smlaier	case PF_OP_EQ:
1879126258Smlaier		return (p == a1);
1880126258Smlaier	case PF_OP_NE:
1881126258Smlaier		return (p != a1);
1882126258Smlaier	case PF_OP_LT:
1883126258Smlaier		return (p < a1);
1884126258Smlaier	case PF_OP_LE:
1885126258Smlaier		return (p <= a1);
1886126258Smlaier	case PF_OP_GT:
1887126258Smlaier		return (p > a1);
1888126258Smlaier	case PF_OP_GE:
1889126258Smlaier		return (p >= a1);
1890126258Smlaier	}
1891126258Smlaier	return (0); /* never reached */
1892126258Smlaier}
1893126258Smlaier
1894126258Smlaierint
1895126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
1896126258Smlaier{
1897126258Smlaier	NTOHS(a1);
1898126258Smlaier	NTOHS(a2);
1899126258Smlaier	NTOHS(p);
1900126258Smlaier	return (pf_match(op, a1, a2, p));
1901126258Smlaier}
1902126258Smlaier
1903126258Smlaierint
1904126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
1905126258Smlaier{
1906126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1907126258Smlaier		return (0);
1908126258Smlaier	return (pf_match(op, a1, a2, u));
1909126258Smlaier}
1910126258Smlaier
1911126258Smlaierint
1912126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
1913126258Smlaier{
1914126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1915126258Smlaier		return (0);
1916126258Smlaier	return (pf_match(op, a1, a2, g));
1917126258Smlaier}
1918126258Smlaier
1919126258Smlaierstruct pf_tag *
1920126258Smlaierpf_get_tag(struct mbuf *m)
1921126258Smlaier{
1922126258Smlaier	struct m_tag	*mtag;
1923126258Smlaier
1924126258Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
1925126258Smlaier		return ((struct pf_tag *)(mtag + 1));
1926126258Smlaier	else
1927126258Smlaier		return (NULL);
1928126258Smlaier}
1929126258Smlaier
1930126258Smlaierint
1931145836Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag)
1932126258Smlaier{
1933126258Smlaier	if (*tag == -1) {	/* find mbuf tag */
1934145836Smlaier		*pftag = pf_get_tag(m);
1935145836Smlaier		if (*pftag != NULL)
1936145836Smlaier			*tag = (*pftag)->tag;
1937126258Smlaier		else
1938126258Smlaier			*tag = 0;
1939126258Smlaier	}
1940126258Smlaier
1941126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
1942126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
1943126258Smlaier}
1944126258Smlaier
1945126258Smlaierint
1946126258Smlaierpf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
1947126258Smlaier{
1948126258Smlaier	struct m_tag	*mtag;
1949126258Smlaier
1950126258Smlaier	if (tag <= 0)
1951126258Smlaier		return (0);
1952126258Smlaier
1953126258Smlaier	if (pftag == NULL) {
1954126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
1955126258Smlaier		if (mtag == NULL)
1956126258Smlaier			return (1);
1957126258Smlaier		((struct pf_tag *)(mtag + 1))->tag = tag;
1958126258Smlaier		m_tag_prepend(m, mtag);
1959126258Smlaier	} else
1960126258Smlaier		pftag->tag = tag;
1961126258Smlaier
1962126258Smlaier	return (0);
1963126258Smlaier}
1964126258Smlaier
1965145836Smlaierstatic void
1966145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
1967145836Smlaier    struct pf_rule **r, struct pf_rule **a)
1968145836Smlaier{
1969145836Smlaier	struct pf_anchor_stackframe	*f;
1970126258Smlaier
1971145836Smlaier	if (*depth >= sizeof(pf_anchor_stack) /
1972145836Smlaier	    sizeof(pf_anchor_stack[0])) {
1973145836Smlaier		printf("pf_step_into_anchor: stack overflow\n");
1974145836Smlaier		*r = TAILQ_NEXT(*r, entries);
1975145836Smlaier		return;
1976145836Smlaier	} else if (*depth == 0 && a != NULL)
1977145836Smlaier		*a = *r;
1978145836Smlaier	f = pf_anchor_stack + (*depth)++;
1979145836Smlaier	f->rs = *rs;
1980145836Smlaier	f->r = *r;
1981145836Smlaier	if ((*r)->anchor_wildcard) {
1982145836Smlaier		f->parent = &(*r)->anchor->children;
1983145836Smlaier		if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
1984145836Smlaier		    NULL) {
1985145836Smlaier			*r = NULL;
1986145836Smlaier			return;
1987145836Smlaier		}
1988145836Smlaier		*rs = &f->child->ruleset;
1989145836Smlaier	} else {
1990145836Smlaier		f->parent = NULL;
1991145836Smlaier		f->child = NULL;
1992145836Smlaier		*rs = &(*r)->anchor->ruleset;
1993145836Smlaier	}
1994145836Smlaier	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
1995145836Smlaier}
1996126258Smlaier
1997145836Smlaierstatic void
1998145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
1999145836Smlaier    struct pf_rule **r, struct pf_rule **a)
2000145836Smlaier{
2001145836Smlaier	struct pf_anchor_stackframe	*f;
2002145836Smlaier
2003145836Smlaier	do {
2004145836Smlaier		if (*depth <= 0)
2005145836Smlaier			break;
2006145836Smlaier		f = pf_anchor_stack + *depth - 1;
2007145836Smlaier		if (f->parent != NULL && f->child != NULL) {
2008145836Smlaier			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
2009145836Smlaier			if (f->child != NULL) {
2010145836Smlaier				*rs = &f->child->ruleset;
2011145836Smlaier				*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2012145836Smlaier				if (*r == NULL)
2013145836Smlaier					continue;
2014145836Smlaier				else
2015145836Smlaier					break;
2016145836Smlaier			}
2017145836Smlaier		}
2018145836Smlaier		(*depth)--;
2019145836Smlaier		if (*depth == 0 && a != NULL)
2020145836Smlaier			*a = NULL;
2021145836Smlaier		*rs = f->rs;
2022145836Smlaier		*r = TAILQ_NEXT(f->r, entries);
2023145836Smlaier	} while (*r == NULL);
2024145836Smlaier}
2025145836Smlaier
2026126258Smlaier#ifdef INET6
2027126258Smlaiervoid
2028126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
2029126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
2030126258Smlaier{
2031126258Smlaier	switch (af) {
2032126258Smlaier#ifdef INET
2033126258Smlaier	case AF_INET:
2034126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2035126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2036126258Smlaier		break;
2037126258Smlaier#endif /* INET */
2038126258Smlaier	case AF_INET6:
2039126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2040126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2041126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
2042126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
2043126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
2044126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
2045126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
2046126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
2047126258Smlaier		break;
2048126258Smlaier	}
2049126258Smlaier}
2050126258Smlaier
2051126258Smlaiervoid
2052130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
2053126258Smlaier{
2054126258Smlaier	switch (af) {
2055126258Smlaier#ifdef INET
2056126258Smlaier	case AF_INET:
2057126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
2058126258Smlaier		break;
2059126258Smlaier#endif /* INET */
2060126258Smlaier	case AF_INET6:
2061126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
2062126258Smlaier			addr->addr32[3] = 0;
2063126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
2064126258Smlaier				addr->addr32[2] = 0;
2065126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
2066126258Smlaier					addr->addr32[1] = 0;
2067126258Smlaier					addr->addr32[0] =
2068126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
2069126258Smlaier				} else
2070126258Smlaier					addr->addr32[1] =
2071126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
2072126258Smlaier			} else
2073126258Smlaier				addr->addr32[2] =
2074126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
2075126258Smlaier		} else
2076126258Smlaier			addr->addr32[3] =
2077126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
2078126258Smlaier		break;
2079126258Smlaier	}
2080126258Smlaier}
2081126258Smlaier#endif /* INET6 */
2082126258Smlaier
2083126258Smlaier#define mix(a,b,c) \
2084126258Smlaier	do {					\
2085126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
2086126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
2087126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
2088126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
2089126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
2090126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
2091126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
2092126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
2093126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
2094126258Smlaier	} while (0)
2095126258Smlaier
2096126258Smlaier/*
2097126258Smlaier * hash function based on bridge_hash in if_bridge.c
2098126258Smlaier */
2099126258Smlaiervoid
2100126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
2101126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
2102126258Smlaier{
2103126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
2104126258Smlaier
2105126258Smlaier	switch (af) {
2106126258Smlaier#ifdef INET
2107126258Smlaier	case AF_INET:
2108126258Smlaier		a += inaddr->addr32[0];
2109126258Smlaier		b += key->key32[1];
2110126258Smlaier		mix(a, b, c);
2111126258Smlaier		hash->addr32[0] = c + key->key32[2];
2112126258Smlaier		break;
2113126258Smlaier#endif /* INET */
2114126258Smlaier#ifdef INET6
2115126258Smlaier	case AF_INET6:
2116126258Smlaier		a += inaddr->addr32[0];
2117126258Smlaier		b += inaddr->addr32[2];
2118126258Smlaier		mix(a, b, c);
2119126258Smlaier		hash->addr32[0] = c;
2120126258Smlaier		a += inaddr->addr32[1];
2121126258Smlaier		b += inaddr->addr32[3];
2122126258Smlaier		c += key->key32[1];
2123126258Smlaier		mix(a, b, c);
2124126258Smlaier		hash->addr32[1] = c;
2125126258Smlaier		a += inaddr->addr32[2];
2126126258Smlaier		b += inaddr->addr32[1];
2127126258Smlaier		c += key->key32[2];
2128126258Smlaier		mix(a, b, c);
2129126258Smlaier		hash->addr32[2] = c;
2130126258Smlaier		a += inaddr->addr32[3];
2131126258Smlaier		b += inaddr->addr32[0];
2132126258Smlaier		c += key->key32[3];
2133126258Smlaier		mix(a, b, c);
2134126258Smlaier		hash->addr32[3] = c;
2135126258Smlaier		break;
2136126258Smlaier#endif /* INET6 */
2137126258Smlaier	}
2138126258Smlaier}
2139126258Smlaier
2140126258Smlaierint
2141130613Smlaierpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
2142130613Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
2143126258Smlaier{
2144126258Smlaier	unsigned char		 hash[16];
2145130613Smlaier	struct pf_pool		*rpool = &r->rpool;
2146130613Smlaier	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
2147130613Smlaier	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
2148126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
2149130613Smlaier	struct pf_src_node	 k;
2150126258Smlaier
2151130613Smlaier	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
2152130613Smlaier	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2153130613Smlaier		k.af = af;
2154130613Smlaier		PF_ACPY(&k.addr, saddr, af);
2155130613Smlaier		if (r->rule_flag & PFRULE_RULESRCTRACK ||
2156130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR)
2157130613Smlaier			k.rule.ptr = r;
2158130613Smlaier		else
2159130613Smlaier			k.rule.ptr = NULL;
2160130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
2161130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
2162130613Smlaier		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
2163130613Smlaier			PF_ACPY(naddr, &(*sn)->raddr, af);
2164130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
2165130613Smlaier				printf("pf_map_addr: src tracking maps ");
2166130613Smlaier				pf_print_host(&k.addr, 0, af);
2167130613Smlaier				printf(" to ");
2168130613Smlaier				pf_print_host(naddr, 0, af);
2169130613Smlaier				printf("\n");
2170130613Smlaier			}
2171130613Smlaier			return (0);
2172130613Smlaier		}
2173130613Smlaier	}
2174130613Smlaier
2175126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
2176126258Smlaier		return (1);
2177130613Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2178145836Smlaier		switch (af) {
2179145836Smlaier#ifdef INET
2180145836Smlaier		case AF_INET:
2181130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
2182130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2183130613Smlaier			    PF_POOL_ROUNDROBIN)
2184130613Smlaier				return (1);
2185130613Smlaier			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
2186130613Smlaier			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
2187145836Smlaier			break;
2188145836Smlaier#endif /* INET */
2189145836Smlaier#ifdef INET6
2190145836Smlaier		case AF_INET6:
2191130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
2192130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2193130613Smlaier			    PF_POOL_ROUNDROBIN)
2194130613Smlaier				return (1);
2195130613Smlaier			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
2196130613Smlaier			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
2197145836Smlaier			break;
2198145836Smlaier#endif /* INET6 */
2199130613Smlaier		}
2200130613Smlaier	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2201126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
2202126258Smlaier			return (1); /* unsupported */
2203126258Smlaier	} else {
2204126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
2205126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
2206126258Smlaier	}
2207126258Smlaier
2208126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
2209126258Smlaier	case PF_POOL_NONE:
2210126258Smlaier		PF_ACPY(naddr, raddr, af);
2211126258Smlaier		break;
2212126258Smlaier	case PF_POOL_BITMASK:
2213126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
2214126258Smlaier		break;
2215126258Smlaier	case PF_POOL_RANDOM:
2216126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
2217126258Smlaier			switch (af) {
2218126258Smlaier#ifdef INET
2219126258Smlaier			case AF_INET:
2220145836Smlaier				rpool->counter.addr32[0] = htonl(arc4random());
2221126258Smlaier				break;
2222126258Smlaier#endif /* INET */
2223126258Smlaier#ifdef INET6
2224126258Smlaier			case AF_INET6:
2225126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
2226145836Smlaier					rpool->counter.addr32[3] =
2227145836Smlaier					    htonl(arc4random());
2228126258Smlaier				else
2229126258Smlaier					break;
2230126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
2231145836Smlaier					rpool->counter.addr32[2] =
2232145836Smlaier					    htonl(arc4random());
2233126258Smlaier				else
2234126258Smlaier					break;
2235126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
2236145836Smlaier					rpool->counter.addr32[1] =
2237145836Smlaier					    htonl(arc4random());
2238126258Smlaier				else
2239126258Smlaier					break;
2240126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
2241145836Smlaier					rpool->counter.addr32[0] =
2242145836Smlaier					    htonl(arc4random());
2243126258Smlaier				break;
2244126258Smlaier#endif /* INET6 */
2245126258Smlaier			}
2246126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2247126258Smlaier			PF_ACPY(init_addr, naddr, af);
2248126258Smlaier
2249126258Smlaier		} else {
2250126258Smlaier			PF_AINC(&rpool->counter, af);
2251126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2252126258Smlaier		}
2253126258Smlaier		break;
2254126258Smlaier	case PF_POOL_SRCHASH:
2255126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
2256126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
2257126258Smlaier		break;
2258126258Smlaier	case PF_POOL_ROUNDROBIN:
2259126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2260126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
2261126258Smlaier			    &rpool->tblidx, &rpool->counter,
2262126258Smlaier			    &raddr, &rmask, af))
2263126258Smlaier				goto get_addr;
2264130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2265130613Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2266130613Smlaier			    &rpool->tblidx, &rpool->counter,
2267130613Smlaier			    &raddr, &rmask, af))
2268130613Smlaier				goto get_addr;
2269126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
2270126258Smlaier			goto get_addr;
2271126258Smlaier
2272126258Smlaier	try_next:
2273126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
2274126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
2275126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2276126258Smlaier			rpool->tblidx = -1;
2277126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
2278126258Smlaier			    &rpool->tblidx, &rpool->counter,
2279126258Smlaier			    &raddr, &rmask, af)) {
2280130613Smlaier				/* table contains no address of type 'af' */
2281126258Smlaier				if (rpool->cur != acur)
2282126258Smlaier					goto try_next;
2283126258Smlaier				return (1);
2284126258Smlaier			}
2285130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2286130613Smlaier			rpool->tblidx = -1;
2287130613Smlaier			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2288130613Smlaier			    &rpool->tblidx, &rpool->counter,
2289130613Smlaier			    &raddr, &rmask, af)) {
2290130613Smlaier				/* table contains no address of type 'af' */
2291130613Smlaier				if (rpool->cur != acur)
2292130613Smlaier					goto try_next;
2293130613Smlaier				return (1);
2294130613Smlaier			}
2295126258Smlaier		} else {
2296126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
2297126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
2298126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
2299126258Smlaier		}
2300126258Smlaier
2301126258Smlaier	get_addr:
2302126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
2303139045Sdhartmei		if (init_addr != NULL && PF_AZERO(init_addr, af))
2304139045Sdhartmei			PF_ACPY(init_addr, naddr, af);
2305126258Smlaier		PF_AINC(&rpool->counter, af);
2306126258Smlaier		break;
2307126258Smlaier	}
2308130613Smlaier	if (*sn != NULL)
2309130613Smlaier		PF_ACPY(&(*sn)->raddr, naddr, af);
2310126258Smlaier
2311126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
2312126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2313130613Smlaier		printf("pf_map_addr: selected address ");
2314126258Smlaier		pf_print_host(naddr, 0, af);
2315126258Smlaier		printf("\n");
2316126258Smlaier	}
2317126258Smlaier
2318126258Smlaier	return (0);
2319126258Smlaier}
2320126258Smlaier
2321126258Smlaierint
2322130613Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
2323126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
2324130613Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
2325130613Smlaier    struct pf_src_node **sn)
2326126258Smlaier{
2327130613Smlaier	struct pf_state		key;
2328126258Smlaier	struct pf_addr		init_addr;
2329126258Smlaier	u_int16_t		cut;
2330126258Smlaier
2331126258Smlaier	bzero(&init_addr, sizeof(init_addr));
2332130613Smlaier	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2333126258Smlaier		return (1);
2334126258Smlaier
2335126258Smlaier	do {
2336126258Smlaier		key.af = af;
2337126258Smlaier		key.proto = proto;
2338130613Smlaier		PF_ACPY(&key.ext.addr, daddr, key.af);
2339130613Smlaier		PF_ACPY(&key.gwy.addr, naddr, key.af);
2340130613Smlaier		key.ext.port = dport;
2341126258Smlaier
2342126258Smlaier		/*
2343126258Smlaier		 * port search; start random, step;
2344126258Smlaier		 * similar 2 portloop in in_pcbbind
2345126258Smlaier		 */
2346126258Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP)) {
2347139045Sdhartmei			key.gwy.port = dport;
2348130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2349126258Smlaier				return (0);
2350126258Smlaier		} else if (low == 0 && high == 0) {
2351130613Smlaier			key.gwy.port = *nport;
2352130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2353126258Smlaier				return (0);
2354126258Smlaier		} else if (low == high) {
2355130613Smlaier			key.gwy.port = htons(low);
2356130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
2357126258Smlaier				*nport = htons(low);
2358126258Smlaier				return (0);
2359126258Smlaier			}
2360126258Smlaier		} else {
2361126258Smlaier			u_int16_t tmp;
2362126258Smlaier
2363126258Smlaier			if (low > high) {
2364126258Smlaier				tmp = low;
2365126258Smlaier				low = high;
2366126258Smlaier				high = tmp;
2367126258Smlaier			}
2368126258Smlaier			/* low < high */
2369145836Smlaier			cut = htonl(arc4random()) % (1 + high - low) + low;
2370126258Smlaier			/* low <= cut <= high */
2371126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
2372130613Smlaier				key.gwy.port = htons(tmp);
2373130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2374126258Smlaier				    NULL) {
2375126258Smlaier					*nport = htons(tmp);
2376126258Smlaier					return (0);
2377126258Smlaier				}
2378126258Smlaier			}
2379126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
2380130613Smlaier				key.gwy.port = htons(tmp);
2381130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2382126258Smlaier				    NULL) {
2383126258Smlaier					*nport = htons(tmp);
2384126258Smlaier					return (0);
2385126258Smlaier				}
2386126258Smlaier			}
2387126258Smlaier		}
2388126258Smlaier
2389130613Smlaier		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
2390126258Smlaier		case PF_POOL_RANDOM:
2391126258Smlaier		case PF_POOL_ROUNDROBIN:
2392130613Smlaier			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2393126258Smlaier				return (1);
2394126258Smlaier			break;
2395126258Smlaier		case PF_POOL_NONE:
2396126258Smlaier		case PF_POOL_SRCHASH:
2397126258Smlaier		case PF_POOL_BITMASK:
2398126258Smlaier		default:
2399126258Smlaier			return (1);
2400126258Smlaier		}
2401126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
2402126258Smlaier
2403126258Smlaier	return (1);					/* none available */
2404126258Smlaier}
2405126258Smlaier
2406126258Smlaierstruct pf_rule *
2407126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
2408130613Smlaier    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
2409126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
2410126258Smlaier{
2411145836Smlaier	struct pf_rule		*r, *rm = NULL;
2412126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2413145836Smlaier	struct pf_tag		*pftag = NULL;
2414145836Smlaier	int			 tag = -1;
2415145836Smlaier	int			 asd = 0;
2416126258Smlaier
2417126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
2418126258Smlaier	while (r && rm == NULL) {
2419126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
2420126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
2421126258Smlaier
2422126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
2423126258Smlaier			src = &r->dst;
2424126258Smlaier			if (r->rpool.cur != NULL)
2425126258Smlaier				xdst = &r->rpool.cur->addr;
2426126258Smlaier		} else {
2427126258Smlaier			src = &r->src;
2428126258Smlaier			dst = &r->dst;
2429126258Smlaier		}
2430126258Smlaier
2431126258Smlaier		r->evaluations++;
2432130613Smlaier		if (r->kif != NULL &&
2433130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
2434126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2435126258Smlaier		else if (r->direction && r->direction != direction)
2436126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2437126258Smlaier		else if (r->af && r->af != pd->af)
2438126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2439126258Smlaier		else if (r->proto && r->proto != pd->proto)
2440126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2441145836Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg))
2442126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
2443126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
2444126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
2445126258Smlaier		    src->port[0], src->port[1], sport))
2446126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
2447126258Smlaier			    PF_SKIP_DST_PORT].ptr;
2448126258Smlaier		else if (dst != NULL &&
2449145836Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg))
2450126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2451126258Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
2452126258Smlaier			r = TAILQ_NEXT(r, entries);
2453126258Smlaier		else if (dst != NULL && dst->port_op &&
2454126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
2455126258Smlaier		    dst->port[1], dport))
2456126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2457145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
2458145836Smlaier			r = TAILQ_NEXT(r, entries);
2459126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
2460126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
2461126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
2462126258Smlaier			r = TAILQ_NEXT(r, entries);
2463145836Smlaier		else {
2464145836Smlaier			if (r->tag)
2465145836Smlaier				tag = r->tag;
2466145836Smlaier			if (r->anchor == NULL) {
2467126258Smlaier				rm = r;
2468145836Smlaier			} else
2469145836Smlaier				pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL);
2470145836Smlaier		}
2471145836Smlaier		if (r == NULL)
2472145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL);
2473126258Smlaier	}
2474145836Smlaier	if (pf_tag_packet(m, pftag, tag))
2475145836Smlaier		return (NULL);
2476126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
2477126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
2478126258Smlaier		return (NULL);
2479126258Smlaier	return (rm);
2480126258Smlaier}
2481126258Smlaier
2482126258Smlaierstruct pf_rule *
2483126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
2484130613Smlaier    struct pfi_kif *kif, struct pf_src_node **sn,
2485126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
2486126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
2487126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
2488126258Smlaier{
2489126258Smlaier	struct pf_rule	*r = NULL;
2490126258Smlaier
2491126258Smlaier	if (direction == PF_OUT) {
2492130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2493126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
2494126258Smlaier		if (r == NULL)
2495130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2496126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
2497126258Smlaier	} else {
2498130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2499126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
2500126258Smlaier		if (r == NULL)
2501130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2502126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
2503126258Smlaier	}
2504126258Smlaier
2505126258Smlaier	if (r != NULL) {
2506126258Smlaier		switch (r->action) {
2507126258Smlaier		case PF_NONAT:
2508126258Smlaier		case PF_NOBINAT:
2509126258Smlaier		case PF_NORDR:
2510126258Smlaier			return (NULL);
2511126258Smlaier		case PF_NAT:
2512130613Smlaier			if (pf_get_sport(pd->af, pd->proto, r, saddr,
2513126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
2514130613Smlaier			    r->rpool.proxy_port[1], sn)) {
2515126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2516126258Smlaier				    ("pf: NAT proxy port allocation "
2517126258Smlaier				    "(%u-%u) failed\n",
2518126258Smlaier				    r->rpool.proxy_port[0],
2519126258Smlaier				    r->rpool.proxy_port[1]));
2520126258Smlaier				return (NULL);
2521126258Smlaier			}
2522126258Smlaier			break;
2523126258Smlaier		case PF_BINAT:
2524126258Smlaier			switch (direction) {
2525126258Smlaier			case PF_OUT:
2526130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2527145836Smlaier					switch (pd->af) {
2528145836Smlaier#ifdef INET
2529145836Smlaier					case AF_INET:
2530130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2531130613Smlaier						    pfid_acnt4 < 1)
2532130613Smlaier							return (NULL);
2533130613Smlaier						PF_POOLMASK(naddr,
2534130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2535130613Smlaier						    pfid_addr4,
2536130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2537130613Smlaier						    pfid_mask4,
2538130613Smlaier						    saddr, AF_INET);
2539145836Smlaier						break;
2540145836Smlaier#endif /* INET */
2541145836Smlaier#ifdef INET6
2542145836Smlaier					case AF_INET6:
2543130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2544130613Smlaier						    pfid_acnt6 < 1)
2545130613Smlaier							return (NULL);
2546130613Smlaier						PF_POOLMASK(naddr,
2547130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2548130613Smlaier						    pfid_addr6,
2549130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2550130613Smlaier						    pfid_mask6,
2551130613Smlaier						    saddr, AF_INET6);
2552145836Smlaier						break;
2553145836Smlaier#endif /* INET6 */
2554130613Smlaier					}
2555130613Smlaier				} else
2556126258Smlaier					PF_POOLMASK(naddr,
2557126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
2558126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
2559126258Smlaier					    saddr, pd->af);
2560126258Smlaier				break;
2561126258Smlaier			case PF_IN:
2562138041Sdhartmei				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
2563145836Smlaier					switch (pd->af) {
2564145836Smlaier#ifdef INET
2565145836Smlaier					case AF_INET:
2566130613Smlaier						if (r->src.addr.p.dyn->
2567130613Smlaier						    pfid_acnt4 < 1)
2568130613Smlaier							return (NULL);
2569130613Smlaier						PF_POOLMASK(naddr,
2570130613Smlaier						    &r->src.addr.p.dyn->
2571130613Smlaier						    pfid_addr4,
2572130613Smlaier						    &r->src.addr.p.dyn->
2573130613Smlaier						    pfid_mask4,
2574130613Smlaier						    daddr, AF_INET);
2575145836Smlaier						break;
2576145836Smlaier#endif /* INET */
2577145836Smlaier#ifdef INET6
2578145836Smlaier					case AF_INET6:
2579130613Smlaier						if (r->src.addr.p.dyn->
2580130613Smlaier						    pfid_acnt6 < 1)
2581130613Smlaier							return (NULL);
2582130613Smlaier						PF_POOLMASK(naddr,
2583130613Smlaier						    &r->src.addr.p.dyn->
2584130613Smlaier						    pfid_addr6,
2585130613Smlaier						    &r->src.addr.p.dyn->
2586130613Smlaier						    pfid_mask6,
2587130613Smlaier						    daddr, AF_INET6);
2588145836Smlaier						break;
2589145836Smlaier#endif /* INET6 */
2590130613Smlaier					}
2591130613Smlaier				} else
2592126258Smlaier					PF_POOLMASK(naddr,
2593126258Smlaier					    &r->src.addr.v.a.addr,
2594126261Smlaier					    &r->src.addr.v.a.mask, daddr,
2595126258Smlaier					    pd->af);
2596126258Smlaier				break;
2597126258Smlaier			}
2598126258Smlaier			break;
2599126258Smlaier		case PF_RDR: {
2600140518Sdhartmei			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
2601126258Smlaier				return (NULL);
2602126258Smlaier
2603126258Smlaier			if (r->rpool.proxy_port[1]) {
2604126258Smlaier				u_int32_t	tmp_nport;
2605126258Smlaier
2606126258Smlaier				tmp_nport = ((ntohs(dport) -
2607126258Smlaier				    ntohs(r->dst.port[0])) %
2608126258Smlaier				    (r->rpool.proxy_port[1] -
2609126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
2610126258Smlaier				    r->rpool.proxy_port[0];
2611126258Smlaier
2612126258Smlaier				/* wrap around if necessary */
2613126258Smlaier				if (tmp_nport > 65535)
2614126258Smlaier					tmp_nport -= 65535;
2615126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
2616126258Smlaier			} else if (r->rpool.proxy_port[0])
2617126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
2618126258Smlaier			break;
2619126258Smlaier		}
2620126258Smlaier		default:
2621126258Smlaier			return (NULL);
2622126258Smlaier		}
2623126258Smlaier	}
2624126258Smlaier
2625126258Smlaier	return (r);
2626126258Smlaier}
2627126258Smlaier
2628126258Smlaierint
2629135920Smlaier#ifdef __FreeBSD__
2630135920Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd,
2631135920Smlaier    struct inpcb *inp_arg)
2632135920Smlaier#else
2633130613Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
2634135920Smlaier#endif
2635126258Smlaier{
2636126258Smlaier	struct pf_addr		*saddr, *daddr;
2637126258Smlaier	u_int16_t		 sport, dport;
2638127145Smlaier#ifdef __FreeBSD__
2639126261Smlaier	struct inpcbinfo	*pi;
2640126261Smlaier#else
2641126258Smlaier	struct inpcbtable	*tb;
2642126261Smlaier#endif
2643126258Smlaier	struct inpcb		*inp;
2644126258Smlaier
2645126258Smlaier	*uid = UID_MAX;
2646126258Smlaier	*gid = GID_MAX;
2647135920Smlaier#ifdef __FreeBSD__
2648135920Smlaier	if (inp_arg != NULL) {
2649135920Smlaier		INP_LOCK_ASSERT(inp_arg);
2650135920Smlaier		if (inp_arg->inp_socket) {
2651135920Smlaier			*uid = inp_arg->inp_socket->so_cred->cr_uid;
2652135920Smlaier			*gid = inp_arg->inp_socket->so_cred->cr_groups[0];
2653135920Smlaier			return (1);
2654135920Smlaier		} else
2655135920Smlaier			return (0);
2656135920Smlaier	}
2657135920Smlaier#endif
2658130613Smlaier	switch (pd->proto) {
2659126258Smlaier	case IPPROTO_TCP:
2660126258Smlaier		sport = pd->hdr.tcp->th_sport;
2661126258Smlaier		dport = pd->hdr.tcp->th_dport;
2662127145Smlaier#ifdef __FreeBSD__
2663126261Smlaier		pi = &tcbinfo;
2664126261Smlaier#else
2665126258Smlaier		tb = &tcbtable;
2666126261Smlaier#endif
2667126258Smlaier		break;
2668126258Smlaier	case IPPROTO_UDP:
2669126258Smlaier		sport = pd->hdr.udp->uh_sport;
2670126258Smlaier		dport = pd->hdr.udp->uh_dport;
2671127145Smlaier#ifdef __FreeBSD__
2672126261Smlaier		pi = &udbinfo;
2673126261Smlaier#else
2674126258Smlaier		tb = &udbtable;
2675126261Smlaier#endif
2676126258Smlaier		break;
2677126258Smlaier	default:
2678126258Smlaier		return (0);
2679126258Smlaier	}
2680126258Smlaier	if (direction == PF_IN) {
2681126258Smlaier		saddr = pd->src;
2682126258Smlaier		daddr = pd->dst;
2683126258Smlaier	} else {
2684126258Smlaier		u_int16_t	p;
2685126258Smlaier
2686126258Smlaier		p = sport;
2687126258Smlaier		sport = dport;
2688126258Smlaier		dport = p;
2689126258Smlaier		saddr = pd->dst;
2690126258Smlaier		daddr = pd->src;
2691126258Smlaier	}
2692130613Smlaier	switch (pd->af) {
2693145836Smlaier#ifdef INET
2694126258Smlaier	case AF_INET:
2695127145Smlaier#ifdef __FreeBSD__
2696126261Smlaier		INP_INFO_RLOCK(pi);	/* XXX LOR */
2697126261Smlaier		inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
2698126261Smlaier			dport, 0, NULL);
2699126261Smlaier		if (inp == NULL) {
2700126261Smlaier			inp = in_pcblookup_hash(pi, saddr->v4, sport,
2701126261Smlaier			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
2702126261Smlaier			if(inp == NULL) {
2703126261Smlaier				INP_INFO_RUNLOCK(pi);
2704126261Smlaier				return (0);
2705126261Smlaier			}
2706126261Smlaier		}
2707126261Smlaier#else
2708126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
2709126258Smlaier		if (inp == NULL) {
2710130613Smlaier			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
2711126258Smlaier			if (inp == NULL)
2712126258Smlaier				return (0);
2713126258Smlaier		}
2714126261Smlaier#endif
2715126258Smlaier		break;
2716145836Smlaier#endif /* INET */
2717126258Smlaier#ifdef INET6
2718126258Smlaier	case AF_INET6:
2719127145Smlaier#ifdef __FreeBSD__
2720126261Smlaier		INP_INFO_RLOCK(pi);
2721126261Smlaier		inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2722126261Smlaier			&daddr->v6, dport, 0, NULL);
2723126261Smlaier		if (inp == NULL) {
2724126261Smlaier			inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2725126261Smlaier			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
2726126261Smlaier			if (inp == NULL) {
2727126261Smlaier				INP_INFO_RUNLOCK(pi);
2728126261Smlaier				return (0);
2729126261Smlaier			}
2730126261Smlaier		}
2731126261Smlaier#else
2732126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
2733126258Smlaier		    dport);
2734126258Smlaier		if (inp == NULL) {
2735130613Smlaier			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
2736126258Smlaier			if (inp == NULL)
2737126258Smlaier				return (0);
2738126258Smlaier		}
2739126261Smlaier#endif
2740126258Smlaier		break;
2741126258Smlaier#endif /* INET6 */
2742126258Smlaier
2743126258Smlaier	default:
2744126258Smlaier		return (0);
2745126258Smlaier	}
2746127145Smlaier#ifdef __FreeBSD__
2747126261Smlaier	INP_LOCK(inp);
2748136925Smlaier	if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) {
2749136925Smlaier		INP_UNLOCK(inp);
2750136925Smlaier		INP_INFO_RUNLOCK(pi);
2751136925Smlaier		return (0);
2752136925Smlaier	}
2753126261Smlaier	*uid = inp->inp_socket->so_cred->cr_uid;
2754126261Smlaier	*gid = inp->inp_socket->so_cred->cr_groups[0];
2755126261Smlaier	INP_UNLOCK(inp);
2756126261Smlaier	INP_INFO_RUNLOCK(pi);
2757126261Smlaier#else
2758126258Smlaier	*uid = inp->inp_socket->so_euid;
2759126258Smlaier	*gid = inp->inp_socket->so_egid;
2760126261Smlaier#endif
2761126258Smlaier	return (1);
2762126258Smlaier}
2763126258Smlaier
2764126258Smlaieru_int8_t
2765126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2766126258Smlaier{
2767126258Smlaier	int		 hlen;
2768126258Smlaier	u_int8_t	 hdr[60];
2769126258Smlaier	u_int8_t	*opt, optlen;
2770126258Smlaier	u_int8_t	 wscale = 0;
2771126258Smlaier
2772126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
2773126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2774126258Smlaier		return (0);
2775126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2776126258Smlaier		return (0);
2777126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2778126258Smlaier	hlen -= sizeof(struct tcphdr);
2779126258Smlaier	while (hlen >= 3) {
2780126258Smlaier		switch (*opt) {
2781126258Smlaier		case TCPOPT_EOL:
2782126258Smlaier		case TCPOPT_NOP:
2783126258Smlaier			++opt;
2784126258Smlaier			--hlen;
2785126258Smlaier			break;
2786126258Smlaier		case TCPOPT_WINDOW:
2787126258Smlaier			wscale = opt[2];
2788126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
2789126258Smlaier				wscale = TCP_MAX_WINSHIFT;
2790126258Smlaier			wscale |= PF_WSCALE_FLAG;
2791130613Smlaier			/* FALLTHROUGH */
2792126258Smlaier		default:
2793126258Smlaier			optlen = opt[1];
2794126258Smlaier			if (optlen < 2)
2795126258Smlaier				optlen = 2;
2796126258Smlaier			hlen -= optlen;
2797126258Smlaier			opt += optlen;
2798130613Smlaier			break;
2799126258Smlaier		}
2800126258Smlaier	}
2801126258Smlaier	return (wscale);
2802126258Smlaier}
2803126258Smlaier
2804126258Smlaieru_int16_t
2805126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2806126258Smlaier{
2807126258Smlaier	int		 hlen;
2808126258Smlaier	u_int8_t	 hdr[60];
2809126258Smlaier	u_int8_t	*opt, optlen;
2810126258Smlaier	u_int16_t	 mss = tcp_mssdflt;
2811126258Smlaier
2812126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
2813126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2814126258Smlaier		return (0);
2815126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2816126258Smlaier		return (0);
2817126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2818126258Smlaier	hlen -= sizeof(struct tcphdr);
2819126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
2820126258Smlaier		switch (*opt) {
2821126258Smlaier		case TCPOPT_EOL:
2822126258Smlaier		case TCPOPT_NOP:
2823126258Smlaier			++opt;
2824126258Smlaier			--hlen;
2825126258Smlaier			break;
2826126258Smlaier		case TCPOPT_MAXSEG:
2827126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
2828145030Sglebius			NTOHS(mss);
2829130613Smlaier			/* FALLTHROUGH */
2830126258Smlaier		default:
2831126258Smlaier			optlen = opt[1];
2832126258Smlaier			if (optlen < 2)
2833126258Smlaier				optlen = 2;
2834126258Smlaier			hlen -= optlen;
2835126258Smlaier			opt += optlen;
2836130613Smlaier			break;
2837126258Smlaier		}
2838126258Smlaier	}
2839126258Smlaier	return (mss);
2840126258Smlaier}
2841126258Smlaier
2842126258Smlaieru_int16_t
2843126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
2844126258Smlaier{
2845126258Smlaier#ifdef INET
2846126258Smlaier	struct sockaddr_in	*dst;
2847126258Smlaier	struct route		 ro;
2848126258Smlaier#endif /* INET */
2849126258Smlaier#ifdef INET6
2850126258Smlaier	struct sockaddr_in6	*dst6;
2851126258Smlaier	struct route_in6	 ro6;
2852126258Smlaier#endif /* INET6 */
2853126258Smlaier	struct rtentry		*rt = NULL;
2854127629Smlaier	int			 hlen = 0;	/* make the compiler happy */
2855126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2856126258Smlaier
2857126258Smlaier	switch (af) {
2858126258Smlaier#ifdef INET
2859126258Smlaier	case AF_INET:
2860126258Smlaier		hlen = sizeof(struct ip);
2861126258Smlaier		bzero(&ro, sizeof(ro));
2862126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
2863126258Smlaier		dst->sin_family = AF_INET;
2864126258Smlaier		dst->sin_len = sizeof(*dst);
2865126258Smlaier		dst->sin_addr = addr->v4;
2866127145Smlaier#ifdef __FreeBSD__
2867126261Smlaier#ifdef RTF_PRCLONING
2868126261Smlaier		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
2869126261Smlaier#else /* !RTF_PRCLONING */
2870126261Smlaier		rtalloc_ign(&ro, RTF_CLONING);
2871126261Smlaier#endif
2872126261Smlaier#else /* ! __FreeBSD__ */
2873126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
2874126261Smlaier#endif
2875126258Smlaier		rt = ro.ro_rt;
2876126258Smlaier		break;
2877126258Smlaier#endif /* INET */
2878126258Smlaier#ifdef INET6
2879126258Smlaier	case AF_INET6:
2880126258Smlaier		hlen = sizeof(struct ip6_hdr);
2881126258Smlaier		bzero(&ro6, sizeof(ro6));
2882126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
2883126258Smlaier		dst6->sin6_family = AF_INET6;
2884126258Smlaier		dst6->sin6_len = sizeof(*dst6);
2885126258Smlaier		dst6->sin6_addr = addr->v6;
2886127145Smlaier#ifdef __FreeBSD__
2887126261Smlaier#ifdef RTF_PRCLONING
2888126261Smlaier		rtalloc_ign((struct route *)&ro6,
2889126261Smlaier		    (RTF_CLONING | RTF_PRCLONING));
2890126261Smlaier#else /* !RTF_PRCLONING */
2891126261Smlaier		rtalloc_ign((struct route *)&ro6, RTF_CLONING);
2892126261Smlaier#endif
2893126261Smlaier#else /* ! __FreeBSD__ */
2894126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
2895126261Smlaier#endif
2896126258Smlaier		rt = ro6.ro_rt;
2897126258Smlaier		break;
2898126258Smlaier#endif /* INET6 */
2899126258Smlaier	}
2900126258Smlaier
2901126258Smlaier	if (rt && rt->rt_ifp) {
2902126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
2903126258Smlaier		mss = max(tcp_mssdflt, mss);
2904126258Smlaier		RTFREE(rt);
2905126258Smlaier	}
2906126258Smlaier	mss = min(mss, offer);
2907126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
2908126258Smlaier	return (mss);
2909126258Smlaier}
2910126258Smlaier
2911126258Smlaiervoid
2912126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
2913126258Smlaier{
2914126258Smlaier	struct pf_rule *r = s->rule.ptr;
2915126258Smlaier
2916130613Smlaier	s->rt_kif = NULL;
2917126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
2918126258Smlaier		return;
2919126258Smlaier	switch (s->af) {
2920126258Smlaier#ifdef INET
2921126258Smlaier	case AF_INET:
2922130613Smlaier		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
2923130613Smlaier		    &s->nat_src_node);
2924130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2925126258Smlaier		break;
2926126258Smlaier#endif /* INET */
2927126258Smlaier#ifdef INET6
2928126258Smlaier	case AF_INET6:
2929130613Smlaier		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
2930130613Smlaier		    &s->nat_src_node);
2931130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2932126258Smlaier		break;
2933126258Smlaier#endif /* INET6 */
2934126258Smlaier	}
2935126258Smlaier}
2936126258Smlaier
2937126258Smlaierint
2938126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
2939130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
2940135920Smlaier#ifdef __FreeBSD__
2941135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
2942145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
2943135920Smlaier#else
2944145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
2945145836Smlaier    struct ifqueue *ifq)
2946135920Smlaier#endif
2947126258Smlaier{
2948130613Smlaier	struct pf_rule		*nr = NULL;
2949126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
2950126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
2951126258Smlaier	u_int16_t		 bport, nport = 0;
2952126258Smlaier	sa_family_t		 af = pd->af;
2953126258Smlaier	int			 lookup = -1;
2954126258Smlaier	uid_t			 uid;
2955126258Smlaier	gid_t			 gid;
2956126258Smlaier	struct pf_rule		*r, *a = NULL;
2957126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2958130613Smlaier	struct pf_src_node	*nsn = NULL;
2959126258Smlaier	u_short			 reason;
2960126258Smlaier	int			 rewrite = 0;
2961126258Smlaier	struct pf_tag		*pftag = NULL;
2962126258Smlaier	int			 tag = -1;
2963126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2964145836Smlaier	int			 asd = 0;
2965126258Smlaier
2966145836Smlaier	if (pf_check_congestion(ifq)) {
2967145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
2968145836Smlaier		return (PF_DROP);
2969145836Smlaier	}
2970145836Smlaier
2971126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
2972126258Smlaier
2973126258Smlaier	if (direction == PF_OUT) {
2974126258Smlaier		bport = nport = th->th_sport;
2975126258Smlaier		/* check outgoing packet for BINAT/NAT */
2976130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
2977126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
2978130613Smlaier		    &pd->naddr, &nport)) != NULL) {
2979130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
2980126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
2981130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
2982126258Smlaier			rewrite++;
2983130613Smlaier			if (nr->natpass)
2984126258Smlaier				r = NULL;
2985130613Smlaier			pd->nat_rule = nr;
2986126258Smlaier		}
2987126258Smlaier	} else {
2988126258Smlaier		bport = nport = th->th_dport;
2989126258Smlaier		/* check incoming packet for BINAT/RDR */
2990130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
2991130613Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
2992130613Smlaier		    &pd->naddr, &nport)) != NULL) {
2993130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
2994126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
2995130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
2996126258Smlaier			rewrite++;
2997130613Smlaier			if (nr->natpass)
2998126258Smlaier				r = NULL;
2999130613Smlaier			pd->nat_rule = nr;
3000126258Smlaier		}
3001126258Smlaier	}
3002126258Smlaier
3003126258Smlaier	while (r != NULL) {
3004126258Smlaier		r->evaluations++;
3005130613Smlaier		if (r->kif != NULL &&
3006130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3007126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3008126258Smlaier		else if (r->direction && r->direction != direction)
3009126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3010126258Smlaier		else if (r->af && r->af != af)
3011126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3012126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
3013126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3014145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3015126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3016126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3017126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
3018126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3019145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3020126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3021126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3022126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
3023126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3024126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3025126258Smlaier			r = TAILQ_NEXT(r, entries);
3026126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3027126258Smlaier			r = TAILQ_NEXT(r, entries);
3028126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
3029126258Smlaier			r = TAILQ_NEXT(r, entries);
3030126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
3031135920Smlaier#ifdef __FreeBSD__
3032135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3033135920Smlaier#else
3034130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3035135920Smlaier#endif
3036126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3037126258Smlaier		    uid))
3038126258Smlaier			r = TAILQ_NEXT(r, entries);
3039126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
3040135920Smlaier#ifdef __FreeBSD__
3041135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3042135920Smlaier#else
3043130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3044135920Smlaier#endif
3045126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3046126258Smlaier		    gid))
3047126258Smlaier			r = TAILQ_NEXT(r, entries);
3048145836Smlaier		else if (r->prob && r->prob <= arc4random())
3049126258Smlaier			r = TAILQ_NEXT(r, entries);
3050145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3051126258Smlaier			r = TAILQ_NEXT(r, entries);
3052126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
3053126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
3054126258Smlaier			r = TAILQ_NEXT(r, entries);
3055126258Smlaier		else {
3056126258Smlaier			if (r->tag)
3057126258Smlaier				tag = r->tag;
3058126258Smlaier			if (r->anchor == NULL) {
3059126258Smlaier				*rm = r;
3060126258Smlaier				*am = a;
3061126258Smlaier				*rsm = ruleset;
3062126258Smlaier				if ((*rm)->quick)
3063126258Smlaier					break;
3064126258Smlaier				r = TAILQ_NEXT(r, entries);
3065126258Smlaier			} else
3066145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3067145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3068126258Smlaier		}
3069145836Smlaier		if (r == NULL)
3070145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3071145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3072126258Smlaier	}
3073126258Smlaier	r = *rm;
3074126258Smlaier	a = *am;
3075126258Smlaier	ruleset = *rsm;
3076126258Smlaier
3077126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3078126258Smlaier
3079126258Smlaier	if (r->log) {
3080126258Smlaier		if (rewrite)
3081126261Smlaier			m_copyback(m, off, sizeof(*th), (caddr_t)th);
3082130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3083126258Smlaier	}
3084126258Smlaier
3085126258Smlaier	if ((r->action == PF_DROP) &&
3086126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
3087126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
3088126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3089126258Smlaier		/* undo NAT changes, if they have taken place */
3090130613Smlaier		if (nr != NULL) {
3091130613Smlaier			if (direction == PF_OUT) {
3092130613Smlaier				pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3093130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3094130613Smlaier				rewrite++;
3095130613Smlaier			} else {
3096130613Smlaier				pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3097130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3098130613Smlaier				rewrite++;
3099130613Smlaier			}
3100126258Smlaier		}
3101126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
3102126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
3103126258Smlaier		    !(th->th_flags & TH_RST)) {
3104126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
3105126258Smlaier
3106126258Smlaier			if (th->th_flags & TH_SYN)
3107126258Smlaier				ack++;
3108126258Smlaier			if (th->th_flags & TH_FIN)
3109126258Smlaier				ack++;
3110126258Smlaier			pf_send_tcp(r, af, pd->dst,
3111126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3112126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
3113145836Smlaier			    r->return_ttl, 1, pd->eh, kif->pfik_ifp);
3114126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
3115126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3116126258Smlaier			    r->return_icmp & 255, af, r);
3117126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3118126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3119126258Smlaier			    r->return_icmp6 & 255, af, r);
3120126258Smlaier	}
3121126258Smlaier
3122126258Smlaier	if (r->action == PF_DROP)
3123126258Smlaier		return (PF_DROP);
3124126258Smlaier
3125126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3126126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3127126258Smlaier		return (PF_DROP);
3128126258Smlaier	}
3129126258Smlaier
3130130613Smlaier	if (r->keep_state || nr != NULL ||
3131126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
3132126258Smlaier		/* create new state */
3133126258Smlaier		u_int16_t	 len;
3134126258Smlaier		struct pf_state	*s = NULL;
3135130613Smlaier		struct pf_src_node *sn = NULL;
3136126258Smlaier
3137126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
3138130613Smlaier
3139130613Smlaier		/* check maximums */
3140145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3141145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3142145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3143130613Smlaier			goto cleanup;
3144145836Smlaier		}
3145130613Smlaier		/* src node for flter rule */
3146130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3147130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3148145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3149145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3150130613Smlaier			goto cleanup;
3151145836Smlaier		}
3152130613Smlaier		/* src node for translation rule */
3153130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3154130613Smlaier		    ((direction == PF_OUT &&
3155130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3156145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3157145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3158130613Smlaier			goto cleanup;
3159145836Smlaier		}
3160130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3161126258Smlaier		if (s == NULL) {
3162145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3163130613Smlaiercleanup:
3164130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3165130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3166130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3167130613Smlaier				pf_status.src_nodes--;
3168130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3169130613Smlaier			}
3170130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3171130613Smlaier			    nsn->expire == 0) {
3172130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3173130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3174130613Smlaier				pf_status.src_nodes--;
3175130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3176130613Smlaier			}
3177126258Smlaier			return (PF_DROP);
3178126258Smlaier		}
3179126258Smlaier		bzero(s, sizeof(*s));
3180126258Smlaier		s->rule.ptr = r;
3181130613Smlaier		s->nat_rule.ptr = nr;
3182126258Smlaier		s->anchor.ptr = a;
3183145836Smlaier		STATE_INC_COUNTERS(s);
3184126258Smlaier		s->allow_opts = r->allow_opts;
3185126258Smlaier		s->log = r->log & 2;
3186126258Smlaier		s->proto = IPPROTO_TCP;
3187126258Smlaier		s->direction = direction;
3188126258Smlaier		s->af = af;
3189126258Smlaier		if (direction == PF_OUT) {
3190126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3191126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
3192126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3193126258Smlaier			s->ext.port = th->th_dport;
3194130613Smlaier			if (nr != NULL) {
3195130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3196126258Smlaier				s->lan.port = bport;
3197126258Smlaier			} else {
3198126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3199126258Smlaier				s->lan.port = s->gwy.port;
3200126258Smlaier			}
3201126258Smlaier		} else {
3202126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3203126258Smlaier			s->lan.port = th->th_dport;
3204126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3205126258Smlaier			s->ext.port = th->th_sport;
3206130613Smlaier			if (nr != NULL) {
3207130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3208126258Smlaier				s->gwy.port = bport;
3209126258Smlaier			} else {
3210126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3211126258Smlaier				s->gwy.port = s->lan.port;
3212126258Smlaier			}
3213126258Smlaier		}
3214126258Smlaier
3215126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
3216126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
3217126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3218126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
3219126258Smlaier			/* Generate sequence number modulator */
3220145836Smlaier			while ((s->src.seqdiff = htonl(arc4random())) == 0)
3221126258Smlaier				;
3222126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
3223126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
3224126258Smlaier			rewrite = 1;
3225126258Smlaier		} else
3226126258Smlaier			s->src.seqdiff = 0;
3227126258Smlaier		if (th->th_flags & TH_SYN) {
3228126258Smlaier			s->src.seqhi++;
3229126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
3230126258Smlaier		}
3231126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
3232126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
3233126258Smlaier			/* Remove scale factor from initial window */
3234126258Smlaier			int win = s->src.max_win;
3235126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
3236126258Smlaier			s->src.max_win = (win - 1) >>
3237126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
3238126258Smlaier		}
3239126258Smlaier		if (th->th_flags & TH_FIN)
3240126258Smlaier			s->src.seqhi++;
3241126258Smlaier		s->dst.seqhi = 1;
3242126258Smlaier		s->dst.max_win = 1;
3243126258Smlaier		s->src.state = TCPS_SYN_SENT;
3244126258Smlaier		s->dst.state = TCPS_CLOSED;
3245126261Smlaier		s->creation = time_second;
3246126261Smlaier		s->expire = time_second;
3247126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
3248126258Smlaier		pf_set_rt_ifp(s, saddr);
3249130613Smlaier		if (sn != NULL) {
3250130613Smlaier			s->src_node = sn;
3251130613Smlaier			s->src_node->states++;
3252130613Smlaier		}
3253130613Smlaier		if (nsn != NULL) {
3254130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3255130613Smlaier			s->nat_src_node = nsn;
3256130613Smlaier			s->nat_src_node->states++;
3257130613Smlaier		}
3258126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3259126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3260126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3261130613Smlaier			pf_src_tree_remove_state(s);
3262145836Smlaier			STATE_DEC_COUNTERS(s);
3263126258Smlaier			pool_put(&pf_state_pl, s);
3264126258Smlaier			return (PF_DROP);
3265126258Smlaier		}
3266126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3267145836Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
3268145836Smlaier		    &s->src, &s->dst, &rewrite)) {
3269145836Smlaier			/* This really shouldn't happen!!! */
3270145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
3271145836Smlaier			    ("pf_normalize_tcp_stateful failed on first pkt"));
3272126258Smlaier			pf_normalize_tcp_cleanup(s);
3273130613Smlaier			pf_src_tree_remove_state(s);
3274145836Smlaier			STATE_DEC_COUNTERS(s);
3275126258Smlaier			pool_put(&pf_state_pl, s);
3276126258Smlaier			return (PF_DROP);
3277126258Smlaier		}
3278130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3279126258Smlaier			pf_normalize_tcp_cleanup(s);
3280145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3281130613Smlaier			pf_src_tree_remove_state(s);
3282145836Smlaier			STATE_DEC_COUNTERS(s);
3283126258Smlaier			pool_put(&pf_state_pl, s);
3284126258Smlaier			return (PF_DROP);
3285126258Smlaier		} else
3286126258Smlaier			*sm = s;
3287145836Smlaier		if (tag > 0) {
3288145836Smlaier			pf_tag_ref(tag);
3289145836Smlaier			s->tag = tag;
3290145836Smlaier		}
3291126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3292126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
3293126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
3294130613Smlaier			if (nr != NULL) {
3295130613Smlaier				if (direction == PF_OUT) {
3296130613Smlaier					pf_change_ap(saddr, &th->th_sport,
3297130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3298130613Smlaier					    bport, 0, af);
3299130613Smlaier				} else {
3300130613Smlaier					pf_change_ap(daddr, &th->th_dport,
3301130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3302130613Smlaier					    bport, 0, af);
3303130613Smlaier				}
3304130613Smlaier			}
3305145836Smlaier			s->src.seqhi = htonl(arc4random());
3306126258Smlaier			/* Find mss option */
3307126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
3308126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
3309126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
3310126258Smlaier			s->src.mss = mss;
3311126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
3312130613Smlaier			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
3313145836Smlaier			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL);
3314145836Smlaier			REASON_SET(&reason, PFRES_SYNPROXY);
3315126258Smlaier			return (PF_SYNPROXY_DROP);
3316126258Smlaier		}
3317126258Smlaier	}
3318126258Smlaier
3319126258Smlaier	/* copy back packet headers if we performed NAT operations */
3320126258Smlaier	if (rewrite)
3321126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
3322126258Smlaier
3323126258Smlaier	return (PF_PASS);
3324126258Smlaier}
3325126258Smlaier
3326126258Smlaierint
3327126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
3328130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3329135920Smlaier#ifdef __FreeBSD__
3330135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3331145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3332135920Smlaier#else
3333145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3334145836Smlaier    struct ifqueue *ifq)
3335135920Smlaier#endif
3336126258Smlaier{
3337130613Smlaier	struct pf_rule		*nr = NULL;
3338126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3339126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3340126258Smlaier	u_int16_t		 bport, nport = 0;
3341126258Smlaier	sa_family_t		 af = pd->af;
3342126258Smlaier	int			 lookup = -1;
3343126258Smlaier	uid_t			 uid;
3344126258Smlaier	gid_t			 gid;
3345126258Smlaier	struct pf_rule		*r, *a = NULL;
3346126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3347130613Smlaier	struct pf_src_node	*nsn = NULL;
3348126258Smlaier	u_short			 reason;
3349126258Smlaier	int			 rewrite = 0;
3350126258Smlaier	struct pf_tag		*pftag = NULL;
3351126258Smlaier	int			 tag = -1;
3352145836Smlaier	int			 asd = 0;
3353126258Smlaier
3354145836Smlaier	if (pf_check_congestion(ifq)) {
3355145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3356145836Smlaier		return (PF_DROP);
3357145836Smlaier	}
3358145836Smlaier
3359126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3360126258Smlaier
3361126258Smlaier	if (direction == PF_OUT) {
3362126258Smlaier		bport = nport = uh->uh_sport;
3363126258Smlaier		/* check outgoing packet for BINAT/NAT */
3364130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3365126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
3366130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3367130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3368126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3369130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3370126258Smlaier			rewrite++;
3371130613Smlaier			if (nr->natpass)
3372126258Smlaier				r = NULL;
3373130613Smlaier			pd->nat_rule = nr;
3374126258Smlaier		}
3375126258Smlaier	} else {
3376126258Smlaier		bport = nport = uh->uh_dport;
3377126258Smlaier		/* check incoming packet for BINAT/RDR */
3378130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3379130613Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
3380130613Smlaier		    &nport)) != NULL) {
3381130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3382126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3383130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3384126258Smlaier			rewrite++;
3385130613Smlaier			if (nr->natpass)
3386126258Smlaier				r = NULL;
3387130613Smlaier			pd->nat_rule = nr;
3388126258Smlaier		}
3389126258Smlaier	}
3390126258Smlaier
3391126258Smlaier	while (r != NULL) {
3392126258Smlaier		r->evaluations++;
3393130613Smlaier		if (r->kif != NULL &&
3394130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3395126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3396126258Smlaier		else if (r->direction && r->direction != direction)
3397126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3398126258Smlaier		else if (r->af && r->af != af)
3399126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3400126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
3401126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3402145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3403126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3404126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3405126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
3406126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3407145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3408126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3409126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3410126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
3411126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3412126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3413126258Smlaier			r = TAILQ_NEXT(r, entries);
3414126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3415126258Smlaier			r = TAILQ_NEXT(r, entries);
3416126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
3417135920Smlaier#ifdef __FreeBSD__
3418135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3419135920Smlaier#else
3420130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3421135920Smlaier#endif
3422126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3423126258Smlaier		    uid))
3424126258Smlaier			r = TAILQ_NEXT(r, entries);
3425126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
3426135920Smlaier#ifdef __FreeBSD__
3427135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3428135920Smlaier#else
3429130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3430135920Smlaier#endif
3431126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3432126258Smlaier		    gid))
3433126258Smlaier			r = TAILQ_NEXT(r, entries);
3434145836Smlaier		else if (r->prob && r->prob <= arc4random())
3435126258Smlaier			r = TAILQ_NEXT(r, entries);
3436145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3437126258Smlaier			r = TAILQ_NEXT(r, entries);
3438126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3439126258Smlaier			r = TAILQ_NEXT(r, entries);
3440126258Smlaier		else {
3441126258Smlaier			if (r->tag)
3442126258Smlaier				tag = r->tag;
3443126258Smlaier			if (r->anchor == NULL) {
3444126258Smlaier				*rm = r;
3445126258Smlaier				*am = a;
3446126258Smlaier				*rsm = ruleset;
3447126258Smlaier				if ((*rm)->quick)
3448126258Smlaier					break;
3449126258Smlaier				r = TAILQ_NEXT(r, entries);
3450126258Smlaier			} else
3451145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3452145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3453126258Smlaier		}
3454145836Smlaier		if (r == NULL)
3455145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3456145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3457126258Smlaier	}
3458126258Smlaier	r = *rm;
3459126258Smlaier	a = *am;
3460126258Smlaier	ruleset = *rsm;
3461126258Smlaier
3462126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3463126258Smlaier
3464126258Smlaier	if (r->log) {
3465126258Smlaier		if (rewrite)
3466126261Smlaier			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3467130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3468126258Smlaier	}
3469126258Smlaier
3470126258Smlaier	if ((r->action == PF_DROP) &&
3471126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3472126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3473126258Smlaier		/* undo NAT changes, if they have taken place */
3474130613Smlaier		if (nr != NULL) {
3475130613Smlaier			if (direction == PF_OUT) {
3476130613Smlaier				pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3477130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3478130613Smlaier				rewrite++;
3479130613Smlaier			} else {
3480130613Smlaier				pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3481130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3482130613Smlaier				rewrite++;
3483130613Smlaier			}
3484126258Smlaier		}
3485126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3486126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3487126258Smlaier			    r->return_icmp & 255, af, r);
3488126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3489126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3490126258Smlaier			    r->return_icmp6 & 255, af, r);
3491126258Smlaier	}
3492126258Smlaier
3493126258Smlaier	if (r->action == PF_DROP)
3494126258Smlaier		return (PF_DROP);
3495126258Smlaier
3496126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3497126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3498126258Smlaier		return (PF_DROP);
3499126258Smlaier	}
3500126258Smlaier
3501130613Smlaier	if (r->keep_state || nr != NULL) {
3502126258Smlaier		/* create new state */
3503126258Smlaier		struct pf_state	*s = NULL;
3504130613Smlaier		struct pf_src_node *sn = NULL;
3505126258Smlaier
3506130613Smlaier		/* check maximums */
3507145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3508145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3509145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3510130613Smlaier			goto cleanup;
3511145836Smlaier		}
3512130613Smlaier		/* src node for flter rule */
3513130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3514130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3515145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3516145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3517130613Smlaier			goto cleanup;
3518145836Smlaier		}
3519130613Smlaier		/* src node for translation rule */
3520130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3521130613Smlaier		    ((direction == PF_OUT &&
3522130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3523145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3524145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3525130613Smlaier			goto cleanup;
3526145836Smlaier		}
3527130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3528126258Smlaier		if (s == NULL) {
3529145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3530130613Smlaiercleanup:
3531130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3532130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3533130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3534130613Smlaier				pf_status.src_nodes--;
3535130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3536130613Smlaier			}
3537130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3538130613Smlaier			    nsn->expire == 0) {
3539130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3540130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3541130613Smlaier				pf_status.src_nodes--;
3542130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3543130613Smlaier			}
3544126258Smlaier			return (PF_DROP);
3545126258Smlaier		}
3546126258Smlaier		bzero(s, sizeof(*s));
3547126258Smlaier		s->rule.ptr = r;
3548130613Smlaier		s->nat_rule.ptr = nr;
3549126258Smlaier		s->anchor.ptr = a;
3550145836Smlaier		STATE_INC_COUNTERS(s);
3551126258Smlaier		s->allow_opts = r->allow_opts;
3552126258Smlaier		s->log = r->log & 2;
3553126258Smlaier		s->proto = IPPROTO_UDP;
3554126258Smlaier		s->direction = direction;
3555126258Smlaier		s->af = af;
3556126258Smlaier		if (direction == PF_OUT) {
3557126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3558126258Smlaier			s->gwy.port = uh->uh_sport;
3559126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3560126258Smlaier			s->ext.port = uh->uh_dport;
3561130613Smlaier			if (nr != NULL) {
3562130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3563126258Smlaier				s->lan.port = bport;
3564126258Smlaier			} else {
3565126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3566126258Smlaier				s->lan.port = s->gwy.port;
3567126258Smlaier			}
3568126258Smlaier		} else {
3569126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3570126258Smlaier			s->lan.port = uh->uh_dport;
3571126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3572126258Smlaier			s->ext.port = uh->uh_sport;
3573130613Smlaier			if (nr != NULL) {
3574130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3575126258Smlaier				s->gwy.port = bport;
3576126258Smlaier			} else {
3577126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3578126258Smlaier				s->gwy.port = s->lan.port;
3579126258Smlaier			}
3580126258Smlaier		}
3581126258Smlaier		s->src.state = PFUDPS_SINGLE;
3582126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
3583126261Smlaier		s->creation = time_second;
3584126261Smlaier		s->expire = time_second;
3585126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
3586126258Smlaier		pf_set_rt_ifp(s, saddr);
3587130613Smlaier		if (sn != NULL) {
3588130613Smlaier			s->src_node = sn;
3589130613Smlaier			s->src_node->states++;
3590130613Smlaier		}
3591130613Smlaier		if (nsn != NULL) {
3592130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3593130613Smlaier			s->nat_src_node = nsn;
3594130613Smlaier			s->nat_src_node->states++;
3595130613Smlaier		}
3596130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3597145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3598130613Smlaier			pf_src_tree_remove_state(s);
3599145836Smlaier			STATE_DEC_COUNTERS(s);
3600126258Smlaier			pool_put(&pf_state_pl, s);
3601126258Smlaier			return (PF_DROP);
3602126258Smlaier		} else
3603126258Smlaier			*sm = s;
3604145836Smlaier		if (tag > 0) {
3605145836Smlaier			pf_tag_ref(tag);
3606145836Smlaier			s->tag = tag;
3607145836Smlaier		}
3608126258Smlaier	}
3609126258Smlaier
3610126258Smlaier	/* copy back packet headers if we performed NAT operations */
3611126258Smlaier	if (rewrite)
3612126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3613126258Smlaier
3614126258Smlaier	return (PF_PASS);
3615126258Smlaier}
3616126258Smlaier
3617126258Smlaierint
3618126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
3619130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3620145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3621145836Smlaier    struct ifqueue *ifq)
3622126258Smlaier{
3623130613Smlaier	struct pf_rule		*nr = NULL;
3624126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3625126258Smlaier	struct pf_rule		*r, *a = NULL;
3626126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3627130613Smlaier	struct pf_src_node	*nsn = NULL;
3628126258Smlaier	u_short			 reason;
3629127629Smlaier	u_int16_t		 icmpid = 0;	/* make the compiler happy */
3630126258Smlaier	sa_family_t		 af = pd->af;
3631127629Smlaier	u_int8_t		 icmptype = 0;	/* make the compiler happy */
3632127629Smlaier	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
3633126258Smlaier	int			 state_icmp = 0;
3634126258Smlaier	struct pf_tag		*pftag = NULL;
3635126258Smlaier	int			 tag = -1;
3636126258Smlaier#ifdef INET6
3637126258Smlaier	int			 rewrite = 0;
3638126258Smlaier#endif /* INET6 */
3639145836Smlaier	int			 asd = 0;
3640126258Smlaier
3641145836Smlaier	if (pf_check_congestion(ifq)) {
3642145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3643145836Smlaier		return (PF_DROP);
3644145836Smlaier	}
3645145836Smlaier
3646126258Smlaier	switch (pd->proto) {
3647126258Smlaier#ifdef INET
3648126258Smlaier	case IPPROTO_ICMP:
3649126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
3650126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
3651126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
3652126258Smlaier
3653126258Smlaier		if (icmptype == ICMP_UNREACH ||
3654126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
3655126258Smlaier		    icmptype == ICMP_REDIRECT ||
3656126258Smlaier		    icmptype == ICMP_TIMXCEED ||
3657126258Smlaier		    icmptype == ICMP_PARAMPROB)
3658126258Smlaier			state_icmp++;
3659126258Smlaier		break;
3660126258Smlaier#endif /* INET */
3661126258Smlaier#ifdef INET6
3662126258Smlaier	case IPPROTO_ICMPV6:
3663126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
3664126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
3665126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
3666126258Smlaier
3667126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
3668126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
3669126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
3670126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
3671126258Smlaier			state_icmp++;
3672126258Smlaier		break;
3673126258Smlaier#endif /* INET6 */
3674126258Smlaier	}
3675126258Smlaier
3676126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3677126258Smlaier
3678126258Smlaier	if (direction == PF_OUT) {
3679126258Smlaier		/* check outgoing packet for BINAT/NAT */
3680130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3681139045Sdhartmei		    saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
3682130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3683126258Smlaier			switch (af) {
3684126258Smlaier#ifdef INET
3685126258Smlaier			case AF_INET:
3686126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3687130613Smlaier				    pd->naddr.v4.s_addr, 0);
3688126258Smlaier				break;
3689126258Smlaier#endif /* INET */
3690126258Smlaier#ifdef INET6
3691126258Smlaier			case AF_INET6:
3692126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
3693130613Smlaier				    &pd->naddr, 0);
3694126258Smlaier				rewrite++;
3695126258Smlaier				break;
3696126258Smlaier#endif /* INET6 */
3697126258Smlaier			}
3698130613Smlaier			if (nr->natpass)
3699126258Smlaier				r = NULL;
3700130613Smlaier			pd->nat_rule = nr;
3701126258Smlaier		}
3702126258Smlaier	} else {
3703126258Smlaier		/* check incoming packet for BINAT/RDR */
3704130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3705139045Sdhartmei		    saddr, icmpid, daddr, icmpid, &pd->naddr, NULL)) != NULL) {
3706130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3707126258Smlaier			switch (af) {
3708126258Smlaier#ifdef INET
3709126258Smlaier			case AF_INET:
3710126258Smlaier				pf_change_a(&daddr->v4.s_addr,
3711130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
3712126258Smlaier				break;
3713126258Smlaier#endif /* INET */
3714126258Smlaier#ifdef INET6
3715126258Smlaier			case AF_INET6:
3716126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
3717130613Smlaier				    &pd->naddr, 0);
3718126258Smlaier				rewrite++;
3719126258Smlaier				break;
3720126258Smlaier#endif /* INET6 */
3721126258Smlaier			}
3722130613Smlaier			if (nr->natpass)
3723126258Smlaier				r = NULL;
3724130613Smlaier			pd->nat_rule = nr;
3725126258Smlaier		}
3726126258Smlaier	}
3727126258Smlaier
3728126258Smlaier	while (r != NULL) {
3729126258Smlaier		r->evaluations++;
3730130613Smlaier		if (r->kif != NULL &&
3731130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3732126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3733126258Smlaier		else if (r->direction && r->direction != direction)
3734126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3735126258Smlaier		else if (r->af && r->af != af)
3736126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3737126258Smlaier		else if (r->proto && r->proto != pd->proto)
3738126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3739145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3740126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3741145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3742126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3743126258Smlaier		else if (r->type && r->type != icmptype + 1)
3744126258Smlaier			r = TAILQ_NEXT(r, entries);
3745126258Smlaier		else if (r->code && r->code != icmpcode + 1)
3746126258Smlaier			r = TAILQ_NEXT(r, entries);
3747126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3748126258Smlaier			r = TAILQ_NEXT(r, entries);
3749126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3750126258Smlaier			r = TAILQ_NEXT(r, entries);
3751145836Smlaier		else if (r->prob && r->prob <= arc4random())
3752126258Smlaier			r = TAILQ_NEXT(r, entries);
3753145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3754126258Smlaier			r = TAILQ_NEXT(r, entries);
3755126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3756126258Smlaier			r = TAILQ_NEXT(r, entries);
3757126258Smlaier		else {
3758126258Smlaier			if (r->tag)
3759126258Smlaier				tag = r->tag;
3760126258Smlaier			if (r->anchor == NULL) {
3761126258Smlaier				*rm = r;
3762126258Smlaier				*am = a;
3763126258Smlaier				*rsm = ruleset;
3764126258Smlaier				if ((*rm)->quick)
3765126258Smlaier					break;
3766126258Smlaier				r = TAILQ_NEXT(r, entries);
3767126258Smlaier			} else
3768145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3769145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3770126258Smlaier		}
3771145836Smlaier		if (r == NULL)
3772145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3773145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3774126258Smlaier	}
3775126258Smlaier	r = *rm;
3776126258Smlaier	a = *am;
3777126258Smlaier	ruleset = *rsm;
3778126258Smlaier
3779126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3780126258Smlaier
3781126258Smlaier	if (r->log) {
3782126258Smlaier#ifdef INET6
3783126258Smlaier		if (rewrite)
3784126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
3785126261Smlaier			    (caddr_t)pd->hdr.icmp6);
3786126258Smlaier#endif /* INET6 */
3787130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3788126258Smlaier	}
3789126258Smlaier
3790126258Smlaier	if (r->action != PF_PASS)
3791126258Smlaier		return (PF_DROP);
3792126258Smlaier
3793126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3794126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3795126258Smlaier		return (PF_DROP);
3796126258Smlaier	}
3797126258Smlaier
3798130613Smlaier	if (!state_icmp && (r->keep_state || nr != NULL)) {
3799126258Smlaier		/* create new state */
3800126258Smlaier		struct pf_state	*s = NULL;
3801130613Smlaier		struct pf_src_node *sn = NULL;
3802126258Smlaier
3803130613Smlaier		/* check maximums */
3804145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3805145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3806145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3807130613Smlaier			goto cleanup;
3808145836Smlaier		}
3809130613Smlaier		/* src node for flter rule */
3810130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3811130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3812145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3813145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3814130613Smlaier			goto cleanup;
3815145836Smlaier		}
3816130613Smlaier		/* src node for translation rule */
3817130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3818130613Smlaier		    ((direction == PF_OUT &&
3819130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3820145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3821145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3822130613Smlaier			goto cleanup;
3823145836Smlaier		}
3824130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3825126258Smlaier		if (s == NULL) {
3826145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3827130613Smlaiercleanup:
3828130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3829130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3830130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3831130613Smlaier				pf_status.src_nodes--;
3832130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3833130613Smlaier			}
3834130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3835130613Smlaier			    nsn->expire == 0) {
3836130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3837130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3838130613Smlaier				pf_status.src_nodes--;
3839130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3840130613Smlaier			}
3841126258Smlaier			return (PF_DROP);
3842126258Smlaier		}
3843126258Smlaier		bzero(s, sizeof(*s));
3844126258Smlaier		s->rule.ptr = r;
3845130613Smlaier		s->nat_rule.ptr = nr;
3846126258Smlaier		s->anchor.ptr = a;
3847145836Smlaier		STATE_INC_COUNTERS(s);
3848126258Smlaier		s->allow_opts = r->allow_opts;
3849126258Smlaier		s->log = r->log & 2;
3850126258Smlaier		s->proto = pd->proto;
3851126258Smlaier		s->direction = direction;
3852126258Smlaier		s->af = af;
3853126258Smlaier		if (direction == PF_OUT) {
3854126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3855126258Smlaier			s->gwy.port = icmpid;
3856126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3857126258Smlaier			s->ext.port = icmpid;
3858130613Smlaier			if (nr != NULL)
3859130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3860126258Smlaier			else
3861126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3862126258Smlaier			s->lan.port = icmpid;
3863126258Smlaier		} else {
3864126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3865126258Smlaier			s->lan.port = icmpid;
3866126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3867126258Smlaier			s->ext.port = icmpid;
3868130613Smlaier			if (nr != NULL)
3869130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3870126258Smlaier			else
3871126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3872126258Smlaier			s->gwy.port = icmpid;
3873126258Smlaier		}
3874126261Smlaier		s->creation = time_second;
3875126261Smlaier		s->expire = time_second;
3876126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
3877126258Smlaier		pf_set_rt_ifp(s, saddr);
3878130613Smlaier		if (sn != NULL) {
3879130613Smlaier			s->src_node = sn;
3880130613Smlaier			s->src_node->states++;
3881130613Smlaier		}
3882130613Smlaier		if (nsn != NULL) {
3883130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3884130613Smlaier			s->nat_src_node = nsn;
3885130613Smlaier			s->nat_src_node->states++;
3886130613Smlaier		}
3887130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3888145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3889130613Smlaier			pf_src_tree_remove_state(s);
3890145836Smlaier			STATE_DEC_COUNTERS(s);
3891126258Smlaier			pool_put(&pf_state_pl, s);
3892126258Smlaier			return (PF_DROP);
3893126258Smlaier		} else
3894126258Smlaier			*sm = s;
3895145836Smlaier		if (tag > 0) {
3896145836Smlaier			pf_tag_ref(tag);
3897145836Smlaier			s->tag = tag;
3898145836Smlaier		}
3899126258Smlaier	}
3900126258Smlaier
3901126258Smlaier#ifdef INET6
3902126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
3903126258Smlaier	if (rewrite)
3904126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
3905126261Smlaier		    (caddr_t)pd->hdr.icmp6);
3906126258Smlaier#endif /* INET6 */
3907126258Smlaier
3908126258Smlaier	return (PF_PASS);
3909126258Smlaier}
3910126258Smlaier
3911126258Smlaierint
3912126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
3913130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
3914145836Smlaier    struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
3915126258Smlaier{
3916130613Smlaier	struct pf_rule		*nr = NULL;
3917126258Smlaier	struct pf_rule		*r, *a = NULL;
3918126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3919130613Smlaier	struct pf_src_node	*nsn = NULL;
3920126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3921126258Smlaier	sa_family_t		 af = pd->af;
3922126258Smlaier	u_short			 reason;
3923126258Smlaier	struct pf_tag		*pftag = NULL;
3924126258Smlaier	int			 tag = -1;
3925145836Smlaier	int			 asd = 0;
3926126258Smlaier
3927145836Smlaier	if (pf_check_congestion(ifq)) {
3928145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3929145836Smlaier		return (PF_DROP);
3930145836Smlaier	}
3931145836Smlaier
3932126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3933126258Smlaier
3934126258Smlaier	if (direction == PF_OUT) {
3935126258Smlaier		/* check outgoing packet for BINAT/NAT */
3936130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3937130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
3938130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3939126258Smlaier			switch (af) {
3940126258Smlaier#ifdef INET
3941126258Smlaier			case AF_INET:
3942126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3943130613Smlaier				    pd->naddr.v4.s_addr, 0);
3944126258Smlaier				break;
3945126258Smlaier#endif /* INET */
3946126258Smlaier#ifdef INET6
3947126258Smlaier			case AF_INET6:
3948130613Smlaier				PF_ACPY(saddr, &pd->naddr, af);
3949126258Smlaier				break;
3950126258Smlaier#endif /* INET6 */
3951126258Smlaier			}
3952130613Smlaier			if (nr->natpass)
3953126258Smlaier				r = NULL;
3954130613Smlaier			pd->nat_rule = nr;
3955126258Smlaier		}
3956126258Smlaier	} else {
3957126258Smlaier		/* check incoming packet for BINAT/RDR */
3958130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3959130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
3960130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3961126258Smlaier			switch (af) {
3962126258Smlaier#ifdef INET
3963126258Smlaier			case AF_INET:
3964126258Smlaier				pf_change_a(&daddr->v4.s_addr,
3965130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
3966126258Smlaier				break;
3967126258Smlaier#endif /* INET */
3968126258Smlaier#ifdef INET6
3969126258Smlaier			case AF_INET6:
3970130613Smlaier				PF_ACPY(daddr, &pd->naddr, af);
3971126258Smlaier				break;
3972126258Smlaier#endif /* INET6 */
3973126258Smlaier			}
3974130613Smlaier			if (nr->natpass)
3975126258Smlaier				r = NULL;
3976130613Smlaier			pd->nat_rule = nr;
3977126258Smlaier		}
3978126258Smlaier	}
3979126258Smlaier
3980126258Smlaier	while (r != NULL) {
3981126258Smlaier		r->evaluations++;
3982130613Smlaier		if (r->kif != NULL &&
3983130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3984126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3985126258Smlaier		else if (r->direction && r->direction != direction)
3986126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3987126258Smlaier		else if (r->af && r->af != af)
3988126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3989126258Smlaier		else if (r->proto && r->proto != pd->proto)
3990126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3991145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
3992126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3993145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
3994126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3995126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3996126258Smlaier			r = TAILQ_NEXT(r, entries);
3997126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3998126258Smlaier			r = TAILQ_NEXT(r, entries);
3999145836Smlaier		else if (r->prob && r->prob <= arc4random())
4000126258Smlaier			r = TAILQ_NEXT(r, entries);
4001145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
4002126258Smlaier			r = TAILQ_NEXT(r, entries);
4003126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4004126258Smlaier			r = TAILQ_NEXT(r, entries);
4005126258Smlaier		else {
4006126258Smlaier			if (r->tag)
4007126258Smlaier				tag = r->tag;
4008126258Smlaier			if (r->anchor == NULL) {
4009126258Smlaier				*rm = r;
4010126258Smlaier				*am = a;
4011126258Smlaier				*rsm = ruleset;
4012126258Smlaier				if ((*rm)->quick)
4013126258Smlaier					break;
4014126258Smlaier				r = TAILQ_NEXT(r, entries);
4015126258Smlaier			} else
4016145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4017145836Smlaier				    PF_RULESET_FILTER, &r, &a);
4018126258Smlaier		}
4019145836Smlaier		if (r == NULL)
4020145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
4021145836Smlaier			    PF_RULESET_FILTER, &r, &a);
4022126258Smlaier	}
4023126258Smlaier	r = *rm;
4024126258Smlaier	a = *am;
4025126258Smlaier	ruleset = *rsm;
4026126258Smlaier
4027126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4028130613Smlaier
4029126258Smlaier	if (r->log)
4030130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
4031126258Smlaier
4032126258Smlaier	if ((r->action == PF_DROP) &&
4033126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
4034126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
4035126258Smlaier		struct pf_addr *a = NULL;
4036126258Smlaier
4037130613Smlaier		if (nr != NULL) {
4038130613Smlaier			if (direction == PF_OUT)
4039130613Smlaier				a = saddr;
4040130613Smlaier			else
4041130613Smlaier				a = daddr;
4042130613Smlaier		}
4043126258Smlaier		if (a != NULL) {
4044126258Smlaier			switch (af) {
4045126258Smlaier#ifdef INET
4046126258Smlaier			case AF_INET:
4047126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
4048130613Smlaier				    pd->baddr.v4.s_addr, 0);
4049126258Smlaier				break;
4050126258Smlaier#endif /* INET */
4051126258Smlaier#ifdef INET6
4052126258Smlaier			case AF_INET6:
4053130613Smlaier				PF_ACPY(a, &pd->baddr, af);
4054126258Smlaier				break;
4055126258Smlaier#endif /* INET6 */
4056126258Smlaier			}
4057126258Smlaier		}
4058126258Smlaier		if ((af == AF_INET) && r->return_icmp)
4059126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
4060126258Smlaier			    r->return_icmp & 255, af, r);
4061126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
4062126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
4063126258Smlaier			    r->return_icmp6 & 255, af, r);
4064126258Smlaier	}
4065126258Smlaier
4066126258Smlaier	if (r->action != PF_PASS)
4067126258Smlaier		return (PF_DROP);
4068126258Smlaier
4069126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
4070126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4071126258Smlaier		return (PF_DROP);
4072126258Smlaier	}
4073126258Smlaier
4074130613Smlaier	if (r->keep_state || nr != NULL) {
4075126258Smlaier		/* create new state */
4076126258Smlaier		struct pf_state	*s = NULL;
4077130613Smlaier		struct pf_src_node *sn = NULL;
4078126258Smlaier
4079130613Smlaier		/* check maximums */
4080145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4081145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4082145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4083130613Smlaier			goto cleanup;
4084145836Smlaier		}
4085130613Smlaier		/* src node for flter rule */
4086130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4087130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4088145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4089145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4090130613Smlaier			goto cleanup;
4091145836Smlaier		}
4092130613Smlaier		/* src node for translation rule */
4093130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4094130613Smlaier		    ((direction == PF_OUT &&
4095130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4096145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4097145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4098130613Smlaier			goto cleanup;
4099145836Smlaier		}
4100130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4101126258Smlaier		if (s == NULL) {
4102145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4103130613Smlaiercleanup:
4104130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4105130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4106130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4107130613Smlaier				pf_status.src_nodes--;
4108130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4109130613Smlaier			}
4110130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4111130613Smlaier			    nsn->expire == 0) {
4112130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4113130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4114130613Smlaier				pf_status.src_nodes--;
4115130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4116130613Smlaier			}
4117126258Smlaier			return (PF_DROP);
4118126258Smlaier		}
4119126258Smlaier		bzero(s, sizeof(*s));
4120126258Smlaier		s->rule.ptr = r;
4121130613Smlaier		s->nat_rule.ptr = nr;
4122126258Smlaier		s->anchor.ptr = a;
4123145836Smlaier		STATE_INC_COUNTERS(s);
4124126258Smlaier		s->allow_opts = r->allow_opts;
4125126258Smlaier		s->log = r->log & 2;
4126126258Smlaier		s->proto = pd->proto;
4127126258Smlaier		s->direction = direction;
4128126258Smlaier		s->af = af;
4129126258Smlaier		if (direction == PF_OUT) {
4130126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4131126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4132130613Smlaier			if (nr != NULL)
4133130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4134126258Smlaier			else
4135126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4136126258Smlaier		} else {
4137126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4138126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4139130613Smlaier			if (nr != NULL)
4140130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4141126258Smlaier			else
4142126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4143126258Smlaier		}
4144126258Smlaier		s->src.state = PFOTHERS_SINGLE;
4145126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
4146126261Smlaier		s->creation = time_second;
4147126261Smlaier		s->expire = time_second;
4148126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
4149126258Smlaier		pf_set_rt_ifp(s, saddr);
4150130613Smlaier		if (sn != NULL) {
4151130613Smlaier			s->src_node = sn;
4152130613Smlaier			s->src_node->states++;
4153130613Smlaier		}
4154130613Smlaier		if (nsn != NULL) {
4155130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4156130613Smlaier			s->nat_src_node = nsn;
4157130613Smlaier			s->nat_src_node->states++;
4158130613Smlaier		}
4159130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4160145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4161130613Smlaier			pf_src_tree_remove_state(s);
4162145836Smlaier			STATE_DEC_COUNTERS(s);
4163126258Smlaier			pool_put(&pf_state_pl, s);
4164126258Smlaier			return (PF_DROP);
4165126258Smlaier		} else
4166126258Smlaier			*sm = s;
4167145836Smlaier		if (tag > 0) {
4168145836Smlaier			pf_tag_ref(tag);
4169145836Smlaier			s->tag = tag;
4170145836Smlaier		}
4171126258Smlaier	}
4172126258Smlaier
4173126258Smlaier	return (PF_PASS);
4174126258Smlaier}
4175126258Smlaier
4176126258Smlaierint
4177130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
4178126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
4179126258Smlaier    struct pf_ruleset **rsm)
4180126258Smlaier{
4181126258Smlaier	struct pf_rule		*r, *a = NULL;
4182126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4183126258Smlaier	sa_family_t		 af = pd->af;
4184126258Smlaier	u_short			 reason;
4185126258Smlaier	struct pf_tag		*pftag = NULL;
4186126258Smlaier	int			 tag = -1;
4187145836Smlaier	int			 asd = 0;
4188126258Smlaier
4189126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4190126258Smlaier	while (r != NULL) {
4191126258Smlaier		r->evaluations++;
4192130613Smlaier		if (r->kif != NULL &&
4193130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
4194126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4195126258Smlaier		else if (r->direction && r->direction != direction)
4196126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4197126258Smlaier		else if (r->af && r->af != af)
4198126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4199126258Smlaier		else if (r->proto && r->proto != pd->proto)
4200126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4201145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
4202126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4203145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
4204126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4205126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
4206126258Smlaier			r = TAILQ_NEXT(r, entries);
4207126258Smlaier		else if (r->src.port_op || r->dst.port_op ||
4208126258Smlaier		    r->flagset || r->type || r->code ||
4209126258Smlaier		    r->os_fingerprint != PF_OSFP_ANY)
4210126258Smlaier			r = TAILQ_NEXT(r, entries);
4211145836Smlaier		else if (r->prob && r->prob <= arc4random())
4212126258Smlaier			r = TAILQ_NEXT(r, entries);
4213145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
4214126258Smlaier			r = TAILQ_NEXT(r, entries);
4215126258Smlaier		else {
4216126258Smlaier			if (r->anchor == NULL) {
4217126258Smlaier				*rm = r;
4218126258Smlaier				*am = a;
4219126258Smlaier				*rsm = ruleset;
4220126258Smlaier				if ((*rm)->quick)
4221126258Smlaier					break;
4222126258Smlaier				r = TAILQ_NEXT(r, entries);
4223126258Smlaier			} else
4224145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4225145836Smlaier				    PF_RULESET_FILTER, &r, &a);
4226126258Smlaier		}
4227145836Smlaier		if (r == NULL)
4228145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
4229145836Smlaier			    PF_RULESET_FILTER, &r, &a);
4230126258Smlaier	}
4231126258Smlaier	r = *rm;
4232126258Smlaier	a = *am;
4233126258Smlaier	ruleset = *rsm;
4234126258Smlaier
4235126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4236130613Smlaier
4237126258Smlaier	if (r->log)
4238130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
4239126258Smlaier
4240126258Smlaier	if (r->action != PF_PASS)
4241126258Smlaier		return (PF_DROP);
4242126258Smlaier
4243126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
4244126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4245126258Smlaier		return (PF_DROP);
4246126258Smlaier	}
4247126258Smlaier
4248126258Smlaier	return (PF_PASS);
4249126258Smlaier}
4250126258Smlaier
4251126258Smlaierint
4252130613Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
4253130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4254126258Smlaier    u_short *reason)
4255126258Smlaier{
4256130613Smlaier	struct pf_state		 key;
4257126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
4258126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
4259145836Smlaier	u_int32_t		 ack, end, seq, orig_seq;
4260126258Smlaier	u_int8_t		 sws, dws;
4261130613Smlaier	int			 ackskew;
4262126258Smlaier	int			 copyback = 0;
4263126258Smlaier	struct pf_state_peer	*src, *dst;
4264126258Smlaier
4265126258Smlaier	key.af = pd->af;
4266126258Smlaier	key.proto = IPPROTO_TCP;
4267130613Smlaier	if (direction == PF_IN)	{
4268130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4269130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4270130613Smlaier		key.ext.port = th->th_sport;
4271130613Smlaier		key.gwy.port = th->th_dport;
4272130613Smlaier	} else {
4273130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4274130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4275130613Smlaier		key.lan.port = th->th_sport;
4276130613Smlaier		key.ext.port = th->th_dport;
4277130613Smlaier	}
4278126258Smlaier
4279126258Smlaier	STATE_LOOKUP();
4280126258Smlaier
4281126258Smlaier	if (direction == (*state)->direction) {
4282126258Smlaier		src = &(*state)->src;
4283126258Smlaier		dst = &(*state)->dst;
4284126258Smlaier	} else {
4285126258Smlaier		src = &(*state)->dst;
4286126258Smlaier		dst = &(*state)->src;
4287126258Smlaier	}
4288126258Smlaier
4289126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4290145836Smlaier		if (direction != (*state)->direction) {
4291145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4292126258Smlaier			return (PF_SYNPROXY_DROP);
4293145836Smlaier		}
4294126258Smlaier		if (th->th_flags & TH_SYN) {
4295145836Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo) {
4296145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4297126258Smlaier				return (PF_DROP);
4298145836Smlaier			}
4299126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4300126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4301126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4302145836Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
4303145836Smlaier			    NULL, NULL);
4304145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4305126258Smlaier			return (PF_SYNPROXY_DROP);
4306126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
4307126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4308145836Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4309145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4310126258Smlaier			return (PF_DROP);
4311145836Smlaier		} else if ((*state)->src_node != NULL &&
4312145836Smlaier		    pf_src_connlimit(state)) {
4313145836Smlaier			REASON_SET(reason, PFRES_SRCLIMIT);
4314145836Smlaier			return (PF_DROP);
4315145836Smlaier		} else
4316126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
4317126258Smlaier	}
4318126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4319126258Smlaier		struct pf_state_host *src, *dst;
4320126258Smlaier
4321126258Smlaier		if (direction == PF_OUT) {
4322126258Smlaier			src = &(*state)->gwy;
4323126258Smlaier			dst = &(*state)->ext;
4324126258Smlaier		} else {
4325126258Smlaier			src = &(*state)->ext;
4326126258Smlaier			dst = &(*state)->lan;
4327126258Smlaier		}
4328126258Smlaier		if (direction == (*state)->direction) {
4329126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4330126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4331145836Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4332145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4333126258Smlaier				return (PF_DROP);
4334145836Smlaier			}
4335126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4336126258Smlaier			if ((*state)->dst.seqhi == 1)
4337145836Smlaier				(*state)->dst.seqhi = htonl(arc4random());
4338126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4339126258Smlaier			    &dst->addr, src->port, dst->port,
4340130613Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4341145836Smlaier			    (*state)->src.mss, 0, 0, NULL, NULL);
4342145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4343126258Smlaier			return (PF_SYNPROXY_DROP);
4344126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4345126258Smlaier		    (TH_SYN|TH_ACK)) ||
4346145836Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
4347145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4348126258Smlaier			return (PF_DROP);
4349145836Smlaier		} else {
4350126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4351126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
4352126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4353126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4354126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4355145836Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
4356145836Smlaier			    NULL, NULL);
4357126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4358126258Smlaier			    &dst->addr, src->port, dst->port,
4359126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4360145836Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
4361145836Smlaier			    NULL, NULL);
4362126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
4363126258Smlaier			    (*state)->src.seqlo;
4364126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
4365126258Smlaier			    (*state)->dst.seqlo;
4366126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
4367145875Smlaier			    (*state)->dst.max_win;
4368145875Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
4369145836Smlaier			    (*state)->src.max_win;
4370126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
4371126258Smlaier			(*state)->src.state = (*state)->dst.state =
4372126258Smlaier			    TCPS_ESTABLISHED;
4373145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4374126258Smlaier			return (PF_SYNPROXY_DROP);
4375126258Smlaier		}
4376126258Smlaier	}
4377126258Smlaier
4378126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4379126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4380126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4381126258Smlaier	} else
4382126258Smlaier		sws = dws = 0;
4383126258Smlaier
4384126258Smlaier	/*
4385126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4386126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4387126258Smlaier	 *	tcp_filtering.ps
4388126258Smlaier	 */
4389126258Smlaier
4390145836Smlaier	orig_seq = seq = ntohl(th->th_seq);
4391126258Smlaier	if (src->seqlo == 0) {
4392126258Smlaier		/* First packet from this end. Set its state */
4393126258Smlaier
4394126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4395126258Smlaier		    src->scrub == NULL) {
4396126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4397126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4398126258Smlaier				return (PF_DROP);
4399126258Smlaier			}
4400126258Smlaier		}
4401126258Smlaier
4402126258Smlaier		/* Deferred generation of sequence number modulator */
4403126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4404145836Smlaier			while ((src->seqdiff = htonl(arc4random())) == 0)
4405126258Smlaier				;
4406126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4407126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4408126258Smlaier			    src->seqdiff), 0);
4409126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4410126258Smlaier			copyback = 1;
4411126258Smlaier		} else {
4412126258Smlaier			ack = ntohl(th->th_ack);
4413126258Smlaier		}
4414126258Smlaier
4415126258Smlaier		end = seq + pd->p_len;
4416126258Smlaier		if (th->th_flags & TH_SYN) {
4417126258Smlaier			end++;
4418126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4419126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4420126258Smlaier				    pd->af);
4421126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4422126258Smlaier					/* Remove scale factor from initial
4423126258Smlaier					 * window */
4424126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4425126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4426126258Smlaier					    >> sws;
4427126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4428126258Smlaier				} else {
4429126258Smlaier					/* fixup other window */
4430126258Smlaier					dst->max_win <<= dst->wscale &
4431126258Smlaier					    PF_WSCALE_MASK;
4432126258Smlaier					/* in case of a retrans SYN|ACK */
4433126258Smlaier					dst->wscale = 0;
4434126258Smlaier				}
4435126258Smlaier			}
4436126258Smlaier		}
4437126258Smlaier		if (th->th_flags & TH_FIN)
4438126258Smlaier			end++;
4439126258Smlaier
4440126258Smlaier		src->seqlo = seq;
4441126258Smlaier		if (src->state < TCPS_SYN_SENT)
4442126258Smlaier			src->state = TCPS_SYN_SENT;
4443126258Smlaier
4444126258Smlaier		/*
4445126258Smlaier		 * May need to slide the window (seqhi may have been set by
4446126258Smlaier		 * the crappy stack check or if we picked up the connection
4447126258Smlaier		 * after establishment)
4448126258Smlaier		 */
4449126258Smlaier		if (src->seqhi == 1 ||
4450126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4451126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4452126258Smlaier		if (win > src->max_win)
4453126258Smlaier			src->max_win = win;
4454126258Smlaier
4455126258Smlaier	} else {
4456126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4457126258Smlaier		if (src->seqdiff) {
4458126258Smlaier			/* Modulate sequence numbers */
4459126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4460126258Smlaier			    src->seqdiff), 0);
4461126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4462126258Smlaier			copyback = 1;
4463126258Smlaier		}
4464126258Smlaier		end = seq + pd->p_len;
4465126258Smlaier		if (th->th_flags & TH_SYN)
4466126258Smlaier			end++;
4467126258Smlaier		if (th->th_flags & TH_FIN)
4468126258Smlaier			end++;
4469126258Smlaier	}
4470126258Smlaier
4471126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4472126258Smlaier		/* Let it pass through the ack skew check */
4473126258Smlaier		ack = dst->seqlo;
4474126258Smlaier	} else if ((ack == 0 &&
4475126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4476126258Smlaier	    /* broken tcp stacks do not set ack */
4477126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4478126258Smlaier		/*
4479126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4480126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4481126258Smlaier		 */
4482126258Smlaier		ack = dst->seqlo;
4483126258Smlaier	}
4484126258Smlaier
4485126258Smlaier	if (seq == end) {
4486126258Smlaier		/* Ease sequencing restrictions on no data packets */
4487126258Smlaier		seq = src->seqlo;
4488126258Smlaier		end = seq;
4489126258Smlaier	}
4490126258Smlaier
4491126258Smlaier	ackskew = dst->seqlo - ack;
4492126258Smlaier
4493126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4494126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4495126258Smlaier	    /* Last octet inside other's window space */
4496126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4497126258Smlaier	    /* Retrans: not more than one window back */
4498126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4499126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4500145836Smlaier	    (ackskew <= (MAXACKWINDOW << sws)) &&
4501126258Smlaier	    /* Acking not more than one window forward */
4502145836Smlaier	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
4503145836Smlaier	    (pd->flags & PFDESC_IP_REAS) == 0)) {
4504145836Smlaier	    /* Require an exact sequence match on resets when possible */
4505126258Smlaier
4506145836Smlaier		if (dst->scrub || src->scrub) {
4507145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4508145836Smlaier			    *state, src, dst, &copyback))
4509145836Smlaier				return (PF_DROP);
4510145836Smlaier		}
4511145836Smlaier
4512126258Smlaier		/* update max window */
4513126258Smlaier		if (src->max_win < win)
4514126258Smlaier			src->max_win = win;
4515126258Smlaier		/* synchronize sequencing */
4516126258Smlaier		if (SEQ_GT(end, src->seqlo))
4517126258Smlaier			src->seqlo = end;
4518126258Smlaier		/* slide the window of what the other end can send */
4519126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4520126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4521126258Smlaier
4522126258Smlaier
4523126258Smlaier		/* update states */
4524126258Smlaier		if (th->th_flags & TH_SYN)
4525126258Smlaier			if (src->state < TCPS_SYN_SENT)
4526126258Smlaier				src->state = TCPS_SYN_SENT;
4527126258Smlaier		if (th->th_flags & TH_FIN)
4528126258Smlaier			if (src->state < TCPS_CLOSING)
4529126258Smlaier				src->state = TCPS_CLOSING;
4530126258Smlaier		if (th->th_flags & TH_ACK) {
4531145836Smlaier			if (dst->state == TCPS_SYN_SENT) {
4532126258Smlaier				dst->state = TCPS_ESTABLISHED;
4533145836Smlaier				if (src->state == TCPS_ESTABLISHED &&
4534145836Smlaier				    (*state)->src_node != NULL &&
4535145836Smlaier				    pf_src_connlimit(state)) {
4536145836Smlaier					REASON_SET(reason, PFRES_SRCLIMIT);
4537145836Smlaier					return (PF_DROP);
4538145836Smlaier				}
4539145836Smlaier			} else if (dst->state == TCPS_CLOSING)
4540126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
4541126258Smlaier		}
4542126258Smlaier		if (th->th_flags & TH_RST)
4543126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4544126258Smlaier
4545126258Smlaier		/* update expire time */
4546126261Smlaier		(*state)->expire = time_second;
4547126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
4548126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4549126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
4550126258Smlaier		else if (src->state >= TCPS_FIN_WAIT_2 ||
4551126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4552126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
4553126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
4554126258Smlaier		    dst->state < TCPS_ESTABLISHED)
4555126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
4556126258Smlaier		else if (src->state >= TCPS_CLOSING ||
4557126258Smlaier		    dst->state >= TCPS_CLOSING)
4558126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
4559126258Smlaier		else
4560126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
4561126258Smlaier
4562126258Smlaier		/* Fall through to PASS packet */
4563126258Smlaier
4564126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
4565126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
4566126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
4567126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
4568126258Smlaier	    /* Within a window forward of the originating packet */
4569126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
4570126258Smlaier	    /* Within a window backward of the originating packet */
4571126258Smlaier
4572126258Smlaier		/*
4573126258Smlaier		 * This currently handles three situations:
4574126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
4575126258Smlaier		 *     replies.
4576126258Smlaier		 *  2) When PF catches an already established stream (the
4577126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
4578126258Smlaier		 *     changed...)
4579126258Smlaier		 *  3) Packets get funky immediately after the connection
4580126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
4581126258Smlaier		 *     that web servers like to spew after a close)
4582126258Smlaier		 *
4583126258Smlaier		 * This must be a little more careful than the above code
4584126258Smlaier		 * since packet floods will also be caught here. We don't
4585126258Smlaier		 * update the TTL here to mitigate the damage of a packet
4586126258Smlaier		 * flood and so the same code can handle awkward establishment
4587126258Smlaier		 * and a loosened connection close.
4588126258Smlaier		 * In the establishment case, a correct peer response will
4589126258Smlaier		 * validate the connection, go through the normal state code
4590126258Smlaier		 * and keep updating the state TTL.
4591126258Smlaier		 */
4592126258Smlaier
4593126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
4594126258Smlaier			printf("pf: loose state match: ");
4595126258Smlaier			pf_print_state(*state);
4596126258Smlaier			pf_print_flags(th->th_flags);
4597126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n",
4598126258Smlaier			    seq, ack, pd->p_len, ackskew,
4599126258Smlaier			    (*state)->packets[0], (*state)->packets[1]);
4600126258Smlaier		}
4601126258Smlaier
4602145836Smlaier		if (dst->scrub || src->scrub) {
4603145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4604145836Smlaier			    *state, src, dst, &copyback))
4605145836Smlaier				return (PF_DROP);
4606145836Smlaier		}
4607145836Smlaier
4608126258Smlaier		/* update max window */
4609126258Smlaier		if (src->max_win < win)
4610126258Smlaier			src->max_win = win;
4611126258Smlaier		/* synchronize sequencing */
4612126258Smlaier		if (SEQ_GT(end, src->seqlo))
4613126258Smlaier			src->seqlo = end;
4614126258Smlaier		/* slide the window of what the other end can send */
4615126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4616126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4617126258Smlaier
4618126258Smlaier		/*
4619126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
4620126258Smlaier		 * SYN and not an already established connection.
4621126258Smlaier		 */
4622126258Smlaier
4623126258Smlaier		if (th->th_flags & TH_FIN)
4624126258Smlaier			if (src->state < TCPS_CLOSING)
4625126258Smlaier				src->state = TCPS_CLOSING;
4626126258Smlaier		if (th->th_flags & TH_RST)
4627126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4628126258Smlaier
4629126258Smlaier		/* Fall through to PASS packet */
4630126258Smlaier
4631126258Smlaier	} else {
4632126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
4633126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
4634126258Smlaier			/* Send RST for state mismatches during handshake */
4635145836Smlaier			if (!(th->th_flags & TH_RST))
4636126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
4637126258Smlaier				    pd->dst, pd->src, th->th_dport,
4638145836Smlaier				    th->th_sport, ntohl(th->th_ack), 0,
4639145836Smlaier				    TH_RST, 0, 0,
4640145836Smlaier				    (*state)->rule.ptr->return_ttl, 1,
4641145836Smlaier				    pd->eh, kif->pfik_ifp);
4642126258Smlaier			src->seqlo = 0;
4643126258Smlaier			src->seqhi = 1;
4644126258Smlaier			src->max_win = 1;
4645126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
4646126258Smlaier			printf("pf: BAD state: ");
4647126258Smlaier			pf_print_state(*state);
4648126258Smlaier			pf_print_flags(th->th_flags);
4649126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d "
4650126258Smlaier			    "dir=%s,%s\n", seq, ack, pd->p_len, ackskew,
4651126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
4652126258Smlaier			    direction == PF_IN ? "in" : "out",
4653126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
4654126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
4655126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
4656126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
4657126258Smlaier			    ' ': '2',
4658126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
4659126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
4660126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
4661126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
4662126258Smlaier		}
4663145836Smlaier		REASON_SET(reason, PFRES_BADSTATE);
4664126258Smlaier		return (PF_DROP);
4665126258Smlaier	}
4666126258Smlaier
4667126258Smlaier	/* Any packets which have gotten here are to be passed */
4668126258Smlaier
4669126258Smlaier	/* translate source/destination address, if necessary */
4670126258Smlaier	if (STATE_TRANSLATE(*state)) {
4671126258Smlaier		if (direction == PF_OUT)
4672126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
4673126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
4674126258Smlaier			    (*state)->gwy.port, 0, pd->af);
4675126258Smlaier		else
4676126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
4677126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
4678126258Smlaier			    (*state)->lan.port, 0, pd->af);
4679126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4680126258Smlaier	} else if (copyback) {
4681126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
4682126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4683126258Smlaier	}
4684126258Smlaier
4685126258Smlaier	return (PF_PASS);
4686126258Smlaier}
4687126258Smlaier
4688126258Smlaierint
4689130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
4690130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
4691126258Smlaier{
4692126258Smlaier	struct pf_state_peer	*src, *dst;
4693130613Smlaier	struct pf_state		 key;
4694126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
4695126258Smlaier
4696126258Smlaier	key.af = pd->af;
4697126258Smlaier	key.proto = IPPROTO_UDP;
4698130613Smlaier	if (direction == PF_IN)	{
4699130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4700130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4701130613Smlaier		key.ext.port = uh->uh_sport;
4702130613Smlaier		key.gwy.port = uh->uh_dport;
4703130613Smlaier	} else {
4704130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4705130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4706130613Smlaier		key.lan.port = uh->uh_sport;
4707130613Smlaier		key.ext.port = uh->uh_dport;
4708130613Smlaier	}
4709126258Smlaier
4710126258Smlaier	STATE_LOOKUP();
4711126258Smlaier
4712126258Smlaier	if (direction == (*state)->direction) {
4713126258Smlaier		src = &(*state)->src;
4714126258Smlaier		dst = &(*state)->dst;
4715126258Smlaier	} else {
4716126258Smlaier		src = &(*state)->dst;
4717126258Smlaier		dst = &(*state)->src;
4718126258Smlaier	}
4719126258Smlaier
4720126258Smlaier	/* update states */
4721126258Smlaier	if (src->state < PFUDPS_SINGLE)
4722126258Smlaier		src->state = PFUDPS_SINGLE;
4723126258Smlaier	if (dst->state == PFUDPS_SINGLE)
4724126258Smlaier		dst->state = PFUDPS_MULTIPLE;
4725126258Smlaier
4726126258Smlaier	/* update expire time */
4727126261Smlaier	(*state)->expire = time_second;
4728126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
4729126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
4730126258Smlaier	else
4731126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
4732126258Smlaier
4733126258Smlaier	/* translate source/destination address, if necessary */
4734126258Smlaier	if (STATE_TRANSLATE(*state)) {
4735126258Smlaier		if (direction == PF_OUT)
4736126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
4737126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
4738126258Smlaier			    (*state)->gwy.port, 1, pd->af);
4739126258Smlaier		else
4740126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
4741126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
4742126258Smlaier			    (*state)->lan.port, 1, pd->af);
4743126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
4744126258Smlaier	}
4745126258Smlaier
4746126258Smlaier	return (PF_PASS);
4747126258Smlaier}
4748126258Smlaier
4749126258Smlaierint
4750130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
4751145836Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
4752126258Smlaier{
4753126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
4754127629Smlaier	u_int16_t	 icmpid = 0;		/* make the compiler happy */
4755127629Smlaier	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
4756127629Smlaier	u_int8_t	 icmptype = 0;		/* make the compiler happy */
4757130613Smlaier	int		 state_icmp = 0;
4758126258Smlaier
4759126258Smlaier	switch (pd->proto) {
4760126258Smlaier#ifdef INET
4761126258Smlaier	case IPPROTO_ICMP:
4762126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
4763126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4764126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
4765126258Smlaier
4766126258Smlaier		if (icmptype == ICMP_UNREACH ||
4767126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4768126258Smlaier		    icmptype == ICMP_REDIRECT ||
4769126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4770126258Smlaier		    icmptype == ICMP_PARAMPROB)
4771126258Smlaier			state_icmp++;
4772126258Smlaier		break;
4773126258Smlaier#endif /* INET */
4774126258Smlaier#ifdef INET6
4775126258Smlaier	case IPPROTO_ICMPV6:
4776126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4777126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4778126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
4779126258Smlaier
4780126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4781126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4782126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4783126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4784126258Smlaier			state_icmp++;
4785126258Smlaier		break;
4786126258Smlaier#endif /* INET6 */
4787126258Smlaier	}
4788126258Smlaier
4789126258Smlaier	if (!state_icmp) {
4790126258Smlaier
4791126258Smlaier		/*
4792126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
4793126258Smlaier		 * Search for an ICMP state.
4794126258Smlaier		 */
4795130613Smlaier		struct pf_state		key;
4796126258Smlaier
4797126258Smlaier		key.af = pd->af;
4798126258Smlaier		key.proto = pd->proto;
4799130613Smlaier		if (direction == PF_IN)	{
4800130613Smlaier			PF_ACPY(&key.ext.addr, pd->src, key.af);
4801130613Smlaier			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4802130613Smlaier			key.ext.port = icmpid;
4803130613Smlaier			key.gwy.port = icmpid;
4804130613Smlaier		} else {
4805130613Smlaier			PF_ACPY(&key.lan.addr, pd->src, key.af);
4806130613Smlaier			PF_ACPY(&key.ext.addr, pd->dst, key.af);
4807130613Smlaier			key.lan.port = icmpid;
4808130613Smlaier			key.ext.port = icmpid;
4809130613Smlaier		}
4810126258Smlaier
4811126258Smlaier		STATE_LOOKUP();
4812126258Smlaier
4813126261Smlaier		(*state)->expire = time_second;
4814126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
4815126258Smlaier
4816126258Smlaier		/* translate source/destination address, if necessary */
4817126258Smlaier		if (PF_ANEQ(&(*state)->lan.addr, &(*state)->gwy.addr, pd->af)) {
4818126258Smlaier			if (direction == PF_OUT) {
4819126258Smlaier				switch (pd->af) {
4820126258Smlaier#ifdef INET
4821126258Smlaier				case AF_INET:
4822126258Smlaier					pf_change_a(&saddr->v4.s_addr,
4823126258Smlaier					    pd->ip_sum,
4824126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
4825126258Smlaier					break;
4826126258Smlaier#endif /* INET */
4827126258Smlaier#ifdef INET6
4828126258Smlaier				case AF_INET6:
4829126258Smlaier					pf_change_a6(saddr,
4830126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4831126258Smlaier					    &(*state)->gwy.addr, 0);
4832126258Smlaier					m_copyback(m, off,
4833126258Smlaier					    sizeof(struct icmp6_hdr),
4834126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4835126258Smlaier					break;
4836126258Smlaier#endif /* INET6 */
4837126258Smlaier				}
4838126258Smlaier			} else {
4839126258Smlaier				switch (pd->af) {
4840126258Smlaier#ifdef INET
4841126258Smlaier				case AF_INET:
4842126258Smlaier					pf_change_a(&daddr->v4.s_addr,
4843126258Smlaier					    pd->ip_sum,
4844126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
4845126258Smlaier					break;
4846126258Smlaier#endif /* INET */
4847126258Smlaier#ifdef INET6
4848126258Smlaier				case AF_INET6:
4849126258Smlaier					pf_change_a6(daddr,
4850126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4851126258Smlaier					    &(*state)->lan.addr, 0);
4852126258Smlaier					m_copyback(m, off,
4853126258Smlaier					    sizeof(struct icmp6_hdr),
4854126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4855126258Smlaier					break;
4856126258Smlaier#endif /* INET6 */
4857126258Smlaier				}
4858126258Smlaier			}
4859126258Smlaier		}
4860126258Smlaier
4861126258Smlaier		return (PF_PASS);
4862126258Smlaier
4863126258Smlaier	} else {
4864126258Smlaier		/*
4865126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
4866126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
4867126258Smlaier		 */
4868126258Smlaier
4869126258Smlaier		struct pf_pdesc	pd2;
4870126258Smlaier#ifdef INET
4871126258Smlaier		struct ip	h2;
4872126258Smlaier#endif /* INET */
4873126258Smlaier#ifdef INET6
4874126258Smlaier		struct ip6_hdr	h2_6;
4875126258Smlaier		int		terminal = 0;
4876126258Smlaier#endif /* INET6 */
4877127629Smlaier		int		ipoff2 = 0;	/* make the compiler happy */
4878127629Smlaier		int		off2 = 0;	/* make the compiler happy */
4879126258Smlaier
4880126258Smlaier		pd2.af = pd->af;
4881126258Smlaier		switch (pd->af) {
4882126258Smlaier#ifdef INET
4883126258Smlaier		case AF_INET:
4884126258Smlaier			/* offset of h2 in mbuf chain */
4885126258Smlaier			ipoff2 = off + ICMP_MINLEN;
4886126258Smlaier
4887126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
4888145836Smlaier			    NULL, reason, pd2.af)) {
4889126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4890126258Smlaier				    ("pf: ICMP error message too short "
4891126258Smlaier				    "(ip)\n"));
4892126258Smlaier				return (PF_DROP);
4893126258Smlaier			}
4894126258Smlaier			/*
4895126258Smlaier			 * ICMP error messages don't refer to non-first
4896126258Smlaier			 * fragments
4897126258Smlaier			 */
4898145836Smlaier			if (h2.ip_off & htons(IP_OFFMASK)) {
4899145836Smlaier				REASON_SET(reason, PFRES_FRAG);
4900126258Smlaier				return (PF_DROP);
4901145836Smlaier			}
4902126258Smlaier
4903126258Smlaier			/* offset of protocol header that follows h2 */
4904126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
4905126258Smlaier
4906126258Smlaier			pd2.proto = h2.ip_p;
4907126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
4908126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
4909126258Smlaier			pd2.ip_sum = &h2.ip_sum;
4910126258Smlaier			break;
4911126258Smlaier#endif /* INET */
4912126258Smlaier#ifdef INET6
4913126258Smlaier		case AF_INET6:
4914126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
4915126258Smlaier
4916126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
4917145836Smlaier			    NULL, reason, pd2.af)) {
4918126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4919126258Smlaier				    ("pf: ICMP error message too short "
4920126258Smlaier				    "(ip6)\n"));
4921126258Smlaier				return (PF_DROP);
4922126258Smlaier			}
4923126258Smlaier			pd2.proto = h2_6.ip6_nxt;
4924126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
4925126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
4926126258Smlaier			pd2.ip_sum = NULL;
4927126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
4928126258Smlaier			do {
4929126258Smlaier				switch (pd2.proto) {
4930126258Smlaier				case IPPROTO_FRAGMENT:
4931126258Smlaier					/*
4932126258Smlaier					 * ICMPv6 error messages for
4933126258Smlaier					 * non-first fragments
4934126258Smlaier					 */
4935145836Smlaier					REASON_SET(reason, PFRES_FRAG);
4936126258Smlaier					return (PF_DROP);
4937126258Smlaier				case IPPROTO_AH:
4938126258Smlaier				case IPPROTO_HOPOPTS:
4939126258Smlaier				case IPPROTO_ROUTING:
4940126258Smlaier				case IPPROTO_DSTOPTS: {
4941126258Smlaier					/* get next header and header length */
4942126258Smlaier					struct ip6_ext opt6;
4943126258Smlaier
4944126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
4945145836Smlaier					    sizeof(opt6), NULL, reason,
4946145836Smlaier					    pd2.af)) {
4947126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
4948126258Smlaier						    ("pf: ICMPv6 short opt\n"));
4949126258Smlaier						return (PF_DROP);
4950126258Smlaier					}
4951126258Smlaier					if (pd2.proto == IPPROTO_AH)
4952126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
4953126258Smlaier					else
4954126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
4955126258Smlaier					pd2.proto = opt6.ip6e_nxt;
4956126258Smlaier					/* goto the next header */
4957126258Smlaier					break;
4958126258Smlaier				}
4959126258Smlaier				default:
4960126258Smlaier					terminal++;
4961126258Smlaier					break;
4962126258Smlaier				}
4963126258Smlaier			} while (!terminal);
4964126258Smlaier			break;
4965126258Smlaier#endif /* INET6 */
4966126258Smlaier		}
4967126258Smlaier
4968126258Smlaier		switch (pd2.proto) {
4969126258Smlaier		case IPPROTO_TCP: {
4970126258Smlaier			struct tcphdr		 th;
4971126258Smlaier			u_int32_t		 seq;
4972130613Smlaier			struct pf_state		 key;
4973126258Smlaier			struct pf_state_peer	*src, *dst;
4974126258Smlaier			u_int8_t		 dws;
4975128129Smlaier			int			 copyback = 0;
4976126258Smlaier
4977126258Smlaier			/*
4978126258Smlaier			 * Only the first 8 bytes of the TCP header can be
4979126258Smlaier			 * expected. Don't access any TCP header fields after
4980126258Smlaier			 * th_seq, an ackskew test is not possible.
4981126258Smlaier			 */
4982145836Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
4983145836Smlaier			    pd2.af)) {
4984126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4985126258Smlaier				    ("pf: ICMP error message too short "
4986126258Smlaier				    "(tcp)\n"));
4987126258Smlaier				return (PF_DROP);
4988126258Smlaier			}
4989126258Smlaier
4990126258Smlaier			key.af = pd2.af;
4991126258Smlaier			key.proto = IPPROTO_TCP;
4992130613Smlaier			if (direction == PF_IN)	{
4993130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
4994130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
4995130613Smlaier				key.ext.port = th.th_dport;
4996130613Smlaier				key.gwy.port = th.th_sport;
4997130613Smlaier			} else {
4998130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
4999130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5000130613Smlaier				key.lan.port = th.th_dport;
5001130613Smlaier				key.ext.port = th.th_sport;
5002130613Smlaier			}
5003126258Smlaier
5004126258Smlaier			STATE_LOOKUP();
5005126258Smlaier
5006126258Smlaier			if (direction == (*state)->direction) {
5007126258Smlaier				src = &(*state)->dst;
5008126258Smlaier				dst = &(*state)->src;
5009126258Smlaier			} else {
5010126258Smlaier				src = &(*state)->src;
5011126258Smlaier				dst = &(*state)->dst;
5012126258Smlaier			}
5013126258Smlaier
5014130613Smlaier			if (src->wscale && dst->wscale &&
5015130613Smlaier			    !(th.th_flags & TH_SYN))
5016126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
5017126258Smlaier			else
5018126258Smlaier				dws = 0;
5019126258Smlaier
5020126258Smlaier			/* Demodulate sequence number */
5021126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
5022128129Smlaier			if (src->seqdiff) {
5023128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
5024126258Smlaier				    htonl(seq), 0);
5025128129Smlaier				copyback = 1;
5026128129Smlaier			}
5027126258Smlaier
5028126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
5029126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
5030126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
5031126258Smlaier					printf("pf: BAD ICMP %d:%d ",
5032126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
5033126258Smlaier					pf_print_host(pd->src, 0, pd->af);
5034126258Smlaier					printf(" -> ");
5035126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
5036126258Smlaier					printf(" state: ");
5037126258Smlaier					pf_print_state(*state);
5038126258Smlaier					printf(" seq=%u\n", seq);
5039126258Smlaier				}
5040145836Smlaier				REASON_SET(reason, PFRES_BADSTATE);
5041126258Smlaier				return (PF_DROP);
5042126258Smlaier			}
5043126258Smlaier
5044126258Smlaier			if (STATE_TRANSLATE(*state)) {
5045126258Smlaier				if (direction == PF_IN) {
5046126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
5047128129Smlaier					    daddr, &(*state)->lan.addr,
5048126258Smlaier					    (*state)->lan.port, NULL,
5049126258Smlaier					    pd2.ip_sum, icmpsum,
5050126258Smlaier					    pd->ip_sum, 0, pd2.af);
5051126258Smlaier				} else {
5052126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
5053126258Smlaier					    saddr, &(*state)->gwy.addr,
5054126258Smlaier					    (*state)->gwy.port, NULL,
5055126258Smlaier					    pd2.ip_sum, icmpsum,
5056126258Smlaier					    pd->ip_sum, 0, pd2.af);
5057126258Smlaier				}
5058128129Smlaier				copyback = 1;
5059128129Smlaier			}
5060128129Smlaier
5061128129Smlaier			if (copyback) {
5062126258Smlaier				switch (pd2.af) {
5063126258Smlaier#ifdef INET
5064126258Smlaier				case AF_INET:
5065126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5066126261Smlaier					    (caddr_t)pd->hdr.icmp);
5067126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5068126261Smlaier					    (caddr_t)&h2);
5069126258Smlaier					break;
5070126258Smlaier#endif /* INET */
5071126258Smlaier#ifdef INET6
5072126258Smlaier				case AF_INET6:
5073126258Smlaier					m_copyback(m, off,
5074126258Smlaier					    sizeof(struct icmp6_hdr),
5075126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5076126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5077126261Smlaier					    (caddr_t)&h2_6);
5078126258Smlaier					break;
5079126258Smlaier#endif /* INET6 */
5080126258Smlaier				}
5081126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
5082126258Smlaier			}
5083126258Smlaier
5084126258Smlaier			return (PF_PASS);
5085126258Smlaier			break;
5086126258Smlaier		}
5087126258Smlaier		case IPPROTO_UDP: {
5088126258Smlaier			struct udphdr		uh;
5089130613Smlaier			struct pf_state		key;
5090126258Smlaier
5091126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
5092145836Smlaier			    NULL, reason, pd2.af)) {
5093126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5094126258Smlaier				    ("pf: ICMP error message too short "
5095126258Smlaier				    "(udp)\n"));
5096126258Smlaier				return (PF_DROP);
5097126258Smlaier			}
5098126258Smlaier
5099126258Smlaier			key.af = pd2.af;
5100126258Smlaier			key.proto = IPPROTO_UDP;
5101130613Smlaier			if (direction == PF_IN)	{
5102130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5103130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5104130613Smlaier				key.ext.port = uh.uh_dport;
5105130613Smlaier				key.gwy.port = uh.uh_sport;
5106130613Smlaier			} else {
5107130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5108130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5109130613Smlaier				key.lan.port = uh.uh_dport;
5110130613Smlaier				key.ext.port = uh.uh_sport;
5111130613Smlaier			}
5112126258Smlaier
5113126258Smlaier			STATE_LOOKUP();
5114126258Smlaier
5115126258Smlaier			if (STATE_TRANSLATE(*state)) {
5116126258Smlaier				if (direction == PF_IN) {
5117126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
5118126258Smlaier					    daddr, &(*state)->lan.addr,
5119126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
5120126258Smlaier					    pd2.ip_sum, icmpsum,
5121126258Smlaier					    pd->ip_sum, 1, pd2.af);
5122126258Smlaier				} else {
5123126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
5124126258Smlaier					    saddr, &(*state)->gwy.addr,
5125126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
5126126258Smlaier					    pd2.ip_sum, icmpsum,
5127126258Smlaier					    pd->ip_sum, 1, pd2.af);
5128126258Smlaier				}
5129126258Smlaier				switch (pd2.af) {
5130126258Smlaier#ifdef INET
5131126258Smlaier				case AF_INET:
5132126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5133126261Smlaier					    (caddr_t)pd->hdr.icmp);
5134126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5135126261Smlaier					    (caddr_t)&h2);
5136126258Smlaier					break;
5137126258Smlaier#endif /* INET */
5138126258Smlaier#ifdef INET6
5139126258Smlaier				case AF_INET6:
5140126258Smlaier					m_copyback(m, off,
5141126258Smlaier					    sizeof(struct icmp6_hdr),
5142126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5143126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5144126261Smlaier					    (caddr_t)&h2_6);
5145126258Smlaier					break;
5146126258Smlaier#endif /* INET6 */
5147126258Smlaier				}
5148126261Smlaier				m_copyback(m, off2, sizeof(uh),
5149126261Smlaier				    (caddr_t)&uh);
5150126258Smlaier			}
5151126258Smlaier
5152126258Smlaier			return (PF_PASS);
5153126258Smlaier			break;
5154126258Smlaier		}
5155126258Smlaier#ifdef INET
5156126258Smlaier		case IPPROTO_ICMP: {
5157126258Smlaier			struct icmp		iih;
5158130613Smlaier			struct pf_state		key;
5159126258Smlaier
5160126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
5161145836Smlaier			    NULL, reason, pd2.af)) {
5162126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5163126258Smlaier				    ("pf: ICMP error message too short i"
5164126258Smlaier				    "(icmp)\n"));
5165126258Smlaier				return (PF_DROP);
5166126258Smlaier			}
5167126258Smlaier
5168126258Smlaier			key.af = pd2.af;
5169126258Smlaier			key.proto = IPPROTO_ICMP;
5170130613Smlaier			if (direction == PF_IN)	{
5171130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5172130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5173130613Smlaier				key.ext.port = iih.icmp_id;
5174130613Smlaier				key.gwy.port = iih.icmp_id;
5175130613Smlaier			} else {
5176130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5177130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5178130613Smlaier				key.lan.port = iih.icmp_id;
5179130613Smlaier				key.ext.port = iih.icmp_id;
5180130613Smlaier			}
5181126258Smlaier
5182126258Smlaier			STATE_LOOKUP();
5183126258Smlaier
5184126258Smlaier			if (STATE_TRANSLATE(*state)) {
5185126258Smlaier				if (direction == PF_IN) {
5186126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
5187126258Smlaier					    daddr, &(*state)->lan.addr,
5188126258Smlaier					    (*state)->lan.port, NULL,
5189126258Smlaier					    pd2.ip_sum, icmpsum,
5190126258Smlaier					    pd->ip_sum, 0, AF_INET);
5191126258Smlaier				} else {
5192126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
5193126258Smlaier					    saddr, &(*state)->gwy.addr,
5194126258Smlaier					    (*state)->gwy.port, NULL,
5195126258Smlaier					    pd2.ip_sum, icmpsum,
5196126258Smlaier					    pd->ip_sum, 0, AF_INET);
5197126258Smlaier				}
5198126261Smlaier				m_copyback(m, off, ICMP_MINLEN,
5199126261Smlaier				    (caddr_t)pd->hdr.icmp);
5200126261Smlaier				m_copyback(m, ipoff2, sizeof(h2),
5201126261Smlaier				    (caddr_t)&h2);
5202126261Smlaier				m_copyback(m, off2, ICMP_MINLEN,
5203126261Smlaier				    (caddr_t)&iih);
5204126258Smlaier			}
5205126258Smlaier
5206126258Smlaier			return (PF_PASS);
5207126258Smlaier			break;
5208126258Smlaier		}
5209126258Smlaier#endif /* INET */
5210126258Smlaier#ifdef INET6
5211126258Smlaier		case IPPROTO_ICMPV6: {
5212126258Smlaier			struct icmp6_hdr	iih;
5213130613Smlaier			struct pf_state		key;
5214126258Smlaier
5215126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
5216145836Smlaier			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
5217126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5218126258Smlaier				    ("pf: ICMP error message too short "
5219126258Smlaier				    "(icmp6)\n"));
5220126258Smlaier				return (PF_DROP);
5221126258Smlaier			}
5222126258Smlaier
5223126258Smlaier			key.af = pd2.af;
5224126258Smlaier			key.proto = IPPROTO_ICMPV6;
5225130613Smlaier			if (direction == PF_IN)	{
5226130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5227130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5228130613Smlaier				key.ext.port = iih.icmp6_id;
5229130613Smlaier				key.gwy.port = iih.icmp6_id;
5230130613Smlaier			} else {
5231130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5232130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5233130613Smlaier				key.lan.port = iih.icmp6_id;
5234130613Smlaier				key.ext.port = iih.icmp6_id;
5235130613Smlaier			}
5236126258Smlaier
5237126258Smlaier			STATE_LOOKUP();
5238126258Smlaier
5239126258Smlaier			if (STATE_TRANSLATE(*state)) {
5240126258Smlaier				if (direction == PF_IN) {
5241126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
5242126258Smlaier					    daddr, &(*state)->lan.addr,
5243126258Smlaier					    (*state)->lan.port, NULL,
5244126258Smlaier					    pd2.ip_sum, icmpsum,
5245126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5246126258Smlaier				} else {
5247126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
5248126258Smlaier					    saddr, &(*state)->gwy.addr,
5249126258Smlaier					    (*state)->gwy.port, NULL,
5250126258Smlaier					    pd2.ip_sum, icmpsum,
5251126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5252126258Smlaier				}
5253126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
5254126261Smlaier				    (caddr_t)pd->hdr.icmp6);
5255126261Smlaier				m_copyback(m, ipoff2, sizeof(h2_6),
5256126261Smlaier				    (caddr_t)&h2_6);
5257126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5258126261Smlaier				    (caddr_t)&iih);
5259126258Smlaier			}
5260126258Smlaier
5261126258Smlaier			return (PF_PASS);
5262126258Smlaier			break;
5263126258Smlaier		}
5264126258Smlaier#endif /* INET6 */
5265126258Smlaier		default: {
5266130613Smlaier			struct pf_state		key;
5267126258Smlaier
5268126258Smlaier			key.af = pd2.af;
5269126258Smlaier			key.proto = pd2.proto;
5270130613Smlaier			if (direction == PF_IN)	{
5271130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5272130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5273130613Smlaier				key.ext.port = 0;
5274130613Smlaier				key.gwy.port = 0;
5275130613Smlaier			} else {
5276130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5277130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5278130613Smlaier				key.lan.port = 0;
5279130613Smlaier				key.ext.port = 0;
5280130613Smlaier			}
5281126258Smlaier
5282126258Smlaier			STATE_LOOKUP();
5283126258Smlaier
5284126258Smlaier			if (STATE_TRANSLATE(*state)) {
5285126258Smlaier				if (direction == PF_IN) {
5286126258Smlaier					pf_change_icmp(pd2.src, NULL,
5287126258Smlaier					    daddr, &(*state)->lan.addr,
5288126258Smlaier					    0, NULL,
5289126258Smlaier					    pd2.ip_sum, icmpsum,
5290126258Smlaier					    pd->ip_sum, 0, pd2.af);
5291126258Smlaier				} else {
5292126258Smlaier					pf_change_icmp(pd2.dst, NULL,
5293126258Smlaier					    saddr, &(*state)->gwy.addr,
5294126258Smlaier					    0, NULL,
5295126258Smlaier					    pd2.ip_sum, icmpsum,
5296126258Smlaier					    pd->ip_sum, 0, pd2.af);
5297126258Smlaier				}
5298126258Smlaier				switch (pd2.af) {
5299126258Smlaier#ifdef INET
5300126258Smlaier				case AF_INET:
5301126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5302126261Smlaier					    (caddr_t)pd->hdr.icmp);
5303126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5304126261Smlaier					    (caddr_t)&h2);
5305126258Smlaier					break;
5306126258Smlaier#endif /* INET */
5307126258Smlaier#ifdef INET6
5308126258Smlaier				case AF_INET6:
5309126258Smlaier					m_copyback(m, off,
5310126258Smlaier					    sizeof(struct icmp6_hdr),
5311126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5312126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5313126261Smlaier					    (caddr_t)&h2_6);
5314126258Smlaier					break;
5315126258Smlaier#endif /* INET6 */
5316126258Smlaier				}
5317126258Smlaier			}
5318126258Smlaier
5319126258Smlaier			return (PF_PASS);
5320126258Smlaier			break;
5321126258Smlaier		}
5322126258Smlaier		}
5323126258Smlaier	}
5324126258Smlaier}
5325126258Smlaier
5326126258Smlaierint
5327130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5328126258Smlaier    struct pf_pdesc *pd)
5329126258Smlaier{
5330126258Smlaier	struct pf_state_peer	*src, *dst;
5331130613Smlaier	struct pf_state		 key;
5332126258Smlaier
5333126258Smlaier	key.af = pd->af;
5334126258Smlaier	key.proto = pd->proto;
5335130613Smlaier	if (direction == PF_IN)	{
5336130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5337130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5338130613Smlaier		key.ext.port = 0;
5339130613Smlaier		key.gwy.port = 0;
5340130613Smlaier	} else {
5341130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5342130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5343130613Smlaier		key.lan.port = 0;
5344130613Smlaier		key.ext.port = 0;
5345130613Smlaier	}
5346126258Smlaier
5347126258Smlaier	STATE_LOOKUP();
5348126258Smlaier
5349126258Smlaier	if (direction == (*state)->direction) {
5350126258Smlaier		src = &(*state)->src;
5351126258Smlaier		dst = &(*state)->dst;
5352126258Smlaier	} else {
5353126258Smlaier		src = &(*state)->dst;
5354126258Smlaier		dst = &(*state)->src;
5355126258Smlaier	}
5356126258Smlaier
5357126258Smlaier	/* update states */
5358126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5359126258Smlaier		src->state = PFOTHERS_SINGLE;
5360126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5361126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5362126258Smlaier
5363126258Smlaier	/* update expire time */
5364126261Smlaier	(*state)->expire = time_second;
5365126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5366126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5367126258Smlaier	else
5368126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5369126258Smlaier
5370126258Smlaier	/* translate source/destination address, if necessary */
5371126258Smlaier	if (STATE_TRANSLATE(*state)) {
5372126258Smlaier		if (direction == PF_OUT)
5373126258Smlaier			switch (pd->af) {
5374126258Smlaier#ifdef INET
5375126258Smlaier			case AF_INET:
5376126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5377126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
5378126258Smlaier				    0);
5379126258Smlaier				break;
5380126258Smlaier#endif /* INET */
5381126258Smlaier#ifdef INET6
5382126258Smlaier			case AF_INET6:
5383126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
5384126258Smlaier				break;
5385126258Smlaier#endif /* INET6 */
5386126258Smlaier			}
5387126258Smlaier		else
5388126258Smlaier			switch (pd->af) {
5389126258Smlaier#ifdef INET
5390126258Smlaier			case AF_INET:
5391126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5392126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
5393126258Smlaier				    0);
5394126258Smlaier				break;
5395126258Smlaier#endif /* INET */
5396126258Smlaier#ifdef INET6
5397126258Smlaier			case AF_INET6:
5398126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
5399126258Smlaier				break;
5400126258Smlaier#endif /* INET6 */
5401126258Smlaier			}
5402126258Smlaier	}
5403126258Smlaier
5404126258Smlaier	return (PF_PASS);
5405126258Smlaier}
5406126258Smlaier
5407126258Smlaier/*
5408126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5409126258Smlaier * h must be at "ipoff" on the mbuf chain.
5410126258Smlaier */
5411126258Smlaiervoid *
5412126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5413126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5414126258Smlaier{
5415126258Smlaier	switch (af) {
5416126258Smlaier#ifdef INET
5417126258Smlaier	case AF_INET: {
5418126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5419126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5420126258Smlaier
5421126258Smlaier		if (fragoff) {
5422126258Smlaier			if (fragoff >= len)
5423126258Smlaier				ACTION_SET(actionp, PF_PASS);
5424126258Smlaier			else {
5425126258Smlaier				ACTION_SET(actionp, PF_DROP);
5426126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5427126258Smlaier			}
5428126258Smlaier			return (NULL);
5429126258Smlaier		}
5430130613Smlaier		if (m->m_pkthdr.len < off + len ||
5431130613Smlaier		    ntohs(h->ip_len) < off + len) {
5432126258Smlaier			ACTION_SET(actionp, PF_DROP);
5433126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5434126258Smlaier			return (NULL);
5435126258Smlaier		}
5436126258Smlaier		break;
5437126258Smlaier	}
5438126258Smlaier#endif /* INET */
5439126258Smlaier#ifdef INET6
5440126258Smlaier	case AF_INET6: {
5441126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5442126258Smlaier
5443126258Smlaier		if (m->m_pkthdr.len < off + len ||
5444126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5445126258Smlaier		    (unsigned)(off + len)) {
5446126258Smlaier			ACTION_SET(actionp, PF_DROP);
5447126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5448126258Smlaier			return (NULL);
5449126258Smlaier		}
5450126258Smlaier		break;
5451126258Smlaier	}
5452126258Smlaier#endif /* INET6 */
5453126258Smlaier	}
5454126258Smlaier	m_copydata(m, off, len, p);
5455126258Smlaier	return (p);
5456126258Smlaier}
5457126258Smlaier
5458126258Smlaierint
5459126258Smlaierpf_routable(struct pf_addr *addr, sa_family_t af)
5460126258Smlaier{
5461126258Smlaier	struct sockaddr_in	*dst;
5462145836Smlaier#ifdef INET6
5463145836Smlaier	struct sockaddr_in6	*dst6;
5464145836Smlaier	struct route_in6	 ro;
5465145836Smlaier#else
5466126258Smlaier	struct route		 ro;
5467145836Smlaier#endif
5468126258Smlaier
5469126258Smlaier	bzero(&ro, sizeof(ro));
5470145836Smlaier	switch (af) {
5471145836Smlaier	case AF_INET:
5472145836Smlaier		dst = satosin(&ro.ro_dst);
5473145836Smlaier		dst->sin_family = AF_INET;
5474145836Smlaier		dst->sin_len = sizeof(*dst);
5475145836Smlaier		dst->sin_addr = addr->v4;
5476145836Smlaier		break;
5477145836Smlaier#ifdef INET6
5478145836Smlaier	case AF_INET6:
5479145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5480145836Smlaier		dst6->sin6_family = AF_INET6;
5481145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5482145836Smlaier		dst6->sin6_addr = addr->v6;
5483145836Smlaier		break;
5484145836Smlaier#endif /* INET6 */
5485145836Smlaier	default:
5486145836Smlaier		return (0);
5487145836Smlaier	}
5488145836Smlaier
5489127145Smlaier#ifdef __FreeBSD__
5490126261Smlaier#ifdef RTF_PRCLONING
5491145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING));
5492126261Smlaier#else /* !RTF_PRCLONING */
5493145836Smlaier	rtalloc_ign((struct route *)&ro, RTF_CLONING);
5494126261Smlaier#endif
5495126261Smlaier#else /* ! __FreeBSD__ */
5496145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5497126261Smlaier#endif
5498126258Smlaier
5499126258Smlaier	if (ro.ro_rt != NULL) {
5500126258Smlaier		RTFREE(ro.ro_rt);
5501145836Smlaier		return (1);
5502126258Smlaier	}
5503126258Smlaier
5504145836Smlaier	return (0);
5505145836Smlaier}
5506145836Smlaier
5507145836Smlaierint
5508145836Smlaierpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
5509145836Smlaier{
5510145836Smlaier	struct sockaddr_in	*dst;
5511145836Smlaier#ifdef INET6
5512145836Smlaier	struct sockaddr_in6	*dst6;
5513145836Smlaier	struct route_in6	 ro;
5514145836Smlaier#else
5515145836Smlaier	struct route		 ro;
5516145836Smlaier#endif
5517145836Smlaier	int			 ret = 0;
5518145836Smlaier
5519145836Smlaier	bzero(&ro, sizeof(ro));
5520145836Smlaier	switch (af) {
5521145836Smlaier	case AF_INET:
5522145836Smlaier		dst = satosin(&ro.ro_dst);
5523145836Smlaier		dst->sin_family = AF_INET;
5524145836Smlaier		dst->sin_len = sizeof(*dst);
5525145836Smlaier		dst->sin_addr = addr->v4;
5526145836Smlaier		break;
5527145836Smlaier#ifdef INET6
5528145836Smlaier	case AF_INET6:
5529145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5530145836Smlaier		dst6->sin6_family = AF_INET6;
5531145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5532145836Smlaier		dst6->sin6_addr = addr->v6;
5533145836Smlaier		break;
5534145836Smlaier#endif /* INET6 */
5535145836Smlaier	default:
5536145836Smlaier		return (0);
5537145836Smlaier	}
5538145836Smlaier
5539145836Smlaier#ifdef __FreeBSD__
5540145836Smlaier# ifdef RTF_PRCLONING
5541145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
5542145836Smlaier# else /* !RTF_PRCLONING */
5543145836Smlaier	rtalloc_ign((struct route *)&ro, RTF_CLONING);
5544145836Smlaier# endif
5545145836Smlaier#else /* ! __FreeBSD__ */
5546145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5547145836Smlaier#endif
5548145836Smlaier
5549145836Smlaier	if (ro.ro_rt != NULL) {
5550145836Smlaier#ifdef __FreeBSD__
5551145836Smlaier		/* XXX_IMPORT: later */
5552145836Smlaier#else
5553145836Smlaier		if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
5554145836Smlaier			ret = 1;
5555145836Smlaier#endif
5556145836Smlaier		RTFREE(ro.ro_rt);
5557145836Smlaier	}
5558145836Smlaier
5559126258Smlaier	return (ret);
5560126258Smlaier}
5561126258Smlaier
5562126258Smlaier#ifdef INET
5563126261Smlaier
5564126258Smlaiervoid
5565126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5566126258Smlaier    struct pf_state *s)
5567126258Smlaier{
5568126258Smlaier	struct mbuf		*m0, *m1;
5569132303Smlaier	struct m_tag		*mtag;
5570126258Smlaier	struct route		 iproute;
5571127629Smlaier	struct route		*ro = NULL;	/* XXX: was uninitialized */
5572126258Smlaier	struct sockaddr_in	*dst;
5573126258Smlaier	struct ip		*ip;
5574126258Smlaier	struct ifnet		*ifp = NULL;
5575126258Smlaier	struct pf_addr		 naddr;
5576130613Smlaier	struct pf_src_node	*sn = NULL;
5577126258Smlaier	int			 error = 0;
5578127145Smlaier#ifdef __FreeBSD__
5579126261Smlaier	int sw_csum;
5580126261Smlaier#endif
5581126258Smlaier
5582126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5583126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5584126258Smlaier		panic("pf_route: invalid parameters");
5585126258Smlaier
5586132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
5587132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
5588132303Smlaier		    NULL) {
5589132303Smlaier			m0 = *m;
5590132303Smlaier			*m = NULL;
5591132303Smlaier			goto bad;
5592132303Smlaier		}
5593132303Smlaier		*(char *)(mtag + 1) = 1;
5594132303Smlaier		m_tag_prepend(*m, mtag);
5595132303Smlaier	} else {
5596132303Smlaier		if (*(char *)(mtag + 1) > 3) {
5597132303Smlaier			m0 = *m;
5598132303Smlaier			*m = NULL;
5599132303Smlaier			goto bad;
5600132303Smlaier		}
5601132303Smlaier		(*(char *)(mtag + 1))++;
5602132303Smlaier	}
5603132303Smlaier
5604126258Smlaier	if (r->rt == PF_DUPTO) {
5605127145Smlaier#ifdef __FreeBSD__
5606132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5607126261Smlaier#else
5608132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5609126261Smlaier#endif
5610126258Smlaier			return;
5611126258Smlaier	} else {
5612126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5613126258Smlaier			return;
5614126258Smlaier		m0 = *m;
5615126258Smlaier	}
5616126258Smlaier
5617145836Smlaier	if (m0->m_len < sizeof(struct ip)) {
5618145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
5619145836Smlaier		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
5620145836Smlaier		goto bad;
5621145836Smlaier	}
5622145836Smlaier
5623126258Smlaier	ip = mtod(m0, struct ip *);
5624126258Smlaier
5625126258Smlaier	ro = &iproute;
5626126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5627126258Smlaier	dst = satosin(&ro->ro_dst);
5628126258Smlaier	dst->sin_family = AF_INET;
5629126258Smlaier	dst->sin_len = sizeof(*dst);
5630126258Smlaier	dst->sin_addr = ip->ip_dst;
5631126258Smlaier
5632126258Smlaier	if (r->rt == PF_FASTROUTE) {
5633126258Smlaier		rtalloc(ro);
5634126258Smlaier		if (ro->ro_rt == 0) {
5635126258Smlaier			ipstat.ips_noroute++;
5636126258Smlaier			goto bad;
5637126258Smlaier		}
5638126258Smlaier
5639126258Smlaier		ifp = ro->ro_rt->rt_ifp;
5640126258Smlaier		ro->ro_rt->rt_use++;
5641126258Smlaier
5642126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
5643126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
5644126258Smlaier	} else {
5645145836Smlaier		if (TAILQ_EMPTY(&r->rpool.list)) {
5646145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
5647145836Smlaier			    ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
5648145836Smlaier			goto bad;
5649145836Smlaier		}
5650126258Smlaier		if (s == NULL) {
5651130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
5652130613Smlaier			    &naddr, NULL, &sn);
5653126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
5654126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
5655130613Smlaier			ifp = r->rpool.cur->kif ?
5656130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
5657126258Smlaier		} else {
5658126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
5659126258Smlaier				dst->sin_addr.s_addr =
5660126258Smlaier				    s->rt_addr.v4.s_addr;
5661130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
5662126258Smlaier		}
5663126258Smlaier	}
5664126258Smlaier	if (ifp == NULL)
5665126258Smlaier		goto bad;
5666126258Smlaier
5667130639Smlaier	if (oifp != ifp) {
5668127145Smlaier#ifdef __FreeBSD__
5669126261Smlaier		PF_UNLOCK();
5670145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
5671126261Smlaier			PF_LOCK();
5672126261Smlaier			goto bad;
5673126261Smlaier		} else if (m0 == NULL) {
5674126261Smlaier			PF_LOCK();
5675126261Smlaier			goto done;
5676126261Smlaier		}
5677126261Smlaier		PF_LOCK();
5678126261Smlaier#else
5679145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
5680126258Smlaier			goto bad;
5681126258Smlaier		else if (m0 == NULL)
5682126258Smlaier			goto done;
5683126261Smlaier#endif
5684145836Smlaier		if (m0->m_len < sizeof(struct ip)) {
5685145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
5686145836Smlaier			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
5687145836Smlaier			goto bad;
5688145836Smlaier		}
5689126258Smlaier		ip = mtod(m0, struct ip *);
5690126258Smlaier	}
5691126258Smlaier
5692127145Smlaier#ifdef __FreeBSD__
5693126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
5694126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
5695126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
5696126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
5697126261Smlaier		/*
5698126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
5699126261Smlaier		 */
5700126261Smlaier		NTOHS(ip->ip_len);
5701126261Smlaier		NTOHS(ip->ip_off);	 /* XXX: needed? */
5702126261Smlaier		in_delayed_cksum(m0);
5703126261Smlaier		HTONS(ip->ip_len);
5704126261Smlaier		HTONS(ip->ip_off);
5705126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
5706126261Smlaier	}
5707126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
5708126261Smlaier
5709126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
5710126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
5711126261Smlaier		((ip->ip_off & htons(IP_DF)) == 0))) {
5712126261Smlaier		/*
5713126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
5714126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
5715126261Smlaier		 */
5716126261Smlaier		ip->ip_sum = 0;
5717126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
5718126261Smlaier			/* From KAME */
5719126261Smlaier			if (ip->ip_v == IPVERSION &&
5720126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
5721126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
5722126261Smlaier			} else {
5723126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5724126261Smlaier			}
5725126261Smlaier		}
5726126261Smlaier		PF_UNLOCK();
5727126261Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
5728126261Smlaier		PF_LOCK();
5729126261Smlaier		goto done;
5730126261Smlaier	}
5731126261Smlaier
5732126261Smlaier#else
5733126258Smlaier	/* Copied from ip_output. */
5734130613Smlaier#ifdef IPSEC
5735130613Smlaier	/*
5736130613Smlaier	 * If deferred crypto processing is needed, check that the
5737130613Smlaier	 * interface supports it.
5738130613Smlaier	 */
5739130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
5740130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
5741130613Smlaier		/* Notify IPsec to do its own crypto. */
5742130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
5743130613Smlaier		goto bad;
5744130613Smlaier	}
5745130613Smlaier#endif /* IPSEC */
5746130613Smlaier
5747130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
5748130613Smlaier	if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) {
5749130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
5750130613Smlaier		    ifp->if_bridge != NULL) {
5751130613Smlaier			in_delayed_cksum(m0);
5752130613Smlaier			m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
5753130613Smlaier		}
5754130613Smlaier	} else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) {
5755130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
5756130613Smlaier		    ifp->if_bridge != NULL) {
5757130613Smlaier			in_delayed_cksum(m0);
5758130613Smlaier			m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
5759130613Smlaier		}
5760130613Smlaier	}
5761130613Smlaier
5762126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
5763126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
5764126258Smlaier		    ifp->if_bridge == NULL) {
5765126258Smlaier			m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT;
5766126258Smlaier			ipstat.ips_outhwcsum++;
5767126258Smlaier		} else {
5768126258Smlaier			ip->ip_sum = 0;
5769126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5770126258Smlaier		}
5771126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
5772126258Smlaier		if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
5773126258Smlaier			tcpstat.tcps_outhwcsum++;
5774126258Smlaier		else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
5775126258Smlaier			udpstat.udps_outhwcsum++;
5776126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
5777126258Smlaier		goto done;
5778126258Smlaier	}
5779126261Smlaier#endif
5780126258Smlaier	/*
5781126258Smlaier	 * Too large for interface; fragment if possible.
5782126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
5783126258Smlaier	 */
5784126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
5785126258Smlaier		ipstat.ips_cantfrag++;
5786126258Smlaier		if (r->rt != PF_DUPTO) {
5787127145Smlaier#ifdef __FreeBSD__
5788126261Smlaier			/* icmp_error() expects host byte ordering */
5789126261Smlaier			NTOHS(ip->ip_len);
5790126261Smlaier			NTOHS(ip->ip_off);
5791126261Smlaier			PF_UNLOCK();
5792126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
5793145886Smlaier			    ifp->if_mtu);
5794145874Smlaier			PF_LOCK();
5795145874Smlaier#else
5796145874Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
5797145873Smlaier			    ifp);
5798126261Smlaier#endif
5799126258Smlaier			goto done;
5800126258Smlaier		} else
5801126258Smlaier			goto bad;
5802126258Smlaier	}
5803126258Smlaier
5804126258Smlaier	m1 = m0;
5805127145Smlaier#ifdef __FreeBSD__
5806126261Smlaier	/*
5807126261Smlaier	 * XXX: is cheaper + less error prone than own function
5808126261Smlaier	 */
5809126261Smlaier	NTOHS(ip->ip_len);
5810126261Smlaier	NTOHS(ip->ip_off);
5811126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
5812126261Smlaier#else
5813126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
5814126261Smlaier#endif
5815127531Smlaier	if (error) {
5816127531Smlaier#ifndef __FreeBSD__	/* ip_fragment does not do m_freem() on FreeBSD */
5817127531Smlaier		m0 = NULL;
5818126261Smlaier#endif
5819126258Smlaier		goto bad;
5820127531Smlaier	}
5821126258Smlaier
5822126258Smlaier	for (m0 = m1; m0; m0 = m1) {
5823126258Smlaier		m1 = m0->m_nextpkt;
5824126258Smlaier		m0->m_nextpkt = 0;
5825127145Smlaier#ifdef __FreeBSD__
5826126261Smlaier		if (error == 0) {
5827126261Smlaier			PF_UNLOCK();
5828126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5829126261Smlaier			    NULL);
5830126261Smlaier			PF_LOCK();
5831126261Smlaier		} else
5832126261Smlaier#else
5833126258Smlaier		if (error == 0)
5834126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5835126258Smlaier			    NULL);
5836126258Smlaier		else
5837126261Smlaier#endif
5838126258Smlaier			m_freem(m0);
5839126258Smlaier	}
5840126258Smlaier
5841126258Smlaier	if (error == 0)
5842126258Smlaier		ipstat.ips_fragmented++;
5843126258Smlaier
5844126258Smlaierdone:
5845126258Smlaier	if (r->rt != PF_DUPTO)
5846126258Smlaier		*m = NULL;
5847126258Smlaier	if (ro == &iproute && ro->ro_rt)
5848126258Smlaier		RTFREE(ro->ro_rt);
5849126258Smlaier	return;
5850126258Smlaier
5851126258Smlaierbad:
5852126258Smlaier	m_freem(m0);
5853126258Smlaier	goto done;
5854126258Smlaier}
5855126258Smlaier#endif /* INET */
5856126258Smlaier
5857126258Smlaier#ifdef INET6
5858126258Smlaiervoid
5859126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5860126258Smlaier    struct pf_state *s)
5861126258Smlaier{
5862126258Smlaier	struct mbuf		*m0;
5863126258Smlaier	struct m_tag		*mtag;
5864126258Smlaier	struct route_in6	 ip6route;
5865126258Smlaier	struct route_in6	*ro;
5866126258Smlaier	struct sockaddr_in6	*dst;
5867126258Smlaier	struct ip6_hdr		*ip6;
5868126258Smlaier	struct ifnet		*ifp = NULL;
5869126258Smlaier	struct pf_addr		 naddr;
5870130613Smlaier	struct pf_src_node	*sn = NULL;
5871126258Smlaier	int			 error = 0;
5872126258Smlaier
5873126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5874126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5875126258Smlaier		panic("pf_route6: invalid parameters");
5876126258Smlaier
5877132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
5878132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
5879132303Smlaier		    NULL) {
5880132303Smlaier			m0 = *m;
5881132303Smlaier			*m = NULL;
5882132303Smlaier			goto bad;
5883132303Smlaier		}
5884132303Smlaier		*(char *)(mtag + 1) = 1;
5885132303Smlaier		m_tag_prepend(*m, mtag);
5886132303Smlaier	} else {
5887132303Smlaier		if (*(char *)(mtag + 1) > 3) {
5888132303Smlaier			m0 = *m;
5889132303Smlaier			*m = NULL;
5890132303Smlaier			goto bad;
5891132303Smlaier		}
5892132303Smlaier		(*(char *)(mtag + 1))++;
5893132303Smlaier	}
5894132303Smlaier
5895126258Smlaier	if (r->rt == PF_DUPTO) {
5896127145Smlaier#ifdef __FreeBSD__
5897132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5898126261Smlaier#else
5899132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5900126261Smlaier#endif
5901126258Smlaier			return;
5902126258Smlaier	} else {
5903126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5904126258Smlaier			return;
5905126258Smlaier		m0 = *m;
5906126258Smlaier	}
5907126258Smlaier
5908145836Smlaier	if (m0->m_len < sizeof(struct ip6_hdr)) {
5909145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
5910145836Smlaier		    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
5911145836Smlaier		goto bad;
5912145836Smlaier	}
5913126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
5914126258Smlaier
5915126258Smlaier	ro = &ip6route;
5916126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5917126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
5918126258Smlaier	dst->sin6_family = AF_INET6;
5919126258Smlaier	dst->sin6_len = sizeof(*dst);
5920126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
5921126258Smlaier
5922126258Smlaier	/* Cheat. */
5923126258Smlaier	if (r->rt == PF_FASTROUTE) {
5924127145Smlaier#ifdef __FreeBSD__
5925132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
5926126261Smlaier		PF_UNLOCK();
5927126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
5928126261Smlaier		PF_LOCK();
5929126261Smlaier#else
5930132280Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
5931132280Smlaier		if (mtag == NULL)
5932132280Smlaier			goto bad;
5933132280Smlaier		m_tag_prepend(m0, mtag);
5934126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
5935126261Smlaier#endif
5936126258Smlaier		return;
5937126258Smlaier	}
5938126258Smlaier
5939145836Smlaier	if (TAILQ_EMPTY(&r->rpool.list)) {
5940145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
5941145836Smlaier		    ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
5942145836Smlaier		goto bad;
5943145836Smlaier	}
5944126258Smlaier	if (s == NULL) {
5945130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
5946130613Smlaier		    &naddr, NULL, &sn);
5947126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
5948126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
5949126258Smlaier			    &naddr, AF_INET6);
5950130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
5951126258Smlaier	} else {
5952126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
5953126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
5954126258Smlaier			    &s->rt_addr, AF_INET6);
5955130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
5956126258Smlaier	}
5957126258Smlaier	if (ifp == NULL)
5958126258Smlaier		goto bad;
5959126258Smlaier
5960126258Smlaier	if (oifp != ifp) {
5961127145Smlaier#ifdef __FreeBSD__
5962132303Smlaier		PF_UNLOCK();
5963145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
5964126261Smlaier			PF_LOCK();
5965132303Smlaier			goto bad;
5966132303Smlaier		} else if (m0 == NULL) {
5967132303Smlaier			PF_LOCK();
5968132303Smlaier			goto done;
5969132303Smlaier		}
5970132303Smlaier		PF_LOCK();
5971126261Smlaier#else
5972145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
5973132303Smlaier			goto bad;
5974132303Smlaier		else if (m0 == NULL)
5975132303Smlaier			goto done;
5976126261Smlaier#endif
5977145836Smlaier		if (m0->m_len < sizeof(struct ip6_hdr)) {
5978145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
5979145836Smlaier			    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
5980145836Smlaier			goto bad;
5981145836Smlaier		}
5982132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
5983126258Smlaier	}
5984126258Smlaier
5985126258Smlaier	/*
5986126258Smlaier	 * If the packet is too large for the outgoing interface,
5987126258Smlaier	 * send back an icmp6 error.
5988126258Smlaier	 */
5989126258Smlaier	if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
5990126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
5991126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
5992127145Smlaier#ifdef __FreeBSD__
5993126261Smlaier		PF_UNLOCK();
5994126261Smlaier#endif
5995126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
5996127145Smlaier#ifdef __FreeBSD__
5997126261Smlaier		PF_LOCK();
5998126261Smlaier#endif
5999126258Smlaier	} else {
6000126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
6001127145Smlaier#ifdef __FreeBSD__
6002126261Smlaier		if (r->rt != PF_DUPTO) {
6003126261Smlaier			PF_UNLOCK();
6004126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6005126261Smlaier			PF_LOCK();
6006126261Smlaier		 } else
6007126261Smlaier#else
6008126258Smlaier		if (r->rt != PF_DUPTO)
6009126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6010126258Smlaier		else
6011126261Smlaier#endif
6012126258Smlaier			goto bad;
6013126258Smlaier	}
6014126258Smlaier
6015126258Smlaierdone:
6016126258Smlaier	if (r->rt != PF_DUPTO)
6017126258Smlaier		*m = NULL;
6018126258Smlaier	return;
6019126258Smlaier
6020126258Smlaierbad:
6021126258Smlaier	m_freem(m0);
6022126258Smlaier	goto done;
6023126258Smlaier}
6024126258Smlaier#endif /* INET6 */
6025126258Smlaier
6026126258Smlaier
6027127145Smlaier#ifdef __FreeBSD__
6028126258Smlaier/*
6029132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
6030137413Sru *  em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
6031132566Smlaier *   ti(4), txp(4), xl(4)
6032132566Smlaier *
6033132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
6034132566Smlaier *  network driver performed cksum including pseudo header, need to verify
6035132566Smlaier *   csum_data
6036132566Smlaier * CSUM_DATA_VALID :
6037132566Smlaier *  network driver performed cksum, needs to additional pseudo header
6038132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
6039132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
6040132566Smlaier *
6041132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
6042132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
6043132566Smlaier * TCP/UDP layer.
6044132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
6045126261Smlaier */
6046126261Smlaierint
6047126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
6048126261Smlaier{
6049126261Smlaier	u_int16_t sum = 0;
6050126261Smlaier	int hw_assist = 0;
6051126261Smlaier	struct ip *ip;
6052126261Smlaier
6053126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6054126261Smlaier		return (1);
6055126261Smlaier	if (m->m_pkthdr.len < off + len)
6056126261Smlaier		return (1);
6057126261Smlaier
6058126261Smlaier	switch (p) {
6059126261Smlaier	case IPPROTO_TCP:
6060126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6061126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6062126261Smlaier				sum = m->m_pkthdr.csum_data;
6063126261Smlaier			} else {
6064126261Smlaier				ip = mtod(m, struct ip *);
6065126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6066135078Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6067135078Smlaier					m->m_pkthdr.csum_data + IPPROTO_TCP));
6068126261Smlaier			}
6069126261Smlaier			sum ^= 0xffff;
6070126261Smlaier			++hw_assist;
6071126261Smlaier		}
6072126261Smlaier		break;
6073126261Smlaier	case IPPROTO_UDP:
6074126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6075126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6076126261Smlaier				sum = m->m_pkthdr.csum_data;
6077126261Smlaier			} else {
6078126261Smlaier				ip = mtod(m, struct ip *);
6079126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6080126261Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6081126261Smlaier					m->m_pkthdr.csum_data + IPPROTO_UDP));
6082126261Smlaier			}
6083126261Smlaier			sum ^= 0xffff;
6084126261Smlaier			++hw_assist;
6085126261Smlaier                }
6086126261Smlaier		break;
6087126261Smlaier	case IPPROTO_ICMP:
6088126261Smlaier#ifdef INET6
6089126261Smlaier	case IPPROTO_ICMPV6:
6090126261Smlaier#endif /* INET6 */
6091126261Smlaier		break;
6092126261Smlaier	default:
6093126261Smlaier		return (1);
6094126261Smlaier	}
6095126261Smlaier
6096126261Smlaier	if (!hw_assist) {
6097126261Smlaier		switch (af) {
6098126261Smlaier		case AF_INET:
6099126261Smlaier			if (p == IPPROTO_ICMP) {
6100126261Smlaier				if (m->m_len < off)
6101126261Smlaier					return (1);
6102126261Smlaier				m->m_data += off;
6103126261Smlaier				m->m_len -= off;
6104126261Smlaier				sum = in_cksum(m, len);
6105126261Smlaier				m->m_data -= off;
6106126261Smlaier				m->m_len += off;
6107126261Smlaier			} else {
6108126261Smlaier				if (m->m_len < sizeof(struct ip))
6109126261Smlaier					return (1);
6110126261Smlaier				sum = in4_cksum(m, p, off, len);
6111126261Smlaier			}
6112126261Smlaier			break;
6113126261Smlaier#ifdef INET6
6114126261Smlaier		case AF_INET6:
6115126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
6116126261Smlaier				return (1);
6117126261Smlaier			sum = in6_cksum(m, p, off, len);
6118126261Smlaier			break;
6119126261Smlaier#endif /* INET6 */
6120126261Smlaier		default:
6121126261Smlaier			return (1);
6122126261Smlaier		}
6123126261Smlaier	}
6124126261Smlaier	if (sum) {
6125126261Smlaier		switch (p) {
6126126261Smlaier		case IPPROTO_TCP:
6127126261Smlaier			tcpstat.tcps_rcvbadsum++;
6128126261Smlaier			break;
6129126261Smlaier		case IPPROTO_UDP:
6130126261Smlaier			udpstat.udps_badsum++;
6131126261Smlaier			break;
6132126261Smlaier		case IPPROTO_ICMP:
6133126261Smlaier			icmpstat.icps_checksum++;
6134126261Smlaier			break;
6135126261Smlaier#ifdef INET6
6136126261Smlaier		case IPPROTO_ICMPV6:
6137126261Smlaier			icmp6stat.icp6s_checksum++;
6138126261Smlaier			break;
6139126261Smlaier#endif /* INET6 */
6140126261Smlaier		}
6141126261Smlaier		return (1);
6142132566Smlaier	} else {
6143132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
6144132566Smlaier			m->m_pkthdr.csum_flags |=
6145132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
6146132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
6147132566Smlaier		}
6148126261Smlaier	}
6149126261Smlaier	return (0);
6150126261Smlaier}
6151126261Smlaier#else
6152126261Smlaier/*
6153126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
6154126258Smlaier *   off is the offset where the protocol header starts
6155126258Smlaier *   len is the total length of protocol header plus payload
6156126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
6157126258Smlaier */
6158126258Smlaierint
6159130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
6160130613Smlaier    sa_family_t af)
6161126258Smlaier{
6162126258Smlaier	u_int16_t flag_ok, flag_bad;
6163126258Smlaier	u_int16_t sum;
6164126258Smlaier
6165126258Smlaier	switch (p) {
6166126258Smlaier	case IPPROTO_TCP:
6167126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
6168126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
6169126258Smlaier		break;
6170126258Smlaier	case IPPROTO_UDP:
6171126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
6172126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
6173126258Smlaier		break;
6174126258Smlaier	case IPPROTO_ICMP:
6175126258Smlaier#ifdef INET6
6176126258Smlaier	case IPPROTO_ICMPV6:
6177126258Smlaier#endif /* INET6 */
6178126258Smlaier		flag_ok = flag_bad = 0;
6179126258Smlaier		break;
6180126258Smlaier	default:
6181126258Smlaier		return (1);
6182126258Smlaier	}
6183126258Smlaier	if (m->m_pkthdr.csum & flag_ok)
6184126258Smlaier		return (0);
6185126258Smlaier	if (m->m_pkthdr.csum & flag_bad)
6186126258Smlaier		return (1);
6187126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6188126258Smlaier		return (1);
6189126258Smlaier	if (m->m_pkthdr.len < off + len)
6190126258Smlaier		return (1);
6191145836Smlaier	switch (af) {
6192145836Smlaier#ifdef INET
6193126258Smlaier	case AF_INET:
6194126258Smlaier		if (p == IPPROTO_ICMP) {
6195126258Smlaier			if (m->m_len < off)
6196126258Smlaier				return (1);
6197126258Smlaier			m->m_data += off;
6198126258Smlaier			m->m_len -= off;
6199126258Smlaier			sum = in_cksum(m, len);
6200126258Smlaier			m->m_data -= off;
6201126258Smlaier			m->m_len += off;
6202126258Smlaier		} else {
6203126258Smlaier			if (m->m_len < sizeof(struct ip))
6204126258Smlaier				return (1);
6205126258Smlaier			sum = in4_cksum(m, p, off, len);
6206126258Smlaier		}
6207126258Smlaier		break;
6208145836Smlaier#endif /* INET */
6209126258Smlaier#ifdef INET6
6210126258Smlaier	case AF_INET6:
6211126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
6212126258Smlaier			return (1);
6213126258Smlaier		sum = in6_cksum(m, p, off, len);
6214126258Smlaier		break;
6215126258Smlaier#endif /* INET6 */
6216126258Smlaier	default:
6217126258Smlaier		return (1);
6218126258Smlaier	}
6219126258Smlaier	if (sum) {
6220126258Smlaier		m->m_pkthdr.csum |= flag_bad;
6221126258Smlaier		switch (p) {
6222126258Smlaier		case IPPROTO_TCP:
6223126258Smlaier			tcpstat.tcps_rcvbadsum++;
6224126258Smlaier			break;
6225126258Smlaier		case IPPROTO_UDP:
6226126258Smlaier			udpstat.udps_badsum++;
6227126258Smlaier			break;
6228126258Smlaier		case IPPROTO_ICMP:
6229126258Smlaier			icmpstat.icps_checksum++;
6230126258Smlaier			break;
6231126258Smlaier#ifdef INET6
6232126258Smlaier		case IPPROTO_ICMPV6:
6233126258Smlaier			icmp6stat.icp6s_checksum++;
6234126258Smlaier			break;
6235126258Smlaier#endif /* INET6 */
6236126258Smlaier		}
6237126258Smlaier		return (1);
6238126258Smlaier	}
6239126258Smlaier	m->m_pkthdr.csum |= flag_ok;
6240126258Smlaier	return (0);
6241126258Smlaier}
6242126261Smlaier#endif
6243126258Smlaier
6244130613Smlaierstatic int
6245130613Smlaierpf_add_mbuf_tag(struct mbuf *m, u_int tag)
6246130613Smlaier{
6247130613Smlaier	struct m_tag *mtag;
6248130613Smlaier
6249130613Smlaier	if (m_tag_find(m, tag, NULL) != NULL)
6250130613Smlaier		return (0);
6251130613Smlaier	mtag = m_tag_get(tag, 0, M_NOWAIT);
6252130613Smlaier	if (mtag == NULL)
6253130613Smlaier		return (1);
6254130613Smlaier	m_tag_prepend(m, mtag);
6255130613Smlaier	return (0);
6256130613Smlaier}
6257130613Smlaier
6258126258Smlaier#ifdef INET
6259126258Smlaierint
6260135920Smlaier#ifdef __FreeBSD__
6261145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6262145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6263135920Smlaier#else
6264145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6265145836Smlaier    struct ether_header *eh)
6266135920Smlaier#endif
6267126258Smlaier{
6268130613Smlaier	struct pfi_kif		*kif;
6269130613Smlaier	u_short			 action, reason = 0, log = 0;
6270130613Smlaier	struct mbuf		*m = *m0;
6271130613Smlaier	struct ip		*h = NULL;	/* make the compiler happy */
6272130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6273130613Smlaier	struct pf_state		*s = NULL;
6274130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6275130613Smlaier	struct pf_pdesc		 pd;
6276130613Smlaier	int			 off, dirndx, pqid = 0;
6277126258Smlaier
6278127145Smlaier#ifdef __FreeBSD__
6279126261Smlaier	PF_LOCK();
6280126261Smlaier#endif
6281126258Smlaier	if (!pf_status.running ||
6282127145Smlaier#ifdef __FreeBSD__
6283132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
6284126261Smlaier		PF_UNLOCK();
6285132280Smlaier#else
6286132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
6287126261Smlaier#endif
6288126261Smlaier	    	return (PF_PASS);
6289126261Smlaier	}
6290126258Smlaier
6291145836Smlaier#ifdef __FreeBSD__
6292145836Smlaier	/* XXX_IMPORT: later */
6293145836Smlaier#else
6294145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6295145836Smlaier		ifp = ifp->if_carpdev;
6296145836Smlaier#endif
6297145836Smlaier
6298130613Smlaier	kif = pfi_index2kif[ifp->if_index];
6299130613Smlaier	if (kif == NULL) {
6300130613Smlaier#ifdef __FreeBSD__
6301130613Smlaier		PF_UNLOCK();
6302130613Smlaier#endif
6303145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6304145836Smlaier		    ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
6305130613Smlaier		return (PF_DROP);
6306130613Smlaier	}
6307145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6308145836Smlaier#ifdef __FreeBSD__
6309145836Smlaier		PF_UNLOCK();
6310145836Smlaier#endif
6311145836Smlaier		return (PF_PASS);
6312145836Smlaier	}
6313130613Smlaier
6314130613Smlaier#ifdef __FreeBSD__
6315126261Smlaier	M_ASSERTPKTHDR(m);
6316126261Smlaier#else
6317126258Smlaier#ifdef DIAGNOSTIC
6318126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6319126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6320145836Smlaier#endif /* DIAGNOSTIC */
6321145836Smlaier#endif /* __FreeBSD__ */
6322126258Smlaier
6323130613Smlaier	memset(&pd, 0, sizeof(pd));
6324126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6325126258Smlaier		action = PF_DROP;
6326126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6327126258Smlaier		log = 1;
6328126258Smlaier		goto done;
6329126258Smlaier	}
6330126258Smlaier
6331126258Smlaier	/* We do IP header normalization and packet reassembly here */
6332145836Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
6333126258Smlaier		action = PF_DROP;
6334126258Smlaier		goto done;
6335126258Smlaier	}
6336126258Smlaier	m = *m0;
6337126258Smlaier	h = mtod(m, struct ip *);
6338126258Smlaier
6339126258Smlaier	off = h->ip_hl << 2;
6340126258Smlaier	if (off < (int)sizeof(*h)) {
6341126258Smlaier		action = PF_DROP;
6342126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6343126258Smlaier		log = 1;
6344126258Smlaier		goto done;
6345126258Smlaier	}
6346126258Smlaier
6347126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
6348126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
6349130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
6350126258Smlaier	pd.ip_sum = &h->ip_sum;
6351126258Smlaier	pd.proto = h->ip_p;
6352126258Smlaier	pd.af = AF_INET;
6353126258Smlaier	pd.tos = h->ip_tos;
6354126258Smlaier	pd.tot_len = ntohs(h->ip_len);
6355145836Smlaier	pd.eh = eh;
6356126258Smlaier
6357126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
6358126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
6359130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
6360126258Smlaier		    &pd, &a, &ruleset);
6361126258Smlaier		goto done;
6362126258Smlaier	}
6363126258Smlaier
6364126258Smlaier	switch (h->ip_p) {
6365126258Smlaier
6366126258Smlaier	case IPPROTO_TCP: {
6367126258Smlaier		struct tcphdr	th;
6368126258Smlaier
6369126258Smlaier		pd.hdr.tcp = &th;
6370126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6371126258Smlaier		    &action, &reason, AF_INET)) {
6372126258Smlaier			log = action != PF_PASS;
6373126258Smlaier			goto done;
6374126258Smlaier		}
6375126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6376126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
6377126258Smlaier			action = PF_DROP;
6378126258Smlaier			goto done;
6379126258Smlaier		}
6380126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6381126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
6382126258Smlaier			pqid = 1;
6383130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6384126258Smlaier		if (action == PF_DROP)
6385130613Smlaier			goto done;
6386130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6387126258Smlaier		    &reason);
6388126258Smlaier		if (action == PF_PASS) {
6389130613Smlaier#if NPFSYNC
6390130613Smlaier			pfsync_update_state(s);
6391145836Smlaier#endif /* NPFSYNC */
6392126258Smlaier			r = s->rule.ptr;
6393130613Smlaier			a = s->anchor.ptr;
6394126258Smlaier			log = s->log;
6395126258Smlaier		} else if (s == NULL)
6396135920Smlaier#ifdef __FreeBSD__
6397130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6398145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6399135920Smlaier#else
6400135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6401145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6402135920Smlaier#endif
6403126258Smlaier		break;
6404126258Smlaier	}
6405126258Smlaier
6406126258Smlaier	case IPPROTO_UDP: {
6407126258Smlaier		struct udphdr	uh;
6408126258Smlaier
6409126258Smlaier		pd.hdr.udp = &uh;
6410126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6411126258Smlaier		    &action, &reason, AF_INET)) {
6412126258Smlaier			log = action != PF_PASS;
6413126258Smlaier			goto done;
6414126258Smlaier		}
6415126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6416126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
6417126258Smlaier			action = PF_DROP;
6418126258Smlaier			goto done;
6419126258Smlaier		}
6420130613Smlaier		if (uh.uh_dport == 0 ||
6421130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6422130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6423130613Smlaier			action = PF_DROP;
6424130613Smlaier			goto done;
6425130613Smlaier		}
6426130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6427126258Smlaier		if (action == PF_PASS) {
6428130613Smlaier#if NPFSYNC
6429130613Smlaier			pfsync_update_state(s);
6430145836Smlaier#endif /* NPFSYNC */
6431126258Smlaier			r = s->rule.ptr;
6432126258Smlaier			a = s->anchor.ptr;
6433126258Smlaier			log = s->log;
6434126258Smlaier		} else if (s == NULL)
6435135920Smlaier#ifdef __FreeBSD__
6436130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6437145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6438135920Smlaier#else
6439135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6440145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6441135920Smlaier#endif
6442126258Smlaier		break;
6443126258Smlaier	}
6444126258Smlaier
6445126258Smlaier	case IPPROTO_ICMP: {
6446126258Smlaier		struct icmp	ih;
6447126258Smlaier
6448126258Smlaier		pd.hdr.icmp = &ih;
6449126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
6450126258Smlaier		    &action, &reason, AF_INET)) {
6451126258Smlaier			log = action != PF_PASS;
6452126258Smlaier			goto done;
6453126258Smlaier		}
6454126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6455126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
6456126258Smlaier			action = PF_DROP;
6457126258Smlaier			goto done;
6458126258Smlaier		}
6459145836Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
6460145836Smlaier		    &reason);
6461126258Smlaier		if (action == PF_PASS) {
6462130613Smlaier#if NPFSYNC
6463130613Smlaier			pfsync_update_state(s);
6464145836Smlaier#endif /* NPFSYNC */
6465126258Smlaier			r = s->rule.ptr;
6466126258Smlaier			a = s->anchor.ptr;
6467126258Smlaier			log = s->log;
6468126258Smlaier		} else if (s == NULL)
6469145836Smlaier#ifdef __FreeBSD__
6470130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6471145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6472145836Smlaier#else
6473145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6474145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6475145836Smlaier#endif
6476126258Smlaier		break;
6477126258Smlaier	}
6478126258Smlaier
6479126258Smlaier	default:
6480130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6481126258Smlaier		if (action == PF_PASS) {
6482130613Smlaier#if NPFSYNC
6483130613Smlaier			pfsync_update_state(s);
6484145836Smlaier#endif /* NPFSYNC */
6485126258Smlaier			r = s->rule.ptr;
6486126258Smlaier			a = s->anchor.ptr;
6487126258Smlaier			log = s->log;
6488126258Smlaier		} else if (s == NULL)
6489145836Smlaier#ifdef __FreeBSD__
6490130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6491145836Smlaier			    &pd, &a, &ruleset, NULL);
6492145836Smlaier#else
6493145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6494145836Smlaier			    &pd, &a, &ruleset, &ipintrq);
6495145836Smlaier#endif
6496126258Smlaier		break;
6497126258Smlaier	}
6498126258Smlaier
6499126258Smlaierdone:
6500126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
6501126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
6502126258Smlaier		action = PF_DROP;
6503145836Smlaier		REASON_SET(&reason, PFRES_IPOPTIONS);
6504126258Smlaier		log = 1;
6505126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
6506126258Smlaier		    ("pf: dropping packet with ip options\n"));
6507126258Smlaier	}
6508126258Smlaier
6509145836Smlaier	if (s && s->tag)
6510145836Smlaier		pf_tag_packet(m, pf_get_tag(m), s->tag);
6511145836Smlaier
6512126258Smlaier#ifdef ALTQ
6513126258Smlaier	if (action == PF_PASS && r->qid) {
6514126258Smlaier		struct m_tag	*mtag;
6515126258Smlaier		struct altq_tag	*atag;
6516126258Smlaier
6517126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
6518126258Smlaier		if (mtag != NULL) {
6519126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
6520126258Smlaier			if (pqid || pd.tos == IPTOS_LOWDELAY)
6521126258Smlaier				atag->qid = r->pqid;
6522126258Smlaier			else
6523126258Smlaier				atag->qid = r->qid;
6524126258Smlaier			/* add hints for ecn */
6525126258Smlaier			atag->af = AF_INET;
6526126258Smlaier			atag->hdr = h;
6527126258Smlaier			m_tag_prepend(m, mtag);
6528126258Smlaier		}
6529126258Smlaier	}
6530145836Smlaier#endif /* ALTQ */
6531126258Smlaier
6532130613Smlaier	/*
6533130613Smlaier	 * connections redirected to loopback should not match sockets
6534130613Smlaier	 * bound specifically to loopback due to security implications,
6535130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
6536130613Smlaier	 */
6537130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
6538130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
6539130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
6540130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
6541130613Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
6542130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
6543130613Smlaier		action = PF_DROP;
6544130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
6545130613Smlaier	}
6546130613Smlaier
6547126258Smlaier	if (log)
6548130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset);
6549126258Smlaier
6550130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
6551130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
6552130613Smlaier
6553130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
6554130613Smlaier		r->packets++;
6555130613Smlaier		r->bytes += pd.tot_len;
6556130613Smlaier		if (a != NULL) {
6557130613Smlaier			a->packets++;
6558130613Smlaier			a->bytes += pd.tot_len;
6559130613Smlaier		}
6560130613Smlaier		if (s != NULL) {
6561130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
6562130613Smlaier			s->packets[dirndx]++;
6563130613Smlaier			s->bytes[dirndx] += pd.tot_len;
6564130613Smlaier			if (s->nat_rule.ptr != NULL) {
6565130613Smlaier				s->nat_rule.ptr->packets++;
6566130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
6567130613Smlaier			}
6568130613Smlaier			if (s->src_node != NULL) {
6569130613Smlaier				s->src_node->packets++;
6570130613Smlaier				s->src_node->bytes += pd.tot_len;
6571130613Smlaier			}
6572130613Smlaier			if (s->nat_src_node != NULL) {
6573130613Smlaier				s->nat_src_node->packets++;
6574130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
6575130613Smlaier			}
6576130613Smlaier		}
6577130613Smlaier		tr = r;
6578130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
6579130613Smlaier		if (nr != NULL) {
6580130613Smlaier			struct pf_addr *x;
6581130613Smlaier			/*
6582130613Smlaier			 * XXX: we need to make sure that the addresses
6583130613Smlaier			 * passed to pfr_update_stats() are the same than
6584130613Smlaier			 * the addresses used during matching (pfr_match)
6585130613Smlaier			 */
6586130613Smlaier			if (r == &pf_default_rule) {
6587130613Smlaier				tr = nr;
6588130613Smlaier				x = (s == NULL || s->direction == dir) ?
6589130613Smlaier				    &pd.baddr : &pd.naddr;
6590130613Smlaier			} else
6591130613Smlaier				x = (s == NULL || s->direction == dir) ?
6592130613Smlaier				    &pd.naddr : &pd.baddr;
6593130613Smlaier			if (x == &pd.baddr || s == NULL) {
6594130613Smlaier				/* we need to change the address */
6595130613Smlaier				if (dir == PF_OUT)
6596130613Smlaier					pd.src = x;
6597130613Smlaier				else
6598130613Smlaier					pd.dst = x;
6599130613Smlaier			}
6600130613Smlaier		}
6601130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
6602130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
6603130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
6604130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6605145836Smlaier			    tr->src.neg);
6606130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
6607130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
6608130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
6609130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6610145836Smlaier			    tr->dst.neg);
6611130613Smlaier	}
6612130613Smlaier
6613130613Smlaier
6614126258Smlaier	if (action == PF_SYNPROXY_DROP) {
6615126258Smlaier		m_freem(*m0);
6616126258Smlaier		*m0 = NULL;
6617126258Smlaier		action = PF_PASS;
6618126258Smlaier	} else if (r->rt)
6619126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
6620126258Smlaier		pf_route(m0, r, dir, ifp, s);
6621126258Smlaier
6622127145Smlaier#ifdef __FreeBSD__
6623126261Smlaier	PF_UNLOCK();
6624126261Smlaier#endif
6625126261Smlaier
6626126258Smlaier	return (action);
6627126258Smlaier}
6628126258Smlaier#endif /* INET */
6629126258Smlaier
6630126258Smlaier#ifdef INET6
6631126258Smlaierint
6632135920Smlaier#ifdef __FreeBSD__
6633145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
6634145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6635135920Smlaier#else
6636145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
6637145836Smlaier    struct ether_header *eh)
6638135920Smlaier#endif
6639126258Smlaier{
6640130613Smlaier	struct pfi_kif		*kif;
6641130613Smlaier	u_short			 action, reason = 0, log = 0;
6642130613Smlaier	struct mbuf		*m = *m0;
6643130613Smlaier	struct ip6_hdr		*h = NULL;	/* make the compiler happy */
6644130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6645130613Smlaier	struct pf_state		*s = NULL;
6646130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6647130613Smlaier	struct pf_pdesc		 pd;
6648130613Smlaier	int			 off, terminal = 0, dirndx;
6649126258Smlaier
6650127145Smlaier#ifdef __FreeBSD__
6651126261Smlaier	PF_LOCK();
6652126261Smlaier#endif
6653126261Smlaier
6654126258Smlaier	if (!pf_status.running ||
6655127145Smlaier#ifdef __FreeBSD__
6656132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
6657126261Smlaier		PF_UNLOCK();
6658132280Smlaier#else
6659132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
6660126261Smlaier#endif
6661126258Smlaier		return (PF_PASS);
6662126261Smlaier	}
6663126258Smlaier
6664145836Smlaier#ifdef __FreeBSD__
6665145836Smlaier	/* XXX_IMPORT: later */
6666145836Smlaier#else
6667145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6668145836Smlaier		ifp = ifp->if_carpdev;
6669145836Smlaier#endif
6670145836Smlaier
6671130613Smlaier	kif = pfi_index2kif[ifp->if_index];
6672130613Smlaier	if (kif == NULL) {
6673130613Smlaier#ifdef __FreeBSD__
6674130613Smlaier		PF_UNLOCK();
6675130613Smlaier#endif
6676145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6677145836Smlaier		    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
6678130613Smlaier		return (PF_DROP);
6679130613Smlaier	}
6680145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6681145836Smlaier#ifdef __FreeBSD__
6682145836Smlaier		PF_UNLOCK();
6683145836Smlaier#endif
6684145836Smlaier		return (PF_PASS);
6685145836Smlaier	}
6686130613Smlaier
6687130613Smlaier#ifdef __FreeBSD__
6688126261Smlaier	M_ASSERTPKTHDR(m);
6689126261Smlaier#else
6690126258Smlaier#ifdef DIAGNOSTIC
6691126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6692145836Smlaier		panic("non-M_PKTHDR is passed to pf_test6");
6693145836Smlaier#endif /* DIAGNOSTIC */
6694126258Smlaier#endif
6695126258Smlaier
6696130613Smlaier	memset(&pd, 0, sizeof(pd));
6697126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6698126258Smlaier		action = PF_DROP;
6699126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6700126258Smlaier		log = 1;
6701126258Smlaier		goto done;
6702126258Smlaier	}
6703126258Smlaier
6704126258Smlaier	/* We do IP header normalization and packet reassembly here */
6705145836Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
6706126258Smlaier		action = PF_DROP;
6707126258Smlaier		goto done;
6708126258Smlaier	}
6709126258Smlaier	m = *m0;
6710126258Smlaier	h = mtod(m, struct ip6_hdr *);
6711126258Smlaier
6712126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
6713126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
6714130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
6715126258Smlaier	pd.ip_sum = NULL;
6716126258Smlaier	pd.af = AF_INET6;
6717126258Smlaier	pd.tos = 0;
6718126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
6719145836Smlaier	pd.eh = eh;
6720126258Smlaier
6721126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
6722126258Smlaier	pd.proto = h->ip6_nxt;
6723126258Smlaier	do {
6724126258Smlaier		switch (pd.proto) {
6725126258Smlaier		case IPPROTO_FRAGMENT:
6726130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
6727126258Smlaier			    &pd, &a, &ruleset);
6728126258Smlaier			if (action == PF_DROP)
6729126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
6730126258Smlaier			goto done;
6731126258Smlaier		case IPPROTO_AH:
6732126258Smlaier		case IPPROTO_HOPOPTS:
6733126258Smlaier		case IPPROTO_ROUTING:
6734126258Smlaier		case IPPROTO_DSTOPTS: {
6735126258Smlaier			/* get next header and header length */
6736126258Smlaier			struct ip6_ext	opt6;
6737126258Smlaier
6738126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
6739145836Smlaier			    NULL, &reason, pd.af)) {
6740126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
6741126258Smlaier				    ("pf: IPv6 short opt\n"));
6742126258Smlaier				action = PF_DROP;
6743126258Smlaier				log = 1;
6744126258Smlaier				goto done;
6745126258Smlaier			}
6746126258Smlaier			if (pd.proto == IPPROTO_AH)
6747126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
6748126258Smlaier			else
6749126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
6750126258Smlaier			pd.proto = opt6.ip6e_nxt;
6751126258Smlaier			/* goto the next header */
6752126258Smlaier			break;
6753126258Smlaier		}
6754126258Smlaier		default:
6755126258Smlaier			terminal++;
6756126258Smlaier			break;
6757126258Smlaier		}
6758126258Smlaier	} while (!terminal);
6759126258Smlaier
6760126258Smlaier	switch (pd.proto) {
6761126258Smlaier
6762126258Smlaier	case IPPROTO_TCP: {
6763126258Smlaier		struct tcphdr	th;
6764126258Smlaier
6765126258Smlaier		pd.hdr.tcp = &th;
6766126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6767126258Smlaier		    &action, &reason, AF_INET6)) {
6768126258Smlaier			log = action != PF_PASS;
6769126258Smlaier			goto done;
6770126258Smlaier		}
6771126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6772138387Sdhartmei		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6773138387Sdhartmei		    IPPROTO_TCP, AF_INET6)) {
6774126258Smlaier			action = PF_DROP;
6775145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6776126258Smlaier			goto done;
6777126258Smlaier		}
6778126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6779130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6780126258Smlaier		if (action == PF_DROP)
6781130613Smlaier			goto done;
6782130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6783126258Smlaier		    &reason);
6784126258Smlaier		if (action == PF_PASS) {
6785130613Smlaier#if NPFSYNC
6786130613Smlaier			pfsync_update_state(s);
6787145836Smlaier#endif /* NPFSYNC */
6788126258Smlaier			r = s->rule.ptr;
6789130613Smlaier			a = s->anchor.ptr;
6790126258Smlaier			log = s->log;
6791126258Smlaier		} else if (s == NULL)
6792135920Smlaier#ifdef __FreeBSD__
6793130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6794145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6795135920Smlaier#else
6796135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6797145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6798135920Smlaier#endif
6799126258Smlaier		break;
6800126258Smlaier	}
6801126258Smlaier
6802126258Smlaier	case IPPROTO_UDP: {
6803126258Smlaier		struct udphdr	uh;
6804126258Smlaier
6805126258Smlaier		pd.hdr.udp = &uh;
6806126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6807126258Smlaier		    &action, &reason, AF_INET6)) {
6808126258Smlaier			log = action != PF_PASS;
6809126258Smlaier			goto done;
6810126258Smlaier		}
6811126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6812138387Sdhartmei		    off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6813138387Sdhartmei		    IPPROTO_UDP, AF_INET6)) {
6814126258Smlaier			action = PF_DROP;
6815145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6816126258Smlaier			goto done;
6817126258Smlaier		}
6818130613Smlaier		if (uh.uh_dport == 0 ||
6819130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6820130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6821130613Smlaier			action = PF_DROP;
6822130613Smlaier			goto done;
6823130613Smlaier		}
6824130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6825126258Smlaier		if (action == PF_PASS) {
6826130613Smlaier#if NPFSYNC
6827130613Smlaier			pfsync_update_state(s);
6828145836Smlaier#endif /* NPFSYNC */
6829126258Smlaier			r = s->rule.ptr;
6830130613Smlaier			a = s->anchor.ptr;
6831126258Smlaier			log = s->log;
6832126258Smlaier		} else if (s == NULL)
6833135920Smlaier#ifdef __FreeBSD__
6834130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6835145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6836135920Smlaier#else
6837135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6838145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6839135920Smlaier#endif
6840126258Smlaier		break;
6841126258Smlaier	}
6842126258Smlaier
6843126258Smlaier	case IPPROTO_ICMPV6: {
6844126258Smlaier		struct icmp6_hdr	ih;
6845126258Smlaier
6846126258Smlaier		pd.hdr.icmp6 = &ih;
6847126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
6848126258Smlaier		    &action, &reason, AF_INET6)) {
6849126258Smlaier			log = action != PF_PASS;
6850126258Smlaier			goto done;
6851126258Smlaier		}
6852126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6853145836Smlaier		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6854138387Sdhartmei		    IPPROTO_ICMPV6, AF_INET6)) {
6855126258Smlaier			action = PF_DROP;
6856145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6857126258Smlaier			goto done;
6858126258Smlaier		}
6859130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
6860145836Smlaier		    m, off, h, &pd, &reason);
6861126258Smlaier		if (action == PF_PASS) {
6862130613Smlaier#if NPFSYNC
6863130613Smlaier			pfsync_update_state(s);
6864145836Smlaier#endif /* NPFSYNC */
6865126258Smlaier			r = s->rule.ptr;
6866130613Smlaier			a = s->anchor.ptr;
6867126258Smlaier			log = s->log;
6868126258Smlaier		} else if (s == NULL)
6869145836Smlaier#ifdef __FreeBSD__
6870130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6871145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6872145836Smlaier#else
6873145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6874145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6875145836Smlaier#endif
6876126258Smlaier		break;
6877126258Smlaier	}
6878126258Smlaier
6879126258Smlaier	default:
6880130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6881130613Smlaier		if (action == PF_PASS) {
6882145836Smlaier#if NPFSYNC
6883145836Smlaier			pfsync_update_state(s);
6884145836Smlaier#endif /* NPFSYNC */
6885130613Smlaier			r = s->rule.ptr;
6886130613Smlaier			a = s->anchor.ptr;
6887130613Smlaier			log = s->log;
6888130613Smlaier		} else if (s == NULL)
6889145836Smlaier#ifdef __FreeBSD__
6890130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6891145836Smlaier			    &pd, &a, &ruleset, NULL);
6892145836Smlaier#else
6893145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6894145836Smlaier			    &pd, &a, &ruleset, &ip6intrq);
6895145836Smlaier#endif
6896126258Smlaier		break;
6897126258Smlaier	}
6898126258Smlaier
6899126258Smlaierdone:
6900126258Smlaier	/* XXX handle IPv6 options, if not allowed. not implemented. */
6901126258Smlaier
6902145836Smlaier	if (s && s->tag)
6903145836Smlaier		pf_tag_packet(m, pf_get_tag(m), s->tag);
6904145836Smlaier
6905126258Smlaier#ifdef ALTQ
6906126258Smlaier	if (action == PF_PASS && r->qid) {
6907126258Smlaier		struct m_tag	*mtag;
6908126258Smlaier		struct altq_tag	*atag;
6909126258Smlaier
6910126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
6911126258Smlaier		if (mtag != NULL) {
6912126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
6913126258Smlaier			if (pd.tos == IPTOS_LOWDELAY)
6914126258Smlaier				atag->qid = r->pqid;
6915126258Smlaier			else
6916126258Smlaier				atag->qid = r->qid;
6917126258Smlaier			/* add hints for ecn */
6918126258Smlaier			atag->af = AF_INET6;
6919126258Smlaier			atag->hdr = h;
6920126258Smlaier			m_tag_prepend(m, mtag);
6921126258Smlaier		}
6922126258Smlaier	}
6923145836Smlaier#endif /* ALTQ */
6924126258Smlaier
6925130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
6926130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
6927130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
6928130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
6929130613Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) &&
6930130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
6931130613Smlaier		action = PF_DROP;
6932130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
6933130613Smlaier	}
6934130613Smlaier
6935126258Smlaier	if (log)
6936130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset);
6937126258Smlaier
6938130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
6939130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
6940130613Smlaier
6941130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
6942130613Smlaier		r->packets++;
6943130613Smlaier		r->bytes += pd.tot_len;
6944130613Smlaier		if (a != NULL) {
6945130613Smlaier			a->packets++;
6946130613Smlaier			a->bytes += pd.tot_len;
6947130613Smlaier		}
6948130613Smlaier		if (s != NULL) {
6949130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
6950130613Smlaier			s->packets[dirndx]++;
6951130613Smlaier			s->bytes[dirndx] += pd.tot_len;
6952130613Smlaier			if (s->nat_rule.ptr != NULL) {
6953130613Smlaier				s->nat_rule.ptr->packets++;
6954130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
6955130613Smlaier			}
6956130613Smlaier			if (s->src_node != NULL) {
6957130613Smlaier				s->src_node->packets++;
6958130613Smlaier				s->src_node->bytes += pd.tot_len;
6959130613Smlaier			}
6960130613Smlaier			if (s->nat_src_node != NULL) {
6961130613Smlaier				s->nat_src_node->packets++;
6962130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
6963130613Smlaier			}
6964130613Smlaier		}
6965130613Smlaier		tr = r;
6966130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
6967130613Smlaier		if (nr != NULL) {
6968130613Smlaier			struct pf_addr *x;
6969130613Smlaier			/*
6970130613Smlaier			 * XXX: we need to make sure that the addresses
6971130613Smlaier			 * passed to pfr_update_stats() are the same than
6972130613Smlaier			 * the addresses used during matching (pfr_match)
6973130613Smlaier			 */
6974130613Smlaier			if (r == &pf_default_rule) {
6975130613Smlaier				tr = nr;
6976130613Smlaier				x = (s == NULL || s->direction == dir) ?
6977130613Smlaier				    &pd.baddr : &pd.naddr;
6978130613Smlaier			} else {
6979130613Smlaier				x = (s == NULL || s->direction == dir) ?
6980130613Smlaier				    &pd.naddr : &pd.baddr;
6981130613Smlaier			}
6982130613Smlaier			if (x == &pd.baddr || s == NULL) {
6983130613Smlaier				if (dir == PF_OUT)
6984130613Smlaier					pd.src = x;
6985130613Smlaier				else
6986130613Smlaier					pd.dst = x;
6987130613Smlaier			}
6988130613Smlaier		}
6989130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
6990130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
6991130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
6992130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6993145836Smlaier			    tr->src.neg);
6994130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
6995130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
6996130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
6997130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6998145836Smlaier			    tr->dst.neg);
6999130613Smlaier	}
7000130613Smlaier
7001130613Smlaier
7002126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7003126258Smlaier		m_freem(*m0);
7004126258Smlaier		*m0 = NULL;
7005126258Smlaier		action = PF_PASS;
7006126258Smlaier	} else if (r->rt)
7007126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
7008126258Smlaier		pf_route6(m0, r, dir, ifp, s);
7009126258Smlaier
7010127145Smlaier#ifdef __FreeBSD__
7011126261Smlaier	PF_UNLOCK();
7012126261Smlaier#endif
7013126258Smlaier	return (action);
7014126258Smlaier}
7015126258Smlaier#endif /* INET6 */
7016145836Smlaier
7017145836Smlaierint
7018145836Smlaierpf_check_congestion(struct ifqueue *ifq)
7019145836Smlaier{
7020145836Smlaier#ifdef __FreeBSD__
7021145836Smlaier	/* XXX_IMPORT: later */
7022145836Smlaier	return (0);
7023145836Smlaier#else
7024145836Smlaier	if (ifq->ifq_congestion)
7025145836Smlaier		return (1);
7026145836Smlaier	else
7027145836Smlaier		return (0);
7028145836Smlaier#endif
7029145836Smlaier}
7030