pf.c revision 153545
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/pf.c 153545 2005-12-20 00:33:33Z 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"
47153110Sru
48153110Sru#ifdef DEV_BPF
49127145Smlaier#define	NBPFILTER	DEV_BPF
50153110Sru#else
51153110Sru#define	NBPFILTER	0
52153110Sru#endif
53153110Sru
54153110Sru#ifdef DEV_PFLOG
55127145Smlaier#define	NPFLOG		DEV_PFLOG
56153110Sru#else
57153110Sru#define	NPFLOG		0
58153110Sru#endif
59153110Sru
60153110Sru#ifdef DEV_PFSYNC
61127145Smlaier#define	NPFSYNC		DEV_PFSYNC
62126261Smlaier#else
63153110Sru#define	NPFSYNC		0
64153110Sru#endif
65153110Sru
66153110Sru#else
67126258Smlaier#include "bpfilter.h"
68126258Smlaier#include "pflog.h"
69126258Smlaier#include "pfsync.h"
70126261Smlaier#endif
71126258Smlaier
72126258Smlaier#include <sys/param.h>
73126258Smlaier#include <sys/systm.h>
74126258Smlaier#include <sys/mbuf.h>
75126258Smlaier#include <sys/filio.h>
76126258Smlaier#include <sys/socket.h>
77126258Smlaier#include <sys/socketvar.h>
78126258Smlaier#include <sys/kernel.h>
79126258Smlaier#include <sys/time.h>
80127145Smlaier#ifdef __FreeBSD__
81126261Smlaier#include <sys/sysctl.h>
82130613Smlaier#include <sys/endian.h>
83126261Smlaier#else
84126258Smlaier#include <sys/pool.h>
85126261Smlaier#endif
86126258Smlaier
87126258Smlaier#include <net/if.h>
88126258Smlaier#include <net/if_types.h>
89126258Smlaier#include <net/bpf.h>
90126258Smlaier#include <net/route.h>
91126258Smlaier
92126258Smlaier#include <netinet/in.h>
93126258Smlaier#include <netinet/in_var.h>
94126258Smlaier#include <netinet/in_systm.h>
95126258Smlaier#include <netinet/ip.h>
96126258Smlaier#include <netinet/ip_var.h>
97126258Smlaier#include <netinet/tcp.h>
98126258Smlaier#include <netinet/tcp_seq.h>
99126258Smlaier#include <netinet/udp.h>
100126258Smlaier#include <netinet/ip_icmp.h>
101126258Smlaier#include <netinet/in_pcb.h>
102126258Smlaier#include <netinet/tcp_timer.h>
103126258Smlaier#include <netinet/tcp_var.h>
104126258Smlaier#include <netinet/udp_var.h>
105126258Smlaier#include <netinet/icmp_var.h>
106145836Smlaier#include <netinet/if_ether.h>
107126258Smlaier
108127145Smlaier#ifndef __FreeBSD__
109126258Smlaier#include <dev/rndvar.h>
110126261Smlaier#endif
111126258Smlaier#include <net/pfvar.h>
112126258Smlaier#include <net/if_pflog.h>
113130613Smlaier
114130613Smlaier#if NPFSYNC > 0
115126258Smlaier#include <net/if_pfsync.h>
116130613Smlaier#endif /* NPFSYNC > 0 */
117126258Smlaier
118126258Smlaier#ifdef INET6
119126258Smlaier#include <netinet/ip6.h>
120126258Smlaier#include <netinet/in_pcb.h>
121126258Smlaier#include <netinet/icmp6.h>
122126258Smlaier#include <netinet6/nd6.h>
123127145Smlaier#ifdef __FreeBSD__
124126261Smlaier#include <netinet6/ip6_var.h>
125126261Smlaier#include <netinet6/in6_pcb.h>
126126261Smlaier#endif
127126258Smlaier#endif /* INET6 */
128126258Smlaier
129127145Smlaier#ifdef __FreeBSD__
130126261Smlaier#include <machine/in_cksum.h>
131126261Smlaier#include <sys/limits.h>
132126261Smlaier#include <sys/ucred.h>
133126258Smlaier
134126261Smlaierextern int ip_optcopy(struct ip *, struct ip *);
135126261Smlaier#endif
136126261Smlaier
137126258Smlaier#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
138126258Smlaier
139126258Smlaier/*
140126258Smlaier * Global variables
141126258Smlaier */
142126258Smlaier
143145836Smlaierstruct pf_anchor_global	 pf_anchors;
144126258Smlaierstruct pf_ruleset	 pf_main_ruleset;
145126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
146126258Smlaierstruct pf_palist	 pf_pabuf;
147126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
148126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
149126258Smlaierstruct pf_status	 pf_status;
150126258Smlaier
151126258Smlaieru_int32_t		 ticket_altqs_active;
152126258Smlaieru_int32_t		 ticket_altqs_inactive;
153130613Smlaierint			 altqs_inactive_open;
154126258Smlaieru_int32_t		 ticket_pabuf;
155126258Smlaier
156127145Smlaier#ifdef __FreeBSD__
157126261Smlaierstruct callout	 	 pf_expire_to;			/* expire timeout */
158126261Smlaier#else
159126258Smlaierstruct timeout		 pf_expire_to;			/* expire timeout */
160126261Smlaier#endif
161126258Smlaier
162145836Smlaierstruct pf_anchor_stackframe {
163145836Smlaier	struct pf_ruleset			*rs;
164145836Smlaier	struct pf_rule				*r;
165145836Smlaier	struct pf_anchor_node			*parent;
166145836Smlaier	struct pf_anchor			*child;
167145836Smlaier} pf_anchor_stack[64];
168126261Smlaier
169127145Smlaier#ifdef __FreeBSD__
170130613Smlaieruma_zone_t		 pf_src_tree_pl, pf_rule_pl;
171126261Smlaieruma_zone_t		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
172126261Smlaier#else
173130613Smlaierstruct pool		 pf_src_tree_pl, pf_rule_pl;
174126258Smlaierstruct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
175126261Smlaier#endif
176126258Smlaier
177126258Smlaiervoid			 pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
178126258Smlaier
179145836Smlaiervoid			 pf_init_threshold(struct pf_threshold *, u_int32_t,
180145836Smlaier			    u_int32_t);
181145836Smlaiervoid			 pf_add_threshold(struct pf_threshold *);
182145836Smlaierint			 pf_check_threshold(struct pf_threshold *);
183145836Smlaier
184126258Smlaiervoid			 pf_change_ap(struct pf_addr *, u_int16_t *,
185126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
186126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
187126258Smlaier#ifdef INET6
188126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
189126258Smlaier			    struct pf_addr *, u_int8_t);
190126258Smlaier#endif /* INET6 */
191126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
192126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
193126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
194126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
195126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
196126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
197126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
198145836Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
199145836Smlaier			    struct ether_header *, struct ifnet *);
200126258Smlaiervoid			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
201126258Smlaier			    sa_family_t, struct pf_rule *);
202126258Smlaierstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
203130613Smlaier			    int, int, struct pfi_kif *,
204126258Smlaier			    struct pf_addr *, u_int16_t, struct pf_addr *,
205126258Smlaier			    u_int16_t, int);
206126258Smlaierstruct pf_rule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
207130613Smlaier			    int, int, struct pfi_kif *, struct pf_src_node **,
208126258Smlaier			    struct pf_addr *, u_int16_t,
209126258Smlaier			    struct pf_addr *, u_int16_t,
210126258Smlaier			    struct pf_addr *, u_int16_t *);
211126258Smlaierint			 pf_test_tcp(struct pf_rule **, struct pf_state **,
212130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
213126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
214135920Smlaier#ifdef __FreeBSD__
215145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
216145836Smlaier			    struct inpcb *);
217135920Smlaier#else
218145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
219135920Smlaier#endif
220126258Smlaierint			 pf_test_udp(struct pf_rule **, struct pf_state **,
221130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
222126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
223135920Smlaier#ifdef __FreeBSD__
224145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
225145836Smlaier			    struct inpcb *);
226135920Smlaier#else
227145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
228135920Smlaier#endif
229126258Smlaierint			 pf_test_icmp(struct pf_rule **, struct pf_state **,
230130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
231126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
232145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
233126258Smlaierint			 pf_test_other(struct pf_rule **, struct pf_state **,
234130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int, void *,
235126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
236145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
237126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
238130613Smlaier			    struct pfi_kif *, struct mbuf *, void *,
239126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
240126258Smlaier			    struct pf_ruleset **);
241126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
242130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
243126258Smlaier			    void *, struct pf_pdesc *, u_short *);
244126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
245130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
246126258Smlaier			    void *, struct pf_pdesc *);
247126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
248130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
249145836Smlaier			    void *, struct pf_pdesc *, u_short *);
250126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
251130613Smlaier			    struct pfi_kif *, struct pf_pdesc *);
252126258Smlaierstruct pf_tag		*pf_get_tag(struct mbuf *);
253126258Smlaierint			 pf_match_tag(struct mbuf *, struct pf_rule *,
254145836Smlaier			     struct pf_tag **, int *);
255126258Smlaiervoid			 pf_hash(struct pf_addr *, struct pf_addr *,
256126258Smlaier			    struct pf_poolhashkey *, sa_family_t);
257130613Smlaierint			 pf_map_addr(u_int8_t, struct pf_rule *,
258126258Smlaier			    struct pf_addr *, struct pf_addr *,
259130613Smlaier			    struct pf_addr *, struct pf_src_node **);
260130613Smlaierint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
261126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
262130613Smlaier			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
263130613Smlaier			    struct pf_src_node **);
264126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
265126258Smlaier			    struct ifnet *, struct pf_state *);
266126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
267126258Smlaier			    struct ifnet *, struct pf_state *);
268135920Smlaier#ifdef __FreeBSD__
269130613Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
270135920Smlaier			    int, struct pf_pdesc *, struct inpcb *);
271135920Smlaier#else
272135920Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
273126258Smlaier			    int, struct pf_pdesc *);
274135920Smlaier#endif
275126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
276126258Smlaier			    sa_family_t);
277126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
278126258Smlaier			    sa_family_t);
279126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
280126258Smlaier				u_int16_t);
281126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
282126258Smlaier			    struct pf_addr *);
283126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
284126258Smlaier			    u_int8_t, sa_family_t);
285126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
286126258Smlaier			    struct pf_addr_wrap *);
287130613Smlaierstatic int		 pf_add_mbuf_tag(struct mbuf *, u_int);
288130613Smlaierstruct pf_state		*pf_find_state_recurse(struct pfi_kif *,
289130613Smlaier			    struct pf_state *, u_int8_t);
290145836Smlaierint			 pf_src_connlimit(struct pf_state **);
291145836Smlaierint			 pf_check_congestion(struct ifqueue *);
292126258Smlaier
293127145Smlaier#ifdef __FreeBSD__
294126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
295126258Smlaier
296126261Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
297145836Smlaier
298126261Smlaier#else
299130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
300130613Smlaier	{ &pf_state_pl, PFSTATE_HIWAT },
301130613Smlaier	{ &pf_src_tree_pl, PFSNODE_HIWAT },
302130613Smlaier	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT }
303130613Smlaier};
304126261Smlaier#endif
305126258Smlaier
306126258Smlaier#define STATE_LOOKUP()							\
307126258Smlaier	do {								\
308126258Smlaier		if (direction == PF_IN)					\
309145836Smlaier			*state = pf_find_state_recurse(			\
310130613Smlaier			    kif, &key, PF_EXT_GWY);			\
311126258Smlaier		else							\
312145836Smlaier			*state = pf_find_state_recurse(			\
313130613Smlaier			    kif, &key, PF_LAN_EXT);			\
314145836Smlaier		if (*state == NULL || (*state)->timeout == PFTM_PURGE)	\
315126258Smlaier			return (PF_DROP);				\
316126258Smlaier		if (direction == PF_OUT &&				\
317126258Smlaier		    (((*state)->rule.ptr->rt == PF_ROUTETO &&		\
318126258Smlaier		    (*state)->rule.ptr->direction == PF_OUT) ||		\
319126258Smlaier		    ((*state)->rule.ptr->rt == PF_REPLYTO &&		\
320126258Smlaier		    (*state)->rule.ptr->direction == PF_IN)) &&		\
321130613Smlaier		    (*state)->rt_kif != NULL &&				\
322130613Smlaier		    (*state)->rt_kif != kif)				\
323126258Smlaier			return (PF_PASS);				\
324126258Smlaier	} while (0)
325126258Smlaier
326126258Smlaier#define	STATE_TRANSLATE(s) \
327126258Smlaier	(s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
328126258Smlaier	((s)->af == AF_INET6 && \
329126258Smlaier	((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
330126258Smlaier	(s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
331126258Smlaier	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
332126258Smlaier	(s)->lan.port != (s)->gwy.port
333126258Smlaier
334130613Smlaier#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) :   \
335130613Smlaier	((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent :	       \
336130613Smlaier	(k)->pfik_parent->pfik_parent)
337126258Smlaier
338145836Smlaier#define STATE_INC_COUNTERS(s)				\
339145836Smlaier	do {						\
340145836Smlaier		s->rule.ptr->states++;			\
341145836Smlaier		if (s->anchor.ptr != NULL)		\
342145836Smlaier			s->anchor.ptr->states++;	\
343145836Smlaier		if (s->nat_rule.ptr != NULL)		\
344145836Smlaier			s->nat_rule.ptr->states++;	\
345145836Smlaier	} while (0)
346145836Smlaier
347145836Smlaier#define STATE_DEC_COUNTERS(s)				\
348145836Smlaier	do {						\
349145836Smlaier		if (s->nat_rule.ptr != NULL)		\
350145836Smlaier			s->nat_rule.ptr->states--;	\
351145836Smlaier		if (s->anchor.ptr != NULL)		\
352145836Smlaier			s->anchor.ptr->states--;	\
353145836Smlaier		s->rule.ptr->states--;			\
354145836Smlaier	} while (0)
355145836Smlaier
356132767Skan#ifndef __FreeBSD__
357130613Smlaierstatic __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
358130613Smlaierstatic __inline int pf_state_compare_lan_ext(struct pf_state *,
359130613Smlaier	struct pf_state *);
360130613Smlaierstatic __inline int pf_state_compare_ext_gwy(struct pf_state *,
361130613Smlaier	struct pf_state *);
362130613Smlaierstatic __inline int pf_state_compare_id(struct pf_state *,
363130613Smlaier	struct pf_state *);
364145836Smlaierstatic __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
365132767Skan#else
366132767Skanstatic int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
367132767Skanstatic int pf_state_compare_lan_ext(struct pf_state *,
368132767Skan	struct pf_state *);
369132767Skanstatic int pf_state_compare_ext_gwy(struct pf_state *,
370132767Skan	struct pf_state *);
371132767Skanstatic int pf_state_compare_id(struct pf_state *,
372132767Skan	struct pf_state *);
373145836Smlaierstatic int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
374132767Skan#endif
375126258Smlaier
376130613Smlaierstruct pf_src_tree tree_src_tracking;
377130613Smlaier
378130613Smlaierstruct pf_state_tree_id tree_id;
379130613Smlaierstruct pf_state_queue state_updates;
380130613Smlaier
381130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
382130613SmlaierRB_GENERATE(pf_state_tree_lan_ext, pf_state,
383130613Smlaier    u.s.entry_lan_ext, pf_state_compare_lan_ext);
384130613SmlaierRB_GENERATE(pf_state_tree_ext_gwy, pf_state,
385130613Smlaier    u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
386130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state,
387130613Smlaier    u.s.entry_id, pf_state_compare_id);
388145836SmlaierRB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
389145836SmlaierRB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
390130613Smlaier
391127145Smlaier#ifdef __FreeBSD__
392126409Smlaierstatic int
393126409Smlaier#else
394126258Smlaierstatic __inline int
395126409Smlaier#endif
396130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
397126258Smlaier{
398126258Smlaier	int	diff;
399126258Smlaier
400130613Smlaier	if (a->rule.ptr > b->rule.ptr)
401130613Smlaier		return (1);
402130613Smlaier	if (a->rule.ptr < b->rule.ptr)
403130613Smlaier		return (-1);
404130613Smlaier	if ((diff = a->af - b->af) != 0)
405130613Smlaier		return (diff);
406130613Smlaier	switch (a->af) {
407130613Smlaier#ifdef INET
408130613Smlaier	case AF_INET:
409130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
410130613Smlaier			return (1);
411130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
412130613Smlaier			return (-1);
413130613Smlaier		break;
414130613Smlaier#endif /* INET */
415130613Smlaier#ifdef INET6
416130613Smlaier	case AF_INET6:
417130613Smlaier		if (a->addr.addr32[3] > b->addr.addr32[3])
418130613Smlaier			return (1);
419130613Smlaier		if (a->addr.addr32[3] < b->addr.addr32[3])
420130613Smlaier			return (-1);
421130613Smlaier		if (a->addr.addr32[2] > b->addr.addr32[2])
422130613Smlaier			return (1);
423130613Smlaier		if (a->addr.addr32[2] < b->addr.addr32[2])
424130613Smlaier			return (-1);
425130613Smlaier		if (a->addr.addr32[1] > b->addr.addr32[1])
426130613Smlaier			return (1);
427130613Smlaier		if (a->addr.addr32[1] < b->addr.addr32[1])
428130613Smlaier			return (-1);
429130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
430130613Smlaier			return (1);
431130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
432130613Smlaier			return (-1);
433130613Smlaier		break;
434130613Smlaier#endif /* INET6 */
435130613Smlaier	}
436130613Smlaier	return (0);
437130613Smlaier}
438130613Smlaier
439130613Smlaier#ifdef __FreeBSD__
440130613Smlaierstatic int
441130613Smlaier#else
442130613Smlaierstatic __inline int
443130613Smlaier#endif
444130613Smlaierpf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
445130613Smlaier{
446130613Smlaier	int	diff;
447130613Smlaier
448126258Smlaier	if ((diff = a->proto - b->proto) != 0)
449126258Smlaier		return (diff);
450126258Smlaier	if ((diff = a->af - b->af) != 0)
451126258Smlaier		return (diff);
452126258Smlaier	switch (a->af) {
453126258Smlaier#ifdef INET
454126258Smlaier	case AF_INET:
455130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
456126258Smlaier			return (1);
457130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
458126258Smlaier			return (-1);
459130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
460126258Smlaier			return (1);
461130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
462126258Smlaier			return (-1);
463126258Smlaier		break;
464126258Smlaier#endif /* INET */
465126258Smlaier#ifdef INET6
466126258Smlaier	case AF_INET6:
467130613Smlaier		if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3])
468126258Smlaier			return (1);
469130613Smlaier		if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3])
470126258Smlaier			return (-1);
471130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
472126258Smlaier			return (1);
473130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
474126258Smlaier			return (-1);
475130613Smlaier		if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2])
476126258Smlaier			return (1);
477130613Smlaier		if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2])
478126258Smlaier			return (-1);
479130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
480126258Smlaier			return (1);
481130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
482126258Smlaier			return (-1);
483130613Smlaier		if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1])
484126258Smlaier			return (1);
485130613Smlaier		if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1])
486126258Smlaier			return (-1);
487130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
488126258Smlaier			return (1);
489130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
490126258Smlaier			return (-1);
491130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
492126258Smlaier			return (1);
493130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
494126258Smlaier			return (-1);
495130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
496126258Smlaier			return (1);
497130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
498126258Smlaier			return (-1);
499126258Smlaier		break;
500126258Smlaier#endif /* INET6 */
501126258Smlaier	}
502126258Smlaier
503130613Smlaier	if ((diff = a->lan.port - b->lan.port) != 0)
504126258Smlaier		return (diff);
505130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
506126258Smlaier		return (diff);
507126258Smlaier
508126258Smlaier	return (0);
509126258Smlaier}
510126258Smlaier
511130613Smlaier#ifdef __FreeBSD__
512130613Smlaierstatic int
513130613Smlaier#else
514130613Smlaierstatic __inline int
515130613Smlaier#endif
516130613Smlaierpf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
517130613Smlaier{
518130613Smlaier	int	diff;
519130613Smlaier
520130613Smlaier	if ((diff = a->proto - b->proto) != 0)
521130613Smlaier		return (diff);
522130613Smlaier	if ((diff = a->af - b->af) != 0)
523130613Smlaier		return (diff);
524130613Smlaier	switch (a->af) {
525130613Smlaier#ifdef INET
526130613Smlaier	case AF_INET:
527130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
528130613Smlaier			return (1);
529130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
530130613Smlaier			return (-1);
531130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
532130613Smlaier			return (1);
533130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
534130613Smlaier			return (-1);
535130613Smlaier		break;
536130613Smlaier#endif /* INET */
537126258Smlaier#ifdef INET6
538130613Smlaier	case AF_INET6:
539130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
540130613Smlaier			return (1);
541130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
542130613Smlaier			return (-1);
543130613Smlaier		if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3])
544130613Smlaier			return (1);
545130613Smlaier		if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3])
546130613Smlaier			return (-1);
547130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
548130613Smlaier			return (1);
549130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
550130613Smlaier			return (-1);
551130613Smlaier		if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2])
552130613Smlaier			return (1);
553130613Smlaier		if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2])
554130613Smlaier			return (-1);
555130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
556130613Smlaier			return (1);
557130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
558130613Smlaier			return (-1);
559130613Smlaier		if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1])
560130613Smlaier			return (1);
561130613Smlaier		if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1])
562130613Smlaier			return (-1);
563130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
564130613Smlaier			return (1);
565130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
566130613Smlaier			return (-1);
567130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
568130613Smlaier			return (1);
569130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
570130613Smlaier			return (-1);
571130613Smlaier		break;
572130613Smlaier#endif /* INET6 */
573130613Smlaier	}
574130613Smlaier
575130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
576130613Smlaier		return (diff);
577130613Smlaier	if ((diff = a->gwy.port - b->gwy.port) != 0)
578130613Smlaier		return (diff);
579130613Smlaier
580130613Smlaier	return (0);
581130613Smlaier}
582130613Smlaier
583130613Smlaier#ifdef __FreeBSD__
584130613Smlaierstatic int
585130613Smlaier#else
586130613Smlaierstatic __inline int
587130613Smlaier#endif
588130613Smlaierpf_state_compare_id(struct pf_state *a, struct pf_state *b)
589130613Smlaier{
590130613Smlaier	if (a->id > b->id)
591130613Smlaier		return (1);
592130613Smlaier	if (a->id < b->id)
593130613Smlaier		return (-1);
594130613Smlaier	if (a->creatorid > b->creatorid)
595130613Smlaier		return (1);
596130613Smlaier	if (a->creatorid < b->creatorid)
597130613Smlaier		return (-1);
598130613Smlaier
599130613Smlaier	return (0);
600130613Smlaier}
601130613Smlaier
602145836Smlaier#ifdef __FreeBSD__
603145836Smlaierstatic int
604145836Smlaier#else
605145836Smlaierstatic __inline int
606145836Smlaier#endif
607145836Smlaierpf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
608145836Smlaier{
609145836Smlaier	int c = strcmp(a->path, b->path);
610145836Smlaier
611145836Smlaier	return (c ? (c < 0 ? -1 : 1) : 0);
612145836Smlaier}
613145836Smlaier
614130613Smlaier#ifdef INET6
615126258Smlaiervoid
616126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
617126258Smlaier{
618126258Smlaier	switch (af) {
619126258Smlaier#ifdef INET
620126258Smlaier	case AF_INET:
621126258Smlaier		dst->addr32[0] = src->addr32[0];
622126258Smlaier		break;
623126258Smlaier#endif /* INET */
624126258Smlaier	case AF_INET6:
625126258Smlaier		dst->addr32[0] = src->addr32[0];
626126258Smlaier		dst->addr32[1] = src->addr32[1];
627126258Smlaier		dst->addr32[2] = src->addr32[2];
628126258Smlaier		dst->addr32[3] = src->addr32[3];
629126258Smlaier		break;
630126258Smlaier	}
631126258Smlaier}
632145836Smlaier#endif /* INET6 */
633126258Smlaier
634126258Smlaierstruct pf_state *
635130613Smlaierpf_find_state_byid(struct pf_state *key)
636126258Smlaier{
637130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
638130613Smlaier	return (RB_FIND(pf_state_tree_id, &tree_id, key));
639130613Smlaier}
640126258Smlaier
641130613Smlaierstruct pf_state *
642130613Smlaierpf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree)
643130613Smlaier{
644130613Smlaier	struct pf_state *s;
645130613Smlaier
646126258Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
647130613Smlaier
648130613Smlaier	switch (tree) {
649130613Smlaier	case PF_LAN_EXT:
650130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
651130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
652130613Smlaier			    &kif->pfik_lan_ext, key);
653130613Smlaier			if (s != NULL)
654130613Smlaier				return (s);
655130613Smlaier		}
656126258Smlaier		return (NULL);
657130613Smlaier	case PF_EXT_GWY:
658130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
659130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
660130613Smlaier			    &kif->pfik_ext_gwy, key);
661130613Smlaier			if (s != NULL)
662130613Smlaier				return (s);
663130613Smlaier		}
664130613Smlaier		return (NULL);
665130613Smlaier	default:
666130613Smlaier		panic("pf_find_state_recurse");
667130613Smlaier	}
668126258Smlaier}
669126258Smlaier
670130613Smlaierstruct pf_state *
671130613Smlaierpf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
672130613Smlaier{
673130613Smlaier	struct pf_state *s, *ss = NULL;
674130613Smlaier	struct pfi_kif	*kif;
675130613Smlaier
676130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
677130613Smlaier
678130613Smlaier	switch (tree) {
679130613Smlaier	case PF_LAN_EXT:
680130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
681130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
682130613Smlaier			    &kif->pfik_lan_ext, key);
683130613Smlaier			if (s == NULL)
684130613Smlaier				continue;
685130613Smlaier			if (more == NULL)
686130613Smlaier				return (s);
687130613Smlaier			ss = s;
688130613Smlaier			(*more)++;
689130613Smlaier		}
690130613Smlaier		return (ss);
691130613Smlaier	case PF_EXT_GWY:
692130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
693130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
694130613Smlaier			    &kif->pfik_ext_gwy, key);
695130613Smlaier			if (s == NULL)
696130613Smlaier				continue;
697130613Smlaier			if (more == NULL)
698130613Smlaier				return (s);
699130613Smlaier			ss = s;
700130613Smlaier			(*more)++;
701130613Smlaier		}
702130613Smlaier		return (ss);
703130613Smlaier	default:
704130613Smlaier		panic("pf_find_state_all");
705130613Smlaier	}
706130613Smlaier}
707130613Smlaier
708145836Smlaiervoid
709145836Smlaierpf_init_threshold(struct pf_threshold *threshold,
710145836Smlaier    u_int32_t limit, u_int32_t seconds)
711145836Smlaier{
712145836Smlaier	threshold->limit = limit * PF_THRESHOLD_MULT;
713145836Smlaier	threshold->seconds = seconds;
714145836Smlaier	threshold->count = 0;
715145836Smlaier	threshold->last = time_second;
716145836Smlaier}
717145836Smlaier
718145836Smlaiervoid
719145836Smlaierpf_add_threshold(struct pf_threshold *threshold)
720145836Smlaier{
721145836Smlaier	u_int32_t t = time_second, diff = t - threshold->last;
722145836Smlaier
723145836Smlaier	if (diff >= threshold->seconds)
724145836Smlaier		threshold->count = 0;
725145836Smlaier	else
726145836Smlaier		threshold->count -= threshold->count * diff /
727145836Smlaier		    threshold->seconds;
728145836Smlaier	threshold->count += PF_THRESHOLD_MULT;
729145836Smlaier	threshold->last = t;
730145836Smlaier}
731145836Smlaier
732126258Smlaierint
733145836Smlaierpf_check_threshold(struct pf_threshold *threshold)
734145836Smlaier{
735145836Smlaier	return (threshold->count > threshold->limit);
736145836Smlaier}
737145836Smlaier
738145836Smlaierint
739145836Smlaierpf_src_connlimit(struct pf_state **state)
740145836Smlaier{
741145836Smlaier	struct pf_state	*s;
742145836Smlaier	int bad = 0;
743145836Smlaier
744145836Smlaier	(*state)->src_node->conn++;
745145836Smlaier	pf_add_threshold(&(*state)->src_node->conn_rate);
746145836Smlaier
747145836Smlaier	if ((*state)->rule.ptr->max_src_conn &&
748145836Smlaier	    (*state)->rule.ptr->max_src_conn <
749145836Smlaier	    (*state)->src_node->conn) {
750145836Smlaier		pf_status.lcounters[LCNT_SRCCONN]++;
751145836Smlaier		bad++;
752145836Smlaier	}
753145836Smlaier
754145836Smlaier	if ((*state)->rule.ptr->max_src_conn_rate.limit &&
755145836Smlaier	    pf_check_threshold(&(*state)->src_node->conn_rate)) {
756145836Smlaier		pf_status.lcounters[LCNT_SRCCONNRATE]++;
757145836Smlaier		bad++;
758145836Smlaier	}
759145836Smlaier
760145836Smlaier	if (!bad)
761145836Smlaier		return (0);
762145836Smlaier
763145836Smlaier	if ((*state)->rule.ptr->overload_tbl) {
764145836Smlaier		struct pfr_addr p;
765145836Smlaier		u_int32_t	killed = 0;
766145836Smlaier
767145836Smlaier		pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
768145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
769145836Smlaier			printf("pf_src_connlimit: blocking address ");
770145836Smlaier			pf_print_host(&(*state)->src_node->addr, 0,
771145836Smlaier			    (*state)->af);
772145836Smlaier		}
773145836Smlaier
774145836Smlaier		bzero(&p, sizeof(p));
775145836Smlaier		p.pfra_af = (*state)->af;
776145836Smlaier		switch ((*state)->af) {
777145836Smlaier#ifdef INET
778145836Smlaier		case AF_INET:
779145836Smlaier			p.pfra_net = 32;
780145836Smlaier			p.pfra_ip4addr = (*state)->src_node->addr.v4;
781145836Smlaier			break;
782145836Smlaier#endif /* INET */
783145836Smlaier#ifdef INET6
784145836Smlaier		case AF_INET6:
785145836Smlaier			p.pfra_net = 128;
786145836Smlaier			p.pfra_ip6addr = (*state)->src_node->addr.v6;
787145836Smlaier			break;
788145836Smlaier#endif /* INET6 */
789145836Smlaier		}
790145836Smlaier
791145836Smlaier		pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
792145836Smlaier		    &p, time_second);
793145836Smlaier
794145836Smlaier		/* kill existing states if that's required. */
795145836Smlaier		if ((*state)->rule.ptr->flush) {
796145836Smlaier			pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
797145836Smlaier
798145836Smlaier			RB_FOREACH(s, pf_state_tree_id, &tree_id) {
799145836Smlaier				/*
800145836Smlaier				 * Kill states from this source.  (Only those
801145836Smlaier				 * from the same rule if PF_FLUSH_GLOBAL is not
802145836Smlaier				 * set)
803145836Smlaier				 */
804145836Smlaier				if (s->af == (*state)->af &&
805145836Smlaier				    (((*state)->direction == PF_OUT &&
806145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
807145836Smlaier				    &s->lan.addr, s->af)) ||
808145836Smlaier				    ((*state)->direction == PF_IN &&
809145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
810145836Smlaier				    &s->ext.addr, s->af))) &&
811145836Smlaier				    ((*state)->rule.ptr->flush &
812145836Smlaier				    PF_FLUSH_GLOBAL ||
813145836Smlaier				    (*state)->rule.ptr == s->rule.ptr)) {
814145836Smlaier					s->timeout = PFTM_PURGE;
815145836Smlaier					s->src.state = s->dst.state =
816145836Smlaier					    TCPS_CLOSED;
817145836Smlaier					killed++;
818145836Smlaier				}
819145836Smlaier			}
820145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
821145836Smlaier				printf(", %u states killed", killed);
822145836Smlaier		}
823145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
824145836Smlaier			printf("\n");
825145836Smlaier	}
826145836Smlaier
827145836Smlaier	/* kill this state */
828145836Smlaier	(*state)->timeout = PFTM_PURGE;
829145836Smlaier	(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
830145836Smlaier	return (1);
831145836Smlaier}
832145836Smlaier
833145836Smlaierint
834130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
835130613Smlaier    struct pf_addr *src, sa_family_t af)
836126258Smlaier{
837130613Smlaier	struct pf_src_node	k;
838126258Smlaier
839130613Smlaier	if (*sn == NULL) {
840130613Smlaier		k.af = af;
841130613Smlaier		PF_ACPY(&k.addr, src, af);
842130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
843130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
844130613Smlaier			k.rule.ptr = rule;
845130613Smlaier		else
846130613Smlaier			k.rule.ptr = NULL;
847130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
848130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
849130613Smlaier	}
850130613Smlaier	if (*sn == NULL) {
851130613Smlaier		if (!rule->max_src_nodes ||
852130613Smlaier		    rule->src_nodes < rule->max_src_nodes)
853130613Smlaier			(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
854145836Smlaier		else
855145836Smlaier			pf_status.lcounters[LCNT_SRCNODES]++;
856130613Smlaier		if ((*sn) == NULL)
857130613Smlaier			return (-1);
858130613Smlaier		bzero(*sn, sizeof(struct pf_src_node));
859145836Smlaier
860145836Smlaier		pf_init_threshold(&(*sn)->conn_rate,
861145836Smlaier		    rule->max_src_conn_rate.limit,
862145836Smlaier		    rule->max_src_conn_rate.seconds);
863145836Smlaier
864130613Smlaier		(*sn)->af = af;
865130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
866130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
867130613Smlaier			(*sn)->rule.ptr = rule;
868130613Smlaier		else
869130613Smlaier			(*sn)->rule.ptr = NULL;
870130613Smlaier		PF_ACPY(&(*sn)->addr, src, af);
871130613Smlaier		if (RB_INSERT(pf_src_tree,
872130613Smlaier		    &tree_src_tracking, *sn) != NULL) {
873130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
874130613Smlaier				printf("pf: src_tree insert failed: ");
875130613Smlaier				pf_print_host(&(*sn)->addr, 0, af);
876130613Smlaier				printf("\n");
877130613Smlaier			}
878130613Smlaier			pool_put(&pf_src_tree_pl, *sn);
879130613Smlaier			return (-1);
880130613Smlaier		}
881130613Smlaier		(*sn)->creation = time_second;
882130613Smlaier		(*sn)->ruletype = rule->action;
883130613Smlaier		if ((*sn)->rule.ptr != NULL)
884130613Smlaier			(*sn)->rule.ptr->src_nodes++;
885130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
886130613Smlaier		pf_status.src_nodes++;
887130613Smlaier	} else {
888130613Smlaier		if (rule->max_src_states &&
889145836Smlaier		    (*sn)->states >= rule->max_src_states) {
890145836Smlaier			pf_status.lcounters[LCNT_SRCSTATES]++;
891130613Smlaier			return (-1);
892145836Smlaier		}
893130613Smlaier	}
894130613Smlaier	return (0);
895130613Smlaier}
896126258Smlaier
897130613Smlaierint
898130613Smlaierpf_insert_state(struct pfi_kif *kif, struct pf_state *state)
899130613Smlaier{
900126258Smlaier	/* Thou MUST NOT insert multiple duplicate keys */
901130613Smlaier	state->u.s.kif = kif;
902130613Smlaier	if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
903126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
904126258Smlaier			printf("pf: state insert failed: tree_lan_ext");
905126258Smlaier			printf(" lan: ");
906126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
907126258Smlaier			    state->af);
908126258Smlaier			printf(" gwy: ");
909126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
910126258Smlaier			    state->af);
911126258Smlaier			printf(" ext: ");
912126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
913126258Smlaier			    state->af);
914130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
915130613Smlaier				printf(" (from sync)");
916126258Smlaier			printf("\n");
917126258Smlaier		}
918126258Smlaier		return (-1);
919126258Smlaier	}
920126258Smlaier
921130613Smlaier	if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
922126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
923126258Smlaier			printf("pf: state insert failed: tree_ext_gwy");
924126258Smlaier			printf(" lan: ");
925126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
926126258Smlaier			    state->af);
927126258Smlaier			printf(" gwy: ");
928126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
929126258Smlaier			    state->af);
930126258Smlaier			printf(" ext: ");
931126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
932126258Smlaier			    state->af);
933130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
934130613Smlaier				printf(" (from sync)");
935126258Smlaier			printf("\n");
936126258Smlaier		}
937130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
938126258Smlaier		return (-1);
939126258Smlaier	}
940126258Smlaier
941130613Smlaier	if (state->id == 0 && state->creatorid == 0) {
942130613Smlaier		state->id = htobe64(pf_status.stateid++);
943130613Smlaier		state->creatorid = pf_status.hostid;
944130613Smlaier	}
945130613Smlaier	if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
946130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
947130613Smlaier#ifdef __FreeBSD__
948130613Smlaier			printf("pf: state insert failed: "
949130613Smlaier			    "id: %016llx creatorid: %08x",
950130613Smlaier			    (long long)be64toh(state->id),
951130613Smlaier			    ntohl(state->creatorid));
952130613Smlaier#else
953130613Smlaier			printf("pf: state insert failed: "
954130613Smlaier			    "id: %016llx creatorid: %08x",
955130613Smlaier			    betoh64(state->id), ntohl(state->creatorid));
956130613Smlaier#endif
957130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
958130613Smlaier				printf(" (from sync)");
959130613Smlaier			printf("\n");
960130613Smlaier		}
961130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
962130613Smlaier		RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
963130613Smlaier		return (-1);
964130613Smlaier	}
965130613Smlaier	TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates);
966130613Smlaier
967126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
968126258Smlaier	pf_status.states++;
969130613Smlaier	pfi_attach_state(kif);
970126258Smlaier#if NPFSYNC
971126258Smlaier	pfsync_insert_state(state);
972126258Smlaier#endif
973126258Smlaier	return (0);
974126258Smlaier}
975126258Smlaier
976126258Smlaiervoid
977126258Smlaierpf_purge_timeout(void *arg)
978126258Smlaier{
979127145Smlaier#ifdef __FreeBSD__
980126261Smlaier	struct callout  *to = arg;
981126261Smlaier#else
982126258Smlaier	struct timeout	*to = arg;
983126261Smlaier#endif
984126258Smlaier	int		 s;
985126258Smlaier
986127145Smlaier#ifdef __FreeBSD__
987126261Smlaier	PF_LOCK();
988126261Smlaier#endif
989126258Smlaier	s = splsoftnet();
990126258Smlaier	pf_purge_expired_states();
991126258Smlaier	pf_purge_expired_fragments();
992130613Smlaier	pf_purge_expired_src_nodes();
993126258Smlaier	splx(s);
994127145Smlaier#ifdef __FreeBSD__
995126261Smlaier	PF_UNLOCK();
996126261Smlaier#endif
997126258Smlaier
998127145Smlaier#ifdef __FreeBSD__
999126261Smlaier	callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz,
1000126261Smlaier	    pf_purge_timeout, to);
1001126261Smlaier#else
1002126258Smlaier	timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
1003126261Smlaier#endif
1004126258Smlaier}
1005126258Smlaier
1006126258Smlaieru_int32_t
1007126258Smlaierpf_state_expires(const struct pf_state *state)
1008126258Smlaier{
1009126258Smlaier	u_int32_t	timeout;
1010126258Smlaier	u_int32_t	start;
1011126258Smlaier	u_int32_t	end;
1012126258Smlaier	u_int32_t	states;
1013126258Smlaier
1014126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
1015126258Smlaier	if (state->timeout == PFTM_PURGE)
1016126261Smlaier		return (time_second);
1017126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
1018126258Smlaier		return (0);
1019127145Smlaier#ifdef __FreeBSD__
1020126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
1021126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
1022126261Smlaier#else
1023126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
1024126261Smlaier#endif
1025126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
1026126258Smlaier	if (!timeout)
1027126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
1028126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
1029126258Smlaier	if (start) {
1030126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
1031126258Smlaier		states = state->rule.ptr->states;
1032126258Smlaier	} else {
1033126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1034126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1035126258Smlaier		states = pf_status.states;
1036126258Smlaier	}
1037126258Smlaier	if (end && states > start && start < end) {
1038126258Smlaier		if (states < end)
1039126258Smlaier			return (state->expire + timeout * (end - states) /
1040126258Smlaier			    (end - start));
1041126258Smlaier		else
1042126261Smlaier			return (time_second);
1043126258Smlaier	}
1044126258Smlaier	return (state->expire + timeout);
1045126258Smlaier}
1046126258Smlaier
1047126258Smlaiervoid
1048130613Smlaierpf_purge_expired_src_nodes(void)
1049126258Smlaier{
1050130613Smlaier	 struct pf_src_node		*cur, *next;
1051126258Smlaier
1052130613Smlaier	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
1053130613Smlaier		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
1054126258Smlaier
1055130613Smlaier		 if (cur->states <= 0 && cur->expire <= time_second) {
1056130613Smlaier			 if (cur->rule.ptr != NULL) {
1057130613Smlaier				 cur->rule.ptr->src_nodes--;
1058130613Smlaier				 if (cur->rule.ptr->states <= 0 &&
1059130613Smlaier				     cur->rule.ptr->max_src_nodes <= 0)
1060130613Smlaier					 pf_rm_rule(NULL, cur->rule.ptr);
1061130613Smlaier			 }
1062130613Smlaier			 RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
1063130613Smlaier			 pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1064130613Smlaier			 pf_status.src_nodes--;
1065130613Smlaier			 pool_put(&pf_src_tree_pl, cur);
1066130613Smlaier		 }
1067130613Smlaier	 }
1068130613Smlaier}
1069126258Smlaier
1070130613Smlaiervoid
1071130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
1072130613Smlaier{
1073130613Smlaier	u_int32_t timeout;
1074126258Smlaier
1075130613Smlaier	if (s->src_node != NULL) {
1076145836Smlaier		if (s->proto == IPPROTO_TCP) {
1077145836Smlaier			if (s->src.state == PF_TCPS_PROXY_DST ||
1078145836Smlaier			    s->timeout >= PFTM_TCP_ESTABLISHED)
1079145836Smlaier				--s->src_node->conn;
1080145836Smlaier		}
1081130613Smlaier		if (--s->src_node->states <= 0) {
1082130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1083130613Smlaier			if (!timeout)
1084130613Smlaier				timeout =
1085130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1086130613Smlaier			s->src_node->expire = time_second + timeout;
1087130613Smlaier		}
1088130613Smlaier	}
1089130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
1090130613Smlaier		if (--s->nat_src_node->states <= 0) {
1091130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1092130613Smlaier			if (!timeout)
1093130613Smlaier				timeout =
1094130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1095130613Smlaier			s->nat_src_node->expire = time_second + timeout;
1096130613Smlaier		}
1097130613Smlaier	}
1098130613Smlaier	s->src_node = s->nat_src_node = NULL;
1099130613Smlaier}
1100126258Smlaier
1101130613Smlaiervoid
1102145836Smlaierpf_purge_expired_state(struct pf_state *cur)
1103145836Smlaier{
1104148196Smlaier#ifdef __FreeBSD__
1105153545Smlaier	if (cur->local_flags & PFSTATE_EXPIRING)
1106148196Smlaier		return;
1107153545Smlaier	cur->local_flags |= PFSTATE_EXPIRING;
1108148196Smlaier#endif
1109145836Smlaier	if (cur->src.state == PF_TCPS_PROXY_DST)
1110145836Smlaier		pf_send_tcp(cur->rule.ptr, cur->af,
1111145836Smlaier		    &cur->ext.addr, &cur->lan.addr,
1112145836Smlaier		    cur->ext.port, cur->lan.port,
1113145836Smlaier		    cur->src.seqhi, cur->src.seqlo + 1,
1114145836Smlaier		    TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL);
1115145836Smlaier	RB_REMOVE(pf_state_tree_ext_gwy,
1116145836Smlaier	    &cur->u.s.kif->pfik_ext_gwy, cur);
1117145836Smlaier	RB_REMOVE(pf_state_tree_lan_ext,
1118145836Smlaier	    &cur->u.s.kif->pfik_lan_ext, cur);
1119145836Smlaier	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
1120145836Smlaier#if NPFSYNC
1121145836Smlaier	pfsync_delete_state(cur);
1122145836Smlaier#endif
1123145836Smlaier	pf_src_tree_remove_state(cur);
1124145836Smlaier	if (--cur->rule.ptr->states <= 0 &&
1125145836Smlaier	    cur->rule.ptr->src_nodes <= 0)
1126145836Smlaier		pf_rm_rule(NULL, cur->rule.ptr);
1127145836Smlaier	if (cur->nat_rule.ptr != NULL)
1128145836Smlaier		if (--cur->nat_rule.ptr->states <= 0 &&
1129145836Smlaier			cur->nat_rule.ptr->src_nodes <= 0)
1130145836Smlaier			pf_rm_rule(NULL, cur->nat_rule.ptr);
1131145836Smlaier	if (cur->anchor.ptr != NULL)
1132145836Smlaier		if (--cur->anchor.ptr->states <= 0)
1133145836Smlaier			pf_rm_rule(NULL, cur->anchor.ptr);
1134145836Smlaier	pf_normalize_tcp_cleanup(cur);
1135145836Smlaier	pfi_detach_state(cur->u.s.kif);
1136145836Smlaier	TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
1137145836Smlaier	if (cur->tag)
1138145836Smlaier		pf_tag_unref(cur->tag);
1139145836Smlaier	pool_put(&pf_state_pl, cur);
1140145836Smlaier	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1141145836Smlaier	pf_status.states--;
1142145836Smlaier}
1143145836Smlaier
1144145836Smlaiervoid
1145130613Smlaierpf_purge_expired_states(void)
1146130613Smlaier{
1147130613Smlaier	struct pf_state		*cur, *next;
1148130613Smlaier
1149130613Smlaier	for (cur = RB_MIN(pf_state_tree_id, &tree_id);
1150130613Smlaier	    cur; cur = next) {
1151130613Smlaier		next = RB_NEXT(pf_state_tree_id, &tree_id, cur);
1152145836Smlaier		if (pf_state_expires(cur) <= time_second)
1153145836Smlaier			pf_purge_expired_state(cur);
1154126258Smlaier	}
1155126258Smlaier}
1156126258Smlaier
1157126258Smlaierint
1158126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
1159126258Smlaier{
1160126258Smlaier	if (aw->type != PF_ADDR_TABLE)
1161126258Smlaier		return (0);
1162126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
1163126258Smlaier		return (1);
1164126258Smlaier	return (0);
1165126258Smlaier}
1166126258Smlaier
1167126258Smlaiervoid
1168126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
1169126258Smlaier{
1170126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
1171126258Smlaier		return;
1172126258Smlaier	pfr_detach_table(aw->p.tbl);
1173126258Smlaier	aw->p.tbl = NULL;
1174126258Smlaier}
1175126258Smlaier
1176126258Smlaiervoid
1177126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
1178126258Smlaier{
1179126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
1180126258Smlaier
1181126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
1182126258Smlaier		return;
1183126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
1184126258Smlaier		kt = kt->pfrkt_root;
1185126258Smlaier	aw->p.tbl = NULL;
1186126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1187126258Smlaier		kt->pfrkt_cnt : -1;
1188126258Smlaier}
1189126258Smlaier
1190126258Smlaiervoid
1191126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1192126258Smlaier{
1193126258Smlaier	switch (af) {
1194126258Smlaier#ifdef INET
1195126258Smlaier	case AF_INET: {
1196126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1197126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1198126258Smlaier		    (a>>8)&255, a&255);
1199126258Smlaier		if (p) {
1200126258Smlaier			p = ntohs(p);
1201126258Smlaier			printf(":%u", p);
1202126258Smlaier		}
1203126258Smlaier		break;
1204126258Smlaier	}
1205126258Smlaier#endif /* INET */
1206126258Smlaier#ifdef INET6
1207126258Smlaier	case AF_INET6: {
1208126258Smlaier		u_int16_t b;
1209126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
1210126258Smlaier		    maxstart = 0, maxend = 0;
1211126258Smlaier		for (i = 0; i < 8; i++) {
1212126258Smlaier			if (!addr->addr16[i]) {
1213126258Smlaier				if (curstart == 255)
1214126258Smlaier					curstart = i;
1215126258Smlaier				else
1216126258Smlaier					curend = i;
1217126258Smlaier			} else {
1218126258Smlaier				if (curstart) {
1219126258Smlaier					if ((curend - curstart) >
1220126258Smlaier					    (maxend - maxstart)) {
1221126258Smlaier						maxstart = curstart;
1222126258Smlaier						maxend = curend;
1223126258Smlaier						curstart = 255;
1224126258Smlaier					}
1225126258Smlaier				}
1226126258Smlaier			}
1227126258Smlaier		}
1228126258Smlaier		for (i = 0; i < 8; i++) {
1229126258Smlaier			if (i >= maxstart && i <= maxend) {
1230126258Smlaier				if (maxend != 7) {
1231126258Smlaier					if (i == maxstart)
1232126258Smlaier						printf(":");
1233126258Smlaier				} else {
1234126258Smlaier					if (i == maxend)
1235126258Smlaier						printf(":");
1236126258Smlaier				}
1237126258Smlaier			} else {
1238126258Smlaier				b = ntohs(addr->addr16[i]);
1239126258Smlaier				printf("%x", b);
1240126258Smlaier				if (i < 7)
1241126258Smlaier					printf(":");
1242126258Smlaier			}
1243126258Smlaier		}
1244126258Smlaier		if (p) {
1245126258Smlaier			p = ntohs(p);
1246126258Smlaier			printf("[%u]", p);
1247126258Smlaier		}
1248126258Smlaier		break;
1249126258Smlaier	}
1250126258Smlaier#endif /* INET6 */
1251126258Smlaier	}
1252126258Smlaier}
1253126258Smlaier
1254126258Smlaiervoid
1255126258Smlaierpf_print_state(struct pf_state *s)
1256126258Smlaier{
1257126258Smlaier	switch (s->proto) {
1258126258Smlaier	case IPPROTO_TCP:
1259126258Smlaier		printf("TCP ");
1260126258Smlaier		break;
1261126258Smlaier	case IPPROTO_UDP:
1262126258Smlaier		printf("UDP ");
1263126258Smlaier		break;
1264126258Smlaier	case IPPROTO_ICMP:
1265126258Smlaier		printf("ICMP ");
1266126258Smlaier		break;
1267126258Smlaier	case IPPROTO_ICMPV6:
1268126258Smlaier		printf("ICMPV6 ");
1269126258Smlaier		break;
1270126258Smlaier	default:
1271126258Smlaier		printf("%u ", s->proto);
1272126258Smlaier		break;
1273126258Smlaier	}
1274126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
1275126258Smlaier	printf(" ");
1276126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
1277126258Smlaier	printf(" ");
1278126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
1279126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
1280126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
1281126258Smlaier	if (s->src.wscale && s->dst.wscale)
1282126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
1283126258Smlaier	printf("]");
1284126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
1285126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
1286126258Smlaier	if (s->src.wscale && s->dst.wscale)
1287126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
1288126258Smlaier	printf("]");
1289126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
1290126258Smlaier}
1291126258Smlaier
1292126258Smlaiervoid
1293126258Smlaierpf_print_flags(u_int8_t f)
1294126258Smlaier{
1295126258Smlaier	if (f)
1296126258Smlaier		printf(" ");
1297126258Smlaier	if (f & TH_FIN)
1298126258Smlaier		printf("F");
1299126258Smlaier	if (f & TH_SYN)
1300126258Smlaier		printf("S");
1301126258Smlaier	if (f & TH_RST)
1302126258Smlaier		printf("R");
1303126258Smlaier	if (f & TH_PUSH)
1304126258Smlaier		printf("P");
1305126258Smlaier	if (f & TH_ACK)
1306126258Smlaier		printf("A");
1307126258Smlaier	if (f & TH_URG)
1308126258Smlaier		printf("U");
1309126258Smlaier	if (f & TH_ECE)
1310126258Smlaier		printf("E");
1311126258Smlaier	if (f & TH_CWR)
1312126258Smlaier		printf("W");
1313126258Smlaier}
1314126258Smlaier
1315126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1316126258Smlaier	do {							\
1317126258Smlaier		while (head[i] != cur) {			\
1318126258Smlaier			head[i]->skip[i].ptr = cur;		\
1319126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1320126258Smlaier		}						\
1321126258Smlaier	} while (0)
1322126258Smlaier
1323126258Smlaiervoid
1324126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1325126258Smlaier{
1326126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1327126258Smlaier	int i;
1328126258Smlaier
1329126258Smlaier	cur = TAILQ_FIRST(rules);
1330126258Smlaier	prev = cur;
1331126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1332126258Smlaier		head[i] = cur;
1333126258Smlaier	while (cur != NULL) {
1334126258Smlaier
1335130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1336126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1337126258Smlaier		if (cur->direction != prev->direction)
1338126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1339126258Smlaier		if (cur->af != prev->af)
1340126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1341126258Smlaier		if (cur->proto != prev->proto)
1342126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1343145836Smlaier		if (cur->src.neg != prev->src.neg ||
1344126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1345126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1346126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1347126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1348126258Smlaier		    cur->src.port_op != prev->src.port_op)
1349126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1350145836Smlaier		if (cur->dst.neg != prev->dst.neg ||
1351126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1352126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1353126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1354126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1355126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1356126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1357126258Smlaier
1358126258Smlaier		prev = cur;
1359126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1360126258Smlaier	}
1361126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1362126258Smlaier		PF_SET_SKIP_STEPS(i);
1363126258Smlaier}
1364126258Smlaier
1365126258Smlaierint
1366126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1367126258Smlaier{
1368126258Smlaier	if (aw1->type != aw2->type)
1369126258Smlaier		return (1);
1370126258Smlaier	switch (aw1->type) {
1371126258Smlaier	case PF_ADDR_ADDRMASK:
1372126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1373126258Smlaier			return (1);
1374126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1375126258Smlaier			return (1);
1376126258Smlaier		return (0);
1377126258Smlaier	case PF_ADDR_DYNIFTL:
1378130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1379126258Smlaier	case PF_ADDR_NOROUTE:
1380126258Smlaier		return (0);
1381126258Smlaier	case PF_ADDR_TABLE:
1382126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
1383126258Smlaier	default:
1384126258Smlaier		printf("invalid address type: %d\n", aw1->type);
1385126258Smlaier		return (1);
1386126258Smlaier	}
1387126258Smlaier}
1388126258Smlaier
1389126258Smlaieru_int16_t
1390126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
1391126258Smlaier{
1392126258Smlaier	u_int32_t	l;
1393126258Smlaier
1394126258Smlaier	if (udp && !cksum)
1395126258Smlaier		return (0x0000);
1396126258Smlaier	l = cksum + old - new;
1397126258Smlaier	l = (l >> 16) + (l & 65535);
1398126258Smlaier	l = l & 65535;
1399126258Smlaier	if (udp && !l)
1400126258Smlaier		return (0xFFFF);
1401126258Smlaier	return (l);
1402126258Smlaier}
1403126258Smlaier
1404126258Smlaiervoid
1405126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
1406126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
1407126258Smlaier{
1408126258Smlaier	struct pf_addr	ao;
1409126258Smlaier	u_int16_t	po = *p;
1410126258Smlaier
1411126258Smlaier	PF_ACPY(&ao, a, af);
1412126258Smlaier	PF_ACPY(a, an, af);
1413126258Smlaier
1414126258Smlaier	*p = pn;
1415126258Smlaier
1416126258Smlaier	switch (af) {
1417126258Smlaier#ifdef INET
1418126258Smlaier	case AF_INET:
1419126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1420126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
1421126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
1422126258Smlaier		*p = pn;
1423126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1424126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1425126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1426126258Smlaier		    po, pn, u);
1427126258Smlaier		break;
1428126258Smlaier#endif /* INET */
1429126258Smlaier#ifdef INET6
1430126258Smlaier	case AF_INET6:
1431126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1432126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1433126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1434126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1435126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1436126258Smlaier		    ao.addr16[2], an->addr16[2], u),
1437126258Smlaier		    ao.addr16[3], an->addr16[3], u),
1438126258Smlaier		    ao.addr16[4], an->addr16[4], u),
1439126258Smlaier		    ao.addr16[5], an->addr16[5], u),
1440126258Smlaier		    ao.addr16[6], an->addr16[6], u),
1441126258Smlaier		    ao.addr16[7], an->addr16[7], u),
1442126258Smlaier		    po, pn, u);
1443126258Smlaier		break;
1444126258Smlaier#endif /* INET6 */
1445126258Smlaier	}
1446126258Smlaier}
1447126258Smlaier
1448126258Smlaier
1449126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
1450126258Smlaiervoid
1451126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
1452126258Smlaier{
1453126258Smlaier	u_int32_t	ao;
1454126258Smlaier
1455126258Smlaier	memcpy(&ao, a, sizeof(ao));
1456126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
1457126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
1458126258Smlaier	    ao % 65536, an % 65536, u);
1459126258Smlaier}
1460126258Smlaier
1461126258Smlaier#ifdef INET6
1462126258Smlaiervoid
1463126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
1464126258Smlaier{
1465126258Smlaier	struct pf_addr	ao;
1466126258Smlaier
1467126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
1468126258Smlaier	PF_ACPY(a, an, AF_INET6);
1469126258Smlaier
1470126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1471126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1472126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
1473126258Smlaier	    ao.addr16[0], an->addr16[0], u),
1474126258Smlaier	    ao.addr16[1], an->addr16[1], u),
1475126258Smlaier	    ao.addr16[2], an->addr16[2], u),
1476126258Smlaier	    ao.addr16[3], an->addr16[3], u),
1477126258Smlaier	    ao.addr16[4], an->addr16[4], u),
1478126258Smlaier	    ao.addr16[5], an->addr16[5], u),
1479126258Smlaier	    ao.addr16[6], an->addr16[6], u),
1480126258Smlaier	    ao.addr16[7], an->addr16[7], u);
1481126258Smlaier}
1482126258Smlaier#endif /* INET6 */
1483126258Smlaier
1484126258Smlaiervoid
1485126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1486126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1487126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1488126258Smlaier{
1489126258Smlaier	struct pf_addr	oia, ooa;
1490126258Smlaier
1491126258Smlaier	PF_ACPY(&oia, ia, af);
1492126258Smlaier	PF_ACPY(&ooa, oa, af);
1493126258Smlaier
1494126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1495126258Smlaier	if (ip != NULL) {
1496126258Smlaier		u_int16_t	oip = *ip;
1497127629Smlaier		u_int32_t	opc = 0;	/* make the compiler happy */
1498126258Smlaier
1499126258Smlaier		if (pc != NULL)
1500126258Smlaier			opc = *pc;
1501126258Smlaier		*ip = np;
1502126258Smlaier		if (pc != NULL)
1503126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1504126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1505126258Smlaier		if (pc != NULL)
1506126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1507126258Smlaier	}
1508126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1509126258Smlaier	PF_ACPY(ia, na, af);
1510126258Smlaier	switch (af) {
1511126258Smlaier#ifdef INET
1512126258Smlaier	case AF_INET: {
1513126258Smlaier		u_int32_t	 oh2c = *h2c;
1514126258Smlaier
1515126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1516126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1517126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1518126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1519126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1520126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1521126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1522126258Smlaier		break;
1523126258Smlaier	}
1524126258Smlaier#endif /* INET */
1525126258Smlaier#ifdef INET6
1526126258Smlaier	case AF_INET6:
1527126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1528126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1529126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1530126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1531126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1532126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1533126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1534126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1535126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1536126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1537126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1538126258Smlaier		break;
1539126258Smlaier#endif /* INET6 */
1540126258Smlaier	}
1541126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1542126258Smlaier	PF_ACPY(oa, na, af);
1543126258Smlaier	switch (af) {
1544126258Smlaier#ifdef INET
1545126258Smlaier	case AF_INET:
1546126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1547126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1548126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1549126258Smlaier		break;
1550126258Smlaier#endif /* INET */
1551126258Smlaier#ifdef INET6
1552126258Smlaier	case AF_INET6:
1553126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1554126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1555126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1556126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1557126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1558126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1559126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1560126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1561126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1562126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1563126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1564126258Smlaier		break;
1565126258Smlaier#endif /* INET6 */
1566126258Smlaier	}
1567126258Smlaier}
1568126258Smlaier
1569126258Smlaiervoid
1570126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1571126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1572126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1573145836Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
1574145836Smlaier    struct ether_header *eh, struct ifnet *ifp)
1575126258Smlaier{
1576126258Smlaier	struct mbuf	*m;
1577127629Smlaier	int		 len = 0, tlen;		/* make the compiler happy */
1578126258Smlaier#ifdef INET
1579127629Smlaier	struct ip	*h = NULL;		/* make the compiler happy */
1580126258Smlaier#endif /* INET */
1581126258Smlaier#ifdef INET6
1582127629Smlaier	struct ip6_hdr	*h6 = NULL;		/* make the compiler happy */
1583126258Smlaier#endif /* INET6 */
1584127629Smlaier	struct tcphdr	*th = NULL;		/* make the compiler happy */
1585126258Smlaier	char *opt;
1586126258Smlaier
1587126258Smlaier	/* maximum segment size tcp option */
1588126258Smlaier	tlen = sizeof(struct tcphdr);
1589126258Smlaier	if (mss)
1590126258Smlaier		tlen += 4;
1591126258Smlaier
1592126258Smlaier	switch (af) {
1593126258Smlaier#ifdef INET
1594126258Smlaier	case AF_INET:
1595126258Smlaier		len = sizeof(struct ip) + tlen;
1596126258Smlaier		break;
1597126258Smlaier#endif /* INET */
1598126258Smlaier#ifdef INET6
1599126258Smlaier	case AF_INET6:
1600126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1601126258Smlaier		break;
1602126258Smlaier#endif /* INET6 */
1603126258Smlaier	}
1604126258Smlaier
1605126258Smlaier	/* create outgoing mbuf */
1606132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1607132280Smlaier	if (m == NULL)
1608132280Smlaier		return;
1609145836Smlaier	if (tag) {
1610145836Smlaier#ifdef __FreeBSD__
1611145836Smlaier		m->m_flags |= M_SKIP_FIREWALL;
1612132280Smlaier#else
1613145836Smlaier		struct m_tag	*mtag;
1614145836Smlaier
1615145836Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1616145836Smlaier		if (mtag == NULL) {
1617145836Smlaier			m_freem(m);
1618145836Smlaier			return;
1619145836Smlaier		}
1620145836Smlaier		m_tag_prepend(m, mtag);
1621145836Smlaier#endif
1622126258Smlaier	}
1623126258Smlaier#ifdef ALTQ
1624126258Smlaier	if (r != NULL && r->qid) {
1625145836Smlaier		struct m_tag	*mtag;
1626126258Smlaier		struct altq_tag *atag;
1627126258Smlaier
1628126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1629126258Smlaier		if (mtag != NULL) {
1630126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1631126258Smlaier			atag->qid = r->qid;
1632126258Smlaier			/* add hints for ecn */
1633126258Smlaier			atag->af = af;
1634126258Smlaier			atag->hdr = mtod(m, struct ip *);
1635126258Smlaier			m_tag_prepend(m, mtag);
1636126258Smlaier		}
1637126258Smlaier	}
1638145836Smlaier#endif /* ALTQ */
1639126258Smlaier	m->m_data += max_linkhdr;
1640126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1641126258Smlaier	m->m_pkthdr.rcvif = NULL;
1642126258Smlaier	bzero(m->m_data, len);
1643126258Smlaier	switch (af) {
1644126258Smlaier#ifdef INET
1645126258Smlaier	case AF_INET:
1646126258Smlaier		h = mtod(m, struct ip *);
1647126258Smlaier
1648126258Smlaier		/* IP header fields included in the TCP checksum */
1649126258Smlaier		h->ip_p = IPPROTO_TCP;
1650126258Smlaier		h->ip_len = htons(tlen);
1651126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1652126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1653126258Smlaier
1654126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1655126258Smlaier		break;
1656126258Smlaier#endif /* INET */
1657126258Smlaier#ifdef INET6
1658126258Smlaier	case AF_INET6:
1659126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1660126258Smlaier
1661126258Smlaier		/* IP header fields included in the TCP checksum */
1662126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1663126258Smlaier		h6->ip6_plen = htons(tlen);
1664126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1665126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1666126258Smlaier
1667126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1668126258Smlaier		break;
1669126258Smlaier#endif /* INET6 */
1670126258Smlaier	}
1671126258Smlaier
1672126258Smlaier	/* TCP header */
1673126258Smlaier	th->th_sport = sport;
1674126258Smlaier	th->th_dport = dport;
1675126258Smlaier	th->th_seq = htonl(seq);
1676126258Smlaier	th->th_ack = htonl(ack);
1677126258Smlaier	th->th_off = tlen >> 2;
1678126258Smlaier	th->th_flags = flags;
1679126258Smlaier	th->th_win = htons(win);
1680126258Smlaier
1681126258Smlaier	if (mss) {
1682126258Smlaier		opt = (char *)(th + 1);
1683126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1684126258Smlaier		opt[1] = 4;
1685126258Smlaier		HTONS(mss);
1686126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1687126258Smlaier	}
1688126258Smlaier
1689126258Smlaier	switch (af) {
1690126258Smlaier#ifdef INET
1691126258Smlaier	case AF_INET:
1692126258Smlaier		/* TCP checksum */
1693126258Smlaier		th->th_sum = in_cksum(m, len);
1694126258Smlaier
1695126258Smlaier		/* Finish the IP header */
1696126258Smlaier		h->ip_v = 4;
1697126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1698126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1699127145Smlaier#ifdef __FreeBSD__
1700130613Smlaier		h->ip_off = path_mtu_discovery ? IP_DF : 0;
1701130613Smlaier		h->ip_len = len;
1702126261Smlaier#else
1703126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1704130613Smlaier		h->ip_len = htons(len);
1705126261Smlaier#endif
1706126258Smlaier		h->ip_ttl = ttl ? ttl : ip_defttl;
1707126258Smlaier		h->ip_sum = 0;
1708145836Smlaier		if (eh == NULL) {
1709127145Smlaier#ifdef __FreeBSD__
1710145836Smlaier			PF_UNLOCK();
1711145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1712145836Smlaier			    (void *)NULL, (void *)NULL);
1713145836Smlaier			PF_LOCK();
1714126261Smlaier#else /* ! __FreeBSD__ */
1715145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1716145836Smlaier			    (void *)NULL, (void *)NULL);
1717126261Smlaier#endif
1718145836Smlaier		} else {
1719145836Smlaier			struct route		 ro;
1720145836Smlaier			struct rtentry		 rt;
1721145836Smlaier			struct ether_header	*e = (void *)ro.ro_dst.sa_data;
1722145836Smlaier
1723145836Smlaier			if (ifp == NULL) {
1724145836Smlaier				m_freem(m);
1725145836Smlaier				return;
1726145836Smlaier			}
1727145836Smlaier			rt.rt_ifp = ifp;
1728145836Smlaier			ro.ro_rt = &rt;
1729145836Smlaier			ro.ro_dst.sa_len = sizeof(ro.ro_dst);
1730145836Smlaier			ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
1731145836Smlaier			bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
1732145836Smlaier			bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
1733145836Smlaier			e->ether_type = eh->ether_type;
1734145836Smlaier#ifdef __FreeBSD__
1735145836Smlaier			PF_UNLOCK();
1736145836Smlaier			/* XXX_IMPORT: later */
1737145836Smlaier			ip_output(m, (void *)NULL, &ro, 0,
1738145836Smlaier			    (void *)NULL, (void *)NULL);
1739145836Smlaier			PF_LOCK();
1740145836Smlaier#else /* ! __FreeBSD__ */
1741145836Smlaier			ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
1742145836Smlaier			    (void *)NULL, (void *)NULL);
1743145836Smlaier#endif
1744145836Smlaier		}
1745126258Smlaier		break;
1746126258Smlaier#endif /* INET */
1747126258Smlaier#ifdef INET6
1748126258Smlaier	case AF_INET6:
1749126258Smlaier		/* TCP checksum */
1750126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
1751126258Smlaier		    sizeof(struct ip6_hdr), tlen);
1752126258Smlaier
1753126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
1754126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
1755126258Smlaier
1756127145Smlaier#ifdef __FreeBSD__
1757126261Smlaier		PF_UNLOCK();
1758126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
1759126261Smlaier		PF_LOCK();
1760126261Smlaier#else
1761126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
1762126261Smlaier#endif
1763126258Smlaier		break;
1764126258Smlaier#endif /* INET6 */
1765126258Smlaier	}
1766126258Smlaier}
1767126258Smlaier
1768126258Smlaiervoid
1769126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
1770126258Smlaier    struct pf_rule *r)
1771126258Smlaier{
1772132280Smlaier#ifdef ALTQ
1773126258Smlaier	struct m_tag	*mtag;
1774132280Smlaier#endif
1775126258Smlaier	struct mbuf	*m0;
1776127145Smlaier#ifdef __FreeBSD__
1777126261Smlaier	struct ip *ip;
1778126261Smlaier#endif
1779126258Smlaier
1780132280Smlaier#ifdef __FreeBSD__
1781132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
1782132280Smlaier	if (m0 == NULL)
1783132280Smlaier		return;
1784132280Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
1785132280Smlaier#else
1786126258Smlaier	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1787126258Smlaier	if (mtag == NULL)
1788126258Smlaier		return;
1789126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
1790126258Smlaier	if (m0 == NULL) {
1791126258Smlaier		m_tag_free(mtag);
1792126258Smlaier		return;
1793126258Smlaier	}
1794126258Smlaier	m_tag_prepend(m0, mtag);
1795132280Smlaier#endif
1796126258Smlaier
1797126258Smlaier#ifdef ALTQ
1798126258Smlaier	if (r->qid) {
1799126258Smlaier		struct altq_tag *atag;
1800126258Smlaier
1801126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1802126258Smlaier		if (mtag != NULL) {
1803126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1804126258Smlaier			atag->qid = r->qid;
1805126258Smlaier			/* add hints for ecn */
1806126258Smlaier			atag->af = af;
1807126258Smlaier			atag->hdr = mtod(m0, struct ip *);
1808126258Smlaier			m_tag_prepend(m0, mtag);
1809126258Smlaier		}
1810126258Smlaier	}
1811145836Smlaier#endif /* ALTQ */
1812126258Smlaier
1813126258Smlaier	switch (af) {
1814126258Smlaier#ifdef INET
1815126258Smlaier	case AF_INET:
1816127145Smlaier#ifdef __FreeBSD__
1817126261Smlaier		/* icmp_error() expects host byte ordering */
1818126261Smlaier		ip = mtod(m0, struct ip *);
1819126261Smlaier		NTOHS(ip->ip_len);
1820126261Smlaier		NTOHS(ip->ip_off);
1821126261Smlaier		PF_UNLOCK();
1822145863Sandre		icmp_error(m0, type, code, 0, 0);
1823126261Smlaier		PF_LOCK();
1824145874Smlaier#else
1825145874Smlaier		icmp_error(m0, type, code, 0, (void *)NULL);
1826126261Smlaier#endif
1827126258Smlaier		break;
1828126258Smlaier#endif /* INET */
1829126258Smlaier#ifdef INET6
1830126258Smlaier	case AF_INET6:
1831127145Smlaier#ifdef __FreeBSD__
1832126261Smlaier		PF_UNLOCK();
1833126261Smlaier#endif
1834126258Smlaier		icmp6_error(m0, type, code, 0);
1835127145Smlaier#ifdef __FreeBSD__
1836126261Smlaier		PF_LOCK();
1837126261Smlaier#endif
1838126258Smlaier		break;
1839126258Smlaier#endif /* INET6 */
1840126258Smlaier	}
1841126258Smlaier}
1842126258Smlaier
1843126258Smlaier/*
1844126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
1845126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
1846126258Smlaier * are different.
1847126258Smlaier */
1848126258Smlaierint
1849126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
1850126258Smlaier    struct pf_addr *b, sa_family_t af)
1851126258Smlaier{
1852126258Smlaier	int	match = 0;
1853126258Smlaier
1854126258Smlaier	switch (af) {
1855126258Smlaier#ifdef INET
1856126258Smlaier	case AF_INET:
1857126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
1858126258Smlaier		    (b->addr32[0] & m->addr32[0]))
1859126258Smlaier			match++;
1860126258Smlaier		break;
1861126258Smlaier#endif /* INET */
1862126258Smlaier#ifdef INET6
1863126258Smlaier	case AF_INET6:
1864126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
1865126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
1866126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
1867126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
1868126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
1869126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
1870126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
1871126258Smlaier		     (b->addr32[3] & m->addr32[3])))
1872126258Smlaier			match++;
1873126258Smlaier		break;
1874126258Smlaier#endif /* INET6 */
1875126258Smlaier	}
1876126258Smlaier	if (match) {
1877126258Smlaier		if (n)
1878126258Smlaier			return (0);
1879126258Smlaier		else
1880126258Smlaier			return (1);
1881126258Smlaier	} else {
1882126258Smlaier		if (n)
1883126258Smlaier			return (1);
1884126258Smlaier		else
1885126258Smlaier			return (0);
1886126258Smlaier	}
1887126258Smlaier}
1888126258Smlaier
1889126258Smlaierint
1890126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
1891126258Smlaier{
1892126258Smlaier	switch (op) {
1893126258Smlaier	case PF_OP_IRG:
1894126258Smlaier		return ((p > a1) && (p < a2));
1895126258Smlaier	case PF_OP_XRG:
1896126258Smlaier		return ((p < a1) || (p > a2));
1897126258Smlaier	case PF_OP_RRG:
1898126258Smlaier		return ((p >= a1) && (p <= a2));
1899126258Smlaier	case PF_OP_EQ:
1900126258Smlaier		return (p == a1);
1901126258Smlaier	case PF_OP_NE:
1902126258Smlaier		return (p != a1);
1903126258Smlaier	case PF_OP_LT:
1904126258Smlaier		return (p < a1);
1905126258Smlaier	case PF_OP_LE:
1906126258Smlaier		return (p <= a1);
1907126258Smlaier	case PF_OP_GT:
1908126258Smlaier		return (p > a1);
1909126258Smlaier	case PF_OP_GE:
1910126258Smlaier		return (p >= a1);
1911126258Smlaier	}
1912126258Smlaier	return (0); /* never reached */
1913126258Smlaier}
1914126258Smlaier
1915126258Smlaierint
1916126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
1917126258Smlaier{
1918126258Smlaier	NTOHS(a1);
1919126258Smlaier	NTOHS(a2);
1920126258Smlaier	NTOHS(p);
1921126258Smlaier	return (pf_match(op, a1, a2, p));
1922126258Smlaier}
1923126258Smlaier
1924126258Smlaierint
1925126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
1926126258Smlaier{
1927126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1928126258Smlaier		return (0);
1929126258Smlaier	return (pf_match(op, a1, a2, u));
1930126258Smlaier}
1931126258Smlaier
1932126258Smlaierint
1933126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
1934126258Smlaier{
1935126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1936126258Smlaier		return (0);
1937126258Smlaier	return (pf_match(op, a1, a2, g));
1938126258Smlaier}
1939126258Smlaier
1940126258Smlaierstruct pf_tag *
1941126258Smlaierpf_get_tag(struct mbuf *m)
1942126258Smlaier{
1943126258Smlaier	struct m_tag	*mtag;
1944126258Smlaier
1945126258Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
1946126258Smlaier		return ((struct pf_tag *)(mtag + 1));
1947126258Smlaier	else
1948126258Smlaier		return (NULL);
1949126258Smlaier}
1950126258Smlaier
1951126258Smlaierint
1952145836Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag)
1953126258Smlaier{
1954126258Smlaier	if (*tag == -1) {	/* find mbuf tag */
1955145836Smlaier		*pftag = pf_get_tag(m);
1956145836Smlaier		if (*pftag != NULL)
1957145836Smlaier			*tag = (*pftag)->tag;
1958126258Smlaier		else
1959126258Smlaier			*tag = 0;
1960126258Smlaier	}
1961126258Smlaier
1962126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
1963126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
1964126258Smlaier}
1965126258Smlaier
1966126258Smlaierint
1967126258Smlaierpf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
1968126258Smlaier{
1969126258Smlaier	struct m_tag	*mtag;
1970126258Smlaier
1971126258Smlaier	if (tag <= 0)
1972126258Smlaier		return (0);
1973126258Smlaier
1974126258Smlaier	if (pftag == NULL) {
1975126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
1976126258Smlaier		if (mtag == NULL)
1977126258Smlaier			return (1);
1978126258Smlaier		((struct pf_tag *)(mtag + 1))->tag = tag;
1979126258Smlaier		m_tag_prepend(m, mtag);
1980126258Smlaier	} else
1981126258Smlaier		pftag->tag = tag;
1982126258Smlaier
1983126258Smlaier	return (0);
1984126258Smlaier}
1985126258Smlaier
1986145836Smlaierstatic void
1987145836Smlaierpf_step_into_anchor(int *depth, struct pf_ruleset **rs, int n,
1988145836Smlaier    struct pf_rule **r, struct pf_rule **a)
1989145836Smlaier{
1990145836Smlaier	struct pf_anchor_stackframe	*f;
1991126258Smlaier
1992145836Smlaier	if (*depth >= sizeof(pf_anchor_stack) /
1993145836Smlaier	    sizeof(pf_anchor_stack[0])) {
1994145836Smlaier		printf("pf_step_into_anchor: stack overflow\n");
1995145836Smlaier		*r = TAILQ_NEXT(*r, entries);
1996145836Smlaier		return;
1997145836Smlaier	} else if (*depth == 0 && a != NULL)
1998145836Smlaier		*a = *r;
1999145836Smlaier	f = pf_anchor_stack + (*depth)++;
2000145836Smlaier	f->rs = *rs;
2001145836Smlaier	f->r = *r;
2002145836Smlaier	if ((*r)->anchor_wildcard) {
2003145836Smlaier		f->parent = &(*r)->anchor->children;
2004145836Smlaier		if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
2005145836Smlaier		    NULL) {
2006145836Smlaier			*r = NULL;
2007145836Smlaier			return;
2008145836Smlaier		}
2009145836Smlaier		*rs = &f->child->ruleset;
2010145836Smlaier	} else {
2011145836Smlaier		f->parent = NULL;
2012145836Smlaier		f->child = NULL;
2013145836Smlaier		*rs = &(*r)->anchor->ruleset;
2014145836Smlaier	}
2015145836Smlaier	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2016145836Smlaier}
2017126258Smlaier
2018145836Smlaierstatic void
2019145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
2020145836Smlaier    struct pf_rule **r, struct pf_rule **a)
2021145836Smlaier{
2022145836Smlaier	struct pf_anchor_stackframe	*f;
2023145836Smlaier
2024145836Smlaier	do {
2025145836Smlaier		if (*depth <= 0)
2026145836Smlaier			break;
2027145836Smlaier		f = pf_anchor_stack + *depth - 1;
2028145836Smlaier		if (f->parent != NULL && f->child != NULL) {
2029145836Smlaier			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
2030145836Smlaier			if (f->child != NULL) {
2031145836Smlaier				*rs = &f->child->ruleset;
2032145836Smlaier				*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2033145836Smlaier				if (*r == NULL)
2034145836Smlaier					continue;
2035145836Smlaier				else
2036145836Smlaier					break;
2037145836Smlaier			}
2038145836Smlaier		}
2039145836Smlaier		(*depth)--;
2040145836Smlaier		if (*depth == 0 && a != NULL)
2041145836Smlaier			*a = NULL;
2042145836Smlaier		*rs = f->rs;
2043145836Smlaier		*r = TAILQ_NEXT(f->r, entries);
2044145836Smlaier	} while (*r == NULL);
2045145836Smlaier}
2046145836Smlaier
2047126258Smlaier#ifdef INET6
2048126258Smlaiervoid
2049126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
2050126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
2051126258Smlaier{
2052126258Smlaier	switch (af) {
2053126258Smlaier#ifdef INET
2054126258Smlaier	case AF_INET:
2055126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2056126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2057126258Smlaier		break;
2058126258Smlaier#endif /* INET */
2059126258Smlaier	case AF_INET6:
2060126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2061126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2062126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
2063126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
2064126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
2065126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
2066126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
2067126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
2068126258Smlaier		break;
2069126258Smlaier	}
2070126258Smlaier}
2071126258Smlaier
2072126258Smlaiervoid
2073130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
2074126258Smlaier{
2075126258Smlaier	switch (af) {
2076126258Smlaier#ifdef INET
2077126258Smlaier	case AF_INET:
2078126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
2079126258Smlaier		break;
2080126258Smlaier#endif /* INET */
2081126258Smlaier	case AF_INET6:
2082126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
2083126258Smlaier			addr->addr32[3] = 0;
2084126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
2085126258Smlaier				addr->addr32[2] = 0;
2086126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
2087126258Smlaier					addr->addr32[1] = 0;
2088126258Smlaier					addr->addr32[0] =
2089126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
2090126258Smlaier				} else
2091126258Smlaier					addr->addr32[1] =
2092126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
2093126258Smlaier			} else
2094126258Smlaier				addr->addr32[2] =
2095126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
2096126258Smlaier		} else
2097126258Smlaier			addr->addr32[3] =
2098126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
2099126258Smlaier		break;
2100126258Smlaier	}
2101126258Smlaier}
2102126258Smlaier#endif /* INET6 */
2103126258Smlaier
2104126258Smlaier#define mix(a,b,c) \
2105126258Smlaier	do {					\
2106126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
2107126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
2108126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
2109126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
2110126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
2111126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
2112126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
2113126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
2114126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
2115126258Smlaier	} while (0)
2116126258Smlaier
2117126258Smlaier/*
2118126258Smlaier * hash function based on bridge_hash in if_bridge.c
2119126258Smlaier */
2120126258Smlaiervoid
2121126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
2122126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
2123126258Smlaier{
2124126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
2125126258Smlaier
2126126258Smlaier	switch (af) {
2127126258Smlaier#ifdef INET
2128126258Smlaier	case AF_INET:
2129126258Smlaier		a += inaddr->addr32[0];
2130126258Smlaier		b += key->key32[1];
2131126258Smlaier		mix(a, b, c);
2132126258Smlaier		hash->addr32[0] = c + key->key32[2];
2133126258Smlaier		break;
2134126258Smlaier#endif /* INET */
2135126258Smlaier#ifdef INET6
2136126258Smlaier	case AF_INET6:
2137126258Smlaier		a += inaddr->addr32[0];
2138126258Smlaier		b += inaddr->addr32[2];
2139126258Smlaier		mix(a, b, c);
2140126258Smlaier		hash->addr32[0] = c;
2141126258Smlaier		a += inaddr->addr32[1];
2142126258Smlaier		b += inaddr->addr32[3];
2143126258Smlaier		c += key->key32[1];
2144126258Smlaier		mix(a, b, c);
2145126258Smlaier		hash->addr32[1] = c;
2146126258Smlaier		a += inaddr->addr32[2];
2147126258Smlaier		b += inaddr->addr32[1];
2148126258Smlaier		c += key->key32[2];
2149126258Smlaier		mix(a, b, c);
2150126258Smlaier		hash->addr32[2] = c;
2151126258Smlaier		a += inaddr->addr32[3];
2152126258Smlaier		b += inaddr->addr32[0];
2153126258Smlaier		c += key->key32[3];
2154126258Smlaier		mix(a, b, c);
2155126258Smlaier		hash->addr32[3] = c;
2156126258Smlaier		break;
2157126258Smlaier#endif /* INET6 */
2158126258Smlaier	}
2159126258Smlaier}
2160126258Smlaier
2161126258Smlaierint
2162130613Smlaierpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
2163130613Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
2164126258Smlaier{
2165126258Smlaier	unsigned char		 hash[16];
2166130613Smlaier	struct pf_pool		*rpool = &r->rpool;
2167130613Smlaier	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
2168130613Smlaier	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
2169126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
2170130613Smlaier	struct pf_src_node	 k;
2171126258Smlaier
2172130613Smlaier	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
2173130613Smlaier	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2174130613Smlaier		k.af = af;
2175130613Smlaier		PF_ACPY(&k.addr, saddr, af);
2176130613Smlaier		if (r->rule_flag & PFRULE_RULESRCTRACK ||
2177130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR)
2178130613Smlaier			k.rule.ptr = r;
2179130613Smlaier		else
2180130613Smlaier			k.rule.ptr = NULL;
2181130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
2182130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
2183130613Smlaier		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
2184130613Smlaier			PF_ACPY(naddr, &(*sn)->raddr, af);
2185130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
2186130613Smlaier				printf("pf_map_addr: src tracking maps ");
2187130613Smlaier				pf_print_host(&k.addr, 0, af);
2188130613Smlaier				printf(" to ");
2189130613Smlaier				pf_print_host(naddr, 0, af);
2190130613Smlaier				printf("\n");
2191130613Smlaier			}
2192130613Smlaier			return (0);
2193130613Smlaier		}
2194130613Smlaier	}
2195130613Smlaier
2196126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
2197126258Smlaier		return (1);
2198130613Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2199145836Smlaier		switch (af) {
2200145836Smlaier#ifdef INET
2201145836Smlaier		case AF_INET:
2202130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
2203130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2204130613Smlaier			    PF_POOL_ROUNDROBIN)
2205130613Smlaier				return (1);
2206130613Smlaier			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
2207130613Smlaier			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
2208145836Smlaier			break;
2209145836Smlaier#endif /* INET */
2210145836Smlaier#ifdef INET6
2211145836Smlaier		case AF_INET6:
2212130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
2213130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2214130613Smlaier			    PF_POOL_ROUNDROBIN)
2215130613Smlaier				return (1);
2216130613Smlaier			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
2217130613Smlaier			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
2218145836Smlaier			break;
2219145836Smlaier#endif /* INET6 */
2220130613Smlaier		}
2221130613Smlaier	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2222126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
2223126258Smlaier			return (1); /* unsupported */
2224126258Smlaier	} else {
2225126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
2226126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
2227126258Smlaier	}
2228126258Smlaier
2229126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
2230126258Smlaier	case PF_POOL_NONE:
2231126258Smlaier		PF_ACPY(naddr, raddr, af);
2232126258Smlaier		break;
2233126258Smlaier	case PF_POOL_BITMASK:
2234126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
2235126258Smlaier		break;
2236126258Smlaier	case PF_POOL_RANDOM:
2237126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
2238126258Smlaier			switch (af) {
2239126258Smlaier#ifdef INET
2240126258Smlaier			case AF_INET:
2241145836Smlaier				rpool->counter.addr32[0] = htonl(arc4random());
2242126258Smlaier				break;
2243126258Smlaier#endif /* INET */
2244126258Smlaier#ifdef INET6
2245126258Smlaier			case AF_INET6:
2246126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
2247145836Smlaier					rpool->counter.addr32[3] =
2248145836Smlaier					    htonl(arc4random());
2249126258Smlaier				else
2250126258Smlaier					break;
2251126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
2252145836Smlaier					rpool->counter.addr32[2] =
2253145836Smlaier					    htonl(arc4random());
2254126258Smlaier				else
2255126258Smlaier					break;
2256126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
2257145836Smlaier					rpool->counter.addr32[1] =
2258145836Smlaier					    htonl(arc4random());
2259126258Smlaier				else
2260126258Smlaier					break;
2261126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
2262145836Smlaier					rpool->counter.addr32[0] =
2263145836Smlaier					    htonl(arc4random());
2264126258Smlaier				break;
2265126258Smlaier#endif /* INET6 */
2266126258Smlaier			}
2267126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2268126258Smlaier			PF_ACPY(init_addr, naddr, af);
2269126258Smlaier
2270126258Smlaier		} else {
2271126258Smlaier			PF_AINC(&rpool->counter, af);
2272126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2273126258Smlaier		}
2274126258Smlaier		break;
2275126258Smlaier	case PF_POOL_SRCHASH:
2276126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
2277126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
2278126258Smlaier		break;
2279126258Smlaier	case PF_POOL_ROUNDROBIN:
2280126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2281126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
2282126258Smlaier			    &rpool->tblidx, &rpool->counter,
2283126258Smlaier			    &raddr, &rmask, af))
2284126258Smlaier				goto get_addr;
2285130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2286130613Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2287130613Smlaier			    &rpool->tblidx, &rpool->counter,
2288130613Smlaier			    &raddr, &rmask, af))
2289130613Smlaier				goto get_addr;
2290126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
2291126258Smlaier			goto get_addr;
2292126258Smlaier
2293126258Smlaier	try_next:
2294126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
2295126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
2296126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2297126258Smlaier			rpool->tblidx = -1;
2298126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
2299126258Smlaier			    &rpool->tblidx, &rpool->counter,
2300126258Smlaier			    &raddr, &rmask, af)) {
2301130613Smlaier				/* table contains no address of type 'af' */
2302126258Smlaier				if (rpool->cur != acur)
2303126258Smlaier					goto try_next;
2304126258Smlaier				return (1);
2305126258Smlaier			}
2306130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2307130613Smlaier			rpool->tblidx = -1;
2308130613Smlaier			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2309130613Smlaier			    &rpool->tblidx, &rpool->counter,
2310130613Smlaier			    &raddr, &rmask, af)) {
2311130613Smlaier				/* table contains no address of type 'af' */
2312130613Smlaier				if (rpool->cur != acur)
2313130613Smlaier					goto try_next;
2314130613Smlaier				return (1);
2315130613Smlaier			}
2316126258Smlaier		} else {
2317126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
2318126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
2319126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
2320126258Smlaier		}
2321126258Smlaier
2322126258Smlaier	get_addr:
2323126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
2324139045Sdhartmei		if (init_addr != NULL && PF_AZERO(init_addr, af))
2325139045Sdhartmei			PF_ACPY(init_addr, naddr, af);
2326126258Smlaier		PF_AINC(&rpool->counter, af);
2327126258Smlaier		break;
2328126258Smlaier	}
2329130613Smlaier	if (*sn != NULL)
2330130613Smlaier		PF_ACPY(&(*sn)->raddr, naddr, af);
2331126258Smlaier
2332126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
2333126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2334130613Smlaier		printf("pf_map_addr: selected address ");
2335126258Smlaier		pf_print_host(naddr, 0, af);
2336126258Smlaier		printf("\n");
2337126258Smlaier	}
2338126258Smlaier
2339126258Smlaier	return (0);
2340126258Smlaier}
2341126258Smlaier
2342126258Smlaierint
2343130613Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
2344126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
2345130613Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
2346130613Smlaier    struct pf_src_node **sn)
2347126258Smlaier{
2348130613Smlaier	struct pf_state		key;
2349126258Smlaier	struct pf_addr		init_addr;
2350126258Smlaier	u_int16_t		cut;
2351126258Smlaier
2352126258Smlaier	bzero(&init_addr, sizeof(init_addr));
2353130613Smlaier	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2354126258Smlaier		return (1);
2355126258Smlaier
2356149884Smlaier	if (proto == IPPROTO_ICMP) {
2357149884Smlaier		low = 1;
2358149884Smlaier		high = 65535;
2359149884Smlaier	}
2360149884Smlaier
2361126258Smlaier	do {
2362126258Smlaier		key.af = af;
2363126258Smlaier		key.proto = proto;
2364130613Smlaier		PF_ACPY(&key.ext.addr, daddr, key.af);
2365130613Smlaier		PF_ACPY(&key.gwy.addr, naddr, key.af);
2366130613Smlaier		key.ext.port = dport;
2367126258Smlaier
2368126258Smlaier		/*
2369126258Smlaier		 * port search; start random, step;
2370126258Smlaier		 * similar 2 portloop in in_pcbbind
2371126258Smlaier		 */
2372149884Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
2373149884Smlaier		    proto == IPPROTO_ICMP)) {
2374139045Sdhartmei			key.gwy.port = dport;
2375130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2376126258Smlaier				return (0);
2377126258Smlaier		} else if (low == 0 && high == 0) {
2378130613Smlaier			key.gwy.port = *nport;
2379130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2380126258Smlaier				return (0);
2381126258Smlaier		} else if (low == high) {
2382130613Smlaier			key.gwy.port = htons(low);
2383130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
2384126258Smlaier				*nport = htons(low);
2385126258Smlaier				return (0);
2386126258Smlaier			}
2387126258Smlaier		} else {
2388126258Smlaier			u_int16_t tmp;
2389126258Smlaier
2390126258Smlaier			if (low > high) {
2391126258Smlaier				tmp = low;
2392126258Smlaier				low = high;
2393126258Smlaier				high = tmp;
2394126258Smlaier			}
2395126258Smlaier			/* low < high */
2396145836Smlaier			cut = htonl(arc4random()) % (1 + high - low) + low;
2397126258Smlaier			/* low <= cut <= high */
2398126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
2399130613Smlaier				key.gwy.port = htons(tmp);
2400130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2401126258Smlaier				    NULL) {
2402126258Smlaier					*nport = htons(tmp);
2403126258Smlaier					return (0);
2404126258Smlaier				}
2405126258Smlaier			}
2406126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
2407130613Smlaier				key.gwy.port = htons(tmp);
2408130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2409126258Smlaier				    NULL) {
2410126258Smlaier					*nport = htons(tmp);
2411126258Smlaier					return (0);
2412126258Smlaier				}
2413126258Smlaier			}
2414126258Smlaier		}
2415126258Smlaier
2416130613Smlaier		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
2417126258Smlaier		case PF_POOL_RANDOM:
2418126258Smlaier		case PF_POOL_ROUNDROBIN:
2419130613Smlaier			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2420126258Smlaier				return (1);
2421126258Smlaier			break;
2422126258Smlaier		case PF_POOL_NONE:
2423126258Smlaier		case PF_POOL_SRCHASH:
2424126258Smlaier		case PF_POOL_BITMASK:
2425126258Smlaier		default:
2426126258Smlaier			return (1);
2427126258Smlaier		}
2428126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
2429126258Smlaier
2430126258Smlaier	return (1);					/* none available */
2431126258Smlaier}
2432126258Smlaier
2433126258Smlaierstruct pf_rule *
2434126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
2435130613Smlaier    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
2436126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
2437126258Smlaier{
2438145836Smlaier	struct pf_rule		*r, *rm = NULL;
2439126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2440145836Smlaier	struct pf_tag		*pftag = NULL;
2441145836Smlaier	int			 tag = -1;
2442145836Smlaier	int			 asd = 0;
2443126258Smlaier
2444126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
2445126258Smlaier	while (r && rm == NULL) {
2446126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
2447126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
2448126258Smlaier
2449126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
2450126258Smlaier			src = &r->dst;
2451126258Smlaier			if (r->rpool.cur != NULL)
2452126258Smlaier				xdst = &r->rpool.cur->addr;
2453126258Smlaier		} else {
2454126258Smlaier			src = &r->src;
2455126258Smlaier			dst = &r->dst;
2456126258Smlaier		}
2457126258Smlaier
2458126258Smlaier		r->evaluations++;
2459130613Smlaier		if (r->kif != NULL &&
2460130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
2461126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2462126258Smlaier		else if (r->direction && r->direction != direction)
2463126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2464126258Smlaier		else if (r->af && r->af != pd->af)
2465126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2466126258Smlaier		else if (r->proto && r->proto != pd->proto)
2467126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2468145836Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg))
2469126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
2470126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
2471126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
2472126258Smlaier		    src->port[0], src->port[1], sport))
2473126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
2474126258Smlaier			    PF_SKIP_DST_PORT].ptr;
2475126258Smlaier		else if (dst != NULL &&
2476145836Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg))
2477126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2478126258Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
2479126258Smlaier			r = TAILQ_NEXT(r, entries);
2480126258Smlaier		else if (dst != NULL && dst->port_op &&
2481126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
2482126258Smlaier		    dst->port[1], dport))
2483126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2484145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
2485145836Smlaier			r = TAILQ_NEXT(r, entries);
2486126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
2487126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
2488126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
2489126258Smlaier			r = TAILQ_NEXT(r, entries);
2490145836Smlaier		else {
2491145836Smlaier			if (r->tag)
2492145836Smlaier				tag = r->tag;
2493145836Smlaier			if (r->anchor == NULL) {
2494126258Smlaier				rm = r;
2495145836Smlaier			} else
2496145836Smlaier				pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL);
2497145836Smlaier		}
2498145836Smlaier		if (r == NULL)
2499145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL);
2500126258Smlaier	}
2501145836Smlaier	if (pf_tag_packet(m, pftag, tag))
2502145836Smlaier		return (NULL);
2503126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
2504126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
2505126258Smlaier		return (NULL);
2506126258Smlaier	return (rm);
2507126258Smlaier}
2508126258Smlaier
2509126258Smlaierstruct pf_rule *
2510126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
2511130613Smlaier    struct pfi_kif *kif, struct pf_src_node **sn,
2512126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
2513126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
2514126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
2515126258Smlaier{
2516126258Smlaier	struct pf_rule	*r = NULL;
2517126258Smlaier
2518126258Smlaier	if (direction == PF_OUT) {
2519130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2520126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
2521126258Smlaier		if (r == NULL)
2522130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2523126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
2524126258Smlaier	} else {
2525130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2526126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
2527126258Smlaier		if (r == NULL)
2528130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2529126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
2530126258Smlaier	}
2531126258Smlaier
2532126258Smlaier	if (r != NULL) {
2533126258Smlaier		switch (r->action) {
2534126258Smlaier		case PF_NONAT:
2535126258Smlaier		case PF_NOBINAT:
2536126258Smlaier		case PF_NORDR:
2537126258Smlaier			return (NULL);
2538126258Smlaier		case PF_NAT:
2539130613Smlaier			if (pf_get_sport(pd->af, pd->proto, r, saddr,
2540126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
2541130613Smlaier			    r->rpool.proxy_port[1], sn)) {
2542126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2543126258Smlaier				    ("pf: NAT proxy port allocation "
2544126258Smlaier				    "(%u-%u) failed\n",
2545126258Smlaier				    r->rpool.proxy_port[0],
2546126258Smlaier				    r->rpool.proxy_port[1]));
2547126258Smlaier				return (NULL);
2548126258Smlaier			}
2549126258Smlaier			break;
2550126258Smlaier		case PF_BINAT:
2551126258Smlaier			switch (direction) {
2552126258Smlaier			case PF_OUT:
2553130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2554145836Smlaier					switch (pd->af) {
2555145836Smlaier#ifdef INET
2556145836Smlaier					case AF_INET:
2557130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2558130613Smlaier						    pfid_acnt4 < 1)
2559130613Smlaier							return (NULL);
2560130613Smlaier						PF_POOLMASK(naddr,
2561130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2562130613Smlaier						    pfid_addr4,
2563130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2564130613Smlaier						    pfid_mask4,
2565130613Smlaier						    saddr, AF_INET);
2566145836Smlaier						break;
2567145836Smlaier#endif /* INET */
2568145836Smlaier#ifdef INET6
2569145836Smlaier					case AF_INET6:
2570130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2571130613Smlaier						    pfid_acnt6 < 1)
2572130613Smlaier							return (NULL);
2573130613Smlaier						PF_POOLMASK(naddr,
2574130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2575130613Smlaier						    pfid_addr6,
2576130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2577130613Smlaier						    pfid_mask6,
2578130613Smlaier						    saddr, AF_INET6);
2579145836Smlaier						break;
2580145836Smlaier#endif /* INET6 */
2581130613Smlaier					}
2582130613Smlaier				} else
2583126258Smlaier					PF_POOLMASK(naddr,
2584126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
2585126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
2586126258Smlaier					    saddr, pd->af);
2587126258Smlaier				break;
2588126258Smlaier			case PF_IN:
2589138041Sdhartmei				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
2590145836Smlaier					switch (pd->af) {
2591145836Smlaier#ifdef INET
2592145836Smlaier					case AF_INET:
2593130613Smlaier						if (r->src.addr.p.dyn->
2594130613Smlaier						    pfid_acnt4 < 1)
2595130613Smlaier							return (NULL);
2596130613Smlaier						PF_POOLMASK(naddr,
2597130613Smlaier						    &r->src.addr.p.dyn->
2598130613Smlaier						    pfid_addr4,
2599130613Smlaier						    &r->src.addr.p.dyn->
2600130613Smlaier						    pfid_mask4,
2601130613Smlaier						    daddr, AF_INET);
2602145836Smlaier						break;
2603145836Smlaier#endif /* INET */
2604145836Smlaier#ifdef INET6
2605145836Smlaier					case AF_INET6:
2606130613Smlaier						if (r->src.addr.p.dyn->
2607130613Smlaier						    pfid_acnt6 < 1)
2608130613Smlaier							return (NULL);
2609130613Smlaier						PF_POOLMASK(naddr,
2610130613Smlaier						    &r->src.addr.p.dyn->
2611130613Smlaier						    pfid_addr6,
2612130613Smlaier						    &r->src.addr.p.dyn->
2613130613Smlaier						    pfid_mask6,
2614130613Smlaier						    daddr, AF_INET6);
2615145836Smlaier						break;
2616145836Smlaier#endif /* INET6 */
2617130613Smlaier					}
2618130613Smlaier				} else
2619126258Smlaier					PF_POOLMASK(naddr,
2620126258Smlaier					    &r->src.addr.v.a.addr,
2621126261Smlaier					    &r->src.addr.v.a.mask, daddr,
2622126258Smlaier					    pd->af);
2623126258Smlaier				break;
2624126258Smlaier			}
2625126258Smlaier			break;
2626126258Smlaier		case PF_RDR: {
2627140518Sdhartmei			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
2628126258Smlaier				return (NULL);
2629149884Smlaier			if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
2630149884Smlaier			    PF_POOL_BITMASK)
2631149884Smlaier				PF_POOLMASK(naddr, naddr,
2632149884Smlaier				    &r->rpool.cur->addr.v.a.mask, daddr,
2633149884Smlaier				    pd->af);
2634126258Smlaier
2635126258Smlaier			if (r->rpool.proxy_port[1]) {
2636126258Smlaier				u_int32_t	tmp_nport;
2637126258Smlaier
2638126258Smlaier				tmp_nport = ((ntohs(dport) -
2639126258Smlaier				    ntohs(r->dst.port[0])) %
2640126258Smlaier				    (r->rpool.proxy_port[1] -
2641126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
2642126258Smlaier				    r->rpool.proxy_port[0];
2643126258Smlaier
2644126258Smlaier				/* wrap around if necessary */
2645126258Smlaier				if (tmp_nport > 65535)
2646126258Smlaier					tmp_nport -= 65535;
2647126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
2648126258Smlaier			} else if (r->rpool.proxy_port[0])
2649126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
2650126258Smlaier			break;
2651126258Smlaier		}
2652126258Smlaier		default:
2653126258Smlaier			return (NULL);
2654126258Smlaier		}
2655126258Smlaier	}
2656126258Smlaier
2657126258Smlaier	return (r);
2658126258Smlaier}
2659126258Smlaier
2660126258Smlaierint
2661135920Smlaier#ifdef __FreeBSD__
2662135920Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd,
2663135920Smlaier    struct inpcb *inp_arg)
2664135920Smlaier#else
2665130613Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
2666135920Smlaier#endif
2667126258Smlaier{
2668126258Smlaier	struct pf_addr		*saddr, *daddr;
2669126258Smlaier	u_int16_t		 sport, dport;
2670127145Smlaier#ifdef __FreeBSD__
2671126261Smlaier	struct inpcbinfo	*pi;
2672126261Smlaier#else
2673126258Smlaier	struct inpcbtable	*tb;
2674126261Smlaier#endif
2675126258Smlaier	struct inpcb		*inp;
2676126258Smlaier
2677126258Smlaier	*uid = UID_MAX;
2678126258Smlaier	*gid = GID_MAX;
2679135920Smlaier#ifdef __FreeBSD__
2680135920Smlaier	if (inp_arg != NULL) {
2681135920Smlaier		INP_LOCK_ASSERT(inp_arg);
2682135920Smlaier		if (inp_arg->inp_socket) {
2683135920Smlaier			*uid = inp_arg->inp_socket->so_cred->cr_uid;
2684135920Smlaier			*gid = inp_arg->inp_socket->so_cred->cr_groups[0];
2685135920Smlaier			return (1);
2686135920Smlaier		} else
2687135920Smlaier			return (0);
2688135920Smlaier	}
2689135920Smlaier#endif
2690130613Smlaier	switch (pd->proto) {
2691126258Smlaier	case IPPROTO_TCP:
2692126258Smlaier		sport = pd->hdr.tcp->th_sport;
2693126258Smlaier		dport = pd->hdr.tcp->th_dport;
2694127145Smlaier#ifdef __FreeBSD__
2695126261Smlaier		pi = &tcbinfo;
2696126261Smlaier#else
2697126258Smlaier		tb = &tcbtable;
2698126261Smlaier#endif
2699126258Smlaier		break;
2700126258Smlaier	case IPPROTO_UDP:
2701126258Smlaier		sport = pd->hdr.udp->uh_sport;
2702126258Smlaier		dport = pd->hdr.udp->uh_dport;
2703127145Smlaier#ifdef __FreeBSD__
2704126261Smlaier		pi = &udbinfo;
2705126261Smlaier#else
2706126258Smlaier		tb = &udbtable;
2707126261Smlaier#endif
2708126258Smlaier		break;
2709126258Smlaier	default:
2710126258Smlaier		return (0);
2711126258Smlaier	}
2712126258Smlaier	if (direction == PF_IN) {
2713126258Smlaier		saddr = pd->src;
2714126258Smlaier		daddr = pd->dst;
2715126258Smlaier	} else {
2716126258Smlaier		u_int16_t	p;
2717126258Smlaier
2718126258Smlaier		p = sport;
2719126258Smlaier		sport = dport;
2720126258Smlaier		dport = p;
2721126258Smlaier		saddr = pd->dst;
2722126258Smlaier		daddr = pd->src;
2723126258Smlaier	}
2724130613Smlaier	switch (pd->af) {
2725145836Smlaier#ifdef INET
2726126258Smlaier	case AF_INET:
2727127145Smlaier#ifdef __FreeBSD__
2728126261Smlaier		INP_INFO_RLOCK(pi);	/* XXX LOR */
2729126261Smlaier		inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
2730126261Smlaier			dport, 0, NULL);
2731126261Smlaier		if (inp == NULL) {
2732126261Smlaier			inp = in_pcblookup_hash(pi, saddr->v4, sport,
2733126261Smlaier			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
2734126261Smlaier			if(inp == NULL) {
2735126261Smlaier				INP_INFO_RUNLOCK(pi);
2736126261Smlaier				return (0);
2737126261Smlaier			}
2738126261Smlaier		}
2739126261Smlaier#else
2740126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
2741126258Smlaier		if (inp == NULL) {
2742130613Smlaier			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
2743126258Smlaier			if (inp == NULL)
2744126258Smlaier				return (0);
2745126258Smlaier		}
2746126261Smlaier#endif
2747126258Smlaier		break;
2748145836Smlaier#endif /* INET */
2749126258Smlaier#ifdef INET6
2750126258Smlaier	case AF_INET6:
2751127145Smlaier#ifdef __FreeBSD__
2752126261Smlaier		INP_INFO_RLOCK(pi);
2753126261Smlaier		inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2754126261Smlaier			&daddr->v6, dport, 0, NULL);
2755126261Smlaier		if (inp == NULL) {
2756126261Smlaier			inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2757126261Smlaier			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
2758126261Smlaier			if (inp == NULL) {
2759126261Smlaier				INP_INFO_RUNLOCK(pi);
2760126261Smlaier				return (0);
2761126261Smlaier			}
2762126261Smlaier		}
2763126261Smlaier#else
2764126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
2765126258Smlaier		    dport);
2766126258Smlaier		if (inp == NULL) {
2767130613Smlaier			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
2768126258Smlaier			if (inp == NULL)
2769126258Smlaier				return (0);
2770126258Smlaier		}
2771126261Smlaier#endif
2772126258Smlaier		break;
2773126258Smlaier#endif /* INET6 */
2774126258Smlaier
2775126258Smlaier	default:
2776126258Smlaier		return (0);
2777126258Smlaier	}
2778127145Smlaier#ifdef __FreeBSD__
2779126261Smlaier	INP_LOCK(inp);
2780136925Smlaier	if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) {
2781136925Smlaier		INP_UNLOCK(inp);
2782136925Smlaier		INP_INFO_RUNLOCK(pi);
2783136925Smlaier		return (0);
2784136925Smlaier	}
2785126261Smlaier	*uid = inp->inp_socket->so_cred->cr_uid;
2786126261Smlaier	*gid = inp->inp_socket->so_cred->cr_groups[0];
2787126261Smlaier	INP_UNLOCK(inp);
2788126261Smlaier	INP_INFO_RUNLOCK(pi);
2789126261Smlaier#else
2790126258Smlaier	*uid = inp->inp_socket->so_euid;
2791126258Smlaier	*gid = inp->inp_socket->so_egid;
2792126261Smlaier#endif
2793126258Smlaier	return (1);
2794126258Smlaier}
2795126258Smlaier
2796126258Smlaieru_int8_t
2797126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2798126258Smlaier{
2799126258Smlaier	int		 hlen;
2800126258Smlaier	u_int8_t	 hdr[60];
2801126258Smlaier	u_int8_t	*opt, optlen;
2802126258Smlaier	u_int8_t	 wscale = 0;
2803126258Smlaier
2804126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
2805126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2806126258Smlaier		return (0);
2807126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2808126258Smlaier		return (0);
2809126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2810126258Smlaier	hlen -= sizeof(struct tcphdr);
2811126258Smlaier	while (hlen >= 3) {
2812126258Smlaier		switch (*opt) {
2813126258Smlaier		case TCPOPT_EOL:
2814126258Smlaier		case TCPOPT_NOP:
2815126258Smlaier			++opt;
2816126258Smlaier			--hlen;
2817126258Smlaier			break;
2818126258Smlaier		case TCPOPT_WINDOW:
2819126258Smlaier			wscale = opt[2];
2820126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
2821126258Smlaier				wscale = TCP_MAX_WINSHIFT;
2822126258Smlaier			wscale |= PF_WSCALE_FLAG;
2823130613Smlaier			/* FALLTHROUGH */
2824126258Smlaier		default:
2825126258Smlaier			optlen = opt[1];
2826126258Smlaier			if (optlen < 2)
2827126258Smlaier				optlen = 2;
2828126258Smlaier			hlen -= optlen;
2829126258Smlaier			opt += optlen;
2830130613Smlaier			break;
2831126258Smlaier		}
2832126258Smlaier	}
2833126258Smlaier	return (wscale);
2834126258Smlaier}
2835126258Smlaier
2836126258Smlaieru_int16_t
2837126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2838126258Smlaier{
2839126258Smlaier	int		 hlen;
2840126258Smlaier	u_int8_t	 hdr[60];
2841126258Smlaier	u_int8_t	*opt, optlen;
2842126258Smlaier	u_int16_t	 mss = tcp_mssdflt;
2843126258Smlaier
2844126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
2845126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2846126258Smlaier		return (0);
2847126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2848126258Smlaier		return (0);
2849126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2850126258Smlaier	hlen -= sizeof(struct tcphdr);
2851126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
2852126258Smlaier		switch (*opt) {
2853126258Smlaier		case TCPOPT_EOL:
2854126258Smlaier		case TCPOPT_NOP:
2855126258Smlaier			++opt;
2856126258Smlaier			--hlen;
2857126258Smlaier			break;
2858126258Smlaier		case TCPOPT_MAXSEG:
2859126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
2860145030Sglebius			NTOHS(mss);
2861130613Smlaier			/* FALLTHROUGH */
2862126258Smlaier		default:
2863126258Smlaier			optlen = opt[1];
2864126258Smlaier			if (optlen < 2)
2865126258Smlaier				optlen = 2;
2866126258Smlaier			hlen -= optlen;
2867126258Smlaier			opt += optlen;
2868130613Smlaier			break;
2869126258Smlaier		}
2870126258Smlaier	}
2871126258Smlaier	return (mss);
2872126258Smlaier}
2873126258Smlaier
2874126258Smlaieru_int16_t
2875126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
2876126258Smlaier{
2877126258Smlaier#ifdef INET
2878126258Smlaier	struct sockaddr_in	*dst;
2879126258Smlaier	struct route		 ro;
2880126258Smlaier#endif /* INET */
2881126258Smlaier#ifdef INET6
2882126258Smlaier	struct sockaddr_in6	*dst6;
2883126258Smlaier	struct route_in6	 ro6;
2884126258Smlaier#endif /* INET6 */
2885126258Smlaier	struct rtentry		*rt = NULL;
2886127629Smlaier	int			 hlen = 0;	/* make the compiler happy */
2887126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2888126258Smlaier
2889126258Smlaier	switch (af) {
2890126258Smlaier#ifdef INET
2891126258Smlaier	case AF_INET:
2892126258Smlaier		hlen = sizeof(struct ip);
2893126258Smlaier		bzero(&ro, sizeof(ro));
2894126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
2895126258Smlaier		dst->sin_family = AF_INET;
2896126258Smlaier		dst->sin_len = sizeof(*dst);
2897126258Smlaier		dst->sin_addr = addr->v4;
2898127145Smlaier#ifdef __FreeBSD__
2899126261Smlaier#ifdef RTF_PRCLONING
2900126261Smlaier		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
2901126261Smlaier#else /* !RTF_PRCLONING */
2902126261Smlaier		rtalloc_ign(&ro, RTF_CLONING);
2903126261Smlaier#endif
2904126261Smlaier#else /* ! __FreeBSD__ */
2905126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
2906126261Smlaier#endif
2907126258Smlaier		rt = ro.ro_rt;
2908126258Smlaier		break;
2909126258Smlaier#endif /* INET */
2910126258Smlaier#ifdef INET6
2911126258Smlaier	case AF_INET6:
2912126258Smlaier		hlen = sizeof(struct ip6_hdr);
2913126258Smlaier		bzero(&ro6, sizeof(ro6));
2914126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
2915126258Smlaier		dst6->sin6_family = AF_INET6;
2916126258Smlaier		dst6->sin6_len = sizeof(*dst6);
2917126258Smlaier		dst6->sin6_addr = addr->v6;
2918127145Smlaier#ifdef __FreeBSD__
2919126261Smlaier#ifdef RTF_PRCLONING
2920126261Smlaier		rtalloc_ign((struct route *)&ro6,
2921126261Smlaier		    (RTF_CLONING | RTF_PRCLONING));
2922126261Smlaier#else /* !RTF_PRCLONING */
2923126261Smlaier		rtalloc_ign((struct route *)&ro6, RTF_CLONING);
2924126261Smlaier#endif
2925126261Smlaier#else /* ! __FreeBSD__ */
2926126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
2927126261Smlaier#endif
2928126258Smlaier		rt = ro6.ro_rt;
2929126258Smlaier		break;
2930126258Smlaier#endif /* INET6 */
2931126258Smlaier	}
2932126258Smlaier
2933126258Smlaier	if (rt && rt->rt_ifp) {
2934126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
2935126258Smlaier		mss = max(tcp_mssdflt, mss);
2936126258Smlaier		RTFREE(rt);
2937126258Smlaier	}
2938126258Smlaier	mss = min(mss, offer);
2939126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
2940126258Smlaier	return (mss);
2941126258Smlaier}
2942126258Smlaier
2943126258Smlaiervoid
2944126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
2945126258Smlaier{
2946126258Smlaier	struct pf_rule *r = s->rule.ptr;
2947126258Smlaier
2948130613Smlaier	s->rt_kif = NULL;
2949126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
2950126258Smlaier		return;
2951126258Smlaier	switch (s->af) {
2952126258Smlaier#ifdef INET
2953126258Smlaier	case AF_INET:
2954130613Smlaier		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
2955130613Smlaier		    &s->nat_src_node);
2956130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2957126258Smlaier		break;
2958126258Smlaier#endif /* INET */
2959126258Smlaier#ifdef INET6
2960126258Smlaier	case AF_INET6:
2961130613Smlaier		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
2962130613Smlaier		    &s->nat_src_node);
2963130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2964126258Smlaier		break;
2965126258Smlaier#endif /* INET6 */
2966126258Smlaier	}
2967126258Smlaier}
2968126258Smlaier
2969126258Smlaierint
2970126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
2971130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
2972135920Smlaier#ifdef __FreeBSD__
2973135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
2974145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
2975135920Smlaier#else
2976145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
2977145836Smlaier    struct ifqueue *ifq)
2978135920Smlaier#endif
2979126258Smlaier{
2980130613Smlaier	struct pf_rule		*nr = NULL;
2981126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
2982126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
2983126258Smlaier	u_int16_t		 bport, nport = 0;
2984126258Smlaier	sa_family_t		 af = pd->af;
2985126258Smlaier	int			 lookup = -1;
2986126258Smlaier	uid_t			 uid;
2987126258Smlaier	gid_t			 gid;
2988126258Smlaier	struct pf_rule		*r, *a = NULL;
2989126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2990130613Smlaier	struct pf_src_node	*nsn = NULL;
2991126258Smlaier	u_short			 reason;
2992126258Smlaier	int			 rewrite = 0;
2993126258Smlaier	struct pf_tag		*pftag = NULL;
2994126258Smlaier	int			 tag = -1;
2995126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2996145836Smlaier	int			 asd = 0;
2997126258Smlaier
2998145836Smlaier	if (pf_check_congestion(ifq)) {
2999145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3000145836Smlaier		return (PF_DROP);
3001145836Smlaier	}
3002145836Smlaier
3003126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3004126258Smlaier
3005126258Smlaier	if (direction == PF_OUT) {
3006126258Smlaier		bport = nport = th->th_sport;
3007126258Smlaier		/* check outgoing packet for BINAT/NAT */
3008130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3009126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3010130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3011130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3012126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3013130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3014126258Smlaier			rewrite++;
3015130613Smlaier			if (nr->natpass)
3016126258Smlaier				r = NULL;
3017130613Smlaier			pd->nat_rule = nr;
3018126258Smlaier		}
3019126258Smlaier	} else {
3020126258Smlaier		bport = nport = th->th_dport;
3021126258Smlaier		/* check incoming packet for BINAT/RDR */
3022130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3023130613Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3024130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3025130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3026126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3027130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3028126258Smlaier			rewrite++;
3029130613Smlaier			if (nr->natpass)
3030126258Smlaier				r = NULL;
3031130613Smlaier			pd->nat_rule = nr;
3032126258Smlaier		}
3033126258Smlaier	}
3034126258Smlaier
3035126258Smlaier	while (r != NULL) {
3036126258Smlaier		r->evaluations++;
3037130613Smlaier		if (r->kif != NULL &&
3038130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3039126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3040126258Smlaier		else if (r->direction && r->direction != direction)
3041126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3042126258Smlaier		else if (r->af && r->af != af)
3043126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3044126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
3045126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3046145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3047126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3048126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3049126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
3050126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3051145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3052126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3053126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3054126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
3055126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3056126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3057126258Smlaier			r = TAILQ_NEXT(r, entries);
3058126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3059126258Smlaier			r = TAILQ_NEXT(r, entries);
3060126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
3061126258Smlaier			r = TAILQ_NEXT(r, entries);
3062126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
3063135920Smlaier#ifdef __FreeBSD__
3064135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3065135920Smlaier#else
3066130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3067135920Smlaier#endif
3068126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3069126258Smlaier		    uid))
3070126258Smlaier			r = TAILQ_NEXT(r, entries);
3071126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
3072135920Smlaier#ifdef __FreeBSD__
3073135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3074135920Smlaier#else
3075130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3076135920Smlaier#endif
3077126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3078126258Smlaier		    gid))
3079126258Smlaier			r = TAILQ_NEXT(r, entries);
3080145836Smlaier		else if (r->prob && r->prob <= arc4random())
3081126258Smlaier			r = TAILQ_NEXT(r, entries);
3082145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3083126258Smlaier			r = TAILQ_NEXT(r, entries);
3084126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
3085126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
3086126258Smlaier			r = TAILQ_NEXT(r, entries);
3087126258Smlaier		else {
3088126258Smlaier			if (r->tag)
3089126258Smlaier				tag = r->tag;
3090126258Smlaier			if (r->anchor == NULL) {
3091126258Smlaier				*rm = r;
3092126258Smlaier				*am = a;
3093126258Smlaier				*rsm = ruleset;
3094126258Smlaier				if ((*rm)->quick)
3095126258Smlaier					break;
3096126258Smlaier				r = TAILQ_NEXT(r, entries);
3097126258Smlaier			} else
3098145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3099145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3100126258Smlaier		}
3101145836Smlaier		if (r == NULL)
3102145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3103145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3104126258Smlaier	}
3105126258Smlaier	r = *rm;
3106126258Smlaier	a = *am;
3107126258Smlaier	ruleset = *rsm;
3108126258Smlaier
3109126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3110126258Smlaier
3111126258Smlaier	if (r->log) {
3112126258Smlaier		if (rewrite)
3113126261Smlaier			m_copyback(m, off, sizeof(*th), (caddr_t)th);
3114130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3115126258Smlaier	}
3116126258Smlaier
3117126258Smlaier	if ((r->action == PF_DROP) &&
3118126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
3119126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
3120126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3121126258Smlaier		/* undo NAT changes, if they have taken place */
3122130613Smlaier		if (nr != NULL) {
3123130613Smlaier			if (direction == PF_OUT) {
3124130613Smlaier				pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3125130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3126130613Smlaier				rewrite++;
3127130613Smlaier			} else {
3128130613Smlaier				pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3129130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3130130613Smlaier				rewrite++;
3131130613Smlaier			}
3132126258Smlaier		}
3133126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
3134126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
3135126258Smlaier		    !(th->th_flags & TH_RST)) {
3136126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
3137126258Smlaier
3138126258Smlaier			if (th->th_flags & TH_SYN)
3139126258Smlaier				ack++;
3140126258Smlaier			if (th->th_flags & TH_FIN)
3141126258Smlaier				ack++;
3142126258Smlaier			pf_send_tcp(r, af, pd->dst,
3143126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3144126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
3145145836Smlaier			    r->return_ttl, 1, pd->eh, kif->pfik_ifp);
3146126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
3147126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3148126258Smlaier			    r->return_icmp & 255, af, r);
3149126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3150126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3151126258Smlaier			    r->return_icmp6 & 255, af, r);
3152126258Smlaier	}
3153126258Smlaier
3154126258Smlaier	if (r->action == PF_DROP)
3155126258Smlaier		return (PF_DROP);
3156126258Smlaier
3157126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3158126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3159126258Smlaier		return (PF_DROP);
3160126258Smlaier	}
3161126258Smlaier
3162130613Smlaier	if (r->keep_state || nr != NULL ||
3163126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
3164126258Smlaier		/* create new state */
3165126258Smlaier		u_int16_t	 len;
3166126258Smlaier		struct pf_state	*s = NULL;
3167130613Smlaier		struct pf_src_node *sn = NULL;
3168126258Smlaier
3169126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
3170130613Smlaier
3171130613Smlaier		/* check maximums */
3172145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3173145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3174145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3175130613Smlaier			goto cleanup;
3176145836Smlaier		}
3177130613Smlaier		/* src node for flter rule */
3178130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3179130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3180145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3181145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3182130613Smlaier			goto cleanup;
3183145836Smlaier		}
3184130613Smlaier		/* src node for translation rule */
3185130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3186130613Smlaier		    ((direction == PF_OUT &&
3187130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3188145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3189145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3190130613Smlaier			goto cleanup;
3191145836Smlaier		}
3192130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3193126258Smlaier		if (s == NULL) {
3194145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3195130613Smlaiercleanup:
3196130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3197130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3198130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3199130613Smlaier				pf_status.src_nodes--;
3200130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3201130613Smlaier			}
3202130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3203130613Smlaier			    nsn->expire == 0) {
3204130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3205130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3206130613Smlaier				pf_status.src_nodes--;
3207130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3208130613Smlaier			}
3209126258Smlaier			return (PF_DROP);
3210126258Smlaier		}
3211126258Smlaier		bzero(s, sizeof(*s));
3212126258Smlaier		s->rule.ptr = r;
3213130613Smlaier		s->nat_rule.ptr = nr;
3214126258Smlaier		s->anchor.ptr = a;
3215145836Smlaier		STATE_INC_COUNTERS(s);
3216126258Smlaier		s->allow_opts = r->allow_opts;
3217126258Smlaier		s->log = r->log & 2;
3218126258Smlaier		s->proto = IPPROTO_TCP;
3219126258Smlaier		s->direction = direction;
3220126258Smlaier		s->af = af;
3221126258Smlaier		if (direction == PF_OUT) {
3222126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3223126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
3224126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3225126258Smlaier			s->ext.port = th->th_dport;
3226130613Smlaier			if (nr != NULL) {
3227130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3228126258Smlaier				s->lan.port = bport;
3229126258Smlaier			} else {
3230126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3231126258Smlaier				s->lan.port = s->gwy.port;
3232126258Smlaier			}
3233126258Smlaier		} else {
3234126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3235126258Smlaier			s->lan.port = th->th_dport;
3236126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3237126258Smlaier			s->ext.port = th->th_sport;
3238130613Smlaier			if (nr != NULL) {
3239130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3240126258Smlaier				s->gwy.port = bport;
3241126258Smlaier			} else {
3242126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3243126258Smlaier				s->gwy.port = s->lan.port;
3244126258Smlaier			}
3245126258Smlaier		}
3246126258Smlaier
3247126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
3248126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
3249126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3250126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
3251126258Smlaier			/* Generate sequence number modulator */
3252145836Smlaier			while ((s->src.seqdiff = htonl(arc4random())) == 0)
3253126258Smlaier				;
3254126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
3255126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
3256126258Smlaier			rewrite = 1;
3257126258Smlaier		} else
3258126258Smlaier			s->src.seqdiff = 0;
3259126258Smlaier		if (th->th_flags & TH_SYN) {
3260126258Smlaier			s->src.seqhi++;
3261126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
3262126258Smlaier		}
3263126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
3264126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
3265126258Smlaier			/* Remove scale factor from initial window */
3266126258Smlaier			int win = s->src.max_win;
3267126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
3268126258Smlaier			s->src.max_win = (win - 1) >>
3269126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
3270126258Smlaier		}
3271126258Smlaier		if (th->th_flags & TH_FIN)
3272126258Smlaier			s->src.seqhi++;
3273126258Smlaier		s->dst.seqhi = 1;
3274126258Smlaier		s->dst.max_win = 1;
3275126258Smlaier		s->src.state = TCPS_SYN_SENT;
3276126258Smlaier		s->dst.state = TCPS_CLOSED;
3277126261Smlaier		s->creation = time_second;
3278126261Smlaier		s->expire = time_second;
3279126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
3280126258Smlaier		pf_set_rt_ifp(s, saddr);
3281130613Smlaier		if (sn != NULL) {
3282130613Smlaier			s->src_node = sn;
3283130613Smlaier			s->src_node->states++;
3284130613Smlaier		}
3285130613Smlaier		if (nsn != NULL) {
3286130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3287130613Smlaier			s->nat_src_node = nsn;
3288130613Smlaier			s->nat_src_node->states++;
3289130613Smlaier		}
3290126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3291126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3292126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3293130613Smlaier			pf_src_tree_remove_state(s);
3294145836Smlaier			STATE_DEC_COUNTERS(s);
3295126258Smlaier			pool_put(&pf_state_pl, s);
3296126258Smlaier			return (PF_DROP);
3297126258Smlaier		}
3298126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3299145836Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
3300145836Smlaier		    &s->src, &s->dst, &rewrite)) {
3301145836Smlaier			/* This really shouldn't happen!!! */
3302145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
3303145836Smlaier			    ("pf_normalize_tcp_stateful failed on first pkt"));
3304126258Smlaier			pf_normalize_tcp_cleanup(s);
3305130613Smlaier			pf_src_tree_remove_state(s);
3306145836Smlaier			STATE_DEC_COUNTERS(s);
3307126258Smlaier			pool_put(&pf_state_pl, s);
3308126258Smlaier			return (PF_DROP);
3309126258Smlaier		}
3310130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3311126258Smlaier			pf_normalize_tcp_cleanup(s);
3312145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3313130613Smlaier			pf_src_tree_remove_state(s);
3314145836Smlaier			STATE_DEC_COUNTERS(s);
3315126258Smlaier			pool_put(&pf_state_pl, s);
3316126258Smlaier			return (PF_DROP);
3317126258Smlaier		} else
3318126258Smlaier			*sm = s;
3319145836Smlaier		if (tag > 0) {
3320145836Smlaier			pf_tag_ref(tag);
3321145836Smlaier			s->tag = tag;
3322145836Smlaier		}
3323126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3324126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
3325126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
3326130613Smlaier			if (nr != NULL) {
3327130613Smlaier				if (direction == PF_OUT) {
3328130613Smlaier					pf_change_ap(saddr, &th->th_sport,
3329130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3330130613Smlaier					    bport, 0, af);
3331130613Smlaier				} else {
3332130613Smlaier					pf_change_ap(daddr, &th->th_dport,
3333130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3334130613Smlaier					    bport, 0, af);
3335130613Smlaier				}
3336130613Smlaier			}
3337145836Smlaier			s->src.seqhi = htonl(arc4random());
3338126258Smlaier			/* Find mss option */
3339126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
3340126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
3341126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
3342126258Smlaier			s->src.mss = mss;
3343126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
3344130613Smlaier			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
3345145836Smlaier			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL);
3346145836Smlaier			REASON_SET(&reason, PFRES_SYNPROXY);
3347126258Smlaier			return (PF_SYNPROXY_DROP);
3348126258Smlaier		}
3349126258Smlaier	}
3350126258Smlaier
3351126258Smlaier	/* copy back packet headers if we performed NAT operations */
3352126258Smlaier	if (rewrite)
3353126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
3354126258Smlaier
3355126258Smlaier	return (PF_PASS);
3356126258Smlaier}
3357126258Smlaier
3358126258Smlaierint
3359126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
3360130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3361135920Smlaier#ifdef __FreeBSD__
3362135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3363145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3364135920Smlaier#else
3365145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3366145836Smlaier    struct ifqueue *ifq)
3367135920Smlaier#endif
3368126258Smlaier{
3369130613Smlaier	struct pf_rule		*nr = NULL;
3370126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3371126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3372126258Smlaier	u_int16_t		 bport, nport = 0;
3373126258Smlaier	sa_family_t		 af = pd->af;
3374126258Smlaier	int			 lookup = -1;
3375126258Smlaier	uid_t			 uid;
3376126258Smlaier	gid_t			 gid;
3377126258Smlaier	struct pf_rule		*r, *a = NULL;
3378126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3379130613Smlaier	struct pf_src_node	*nsn = NULL;
3380126258Smlaier	u_short			 reason;
3381126258Smlaier	int			 rewrite = 0;
3382126258Smlaier	struct pf_tag		*pftag = NULL;
3383126258Smlaier	int			 tag = -1;
3384145836Smlaier	int			 asd = 0;
3385126258Smlaier
3386145836Smlaier	if (pf_check_congestion(ifq)) {
3387145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3388145836Smlaier		return (PF_DROP);
3389145836Smlaier	}
3390145836Smlaier
3391126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3392126258Smlaier
3393126258Smlaier	if (direction == PF_OUT) {
3394126258Smlaier		bport = nport = uh->uh_sport;
3395126258Smlaier		/* check outgoing packet for BINAT/NAT */
3396130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3397126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
3398130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3399130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3400126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3401130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3402126258Smlaier			rewrite++;
3403130613Smlaier			if (nr->natpass)
3404126258Smlaier				r = NULL;
3405130613Smlaier			pd->nat_rule = nr;
3406126258Smlaier		}
3407126258Smlaier	} else {
3408126258Smlaier		bport = nport = uh->uh_dport;
3409126258Smlaier		/* check incoming packet for BINAT/RDR */
3410130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3411130613Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
3412130613Smlaier		    &nport)) != NULL) {
3413130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3414126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3415130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3416126258Smlaier			rewrite++;
3417130613Smlaier			if (nr->natpass)
3418126258Smlaier				r = NULL;
3419130613Smlaier			pd->nat_rule = nr;
3420126258Smlaier		}
3421126258Smlaier	}
3422126258Smlaier
3423126258Smlaier	while (r != NULL) {
3424126258Smlaier		r->evaluations++;
3425130613Smlaier		if (r->kif != NULL &&
3426130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3427126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3428126258Smlaier		else if (r->direction && r->direction != direction)
3429126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3430126258Smlaier		else if (r->af && r->af != af)
3431126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3432126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
3433126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3434145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3435126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3436126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3437126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
3438126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3439145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3440126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3441126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3442126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
3443126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3444126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3445126258Smlaier			r = TAILQ_NEXT(r, entries);
3446126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3447126258Smlaier			r = TAILQ_NEXT(r, entries);
3448126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
3449135920Smlaier#ifdef __FreeBSD__
3450135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3451135920Smlaier#else
3452130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3453135920Smlaier#endif
3454126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3455126258Smlaier		    uid))
3456126258Smlaier			r = TAILQ_NEXT(r, entries);
3457126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
3458135920Smlaier#ifdef __FreeBSD__
3459135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3460135920Smlaier#else
3461130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3462135920Smlaier#endif
3463126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3464126258Smlaier		    gid))
3465126258Smlaier			r = TAILQ_NEXT(r, entries);
3466145836Smlaier		else if (r->prob && r->prob <= arc4random())
3467126258Smlaier			r = TAILQ_NEXT(r, entries);
3468145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3469126258Smlaier			r = TAILQ_NEXT(r, entries);
3470126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3471126258Smlaier			r = TAILQ_NEXT(r, entries);
3472126258Smlaier		else {
3473126258Smlaier			if (r->tag)
3474126258Smlaier				tag = r->tag;
3475126258Smlaier			if (r->anchor == NULL) {
3476126258Smlaier				*rm = r;
3477126258Smlaier				*am = a;
3478126258Smlaier				*rsm = ruleset;
3479126258Smlaier				if ((*rm)->quick)
3480126258Smlaier					break;
3481126258Smlaier				r = TAILQ_NEXT(r, entries);
3482126258Smlaier			} else
3483145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3484145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3485126258Smlaier		}
3486145836Smlaier		if (r == NULL)
3487145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3488145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3489126258Smlaier	}
3490126258Smlaier	r = *rm;
3491126258Smlaier	a = *am;
3492126258Smlaier	ruleset = *rsm;
3493126258Smlaier
3494126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3495126258Smlaier
3496126258Smlaier	if (r->log) {
3497126258Smlaier		if (rewrite)
3498126261Smlaier			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3499130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3500126258Smlaier	}
3501126258Smlaier
3502126258Smlaier	if ((r->action == PF_DROP) &&
3503126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3504126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3505126258Smlaier		/* undo NAT changes, if they have taken place */
3506130613Smlaier		if (nr != NULL) {
3507130613Smlaier			if (direction == PF_OUT) {
3508130613Smlaier				pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3509130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3510130613Smlaier				rewrite++;
3511130613Smlaier			} else {
3512130613Smlaier				pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3513130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3514130613Smlaier				rewrite++;
3515130613Smlaier			}
3516126258Smlaier		}
3517126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3518126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3519126258Smlaier			    r->return_icmp & 255, af, r);
3520126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3521126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3522126258Smlaier			    r->return_icmp6 & 255, af, r);
3523126258Smlaier	}
3524126258Smlaier
3525126258Smlaier	if (r->action == PF_DROP)
3526126258Smlaier		return (PF_DROP);
3527126258Smlaier
3528126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3529126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3530126258Smlaier		return (PF_DROP);
3531126258Smlaier	}
3532126258Smlaier
3533130613Smlaier	if (r->keep_state || nr != NULL) {
3534126258Smlaier		/* create new state */
3535126258Smlaier		struct pf_state	*s = NULL;
3536130613Smlaier		struct pf_src_node *sn = NULL;
3537126258Smlaier
3538130613Smlaier		/* check maximums */
3539145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3540145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3541145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3542130613Smlaier			goto cleanup;
3543145836Smlaier		}
3544130613Smlaier		/* src node for flter rule */
3545130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3546130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3547145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3548145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3549130613Smlaier			goto cleanup;
3550145836Smlaier		}
3551130613Smlaier		/* src node for translation rule */
3552130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3553130613Smlaier		    ((direction == PF_OUT &&
3554130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3555145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3556145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3557130613Smlaier			goto cleanup;
3558145836Smlaier		}
3559130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3560126258Smlaier		if (s == NULL) {
3561145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3562130613Smlaiercleanup:
3563130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3564130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3565130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3566130613Smlaier				pf_status.src_nodes--;
3567130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3568130613Smlaier			}
3569130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3570130613Smlaier			    nsn->expire == 0) {
3571130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3572130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3573130613Smlaier				pf_status.src_nodes--;
3574130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3575130613Smlaier			}
3576126258Smlaier			return (PF_DROP);
3577126258Smlaier		}
3578126258Smlaier		bzero(s, sizeof(*s));
3579126258Smlaier		s->rule.ptr = r;
3580130613Smlaier		s->nat_rule.ptr = nr;
3581126258Smlaier		s->anchor.ptr = a;
3582145836Smlaier		STATE_INC_COUNTERS(s);
3583126258Smlaier		s->allow_opts = r->allow_opts;
3584126258Smlaier		s->log = r->log & 2;
3585126258Smlaier		s->proto = IPPROTO_UDP;
3586126258Smlaier		s->direction = direction;
3587126258Smlaier		s->af = af;
3588126258Smlaier		if (direction == PF_OUT) {
3589126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3590126258Smlaier			s->gwy.port = uh->uh_sport;
3591126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3592126258Smlaier			s->ext.port = uh->uh_dport;
3593130613Smlaier			if (nr != NULL) {
3594130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3595126258Smlaier				s->lan.port = bport;
3596126258Smlaier			} else {
3597126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3598126258Smlaier				s->lan.port = s->gwy.port;
3599126258Smlaier			}
3600126258Smlaier		} else {
3601126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3602126258Smlaier			s->lan.port = uh->uh_dport;
3603126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3604126258Smlaier			s->ext.port = uh->uh_sport;
3605130613Smlaier			if (nr != NULL) {
3606130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3607126258Smlaier				s->gwy.port = bport;
3608126258Smlaier			} else {
3609126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3610126258Smlaier				s->gwy.port = s->lan.port;
3611126258Smlaier			}
3612126258Smlaier		}
3613126258Smlaier		s->src.state = PFUDPS_SINGLE;
3614126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
3615126261Smlaier		s->creation = time_second;
3616126261Smlaier		s->expire = time_second;
3617126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
3618126258Smlaier		pf_set_rt_ifp(s, saddr);
3619130613Smlaier		if (sn != NULL) {
3620130613Smlaier			s->src_node = sn;
3621130613Smlaier			s->src_node->states++;
3622130613Smlaier		}
3623130613Smlaier		if (nsn != NULL) {
3624130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3625130613Smlaier			s->nat_src_node = nsn;
3626130613Smlaier			s->nat_src_node->states++;
3627130613Smlaier		}
3628130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3629145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3630130613Smlaier			pf_src_tree_remove_state(s);
3631145836Smlaier			STATE_DEC_COUNTERS(s);
3632126258Smlaier			pool_put(&pf_state_pl, s);
3633126258Smlaier			return (PF_DROP);
3634126258Smlaier		} else
3635126258Smlaier			*sm = s;
3636145836Smlaier		if (tag > 0) {
3637145836Smlaier			pf_tag_ref(tag);
3638145836Smlaier			s->tag = tag;
3639145836Smlaier		}
3640126258Smlaier	}
3641126258Smlaier
3642126258Smlaier	/* copy back packet headers if we performed NAT operations */
3643126258Smlaier	if (rewrite)
3644126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3645126258Smlaier
3646126258Smlaier	return (PF_PASS);
3647126258Smlaier}
3648126258Smlaier
3649126258Smlaierint
3650126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
3651130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3652145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3653145836Smlaier    struct ifqueue *ifq)
3654126258Smlaier{
3655130613Smlaier	struct pf_rule		*nr = NULL;
3656126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3657126258Smlaier	struct pf_rule		*r, *a = NULL;
3658126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3659130613Smlaier	struct pf_src_node	*nsn = NULL;
3660126258Smlaier	u_short			 reason;
3661149893Smlaier	u_int16_t		 icmpid = 0, bport, nport = 0;
3662126258Smlaier	sa_family_t		 af = pd->af;
3663127629Smlaier	u_int8_t		 icmptype = 0;	/* make the compiler happy */
3664127629Smlaier	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
3665126258Smlaier	int			 state_icmp = 0;
3666126258Smlaier	struct pf_tag		*pftag = NULL;
3667126258Smlaier	int			 tag = -1;
3668126258Smlaier#ifdef INET6
3669126258Smlaier	int			 rewrite = 0;
3670126258Smlaier#endif /* INET6 */
3671145836Smlaier	int			 asd = 0;
3672126258Smlaier
3673145836Smlaier	if (pf_check_congestion(ifq)) {
3674145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3675145836Smlaier		return (PF_DROP);
3676145836Smlaier	}
3677145836Smlaier
3678126258Smlaier	switch (pd->proto) {
3679126258Smlaier#ifdef INET
3680126258Smlaier	case IPPROTO_ICMP:
3681126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
3682126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
3683126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
3684126258Smlaier
3685126258Smlaier		if (icmptype == ICMP_UNREACH ||
3686126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
3687126258Smlaier		    icmptype == ICMP_REDIRECT ||
3688126258Smlaier		    icmptype == ICMP_TIMXCEED ||
3689126258Smlaier		    icmptype == ICMP_PARAMPROB)
3690126258Smlaier			state_icmp++;
3691126258Smlaier		break;
3692126258Smlaier#endif /* INET */
3693126258Smlaier#ifdef INET6
3694126258Smlaier	case IPPROTO_ICMPV6:
3695126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
3696126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
3697126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
3698126258Smlaier
3699126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
3700126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
3701126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
3702126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
3703126258Smlaier			state_icmp++;
3704126258Smlaier		break;
3705126258Smlaier#endif /* INET6 */
3706126258Smlaier	}
3707126258Smlaier
3708126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3709126258Smlaier
3710126258Smlaier	if (direction == PF_OUT) {
3711149884Smlaier		bport = nport = icmpid;
3712126258Smlaier		/* check outgoing packet for BINAT/NAT */
3713130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3714149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
3715149884Smlaier		    NULL) {
3716130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3717126258Smlaier			switch (af) {
3718126258Smlaier#ifdef INET
3719126258Smlaier			case AF_INET:
3720126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3721130613Smlaier				    pd->naddr.v4.s_addr, 0);
3722149884Smlaier				pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
3723149884Smlaier				    pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
3724149884Smlaier				pd->hdr.icmp->icmp_id = nport;
3725149893Smlaier				m_copyback(m, off, ICMP_MINLEN,
3726149893Smlaier				    (caddr_t)pd->hdr.icmp);
3727126258Smlaier				break;
3728126258Smlaier#endif /* INET */
3729126258Smlaier#ifdef INET6
3730126258Smlaier			case AF_INET6:
3731126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
3732130613Smlaier				    &pd->naddr, 0);
3733126258Smlaier				rewrite++;
3734126258Smlaier				break;
3735126258Smlaier#endif /* INET6 */
3736126258Smlaier			}
3737130613Smlaier			if (nr->natpass)
3738126258Smlaier				r = NULL;
3739130613Smlaier			pd->nat_rule = nr;
3740126258Smlaier		}
3741126258Smlaier	} else {
3742149884Smlaier		bport = nport = icmpid;
3743126258Smlaier		/* check incoming packet for BINAT/RDR */
3744130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3745149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
3746149884Smlaier		    NULL) {
3747130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3748126258Smlaier			switch (af) {
3749126258Smlaier#ifdef INET
3750126258Smlaier			case AF_INET:
3751126258Smlaier				pf_change_a(&daddr->v4.s_addr,
3752130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
3753126258Smlaier				break;
3754126258Smlaier#endif /* INET */
3755126258Smlaier#ifdef INET6
3756126258Smlaier			case AF_INET6:
3757126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
3758130613Smlaier				    &pd->naddr, 0);
3759126258Smlaier				rewrite++;
3760126258Smlaier				break;
3761126258Smlaier#endif /* INET6 */
3762126258Smlaier			}
3763130613Smlaier			if (nr->natpass)
3764126258Smlaier				r = NULL;
3765130613Smlaier			pd->nat_rule = nr;
3766126258Smlaier		}
3767126258Smlaier	}
3768126258Smlaier
3769126258Smlaier	while (r != NULL) {
3770126258Smlaier		r->evaluations++;
3771130613Smlaier		if (r->kif != NULL &&
3772130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3773126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3774126258Smlaier		else if (r->direction && r->direction != direction)
3775126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3776126258Smlaier		else if (r->af && r->af != af)
3777126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3778126258Smlaier		else if (r->proto && r->proto != pd->proto)
3779126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3780145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3781126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3782145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3783126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3784126258Smlaier		else if (r->type && r->type != icmptype + 1)
3785126258Smlaier			r = TAILQ_NEXT(r, entries);
3786126258Smlaier		else if (r->code && r->code != icmpcode + 1)
3787126258Smlaier			r = TAILQ_NEXT(r, entries);
3788126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3789126258Smlaier			r = TAILQ_NEXT(r, entries);
3790126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3791126258Smlaier			r = TAILQ_NEXT(r, entries);
3792145836Smlaier		else if (r->prob && r->prob <= arc4random())
3793126258Smlaier			r = TAILQ_NEXT(r, entries);
3794145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3795126258Smlaier			r = TAILQ_NEXT(r, entries);
3796126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3797126258Smlaier			r = TAILQ_NEXT(r, entries);
3798126258Smlaier		else {
3799126258Smlaier			if (r->tag)
3800126258Smlaier				tag = r->tag;
3801126258Smlaier			if (r->anchor == NULL) {
3802126258Smlaier				*rm = r;
3803126258Smlaier				*am = a;
3804126258Smlaier				*rsm = ruleset;
3805126258Smlaier				if ((*rm)->quick)
3806126258Smlaier					break;
3807126258Smlaier				r = TAILQ_NEXT(r, entries);
3808126258Smlaier			} else
3809145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3810145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3811126258Smlaier		}
3812145836Smlaier		if (r == NULL)
3813145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3814145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3815126258Smlaier	}
3816126258Smlaier	r = *rm;
3817126258Smlaier	a = *am;
3818126258Smlaier	ruleset = *rsm;
3819126258Smlaier
3820126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3821126258Smlaier
3822126258Smlaier	if (r->log) {
3823126258Smlaier#ifdef INET6
3824126258Smlaier		if (rewrite)
3825126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
3826126261Smlaier			    (caddr_t)pd->hdr.icmp6);
3827126258Smlaier#endif /* INET6 */
3828130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3829126258Smlaier	}
3830126258Smlaier
3831126258Smlaier	if (r->action != PF_PASS)
3832126258Smlaier		return (PF_DROP);
3833126258Smlaier
3834126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3835126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3836126258Smlaier		return (PF_DROP);
3837126258Smlaier	}
3838126258Smlaier
3839130613Smlaier	if (!state_icmp && (r->keep_state || nr != NULL)) {
3840126258Smlaier		/* create new state */
3841126258Smlaier		struct pf_state	*s = NULL;
3842130613Smlaier		struct pf_src_node *sn = NULL;
3843126258Smlaier
3844130613Smlaier		/* check maximums */
3845145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3846145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3847145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3848130613Smlaier			goto cleanup;
3849145836Smlaier		}
3850130613Smlaier		/* src node for flter rule */
3851130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3852130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3853145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3854145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3855130613Smlaier			goto cleanup;
3856145836Smlaier		}
3857130613Smlaier		/* src node for translation rule */
3858130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3859130613Smlaier		    ((direction == PF_OUT &&
3860130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3861145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3862145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3863130613Smlaier			goto cleanup;
3864145836Smlaier		}
3865130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3866126258Smlaier		if (s == NULL) {
3867145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3868130613Smlaiercleanup:
3869130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3870130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3871130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3872130613Smlaier				pf_status.src_nodes--;
3873130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3874130613Smlaier			}
3875130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3876130613Smlaier			    nsn->expire == 0) {
3877130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3878130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3879130613Smlaier				pf_status.src_nodes--;
3880130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3881130613Smlaier			}
3882126258Smlaier			return (PF_DROP);
3883126258Smlaier		}
3884126258Smlaier		bzero(s, sizeof(*s));
3885126258Smlaier		s->rule.ptr = r;
3886130613Smlaier		s->nat_rule.ptr = nr;
3887126258Smlaier		s->anchor.ptr = a;
3888145836Smlaier		STATE_INC_COUNTERS(s);
3889126258Smlaier		s->allow_opts = r->allow_opts;
3890126258Smlaier		s->log = r->log & 2;
3891126258Smlaier		s->proto = pd->proto;
3892126258Smlaier		s->direction = direction;
3893126258Smlaier		s->af = af;
3894126258Smlaier		if (direction == PF_OUT) {
3895126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3896149884Smlaier			s->gwy.port = nport;
3897126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3898149884Smlaier			s->ext.port = 0;
3899149884Smlaier			if (nr != NULL) {
3900130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3901149884Smlaier				s->lan.port = bport;
3902149884Smlaier			} else {
3903126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3904149884Smlaier				s->lan.port = s->gwy.port;
3905149884Smlaier			}
3906126258Smlaier		} else {
3907126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3908149884Smlaier			s->lan.port = nport;
3909126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3910149884Smlaier			s->ext.port = 0;
3911149884Smlaier			if (nr != NULL) {
3912130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3913149884Smlaier				s->gwy.port = bport;
3914149884Smlaier			} else {
3915126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3916149884Smlaier				s->gwy.port = s->lan.port;
3917149884Smlaier			}
3918126258Smlaier		}
3919126261Smlaier		s->creation = time_second;
3920126261Smlaier		s->expire = time_second;
3921126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
3922126258Smlaier		pf_set_rt_ifp(s, saddr);
3923130613Smlaier		if (sn != NULL) {
3924130613Smlaier			s->src_node = sn;
3925130613Smlaier			s->src_node->states++;
3926130613Smlaier		}
3927130613Smlaier		if (nsn != NULL) {
3928130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3929130613Smlaier			s->nat_src_node = nsn;
3930130613Smlaier			s->nat_src_node->states++;
3931130613Smlaier		}
3932130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3933145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3934130613Smlaier			pf_src_tree_remove_state(s);
3935145836Smlaier			STATE_DEC_COUNTERS(s);
3936126258Smlaier			pool_put(&pf_state_pl, s);
3937126258Smlaier			return (PF_DROP);
3938126258Smlaier		} else
3939126258Smlaier			*sm = s;
3940145836Smlaier		if (tag > 0) {
3941145836Smlaier			pf_tag_ref(tag);
3942145836Smlaier			s->tag = tag;
3943145836Smlaier		}
3944126258Smlaier	}
3945126258Smlaier
3946126258Smlaier#ifdef INET6
3947126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
3948126258Smlaier	if (rewrite)
3949126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
3950126261Smlaier		    (caddr_t)pd->hdr.icmp6);
3951126258Smlaier#endif /* INET6 */
3952126258Smlaier
3953126258Smlaier	return (PF_PASS);
3954126258Smlaier}
3955126258Smlaier
3956126258Smlaierint
3957126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
3958130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
3959145836Smlaier    struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
3960126258Smlaier{
3961130613Smlaier	struct pf_rule		*nr = NULL;
3962126258Smlaier	struct pf_rule		*r, *a = NULL;
3963126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3964130613Smlaier	struct pf_src_node	*nsn = NULL;
3965126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3966126258Smlaier	sa_family_t		 af = pd->af;
3967126258Smlaier	u_short			 reason;
3968126258Smlaier	struct pf_tag		*pftag = NULL;
3969126258Smlaier	int			 tag = -1;
3970145836Smlaier	int			 asd = 0;
3971126258Smlaier
3972145836Smlaier	if (pf_check_congestion(ifq)) {
3973145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3974145836Smlaier		return (PF_DROP);
3975145836Smlaier	}
3976145836Smlaier
3977126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3978126258Smlaier
3979126258Smlaier	if (direction == PF_OUT) {
3980126258Smlaier		/* check outgoing packet for BINAT/NAT */
3981130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3982130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
3983130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3984126258Smlaier			switch (af) {
3985126258Smlaier#ifdef INET
3986126258Smlaier			case AF_INET:
3987126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3988130613Smlaier				    pd->naddr.v4.s_addr, 0);
3989126258Smlaier				break;
3990126258Smlaier#endif /* INET */
3991126258Smlaier#ifdef INET6
3992126258Smlaier			case AF_INET6:
3993130613Smlaier				PF_ACPY(saddr, &pd->naddr, af);
3994126258Smlaier				break;
3995126258Smlaier#endif /* INET6 */
3996126258Smlaier			}
3997130613Smlaier			if (nr->natpass)
3998126258Smlaier				r = NULL;
3999130613Smlaier			pd->nat_rule = nr;
4000126258Smlaier		}
4001126258Smlaier	} else {
4002126258Smlaier		/* check incoming packet for BINAT/RDR */
4003130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4004130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4005130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4006126258Smlaier			switch (af) {
4007126258Smlaier#ifdef INET
4008126258Smlaier			case AF_INET:
4009126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4010130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4011126258Smlaier				break;
4012126258Smlaier#endif /* INET */
4013126258Smlaier#ifdef INET6
4014126258Smlaier			case AF_INET6:
4015130613Smlaier				PF_ACPY(daddr, &pd->naddr, af);
4016126258Smlaier				break;
4017126258Smlaier#endif /* INET6 */
4018126258Smlaier			}
4019130613Smlaier			if (nr->natpass)
4020126258Smlaier				r = NULL;
4021130613Smlaier			pd->nat_rule = nr;
4022126258Smlaier		}
4023126258Smlaier	}
4024126258Smlaier
4025126258Smlaier	while (r != NULL) {
4026126258Smlaier		r->evaluations++;
4027130613Smlaier		if (r->kif != NULL &&
4028130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
4029126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4030126258Smlaier		else if (r->direction && r->direction != direction)
4031126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4032126258Smlaier		else if (r->af && r->af != af)
4033126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4034126258Smlaier		else if (r->proto && r->proto != pd->proto)
4035126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4036145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
4037126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4038145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
4039126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4040126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
4041126258Smlaier			r = TAILQ_NEXT(r, entries);
4042126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4043126258Smlaier			r = TAILQ_NEXT(r, entries);
4044145836Smlaier		else if (r->prob && r->prob <= arc4random())
4045126258Smlaier			r = TAILQ_NEXT(r, entries);
4046145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
4047126258Smlaier			r = TAILQ_NEXT(r, entries);
4048126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4049126258Smlaier			r = TAILQ_NEXT(r, entries);
4050126258Smlaier		else {
4051126258Smlaier			if (r->tag)
4052126258Smlaier				tag = r->tag;
4053126258Smlaier			if (r->anchor == NULL) {
4054126258Smlaier				*rm = r;
4055126258Smlaier				*am = a;
4056126258Smlaier				*rsm = ruleset;
4057126258Smlaier				if ((*rm)->quick)
4058126258Smlaier					break;
4059126258Smlaier				r = TAILQ_NEXT(r, entries);
4060126258Smlaier			} else
4061145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4062145836Smlaier				    PF_RULESET_FILTER, &r, &a);
4063126258Smlaier		}
4064145836Smlaier		if (r == NULL)
4065145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
4066145836Smlaier			    PF_RULESET_FILTER, &r, &a);
4067126258Smlaier	}
4068126258Smlaier	r = *rm;
4069126258Smlaier	a = *am;
4070126258Smlaier	ruleset = *rsm;
4071126258Smlaier
4072126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4073130613Smlaier
4074126258Smlaier	if (r->log)
4075130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
4076126258Smlaier
4077126258Smlaier	if ((r->action == PF_DROP) &&
4078126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
4079126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
4080126258Smlaier		struct pf_addr *a = NULL;
4081126258Smlaier
4082130613Smlaier		if (nr != NULL) {
4083130613Smlaier			if (direction == PF_OUT)
4084130613Smlaier				a = saddr;
4085130613Smlaier			else
4086130613Smlaier				a = daddr;
4087130613Smlaier		}
4088126258Smlaier		if (a != NULL) {
4089126258Smlaier			switch (af) {
4090126258Smlaier#ifdef INET
4091126258Smlaier			case AF_INET:
4092126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
4093130613Smlaier				    pd->baddr.v4.s_addr, 0);
4094126258Smlaier				break;
4095126258Smlaier#endif /* INET */
4096126258Smlaier#ifdef INET6
4097126258Smlaier			case AF_INET6:
4098130613Smlaier				PF_ACPY(a, &pd->baddr, af);
4099126258Smlaier				break;
4100126258Smlaier#endif /* INET6 */
4101126258Smlaier			}
4102126258Smlaier		}
4103126258Smlaier		if ((af == AF_INET) && r->return_icmp)
4104126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
4105126258Smlaier			    r->return_icmp & 255, af, r);
4106126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
4107126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
4108126258Smlaier			    r->return_icmp6 & 255, af, r);
4109126258Smlaier	}
4110126258Smlaier
4111126258Smlaier	if (r->action != PF_PASS)
4112126258Smlaier		return (PF_DROP);
4113126258Smlaier
4114126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
4115126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4116126258Smlaier		return (PF_DROP);
4117126258Smlaier	}
4118126258Smlaier
4119130613Smlaier	if (r->keep_state || nr != NULL) {
4120126258Smlaier		/* create new state */
4121126258Smlaier		struct pf_state	*s = NULL;
4122130613Smlaier		struct pf_src_node *sn = NULL;
4123126258Smlaier
4124130613Smlaier		/* check maximums */
4125145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4126145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4127145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4128130613Smlaier			goto cleanup;
4129145836Smlaier		}
4130130613Smlaier		/* src node for flter rule */
4131130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4132130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4133145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4134145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4135130613Smlaier			goto cleanup;
4136145836Smlaier		}
4137130613Smlaier		/* src node for translation rule */
4138130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4139130613Smlaier		    ((direction == PF_OUT &&
4140130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4141145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4142145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4143130613Smlaier			goto cleanup;
4144145836Smlaier		}
4145130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4146126258Smlaier		if (s == NULL) {
4147145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4148130613Smlaiercleanup:
4149130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4150130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4151130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4152130613Smlaier				pf_status.src_nodes--;
4153130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4154130613Smlaier			}
4155130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4156130613Smlaier			    nsn->expire == 0) {
4157130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4158130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4159130613Smlaier				pf_status.src_nodes--;
4160130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4161130613Smlaier			}
4162126258Smlaier			return (PF_DROP);
4163126258Smlaier		}
4164126258Smlaier		bzero(s, sizeof(*s));
4165126258Smlaier		s->rule.ptr = r;
4166130613Smlaier		s->nat_rule.ptr = nr;
4167126258Smlaier		s->anchor.ptr = a;
4168145836Smlaier		STATE_INC_COUNTERS(s);
4169126258Smlaier		s->allow_opts = r->allow_opts;
4170126258Smlaier		s->log = r->log & 2;
4171126258Smlaier		s->proto = pd->proto;
4172126258Smlaier		s->direction = direction;
4173126258Smlaier		s->af = af;
4174126258Smlaier		if (direction == PF_OUT) {
4175126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4176126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4177130613Smlaier			if (nr != NULL)
4178130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4179126258Smlaier			else
4180126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4181126258Smlaier		} else {
4182126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4183126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4184130613Smlaier			if (nr != NULL)
4185130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4186126258Smlaier			else
4187126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4188126258Smlaier		}
4189126258Smlaier		s->src.state = PFOTHERS_SINGLE;
4190126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
4191126261Smlaier		s->creation = time_second;
4192126261Smlaier		s->expire = time_second;
4193126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
4194126258Smlaier		pf_set_rt_ifp(s, saddr);
4195130613Smlaier		if (sn != NULL) {
4196130613Smlaier			s->src_node = sn;
4197130613Smlaier			s->src_node->states++;
4198130613Smlaier		}
4199130613Smlaier		if (nsn != NULL) {
4200130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4201130613Smlaier			s->nat_src_node = nsn;
4202130613Smlaier			s->nat_src_node->states++;
4203130613Smlaier		}
4204130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4205145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4206130613Smlaier			pf_src_tree_remove_state(s);
4207145836Smlaier			STATE_DEC_COUNTERS(s);
4208126258Smlaier			pool_put(&pf_state_pl, s);
4209126258Smlaier			return (PF_DROP);
4210126258Smlaier		} else
4211126258Smlaier			*sm = s;
4212145836Smlaier		if (tag > 0) {
4213145836Smlaier			pf_tag_ref(tag);
4214145836Smlaier			s->tag = tag;
4215145836Smlaier		}
4216126258Smlaier	}
4217126258Smlaier
4218126258Smlaier	return (PF_PASS);
4219126258Smlaier}
4220126258Smlaier
4221126258Smlaierint
4222130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
4223126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
4224126258Smlaier    struct pf_ruleset **rsm)
4225126258Smlaier{
4226126258Smlaier	struct pf_rule		*r, *a = NULL;
4227126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4228126258Smlaier	sa_family_t		 af = pd->af;
4229126258Smlaier	u_short			 reason;
4230126258Smlaier	struct pf_tag		*pftag = NULL;
4231126258Smlaier	int			 tag = -1;
4232145836Smlaier	int			 asd = 0;
4233126258Smlaier
4234126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4235126258Smlaier	while (r != NULL) {
4236126258Smlaier		r->evaluations++;
4237130613Smlaier		if (r->kif != NULL &&
4238130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
4239126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4240126258Smlaier		else if (r->direction && r->direction != direction)
4241126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4242126258Smlaier		else if (r->af && r->af != af)
4243126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4244126258Smlaier		else if (r->proto && r->proto != pd->proto)
4245126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4246145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
4247126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4248145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
4249126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4250126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
4251126258Smlaier			r = TAILQ_NEXT(r, entries);
4252126258Smlaier		else if (r->src.port_op || r->dst.port_op ||
4253126258Smlaier		    r->flagset || r->type || r->code ||
4254126258Smlaier		    r->os_fingerprint != PF_OSFP_ANY)
4255126258Smlaier			r = TAILQ_NEXT(r, entries);
4256145836Smlaier		else if (r->prob && r->prob <= arc4random())
4257126258Smlaier			r = TAILQ_NEXT(r, entries);
4258145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
4259126258Smlaier			r = TAILQ_NEXT(r, entries);
4260126258Smlaier		else {
4261126258Smlaier			if (r->anchor == NULL) {
4262126258Smlaier				*rm = r;
4263126258Smlaier				*am = a;
4264126258Smlaier				*rsm = ruleset;
4265126258Smlaier				if ((*rm)->quick)
4266126258Smlaier					break;
4267126258Smlaier				r = TAILQ_NEXT(r, entries);
4268126258Smlaier			} else
4269145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4270145836Smlaier				    PF_RULESET_FILTER, &r, &a);
4271126258Smlaier		}
4272145836Smlaier		if (r == NULL)
4273145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
4274145836Smlaier			    PF_RULESET_FILTER, &r, &a);
4275126258Smlaier	}
4276126258Smlaier	r = *rm;
4277126258Smlaier	a = *am;
4278126258Smlaier	ruleset = *rsm;
4279126258Smlaier
4280126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4281130613Smlaier
4282126258Smlaier	if (r->log)
4283130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
4284126258Smlaier
4285126258Smlaier	if (r->action != PF_PASS)
4286126258Smlaier		return (PF_DROP);
4287126258Smlaier
4288126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
4289126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4290126258Smlaier		return (PF_DROP);
4291126258Smlaier	}
4292126258Smlaier
4293126258Smlaier	return (PF_PASS);
4294126258Smlaier}
4295126258Smlaier
4296126258Smlaierint
4297130613Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
4298130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4299126258Smlaier    u_short *reason)
4300126258Smlaier{
4301130613Smlaier	struct pf_state		 key;
4302126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
4303126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
4304145836Smlaier	u_int32_t		 ack, end, seq, orig_seq;
4305126258Smlaier	u_int8_t		 sws, dws;
4306130613Smlaier	int			 ackskew;
4307126258Smlaier	int			 copyback = 0;
4308126258Smlaier	struct pf_state_peer	*src, *dst;
4309126258Smlaier
4310126258Smlaier	key.af = pd->af;
4311126258Smlaier	key.proto = IPPROTO_TCP;
4312130613Smlaier	if (direction == PF_IN)	{
4313130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4314130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4315130613Smlaier		key.ext.port = th->th_sport;
4316130613Smlaier		key.gwy.port = th->th_dport;
4317130613Smlaier	} else {
4318130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4319130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4320130613Smlaier		key.lan.port = th->th_sport;
4321130613Smlaier		key.ext.port = th->th_dport;
4322130613Smlaier	}
4323126258Smlaier
4324126258Smlaier	STATE_LOOKUP();
4325126258Smlaier
4326126258Smlaier	if (direction == (*state)->direction) {
4327126258Smlaier		src = &(*state)->src;
4328126258Smlaier		dst = &(*state)->dst;
4329126258Smlaier	} else {
4330126258Smlaier		src = &(*state)->dst;
4331126258Smlaier		dst = &(*state)->src;
4332126258Smlaier	}
4333126258Smlaier
4334126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4335145836Smlaier		if (direction != (*state)->direction) {
4336145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4337126258Smlaier			return (PF_SYNPROXY_DROP);
4338145836Smlaier		}
4339126258Smlaier		if (th->th_flags & TH_SYN) {
4340145836Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo) {
4341145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4342126258Smlaier				return (PF_DROP);
4343145836Smlaier			}
4344126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4345126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4346126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4347145836Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
4348145836Smlaier			    NULL, NULL);
4349145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4350126258Smlaier			return (PF_SYNPROXY_DROP);
4351126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
4352126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4353145836Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4354145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4355126258Smlaier			return (PF_DROP);
4356145836Smlaier		} else if ((*state)->src_node != NULL &&
4357145836Smlaier		    pf_src_connlimit(state)) {
4358145836Smlaier			REASON_SET(reason, PFRES_SRCLIMIT);
4359145836Smlaier			return (PF_DROP);
4360145836Smlaier		} else
4361126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
4362126258Smlaier	}
4363126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4364126258Smlaier		struct pf_state_host *src, *dst;
4365126258Smlaier
4366126258Smlaier		if (direction == PF_OUT) {
4367126258Smlaier			src = &(*state)->gwy;
4368126258Smlaier			dst = &(*state)->ext;
4369126258Smlaier		} else {
4370126258Smlaier			src = &(*state)->ext;
4371126258Smlaier			dst = &(*state)->lan;
4372126258Smlaier		}
4373126258Smlaier		if (direction == (*state)->direction) {
4374126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4375126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4376145836Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4377145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4378126258Smlaier				return (PF_DROP);
4379145836Smlaier			}
4380126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4381126258Smlaier			if ((*state)->dst.seqhi == 1)
4382145836Smlaier				(*state)->dst.seqhi = htonl(arc4random());
4383126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4384126258Smlaier			    &dst->addr, src->port, dst->port,
4385130613Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4386145836Smlaier			    (*state)->src.mss, 0, 0, NULL, NULL);
4387145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4388126258Smlaier			return (PF_SYNPROXY_DROP);
4389126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4390126258Smlaier		    (TH_SYN|TH_ACK)) ||
4391145836Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
4392145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4393126258Smlaier			return (PF_DROP);
4394145836Smlaier		} else {
4395126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4396126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
4397126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4398126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4399126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4400145836Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
4401145836Smlaier			    NULL, NULL);
4402126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4403126258Smlaier			    &dst->addr, src->port, dst->port,
4404126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4405145836Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
4406145836Smlaier			    NULL, NULL);
4407126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
4408126258Smlaier			    (*state)->src.seqlo;
4409126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
4410126258Smlaier			    (*state)->dst.seqlo;
4411126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
4412145875Smlaier			    (*state)->dst.max_win;
4413145875Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
4414145836Smlaier			    (*state)->src.max_win;
4415126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
4416126258Smlaier			(*state)->src.state = (*state)->dst.state =
4417126258Smlaier			    TCPS_ESTABLISHED;
4418145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4419126258Smlaier			return (PF_SYNPROXY_DROP);
4420126258Smlaier		}
4421126258Smlaier	}
4422126258Smlaier
4423126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4424126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4425126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4426126258Smlaier	} else
4427126258Smlaier		sws = dws = 0;
4428126258Smlaier
4429126258Smlaier	/*
4430126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4431126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4432126258Smlaier	 *	tcp_filtering.ps
4433126258Smlaier	 */
4434126258Smlaier
4435145836Smlaier	orig_seq = seq = ntohl(th->th_seq);
4436126258Smlaier	if (src->seqlo == 0) {
4437126258Smlaier		/* First packet from this end. Set its state */
4438126258Smlaier
4439126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4440126258Smlaier		    src->scrub == NULL) {
4441126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4442126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4443126258Smlaier				return (PF_DROP);
4444126258Smlaier			}
4445126258Smlaier		}
4446126258Smlaier
4447126258Smlaier		/* Deferred generation of sequence number modulator */
4448126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4449145836Smlaier			while ((src->seqdiff = htonl(arc4random())) == 0)
4450126258Smlaier				;
4451126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4452126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4453126258Smlaier			    src->seqdiff), 0);
4454126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4455126258Smlaier			copyback = 1;
4456126258Smlaier		} else {
4457126258Smlaier			ack = ntohl(th->th_ack);
4458126258Smlaier		}
4459126258Smlaier
4460126258Smlaier		end = seq + pd->p_len;
4461126258Smlaier		if (th->th_flags & TH_SYN) {
4462126258Smlaier			end++;
4463126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4464126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4465126258Smlaier				    pd->af);
4466126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4467126258Smlaier					/* Remove scale factor from initial
4468126258Smlaier					 * window */
4469126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4470126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4471126258Smlaier					    >> sws;
4472126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4473126258Smlaier				} else {
4474126258Smlaier					/* fixup other window */
4475126258Smlaier					dst->max_win <<= dst->wscale &
4476126258Smlaier					    PF_WSCALE_MASK;
4477126258Smlaier					/* in case of a retrans SYN|ACK */
4478126258Smlaier					dst->wscale = 0;
4479126258Smlaier				}
4480126258Smlaier			}
4481126258Smlaier		}
4482126258Smlaier		if (th->th_flags & TH_FIN)
4483126258Smlaier			end++;
4484126258Smlaier
4485126258Smlaier		src->seqlo = seq;
4486126258Smlaier		if (src->state < TCPS_SYN_SENT)
4487126258Smlaier			src->state = TCPS_SYN_SENT;
4488126258Smlaier
4489126258Smlaier		/*
4490126258Smlaier		 * May need to slide the window (seqhi may have been set by
4491126258Smlaier		 * the crappy stack check or if we picked up the connection
4492126258Smlaier		 * after establishment)
4493126258Smlaier		 */
4494126258Smlaier		if (src->seqhi == 1 ||
4495126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4496126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4497126258Smlaier		if (win > src->max_win)
4498126258Smlaier			src->max_win = win;
4499126258Smlaier
4500126258Smlaier	} else {
4501126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4502126258Smlaier		if (src->seqdiff) {
4503126258Smlaier			/* Modulate sequence numbers */
4504126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4505126258Smlaier			    src->seqdiff), 0);
4506126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4507126258Smlaier			copyback = 1;
4508126258Smlaier		}
4509126258Smlaier		end = seq + pd->p_len;
4510126258Smlaier		if (th->th_flags & TH_SYN)
4511126258Smlaier			end++;
4512126258Smlaier		if (th->th_flags & TH_FIN)
4513126258Smlaier			end++;
4514126258Smlaier	}
4515126258Smlaier
4516126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4517126258Smlaier		/* Let it pass through the ack skew check */
4518126258Smlaier		ack = dst->seqlo;
4519126258Smlaier	} else if ((ack == 0 &&
4520126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4521126258Smlaier	    /* broken tcp stacks do not set ack */
4522126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4523126258Smlaier		/*
4524126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4525126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4526126258Smlaier		 */
4527126258Smlaier		ack = dst->seqlo;
4528126258Smlaier	}
4529126258Smlaier
4530126258Smlaier	if (seq == end) {
4531126258Smlaier		/* Ease sequencing restrictions on no data packets */
4532126258Smlaier		seq = src->seqlo;
4533126258Smlaier		end = seq;
4534126258Smlaier	}
4535126258Smlaier
4536126258Smlaier	ackskew = dst->seqlo - ack;
4537126258Smlaier
4538126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4539126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4540126258Smlaier	    /* Last octet inside other's window space */
4541126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4542126258Smlaier	    /* Retrans: not more than one window back */
4543126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4544126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4545145836Smlaier	    (ackskew <= (MAXACKWINDOW << sws)) &&
4546126258Smlaier	    /* Acking not more than one window forward */
4547145836Smlaier	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
4548145836Smlaier	    (pd->flags & PFDESC_IP_REAS) == 0)) {
4549145836Smlaier	    /* Require an exact sequence match on resets when possible */
4550126258Smlaier
4551145836Smlaier		if (dst->scrub || src->scrub) {
4552145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4553145836Smlaier			    *state, src, dst, &copyback))
4554145836Smlaier				return (PF_DROP);
4555145836Smlaier		}
4556145836Smlaier
4557126258Smlaier		/* update max window */
4558126258Smlaier		if (src->max_win < win)
4559126258Smlaier			src->max_win = win;
4560126258Smlaier		/* synchronize sequencing */
4561126258Smlaier		if (SEQ_GT(end, src->seqlo))
4562126258Smlaier			src->seqlo = end;
4563126258Smlaier		/* slide the window of what the other end can send */
4564126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4565126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4566126258Smlaier
4567126258Smlaier
4568126258Smlaier		/* update states */
4569126258Smlaier		if (th->th_flags & TH_SYN)
4570126258Smlaier			if (src->state < TCPS_SYN_SENT)
4571126258Smlaier				src->state = TCPS_SYN_SENT;
4572126258Smlaier		if (th->th_flags & TH_FIN)
4573126258Smlaier			if (src->state < TCPS_CLOSING)
4574126258Smlaier				src->state = TCPS_CLOSING;
4575126258Smlaier		if (th->th_flags & TH_ACK) {
4576145836Smlaier			if (dst->state == TCPS_SYN_SENT) {
4577126258Smlaier				dst->state = TCPS_ESTABLISHED;
4578145836Smlaier				if (src->state == TCPS_ESTABLISHED &&
4579145836Smlaier				    (*state)->src_node != NULL &&
4580145836Smlaier				    pf_src_connlimit(state)) {
4581145836Smlaier					REASON_SET(reason, PFRES_SRCLIMIT);
4582145836Smlaier					return (PF_DROP);
4583145836Smlaier				}
4584145836Smlaier			} else if (dst->state == TCPS_CLOSING)
4585126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
4586126258Smlaier		}
4587126258Smlaier		if (th->th_flags & TH_RST)
4588126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4589126258Smlaier
4590126258Smlaier		/* update expire time */
4591126261Smlaier		(*state)->expire = time_second;
4592126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
4593126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4594126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
4595126258Smlaier		else if (src->state >= TCPS_FIN_WAIT_2 ||
4596126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4597126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
4598126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
4599126258Smlaier		    dst->state < TCPS_ESTABLISHED)
4600126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
4601126258Smlaier		else if (src->state >= TCPS_CLOSING ||
4602126258Smlaier		    dst->state >= TCPS_CLOSING)
4603126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
4604126258Smlaier		else
4605126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
4606126258Smlaier
4607126258Smlaier		/* Fall through to PASS packet */
4608126258Smlaier
4609126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
4610126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
4611126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
4612126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
4613126258Smlaier	    /* Within a window forward of the originating packet */
4614126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
4615126258Smlaier	    /* Within a window backward of the originating packet */
4616126258Smlaier
4617126258Smlaier		/*
4618126258Smlaier		 * This currently handles three situations:
4619126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
4620126258Smlaier		 *     replies.
4621126258Smlaier		 *  2) When PF catches an already established stream (the
4622126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
4623126258Smlaier		 *     changed...)
4624126258Smlaier		 *  3) Packets get funky immediately after the connection
4625126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
4626126258Smlaier		 *     that web servers like to spew after a close)
4627126258Smlaier		 *
4628126258Smlaier		 * This must be a little more careful than the above code
4629126258Smlaier		 * since packet floods will also be caught here. We don't
4630126258Smlaier		 * update the TTL here to mitigate the damage of a packet
4631126258Smlaier		 * flood and so the same code can handle awkward establishment
4632126258Smlaier		 * and a loosened connection close.
4633126258Smlaier		 * In the establishment case, a correct peer response will
4634126258Smlaier		 * validate the connection, go through the normal state code
4635126258Smlaier		 * and keep updating the state TTL.
4636126258Smlaier		 */
4637126258Smlaier
4638126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
4639126258Smlaier			printf("pf: loose state match: ");
4640126258Smlaier			pf_print_state(*state);
4641126258Smlaier			pf_print_flags(th->th_flags);
4642126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n",
4643126258Smlaier			    seq, ack, pd->p_len, ackskew,
4644126258Smlaier			    (*state)->packets[0], (*state)->packets[1]);
4645126258Smlaier		}
4646126258Smlaier
4647145836Smlaier		if (dst->scrub || src->scrub) {
4648145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4649145836Smlaier			    *state, src, dst, &copyback))
4650145836Smlaier				return (PF_DROP);
4651145836Smlaier		}
4652145836Smlaier
4653126258Smlaier		/* update max window */
4654126258Smlaier		if (src->max_win < win)
4655126258Smlaier			src->max_win = win;
4656126258Smlaier		/* synchronize sequencing */
4657126258Smlaier		if (SEQ_GT(end, src->seqlo))
4658126258Smlaier			src->seqlo = end;
4659126258Smlaier		/* slide the window of what the other end can send */
4660126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4661126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4662126258Smlaier
4663126258Smlaier		/*
4664126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
4665126258Smlaier		 * SYN and not an already established connection.
4666126258Smlaier		 */
4667126258Smlaier
4668126258Smlaier		if (th->th_flags & TH_FIN)
4669126258Smlaier			if (src->state < TCPS_CLOSING)
4670126258Smlaier				src->state = TCPS_CLOSING;
4671126258Smlaier		if (th->th_flags & TH_RST)
4672126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4673126258Smlaier
4674126258Smlaier		/* Fall through to PASS packet */
4675126258Smlaier
4676126258Smlaier	} else {
4677126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
4678126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
4679126258Smlaier			/* Send RST for state mismatches during handshake */
4680145836Smlaier			if (!(th->th_flags & TH_RST))
4681126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
4682126258Smlaier				    pd->dst, pd->src, th->th_dport,
4683145836Smlaier				    th->th_sport, ntohl(th->th_ack), 0,
4684145836Smlaier				    TH_RST, 0, 0,
4685145836Smlaier				    (*state)->rule.ptr->return_ttl, 1,
4686145836Smlaier				    pd->eh, kif->pfik_ifp);
4687126258Smlaier			src->seqlo = 0;
4688126258Smlaier			src->seqhi = 1;
4689126258Smlaier			src->max_win = 1;
4690126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
4691126258Smlaier			printf("pf: BAD state: ");
4692126258Smlaier			pf_print_state(*state);
4693126258Smlaier			pf_print_flags(th->th_flags);
4694126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d "
4695126258Smlaier			    "dir=%s,%s\n", seq, ack, pd->p_len, ackskew,
4696126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
4697126258Smlaier			    direction == PF_IN ? "in" : "out",
4698126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
4699126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
4700126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
4701126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
4702126258Smlaier			    ' ': '2',
4703126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
4704126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
4705126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
4706126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
4707126258Smlaier		}
4708145836Smlaier		REASON_SET(reason, PFRES_BADSTATE);
4709126258Smlaier		return (PF_DROP);
4710126258Smlaier	}
4711126258Smlaier
4712126258Smlaier	/* Any packets which have gotten here are to be passed */
4713126258Smlaier
4714126258Smlaier	/* translate source/destination address, if necessary */
4715126258Smlaier	if (STATE_TRANSLATE(*state)) {
4716126258Smlaier		if (direction == PF_OUT)
4717126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
4718126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
4719126258Smlaier			    (*state)->gwy.port, 0, pd->af);
4720126258Smlaier		else
4721126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
4722126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
4723126258Smlaier			    (*state)->lan.port, 0, pd->af);
4724126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4725126258Smlaier	} else if (copyback) {
4726126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
4727126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4728126258Smlaier	}
4729126258Smlaier
4730126258Smlaier	return (PF_PASS);
4731126258Smlaier}
4732126258Smlaier
4733126258Smlaierint
4734130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
4735130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
4736126258Smlaier{
4737126258Smlaier	struct pf_state_peer	*src, *dst;
4738130613Smlaier	struct pf_state		 key;
4739126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
4740126258Smlaier
4741126258Smlaier	key.af = pd->af;
4742126258Smlaier	key.proto = IPPROTO_UDP;
4743130613Smlaier	if (direction == PF_IN)	{
4744130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4745130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4746130613Smlaier		key.ext.port = uh->uh_sport;
4747130613Smlaier		key.gwy.port = uh->uh_dport;
4748130613Smlaier	} else {
4749130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4750130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4751130613Smlaier		key.lan.port = uh->uh_sport;
4752130613Smlaier		key.ext.port = uh->uh_dport;
4753130613Smlaier	}
4754126258Smlaier
4755126258Smlaier	STATE_LOOKUP();
4756126258Smlaier
4757126258Smlaier	if (direction == (*state)->direction) {
4758126258Smlaier		src = &(*state)->src;
4759126258Smlaier		dst = &(*state)->dst;
4760126258Smlaier	} else {
4761126258Smlaier		src = &(*state)->dst;
4762126258Smlaier		dst = &(*state)->src;
4763126258Smlaier	}
4764126258Smlaier
4765126258Smlaier	/* update states */
4766126258Smlaier	if (src->state < PFUDPS_SINGLE)
4767126258Smlaier		src->state = PFUDPS_SINGLE;
4768126258Smlaier	if (dst->state == PFUDPS_SINGLE)
4769126258Smlaier		dst->state = PFUDPS_MULTIPLE;
4770126258Smlaier
4771126258Smlaier	/* update expire time */
4772126261Smlaier	(*state)->expire = time_second;
4773126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
4774126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
4775126258Smlaier	else
4776126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
4777126258Smlaier
4778126258Smlaier	/* translate source/destination address, if necessary */
4779126258Smlaier	if (STATE_TRANSLATE(*state)) {
4780126258Smlaier		if (direction == PF_OUT)
4781126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
4782126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
4783126258Smlaier			    (*state)->gwy.port, 1, pd->af);
4784126258Smlaier		else
4785126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
4786126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
4787126258Smlaier			    (*state)->lan.port, 1, pd->af);
4788126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
4789126258Smlaier	}
4790126258Smlaier
4791126258Smlaier	return (PF_PASS);
4792126258Smlaier}
4793126258Smlaier
4794126258Smlaierint
4795130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
4796145836Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
4797126258Smlaier{
4798126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
4799127629Smlaier	u_int16_t	 icmpid = 0;		/* make the compiler happy */
4800127629Smlaier	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
4801127629Smlaier	u_int8_t	 icmptype = 0;		/* make the compiler happy */
4802130613Smlaier	int		 state_icmp = 0;
4803126258Smlaier
4804126258Smlaier	switch (pd->proto) {
4805126258Smlaier#ifdef INET
4806126258Smlaier	case IPPROTO_ICMP:
4807126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
4808126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4809126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
4810126258Smlaier
4811126258Smlaier		if (icmptype == ICMP_UNREACH ||
4812126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4813126258Smlaier		    icmptype == ICMP_REDIRECT ||
4814126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4815126258Smlaier		    icmptype == ICMP_PARAMPROB)
4816126258Smlaier			state_icmp++;
4817126258Smlaier		break;
4818126258Smlaier#endif /* INET */
4819126258Smlaier#ifdef INET6
4820126258Smlaier	case IPPROTO_ICMPV6:
4821126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4822126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4823126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
4824126258Smlaier
4825126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4826126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4827126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4828126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4829126258Smlaier			state_icmp++;
4830126258Smlaier		break;
4831126258Smlaier#endif /* INET6 */
4832126258Smlaier	}
4833126258Smlaier
4834126258Smlaier	if (!state_icmp) {
4835126258Smlaier
4836126258Smlaier		/*
4837126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
4838126258Smlaier		 * Search for an ICMP state.
4839126258Smlaier		 */
4840130613Smlaier		struct pf_state		key;
4841126258Smlaier
4842126258Smlaier		key.af = pd->af;
4843126258Smlaier		key.proto = pd->proto;
4844130613Smlaier		if (direction == PF_IN)	{
4845130613Smlaier			PF_ACPY(&key.ext.addr, pd->src, key.af);
4846130613Smlaier			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4847149884Smlaier			key.ext.port = 0;
4848130613Smlaier			key.gwy.port = icmpid;
4849130613Smlaier		} else {
4850130613Smlaier			PF_ACPY(&key.lan.addr, pd->src, key.af);
4851130613Smlaier			PF_ACPY(&key.ext.addr, pd->dst, key.af);
4852130613Smlaier			key.lan.port = icmpid;
4853149884Smlaier			key.ext.port = 0;
4854130613Smlaier		}
4855126258Smlaier
4856126258Smlaier		STATE_LOOKUP();
4857126258Smlaier
4858126261Smlaier		(*state)->expire = time_second;
4859126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
4860126258Smlaier
4861126258Smlaier		/* translate source/destination address, if necessary */
4862149884Smlaier		if (STATE_TRANSLATE(*state)) {
4863126258Smlaier			if (direction == PF_OUT) {
4864126258Smlaier				switch (pd->af) {
4865126258Smlaier#ifdef INET
4866126258Smlaier				case AF_INET:
4867126258Smlaier					pf_change_a(&saddr->v4.s_addr,
4868126258Smlaier					    pd->ip_sum,
4869126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
4870149884Smlaier					pd->hdr.icmp->icmp_cksum =
4871149884Smlaier					    pf_cksum_fixup(
4872149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
4873149884Smlaier					    (*state)->gwy.port, 0);
4874149884Smlaier					pd->hdr.icmp->icmp_id =
4875149884Smlaier					    (*state)->gwy.port;
4876149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
4877149893Smlaier					    (caddr_t)pd->hdr.icmp);
4878126258Smlaier					break;
4879126258Smlaier#endif /* INET */
4880126258Smlaier#ifdef INET6
4881126258Smlaier				case AF_INET6:
4882126258Smlaier					pf_change_a6(saddr,
4883126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4884126258Smlaier					    &(*state)->gwy.addr, 0);
4885126258Smlaier					m_copyback(m, off,
4886126258Smlaier					    sizeof(struct icmp6_hdr),
4887126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4888126258Smlaier					break;
4889126258Smlaier#endif /* INET6 */
4890126258Smlaier				}
4891126258Smlaier			} else {
4892126258Smlaier				switch (pd->af) {
4893126258Smlaier#ifdef INET
4894126258Smlaier				case AF_INET:
4895126258Smlaier					pf_change_a(&daddr->v4.s_addr,
4896126258Smlaier					    pd->ip_sum,
4897126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
4898149884Smlaier					pd->hdr.icmp->icmp_cksum =
4899149884Smlaier					    pf_cksum_fixup(
4900149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
4901149884Smlaier					    (*state)->lan.port, 0);
4902149884Smlaier					pd->hdr.icmp->icmp_id =
4903149884Smlaier					    (*state)->lan.port;
4904149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
4905149893Smlaier					    (caddr_t)pd->hdr.icmp);
4906126258Smlaier					break;
4907126258Smlaier#endif /* INET */
4908126258Smlaier#ifdef INET6
4909126258Smlaier				case AF_INET6:
4910126258Smlaier					pf_change_a6(daddr,
4911126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4912126258Smlaier					    &(*state)->lan.addr, 0);
4913126258Smlaier					m_copyback(m, off,
4914126258Smlaier					    sizeof(struct icmp6_hdr),
4915126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4916126258Smlaier					break;
4917126258Smlaier#endif /* INET6 */
4918126258Smlaier				}
4919126258Smlaier			}
4920126258Smlaier		}
4921126258Smlaier
4922126258Smlaier		return (PF_PASS);
4923126258Smlaier
4924126258Smlaier	} else {
4925126258Smlaier		/*
4926126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
4927126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
4928126258Smlaier		 */
4929126258Smlaier
4930126258Smlaier		struct pf_pdesc	pd2;
4931126258Smlaier#ifdef INET
4932126258Smlaier		struct ip	h2;
4933126258Smlaier#endif /* INET */
4934126258Smlaier#ifdef INET6
4935126258Smlaier		struct ip6_hdr	h2_6;
4936126258Smlaier		int		terminal = 0;
4937126258Smlaier#endif /* INET6 */
4938127629Smlaier		int		ipoff2 = 0;	/* make the compiler happy */
4939127629Smlaier		int		off2 = 0;	/* make the compiler happy */
4940126258Smlaier
4941126258Smlaier		pd2.af = pd->af;
4942126258Smlaier		switch (pd->af) {
4943126258Smlaier#ifdef INET
4944126258Smlaier		case AF_INET:
4945126258Smlaier			/* offset of h2 in mbuf chain */
4946126258Smlaier			ipoff2 = off + ICMP_MINLEN;
4947126258Smlaier
4948126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
4949145836Smlaier			    NULL, reason, pd2.af)) {
4950126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4951126258Smlaier				    ("pf: ICMP error message too short "
4952126258Smlaier				    "(ip)\n"));
4953126258Smlaier				return (PF_DROP);
4954126258Smlaier			}
4955126258Smlaier			/*
4956126258Smlaier			 * ICMP error messages don't refer to non-first
4957126258Smlaier			 * fragments
4958126258Smlaier			 */
4959145836Smlaier			if (h2.ip_off & htons(IP_OFFMASK)) {
4960145836Smlaier				REASON_SET(reason, PFRES_FRAG);
4961126258Smlaier				return (PF_DROP);
4962145836Smlaier			}
4963126258Smlaier
4964126258Smlaier			/* offset of protocol header that follows h2 */
4965126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
4966126258Smlaier
4967126258Smlaier			pd2.proto = h2.ip_p;
4968126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
4969126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
4970126258Smlaier			pd2.ip_sum = &h2.ip_sum;
4971126258Smlaier			break;
4972126258Smlaier#endif /* INET */
4973126258Smlaier#ifdef INET6
4974126258Smlaier		case AF_INET6:
4975126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
4976126258Smlaier
4977126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
4978145836Smlaier			    NULL, reason, pd2.af)) {
4979126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
4980126258Smlaier				    ("pf: ICMP error message too short "
4981126258Smlaier				    "(ip6)\n"));
4982126258Smlaier				return (PF_DROP);
4983126258Smlaier			}
4984126258Smlaier			pd2.proto = h2_6.ip6_nxt;
4985126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
4986126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
4987126258Smlaier			pd2.ip_sum = NULL;
4988126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
4989126258Smlaier			do {
4990126258Smlaier				switch (pd2.proto) {
4991126258Smlaier				case IPPROTO_FRAGMENT:
4992126258Smlaier					/*
4993126258Smlaier					 * ICMPv6 error messages for
4994126258Smlaier					 * non-first fragments
4995126258Smlaier					 */
4996145836Smlaier					REASON_SET(reason, PFRES_FRAG);
4997126258Smlaier					return (PF_DROP);
4998126258Smlaier				case IPPROTO_AH:
4999126258Smlaier				case IPPROTO_HOPOPTS:
5000126258Smlaier				case IPPROTO_ROUTING:
5001126258Smlaier				case IPPROTO_DSTOPTS: {
5002126258Smlaier					/* get next header and header length */
5003126258Smlaier					struct ip6_ext opt6;
5004126258Smlaier
5005126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
5006145836Smlaier					    sizeof(opt6), NULL, reason,
5007145836Smlaier					    pd2.af)) {
5008126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
5009126258Smlaier						    ("pf: ICMPv6 short opt\n"));
5010126258Smlaier						return (PF_DROP);
5011126258Smlaier					}
5012126258Smlaier					if (pd2.proto == IPPROTO_AH)
5013126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
5014126258Smlaier					else
5015126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
5016126258Smlaier					pd2.proto = opt6.ip6e_nxt;
5017126258Smlaier					/* goto the next header */
5018126258Smlaier					break;
5019126258Smlaier				}
5020126258Smlaier				default:
5021126258Smlaier					terminal++;
5022126258Smlaier					break;
5023126258Smlaier				}
5024126258Smlaier			} while (!terminal);
5025126258Smlaier			break;
5026126258Smlaier#endif /* INET6 */
5027126258Smlaier		}
5028126258Smlaier
5029126258Smlaier		switch (pd2.proto) {
5030126258Smlaier		case IPPROTO_TCP: {
5031126258Smlaier			struct tcphdr		 th;
5032126258Smlaier			u_int32_t		 seq;
5033130613Smlaier			struct pf_state		 key;
5034126258Smlaier			struct pf_state_peer	*src, *dst;
5035126258Smlaier			u_int8_t		 dws;
5036128129Smlaier			int			 copyback = 0;
5037126258Smlaier
5038126258Smlaier			/*
5039126258Smlaier			 * Only the first 8 bytes of the TCP header can be
5040126258Smlaier			 * expected. Don't access any TCP header fields after
5041126258Smlaier			 * th_seq, an ackskew test is not possible.
5042126258Smlaier			 */
5043145836Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
5044145836Smlaier			    pd2.af)) {
5045126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5046126258Smlaier				    ("pf: ICMP error message too short "
5047126258Smlaier				    "(tcp)\n"));
5048126258Smlaier				return (PF_DROP);
5049126258Smlaier			}
5050126258Smlaier
5051126258Smlaier			key.af = pd2.af;
5052126258Smlaier			key.proto = IPPROTO_TCP;
5053130613Smlaier			if (direction == PF_IN)	{
5054130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5055130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5056130613Smlaier				key.ext.port = th.th_dport;
5057130613Smlaier				key.gwy.port = th.th_sport;
5058130613Smlaier			} else {
5059130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5060130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5061130613Smlaier				key.lan.port = th.th_dport;
5062130613Smlaier				key.ext.port = th.th_sport;
5063130613Smlaier			}
5064126258Smlaier
5065126258Smlaier			STATE_LOOKUP();
5066126258Smlaier
5067126258Smlaier			if (direction == (*state)->direction) {
5068126258Smlaier				src = &(*state)->dst;
5069126258Smlaier				dst = &(*state)->src;
5070126258Smlaier			} else {
5071126258Smlaier				src = &(*state)->src;
5072126258Smlaier				dst = &(*state)->dst;
5073126258Smlaier			}
5074126258Smlaier
5075130613Smlaier			if (src->wscale && dst->wscale &&
5076130613Smlaier			    !(th.th_flags & TH_SYN))
5077126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
5078126258Smlaier			else
5079126258Smlaier				dws = 0;
5080126258Smlaier
5081126258Smlaier			/* Demodulate sequence number */
5082126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
5083128129Smlaier			if (src->seqdiff) {
5084128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
5085126258Smlaier				    htonl(seq), 0);
5086128129Smlaier				copyback = 1;
5087128129Smlaier			}
5088126258Smlaier
5089126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
5090126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
5091126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
5092126258Smlaier					printf("pf: BAD ICMP %d:%d ",
5093126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
5094126258Smlaier					pf_print_host(pd->src, 0, pd->af);
5095126258Smlaier					printf(" -> ");
5096126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
5097126258Smlaier					printf(" state: ");
5098126258Smlaier					pf_print_state(*state);
5099126258Smlaier					printf(" seq=%u\n", seq);
5100126258Smlaier				}
5101145836Smlaier				REASON_SET(reason, PFRES_BADSTATE);
5102126258Smlaier				return (PF_DROP);
5103126258Smlaier			}
5104126258Smlaier
5105126258Smlaier			if (STATE_TRANSLATE(*state)) {
5106126258Smlaier				if (direction == PF_IN) {
5107126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
5108128129Smlaier					    daddr, &(*state)->lan.addr,
5109126258Smlaier					    (*state)->lan.port, NULL,
5110126258Smlaier					    pd2.ip_sum, icmpsum,
5111126258Smlaier					    pd->ip_sum, 0, pd2.af);
5112126258Smlaier				} else {
5113126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
5114126258Smlaier					    saddr, &(*state)->gwy.addr,
5115126258Smlaier					    (*state)->gwy.port, NULL,
5116126258Smlaier					    pd2.ip_sum, icmpsum,
5117126258Smlaier					    pd->ip_sum, 0, pd2.af);
5118126258Smlaier				}
5119128129Smlaier				copyback = 1;
5120128129Smlaier			}
5121128129Smlaier
5122128129Smlaier			if (copyback) {
5123126258Smlaier				switch (pd2.af) {
5124126258Smlaier#ifdef INET
5125126258Smlaier				case AF_INET:
5126126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5127126261Smlaier					    (caddr_t)pd->hdr.icmp);
5128126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5129126261Smlaier					    (caddr_t)&h2);
5130126258Smlaier					break;
5131126258Smlaier#endif /* INET */
5132126258Smlaier#ifdef INET6
5133126258Smlaier				case AF_INET6:
5134126258Smlaier					m_copyback(m, off,
5135126258Smlaier					    sizeof(struct icmp6_hdr),
5136126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5137126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5138126261Smlaier					    (caddr_t)&h2_6);
5139126258Smlaier					break;
5140126258Smlaier#endif /* INET6 */
5141126258Smlaier				}
5142126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
5143126258Smlaier			}
5144126258Smlaier
5145126258Smlaier			return (PF_PASS);
5146126258Smlaier			break;
5147126258Smlaier		}
5148126258Smlaier		case IPPROTO_UDP: {
5149126258Smlaier			struct udphdr		uh;
5150130613Smlaier			struct pf_state		key;
5151126258Smlaier
5152126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
5153145836Smlaier			    NULL, reason, pd2.af)) {
5154126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5155126258Smlaier				    ("pf: ICMP error message too short "
5156126258Smlaier				    "(udp)\n"));
5157126258Smlaier				return (PF_DROP);
5158126258Smlaier			}
5159126258Smlaier
5160126258Smlaier			key.af = pd2.af;
5161126258Smlaier			key.proto = IPPROTO_UDP;
5162130613Smlaier			if (direction == PF_IN)	{
5163130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5164130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5165130613Smlaier				key.ext.port = uh.uh_dport;
5166130613Smlaier				key.gwy.port = uh.uh_sport;
5167130613Smlaier			} else {
5168130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5169130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5170130613Smlaier				key.lan.port = uh.uh_dport;
5171130613Smlaier				key.ext.port = uh.uh_sport;
5172130613Smlaier			}
5173126258Smlaier
5174126258Smlaier			STATE_LOOKUP();
5175126258Smlaier
5176126258Smlaier			if (STATE_TRANSLATE(*state)) {
5177126258Smlaier				if (direction == PF_IN) {
5178126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
5179126258Smlaier					    daddr, &(*state)->lan.addr,
5180126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
5181126258Smlaier					    pd2.ip_sum, icmpsum,
5182126258Smlaier					    pd->ip_sum, 1, pd2.af);
5183126258Smlaier				} else {
5184126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
5185126258Smlaier					    saddr, &(*state)->gwy.addr,
5186126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
5187126258Smlaier					    pd2.ip_sum, icmpsum,
5188126258Smlaier					    pd->ip_sum, 1, pd2.af);
5189126258Smlaier				}
5190126258Smlaier				switch (pd2.af) {
5191126258Smlaier#ifdef INET
5192126258Smlaier				case AF_INET:
5193126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5194126261Smlaier					    (caddr_t)pd->hdr.icmp);
5195126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5196126261Smlaier					    (caddr_t)&h2);
5197126258Smlaier					break;
5198126258Smlaier#endif /* INET */
5199126258Smlaier#ifdef INET6
5200126258Smlaier				case AF_INET6:
5201126258Smlaier					m_copyback(m, off,
5202126258Smlaier					    sizeof(struct icmp6_hdr),
5203126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5204126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5205126261Smlaier					    (caddr_t)&h2_6);
5206126258Smlaier					break;
5207126258Smlaier#endif /* INET6 */
5208126258Smlaier				}
5209126261Smlaier				m_copyback(m, off2, sizeof(uh),
5210126261Smlaier				    (caddr_t)&uh);
5211126258Smlaier			}
5212126258Smlaier
5213126258Smlaier			return (PF_PASS);
5214126258Smlaier			break;
5215126258Smlaier		}
5216126258Smlaier#ifdef INET
5217126258Smlaier		case IPPROTO_ICMP: {
5218126258Smlaier			struct icmp		iih;
5219130613Smlaier			struct pf_state		key;
5220126258Smlaier
5221126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
5222145836Smlaier			    NULL, reason, pd2.af)) {
5223126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5224126258Smlaier				    ("pf: ICMP error message too short i"
5225126258Smlaier				    "(icmp)\n"));
5226126258Smlaier				return (PF_DROP);
5227126258Smlaier			}
5228126258Smlaier
5229126258Smlaier			key.af = pd2.af;
5230126258Smlaier			key.proto = IPPROTO_ICMP;
5231130613Smlaier			if (direction == PF_IN)	{
5232130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5233130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5234149884Smlaier				key.ext.port = 0;
5235130613Smlaier				key.gwy.port = iih.icmp_id;
5236130613Smlaier			} else {
5237130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5238130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5239130613Smlaier				key.lan.port = iih.icmp_id;
5240149884Smlaier				key.ext.port = 0;
5241130613Smlaier			}
5242126258Smlaier
5243126258Smlaier			STATE_LOOKUP();
5244126258Smlaier
5245126258Smlaier			if (STATE_TRANSLATE(*state)) {
5246126258Smlaier				if (direction == PF_IN) {
5247126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
5248126258Smlaier					    daddr, &(*state)->lan.addr,
5249126258Smlaier					    (*state)->lan.port, NULL,
5250126258Smlaier					    pd2.ip_sum, icmpsum,
5251126258Smlaier					    pd->ip_sum, 0, AF_INET);
5252126258Smlaier				} else {
5253126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
5254126258Smlaier					    saddr, &(*state)->gwy.addr,
5255126258Smlaier					    (*state)->gwy.port, NULL,
5256126258Smlaier					    pd2.ip_sum, icmpsum,
5257126258Smlaier					    pd->ip_sum, 0, AF_INET);
5258126258Smlaier				}
5259126261Smlaier				m_copyback(m, off, ICMP_MINLEN,
5260126261Smlaier				    (caddr_t)pd->hdr.icmp);
5261126261Smlaier				m_copyback(m, ipoff2, sizeof(h2),
5262126261Smlaier				    (caddr_t)&h2);
5263126261Smlaier				m_copyback(m, off2, ICMP_MINLEN,
5264126261Smlaier				    (caddr_t)&iih);
5265126258Smlaier			}
5266126258Smlaier
5267126258Smlaier			return (PF_PASS);
5268126258Smlaier			break;
5269126258Smlaier		}
5270126258Smlaier#endif /* INET */
5271126258Smlaier#ifdef INET6
5272126258Smlaier		case IPPROTO_ICMPV6: {
5273126258Smlaier			struct icmp6_hdr	iih;
5274130613Smlaier			struct pf_state		key;
5275126258Smlaier
5276126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
5277145836Smlaier			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
5278126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5279126258Smlaier				    ("pf: ICMP error message too short "
5280126258Smlaier				    "(icmp6)\n"));
5281126258Smlaier				return (PF_DROP);
5282126258Smlaier			}
5283126258Smlaier
5284126258Smlaier			key.af = pd2.af;
5285126258Smlaier			key.proto = IPPROTO_ICMPV6;
5286130613Smlaier			if (direction == PF_IN)	{
5287130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5288130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5289149884Smlaier				key.ext.port = 0;
5290130613Smlaier				key.gwy.port = iih.icmp6_id;
5291130613Smlaier			} else {
5292130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5293130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5294130613Smlaier				key.lan.port = iih.icmp6_id;
5295149884Smlaier				key.ext.port = 0;
5296130613Smlaier			}
5297126258Smlaier
5298126258Smlaier			STATE_LOOKUP();
5299126258Smlaier
5300126258Smlaier			if (STATE_TRANSLATE(*state)) {
5301126258Smlaier				if (direction == PF_IN) {
5302126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
5303126258Smlaier					    daddr, &(*state)->lan.addr,
5304126258Smlaier					    (*state)->lan.port, NULL,
5305126258Smlaier					    pd2.ip_sum, icmpsum,
5306126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5307126258Smlaier				} else {
5308126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
5309126258Smlaier					    saddr, &(*state)->gwy.addr,
5310126258Smlaier					    (*state)->gwy.port, NULL,
5311126258Smlaier					    pd2.ip_sum, icmpsum,
5312126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5313126258Smlaier				}
5314126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
5315126261Smlaier				    (caddr_t)pd->hdr.icmp6);
5316126261Smlaier				m_copyback(m, ipoff2, sizeof(h2_6),
5317126261Smlaier				    (caddr_t)&h2_6);
5318126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5319126261Smlaier				    (caddr_t)&iih);
5320126258Smlaier			}
5321126258Smlaier
5322126258Smlaier			return (PF_PASS);
5323126258Smlaier			break;
5324126258Smlaier		}
5325126258Smlaier#endif /* INET6 */
5326126258Smlaier		default: {
5327130613Smlaier			struct pf_state		key;
5328126258Smlaier
5329126258Smlaier			key.af = pd2.af;
5330126258Smlaier			key.proto = pd2.proto;
5331130613Smlaier			if (direction == PF_IN)	{
5332130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5333130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5334130613Smlaier				key.ext.port = 0;
5335130613Smlaier				key.gwy.port = 0;
5336130613Smlaier			} else {
5337130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5338130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5339130613Smlaier				key.lan.port = 0;
5340130613Smlaier				key.ext.port = 0;
5341130613Smlaier			}
5342126258Smlaier
5343126258Smlaier			STATE_LOOKUP();
5344126258Smlaier
5345126258Smlaier			if (STATE_TRANSLATE(*state)) {
5346126258Smlaier				if (direction == PF_IN) {
5347126258Smlaier					pf_change_icmp(pd2.src, NULL,
5348126258Smlaier					    daddr, &(*state)->lan.addr,
5349126258Smlaier					    0, NULL,
5350126258Smlaier					    pd2.ip_sum, icmpsum,
5351126258Smlaier					    pd->ip_sum, 0, pd2.af);
5352126258Smlaier				} else {
5353126258Smlaier					pf_change_icmp(pd2.dst, NULL,
5354126258Smlaier					    saddr, &(*state)->gwy.addr,
5355126258Smlaier					    0, NULL,
5356126258Smlaier					    pd2.ip_sum, icmpsum,
5357126258Smlaier					    pd->ip_sum, 0, pd2.af);
5358126258Smlaier				}
5359126258Smlaier				switch (pd2.af) {
5360126258Smlaier#ifdef INET
5361126258Smlaier				case AF_INET:
5362126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5363126261Smlaier					    (caddr_t)pd->hdr.icmp);
5364126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5365126261Smlaier					    (caddr_t)&h2);
5366126258Smlaier					break;
5367126258Smlaier#endif /* INET */
5368126258Smlaier#ifdef INET6
5369126258Smlaier				case AF_INET6:
5370126258Smlaier					m_copyback(m, off,
5371126258Smlaier					    sizeof(struct icmp6_hdr),
5372126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5373126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5374126261Smlaier					    (caddr_t)&h2_6);
5375126258Smlaier					break;
5376126258Smlaier#endif /* INET6 */
5377126258Smlaier				}
5378126258Smlaier			}
5379126258Smlaier
5380126258Smlaier			return (PF_PASS);
5381126258Smlaier			break;
5382126258Smlaier		}
5383126258Smlaier		}
5384126258Smlaier	}
5385126258Smlaier}
5386126258Smlaier
5387126258Smlaierint
5388130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5389126258Smlaier    struct pf_pdesc *pd)
5390126258Smlaier{
5391126258Smlaier	struct pf_state_peer	*src, *dst;
5392130613Smlaier	struct pf_state		 key;
5393126258Smlaier
5394126258Smlaier	key.af = pd->af;
5395126258Smlaier	key.proto = pd->proto;
5396130613Smlaier	if (direction == PF_IN)	{
5397130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5398130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5399130613Smlaier		key.ext.port = 0;
5400130613Smlaier		key.gwy.port = 0;
5401130613Smlaier	} else {
5402130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5403130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5404130613Smlaier		key.lan.port = 0;
5405130613Smlaier		key.ext.port = 0;
5406130613Smlaier	}
5407126258Smlaier
5408126258Smlaier	STATE_LOOKUP();
5409126258Smlaier
5410126258Smlaier	if (direction == (*state)->direction) {
5411126258Smlaier		src = &(*state)->src;
5412126258Smlaier		dst = &(*state)->dst;
5413126258Smlaier	} else {
5414126258Smlaier		src = &(*state)->dst;
5415126258Smlaier		dst = &(*state)->src;
5416126258Smlaier	}
5417126258Smlaier
5418126258Smlaier	/* update states */
5419126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5420126258Smlaier		src->state = PFOTHERS_SINGLE;
5421126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5422126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5423126258Smlaier
5424126258Smlaier	/* update expire time */
5425126261Smlaier	(*state)->expire = time_second;
5426126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5427126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5428126258Smlaier	else
5429126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5430126258Smlaier
5431126258Smlaier	/* translate source/destination address, if necessary */
5432126258Smlaier	if (STATE_TRANSLATE(*state)) {
5433126258Smlaier		if (direction == PF_OUT)
5434126258Smlaier			switch (pd->af) {
5435126258Smlaier#ifdef INET
5436126258Smlaier			case AF_INET:
5437126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5438126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
5439126258Smlaier				    0);
5440126258Smlaier				break;
5441126258Smlaier#endif /* INET */
5442126258Smlaier#ifdef INET6
5443126258Smlaier			case AF_INET6:
5444126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
5445126258Smlaier				break;
5446126258Smlaier#endif /* INET6 */
5447126258Smlaier			}
5448126258Smlaier		else
5449126258Smlaier			switch (pd->af) {
5450126258Smlaier#ifdef INET
5451126258Smlaier			case AF_INET:
5452126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5453126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
5454126258Smlaier				    0);
5455126258Smlaier				break;
5456126258Smlaier#endif /* INET */
5457126258Smlaier#ifdef INET6
5458126258Smlaier			case AF_INET6:
5459126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
5460126258Smlaier				break;
5461126258Smlaier#endif /* INET6 */
5462126258Smlaier			}
5463126258Smlaier	}
5464126258Smlaier
5465126258Smlaier	return (PF_PASS);
5466126258Smlaier}
5467126258Smlaier
5468126258Smlaier/*
5469126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5470126258Smlaier * h must be at "ipoff" on the mbuf chain.
5471126258Smlaier */
5472126258Smlaiervoid *
5473126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5474126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5475126258Smlaier{
5476126258Smlaier	switch (af) {
5477126258Smlaier#ifdef INET
5478126258Smlaier	case AF_INET: {
5479126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5480126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5481126258Smlaier
5482126258Smlaier		if (fragoff) {
5483126258Smlaier			if (fragoff >= len)
5484126258Smlaier				ACTION_SET(actionp, PF_PASS);
5485126258Smlaier			else {
5486126258Smlaier				ACTION_SET(actionp, PF_DROP);
5487126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5488126258Smlaier			}
5489126258Smlaier			return (NULL);
5490126258Smlaier		}
5491130613Smlaier		if (m->m_pkthdr.len < off + len ||
5492130613Smlaier		    ntohs(h->ip_len) < off + len) {
5493126258Smlaier			ACTION_SET(actionp, PF_DROP);
5494126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5495126258Smlaier			return (NULL);
5496126258Smlaier		}
5497126258Smlaier		break;
5498126258Smlaier	}
5499126258Smlaier#endif /* INET */
5500126258Smlaier#ifdef INET6
5501126258Smlaier	case AF_INET6: {
5502126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5503126258Smlaier
5504126258Smlaier		if (m->m_pkthdr.len < off + len ||
5505126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5506126258Smlaier		    (unsigned)(off + len)) {
5507126258Smlaier			ACTION_SET(actionp, PF_DROP);
5508126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5509126258Smlaier			return (NULL);
5510126258Smlaier		}
5511126258Smlaier		break;
5512126258Smlaier	}
5513126258Smlaier#endif /* INET6 */
5514126258Smlaier	}
5515126258Smlaier	m_copydata(m, off, len, p);
5516126258Smlaier	return (p);
5517126258Smlaier}
5518126258Smlaier
5519126258Smlaierint
5520126258Smlaierpf_routable(struct pf_addr *addr, sa_family_t af)
5521126258Smlaier{
5522126258Smlaier	struct sockaddr_in	*dst;
5523145836Smlaier#ifdef INET6
5524145836Smlaier	struct sockaddr_in6	*dst6;
5525145836Smlaier	struct route_in6	 ro;
5526145836Smlaier#else
5527126258Smlaier	struct route		 ro;
5528145836Smlaier#endif
5529126258Smlaier
5530126258Smlaier	bzero(&ro, sizeof(ro));
5531145836Smlaier	switch (af) {
5532145836Smlaier	case AF_INET:
5533145836Smlaier		dst = satosin(&ro.ro_dst);
5534145836Smlaier		dst->sin_family = AF_INET;
5535145836Smlaier		dst->sin_len = sizeof(*dst);
5536145836Smlaier		dst->sin_addr = addr->v4;
5537145836Smlaier		break;
5538145836Smlaier#ifdef INET6
5539145836Smlaier	case AF_INET6:
5540145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5541145836Smlaier		dst6->sin6_family = AF_INET6;
5542145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5543145836Smlaier		dst6->sin6_addr = addr->v6;
5544145836Smlaier		break;
5545145836Smlaier#endif /* INET6 */
5546145836Smlaier	default:
5547145836Smlaier		return (0);
5548145836Smlaier	}
5549145836Smlaier
5550127145Smlaier#ifdef __FreeBSD__
5551126261Smlaier#ifdef RTF_PRCLONING
5552145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING));
5553126261Smlaier#else /* !RTF_PRCLONING */
5554145836Smlaier	rtalloc_ign((struct route *)&ro, RTF_CLONING);
5555126261Smlaier#endif
5556126261Smlaier#else /* ! __FreeBSD__ */
5557145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5558126261Smlaier#endif
5559126258Smlaier
5560126258Smlaier	if (ro.ro_rt != NULL) {
5561126258Smlaier		RTFREE(ro.ro_rt);
5562145836Smlaier		return (1);
5563126258Smlaier	}
5564126258Smlaier
5565145836Smlaier	return (0);
5566145836Smlaier}
5567145836Smlaier
5568145836Smlaierint
5569145836Smlaierpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
5570145836Smlaier{
5571145836Smlaier	struct sockaddr_in	*dst;
5572145836Smlaier#ifdef INET6
5573145836Smlaier	struct sockaddr_in6	*dst6;
5574145836Smlaier	struct route_in6	 ro;
5575145836Smlaier#else
5576145836Smlaier	struct route		 ro;
5577145836Smlaier#endif
5578145836Smlaier	int			 ret = 0;
5579145836Smlaier
5580145836Smlaier	bzero(&ro, sizeof(ro));
5581145836Smlaier	switch (af) {
5582145836Smlaier	case AF_INET:
5583145836Smlaier		dst = satosin(&ro.ro_dst);
5584145836Smlaier		dst->sin_family = AF_INET;
5585145836Smlaier		dst->sin_len = sizeof(*dst);
5586145836Smlaier		dst->sin_addr = addr->v4;
5587145836Smlaier		break;
5588145836Smlaier#ifdef INET6
5589145836Smlaier	case AF_INET6:
5590145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5591145836Smlaier		dst6->sin6_family = AF_INET6;
5592145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5593145836Smlaier		dst6->sin6_addr = addr->v6;
5594145836Smlaier		break;
5595145836Smlaier#endif /* INET6 */
5596145836Smlaier	default:
5597145836Smlaier		return (0);
5598145836Smlaier	}
5599145836Smlaier
5600145836Smlaier#ifdef __FreeBSD__
5601145836Smlaier# ifdef RTF_PRCLONING
5602145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
5603145836Smlaier# else /* !RTF_PRCLONING */
5604145836Smlaier	rtalloc_ign((struct route *)&ro, RTF_CLONING);
5605145836Smlaier# endif
5606145836Smlaier#else /* ! __FreeBSD__ */
5607145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5608145836Smlaier#endif
5609145836Smlaier
5610145836Smlaier	if (ro.ro_rt != NULL) {
5611145836Smlaier#ifdef __FreeBSD__
5612145836Smlaier		/* XXX_IMPORT: later */
5613145836Smlaier#else
5614145836Smlaier		if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
5615145836Smlaier			ret = 1;
5616145836Smlaier#endif
5617145836Smlaier		RTFREE(ro.ro_rt);
5618145836Smlaier	}
5619145836Smlaier
5620126258Smlaier	return (ret);
5621126258Smlaier}
5622126258Smlaier
5623126258Smlaier#ifdef INET
5624126261Smlaier
5625126258Smlaiervoid
5626126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5627126258Smlaier    struct pf_state *s)
5628126258Smlaier{
5629126258Smlaier	struct mbuf		*m0, *m1;
5630132303Smlaier	struct m_tag		*mtag;
5631126258Smlaier	struct route		 iproute;
5632127629Smlaier	struct route		*ro = NULL;	/* XXX: was uninitialized */
5633126258Smlaier	struct sockaddr_in	*dst;
5634126258Smlaier	struct ip		*ip;
5635126258Smlaier	struct ifnet		*ifp = NULL;
5636126258Smlaier	struct pf_addr		 naddr;
5637130613Smlaier	struct pf_src_node	*sn = NULL;
5638126258Smlaier	int			 error = 0;
5639127145Smlaier#ifdef __FreeBSD__
5640126261Smlaier	int sw_csum;
5641126261Smlaier#endif
5642126258Smlaier
5643126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5644126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5645126258Smlaier		panic("pf_route: invalid parameters");
5646126258Smlaier
5647132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
5648132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
5649132303Smlaier		    NULL) {
5650132303Smlaier			m0 = *m;
5651132303Smlaier			*m = NULL;
5652132303Smlaier			goto bad;
5653132303Smlaier		}
5654132303Smlaier		*(char *)(mtag + 1) = 1;
5655132303Smlaier		m_tag_prepend(*m, mtag);
5656132303Smlaier	} else {
5657132303Smlaier		if (*(char *)(mtag + 1) > 3) {
5658132303Smlaier			m0 = *m;
5659132303Smlaier			*m = NULL;
5660132303Smlaier			goto bad;
5661132303Smlaier		}
5662132303Smlaier		(*(char *)(mtag + 1))++;
5663132303Smlaier	}
5664132303Smlaier
5665126258Smlaier	if (r->rt == PF_DUPTO) {
5666127145Smlaier#ifdef __FreeBSD__
5667132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5668126261Smlaier#else
5669132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5670126261Smlaier#endif
5671126258Smlaier			return;
5672126258Smlaier	} else {
5673126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5674126258Smlaier			return;
5675126258Smlaier		m0 = *m;
5676126258Smlaier	}
5677126258Smlaier
5678145836Smlaier	if (m0->m_len < sizeof(struct ip)) {
5679145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
5680145836Smlaier		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
5681145836Smlaier		goto bad;
5682145836Smlaier	}
5683145836Smlaier
5684126258Smlaier	ip = mtod(m0, struct ip *);
5685126258Smlaier
5686126258Smlaier	ro = &iproute;
5687126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5688126258Smlaier	dst = satosin(&ro->ro_dst);
5689126258Smlaier	dst->sin_family = AF_INET;
5690126258Smlaier	dst->sin_len = sizeof(*dst);
5691126258Smlaier	dst->sin_addr = ip->ip_dst;
5692126258Smlaier
5693126258Smlaier	if (r->rt == PF_FASTROUTE) {
5694126258Smlaier		rtalloc(ro);
5695126258Smlaier		if (ro->ro_rt == 0) {
5696126258Smlaier			ipstat.ips_noroute++;
5697126258Smlaier			goto bad;
5698126258Smlaier		}
5699126258Smlaier
5700126258Smlaier		ifp = ro->ro_rt->rt_ifp;
5701126258Smlaier		ro->ro_rt->rt_use++;
5702126258Smlaier
5703126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
5704126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
5705126258Smlaier	} else {
5706145836Smlaier		if (TAILQ_EMPTY(&r->rpool.list)) {
5707145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
5708145836Smlaier			    ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
5709145836Smlaier			goto bad;
5710145836Smlaier		}
5711126258Smlaier		if (s == NULL) {
5712130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
5713130613Smlaier			    &naddr, NULL, &sn);
5714126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
5715126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
5716130613Smlaier			ifp = r->rpool.cur->kif ?
5717130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
5718126258Smlaier		} else {
5719126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
5720126258Smlaier				dst->sin_addr.s_addr =
5721126258Smlaier				    s->rt_addr.v4.s_addr;
5722130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
5723126258Smlaier		}
5724126258Smlaier	}
5725126258Smlaier	if (ifp == NULL)
5726126258Smlaier		goto bad;
5727126258Smlaier
5728130639Smlaier	if (oifp != ifp) {
5729127145Smlaier#ifdef __FreeBSD__
5730126261Smlaier		PF_UNLOCK();
5731145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
5732126261Smlaier			PF_LOCK();
5733126261Smlaier			goto bad;
5734126261Smlaier		} else if (m0 == NULL) {
5735126261Smlaier			PF_LOCK();
5736126261Smlaier			goto done;
5737126261Smlaier		}
5738126261Smlaier		PF_LOCK();
5739126261Smlaier#else
5740145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
5741126258Smlaier			goto bad;
5742126258Smlaier		else if (m0 == NULL)
5743126258Smlaier			goto done;
5744126261Smlaier#endif
5745145836Smlaier		if (m0->m_len < sizeof(struct ip)) {
5746145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
5747145836Smlaier			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
5748145836Smlaier			goto bad;
5749145836Smlaier		}
5750126258Smlaier		ip = mtod(m0, struct ip *);
5751126258Smlaier	}
5752126258Smlaier
5753127145Smlaier#ifdef __FreeBSD__
5754126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
5755126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
5756126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
5757126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
5758126261Smlaier		/*
5759126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
5760126261Smlaier		 */
5761126261Smlaier		NTOHS(ip->ip_len);
5762126261Smlaier		NTOHS(ip->ip_off);	 /* XXX: needed? */
5763126261Smlaier		in_delayed_cksum(m0);
5764126261Smlaier		HTONS(ip->ip_len);
5765126261Smlaier		HTONS(ip->ip_off);
5766126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
5767126261Smlaier	}
5768126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
5769126261Smlaier
5770126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
5771126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
5772126261Smlaier		((ip->ip_off & htons(IP_DF)) == 0))) {
5773126261Smlaier		/*
5774126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
5775126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
5776126261Smlaier		 */
5777126261Smlaier		ip->ip_sum = 0;
5778126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
5779126261Smlaier			/* From KAME */
5780126261Smlaier			if (ip->ip_v == IPVERSION &&
5781126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
5782126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
5783126261Smlaier			} else {
5784126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5785126261Smlaier			}
5786126261Smlaier		}
5787126261Smlaier		PF_UNLOCK();
5788126261Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
5789126261Smlaier		PF_LOCK();
5790126261Smlaier		goto done;
5791126261Smlaier	}
5792126261Smlaier
5793126261Smlaier#else
5794126258Smlaier	/* Copied from ip_output. */
5795130613Smlaier#ifdef IPSEC
5796130613Smlaier	/*
5797130613Smlaier	 * If deferred crypto processing is needed, check that the
5798130613Smlaier	 * interface supports it.
5799130613Smlaier	 */
5800130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
5801130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
5802130613Smlaier		/* Notify IPsec to do its own crypto. */
5803130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
5804130613Smlaier		goto bad;
5805130613Smlaier	}
5806130613Smlaier#endif /* IPSEC */
5807130613Smlaier
5808130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
5809130613Smlaier	if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) {
5810130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
5811130613Smlaier		    ifp->if_bridge != NULL) {
5812130613Smlaier			in_delayed_cksum(m0);
5813130613Smlaier			m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
5814130613Smlaier		}
5815130613Smlaier	} else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) {
5816130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
5817130613Smlaier		    ifp->if_bridge != NULL) {
5818130613Smlaier			in_delayed_cksum(m0);
5819130613Smlaier			m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
5820130613Smlaier		}
5821130613Smlaier	}
5822130613Smlaier
5823126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
5824126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
5825126258Smlaier		    ifp->if_bridge == NULL) {
5826126258Smlaier			m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT;
5827126258Smlaier			ipstat.ips_outhwcsum++;
5828126258Smlaier		} else {
5829126258Smlaier			ip->ip_sum = 0;
5830126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5831126258Smlaier		}
5832126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
5833126258Smlaier		if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
5834126258Smlaier			tcpstat.tcps_outhwcsum++;
5835126258Smlaier		else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
5836126258Smlaier			udpstat.udps_outhwcsum++;
5837126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
5838126258Smlaier		goto done;
5839126258Smlaier	}
5840126261Smlaier#endif
5841126258Smlaier	/*
5842126258Smlaier	 * Too large for interface; fragment if possible.
5843126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
5844126258Smlaier	 */
5845126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
5846126258Smlaier		ipstat.ips_cantfrag++;
5847126258Smlaier		if (r->rt != PF_DUPTO) {
5848127145Smlaier#ifdef __FreeBSD__
5849126261Smlaier			/* icmp_error() expects host byte ordering */
5850126261Smlaier			NTOHS(ip->ip_len);
5851126261Smlaier			NTOHS(ip->ip_off);
5852126261Smlaier			PF_UNLOCK();
5853126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
5854145886Smlaier			    ifp->if_mtu);
5855145874Smlaier			PF_LOCK();
5856145874Smlaier#else
5857145874Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
5858145873Smlaier			    ifp);
5859126261Smlaier#endif
5860126258Smlaier			goto done;
5861126258Smlaier		} else
5862126258Smlaier			goto bad;
5863126258Smlaier	}
5864126258Smlaier
5865126258Smlaier	m1 = m0;
5866127145Smlaier#ifdef __FreeBSD__
5867126261Smlaier	/*
5868126261Smlaier	 * XXX: is cheaper + less error prone than own function
5869126261Smlaier	 */
5870126261Smlaier	NTOHS(ip->ip_len);
5871126261Smlaier	NTOHS(ip->ip_off);
5872126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
5873126261Smlaier#else
5874126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
5875126261Smlaier#endif
5876127531Smlaier	if (error) {
5877127531Smlaier#ifndef __FreeBSD__	/* ip_fragment does not do m_freem() on FreeBSD */
5878127531Smlaier		m0 = NULL;
5879126261Smlaier#endif
5880126258Smlaier		goto bad;
5881127531Smlaier	}
5882126258Smlaier
5883126258Smlaier	for (m0 = m1; m0; m0 = m1) {
5884126258Smlaier		m1 = m0->m_nextpkt;
5885126258Smlaier		m0->m_nextpkt = 0;
5886127145Smlaier#ifdef __FreeBSD__
5887126261Smlaier		if (error == 0) {
5888126261Smlaier			PF_UNLOCK();
5889126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5890126261Smlaier			    NULL);
5891126261Smlaier			PF_LOCK();
5892126261Smlaier		} else
5893126261Smlaier#else
5894126258Smlaier		if (error == 0)
5895126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5896126258Smlaier			    NULL);
5897126258Smlaier		else
5898126261Smlaier#endif
5899126258Smlaier			m_freem(m0);
5900126258Smlaier	}
5901126258Smlaier
5902126258Smlaier	if (error == 0)
5903126258Smlaier		ipstat.ips_fragmented++;
5904126258Smlaier
5905126258Smlaierdone:
5906126258Smlaier	if (r->rt != PF_DUPTO)
5907126258Smlaier		*m = NULL;
5908126258Smlaier	if (ro == &iproute && ro->ro_rt)
5909126258Smlaier		RTFREE(ro->ro_rt);
5910126258Smlaier	return;
5911126258Smlaier
5912126258Smlaierbad:
5913126258Smlaier	m_freem(m0);
5914126258Smlaier	goto done;
5915126258Smlaier}
5916126258Smlaier#endif /* INET */
5917126258Smlaier
5918126258Smlaier#ifdef INET6
5919126258Smlaiervoid
5920126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5921126258Smlaier    struct pf_state *s)
5922126258Smlaier{
5923126258Smlaier	struct mbuf		*m0;
5924126258Smlaier	struct m_tag		*mtag;
5925126258Smlaier	struct route_in6	 ip6route;
5926126258Smlaier	struct route_in6	*ro;
5927126258Smlaier	struct sockaddr_in6	*dst;
5928126258Smlaier	struct ip6_hdr		*ip6;
5929126258Smlaier	struct ifnet		*ifp = NULL;
5930126258Smlaier	struct pf_addr		 naddr;
5931130613Smlaier	struct pf_src_node	*sn = NULL;
5932126258Smlaier	int			 error = 0;
5933126258Smlaier
5934126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5935126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5936126258Smlaier		panic("pf_route6: invalid parameters");
5937126258Smlaier
5938132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
5939132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
5940132303Smlaier		    NULL) {
5941132303Smlaier			m0 = *m;
5942132303Smlaier			*m = NULL;
5943132303Smlaier			goto bad;
5944132303Smlaier		}
5945132303Smlaier		*(char *)(mtag + 1) = 1;
5946132303Smlaier		m_tag_prepend(*m, mtag);
5947132303Smlaier	} else {
5948132303Smlaier		if (*(char *)(mtag + 1) > 3) {
5949132303Smlaier			m0 = *m;
5950132303Smlaier			*m = NULL;
5951132303Smlaier			goto bad;
5952132303Smlaier		}
5953132303Smlaier		(*(char *)(mtag + 1))++;
5954132303Smlaier	}
5955132303Smlaier
5956126258Smlaier	if (r->rt == PF_DUPTO) {
5957127145Smlaier#ifdef __FreeBSD__
5958132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5959126261Smlaier#else
5960132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5961126261Smlaier#endif
5962126258Smlaier			return;
5963126258Smlaier	} else {
5964126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5965126258Smlaier			return;
5966126258Smlaier		m0 = *m;
5967126258Smlaier	}
5968126258Smlaier
5969145836Smlaier	if (m0->m_len < sizeof(struct ip6_hdr)) {
5970145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
5971145836Smlaier		    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
5972145836Smlaier		goto bad;
5973145836Smlaier	}
5974126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
5975126258Smlaier
5976126258Smlaier	ro = &ip6route;
5977126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5978126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
5979126258Smlaier	dst->sin6_family = AF_INET6;
5980126258Smlaier	dst->sin6_len = sizeof(*dst);
5981126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
5982126258Smlaier
5983126258Smlaier	/* Cheat. */
5984126258Smlaier	if (r->rt == PF_FASTROUTE) {
5985127145Smlaier#ifdef __FreeBSD__
5986132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
5987126261Smlaier		PF_UNLOCK();
5988126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
5989126261Smlaier		PF_LOCK();
5990126261Smlaier#else
5991132280Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
5992132280Smlaier		if (mtag == NULL)
5993132280Smlaier			goto bad;
5994132280Smlaier		m_tag_prepend(m0, mtag);
5995126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
5996126261Smlaier#endif
5997126258Smlaier		return;
5998126258Smlaier	}
5999126258Smlaier
6000145836Smlaier	if (TAILQ_EMPTY(&r->rpool.list)) {
6001145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6002145836Smlaier		    ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
6003145836Smlaier		goto bad;
6004145836Smlaier	}
6005126258Smlaier	if (s == NULL) {
6006130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
6007130613Smlaier		    &naddr, NULL, &sn);
6008126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
6009126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6010126258Smlaier			    &naddr, AF_INET6);
6011130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
6012126258Smlaier	} else {
6013126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
6014126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6015126258Smlaier			    &s->rt_addr, AF_INET6);
6016130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6017126258Smlaier	}
6018126258Smlaier	if (ifp == NULL)
6019126258Smlaier		goto bad;
6020126258Smlaier
6021126258Smlaier	if (oifp != ifp) {
6022127145Smlaier#ifdef __FreeBSD__
6023132303Smlaier		PF_UNLOCK();
6024145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6025126261Smlaier			PF_LOCK();
6026132303Smlaier			goto bad;
6027132303Smlaier		} else if (m0 == NULL) {
6028132303Smlaier			PF_LOCK();
6029132303Smlaier			goto done;
6030132303Smlaier		}
6031132303Smlaier		PF_LOCK();
6032126261Smlaier#else
6033145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6034132303Smlaier			goto bad;
6035132303Smlaier		else if (m0 == NULL)
6036132303Smlaier			goto done;
6037126261Smlaier#endif
6038145836Smlaier		if (m0->m_len < sizeof(struct ip6_hdr)) {
6039145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6040145836Smlaier			    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6041145836Smlaier			goto bad;
6042145836Smlaier		}
6043132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
6044126258Smlaier	}
6045126258Smlaier
6046126258Smlaier	/*
6047126258Smlaier	 * If the packet is too large for the outgoing interface,
6048126258Smlaier	 * send back an icmp6 error.
6049126258Smlaier	 */
6050126258Smlaier	if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
6051126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
6052126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
6053127145Smlaier#ifdef __FreeBSD__
6054126261Smlaier		PF_UNLOCK();
6055126261Smlaier#endif
6056126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
6057127145Smlaier#ifdef __FreeBSD__
6058126261Smlaier		PF_LOCK();
6059126261Smlaier#endif
6060126258Smlaier	} else {
6061126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
6062127145Smlaier#ifdef __FreeBSD__
6063126261Smlaier		if (r->rt != PF_DUPTO) {
6064126261Smlaier			PF_UNLOCK();
6065126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6066126261Smlaier			PF_LOCK();
6067126261Smlaier		 } else
6068126261Smlaier#else
6069126258Smlaier		if (r->rt != PF_DUPTO)
6070126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6071126258Smlaier		else
6072126261Smlaier#endif
6073126258Smlaier			goto bad;
6074126258Smlaier	}
6075126258Smlaier
6076126258Smlaierdone:
6077126258Smlaier	if (r->rt != PF_DUPTO)
6078126258Smlaier		*m = NULL;
6079126258Smlaier	return;
6080126258Smlaier
6081126258Smlaierbad:
6082126258Smlaier	m_freem(m0);
6083126258Smlaier	goto done;
6084126258Smlaier}
6085126258Smlaier#endif /* INET6 */
6086126258Smlaier
6087126258Smlaier
6088127145Smlaier#ifdef __FreeBSD__
6089126258Smlaier/*
6090132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
6091137413Sru *  em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
6092132566Smlaier *   ti(4), txp(4), xl(4)
6093132566Smlaier *
6094132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
6095132566Smlaier *  network driver performed cksum including pseudo header, need to verify
6096132566Smlaier *   csum_data
6097132566Smlaier * CSUM_DATA_VALID :
6098132566Smlaier *  network driver performed cksum, needs to additional pseudo header
6099132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
6100132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
6101132566Smlaier *
6102132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
6103132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
6104132566Smlaier * TCP/UDP layer.
6105132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
6106126261Smlaier */
6107126261Smlaierint
6108126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
6109126261Smlaier{
6110126261Smlaier	u_int16_t sum = 0;
6111126261Smlaier	int hw_assist = 0;
6112126261Smlaier	struct ip *ip;
6113126261Smlaier
6114126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6115126261Smlaier		return (1);
6116126261Smlaier	if (m->m_pkthdr.len < off + len)
6117126261Smlaier		return (1);
6118126261Smlaier
6119126261Smlaier	switch (p) {
6120126261Smlaier	case IPPROTO_TCP:
6121126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6122126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6123126261Smlaier				sum = m->m_pkthdr.csum_data;
6124126261Smlaier			} else {
6125126261Smlaier				ip = mtod(m, struct ip *);
6126126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6127135078Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6128135078Smlaier					m->m_pkthdr.csum_data + IPPROTO_TCP));
6129126261Smlaier			}
6130126261Smlaier			sum ^= 0xffff;
6131126261Smlaier			++hw_assist;
6132126261Smlaier		}
6133126261Smlaier		break;
6134126261Smlaier	case IPPROTO_UDP:
6135126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6136126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6137126261Smlaier				sum = m->m_pkthdr.csum_data;
6138126261Smlaier			} else {
6139126261Smlaier				ip = mtod(m, struct ip *);
6140126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6141126261Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6142126261Smlaier					m->m_pkthdr.csum_data + IPPROTO_UDP));
6143126261Smlaier			}
6144126261Smlaier			sum ^= 0xffff;
6145126261Smlaier			++hw_assist;
6146126261Smlaier                }
6147126261Smlaier		break;
6148126261Smlaier	case IPPROTO_ICMP:
6149126261Smlaier#ifdef INET6
6150126261Smlaier	case IPPROTO_ICMPV6:
6151126261Smlaier#endif /* INET6 */
6152126261Smlaier		break;
6153126261Smlaier	default:
6154126261Smlaier		return (1);
6155126261Smlaier	}
6156126261Smlaier
6157126261Smlaier	if (!hw_assist) {
6158126261Smlaier		switch (af) {
6159126261Smlaier		case AF_INET:
6160126261Smlaier			if (p == IPPROTO_ICMP) {
6161126261Smlaier				if (m->m_len < off)
6162126261Smlaier					return (1);
6163126261Smlaier				m->m_data += off;
6164126261Smlaier				m->m_len -= off;
6165126261Smlaier				sum = in_cksum(m, len);
6166126261Smlaier				m->m_data -= off;
6167126261Smlaier				m->m_len += off;
6168126261Smlaier			} else {
6169126261Smlaier				if (m->m_len < sizeof(struct ip))
6170126261Smlaier					return (1);
6171126261Smlaier				sum = in4_cksum(m, p, off, len);
6172126261Smlaier			}
6173126261Smlaier			break;
6174126261Smlaier#ifdef INET6
6175126261Smlaier		case AF_INET6:
6176126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
6177126261Smlaier				return (1);
6178126261Smlaier			sum = in6_cksum(m, p, off, len);
6179126261Smlaier			break;
6180126261Smlaier#endif /* INET6 */
6181126261Smlaier		default:
6182126261Smlaier			return (1);
6183126261Smlaier		}
6184126261Smlaier	}
6185126261Smlaier	if (sum) {
6186126261Smlaier		switch (p) {
6187126261Smlaier		case IPPROTO_TCP:
6188126261Smlaier			tcpstat.tcps_rcvbadsum++;
6189126261Smlaier			break;
6190126261Smlaier		case IPPROTO_UDP:
6191126261Smlaier			udpstat.udps_badsum++;
6192126261Smlaier			break;
6193126261Smlaier		case IPPROTO_ICMP:
6194126261Smlaier			icmpstat.icps_checksum++;
6195126261Smlaier			break;
6196126261Smlaier#ifdef INET6
6197126261Smlaier		case IPPROTO_ICMPV6:
6198126261Smlaier			icmp6stat.icp6s_checksum++;
6199126261Smlaier			break;
6200126261Smlaier#endif /* INET6 */
6201126261Smlaier		}
6202126261Smlaier		return (1);
6203132566Smlaier	} else {
6204132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
6205132566Smlaier			m->m_pkthdr.csum_flags |=
6206132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
6207132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
6208132566Smlaier		}
6209126261Smlaier	}
6210126261Smlaier	return (0);
6211126261Smlaier}
6212126261Smlaier#else
6213126261Smlaier/*
6214126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
6215126258Smlaier *   off is the offset where the protocol header starts
6216126258Smlaier *   len is the total length of protocol header plus payload
6217126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
6218126258Smlaier */
6219126258Smlaierint
6220130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
6221130613Smlaier    sa_family_t af)
6222126258Smlaier{
6223126258Smlaier	u_int16_t flag_ok, flag_bad;
6224126258Smlaier	u_int16_t sum;
6225126258Smlaier
6226126258Smlaier	switch (p) {
6227126258Smlaier	case IPPROTO_TCP:
6228126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
6229126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
6230126258Smlaier		break;
6231126258Smlaier	case IPPROTO_UDP:
6232126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
6233126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
6234126258Smlaier		break;
6235126258Smlaier	case IPPROTO_ICMP:
6236126258Smlaier#ifdef INET6
6237126258Smlaier	case IPPROTO_ICMPV6:
6238126258Smlaier#endif /* INET6 */
6239126258Smlaier		flag_ok = flag_bad = 0;
6240126258Smlaier		break;
6241126258Smlaier	default:
6242126258Smlaier		return (1);
6243126258Smlaier	}
6244126258Smlaier	if (m->m_pkthdr.csum & flag_ok)
6245126258Smlaier		return (0);
6246126258Smlaier	if (m->m_pkthdr.csum & flag_bad)
6247126258Smlaier		return (1);
6248126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6249126258Smlaier		return (1);
6250126258Smlaier	if (m->m_pkthdr.len < off + len)
6251126258Smlaier		return (1);
6252145836Smlaier	switch (af) {
6253145836Smlaier#ifdef INET
6254126258Smlaier	case AF_INET:
6255126258Smlaier		if (p == IPPROTO_ICMP) {
6256126258Smlaier			if (m->m_len < off)
6257126258Smlaier				return (1);
6258126258Smlaier			m->m_data += off;
6259126258Smlaier			m->m_len -= off;
6260126258Smlaier			sum = in_cksum(m, len);
6261126258Smlaier			m->m_data -= off;
6262126258Smlaier			m->m_len += off;
6263126258Smlaier		} else {
6264126258Smlaier			if (m->m_len < sizeof(struct ip))
6265126258Smlaier				return (1);
6266126258Smlaier			sum = in4_cksum(m, p, off, len);
6267126258Smlaier		}
6268126258Smlaier		break;
6269145836Smlaier#endif /* INET */
6270126258Smlaier#ifdef INET6
6271126258Smlaier	case AF_INET6:
6272126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
6273126258Smlaier			return (1);
6274126258Smlaier		sum = in6_cksum(m, p, off, len);
6275126258Smlaier		break;
6276126258Smlaier#endif /* INET6 */
6277126258Smlaier	default:
6278126258Smlaier		return (1);
6279126258Smlaier	}
6280126258Smlaier	if (sum) {
6281126258Smlaier		m->m_pkthdr.csum |= flag_bad;
6282126258Smlaier		switch (p) {
6283126258Smlaier		case IPPROTO_TCP:
6284126258Smlaier			tcpstat.tcps_rcvbadsum++;
6285126258Smlaier			break;
6286126258Smlaier		case IPPROTO_UDP:
6287126258Smlaier			udpstat.udps_badsum++;
6288126258Smlaier			break;
6289126258Smlaier		case IPPROTO_ICMP:
6290126258Smlaier			icmpstat.icps_checksum++;
6291126258Smlaier			break;
6292126258Smlaier#ifdef INET6
6293126258Smlaier		case IPPROTO_ICMPV6:
6294126258Smlaier			icmp6stat.icp6s_checksum++;
6295126258Smlaier			break;
6296126258Smlaier#endif /* INET6 */
6297126258Smlaier		}
6298126258Smlaier		return (1);
6299126258Smlaier	}
6300126258Smlaier	m->m_pkthdr.csum |= flag_ok;
6301126258Smlaier	return (0);
6302126258Smlaier}
6303126261Smlaier#endif
6304126258Smlaier
6305130613Smlaierstatic int
6306130613Smlaierpf_add_mbuf_tag(struct mbuf *m, u_int tag)
6307130613Smlaier{
6308130613Smlaier	struct m_tag *mtag;
6309130613Smlaier
6310130613Smlaier	if (m_tag_find(m, tag, NULL) != NULL)
6311130613Smlaier		return (0);
6312130613Smlaier	mtag = m_tag_get(tag, 0, M_NOWAIT);
6313130613Smlaier	if (mtag == NULL)
6314130613Smlaier		return (1);
6315130613Smlaier	m_tag_prepend(m, mtag);
6316130613Smlaier	return (0);
6317130613Smlaier}
6318130613Smlaier
6319126258Smlaier#ifdef INET
6320126258Smlaierint
6321135920Smlaier#ifdef __FreeBSD__
6322145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6323145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6324135920Smlaier#else
6325145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6326145836Smlaier    struct ether_header *eh)
6327135920Smlaier#endif
6328126258Smlaier{
6329130613Smlaier	struct pfi_kif		*kif;
6330130613Smlaier	u_short			 action, reason = 0, log = 0;
6331130613Smlaier	struct mbuf		*m = *m0;
6332130613Smlaier	struct ip		*h = NULL;	/* make the compiler happy */
6333130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6334130613Smlaier	struct pf_state		*s = NULL;
6335130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6336130613Smlaier	struct pf_pdesc		 pd;
6337130613Smlaier	int			 off, dirndx, pqid = 0;
6338126258Smlaier
6339127145Smlaier#ifdef __FreeBSD__
6340126261Smlaier	PF_LOCK();
6341126261Smlaier#endif
6342126258Smlaier	if (!pf_status.running ||
6343127145Smlaier#ifdef __FreeBSD__
6344132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
6345126261Smlaier		PF_UNLOCK();
6346132280Smlaier#else
6347132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
6348126261Smlaier#endif
6349126261Smlaier	    	return (PF_PASS);
6350126261Smlaier	}
6351126258Smlaier
6352145836Smlaier#ifdef __FreeBSD__
6353145836Smlaier	/* XXX_IMPORT: later */
6354145836Smlaier#else
6355145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6356145836Smlaier		ifp = ifp->if_carpdev;
6357145836Smlaier#endif
6358145836Smlaier
6359130613Smlaier	kif = pfi_index2kif[ifp->if_index];
6360130613Smlaier	if (kif == NULL) {
6361130613Smlaier#ifdef __FreeBSD__
6362130613Smlaier		PF_UNLOCK();
6363130613Smlaier#endif
6364145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6365145836Smlaier		    ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
6366130613Smlaier		return (PF_DROP);
6367130613Smlaier	}
6368145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6369145836Smlaier#ifdef __FreeBSD__
6370145836Smlaier		PF_UNLOCK();
6371145836Smlaier#endif
6372145836Smlaier		return (PF_PASS);
6373145836Smlaier	}
6374130613Smlaier
6375130613Smlaier#ifdef __FreeBSD__
6376126261Smlaier	M_ASSERTPKTHDR(m);
6377126261Smlaier#else
6378126258Smlaier#ifdef DIAGNOSTIC
6379126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6380126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6381145836Smlaier#endif /* DIAGNOSTIC */
6382145836Smlaier#endif /* __FreeBSD__ */
6383126258Smlaier
6384130613Smlaier	memset(&pd, 0, sizeof(pd));
6385126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6386126258Smlaier		action = PF_DROP;
6387126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6388126258Smlaier		log = 1;
6389126258Smlaier		goto done;
6390126258Smlaier	}
6391126258Smlaier
6392126258Smlaier	/* We do IP header normalization and packet reassembly here */
6393145836Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
6394126258Smlaier		action = PF_DROP;
6395126258Smlaier		goto done;
6396126258Smlaier	}
6397126258Smlaier	m = *m0;
6398126258Smlaier	h = mtod(m, struct ip *);
6399126258Smlaier
6400126258Smlaier	off = h->ip_hl << 2;
6401126258Smlaier	if (off < (int)sizeof(*h)) {
6402126258Smlaier		action = PF_DROP;
6403126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6404126258Smlaier		log = 1;
6405126258Smlaier		goto done;
6406126258Smlaier	}
6407126258Smlaier
6408126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
6409126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
6410130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
6411126258Smlaier	pd.ip_sum = &h->ip_sum;
6412126258Smlaier	pd.proto = h->ip_p;
6413126258Smlaier	pd.af = AF_INET;
6414126258Smlaier	pd.tos = h->ip_tos;
6415126258Smlaier	pd.tot_len = ntohs(h->ip_len);
6416145836Smlaier	pd.eh = eh;
6417126258Smlaier
6418126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
6419126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
6420130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
6421126258Smlaier		    &pd, &a, &ruleset);
6422126258Smlaier		goto done;
6423126258Smlaier	}
6424126258Smlaier
6425126258Smlaier	switch (h->ip_p) {
6426126258Smlaier
6427126258Smlaier	case IPPROTO_TCP: {
6428126258Smlaier		struct tcphdr	th;
6429126258Smlaier
6430126258Smlaier		pd.hdr.tcp = &th;
6431126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6432126258Smlaier		    &action, &reason, AF_INET)) {
6433126258Smlaier			log = action != PF_PASS;
6434126258Smlaier			goto done;
6435126258Smlaier		}
6436126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6437126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
6438126258Smlaier			action = PF_DROP;
6439126258Smlaier			goto done;
6440126258Smlaier		}
6441126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6442126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
6443126258Smlaier			pqid = 1;
6444130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6445126258Smlaier		if (action == PF_DROP)
6446130613Smlaier			goto done;
6447130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6448126258Smlaier		    &reason);
6449126258Smlaier		if (action == PF_PASS) {
6450130613Smlaier#if NPFSYNC
6451130613Smlaier			pfsync_update_state(s);
6452145836Smlaier#endif /* NPFSYNC */
6453126258Smlaier			r = s->rule.ptr;
6454130613Smlaier			a = s->anchor.ptr;
6455126258Smlaier			log = s->log;
6456126258Smlaier		} else if (s == NULL)
6457135920Smlaier#ifdef __FreeBSD__
6458130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6459145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6460135920Smlaier#else
6461135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6462145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6463135920Smlaier#endif
6464126258Smlaier		break;
6465126258Smlaier	}
6466126258Smlaier
6467126258Smlaier	case IPPROTO_UDP: {
6468126258Smlaier		struct udphdr	uh;
6469126258Smlaier
6470126258Smlaier		pd.hdr.udp = &uh;
6471126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6472126258Smlaier		    &action, &reason, AF_INET)) {
6473126258Smlaier			log = action != PF_PASS;
6474126258Smlaier			goto done;
6475126258Smlaier		}
6476126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6477126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
6478126258Smlaier			action = PF_DROP;
6479126258Smlaier			goto done;
6480126258Smlaier		}
6481130613Smlaier		if (uh.uh_dport == 0 ||
6482130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6483130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6484130613Smlaier			action = PF_DROP;
6485130613Smlaier			goto done;
6486130613Smlaier		}
6487130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6488126258Smlaier		if (action == PF_PASS) {
6489130613Smlaier#if NPFSYNC
6490130613Smlaier			pfsync_update_state(s);
6491145836Smlaier#endif /* NPFSYNC */
6492126258Smlaier			r = s->rule.ptr;
6493126258Smlaier			a = s->anchor.ptr;
6494126258Smlaier			log = s->log;
6495126258Smlaier		} else if (s == NULL)
6496135920Smlaier#ifdef __FreeBSD__
6497130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6498145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6499135920Smlaier#else
6500135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6501145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6502135920Smlaier#endif
6503126258Smlaier		break;
6504126258Smlaier	}
6505126258Smlaier
6506126258Smlaier	case IPPROTO_ICMP: {
6507126258Smlaier		struct icmp	ih;
6508126258Smlaier
6509126258Smlaier		pd.hdr.icmp = &ih;
6510126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
6511126258Smlaier		    &action, &reason, AF_INET)) {
6512126258Smlaier			log = action != PF_PASS;
6513126258Smlaier			goto done;
6514126258Smlaier		}
6515126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6516126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
6517126258Smlaier			action = PF_DROP;
6518126258Smlaier			goto done;
6519126258Smlaier		}
6520145836Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
6521145836Smlaier		    &reason);
6522126258Smlaier		if (action == PF_PASS) {
6523130613Smlaier#if NPFSYNC
6524130613Smlaier			pfsync_update_state(s);
6525145836Smlaier#endif /* NPFSYNC */
6526126258Smlaier			r = s->rule.ptr;
6527126258Smlaier			a = s->anchor.ptr;
6528126258Smlaier			log = s->log;
6529126258Smlaier		} else if (s == NULL)
6530145836Smlaier#ifdef __FreeBSD__
6531130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6532145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6533145836Smlaier#else
6534145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6535145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6536145836Smlaier#endif
6537126258Smlaier		break;
6538126258Smlaier	}
6539126258Smlaier
6540126258Smlaier	default:
6541130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6542126258Smlaier		if (action == PF_PASS) {
6543130613Smlaier#if NPFSYNC
6544130613Smlaier			pfsync_update_state(s);
6545145836Smlaier#endif /* NPFSYNC */
6546126258Smlaier			r = s->rule.ptr;
6547126258Smlaier			a = s->anchor.ptr;
6548126258Smlaier			log = s->log;
6549126258Smlaier		} else if (s == NULL)
6550145836Smlaier#ifdef __FreeBSD__
6551130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6552145836Smlaier			    &pd, &a, &ruleset, NULL);
6553145836Smlaier#else
6554145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6555145836Smlaier			    &pd, &a, &ruleset, &ipintrq);
6556145836Smlaier#endif
6557126258Smlaier		break;
6558126258Smlaier	}
6559126258Smlaier
6560126258Smlaierdone:
6561126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
6562126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
6563126258Smlaier		action = PF_DROP;
6564145836Smlaier		REASON_SET(&reason, PFRES_IPOPTIONS);
6565126258Smlaier		log = 1;
6566126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
6567126258Smlaier		    ("pf: dropping packet with ip options\n"));
6568126258Smlaier	}
6569126258Smlaier
6570145836Smlaier	if (s && s->tag)
6571145836Smlaier		pf_tag_packet(m, pf_get_tag(m), s->tag);
6572145836Smlaier
6573126258Smlaier#ifdef ALTQ
6574126258Smlaier	if (action == PF_PASS && r->qid) {
6575126258Smlaier		struct m_tag	*mtag;
6576126258Smlaier		struct altq_tag	*atag;
6577126258Smlaier
6578126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
6579126258Smlaier		if (mtag != NULL) {
6580126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
6581126258Smlaier			if (pqid || pd.tos == IPTOS_LOWDELAY)
6582126258Smlaier				atag->qid = r->pqid;
6583126258Smlaier			else
6584126258Smlaier				atag->qid = r->qid;
6585126258Smlaier			/* add hints for ecn */
6586126258Smlaier			atag->af = AF_INET;
6587126258Smlaier			atag->hdr = h;
6588126258Smlaier			m_tag_prepend(m, mtag);
6589126258Smlaier		}
6590126258Smlaier	}
6591145836Smlaier#endif /* ALTQ */
6592126258Smlaier
6593130613Smlaier	/*
6594130613Smlaier	 * connections redirected to loopback should not match sockets
6595130613Smlaier	 * bound specifically to loopback due to security implications,
6596130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
6597130613Smlaier	 */
6598130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
6599130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
6600130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
6601130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
6602130613Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
6603130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
6604130613Smlaier		action = PF_DROP;
6605130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
6606130613Smlaier	}
6607130613Smlaier
6608126258Smlaier	if (log)
6609130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset);
6610126258Smlaier
6611130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
6612130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
6613130613Smlaier
6614130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
6615130613Smlaier		r->packets++;
6616130613Smlaier		r->bytes += pd.tot_len;
6617130613Smlaier		if (a != NULL) {
6618130613Smlaier			a->packets++;
6619130613Smlaier			a->bytes += pd.tot_len;
6620130613Smlaier		}
6621130613Smlaier		if (s != NULL) {
6622130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
6623130613Smlaier			s->packets[dirndx]++;
6624130613Smlaier			s->bytes[dirndx] += pd.tot_len;
6625130613Smlaier			if (s->nat_rule.ptr != NULL) {
6626130613Smlaier				s->nat_rule.ptr->packets++;
6627130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
6628130613Smlaier			}
6629130613Smlaier			if (s->src_node != NULL) {
6630130613Smlaier				s->src_node->packets++;
6631130613Smlaier				s->src_node->bytes += pd.tot_len;
6632130613Smlaier			}
6633130613Smlaier			if (s->nat_src_node != NULL) {
6634130613Smlaier				s->nat_src_node->packets++;
6635130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
6636130613Smlaier			}
6637130613Smlaier		}
6638130613Smlaier		tr = r;
6639130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
6640130613Smlaier		if (nr != NULL) {
6641130613Smlaier			struct pf_addr *x;
6642130613Smlaier			/*
6643130613Smlaier			 * XXX: we need to make sure that the addresses
6644130613Smlaier			 * passed to pfr_update_stats() are the same than
6645130613Smlaier			 * the addresses used during matching (pfr_match)
6646130613Smlaier			 */
6647130613Smlaier			if (r == &pf_default_rule) {
6648130613Smlaier				tr = nr;
6649130613Smlaier				x = (s == NULL || s->direction == dir) ?
6650130613Smlaier				    &pd.baddr : &pd.naddr;
6651130613Smlaier			} else
6652130613Smlaier				x = (s == NULL || s->direction == dir) ?
6653130613Smlaier				    &pd.naddr : &pd.baddr;
6654130613Smlaier			if (x == &pd.baddr || s == NULL) {
6655130613Smlaier				/* we need to change the address */
6656130613Smlaier				if (dir == PF_OUT)
6657130613Smlaier					pd.src = x;
6658130613Smlaier				else
6659130613Smlaier					pd.dst = x;
6660130613Smlaier			}
6661130613Smlaier		}
6662130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
6663130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
6664130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
6665130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6666145836Smlaier			    tr->src.neg);
6667130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
6668130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
6669130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
6670130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6671145836Smlaier			    tr->dst.neg);
6672130613Smlaier	}
6673130613Smlaier
6674130613Smlaier
6675126258Smlaier	if (action == PF_SYNPROXY_DROP) {
6676126258Smlaier		m_freem(*m0);
6677126258Smlaier		*m0 = NULL;
6678126258Smlaier		action = PF_PASS;
6679126258Smlaier	} else if (r->rt)
6680126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
6681126258Smlaier		pf_route(m0, r, dir, ifp, s);
6682126258Smlaier
6683127145Smlaier#ifdef __FreeBSD__
6684126261Smlaier	PF_UNLOCK();
6685126261Smlaier#endif
6686126261Smlaier
6687126258Smlaier	return (action);
6688126258Smlaier}
6689126258Smlaier#endif /* INET */
6690126258Smlaier
6691126258Smlaier#ifdef INET6
6692126258Smlaierint
6693135920Smlaier#ifdef __FreeBSD__
6694145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
6695145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6696135920Smlaier#else
6697145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
6698145836Smlaier    struct ether_header *eh)
6699135920Smlaier#endif
6700126258Smlaier{
6701130613Smlaier	struct pfi_kif		*kif;
6702130613Smlaier	u_short			 action, reason = 0, log = 0;
6703130613Smlaier	struct mbuf		*m = *m0;
6704130613Smlaier	struct ip6_hdr		*h = NULL;	/* make the compiler happy */
6705130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6706130613Smlaier	struct pf_state		*s = NULL;
6707130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6708130613Smlaier	struct pf_pdesc		 pd;
6709130613Smlaier	int			 off, terminal = 0, dirndx;
6710126258Smlaier
6711127145Smlaier#ifdef __FreeBSD__
6712126261Smlaier	PF_LOCK();
6713126261Smlaier#endif
6714126261Smlaier
6715126258Smlaier	if (!pf_status.running ||
6716127145Smlaier#ifdef __FreeBSD__
6717132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
6718126261Smlaier		PF_UNLOCK();
6719132280Smlaier#else
6720132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
6721126261Smlaier#endif
6722126258Smlaier		return (PF_PASS);
6723126261Smlaier	}
6724126258Smlaier
6725145836Smlaier#ifdef __FreeBSD__
6726145836Smlaier	/* XXX_IMPORT: later */
6727145836Smlaier#else
6728145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6729145836Smlaier		ifp = ifp->if_carpdev;
6730145836Smlaier#endif
6731145836Smlaier
6732130613Smlaier	kif = pfi_index2kif[ifp->if_index];
6733130613Smlaier	if (kif == NULL) {
6734130613Smlaier#ifdef __FreeBSD__
6735130613Smlaier		PF_UNLOCK();
6736130613Smlaier#endif
6737145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6738145836Smlaier		    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
6739130613Smlaier		return (PF_DROP);
6740130613Smlaier	}
6741145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6742145836Smlaier#ifdef __FreeBSD__
6743145836Smlaier		PF_UNLOCK();
6744145836Smlaier#endif
6745145836Smlaier		return (PF_PASS);
6746145836Smlaier	}
6747130613Smlaier
6748130613Smlaier#ifdef __FreeBSD__
6749126261Smlaier	M_ASSERTPKTHDR(m);
6750126261Smlaier#else
6751126258Smlaier#ifdef DIAGNOSTIC
6752126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6753145836Smlaier		panic("non-M_PKTHDR is passed to pf_test6");
6754145836Smlaier#endif /* DIAGNOSTIC */
6755126258Smlaier#endif
6756126258Smlaier
6757130613Smlaier	memset(&pd, 0, sizeof(pd));
6758126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6759126258Smlaier		action = PF_DROP;
6760126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6761126258Smlaier		log = 1;
6762126258Smlaier		goto done;
6763126258Smlaier	}
6764126258Smlaier
6765126258Smlaier	/* We do IP header normalization and packet reassembly here */
6766145836Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
6767126258Smlaier		action = PF_DROP;
6768126258Smlaier		goto done;
6769126258Smlaier	}
6770126258Smlaier	m = *m0;
6771126258Smlaier	h = mtod(m, struct ip6_hdr *);
6772126258Smlaier
6773126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
6774126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
6775130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
6776126258Smlaier	pd.ip_sum = NULL;
6777126258Smlaier	pd.af = AF_INET6;
6778126258Smlaier	pd.tos = 0;
6779126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
6780145836Smlaier	pd.eh = eh;
6781126258Smlaier
6782126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
6783126258Smlaier	pd.proto = h->ip6_nxt;
6784126258Smlaier	do {
6785126258Smlaier		switch (pd.proto) {
6786126258Smlaier		case IPPROTO_FRAGMENT:
6787130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
6788126258Smlaier			    &pd, &a, &ruleset);
6789126258Smlaier			if (action == PF_DROP)
6790126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
6791126258Smlaier			goto done;
6792126258Smlaier		case IPPROTO_AH:
6793126258Smlaier		case IPPROTO_HOPOPTS:
6794126258Smlaier		case IPPROTO_ROUTING:
6795126258Smlaier		case IPPROTO_DSTOPTS: {
6796126258Smlaier			/* get next header and header length */
6797126258Smlaier			struct ip6_ext	opt6;
6798126258Smlaier
6799126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
6800145836Smlaier			    NULL, &reason, pd.af)) {
6801126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
6802126258Smlaier				    ("pf: IPv6 short opt\n"));
6803126258Smlaier				action = PF_DROP;
6804126258Smlaier				log = 1;
6805126258Smlaier				goto done;
6806126258Smlaier			}
6807126258Smlaier			if (pd.proto == IPPROTO_AH)
6808126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
6809126258Smlaier			else
6810126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
6811126258Smlaier			pd.proto = opt6.ip6e_nxt;
6812126258Smlaier			/* goto the next header */
6813126258Smlaier			break;
6814126258Smlaier		}
6815126258Smlaier		default:
6816126258Smlaier			terminal++;
6817126258Smlaier			break;
6818126258Smlaier		}
6819126258Smlaier	} while (!terminal);
6820126258Smlaier
6821126258Smlaier	switch (pd.proto) {
6822126258Smlaier
6823126258Smlaier	case IPPROTO_TCP: {
6824126258Smlaier		struct tcphdr	th;
6825126258Smlaier
6826126258Smlaier		pd.hdr.tcp = &th;
6827126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6828126258Smlaier		    &action, &reason, AF_INET6)) {
6829126258Smlaier			log = action != PF_PASS;
6830126258Smlaier			goto done;
6831126258Smlaier		}
6832126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6833138387Sdhartmei		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6834138387Sdhartmei		    IPPROTO_TCP, AF_INET6)) {
6835126258Smlaier			action = PF_DROP;
6836145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6837126258Smlaier			goto done;
6838126258Smlaier		}
6839126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6840130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6841126258Smlaier		if (action == PF_DROP)
6842130613Smlaier			goto done;
6843130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6844126258Smlaier		    &reason);
6845126258Smlaier		if (action == PF_PASS) {
6846130613Smlaier#if NPFSYNC
6847130613Smlaier			pfsync_update_state(s);
6848145836Smlaier#endif /* NPFSYNC */
6849126258Smlaier			r = s->rule.ptr;
6850130613Smlaier			a = s->anchor.ptr;
6851126258Smlaier			log = s->log;
6852126258Smlaier		} else if (s == NULL)
6853135920Smlaier#ifdef __FreeBSD__
6854130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6855145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6856135920Smlaier#else
6857135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6858145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6859135920Smlaier#endif
6860126258Smlaier		break;
6861126258Smlaier	}
6862126258Smlaier
6863126258Smlaier	case IPPROTO_UDP: {
6864126258Smlaier		struct udphdr	uh;
6865126258Smlaier
6866126258Smlaier		pd.hdr.udp = &uh;
6867126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6868126258Smlaier		    &action, &reason, AF_INET6)) {
6869126258Smlaier			log = action != PF_PASS;
6870126258Smlaier			goto done;
6871126258Smlaier		}
6872126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6873138387Sdhartmei		    off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6874138387Sdhartmei		    IPPROTO_UDP, AF_INET6)) {
6875126258Smlaier			action = PF_DROP;
6876145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6877126258Smlaier			goto done;
6878126258Smlaier		}
6879130613Smlaier		if (uh.uh_dport == 0 ||
6880130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6881130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6882130613Smlaier			action = PF_DROP;
6883130613Smlaier			goto done;
6884130613Smlaier		}
6885130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6886126258Smlaier		if (action == PF_PASS) {
6887130613Smlaier#if NPFSYNC
6888130613Smlaier			pfsync_update_state(s);
6889145836Smlaier#endif /* NPFSYNC */
6890126258Smlaier			r = s->rule.ptr;
6891130613Smlaier			a = s->anchor.ptr;
6892126258Smlaier			log = s->log;
6893126258Smlaier		} else if (s == NULL)
6894135920Smlaier#ifdef __FreeBSD__
6895130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6896145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6897135920Smlaier#else
6898135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6899145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6900135920Smlaier#endif
6901126258Smlaier		break;
6902126258Smlaier	}
6903126258Smlaier
6904126258Smlaier	case IPPROTO_ICMPV6: {
6905126258Smlaier		struct icmp6_hdr	ih;
6906126258Smlaier
6907126258Smlaier		pd.hdr.icmp6 = &ih;
6908126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
6909126258Smlaier		    &action, &reason, AF_INET6)) {
6910126258Smlaier			log = action != PF_PASS;
6911126258Smlaier			goto done;
6912126258Smlaier		}
6913126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6914145836Smlaier		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6915138387Sdhartmei		    IPPROTO_ICMPV6, AF_INET6)) {
6916126258Smlaier			action = PF_DROP;
6917145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6918126258Smlaier			goto done;
6919126258Smlaier		}
6920130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
6921145836Smlaier		    m, off, h, &pd, &reason);
6922126258Smlaier		if (action == PF_PASS) {
6923130613Smlaier#if NPFSYNC
6924130613Smlaier			pfsync_update_state(s);
6925145836Smlaier#endif /* NPFSYNC */
6926126258Smlaier			r = s->rule.ptr;
6927130613Smlaier			a = s->anchor.ptr;
6928126258Smlaier			log = s->log;
6929126258Smlaier		} else if (s == NULL)
6930145836Smlaier#ifdef __FreeBSD__
6931130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6932145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6933145836Smlaier#else
6934145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6935145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6936145836Smlaier#endif
6937126258Smlaier		break;
6938126258Smlaier	}
6939126258Smlaier
6940126258Smlaier	default:
6941130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6942130613Smlaier		if (action == PF_PASS) {
6943145836Smlaier#if NPFSYNC
6944145836Smlaier			pfsync_update_state(s);
6945145836Smlaier#endif /* NPFSYNC */
6946130613Smlaier			r = s->rule.ptr;
6947130613Smlaier			a = s->anchor.ptr;
6948130613Smlaier			log = s->log;
6949130613Smlaier		} else if (s == NULL)
6950145836Smlaier#ifdef __FreeBSD__
6951130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6952145836Smlaier			    &pd, &a, &ruleset, NULL);
6953145836Smlaier#else
6954145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6955145836Smlaier			    &pd, &a, &ruleset, &ip6intrq);
6956145836Smlaier#endif
6957126258Smlaier		break;
6958126258Smlaier	}
6959126258Smlaier
6960126258Smlaierdone:
6961126258Smlaier	/* XXX handle IPv6 options, if not allowed. not implemented. */
6962126258Smlaier
6963145836Smlaier	if (s && s->tag)
6964145836Smlaier		pf_tag_packet(m, pf_get_tag(m), s->tag);
6965145836Smlaier
6966126258Smlaier#ifdef ALTQ
6967126258Smlaier	if (action == PF_PASS && r->qid) {
6968126258Smlaier		struct m_tag	*mtag;
6969126258Smlaier		struct altq_tag	*atag;
6970126258Smlaier
6971126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
6972126258Smlaier		if (mtag != NULL) {
6973126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
6974126258Smlaier			if (pd.tos == IPTOS_LOWDELAY)
6975126258Smlaier				atag->qid = r->pqid;
6976126258Smlaier			else
6977126258Smlaier				atag->qid = r->qid;
6978126258Smlaier			/* add hints for ecn */
6979126258Smlaier			atag->af = AF_INET6;
6980126258Smlaier			atag->hdr = h;
6981126258Smlaier			m_tag_prepend(m, mtag);
6982126258Smlaier		}
6983126258Smlaier	}
6984145836Smlaier#endif /* ALTQ */
6985126258Smlaier
6986130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
6987130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
6988130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
6989130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
6990130613Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) &&
6991130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
6992130613Smlaier		action = PF_DROP;
6993130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
6994130613Smlaier	}
6995130613Smlaier
6996126258Smlaier	if (log)
6997130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset);
6998126258Smlaier
6999130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7000130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
7001130613Smlaier
7002130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7003130613Smlaier		r->packets++;
7004130613Smlaier		r->bytes += pd.tot_len;
7005130613Smlaier		if (a != NULL) {
7006130613Smlaier			a->packets++;
7007130613Smlaier			a->bytes += pd.tot_len;
7008130613Smlaier		}
7009130613Smlaier		if (s != NULL) {
7010130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7011130613Smlaier			s->packets[dirndx]++;
7012130613Smlaier			s->bytes[dirndx] += pd.tot_len;
7013130613Smlaier			if (s->nat_rule.ptr != NULL) {
7014130613Smlaier				s->nat_rule.ptr->packets++;
7015130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
7016130613Smlaier			}
7017130613Smlaier			if (s->src_node != NULL) {
7018130613Smlaier				s->src_node->packets++;
7019130613Smlaier				s->src_node->bytes += pd.tot_len;
7020130613Smlaier			}
7021130613Smlaier			if (s->nat_src_node != NULL) {
7022130613Smlaier				s->nat_src_node->packets++;
7023130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
7024130613Smlaier			}
7025130613Smlaier		}
7026130613Smlaier		tr = r;
7027130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7028130613Smlaier		if (nr != NULL) {
7029130613Smlaier			struct pf_addr *x;
7030130613Smlaier			/*
7031130613Smlaier			 * XXX: we need to make sure that the addresses
7032130613Smlaier			 * passed to pfr_update_stats() are the same than
7033130613Smlaier			 * the addresses used during matching (pfr_match)
7034130613Smlaier			 */
7035130613Smlaier			if (r == &pf_default_rule) {
7036130613Smlaier				tr = nr;
7037130613Smlaier				x = (s == NULL || s->direction == dir) ?
7038130613Smlaier				    &pd.baddr : &pd.naddr;
7039130613Smlaier			} else {
7040130613Smlaier				x = (s == NULL || s->direction == dir) ?
7041130613Smlaier				    &pd.naddr : &pd.baddr;
7042130613Smlaier			}
7043130613Smlaier			if (x == &pd.baddr || s == NULL) {
7044130613Smlaier				if (dir == PF_OUT)
7045130613Smlaier					pd.src = x;
7046130613Smlaier				else
7047130613Smlaier					pd.dst = x;
7048130613Smlaier			}
7049130613Smlaier		}
7050130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7051130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7052130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7053130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7054145836Smlaier			    tr->src.neg);
7055130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7056130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7057130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7058130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7059145836Smlaier			    tr->dst.neg);
7060130613Smlaier	}
7061130613Smlaier
7062130613Smlaier
7063126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7064126258Smlaier		m_freem(*m0);
7065126258Smlaier		*m0 = NULL;
7066126258Smlaier		action = PF_PASS;
7067126258Smlaier	} else if (r->rt)
7068126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
7069126258Smlaier		pf_route6(m0, r, dir, ifp, s);
7070126258Smlaier
7071127145Smlaier#ifdef __FreeBSD__
7072126261Smlaier	PF_UNLOCK();
7073126261Smlaier#endif
7074126258Smlaier	return (action);
7075126258Smlaier}
7076126258Smlaier#endif /* INET6 */
7077145836Smlaier
7078145836Smlaierint
7079145836Smlaierpf_check_congestion(struct ifqueue *ifq)
7080145836Smlaier{
7081145836Smlaier#ifdef __FreeBSD__
7082145836Smlaier	/* XXX_IMPORT: later */
7083145836Smlaier	return (0);
7084145836Smlaier#else
7085145836Smlaier	if (ifq->ifq_congestion)
7086145836Smlaier		return (1);
7087145836Smlaier	else
7088145836Smlaier		return (0);
7089145836Smlaier#endif
7090145836Smlaier}
7091