pf.c revision 163606
1126261Smlaier/*	$FreeBSD: head/sys/contrib/pf/net/pf.c 163606 2006-10-22 11:52:19Z rwatson $	*/
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__
45162238Scsjp#include "opt_mac.h"
46126261Smlaier#include "opt_bpf.h"
47126261Smlaier#include "opt_pf.h"
48153110Sru
49153110Sru#ifdef DEV_BPF
50127145Smlaier#define	NBPFILTER	DEV_BPF
51153110Sru#else
52153110Sru#define	NBPFILTER	0
53153110Sru#endif
54153110Sru
55153110Sru#ifdef DEV_PFLOG
56127145Smlaier#define	NPFLOG		DEV_PFLOG
57153110Sru#else
58153110Sru#define	NPFLOG		0
59153110Sru#endif
60153110Sru
61153110Sru#ifdef DEV_PFSYNC
62127145Smlaier#define	NPFSYNC		DEV_PFSYNC
63126261Smlaier#else
64153110Sru#define	NPFSYNC		0
65153110Sru#endif
66153110Sru
67153110Sru#else
68126258Smlaier#include "bpfilter.h"
69126258Smlaier#include "pflog.h"
70126258Smlaier#include "pfsync.h"
71126261Smlaier#endif
72126258Smlaier
73126258Smlaier#include <sys/param.h>
74126258Smlaier#include <sys/systm.h>
75126258Smlaier#include <sys/mbuf.h>
76126258Smlaier#include <sys/filio.h>
77126258Smlaier#include <sys/socket.h>
78126258Smlaier#include <sys/socketvar.h>
79126258Smlaier#include <sys/kernel.h>
80126258Smlaier#include <sys/time.h>
81127145Smlaier#ifdef __FreeBSD__
82126261Smlaier#include <sys/sysctl.h>
83130613Smlaier#include <sys/endian.h>
84126261Smlaier#else
85126258Smlaier#include <sys/pool.h>
86126261Smlaier#endif
87126258Smlaier
88126258Smlaier#include <net/if.h>
89126258Smlaier#include <net/if_types.h>
90126258Smlaier#include <net/bpf.h>
91126258Smlaier#include <net/route.h>
92126258Smlaier
93126258Smlaier#include <netinet/in.h>
94126258Smlaier#include <netinet/in_var.h>
95126258Smlaier#include <netinet/in_systm.h>
96126258Smlaier#include <netinet/ip.h>
97126258Smlaier#include <netinet/ip_var.h>
98126258Smlaier#include <netinet/tcp.h>
99126258Smlaier#include <netinet/tcp_seq.h>
100126258Smlaier#include <netinet/udp.h>
101126258Smlaier#include <netinet/ip_icmp.h>
102126258Smlaier#include <netinet/in_pcb.h>
103126258Smlaier#include <netinet/tcp_timer.h>
104126258Smlaier#include <netinet/tcp_var.h>
105126258Smlaier#include <netinet/udp_var.h>
106126258Smlaier#include <netinet/icmp_var.h>
107145836Smlaier#include <netinet/if_ether.h>
108126258Smlaier
109127145Smlaier#ifndef __FreeBSD__
110126258Smlaier#include <dev/rndvar.h>
111126261Smlaier#endif
112126258Smlaier#include <net/pfvar.h>
113126258Smlaier#include <net/if_pflog.h>
114130613Smlaier
115130613Smlaier#if NPFSYNC > 0
116126258Smlaier#include <net/if_pfsync.h>
117130613Smlaier#endif /* NPFSYNC > 0 */
118126258Smlaier
119126258Smlaier#ifdef INET6
120126258Smlaier#include <netinet/ip6.h>
121126258Smlaier#include <netinet/in_pcb.h>
122126258Smlaier#include <netinet/icmp6.h>
123126258Smlaier#include <netinet6/nd6.h>
124127145Smlaier#ifdef __FreeBSD__
125126261Smlaier#include <netinet6/ip6_var.h>
126126261Smlaier#include <netinet6/in6_pcb.h>
127126261Smlaier#endif
128126258Smlaier#endif /* INET6 */
129126258Smlaier
130127145Smlaier#ifdef __FreeBSD__
131126261Smlaier#include <machine/in_cksum.h>
132126261Smlaier#include <sys/limits.h>
133126261Smlaier#include <sys/ucred.h>
134163606Srwatson#include <security/mac/mac_framework.h>
135126258Smlaier
136126261Smlaierextern int ip_optcopy(struct ip *, struct ip *);
137126261Smlaier#endif
138126261Smlaier
139126258Smlaier#define DPFPRINTF(n, x)	if (pf_status.debug >= (n)) printf x
140126258Smlaier
141126258Smlaier/*
142126258Smlaier * Global variables
143126258Smlaier */
144126258Smlaier
145145836Smlaierstruct pf_anchor_global	 pf_anchors;
146126258Smlaierstruct pf_ruleset	 pf_main_ruleset;
147126258Smlaierstruct pf_altqqueue	 pf_altqs[2];
148126258Smlaierstruct pf_palist	 pf_pabuf;
149126258Smlaierstruct pf_altqqueue	*pf_altqs_active;
150126258Smlaierstruct pf_altqqueue	*pf_altqs_inactive;
151126258Smlaierstruct pf_status	 pf_status;
152126258Smlaier
153126258Smlaieru_int32_t		 ticket_altqs_active;
154126258Smlaieru_int32_t		 ticket_altqs_inactive;
155130613Smlaierint			 altqs_inactive_open;
156126258Smlaieru_int32_t		 ticket_pabuf;
157126258Smlaier
158127145Smlaier#ifdef __FreeBSD__
159126261Smlaierstruct callout	 	 pf_expire_to;			/* expire timeout */
160126261Smlaier#else
161126258Smlaierstruct timeout		 pf_expire_to;			/* expire timeout */
162126261Smlaier#endif
163126258Smlaier
164145836Smlaierstruct pf_anchor_stackframe {
165145836Smlaier	struct pf_ruleset			*rs;
166145836Smlaier	struct pf_rule				*r;
167145836Smlaier	struct pf_anchor_node			*parent;
168145836Smlaier	struct pf_anchor			*child;
169145836Smlaier} pf_anchor_stack[64];
170126261Smlaier
171127145Smlaier#ifdef __FreeBSD__
172130613Smlaieruma_zone_t		 pf_src_tree_pl, pf_rule_pl;
173126261Smlaieruma_zone_t		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
174126261Smlaier#else
175130613Smlaierstruct pool		 pf_src_tree_pl, pf_rule_pl;
176126258Smlaierstruct pool		 pf_state_pl, pf_altq_pl, pf_pooladdr_pl;
177126261Smlaier#endif
178126258Smlaier
179126258Smlaiervoid			 pf_print_host(struct pf_addr *, u_int16_t, u_int8_t);
180126258Smlaier
181145836Smlaiervoid			 pf_init_threshold(struct pf_threshold *, u_int32_t,
182145836Smlaier			    u_int32_t);
183145836Smlaiervoid			 pf_add_threshold(struct pf_threshold *);
184145836Smlaierint			 pf_check_threshold(struct pf_threshold *);
185145836Smlaier
186126258Smlaiervoid			 pf_change_ap(struct pf_addr *, u_int16_t *,
187126258Smlaier			    u_int16_t *, u_int16_t *, struct pf_addr *,
188126258Smlaier			    u_int16_t, u_int8_t, sa_family_t);
189126258Smlaier#ifdef INET6
190126258Smlaiervoid			 pf_change_a6(struct pf_addr *, u_int16_t *,
191126258Smlaier			    struct pf_addr *, u_int8_t);
192126258Smlaier#endif /* INET6 */
193126258Smlaiervoid			 pf_change_icmp(struct pf_addr *, u_int16_t *,
194126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
195126258Smlaier			    u_int16_t *, u_int16_t *, u_int16_t *,
196126258Smlaier			    u_int16_t *, u_int8_t, sa_family_t);
197162238Scsjp#ifdef __FreeBSD__
198162238Scsjpvoid			 pf_send_tcp(struct mbuf *,
199162238Scsjp			    const struct pf_rule *, sa_family_t,
200162238Scsjp#else
201126258Smlaiervoid			 pf_send_tcp(const struct pf_rule *, sa_family_t,
202162238Scsjp#endif
203126258Smlaier			    const struct pf_addr *, const struct pf_addr *,
204126258Smlaier			    u_int16_t, u_int16_t, u_int32_t, u_int32_t,
205145836Smlaier			    u_int8_t, u_int16_t, u_int16_t, u_int8_t, int,
206145836Smlaier			    struct ether_header *, struct ifnet *);
207126258Smlaiervoid			 pf_send_icmp(struct mbuf *, u_int8_t, u_int8_t,
208126258Smlaier			    sa_family_t, struct pf_rule *);
209126258Smlaierstruct pf_rule		*pf_match_translation(struct pf_pdesc *, struct mbuf *,
210130613Smlaier			    int, int, struct pfi_kif *,
211126258Smlaier			    struct pf_addr *, u_int16_t, struct pf_addr *,
212126258Smlaier			    u_int16_t, int);
213126258Smlaierstruct pf_rule		*pf_get_translation(struct pf_pdesc *, struct mbuf *,
214130613Smlaier			    int, int, struct pfi_kif *, struct pf_src_node **,
215126258Smlaier			    struct pf_addr *, u_int16_t,
216126258Smlaier			    struct pf_addr *, u_int16_t,
217126258Smlaier			    struct pf_addr *, u_int16_t *);
218126258Smlaierint			 pf_test_tcp(struct pf_rule **, struct pf_state **,
219130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
220126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
221135920Smlaier#ifdef __FreeBSD__
222145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
223145836Smlaier			    struct inpcb *);
224135920Smlaier#else
225145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
226135920Smlaier#endif
227126258Smlaierint			 pf_test_udp(struct pf_rule **, struct pf_state **,
228130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
229126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
230135920Smlaier#ifdef __FreeBSD__
231145836Smlaier			    struct pf_ruleset **, struct ifqueue *,
232145836Smlaier			    struct inpcb *);
233135920Smlaier#else
234145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
235135920Smlaier#endif
236126258Smlaierint			 pf_test_icmp(struct pf_rule **, struct pf_state **,
237130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int,
238126258Smlaier			    void *, struct pf_pdesc *, struct pf_rule **,
239145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
240126258Smlaierint			 pf_test_other(struct pf_rule **, struct pf_state **,
241130613Smlaier			    int, struct pfi_kif *, struct mbuf *, int, void *,
242126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
243145836Smlaier			    struct pf_ruleset **, struct ifqueue *);
244126258Smlaierint			 pf_test_fragment(struct pf_rule **, int,
245130613Smlaier			    struct pfi_kif *, struct mbuf *, void *,
246126258Smlaier			    struct pf_pdesc *, struct pf_rule **,
247126258Smlaier			    struct pf_ruleset **);
248126258Smlaierint			 pf_test_state_tcp(struct pf_state **, int,
249130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
250126258Smlaier			    void *, struct pf_pdesc *, u_short *);
251126258Smlaierint			 pf_test_state_udp(struct pf_state **, int,
252130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
253126258Smlaier			    void *, struct pf_pdesc *);
254126258Smlaierint			 pf_test_state_icmp(struct pf_state **, int,
255130613Smlaier			    struct pfi_kif *, struct mbuf *, int,
256145836Smlaier			    void *, struct pf_pdesc *, u_short *);
257126258Smlaierint			 pf_test_state_other(struct pf_state **, int,
258130613Smlaier			    struct pfi_kif *, struct pf_pdesc *);
259126258Smlaierstruct pf_tag		*pf_get_tag(struct mbuf *);
260126258Smlaierint			 pf_match_tag(struct mbuf *, struct pf_rule *,
261145836Smlaier			     struct pf_tag **, int *);
262126258Smlaiervoid			 pf_hash(struct pf_addr *, struct pf_addr *,
263126258Smlaier			    struct pf_poolhashkey *, sa_family_t);
264130613Smlaierint			 pf_map_addr(u_int8_t, struct pf_rule *,
265126258Smlaier			    struct pf_addr *, struct pf_addr *,
266130613Smlaier			    struct pf_addr *, struct pf_src_node **);
267130613Smlaierint			 pf_get_sport(sa_family_t, u_int8_t, struct pf_rule *,
268126258Smlaier			    struct pf_addr *, struct pf_addr *, u_int16_t,
269130613Smlaier			    struct pf_addr *, u_int16_t*, u_int16_t, u_int16_t,
270130613Smlaier			    struct pf_src_node **);
271126258Smlaiervoid			 pf_route(struct mbuf **, struct pf_rule *, int,
272126258Smlaier			    struct ifnet *, struct pf_state *);
273126258Smlaiervoid			 pf_route6(struct mbuf **, struct pf_rule *, int,
274126258Smlaier			    struct ifnet *, struct pf_state *);
275135920Smlaier#ifdef __FreeBSD__
276130613Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
277135920Smlaier			    int, struct pf_pdesc *, struct inpcb *);
278135920Smlaier#else
279135920Smlaierint			 pf_socket_lookup(uid_t *, gid_t *,
280126258Smlaier			    int, struct pf_pdesc *);
281135920Smlaier#endif
282126258Smlaieru_int8_t		 pf_get_wscale(struct mbuf *, int, u_int16_t,
283126258Smlaier			    sa_family_t);
284126258Smlaieru_int16_t		 pf_get_mss(struct mbuf *, int, u_int16_t,
285126258Smlaier			    sa_family_t);
286126258Smlaieru_int16_t		 pf_calc_mss(struct pf_addr *, sa_family_t,
287126258Smlaier				u_int16_t);
288126258Smlaiervoid			 pf_set_rt_ifp(struct pf_state *,
289126258Smlaier			    struct pf_addr *);
290126258Smlaierint			 pf_check_proto_cksum(struct mbuf *, int, int,
291126258Smlaier			    u_int8_t, sa_family_t);
292126258Smlaierint			 pf_addr_wrap_neq(struct pf_addr_wrap *,
293126258Smlaier			    struct pf_addr_wrap *);
294130613Smlaierstatic int		 pf_add_mbuf_tag(struct mbuf *, u_int);
295130613Smlaierstruct pf_state		*pf_find_state_recurse(struct pfi_kif *,
296130613Smlaier			    struct pf_state *, u_int8_t);
297145836Smlaierint			 pf_src_connlimit(struct pf_state **);
298145836Smlaierint			 pf_check_congestion(struct ifqueue *);
299126258Smlaier
300127145Smlaier#ifdef __FreeBSD__
301126261Smlaierint in4_cksum(struct mbuf *m, u_int8_t nxt, int off, int len);
302126258Smlaier
303126261Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX];
304145836Smlaier
305126261Smlaier#else
306130613Smlaierstruct pf_pool_limit pf_pool_limits[PF_LIMIT_MAX] = {
307130613Smlaier	{ &pf_state_pl, PFSTATE_HIWAT },
308130613Smlaier	{ &pf_src_tree_pl, PFSNODE_HIWAT },
309130613Smlaier	{ &pf_frent_pl, PFFRAG_FRENT_HIWAT }
310130613Smlaier};
311126261Smlaier#endif
312126258Smlaier
313126258Smlaier#define STATE_LOOKUP()							\
314126258Smlaier	do {								\
315126258Smlaier		if (direction == PF_IN)					\
316145836Smlaier			*state = pf_find_state_recurse(			\
317130613Smlaier			    kif, &key, PF_EXT_GWY);			\
318126258Smlaier		else							\
319145836Smlaier			*state = pf_find_state_recurse(			\
320130613Smlaier			    kif, &key, PF_LAN_EXT);			\
321145836Smlaier		if (*state == NULL || (*state)->timeout == PFTM_PURGE)	\
322126258Smlaier			return (PF_DROP);				\
323126258Smlaier		if (direction == PF_OUT &&				\
324126258Smlaier		    (((*state)->rule.ptr->rt == PF_ROUTETO &&		\
325126258Smlaier		    (*state)->rule.ptr->direction == PF_OUT) ||		\
326126258Smlaier		    ((*state)->rule.ptr->rt == PF_REPLYTO &&		\
327126258Smlaier		    (*state)->rule.ptr->direction == PF_IN)) &&		\
328130613Smlaier		    (*state)->rt_kif != NULL &&				\
329130613Smlaier		    (*state)->rt_kif != kif)				\
330126258Smlaier			return (PF_PASS);				\
331126258Smlaier	} while (0)
332126258Smlaier
333126258Smlaier#define	STATE_TRANSLATE(s) \
334126258Smlaier	(s)->lan.addr.addr32[0] != (s)->gwy.addr.addr32[0] || \
335126258Smlaier	((s)->af == AF_INET6 && \
336126258Smlaier	((s)->lan.addr.addr32[1] != (s)->gwy.addr.addr32[1] || \
337126258Smlaier	(s)->lan.addr.addr32[2] != (s)->gwy.addr.addr32[2] || \
338126258Smlaier	(s)->lan.addr.addr32[3] != (s)->gwy.addr.addr32[3])) || \
339126258Smlaier	(s)->lan.port != (s)->gwy.port
340126258Smlaier
341130613Smlaier#define BOUND_IFACE(r, k) (((r)->rule_flag & PFRULE_IFBOUND) ? (k) :   \
342130613Smlaier	((r)->rule_flag & PFRULE_GRBOUND) ? (k)->pfik_parent :	       \
343130613Smlaier	(k)->pfik_parent->pfik_parent)
344126258Smlaier
345145836Smlaier#define STATE_INC_COUNTERS(s)				\
346145836Smlaier	do {						\
347145836Smlaier		s->rule.ptr->states++;			\
348145836Smlaier		if (s->anchor.ptr != NULL)		\
349145836Smlaier			s->anchor.ptr->states++;	\
350145836Smlaier		if (s->nat_rule.ptr != NULL)		\
351145836Smlaier			s->nat_rule.ptr->states++;	\
352145836Smlaier	} while (0)
353145836Smlaier
354145836Smlaier#define STATE_DEC_COUNTERS(s)				\
355145836Smlaier	do {						\
356145836Smlaier		if (s->nat_rule.ptr != NULL)		\
357145836Smlaier			s->nat_rule.ptr->states--;	\
358145836Smlaier		if (s->anchor.ptr != NULL)		\
359145836Smlaier			s->anchor.ptr->states--;	\
360145836Smlaier		s->rule.ptr->states--;			\
361145836Smlaier	} while (0)
362145836Smlaier
363132767Skan#ifndef __FreeBSD__
364130613Smlaierstatic __inline int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
365130613Smlaierstatic __inline int pf_state_compare_lan_ext(struct pf_state *,
366130613Smlaier	struct pf_state *);
367130613Smlaierstatic __inline int pf_state_compare_ext_gwy(struct pf_state *,
368130613Smlaier	struct pf_state *);
369130613Smlaierstatic __inline int pf_state_compare_id(struct pf_state *,
370130613Smlaier	struct pf_state *);
371145836Smlaierstatic __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
372132767Skan#else
373132767Skanstatic int pf_src_compare(struct pf_src_node *, struct pf_src_node *);
374132767Skanstatic int pf_state_compare_lan_ext(struct pf_state *,
375132767Skan	struct pf_state *);
376132767Skanstatic int pf_state_compare_ext_gwy(struct pf_state *,
377132767Skan	struct pf_state *);
378132767Skanstatic int pf_state_compare_id(struct pf_state *,
379132767Skan	struct pf_state *);
380145836Smlaierstatic int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
381132767Skan#endif
382126258Smlaier
383130613Smlaierstruct pf_src_tree tree_src_tracking;
384130613Smlaier
385130613Smlaierstruct pf_state_tree_id tree_id;
386130613Smlaierstruct pf_state_queue state_updates;
387130613Smlaier
388130613SmlaierRB_GENERATE(pf_src_tree, pf_src_node, entry, pf_src_compare);
389130613SmlaierRB_GENERATE(pf_state_tree_lan_ext, pf_state,
390130613Smlaier    u.s.entry_lan_ext, pf_state_compare_lan_ext);
391130613SmlaierRB_GENERATE(pf_state_tree_ext_gwy, pf_state,
392130613Smlaier    u.s.entry_ext_gwy, pf_state_compare_ext_gwy);
393130613SmlaierRB_GENERATE(pf_state_tree_id, pf_state,
394130613Smlaier    u.s.entry_id, pf_state_compare_id);
395145836SmlaierRB_GENERATE(pf_anchor_global, pf_anchor, entry_global, pf_anchor_compare);
396145836SmlaierRB_GENERATE(pf_anchor_node, pf_anchor, entry_node, pf_anchor_compare);
397130613Smlaier
398127145Smlaier#ifdef __FreeBSD__
399126409Smlaierstatic int
400126409Smlaier#else
401126258Smlaierstatic __inline int
402126409Smlaier#endif
403130613Smlaierpf_src_compare(struct pf_src_node *a, struct pf_src_node *b)
404126258Smlaier{
405126258Smlaier	int	diff;
406126258Smlaier
407130613Smlaier	if (a->rule.ptr > b->rule.ptr)
408130613Smlaier		return (1);
409130613Smlaier	if (a->rule.ptr < b->rule.ptr)
410130613Smlaier		return (-1);
411130613Smlaier	if ((diff = a->af - b->af) != 0)
412130613Smlaier		return (diff);
413130613Smlaier	switch (a->af) {
414130613Smlaier#ifdef INET
415130613Smlaier	case AF_INET:
416130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
417130613Smlaier			return (1);
418130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
419130613Smlaier			return (-1);
420130613Smlaier		break;
421130613Smlaier#endif /* INET */
422130613Smlaier#ifdef INET6
423130613Smlaier	case AF_INET6:
424130613Smlaier		if (a->addr.addr32[3] > b->addr.addr32[3])
425130613Smlaier			return (1);
426130613Smlaier		if (a->addr.addr32[3] < b->addr.addr32[3])
427130613Smlaier			return (-1);
428130613Smlaier		if (a->addr.addr32[2] > b->addr.addr32[2])
429130613Smlaier			return (1);
430130613Smlaier		if (a->addr.addr32[2] < b->addr.addr32[2])
431130613Smlaier			return (-1);
432130613Smlaier		if (a->addr.addr32[1] > b->addr.addr32[1])
433130613Smlaier			return (1);
434130613Smlaier		if (a->addr.addr32[1] < b->addr.addr32[1])
435130613Smlaier			return (-1);
436130613Smlaier		if (a->addr.addr32[0] > b->addr.addr32[0])
437130613Smlaier			return (1);
438130613Smlaier		if (a->addr.addr32[0] < b->addr.addr32[0])
439130613Smlaier			return (-1);
440130613Smlaier		break;
441130613Smlaier#endif /* INET6 */
442130613Smlaier	}
443130613Smlaier	return (0);
444130613Smlaier}
445130613Smlaier
446130613Smlaier#ifdef __FreeBSD__
447130613Smlaierstatic int
448130613Smlaier#else
449130613Smlaierstatic __inline int
450130613Smlaier#endif
451130613Smlaierpf_state_compare_lan_ext(struct pf_state *a, struct pf_state *b)
452130613Smlaier{
453130613Smlaier	int	diff;
454130613Smlaier
455126258Smlaier	if ((diff = a->proto - b->proto) != 0)
456126258Smlaier		return (diff);
457126258Smlaier	if ((diff = a->af - b->af) != 0)
458126258Smlaier		return (diff);
459126258Smlaier	switch (a->af) {
460126258Smlaier#ifdef INET
461126258Smlaier	case AF_INET:
462130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
463126258Smlaier			return (1);
464130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
465126258Smlaier			return (-1);
466130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
467126258Smlaier			return (1);
468130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
469126258Smlaier			return (-1);
470126258Smlaier		break;
471126258Smlaier#endif /* INET */
472126258Smlaier#ifdef INET6
473126258Smlaier	case AF_INET6:
474130613Smlaier		if (a->lan.addr.addr32[3] > b->lan.addr.addr32[3])
475126258Smlaier			return (1);
476130613Smlaier		if (a->lan.addr.addr32[3] < b->lan.addr.addr32[3])
477126258Smlaier			return (-1);
478130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
479126258Smlaier			return (1);
480130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
481126258Smlaier			return (-1);
482130613Smlaier		if (a->lan.addr.addr32[2] > b->lan.addr.addr32[2])
483126258Smlaier			return (1);
484130613Smlaier		if (a->lan.addr.addr32[2] < b->lan.addr.addr32[2])
485126258Smlaier			return (-1);
486130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
487126258Smlaier			return (1);
488130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
489126258Smlaier			return (-1);
490130613Smlaier		if (a->lan.addr.addr32[1] > b->lan.addr.addr32[1])
491126258Smlaier			return (1);
492130613Smlaier		if (a->lan.addr.addr32[1] < b->lan.addr.addr32[1])
493126258Smlaier			return (-1);
494130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
495126258Smlaier			return (1);
496130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
497126258Smlaier			return (-1);
498130613Smlaier		if (a->lan.addr.addr32[0] > b->lan.addr.addr32[0])
499126258Smlaier			return (1);
500130613Smlaier		if (a->lan.addr.addr32[0] < b->lan.addr.addr32[0])
501126258Smlaier			return (-1);
502130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
503126258Smlaier			return (1);
504130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
505126258Smlaier			return (-1);
506126258Smlaier		break;
507126258Smlaier#endif /* INET6 */
508126258Smlaier	}
509126258Smlaier
510130613Smlaier	if ((diff = a->lan.port - b->lan.port) != 0)
511126258Smlaier		return (diff);
512130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
513126258Smlaier		return (diff);
514126258Smlaier
515126258Smlaier	return (0);
516126258Smlaier}
517126258Smlaier
518130613Smlaier#ifdef __FreeBSD__
519130613Smlaierstatic int
520130613Smlaier#else
521130613Smlaierstatic __inline int
522130613Smlaier#endif
523130613Smlaierpf_state_compare_ext_gwy(struct pf_state *a, struct pf_state *b)
524130613Smlaier{
525130613Smlaier	int	diff;
526130613Smlaier
527130613Smlaier	if ((diff = a->proto - b->proto) != 0)
528130613Smlaier		return (diff);
529130613Smlaier	if ((diff = a->af - b->af) != 0)
530130613Smlaier		return (diff);
531130613Smlaier	switch (a->af) {
532130613Smlaier#ifdef INET
533130613Smlaier	case AF_INET:
534130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
535130613Smlaier			return (1);
536130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
537130613Smlaier			return (-1);
538130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
539130613Smlaier			return (1);
540130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
541130613Smlaier			return (-1);
542130613Smlaier		break;
543130613Smlaier#endif /* INET */
544126258Smlaier#ifdef INET6
545130613Smlaier	case AF_INET6:
546130613Smlaier		if (a->ext.addr.addr32[3] > b->ext.addr.addr32[3])
547130613Smlaier			return (1);
548130613Smlaier		if (a->ext.addr.addr32[3] < b->ext.addr.addr32[3])
549130613Smlaier			return (-1);
550130613Smlaier		if (a->gwy.addr.addr32[3] > b->gwy.addr.addr32[3])
551130613Smlaier			return (1);
552130613Smlaier		if (a->gwy.addr.addr32[3] < b->gwy.addr.addr32[3])
553130613Smlaier			return (-1);
554130613Smlaier		if (a->ext.addr.addr32[2] > b->ext.addr.addr32[2])
555130613Smlaier			return (1);
556130613Smlaier		if (a->ext.addr.addr32[2] < b->ext.addr.addr32[2])
557130613Smlaier			return (-1);
558130613Smlaier		if (a->gwy.addr.addr32[2] > b->gwy.addr.addr32[2])
559130613Smlaier			return (1);
560130613Smlaier		if (a->gwy.addr.addr32[2] < b->gwy.addr.addr32[2])
561130613Smlaier			return (-1);
562130613Smlaier		if (a->ext.addr.addr32[1] > b->ext.addr.addr32[1])
563130613Smlaier			return (1);
564130613Smlaier		if (a->ext.addr.addr32[1] < b->ext.addr.addr32[1])
565130613Smlaier			return (-1);
566130613Smlaier		if (a->gwy.addr.addr32[1] > b->gwy.addr.addr32[1])
567130613Smlaier			return (1);
568130613Smlaier		if (a->gwy.addr.addr32[1] < b->gwy.addr.addr32[1])
569130613Smlaier			return (-1);
570130613Smlaier		if (a->ext.addr.addr32[0] > b->ext.addr.addr32[0])
571130613Smlaier			return (1);
572130613Smlaier		if (a->ext.addr.addr32[0] < b->ext.addr.addr32[0])
573130613Smlaier			return (-1);
574130613Smlaier		if (a->gwy.addr.addr32[0] > b->gwy.addr.addr32[0])
575130613Smlaier			return (1);
576130613Smlaier		if (a->gwy.addr.addr32[0] < b->gwy.addr.addr32[0])
577130613Smlaier			return (-1);
578130613Smlaier		break;
579130613Smlaier#endif /* INET6 */
580130613Smlaier	}
581130613Smlaier
582130613Smlaier	if ((diff = a->ext.port - b->ext.port) != 0)
583130613Smlaier		return (diff);
584130613Smlaier	if ((diff = a->gwy.port - b->gwy.port) != 0)
585130613Smlaier		return (diff);
586130613Smlaier
587130613Smlaier	return (0);
588130613Smlaier}
589130613Smlaier
590130613Smlaier#ifdef __FreeBSD__
591130613Smlaierstatic int
592130613Smlaier#else
593130613Smlaierstatic __inline int
594130613Smlaier#endif
595130613Smlaierpf_state_compare_id(struct pf_state *a, struct pf_state *b)
596130613Smlaier{
597130613Smlaier	if (a->id > b->id)
598130613Smlaier		return (1);
599130613Smlaier	if (a->id < b->id)
600130613Smlaier		return (-1);
601130613Smlaier	if (a->creatorid > b->creatorid)
602130613Smlaier		return (1);
603130613Smlaier	if (a->creatorid < b->creatorid)
604130613Smlaier		return (-1);
605130613Smlaier
606130613Smlaier	return (0);
607130613Smlaier}
608130613Smlaier
609145836Smlaier#ifdef __FreeBSD__
610145836Smlaierstatic int
611145836Smlaier#else
612145836Smlaierstatic __inline int
613145836Smlaier#endif
614145836Smlaierpf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
615145836Smlaier{
616145836Smlaier	int c = strcmp(a->path, b->path);
617145836Smlaier
618145836Smlaier	return (c ? (c < 0 ? -1 : 1) : 0);
619145836Smlaier}
620145836Smlaier
621130613Smlaier#ifdef INET6
622126258Smlaiervoid
623126258Smlaierpf_addrcpy(struct pf_addr *dst, struct pf_addr *src, sa_family_t af)
624126258Smlaier{
625126258Smlaier	switch (af) {
626126258Smlaier#ifdef INET
627126258Smlaier	case AF_INET:
628126258Smlaier		dst->addr32[0] = src->addr32[0];
629126258Smlaier		break;
630126258Smlaier#endif /* INET */
631126258Smlaier	case AF_INET6:
632126258Smlaier		dst->addr32[0] = src->addr32[0];
633126258Smlaier		dst->addr32[1] = src->addr32[1];
634126258Smlaier		dst->addr32[2] = src->addr32[2];
635126258Smlaier		dst->addr32[3] = src->addr32[3];
636126258Smlaier		break;
637126258Smlaier	}
638126258Smlaier}
639145836Smlaier#endif /* INET6 */
640126258Smlaier
641126258Smlaierstruct pf_state *
642130613Smlaierpf_find_state_byid(struct pf_state *key)
643126258Smlaier{
644130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
645130613Smlaier	return (RB_FIND(pf_state_tree_id, &tree_id, key));
646130613Smlaier}
647126258Smlaier
648130613Smlaierstruct pf_state *
649130613Smlaierpf_find_state_recurse(struct pfi_kif *kif, struct pf_state *key, u_int8_t tree)
650130613Smlaier{
651130613Smlaier	struct pf_state *s;
652130613Smlaier
653126258Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
654130613Smlaier
655130613Smlaier	switch (tree) {
656130613Smlaier	case PF_LAN_EXT:
657130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
658130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
659130613Smlaier			    &kif->pfik_lan_ext, key);
660130613Smlaier			if (s != NULL)
661130613Smlaier				return (s);
662130613Smlaier		}
663126258Smlaier		return (NULL);
664130613Smlaier	case PF_EXT_GWY:
665130613Smlaier		for (; kif != NULL; kif = kif->pfik_parent) {
666130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
667130613Smlaier			    &kif->pfik_ext_gwy, key);
668130613Smlaier			if (s != NULL)
669130613Smlaier				return (s);
670130613Smlaier		}
671130613Smlaier		return (NULL);
672130613Smlaier	default:
673130613Smlaier		panic("pf_find_state_recurse");
674130613Smlaier	}
675126258Smlaier}
676126258Smlaier
677130613Smlaierstruct pf_state *
678130613Smlaierpf_find_state_all(struct pf_state *key, u_int8_t tree, int *more)
679130613Smlaier{
680130613Smlaier	struct pf_state *s, *ss = NULL;
681130613Smlaier	struct pfi_kif	*kif;
682130613Smlaier
683130613Smlaier	pf_status.fcounters[FCNT_STATE_SEARCH]++;
684130613Smlaier
685130613Smlaier	switch (tree) {
686130613Smlaier	case PF_LAN_EXT:
687130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
688130613Smlaier			s = RB_FIND(pf_state_tree_lan_ext,
689130613Smlaier			    &kif->pfik_lan_ext, key);
690130613Smlaier			if (s == NULL)
691130613Smlaier				continue;
692130613Smlaier			if (more == NULL)
693130613Smlaier				return (s);
694130613Smlaier			ss = s;
695130613Smlaier			(*more)++;
696130613Smlaier		}
697130613Smlaier		return (ss);
698130613Smlaier	case PF_EXT_GWY:
699130613Smlaier		TAILQ_FOREACH(kif, &pfi_statehead, pfik_w_states) {
700130613Smlaier			s = RB_FIND(pf_state_tree_ext_gwy,
701130613Smlaier			    &kif->pfik_ext_gwy, key);
702130613Smlaier			if (s == NULL)
703130613Smlaier				continue;
704130613Smlaier			if (more == NULL)
705130613Smlaier				return (s);
706130613Smlaier			ss = s;
707130613Smlaier			(*more)++;
708130613Smlaier		}
709130613Smlaier		return (ss);
710130613Smlaier	default:
711130613Smlaier		panic("pf_find_state_all");
712130613Smlaier	}
713130613Smlaier}
714130613Smlaier
715145836Smlaiervoid
716145836Smlaierpf_init_threshold(struct pf_threshold *threshold,
717145836Smlaier    u_int32_t limit, u_int32_t seconds)
718145836Smlaier{
719145836Smlaier	threshold->limit = limit * PF_THRESHOLD_MULT;
720145836Smlaier	threshold->seconds = seconds;
721145836Smlaier	threshold->count = 0;
722145836Smlaier	threshold->last = time_second;
723145836Smlaier}
724145836Smlaier
725145836Smlaiervoid
726145836Smlaierpf_add_threshold(struct pf_threshold *threshold)
727145836Smlaier{
728145836Smlaier	u_int32_t t = time_second, diff = t - threshold->last;
729145836Smlaier
730145836Smlaier	if (diff >= threshold->seconds)
731145836Smlaier		threshold->count = 0;
732145836Smlaier	else
733145836Smlaier		threshold->count -= threshold->count * diff /
734145836Smlaier		    threshold->seconds;
735145836Smlaier	threshold->count += PF_THRESHOLD_MULT;
736145836Smlaier	threshold->last = t;
737145836Smlaier}
738145836Smlaier
739126258Smlaierint
740145836Smlaierpf_check_threshold(struct pf_threshold *threshold)
741145836Smlaier{
742145836Smlaier	return (threshold->count > threshold->limit);
743145836Smlaier}
744145836Smlaier
745145836Smlaierint
746145836Smlaierpf_src_connlimit(struct pf_state **state)
747145836Smlaier{
748145836Smlaier	struct pf_state	*s;
749145836Smlaier	int bad = 0;
750145836Smlaier
751145836Smlaier	(*state)->src_node->conn++;
752153725Smlaier#ifdef __FreeBSD__
753153725Smlaier	(*state)->local_flags |= PFSTATE_SRC_CONN;
754153725Smlaier#endif
755145836Smlaier	pf_add_threshold(&(*state)->src_node->conn_rate);
756145836Smlaier
757145836Smlaier	if ((*state)->rule.ptr->max_src_conn &&
758145836Smlaier	    (*state)->rule.ptr->max_src_conn <
759145836Smlaier	    (*state)->src_node->conn) {
760145836Smlaier		pf_status.lcounters[LCNT_SRCCONN]++;
761145836Smlaier		bad++;
762145836Smlaier	}
763145836Smlaier
764145836Smlaier	if ((*state)->rule.ptr->max_src_conn_rate.limit &&
765145836Smlaier	    pf_check_threshold(&(*state)->src_node->conn_rate)) {
766145836Smlaier		pf_status.lcounters[LCNT_SRCCONNRATE]++;
767145836Smlaier		bad++;
768145836Smlaier	}
769145836Smlaier
770145836Smlaier	if (!bad)
771145836Smlaier		return (0);
772145836Smlaier
773145836Smlaier	if ((*state)->rule.ptr->overload_tbl) {
774145836Smlaier		struct pfr_addr p;
775145836Smlaier		u_int32_t	killed = 0;
776145836Smlaier
777145836Smlaier		pf_status.lcounters[LCNT_OVERLOAD_TABLE]++;
778145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
779145836Smlaier			printf("pf_src_connlimit: blocking address ");
780145836Smlaier			pf_print_host(&(*state)->src_node->addr, 0,
781145836Smlaier			    (*state)->af);
782145836Smlaier		}
783145836Smlaier
784145836Smlaier		bzero(&p, sizeof(p));
785145836Smlaier		p.pfra_af = (*state)->af;
786145836Smlaier		switch ((*state)->af) {
787145836Smlaier#ifdef INET
788145836Smlaier		case AF_INET:
789145836Smlaier			p.pfra_net = 32;
790145836Smlaier			p.pfra_ip4addr = (*state)->src_node->addr.v4;
791145836Smlaier			break;
792145836Smlaier#endif /* INET */
793145836Smlaier#ifdef INET6
794145836Smlaier		case AF_INET6:
795145836Smlaier			p.pfra_net = 128;
796145836Smlaier			p.pfra_ip6addr = (*state)->src_node->addr.v6;
797145836Smlaier			break;
798145836Smlaier#endif /* INET6 */
799145836Smlaier		}
800145836Smlaier
801145836Smlaier		pfr_insert_kentry((*state)->rule.ptr->overload_tbl,
802145836Smlaier		    &p, time_second);
803145836Smlaier
804145836Smlaier		/* kill existing states if that's required. */
805145836Smlaier		if ((*state)->rule.ptr->flush) {
806145836Smlaier			pf_status.lcounters[LCNT_OVERLOAD_FLUSH]++;
807145836Smlaier
808145836Smlaier			RB_FOREACH(s, pf_state_tree_id, &tree_id) {
809145836Smlaier				/*
810145836Smlaier				 * Kill states from this source.  (Only those
811145836Smlaier				 * from the same rule if PF_FLUSH_GLOBAL is not
812145836Smlaier				 * set)
813145836Smlaier				 */
814145836Smlaier				if (s->af == (*state)->af &&
815145836Smlaier				    (((*state)->direction == PF_OUT &&
816145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
817145836Smlaier				    &s->lan.addr, s->af)) ||
818145836Smlaier				    ((*state)->direction == PF_IN &&
819145836Smlaier				    PF_AEQ(&(*state)->src_node->addr,
820145836Smlaier				    &s->ext.addr, s->af))) &&
821145836Smlaier				    ((*state)->rule.ptr->flush &
822145836Smlaier				    PF_FLUSH_GLOBAL ||
823145836Smlaier				    (*state)->rule.ptr == s->rule.ptr)) {
824145836Smlaier					s->timeout = PFTM_PURGE;
825145836Smlaier					s->src.state = s->dst.state =
826145836Smlaier					    TCPS_CLOSED;
827145836Smlaier					killed++;
828145836Smlaier				}
829145836Smlaier			}
830145836Smlaier			if (pf_status.debug >= PF_DEBUG_MISC)
831145836Smlaier				printf(", %u states killed", killed);
832145836Smlaier		}
833145836Smlaier		if (pf_status.debug >= PF_DEBUG_MISC)
834145836Smlaier			printf("\n");
835145836Smlaier	}
836145836Smlaier
837145836Smlaier	/* kill this state */
838145836Smlaier	(*state)->timeout = PFTM_PURGE;
839145836Smlaier	(*state)->src.state = (*state)->dst.state = TCPS_CLOSED;
840145836Smlaier	return (1);
841145836Smlaier}
842145836Smlaier
843145836Smlaierint
844130613Smlaierpf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule,
845130613Smlaier    struct pf_addr *src, sa_family_t af)
846126258Smlaier{
847130613Smlaier	struct pf_src_node	k;
848126258Smlaier
849130613Smlaier	if (*sn == NULL) {
850130613Smlaier		k.af = af;
851130613Smlaier		PF_ACPY(&k.addr, src, af);
852130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
853130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
854130613Smlaier			k.rule.ptr = rule;
855130613Smlaier		else
856130613Smlaier			k.rule.ptr = NULL;
857130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
858130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
859130613Smlaier	}
860130613Smlaier	if (*sn == NULL) {
861130613Smlaier		if (!rule->max_src_nodes ||
862130613Smlaier		    rule->src_nodes < rule->max_src_nodes)
863130613Smlaier			(*sn) = pool_get(&pf_src_tree_pl, PR_NOWAIT);
864145836Smlaier		else
865145836Smlaier			pf_status.lcounters[LCNT_SRCNODES]++;
866130613Smlaier		if ((*sn) == NULL)
867130613Smlaier			return (-1);
868130613Smlaier		bzero(*sn, sizeof(struct pf_src_node));
869145836Smlaier
870145836Smlaier		pf_init_threshold(&(*sn)->conn_rate,
871145836Smlaier		    rule->max_src_conn_rate.limit,
872145836Smlaier		    rule->max_src_conn_rate.seconds);
873145836Smlaier
874130613Smlaier		(*sn)->af = af;
875130613Smlaier		if (rule->rule_flag & PFRULE_RULESRCTRACK ||
876130613Smlaier		    rule->rpool.opts & PF_POOL_STICKYADDR)
877130613Smlaier			(*sn)->rule.ptr = rule;
878130613Smlaier		else
879130613Smlaier			(*sn)->rule.ptr = NULL;
880130613Smlaier		PF_ACPY(&(*sn)->addr, src, af);
881130613Smlaier		if (RB_INSERT(pf_src_tree,
882130613Smlaier		    &tree_src_tracking, *sn) != NULL) {
883130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
884130613Smlaier				printf("pf: src_tree insert failed: ");
885130613Smlaier				pf_print_host(&(*sn)->addr, 0, af);
886130613Smlaier				printf("\n");
887130613Smlaier			}
888130613Smlaier			pool_put(&pf_src_tree_pl, *sn);
889130613Smlaier			return (-1);
890130613Smlaier		}
891130613Smlaier		(*sn)->creation = time_second;
892130613Smlaier		(*sn)->ruletype = rule->action;
893130613Smlaier		if ((*sn)->rule.ptr != NULL)
894130613Smlaier			(*sn)->rule.ptr->src_nodes++;
895130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_INSERT]++;
896130613Smlaier		pf_status.src_nodes++;
897130613Smlaier	} else {
898130613Smlaier		if (rule->max_src_states &&
899145836Smlaier		    (*sn)->states >= rule->max_src_states) {
900145836Smlaier			pf_status.lcounters[LCNT_SRCSTATES]++;
901130613Smlaier			return (-1);
902145836Smlaier		}
903130613Smlaier	}
904130613Smlaier	return (0);
905130613Smlaier}
906126258Smlaier
907130613Smlaierint
908130613Smlaierpf_insert_state(struct pfi_kif *kif, struct pf_state *state)
909130613Smlaier{
910126258Smlaier	/* Thou MUST NOT insert multiple duplicate keys */
911130613Smlaier	state->u.s.kif = kif;
912130613Smlaier	if (RB_INSERT(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state)) {
913126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
914126258Smlaier			printf("pf: state insert failed: tree_lan_ext");
915126258Smlaier			printf(" lan: ");
916126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
917126258Smlaier			    state->af);
918126258Smlaier			printf(" gwy: ");
919126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
920126258Smlaier			    state->af);
921126258Smlaier			printf(" ext: ");
922126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
923126258Smlaier			    state->af);
924130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
925130613Smlaier				printf(" (from sync)");
926126258Smlaier			printf("\n");
927126258Smlaier		}
928126258Smlaier		return (-1);
929126258Smlaier	}
930126258Smlaier
931130613Smlaier	if (RB_INSERT(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state)) {
932126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
933126258Smlaier			printf("pf: state insert failed: tree_ext_gwy");
934126258Smlaier			printf(" lan: ");
935126258Smlaier			pf_print_host(&state->lan.addr, state->lan.port,
936126258Smlaier			    state->af);
937126258Smlaier			printf(" gwy: ");
938126258Smlaier			pf_print_host(&state->gwy.addr, state->gwy.port,
939126258Smlaier			    state->af);
940126258Smlaier			printf(" ext: ");
941126258Smlaier			pf_print_host(&state->ext.addr, state->ext.port,
942126258Smlaier			    state->af);
943130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
944130613Smlaier				printf(" (from sync)");
945126258Smlaier			printf("\n");
946126258Smlaier		}
947130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
948126258Smlaier		return (-1);
949126258Smlaier	}
950126258Smlaier
951130613Smlaier	if (state->id == 0 && state->creatorid == 0) {
952130613Smlaier		state->id = htobe64(pf_status.stateid++);
953130613Smlaier		state->creatorid = pf_status.hostid;
954130613Smlaier	}
955130613Smlaier	if (RB_INSERT(pf_state_tree_id, &tree_id, state) != NULL) {
956130613Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
957130613Smlaier#ifdef __FreeBSD__
958130613Smlaier			printf("pf: state insert failed: "
959130613Smlaier			    "id: %016llx creatorid: %08x",
960130613Smlaier			    (long long)be64toh(state->id),
961130613Smlaier			    ntohl(state->creatorid));
962130613Smlaier#else
963130613Smlaier			printf("pf: state insert failed: "
964130613Smlaier			    "id: %016llx creatorid: %08x",
965130613Smlaier			    betoh64(state->id), ntohl(state->creatorid));
966130613Smlaier#endif
967130613Smlaier			if (state->sync_flags & PFSTATE_FROMSYNC)
968130613Smlaier				printf(" (from sync)");
969130613Smlaier			printf("\n");
970130613Smlaier		}
971130613Smlaier		RB_REMOVE(pf_state_tree_lan_ext, &kif->pfik_lan_ext, state);
972130613Smlaier		RB_REMOVE(pf_state_tree_ext_gwy, &kif->pfik_ext_gwy, state);
973130613Smlaier		return (-1);
974130613Smlaier	}
975130613Smlaier	TAILQ_INSERT_HEAD(&state_updates, state, u.s.entry_updates);
976130613Smlaier
977126258Smlaier	pf_status.fcounters[FCNT_STATE_INSERT]++;
978126258Smlaier	pf_status.states++;
979130613Smlaier	pfi_attach_state(kif);
980126258Smlaier#if NPFSYNC
981126258Smlaier	pfsync_insert_state(state);
982126258Smlaier#endif
983126258Smlaier	return (0);
984126258Smlaier}
985126258Smlaier
986126258Smlaiervoid
987126258Smlaierpf_purge_timeout(void *arg)
988126258Smlaier{
989127145Smlaier#ifdef __FreeBSD__
990126261Smlaier	struct callout  *to = arg;
991126261Smlaier#else
992126258Smlaier	struct timeout	*to = arg;
993126261Smlaier#endif
994126258Smlaier	int		 s;
995126258Smlaier
996127145Smlaier#ifdef __FreeBSD__
997126261Smlaier	PF_LOCK();
998126261Smlaier#endif
999126258Smlaier	s = splsoftnet();
1000126258Smlaier	pf_purge_expired_states();
1001126258Smlaier	pf_purge_expired_fragments();
1002130613Smlaier	pf_purge_expired_src_nodes();
1003126258Smlaier	splx(s);
1004127145Smlaier#ifdef __FreeBSD__
1005126261Smlaier	PF_UNLOCK();
1006126261Smlaier#endif
1007126258Smlaier
1008127145Smlaier#ifdef __FreeBSD__
1009126261Smlaier	callout_reset(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz,
1010126261Smlaier	    pf_purge_timeout, to);
1011126261Smlaier#else
1012126258Smlaier	timeout_add(to, pf_default_rule.timeout[PFTM_INTERVAL] * hz);
1013126261Smlaier#endif
1014126258Smlaier}
1015126258Smlaier
1016126258Smlaieru_int32_t
1017126258Smlaierpf_state_expires(const struct pf_state *state)
1018126258Smlaier{
1019126258Smlaier	u_int32_t	timeout;
1020126258Smlaier	u_int32_t	start;
1021126258Smlaier	u_int32_t	end;
1022126258Smlaier	u_int32_t	states;
1023126258Smlaier
1024126258Smlaier	/* handle all PFTM_* > PFTM_MAX here */
1025126258Smlaier	if (state->timeout == PFTM_PURGE)
1026126261Smlaier		return (time_second);
1027126258Smlaier	if (state->timeout == PFTM_UNTIL_PACKET)
1028126258Smlaier		return (0);
1029127145Smlaier#ifdef __FreeBSD__
1030126261Smlaier	KASSERT((state->timeout < PFTM_MAX),
1031126261Smlaier	    ("pf_state_expires: timeout > PFTM_MAX"));
1032126261Smlaier#else
1033126258Smlaier	KASSERT(state->timeout < PFTM_MAX);
1034126261Smlaier#endif
1035126258Smlaier	timeout = state->rule.ptr->timeout[state->timeout];
1036126258Smlaier	if (!timeout)
1037126258Smlaier		timeout = pf_default_rule.timeout[state->timeout];
1038126258Smlaier	start = state->rule.ptr->timeout[PFTM_ADAPTIVE_START];
1039126258Smlaier	if (start) {
1040126258Smlaier		end = state->rule.ptr->timeout[PFTM_ADAPTIVE_END];
1041126258Smlaier		states = state->rule.ptr->states;
1042126258Smlaier	} else {
1043126258Smlaier		start = pf_default_rule.timeout[PFTM_ADAPTIVE_START];
1044126258Smlaier		end = pf_default_rule.timeout[PFTM_ADAPTIVE_END];
1045126258Smlaier		states = pf_status.states;
1046126258Smlaier	}
1047126258Smlaier	if (end && states > start && start < end) {
1048126258Smlaier		if (states < end)
1049126258Smlaier			return (state->expire + timeout * (end - states) /
1050126258Smlaier			    (end - start));
1051126258Smlaier		else
1052126261Smlaier			return (time_second);
1053126258Smlaier	}
1054126258Smlaier	return (state->expire + timeout);
1055126258Smlaier}
1056126258Smlaier
1057126258Smlaiervoid
1058130613Smlaierpf_purge_expired_src_nodes(void)
1059126258Smlaier{
1060130613Smlaier	 struct pf_src_node		*cur, *next;
1061126258Smlaier
1062130613Smlaier	 for (cur = RB_MIN(pf_src_tree, &tree_src_tracking); cur; cur = next) {
1063130613Smlaier		 next = RB_NEXT(pf_src_tree, &tree_src_tracking, cur);
1064126258Smlaier
1065130613Smlaier		 if (cur->states <= 0 && cur->expire <= time_second) {
1066130613Smlaier			 if (cur->rule.ptr != NULL) {
1067130613Smlaier				 cur->rule.ptr->src_nodes--;
1068130613Smlaier				 if (cur->rule.ptr->states <= 0 &&
1069130613Smlaier				     cur->rule.ptr->max_src_nodes <= 0)
1070130613Smlaier					 pf_rm_rule(NULL, cur->rule.ptr);
1071130613Smlaier			 }
1072130613Smlaier			 RB_REMOVE(pf_src_tree, &tree_src_tracking, cur);
1073130613Smlaier			 pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
1074130613Smlaier			 pf_status.src_nodes--;
1075130613Smlaier			 pool_put(&pf_src_tree_pl, cur);
1076130613Smlaier		 }
1077130613Smlaier	 }
1078130613Smlaier}
1079126258Smlaier
1080130613Smlaiervoid
1081130613Smlaierpf_src_tree_remove_state(struct pf_state *s)
1082130613Smlaier{
1083130613Smlaier	u_int32_t timeout;
1084126258Smlaier
1085130613Smlaier	if (s->src_node != NULL) {
1086145836Smlaier		if (s->proto == IPPROTO_TCP) {
1087153725Smlaier#ifdef __FreeBSD__
1088153725Smlaier			if (s->local_flags & PFSTATE_SRC_CONN)
1089153725Smlaier#else
1090145836Smlaier			if (s->src.state == PF_TCPS_PROXY_DST ||
1091145836Smlaier			    s->timeout >= PFTM_TCP_ESTABLISHED)
1092153725Smlaier#endif
1093145836Smlaier				--s->src_node->conn;
1094145836Smlaier		}
1095130613Smlaier		if (--s->src_node->states <= 0) {
1096130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1097130613Smlaier			if (!timeout)
1098130613Smlaier				timeout =
1099130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1100130613Smlaier			s->src_node->expire = time_second + timeout;
1101130613Smlaier		}
1102130613Smlaier	}
1103130613Smlaier	if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) {
1104130613Smlaier		if (--s->nat_src_node->states <= 0) {
1105130613Smlaier			timeout = s->rule.ptr->timeout[PFTM_SRC_NODE];
1106130613Smlaier			if (!timeout)
1107130613Smlaier				timeout =
1108130613Smlaier				    pf_default_rule.timeout[PFTM_SRC_NODE];
1109130613Smlaier			s->nat_src_node->expire = time_second + timeout;
1110130613Smlaier		}
1111130613Smlaier	}
1112130613Smlaier	s->src_node = s->nat_src_node = NULL;
1113130613Smlaier}
1114126258Smlaier
1115130613Smlaiervoid
1116145836Smlaierpf_purge_expired_state(struct pf_state *cur)
1117145836Smlaier{
1118148196Smlaier#ifdef __FreeBSD__
1119153545Smlaier	if (cur->local_flags & PFSTATE_EXPIRING)
1120148196Smlaier		return;
1121153545Smlaier	cur->local_flags |= PFSTATE_EXPIRING;
1122148196Smlaier#endif
1123145836Smlaier	if (cur->src.state == PF_TCPS_PROXY_DST)
1124162238Scsjp#ifdef __FreeBSD__
1125162238Scsjp		pf_send_tcp(NULL, cur->rule.ptr, cur->af,
1126162238Scsjp#else
1127145836Smlaier		pf_send_tcp(cur->rule.ptr, cur->af,
1128162238Scsjp#endif
1129145836Smlaier		    &cur->ext.addr, &cur->lan.addr,
1130145836Smlaier		    cur->ext.port, cur->lan.port,
1131145836Smlaier		    cur->src.seqhi, cur->src.seqlo + 1,
1132145836Smlaier		    TH_RST|TH_ACK, 0, 0, 0, 1, NULL, NULL);
1133145836Smlaier	RB_REMOVE(pf_state_tree_ext_gwy,
1134145836Smlaier	    &cur->u.s.kif->pfik_ext_gwy, cur);
1135145836Smlaier	RB_REMOVE(pf_state_tree_lan_ext,
1136145836Smlaier	    &cur->u.s.kif->pfik_lan_ext, cur);
1137145836Smlaier	RB_REMOVE(pf_state_tree_id, &tree_id, cur);
1138145836Smlaier#if NPFSYNC
1139145836Smlaier	pfsync_delete_state(cur);
1140145836Smlaier#endif
1141145836Smlaier	pf_src_tree_remove_state(cur);
1142145836Smlaier	if (--cur->rule.ptr->states <= 0 &&
1143145836Smlaier	    cur->rule.ptr->src_nodes <= 0)
1144145836Smlaier		pf_rm_rule(NULL, cur->rule.ptr);
1145145836Smlaier	if (cur->nat_rule.ptr != NULL)
1146145836Smlaier		if (--cur->nat_rule.ptr->states <= 0 &&
1147145836Smlaier			cur->nat_rule.ptr->src_nodes <= 0)
1148145836Smlaier			pf_rm_rule(NULL, cur->nat_rule.ptr);
1149145836Smlaier	if (cur->anchor.ptr != NULL)
1150145836Smlaier		if (--cur->anchor.ptr->states <= 0)
1151145836Smlaier			pf_rm_rule(NULL, cur->anchor.ptr);
1152145836Smlaier	pf_normalize_tcp_cleanup(cur);
1153145836Smlaier	pfi_detach_state(cur->u.s.kif);
1154145836Smlaier	TAILQ_REMOVE(&state_updates, cur, u.s.entry_updates);
1155145836Smlaier	if (cur->tag)
1156145836Smlaier		pf_tag_unref(cur->tag);
1157145836Smlaier	pool_put(&pf_state_pl, cur);
1158145836Smlaier	pf_status.fcounters[FCNT_STATE_REMOVALS]++;
1159145836Smlaier	pf_status.states--;
1160145836Smlaier}
1161145836Smlaier
1162145836Smlaiervoid
1163130613Smlaierpf_purge_expired_states(void)
1164130613Smlaier{
1165130613Smlaier	struct pf_state		*cur, *next;
1166130613Smlaier
1167130613Smlaier	for (cur = RB_MIN(pf_state_tree_id, &tree_id);
1168130613Smlaier	    cur; cur = next) {
1169130613Smlaier		next = RB_NEXT(pf_state_tree_id, &tree_id, cur);
1170145836Smlaier		if (pf_state_expires(cur) <= time_second)
1171145836Smlaier			pf_purge_expired_state(cur);
1172126258Smlaier	}
1173126258Smlaier}
1174126258Smlaier
1175126258Smlaierint
1176126258Smlaierpf_tbladdr_setup(struct pf_ruleset *rs, struct pf_addr_wrap *aw)
1177126258Smlaier{
1178126258Smlaier	if (aw->type != PF_ADDR_TABLE)
1179126258Smlaier		return (0);
1180126258Smlaier	if ((aw->p.tbl = pfr_attach_table(rs, aw->v.tblname)) == NULL)
1181126258Smlaier		return (1);
1182126258Smlaier	return (0);
1183126258Smlaier}
1184126258Smlaier
1185126258Smlaiervoid
1186126258Smlaierpf_tbladdr_remove(struct pf_addr_wrap *aw)
1187126258Smlaier{
1188126258Smlaier	if (aw->type != PF_ADDR_TABLE || aw->p.tbl == NULL)
1189126258Smlaier		return;
1190126258Smlaier	pfr_detach_table(aw->p.tbl);
1191126258Smlaier	aw->p.tbl = NULL;
1192126258Smlaier}
1193126258Smlaier
1194126258Smlaiervoid
1195126258Smlaierpf_tbladdr_copyout(struct pf_addr_wrap *aw)
1196126258Smlaier{
1197126258Smlaier	struct pfr_ktable *kt = aw->p.tbl;
1198126258Smlaier
1199126258Smlaier	if (aw->type != PF_ADDR_TABLE || kt == NULL)
1200126258Smlaier		return;
1201126258Smlaier	if (!(kt->pfrkt_flags & PFR_TFLAG_ACTIVE) && kt->pfrkt_root != NULL)
1202126258Smlaier		kt = kt->pfrkt_root;
1203126258Smlaier	aw->p.tbl = NULL;
1204126258Smlaier	aw->p.tblcnt = (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) ?
1205126258Smlaier		kt->pfrkt_cnt : -1;
1206126258Smlaier}
1207126258Smlaier
1208126258Smlaiervoid
1209126258Smlaierpf_print_host(struct pf_addr *addr, u_int16_t p, sa_family_t af)
1210126258Smlaier{
1211126258Smlaier	switch (af) {
1212126258Smlaier#ifdef INET
1213126258Smlaier	case AF_INET: {
1214126258Smlaier		u_int32_t a = ntohl(addr->addr32[0]);
1215126258Smlaier		printf("%u.%u.%u.%u", (a>>24)&255, (a>>16)&255,
1216126258Smlaier		    (a>>8)&255, a&255);
1217126258Smlaier		if (p) {
1218126258Smlaier			p = ntohs(p);
1219126258Smlaier			printf(":%u", p);
1220126258Smlaier		}
1221126258Smlaier		break;
1222126258Smlaier	}
1223126258Smlaier#endif /* INET */
1224126258Smlaier#ifdef INET6
1225126258Smlaier	case AF_INET6: {
1226126258Smlaier		u_int16_t b;
1227126258Smlaier		u_int8_t i, curstart = 255, curend = 0,
1228126258Smlaier		    maxstart = 0, maxend = 0;
1229126258Smlaier		for (i = 0; i < 8; i++) {
1230126258Smlaier			if (!addr->addr16[i]) {
1231126258Smlaier				if (curstart == 255)
1232126258Smlaier					curstart = i;
1233126258Smlaier				else
1234126258Smlaier					curend = i;
1235126258Smlaier			} else {
1236126258Smlaier				if (curstart) {
1237126258Smlaier					if ((curend - curstart) >
1238126258Smlaier					    (maxend - maxstart)) {
1239126258Smlaier						maxstart = curstart;
1240126258Smlaier						maxend = curend;
1241126258Smlaier						curstart = 255;
1242126258Smlaier					}
1243126258Smlaier				}
1244126258Smlaier			}
1245126258Smlaier		}
1246126258Smlaier		for (i = 0; i < 8; i++) {
1247126258Smlaier			if (i >= maxstart && i <= maxend) {
1248126258Smlaier				if (maxend != 7) {
1249126258Smlaier					if (i == maxstart)
1250126258Smlaier						printf(":");
1251126258Smlaier				} else {
1252126258Smlaier					if (i == maxend)
1253126258Smlaier						printf(":");
1254126258Smlaier				}
1255126258Smlaier			} else {
1256126258Smlaier				b = ntohs(addr->addr16[i]);
1257126258Smlaier				printf("%x", b);
1258126258Smlaier				if (i < 7)
1259126258Smlaier					printf(":");
1260126258Smlaier			}
1261126258Smlaier		}
1262126258Smlaier		if (p) {
1263126258Smlaier			p = ntohs(p);
1264126258Smlaier			printf("[%u]", p);
1265126258Smlaier		}
1266126258Smlaier		break;
1267126258Smlaier	}
1268126258Smlaier#endif /* INET6 */
1269126258Smlaier	}
1270126258Smlaier}
1271126258Smlaier
1272126258Smlaiervoid
1273126258Smlaierpf_print_state(struct pf_state *s)
1274126258Smlaier{
1275126258Smlaier	switch (s->proto) {
1276126258Smlaier	case IPPROTO_TCP:
1277126258Smlaier		printf("TCP ");
1278126258Smlaier		break;
1279126258Smlaier	case IPPROTO_UDP:
1280126258Smlaier		printf("UDP ");
1281126258Smlaier		break;
1282126258Smlaier	case IPPROTO_ICMP:
1283126258Smlaier		printf("ICMP ");
1284126258Smlaier		break;
1285126258Smlaier	case IPPROTO_ICMPV6:
1286126258Smlaier		printf("ICMPV6 ");
1287126258Smlaier		break;
1288126258Smlaier	default:
1289126258Smlaier		printf("%u ", s->proto);
1290126258Smlaier		break;
1291126258Smlaier	}
1292126258Smlaier	pf_print_host(&s->lan.addr, s->lan.port, s->af);
1293126258Smlaier	printf(" ");
1294126258Smlaier	pf_print_host(&s->gwy.addr, s->gwy.port, s->af);
1295126258Smlaier	printf(" ");
1296126258Smlaier	pf_print_host(&s->ext.addr, s->ext.port, s->af);
1297126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->src.seqlo,
1298126258Smlaier	    s->src.seqhi, s->src.max_win, s->src.seqdiff);
1299126258Smlaier	if (s->src.wscale && s->dst.wscale)
1300126258Smlaier		printf(" wscale=%u", s->src.wscale & PF_WSCALE_MASK);
1301126258Smlaier	printf("]");
1302126258Smlaier	printf(" [lo=%u high=%u win=%u modulator=%u", s->dst.seqlo,
1303126258Smlaier	    s->dst.seqhi, s->dst.max_win, s->dst.seqdiff);
1304126258Smlaier	if (s->src.wscale && s->dst.wscale)
1305126258Smlaier		printf(" wscale=%u", s->dst.wscale & PF_WSCALE_MASK);
1306126258Smlaier	printf("]");
1307126258Smlaier	printf(" %u:%u", s->src.state, s->dst.state);
1308126258Smlaier}
1309126258Smlaier
1310126258Smlaiervoid
1311126258Smlaierpf_print_flags(u_int8_t f)
1312126258Smlaier{
1313126258Smlaier	if (f)
1314126258Smlaier		printf(" ");
1315126258Smlaier	if (f & TH_FIN)
1316126258Smlaier		printf("F");
1317126258Smlaier	if (f & TH_SYN)
1318126258Smlaier		printf("S");
1319126258Smlaier	if (f & TH_RST)
1320126258Smlaier		printf("R");
1321126258Smlaier	if (f & TH_PUSH)
1322126258Smlaier		printf("P");
1323126258Smlaier	if (f & TH_ACK)
1324126258Smlaier		printf("A");
1325126258Smlaier	if (f & TH_URG)
1326126258Smlaier		printf("U");
1327126258Smlaier	if (f & TH_ECE)
1328126258Smlaier		printf("E");
1329126258Smlaier	if (f & TH_CWR)
1330126258Smlaier		printf("W");
1331126258Smlaier}
1332126258Smlaier
1333126258Smlaier#define	PF_SET_SKIP_STEPS(i)					\
1334126258Smlaier	do {							\
1335126258Smlaier		while (head[i] != cur) {			\
1336126258Smlaier			head[i]->skip[i].ptr = cur;		\
1337126258Smlaier			head[i] = TAILQ_NEXT(head[i], entries);	\
1338126258Smlaier		}						\
1339126258Smlaier	} while (0)
1340126258Smlaier
1341126258Smlaiervoid
1342126258Smlaierpf_calc_skip_steps(struct pf_rulequeue *rules)
1343126258Smlaier{
1344126258Smlaier	struct pf_rule *cur, *prev, *head[PF_SKIP_COUNT];
1345126258Smlaier	int i;
1346126258Smlaier
1347126258Smlaier	cur = TAILQ_FIRST(rules);
1348126258Smlaier	prev = cur;
1349126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1350126258Smlaier		head[i] = cur;
1351126258Smlaier	while (cur != NULL) {
1352126258Smlaier
1353130613Smlaier		if (cur->kif != prev->kif || cur->ifnot != prev->ifnot)
1354126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_IFP);
1355126258Smlaier		if (cur->direction != prev->direction)
1356126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DIR);
1357126258Smlaier		if (cur->af != prev->af)
1358126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_AF);
1359126258Smlaier		if (cur->proto != prev->proto)
1360126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_PROTO);
1361145836Smlaier		if (cur->src.neg != prev->src.neg ||
1362126258Smlaier		    pf_addr_wrap_neq(&cur->src.addr, &prev->src.addr))
1363126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_ADDR);
1364126258Smlaier		if (cur->src.port[0] != prev->src.port[0] ||
1365126258Smlaier		    cur->src.port[1] != prev->src.port[1] ||
1366126258Smlaier		    cur->src.port_op != prev->src.port_op)
1367126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_SRC_PORT);
1368145836Smlaier		if (cur->dst.neg != prev->dst.neg ||
1369126258Smlaier		    pf_addr_wrap_neq(&cur->dst.addr, &prev->dst.addr))
1370126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_ADDR);
1371126258Smlaier		if (cur->dst.port[0] != prev->dst.port[0] ||
1372126258Smlaier		    cur->dst.port[1] != prev->dst.port[1] ||
1373126258Smlaier		    cur->dst.port_op != prev->dst.port_op)
1374126258Smlaier			PF_SET_SKIP_STEPS(PF_SKIP_DST_PORT);
1375126258Smlaier
1376126258Smlaier		prev = cur;
1377126258Smlaier		cur = TAILQ_NEXT(cur, entries);
1378126258Smlaier	}
1379126258Smlaier	for (i = 0; i < PF_SKIP_COUNT; ++i)
1380126258Smlaier		PF_SET_SKIP_STEPS(i);
1381126258Smlaier}
1382126258Smlaier
1383126258Smlaierint
1384126258Smlaierpf_addr_wrap_neq(struct pf_addr_wrap *aw1, struct pf_addr_wrap *aw2)
1385126258Smlaier{
1386126258Smlaier	if (aw1->type != aw2->type)
1387126258Smlaier		return (1);
1388126258Smlaier	switch (aw1->type) {
1389126258Smlaier	case PF_ADDR_ADDRMASK:
1390126258Smlaier		if (PF_ANEQ(&aw1->v.a.addr, &aw2->v.a.addr, 0))
1391126258Smlaier			return (1);
1392126258Smlaier		if (PF_ANEQ(&aw1->v.a.mask, &aw2->v.a.mask, 0))
1393126258Smlaier			return (1);
1394126258Smlaier		return (0);
1395126258Smlaier	case PF_ADDR_DYNIFTL:
1396130613Smlaier		return (aw1->p.dyn->pfid_kt != aw2->p.dyn->pfid_kt);
1397126258Smlaier	case PF_ADDR_NOROUTE:
1398126258Smlaier		return (0);
1399126258Smlaier	case PF_ADDR_TABLE:
1400126258Smlaier		return (aw1->p.tbl != aw2->p.tbl);
1401126258Smlaier	default:
1402126258Smlaier		printf("invalid address type: %d\n", aw1->type);
1403126258Smlaier		return (1);
1404126258Smlaier	}
1405126258Smlaier}
1406126258Smlaier
1407126258Smlaieru_int16_t
1408126258Smlaierpf_cksum_fixup(u_int16_t cksum, u_int16_t old, u_int16_t new, u_int8_t udp)
1409126258Smlaier{
1410126258Smlaier	u_int32_t	l;
1411126258Smlaier
1412126258Smlaier	if (udp && !cksum)
1413126258Smlaier		return (0x0000);
1414126258Smlaier	l = cksum + old - new;
1415126258Smlaier	l = (l >> 16) + (l & 65535);
1416126258Smlaier	l = l & 65535;
1417126258Smlaier	if (udp && !l)
1418126258Smlaier		return (0xFFFF);
1419126258Smlaier	return (l);
1420126258Smlaier}
1421126258Smlaier
1422126258Smlaiervoid
1423126258Smlaierpf_change_ap(struct pf_addr *a, u_int16_t *p, u_int16_t *ic, u_int16_t *pc,
1424126258Smlaier    struct pf_addr *an, u_int16_t pn, u_int8_t u, sa_family_t af)
1425126258Smlaier{
1426126258Smlaier	struct pf_addr	ao;
1427126258Smlaier	u_int16_t	po = *p;
1428126258Smlaier
1429126258Smlaier	PF_ACPY(&ao, a, af);
1430126258Smlaier	PF_ACPY(a, an, af);
1431126258Smlaier
1432126258Smlaier	*p = pn;
1433126258Smlaier
1434126258Smlaier	switch (af) {
1435126258Smlaier#ifdef INET
1436126258Smlaier	case AF_INET:
1437126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1438126258Smlaier		    ao.addr16[0], an->addr16[0], 0),
1439126258Smlaier		    ao.addr16[1], an->addr16[1], 0);
1440126258Smlaier		*p = pn;
1441126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1442126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1443126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1444126258Smlaier		    po, pn, u);
1445126258Smlaier		break;
1446126258Smlaier#endif /* INET */
1447126258Smlaier#ifdef INET6
1448126258Smlaier	case AF_INET6:
1449126258Smlaier		*pc = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1450126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1451126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(*pc,
1452126258Smlaier		    ao.addr16[0], an->addr16[0], u),
1453126258Smlaier		    ao.addr16[1], an->addr16[1], u),
1454126258Smlaier		    ao.addr16[2], an->addr16[2], u),
1455126258Smlaier		    ao.addr16[3], an->addr16[3], u),
1456126258Smlaier		    ao.addr16[4], an->addr16[4], u),
1457126258Smlaier		    ao.addr16[5], an->addr16[5], u),
1458126258Smlaier		    ao.addr16[6], an->addr16[6], u),
1459126258Smlaier		    ao.addr16[7], an->addr16[7], u),
1460126258Smlaier		    po, pn, u);
1461126258Smlaier		break;
1462126258Smlaier#endif /* INET6 */
1463126258Smlaier	}
1464126258Smlaier}
1465126258Smlaier
1466126258Smlaier
1467126258Smlaier/* Changes a u_int32_t.  Uses a void * so there are no align restrictions */
1468126258Smlaiervoid
1469126258Smlaierpf_change_a(void *a, u_int16_t *c, u_int32_t an, u_int8_t u)
1470126258Smlaier{
1471126258Smlaier	u_int32_t	ao;
1472126258Smlaier
1473126258Smlaier	memcpy(&ao, a, sizeof(ao));
1474126258Smlaier	memcpy(a, &an, sizeof(u_int32_t));
1475126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(*c, ao / 65536, an / 65536, u),
1476126258Smlaier	    ao % 65536, an % 65536, u);
1477126258Smlaier}
1478126258Smlaier
1479126258Smlaier#ifdef INET6
1480126258Smlaiervoid
1481126258Smlaierpf_change_a6(struct pf_addr *a, u_int16_t *c, struct pf_addr *an, u_int8_t u)
1482126258Smlaier{
1483126258Smlaier	struct pf_addr	ao;
1484126258Smlaier
1485126258Smlaier	PF_ACPY(&ao, a, AF_INET6);
1486126258Smlaier	PF_ACPY(a, an, AF_INET6);
1487126258Smlaier
1488126258Smlaier	*c = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1489126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1490126258Smlaier	    pf_cksum_fixup(pf_cksum_fixup(*c,
1491126258Smlaier	    ao.addr16[0], an->addr16[0], u),
1492126258Smlaier	    ao.addr16[1], an->addr16[1], u),
1493126258Smlaier	    ao.addr16[2], an->addr16[2], u),
1494126258Smlaier	    ao.addr16[3], an->addr16[3], u),
1495126258Smlaier	    ao.addr16[4], an->addr16[4], u),
1496126258Smlaier	    ao.addr16[5], an->addr16[5], u),
1497126258Smlaier	    ao.addr16[6], an->addr16[6], u),
1498126258Smlaier	    ao.addr16[7], an->addr16[7], u);
1499126258Smlaier}
1500126258Smlaier#endif /* INET6 */
1501126258Smlaier
1502126258Smlaiervoid
1503126258Smlaierpf_change_icmp(struct pf_addr *ia, u_int16_t *ip, struct pf_addr *oa,
1504126258Smlaier    struct pf_addr *na, u_int16_t np, u_int16_t *pc, u_int16_t *h2c,
1505126258Smlaier    u_int16_t *ic, u_int16_t *hc, u_int8_t u, sa_family_t af)
1506126258Smlaier{
1507126258Smlaier	struct pf_addr	oia, ooa;
1508126258Smlaier
1509126258Smlaier	PF_ACPY(&oia, ia, af);
1510126258Smlaier	PF_ACPY(&ooa, oa, af);
1511126258Smlaier
1512126258Smlaier	/* Change inner protocol port, fix inner protocol checksum. */
1513126258Smlaier	if (ip != NULL) {
1514126258Smlaier		u_int16_t	oip = *ip;
1515127629Smlaier		u_int32_t	opc = 0;	/* make the compiler happy */
1516126258Smlaier
1517126258Smlaier		if (pc != NULL)
1518126258Smlaier			opc = *pc;
1519126258Smlaier		*ip = np;
1520126258Smlaier		if (pc != NULL)
1521126258Smlaier			*pc = pf_cksum_fixup(*pc, oip, *ip, u);
1522126258Smlaier		*ic = pf_cksum_fixup(*ic, oip, *ip, 0);
1523126258Smlaier		if (pc != NULL)
1524126258Smlaier			*ic = pf_cksum_fixup(*ic, opc, *pc, 0);
1525126258Smlaier	}
1526126258Smlaier	/* Change inner ip address, fix inner ip and icmp checksums. */
1527126258Smlaier	PF_ACPY(ia, na, af);
1528126258Smlaier	switch (af) {
1529126258Smlaier#ifdef INET
1530126258Smlaier	case AF_INET: {
1531126258Smlaier		u_int32_t	 oh2c = *h2c;
1532126258Smlaier
1533126258Smlaier		*h2c = pf_cksum_fixup(pf_cksum_fixup(*h2c,
1534126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1535126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1536126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(*ic,
1537126258Smlaier		    oia.addr16[0], ia->addr16[0], 0),
1538126258Smlaier		    oia.addr16[1], ia->addr16[1], 0);
1539126258Smlaier		*ic = pf_cksum_fixup(*ic, oh2c, *h2c, 0);
1540126258Smlaier		break;
1541126258Smlaier	}
1542126258Smlaier#endif /* INET */
1543126258Smlaier#ifdef INET6
1544126258Smlaier	case AF_INET6:
1545126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1546126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1547126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1548126258Smlaier		    oia.addr16[0], ia->addr16[0], u),
1549126258Smlaier		    oia.addr16[1], ia->addr16[1], u),
1550126258Smlaier		    oia.addr16[2], ia->addr16[2], u),
1551126258Smlaier		    oia.addr16[3], ia->addr16[3], u),
1552126258Smlaier		    oia.addr16[4], ia->addr16[4], u),
1553126258Smlaier		    oia.addr16[5], ia->addr16[5], u),
1554126258Smlaier		    oia.addr16[6], ia->addr16[6], u),
1555126258Smlaier		    oia.addr16[7], ia->addr16[7], u);
1556126258Smlaier		break;
1557126258Smlaier#endif /* INET6 */
1558126258Smlaier	}
1559126258Smlaier	/* Change outer ip address, fix outer ip or icmpv6 checksum. */
1560126258Smlaier	PF_ACPY(oa, na, af);
1561126258Smlaier	switch (af) {
1562126258Smlaier#ifdef INET
1563126258Smlaier	case AF_INET:
1564126258Smlaier		*hc = pf_cksum_fixup(pf_cksum_fixup(*hc,
1565126258Smlaier		    ooa.addr16[0], oa->addr16[0], 0),
1566126258Smlaier		    ooa.addr16[1], oa->addr16[1], 0);
1567126258Smlaier		break;
1568126258Smlaier#endif /* INET */
1569126258Smlaier#ifdef INET6
1570126258Smlaier	case AF_INET6:
1571126258Smlaier		*ic = pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1572126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(pf_cksum_fixup(
1573126258Smlaier		    pf_cksum_fixup(pf_cksum_fixup(*ic,
1574126258Smlaier		    ooa.addr16[0], oa->addr16[0], u),
1575126258Smlaier		    ooa.addr16[1], oa->addr16[1], u),
1576126258Smlaier		    ooa.addr16[2], oa->addr16[2], u),
1577126258Smlaier		    ooa.addr16[3], oa->addr16[3], u),
1578126258Smlaier		    ooa.addr16[4], oa->addr16[4], u),
1579126258Smlaier		    ooa.addr16[5], oa->addr16[5], u),
1580126258Smlaier		    ooa.addr16[6], oa->addr16[6], u),
1581126258Smlaier		    ooa.addr16[7], oa->addr16[7], u);
1582126258Smlaier		break;
1583126258Smlaier#endif /* INET6 */
1584126258Smlaier	}
1585126258Smlaier}
1586126258Smlaier
1587126258Smlaiervoid
1588162238Scsjp#ifdef __FreeBSD__
1589162238Scsjppf_send_tcp(struct mbuf *replyto, const struct pf_rule *r, sa_family_t af,
1590162238Scsjp#else
1591126258Smlaierpf_send_tcp(const struct pf_rule *r, sa_family_t af,
1592162238Scsjp#endif
1593126258Smlaier    const struct pf_addr *saddr, const struct pf_addr *daddr,
1594126258Smlaier    u_int16_t sport, u_int16_t dport, u_int32_t seq, u_int32_t ack,
1595145836Smlaier    u_int8_t flags, u_int16_t win, u_int16_t mss, u_int8_t ttl, int tag,
1596145836Smlaier    struct ether_header *eh, struct ifnet *ifp)
1597126258Smlaier{
1598126258Smlaier	struct mbuf	*m;
1599127629Smlaier	int		 len = 0, tlen;		/* make the compiler happy */
1600126258Smlaier#ifdef INET
1601127629Smlaier	struct ip	*h = NULL;		/* make the compiler happy */
1602126258Smlaier#endif /* INET */
1603126258Smlaier#ifdef INET6
1604127629Smlaier	struct ip6_hdr	*h6 = NULL;		/* make the compiler happy */
1605126258Smlaier#endif /* INET6 */
1606127629Smlaier	struct tcphdr	*th = NULL;		/* make the compiler happy */
1607126258Smlaier	char *opt;
1608126258Smlaier
1609126258Smlaier	/* maximum segment size tcp option */
1610126258Smlaier	tlen = sizeof(struct tcphdr);
1611126258Smlaier	if (mss)
1612126258Smlaier		tlen += 4;
1613126258Smlaier
1614126258Smlaier	switch (af) {
1615126258Smlaier#ifdef INET
1616126258Smlaier	case AF_INET:
1617126258Smlaier		len = sizeof(struct ip) + tlen;
1618126258Smlaier		break;
1619126258Smlaier#endif /* INET */
1620126258Smlaier#ifdef INET6
1621126258Smlaier	case AF_INET6:
1622126258Smlaier		len = sizeof(struct ip6_hdr) + tlen;
1623126258Smlaier		break;
1624126258Smlaier#endif /* INET6 */
1625126258Smlaier	}
1626126258Smlaier
1627126258Smlaier	/* create outgoing mbuf */
1628132280Smlaier	m = m_gethdr(M_DONTWAIT, MT_HEADER);
1629132280Smlaier	if (m == NULL)
1630132280Smlaier		return;
1631162238Scsjp#ifdef __FreeBSD__
1632162238Scsjp#ifdef MAC
1633162238Scsjp	if (replyto)
1634162238Scsjp		mac_create_mbuf_netlayer(replyto, m);
1635162238Scsjp	else
1636162238Scsjp		mac_create_mbuf_from_firewall(m);
1637162238Scsjp#else
1638162238Scsjp	(void)replyto;
1639162238Scsjp#endif
1640162238Scsjp#endif
1641145836Smlaier	if (tag) {
1642145836Smlaier#ifdef __FreeBSD__
1643145836Smlaier		m->m_flags |= M_SKIP_FIREWALL;
1644132280Smlaier#else
1645145836Smlaier		struct m_tag	*mtag;
1646145836Smlaier
1647145836Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1648145836Smlaier		if (mtag == NULL) {
1649145836Smlaier			m_freem(m);
1650145836Smlaier			return;
1651145836Smlaier		}
1652145836Smlaier		m_tag_prepend(m, mtag);
1653145836Smlaier#endif
1654126258Smlaier	}
1655126258Smlaier#ifdef ALTQ
1656126258Smlaier	if (r != NULL && r->qid) {
1657145836Smlaier		struct m_tag	*mtag;
1658126258Smlaier		struct altq_tag *atag;
1659126258Smlaier
1660126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1661126258Smlaier		if (mtag != NULL) {
1662126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1663126258Smlaier			atag->qid = r->qid;
1664126258Smlaier			/* add hints for ecn */
1665126258Smlaier			atag->af = af;
1666126258Smlaier			atag->hdr = mtod(m, struct ip *);
1667126258Smlaier			m_tag_prepend(m, mtag);
1668126258Smlaier		}
1669126258Smlaier	}
1670145836Smlaier#endif /* ALTQ */
1671126258Smlaier	m->m_data += max_linkhdr;
1672126258Smlaier	m->m_pkthdr.len = m->m_len = len;
1673126258Smlaier	m->m_pkthdr.rcvif = NULL;
1674126258Smlaier	bzero(m->m_data, len);
1675126258Smlaier	switch (af) {
1676126258Smlaier#ifdef INET
1677126258Smlaier	case AF_INET:
1678126258Smlaier		h = mtod(m, struct ip *);
1679126258Smlaier
1680126258Smlaier		/* IP header fields included in the TCP checksum */
1681126258Smlaier		h->ip_p = IPPROTO_TCP;
1682126258Smlaier		h->ip_len = htons(tlen);
1683126258Smlaier		h->ip_src.s_addr = saddr->v4.s_addr;
1684126258Smlaier		h->ip_dst.s_addr = daddr->v4.s_addr;
1685126258Smlaier
1686126258Smlaier		th = (struct tcphdr *)((caddr_t)h + sizeof(struct ip));
1687126258Smlaier		break;
1688126258Smlaier#endif /* INET */
1689126258Smlaier#ifdef INET6
1690126258Smlaier	case AF_INET6:
1691126258Smlaier		h6 = mtod(m, struct ip6_hdr *);
1692126258Smlaier
1693126258Smlaier		/* IP header fields included in the TCP checksum */
1694126258Smlaier		h6->ip6_nxt = IPPROTO_TCP;
1695126258Smlaier		h6->ip6_plen = htons(tlen);
1696126258Smlaier		memcpy(&h6->ip6_src, &saddr->v6, sizeof(struct in6_addr));
1697126258Smlaier		memcpy(&h6->ip6_dst, &daddr->v6, sizeof(struct in6_addr));
1698126258Smlaier
1699126258Smlaier		th = (struct tcphdr *)((caddr_t)h6 + sizeof(struct ip6_hdr));
1700126258Smlaier		break;
1701126258Smlaier#endif /* INET6 */
1702126258Smlaier	}
1703126258Smlaier
1704126258Smlaier	/* TCP header */
1705126258Smlaier	th->th_sport = sport;
1706126258Smlaier	th->th_dport = dport;
1707126258Smlaier	th->th_seq = htonl(seq);
1708126258Smlaier	th->th_ack = htonl(ack);
1709126258Smlaier	th->th_off = tlen >> 2;
1710126258Smlaier	th->th_flags = flags;
1711126258Smlaier	th->th_win = htons(win);
1712126258Smlaier
1713126258Smlaier	if (mss) {
1714126258Smlaier		opt = (char *)(th + 1);
1715126258Smlaier		opt[0] = TCPOPT_MAXSEG;
1716126258Smlaier		opt[1] = 4;
1717126258Smlaier		HTONS(mss);
1718126258Smlaier		bcopy((caddr_t)&mss, (caddr_t)(opt + 2), 2);
1719126258Smlaier	}
1720126258Smlaier
1721126258Smlaier	switch (af) {
1722126258Smlaier#ifdef INET
1723126258Smlaier	case AF_INET:
1724126258Smlaier		/* TCP checksum */
1725126258Smlaier		th->th_sum = in_cksum(m, len);
1726126258Smlaier
1727126258Smlaier		/* Finish the IP header */
1728126258Smlaier		h->ip_v = 4;
1729126258Smlaier		h->ip_hl = sizeof(*h) >> 2;
1730126258Smlaier		h->ip_tos = IPTOS_LOWDELAY;
1731127145Smlaier#ifdef __FreeBSD__
1732130613Smlaier		h->ip_off = path_mtu_discovery ? IP_DF : 0;
1733130613Smlaier		h->ip_len = len;
1734126261Smlaier#else
1735126261Smlaier		h->ip_off = htons(ip_mtudisc ? IP_DF : 0);
1736130613Smlaier		h->ip_len = htons(len);
1737126261Smlaier#endif
1738126258Smlaier		h->ip_ttl = ttl ? ttl : ip_defttl;
1739126258Smlaier		h->ip_sum = 0;
1740145836Smlaier		if (eh == NULL) {
1741127145Smlaier#ifdef __FreeBSD__
1742145836Smlaier			PF_UNLOCK();
1743145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1744145836Smlaier			    (void *)NULL, (void *)NULL);
1745145836Smlaier			PF_LOCK();
1746126261Smlaier#else /* ! __FreeBSD__ */
1747145836Smlaier			ip_output(m, (void *)NULL, (void *)NULL, 0,
1748145836Smlaier			    (void *)NULL, (void *)NULL);
1749126261Smlaier#endif
1750145836Smlaier		} else {
1751145836Smlaier			struct route		 ro;
1752145836Smlaier			struct rtentry		 rt;
1753145836Smlaier			struct ether_header	*e = (void *)ro.ro_dst.sa_data;
1754145836Smlaier
1755145836Smlaier			if (ifp == NULL) {
1756145836Smlaier				m_freem(m);
1757145836Smlaier				return;
1758145836Smlaier			}
1759145836Smlaier			rt.rt_ifp = ifp;
1760145836Smlaier			ro.ro_rt = &rt;
1761145836Smlaier			ro.ro_dst.sa_len = sizeof(ro.ro_dst);
1762145836Smlaier			ro.ro_dst.sa_family = pseudo_AF_HDRCMPLT;
1763145836Smlaier			bcopy(eh->ether_dhost, e->ether_shost, ETHER_ADDR_LEN);
1764145836Smlaier			bcopy(eh->ether_shost, e->ether_dhost, ETHER_ADDR_LEN);
1765145836Smlaier			e->ether_type = eh->ether_type;
1766145836Smlaier#ifdef __FreeBSD__
1767145836Smlaier			PF_UNLOCK();
1768145836Smlaier			/* XXX_IMPORT: later */
1769145836Smlaier			ip_output(m, (void *)NULL, &ro, 0,
1770145836Smlaier			    (void *)NULL, (void *)NULL);
1771145836Smlaier			PF_LOCK();
1772145836Smlaier#else /* ! __FreeBSD__ */
1773145836Smlaier			ip_output(m, (void *)NULL, &ro, IP_ROUTETOETHER,
1774145836Smlaier			    (void *)NULL, (void *)NULL);
1775145836Smlaier#endif
1776145836Smlaier		}
1777126258Smlaier		break;
1778126258Smlaier#endif /* INET */
1779126258Smlaier#ifdef INET6
1780126258Smlaier	case AF_INET6:
1781126258Smlaier		/* TCP checksum */
1782126258Smlaier		th->th_sum = in6_cksum(m, IPPROTO_TCP,
1783126258Smlaier		    sizeof(struct ip6_hdr), tlen);
1784126258Smlaier
1785126258Smlaier		h6->ip6_vfc |= IPV6_VERSION;
1786126258Smlaier		h6->ip6_hlim = IPV6_DEFHLIM;
1787126258Smlaier
1788127145Smlaier#ifdef __FreeBSD__
1789126261Smlaier		PF_UNLOCK();
1790126261Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
1791126261Smlaier		PF_LOCK();
1792126261Smlaier#else
1793126258Smlaier		ip6_output(m, NULL, NULL, 0, NULL, NULL);
1794126261Smlaier#endif
1795126258Smlaier		break;
1796126258Smlaier#endif /* INET6 */
1797126258Smlaier	}
1798126258Smlaier}
1799126258Smlaier
1800126258Smlaiervoid
1801126258Smlaierpf_send_icmp(struct mbuf *m, u_int8_t type, u_int8_t code, sa_family_t af,
1802126258Smlaier    struct pf_rule *r)
1803126258Smlaier{
1804132280Smlaier#ifdef ALTQ
1805126258Smlaier	struct m_tag	*mtag;
1806132280Smlaier#endif
1807126258Smlaier	struct mbuf	*m0;
1808127145Smlaier#ifdef __FreeBSD__
1809126261Smlaier	struct ip *ip;
1810126261Smlaier#endif
1811126258Smlaier
1812132280Smlaier#ifdef __FreeBSD__
1813132280Smlaier	m0 = m_copypacket(m, M_DONTWAIT);
1814132280Smlaier	if (m0 == NULL)
1815132280Smlaier		return;
1816132280Smlaier	m0->m_flags |= M_SKIP_FIREWALL;
1817132280Smlaier#else
1818126258Smlaier	mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
1819126258Smlaier	if (mtag == NULL)
1820126258Smlaier		return;
1821126258Smlaier	m0 = m_copy(m, 0, M_COPYALL);
1822126258Smlaier	if (m0 == NULL) {
1823126258Smlaier		m_tag_free(mtag);
1824126258Smlaier		return;
1825126258Smlaier	}
1826126258Smlaier	m_tag_prepend(m0, mtag);
1827132280Smlaier#endif
1828126258Smlaier
1829126258Smlaier#ifdef ALTQ
1830126258Smlaier	if (r->qid) {
1831126258Smlaier		struct altq_tag *atag;
1832126258Smlaier
1833126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
1834126258Smlaier		if (mtag != NULL) {
1835126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
1836126258Smlaier			atag->qid = r->qid;
1837126258Smlaier			/* add hints for ecn */
1838126258Smlaier			atag->af = af;
1839126258Smlaier			atag->hdr = mtod(m0, struct ip *);
1840126258Smlaier			m_tag_prepend(m0, mtag);
1841126258Smlaier		}
1842126258Smlaier	}
1843145836Smlaier#endif /* ALTQ */
1844126258Smlaier
1845126258Smlaier	switch (af) {
1846126258Smlaier#ifdef INET
1847126258Smlaier	case AF_INET:
1848127145Smlaier#ifdef __FreeBSD__
1849126261Smlaier		/* icmp_error() expects host byte ordering */
1850126261Smlaier		ip = mtod(m0, struct ip *);
1851126261Smlaier		NTOHS(ip->ip_len);
1852126261Smlaier		NTOHS(ip->ip_off);
1853126261Smlaier		PF_UNLOCK();
1854145863Sandre		icmp_error(m0, type, code, 0, 0);
1855126261Smlaier		PF_LOCK();
1856145874Smlaier#else
1857145874Smlaier		icmp_error(m0, type, code, 0, (void *)NULL);
1858126261Smlaier#endif
1859126258Smlaier		break;
1860126258Smlaier#endif /* INET */
1861126258Smlaier#ifdef INET6
1862126258Smlaier	case AF_INET6:
1863127145Smlaier#ifdef __FreeBSD__
1864126261Smlaier		PF_UNLOCK();
1865126261Smlaier#endif
1866126258Smlaier		icmp6_error(m0, type, code, 0);
1867127145Smlaier#ifdef __FreeBSD__
1868126261Smlaier		PF_LOCK();
1869126261Smlaier#endif
1870126258Smlaier		break;
1871126258Smlaier#endif /* INET6 */
1872126258Smlaier	}
1873126258Smlaier}
1874126258Smlaier
1875126258Smlaier/*
1876126258Smlaier * Return 1 if the addresses a and b match (with mask m), otherwise return 0.
1877126258Smlaier * If n is 0, they match if they are equal. If n is != 0, they match if they
1878126258Smlaier * are different.
1879126258Smlaier */
1880126258Smlaierint
1881126258Smlaierpf_match_addr(u_int8_t n, struct pf_addr *a, struct pf_addr *m,
1882126258Smlaier    struct pf_addr *b, sa_family_t af)
1883126258Smlaier{
1884126258Smlaier	int	match = 0;
1885126258Smlaier
1886126258Smlaier	switch (af) {
1887126258Smlaier#ifdef INET
1888126258Smlaier	case AF_INET:
1889126258Smlaier		if ((a->addr32[0] & m->addr32[0]) ==
1890126258Smlaier		    (b->addr32[0] & m->addr32[0]))
1891126258Smlaier			match++;
1892126258Smlaier		break;
1893126258Smlaier#endif /* INET */
1894126258Smlaier#ifdef INET6
1895126258Smlaier	case AF_INET6:
1896126258Smlaier		if (((a->addr32[0] & m->addr32[0]) ==
1897126258Smlaier		     (b->addr32[0] & m->addr32[0])) &&
1898126258Smlaier		    ((a->addr32[1] & m->addr32[1]) ==
1899126258Smlaier		     (b->addr32[1] & m->addr32[1])) &&
1900126258Smlaier		    ((a->addr32[2] & m->addr32[2]) ==
1901126258Smlaier		     (b->addr32[2] & m->addr32[2])) &&
1902126258Smlaier		    ((a->addr32[3] & m->addr32[3]) ==
1903126258Smlaier		     (b->addr32[3] & m->addr32[3])))
1904126258Smlaier			match++;
1905126258Smlaier		break;
1906126258Smlaier#endif /* INET6 */
1907126258Smlaier	}
1908126258Smlaier	if (match) {
1909126258Smlaier		if (n)
1910126258Smlaier			return (0);
1911126258Smlaier		else
1912126258Smlaier			return (1);
1913126258Smlaier	} else {
1914126258Smlaier		if (n)
1915126258Smlaier			return (1);
1916126258Smlaier		else
1917126258Smlaier			return (0);
1918126258Smlaier	}
1919126258Smlaier}
1920126258Smlaier
1921126258Smlaierint
1922126258Smlaierpf_match(u_int8_t op, u_int32_t a1, u_int32_t a2, u_int32_t p)
1923126258Smlaier{
1924126258Smlaier	switch (op) {
1925126258Smlaier	case PF_OP_IRG:
1926126258Smlaier		return ((p > a1) && (p < a2));
1927126258Smlaier	case PF_OP_XRG:
1928126258Smlaier		return ((p < a1) || (p > a2));
1929126258Smlaier	case PF_OP_RRG:
1930126258Smlaier		return ((p >= a1) && (p <= a2));
1931126258Smlaier	case PF_OP_EQ:
1932126258Smlaier		return (p == a1);
1933126258Smlaier	case PF_OP_NE:
1934126258Smlaier		return (p != a1);
1935126258Smlaier	case PF_OP_LT:
1936126258Smlaier		return (p < a1);
1937126258Smlaier	case PF_OP_LE:
1938126258Smlaier		return (p <= a1);
1939126258Smlaier	case PF_OP_GT:
1940126258Smlaier		return (p > a1);
1941126258Smlaier	case PF_OP_GE:
1942126258Smlaier		return (p >= a1);
1943126258Smlaier	}
1944126258Smlaier	return (0); /* never reached */
1945126258Smlaier}
1946126258Smlaier
1947126258Smlaierint
1948126258Smlaierpf_match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
1949126258Smlaier{
1950126258Smlaier	NTOHS(a1);
1951126258Smlaier	NTOHS(a2);
1952126258Smlaier	NTOHS(p);
1953126258Smlaier	return (pf_match(op, a1, a2, p));
1954126258Smlaier}
1955126258Smlaier
1956126258Smlaierint
1957126258Smlaierpf_match_uid(u_int8_t op, uid_t a1, uid_t a2, uid_t u)
1958126258Smlaier{
1959126258Smlaier	if (u == UID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1960126258Smlaier		return (0);
1961126258Smlaier	return (pf_match(op, a1, a2, u));
1962126258Smlaier}
1963126258Smlaier
1964126258Smlaierint
1965126258Smlaierpf_match_gid(u_int8_t op, gid_t a1, gid_t a2, gid_t g)
1966126258Smlaier{
1967126258Smlaier	if (g == GID_MAX && op != PF_OP_EQ && op != PF_OP_NE)
1968126258Smlaier		return (0);
1969126258Smlaier	return (pf_match(op, a1, a2, g));
1970126258Smlaier}
1971126258Smlaier
1972126258Smlaierstruct pf_tag *
1973126258Smlaierpf_get_tag(struct mbuf *m)
1974126258Smlaier{
1975126258Smlaier	struct m_tag	*mtag;
1976126258Smlaier
1977126258Smlaier	if ((mtag = m_tag_find(m, PACKET_TAG_PF_TAG, NULL)) != NULL)
1978126258Smlaier		return ((struct pf_tag *)(mtag + 1));
1979126258Smlaier	else
1980126258Smlaier		return (NULL);
1981126258Smlaier}
1982126258Smlaier
1983126258Smlaierint
1984145836Smlaierpf_match_tag(struct mbuf *m, struct pf_rule *r, struct pf_tag **pftag, int *tag)
1985126258Smlaier{
1986126258Smlaier	if (*tag == -1) {	/* find mbuf tag */
1987145836Smlaier		*pftag = pf_get_tag(m);
1988145836Smlaier		if (*pftag != NULL)
1989145836Smlaier			*tag = (*pftag)->tag;
1990126258Smlaier		else
1991126258Smlaier			*tag = 0;
1992126258Smlaier	}
1993126258Smlaier
1994126258Smlaier	return ((!r->match_tag_not && r->match_tag == *tag) ||
1995126258Smlaier	    (r->match_tag_not && r->match_tag != *tag));
1996126258Smlaier}
1997126258Smlaier
1998126258Smlaierint
1999126258Smlaierpf_tag_packet(struct mbuf *m, struct pf_tag *pftag, int tag)
2000126258Smlaier{
2001126258Smlaier	struct m_tag	*mtag;
2002126258Smlaier
2003126258Smlaier	if (tag <= 0)
2004126258Smlaier		return (0);
2005126258Smlaier
2006126258Smlaier	if (pftag == NULL) {
2007126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_TAG, sizeof(*pftag), M_NOWAIT);
2008126258Smlaier		if (mtag == NULL)
2009126258Smlaier			return (1);
2010126258Smlaier		((struct pf_tag *)(mtag + 1))->tag = tag;
2011126258Smlaier		m_tag_prepend(m, mtag);
2012126258Smlaier	} else
2013126258Smlaier		pftag->tag = tag;
2014126258Smlaier
2015126258Smlaier	return (0);
2016126258Smlaier}
2017126258Smlaier
2018145836Smlaierstatic void
2019145836Smlaierpf_step_into_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;
2023126258Smlaier
2024145836Smlaier	if (*depth >= sizeof(pf_anchor_stack) /
2025145836Smlaier	    sizeof(pf_anchor_stack[0])) {
2026145836Smlaier		printf("pf_step_into_anchor: stack overflow\n");
2027145836Smlaier		*r = TAILQ_NEXT(*r, entries);
2028145836Smlaier		return;
2029145836Smlaier	} else if (*depth == 0 && a != NULL)
2030145836Smlaier		*a = *r;
2031145836Smlaier	f = pf_anchor_stack + (*depth)++;
2032145836Smlaier	f->rs = *rs;
2033145836Smlaier	f->r = *r;
2034145836Smlaier	if ((*r)->anchor_wildcard) {
2035145836Smlaier		f->parent = &(*r)->anchor->children;
2036145836Smlaier		if ((f->child = RB_MIN(pf_anchor_node, f->parent)) ==
2037145836Smlaier		    NULL) {
2038145836Smlaier			*r = NULL;
2039145836Smlaier			return;
2040145836Smlaier		}
2041145836Smlaier		*rs = &f->child->ruleset;
2042145836Smlaier	} else {
2043145836Smlaier		f->parent = NULL;
2044145836Smlaier		f->child = NULL;
2045145836Smlaier		*rs = &(*r)->anchor->ruleset;
2046145836Smlaier	}
2047145836Smlaier	*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2048145836Smlaier}
2049126258Smlaier
2050145836Smlaierstatic void
2051145836Smlaierpf_step_out_of_anchor(int *depth, struct pf_ruleset **rs, int n,
2052145836Smlaier    struct pf_rule **r, struct pf_rule **a)
2053145836Smlaier{
2054145836Smlaier	struct pf_anchor_stackframe	*f;
2055145836Smlaier
2056145836Smlaier	do {
2057145836Smlaier		if (*depth <= 0)
2058145836Smlaier			break;
2059145836Smlaier		f = pf_anchor_stack + *depth - 1;
2060145836Smlaier		if (f->parent != NULL && f->child != NULL) {
2061145836Smlaier			f->child = RB_NEXT(pf_anchor_node, f->parent, f->child);
2062145836Smlaier			if (f->child != NULL) {
2063145836Smlaier				*rs = &f->child->ruleset;
2064145836Smlaier				*r = TAILQ_FIRST((*rs)->rules[n].active.ptr);
2065145836Smlaier				if (*r == NULL)
2066145836Smlaier					continue;
2067145836Smlaier				else
2068145836Smlaier					break;
2069145836Smlaier			}
2070145836Smlaier		}
2071145836Smlaier		(*depth)--;
2072145836Smlaier		if (*depth == 0 && a != NULL)
2073145836Smlaier			*a = NULL;
2074145836Smlaier		*rs = f->rs;
2075145836Smlaier		*r = TAILQ_NEXT(f->r, entries);
2076145836Smlaier	} while (*r == NULL);
2077145836Smlaier}
2078145836Smlaier
2079126258Smlaier#ifdef INET6
2080126258Smlaiervoid
2081126258Smlaierpf_poolmask(struct pf_addr *naddr, struct pf_addr *raddr,
2082126258Smlaier    struct pf_addr *rmask, struct pf_addr *saddr, sa_family_t af)
2083126258Smlaier{
2084126258Smlaier	switch (af) {
2085126258Smlaier#ifdef INET
2086126258Smlaier	case AF_INET:
2087126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2088126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2089126258Smlaier		break;
2090126258Smlaier#endif /* INET */
2091126258Smlaier	case AF_INET6:
2092126258Smlaier		naddr->addr32[0] = (raddr->addr32[0] & rmask->addr32[0]) |
2093126258Smlaier		((rmask->addr32[0] ^ 0xffffffff ) & saddr->addr32[0]);
2094126258Smlaier		naddr->addr32[1] = (raddr->addr32[1] & rmask->addr32[1]) |
2095126258Smlaier		((rmask->addr32[1] ^ 0xffffffff ) & saddr->addr32[1]);
2096126258Smlaier		naddr->addr32[2] = (raddr->addr32[2] & rmask->addr32[2]) |
2097126258Smlaier		((rmask->addr32[2] ^ 0xffffffff ) & saddr->addr32[2]);
2098126258Smlaier		naddr->addr32[3] = (raddr->addr32[3] & rmask->addr32[3]) |
2099126258Smlaier		((rmask->addr32[3] ^ 0xffffffff ) & saddr->addr32[3]);
2100126258Smlaier		break;
2101126258Smlaier	}
2102126258Smlaier}
2103126258Smlaier
2104126258Smlaiervoid
2105130613Smlaierpf_addr_inc(struct pf_addr *addr, sa_family_t af)
2106126258Smlaier{
2107126258Smlaier	switch (af) {
2108126258Smlaier#ifdef INET
2109126258Smlaier	case AF_INET:
2110126258Smlaier		addr->addr32[0] = htonl(ntohl(addr->addr32[0]) + 1);
2111126258Smlaier		break;
2112126258Smlaier#endif /* INET */
2113126258Smlaier	case AF_INET6:
2114126258Smlaier		if (addr->addr32[3] == 0xffffffff) {
2115126258Smlaier			addr->addr32[3] = 0;
2116126258Smlaier			if (addr->addr32[2] == 0xffffffff) {
2117126258Smlaier				addr->addr32[2] = 0;
2118126258Smlaier				if (addr->addr32[1] == 0xffffffff) {
2119126258Smlaier					addr->addr32[1] = 0;
2120126258Smlaier					addr->addr32[0] =
2121126258Smlaier					    htonl(ntohl(addr->addr32[0]) + 1);
2122126258Smlaier				} else
2123126258Smlaier					addr->addr32[1] =
2124126258Smlaier					    htonl(ntohl(addr->addr32[1]) + 1);
2125126258Smlaier			} else
2126126258Smlaier				addr->addr32[2] =
2127126258Smlaier				    htonl(ntohl(addr->addr32[2]) + 1);
2128126258Smlaier		} else
2129126258Smlaier			addr->addr32[3] =
2130126258Smlaier			    htonl(ntohl(addr->addr32[3]) + 1);
2131126258Smlaier		break;
2132126258Smlaier	}
2133126258Smlaier}
2134126258Smlaier#endif /* INET6 */
2135126258Smlaier
2136126258Smlaier#define mix(a,b,c) \
2137126258Smlaier	do {					\
2138126258Smlaier		a -= b; a -= c; a ^= (c >> 13);	\
2139126258Smlaier		b -= c; b -= a; b ^= (a << 8);	\
2140126258Smlaier		c -= a; c -= b; c ^= (b >> 13);	\
2141126258Smlaier		a -= b; a -= c; a ^= (c >> 12);	\
2142126258Smlaier		b -= c; b -= a; b ^= (a << 16);	\
2143126258Smlaier		c -= a; c -= b; c ^= (b >> 5);	\
2144126258Smlaier		a -= b; a -= c; a ^= (c >> 3);	\
2145126258Smlaier		b -= c; b -= a; b ^= (a << 10);	\
2146126258Smlaier		c -= a; c -= b; c ^= (b >> 15);	\
2147126258Smlaier	} while (0)
2148126258Smlaier
2149126258Smlaier/*
2150126258Smlaier * hash function based on bridge_hash in if_bridge.c
2151126258Smlaier */
2152126258Smlaiervoid
2153126258Smlaierpf_hash(struct pf_addr *inaddr, struct pf_addr *hash,
2154126258Smlaier    struct pf_poolhashkey *key, sa_family_t af)
2155126258Smlaier{
2156126258Smlaier	u_int32_t	a = 0x9e3779b9, b = 0x9e3779b9, c = key->key32[0];
2157126258Smlaier
2158126258Smlaier	switch (af) {
2159126258Smlaier#ifdef INET
2160126258Smlaier	case AF_INET:
2161126258Smlaier		a += inaddr->addr32[0];
2162126258Smlaier		b += key->key32[1];
2163126258Smlaier		mix(a, b, c);
2164126258Smlaier		hash->addr32[0] = c + key->key32[2];
2165126258Smlaier		break;
2166126258Smlaier#endif /* INET */
2167126258Smlaier#ifdef INET6
2168126258Smlaier	case AF_INET6:
2169126258Smlaier		a += inaddr->addr32[0];
2170126258Smlaier		b += inaddr->addr32[2];
2171126258Smlaier		mix(a, b, c);
2172126258Smlaier		hash->addr32[0] = c;
2173126258Smlaier		a += inaddr->addr32[1];
2174126258Smlaier		b += inaddr->addr32[3];
2175126258Smlaier		c += key->key32[1];
2176126258Smlaier		mix(a, b, c);
2177126258Smlaier		hash->addr32[1] = c;
2178126258Smlaier		a += inaddr->addr32[2];
2179126258Smlaier		b += inaddr->addr32[1];
2180126258Smlaier		c += key->key32[2];
2181126258Smlaier		mix(a, b, c);
2182126258Smlaier		hash->addr32[2] = c;
2183126258Smlaier		a += inaddr->addr32[3];
2184126258Smlaier		b += inaddr->addr32[0];
2185126258Smlaier		c += key->key32[3];
2186126258Smlaier		mix(a, b, c);
2187126258Smlaier		hash->addr32[3] = c;
2188126258Smlaier		break;
2189126258Smlaier#endif /* INET6 */
2190126258Smlaier	}
2191126258Smlaier}
2192126258Smlaier
2193126258Smlaierint
2194130613Smlaierpf_map_addr(sa_family_t af, struct pf_rule *r, struct pf_addr *saddr,
2195130613Smlaier    struct pf_addr *naddr, struct pf_addr *init_addr, struct pf_src_node **sn)
2196126258Smlaier{
2197126258Smlaier	unsigned char		 hash[16];
2198130613Smlaier	struct pf_pool		*rpool = &r->rpool;
2199130613Smlaier	struct pf_addr		*raddr = &rpool->cur->addr.v.a.addr;
2200130613Smlaier	struct pf_addr		*rmask = &rpool->cur->addr.v.a.mask;
2201126258Smlaier	struct pf_pooladdr	*acur = rpool->cur;
2202130613Smlaier	struct pf_src_node	 k;
2203126258Smlaier
2204130613Smlaier	if (*sn == NULL && r->rpool.opts & PF_POOL_STICKYADDR &&
2205130613Smlaier	    (r->rpool.opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2206130613Smlaier		k.af = af;
2207130613Smlaier		PF_ACPY(&k.addr, saddr, af);
2208130613Smlaier		if (r->rule_flag & PFRULE_RULESRCTRACK ||
2209130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR)
2210130613Smlaier			k.rule.ptr = r;
2211130613Smlaier		else
2212130613Smlaier			k.rule.ptr = NULL;
2213130613Smlaier		pf_status.scounters[SCNT_SRC_NODE_SEARCH]++;
2214130613Smlaier		*sn = RB_FIND(pf_src_tree, &tree_src_tracking, &k);
2215130613Smlaier		if (*sn != NULL && !PF_AZERO(&(*sn)->raddr, af)) {
2216130613Smlaier			PF_ACPY(naddr, &(*sn)->raddr, af);
2217130613Smlaier			if (pf_status.debug >= PF_DEBUG_MISC) {
2218130613Smlaier				printf("pf_map_addr: src tracking maps ");
2219130613Smlaier				pf_print_host(&k.addr, 0, af);
2220130613Smlaier				printf(" to ");
2221130613Smlaier				pf_print_host(naddr, 0, af);
2222130613Smlaier				printf("\n");
2223130613Smlaier			}
2224130613Smlaier			return (0);
2225130613Smlaier		}
2226130613Smlaier	}
2227130613Smlaier
2228126258Smlaier	if (rpool->cur->addr.type == PF_ADDR_NOROUTE)
2229126258Smlaier		return (1);
2230130613Smlaier	if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2231145836Smlaier		switch (af) {
2232145836Smlaier#ifdef INET
2233145836Smlaier		case AF_INET:
2234130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt4 < 1 &&
2235130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2236130613Smlaier			    PF_POOL_ROUNDROBIN)
2237130613Smlaier				return (1);
2238130613Smlaier			 raddr = &rpool->cur->addr.p.dyn->pfid_addr4;
2239130613Smlaier			 rmask = &rpool->cur->addr.p.dyn->pfid_mask4;
2240145836Smlaier			break;
2241145836Smlaier#endif /* INET */
2242145836Smlaier#ifdef INET6
2243145836Smlaier		case AF_INET6:
2244130613Smlaier			if (rpool->cur->addr.p.dyn->pfid_acnt6 < 1 &&
2245130613Smlaier			    (rpool->opts & PF_POOL_TYPEMASK) !=
2246130613Smlaier			    PF_POOL_ROUNDROBIN)
2247130613Smlaier				return (1);
2248130613Smlaier			raddr = &rpool->cur->addr.p.dyn->pfid_addr6;
2249130613Smlaier			rmask = &rpool->cur->addr.p.dyn->pfid_mask6;
2250145836Smlaier			break;
2251145836Smlaier#endif /* INET6 */
2252130613Smlaier		}
2253130613Smlaier	} else if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2254126258Smlaier		if ((rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_ROUNDROBIN)
2255126258Smlaier			return (1); /* unsupported */
2256126258Smlaier	} else {
2257126258Smlaier		raddr = &rpool->cur->addr.v.a.addr;
2258126258Smlaier		rmask = &rpool->cur->addr.v.a.mask;
2259126258Smlaier	}
2260126258Smlaier
2261126258Smlaier	switch (rpool->opts & PF_POOL_TYPEMASK) {
2262126258Smlaier	case PF_POOL_NONE:
2263126258Smlaier		PF_ACPY(naddr, raddr, af);
2264126258Smlaier		break;
2265126258Smlaier	case PF_POOL_BITMASK:
2266126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, saddr, af);
2267126258Smlaier		break;
2268126258Smlaier	case PF_POOL_RANDOM:
2269126258Smlaier		if (init_addr != NULL && PF_AZERO(init_addr, af)) {
2270126258Smlaier			switch (af) {
2271126258Smlaier#ifdef INET
2272126258Smlaier			case AF_INET:
2273145836Smlaier				rpool->counter.addr32[0] = htonl(arc4random());
2274126258Smlaier				break;
2275126258Smlaier#endif /* INET */
2276126258Smlaier#ifdef INET6
2277126258Smlaier			case AF_INET6:
2278126258Smlaier				if (rmask->addr32[3] != 0xffffffff)
2279145836Smlaier					rpool->counter.addr32[3] =
2280145836Smlaier					    htonl(arc4random());
2281126258Smlaier				else
2282126258Smlaier					break;
2283126258Smlaier				if (rmask->addr32[2] != 0xffffffff)
2284145836Smlaier					rpool->counter.addr32[2] =
2285145836Smlaier					    htonl(arc4random());
2286126258Smlaier				else
2287126258Smlaier					break;
2288126258Smlaier				if (rmask->addr32[1] != 0xffffffff)
2289145836Smlaier					rpool->counter.addr32[1] =
2290145836Smlaier					    htonl(arc4random());
2291126258Smlaier				else
2292126258Smlaier					break;
2293126258Smlaier				if (rmask->addr32[0] != 0xffffffff)
2294145836Smlaier					rpool->counter.addr32[0] =
2295145836Smlaier					    htonl(arc4random());
2296126258Smlaier				break;
2297126258Smlaier#endif /* INET6 */
2298126258Smlaier			}
2299126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2300126258Smlaier			PF_ACPY(init_addr, naddr, af);
2301126258Smlaier
2302126258Smlaier		} else {
2303126258Smlaier			PF_AINC(&rpool->counter, af);
2304126258Smlaier			PF_POOLMASK(naddr, raddr, rmask, &rpool->counter, af);
2305126258Smlaier		}
2306126258Smlaier		break;
2307126258Smlaier	case PF_POOL_SRCHASH:
2308126258Smlaier		pf_hash(saddr, (struct pf_addr *)&hash, &rpool->key, af);
2309126258Smlaier		PF_POOLMASK(naddr, raddr, rmask, (struct pf_addr *)&hash, af);
2310126258Smlaier		break;
2311126258Smlaier	case PF_POOL_ROUNDROBIN:
2312126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2313126258Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.tbl,
2314126258Smlaier			    &rpool->tblidx, &rpool->counter,
2315126258Smlaier			    &raddr, &rmask, af))
2316126258Smlaier				goto get_addr;
2317130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2318130613Smlaier			if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2319130613Smlaier			    &rpool->tblidx, &rpool->counter,
2320130613Smlaier			    &raddr, &rmask, af))
2321130613Smlaier				goto get_addr;
2322126258Smlaier		} else if (pf_match_addr(0, raddr, rmask, &rpool->counter, af))
2323126258Smlaier			goto get_addr;
2324126258Smlaier
2325126258Smlaier	try_next:
2326126258Smlaier		if ((rpool->cur = TAILQ_NEXT(rpool->cur, entries)) == NULL)
2327126258Smlaier			rpool->cur = TAILQ_FIRST(&rpool->list);
2328126258Smlaier		if (rpool->cur->addr.type == PF_ADDR_TABLE) {
2329126258Smlaier			rpool->tblidx = -1;
2330126258Smlaier			if (pfr_pool_get(rpool->cur->addr.p.tbl,
2331126258Smlaier			    &rpool->tblidx, &rpool->counter,
2332126258Smlaier			    &raddr, &rmask, af)) {
2333130613Smlaier				/* table contains no address of type 'af' */
2334126258Smlaier				if (rpool->cur != acur)
2335126258Smlaier					goto try_next;
2336126258Smlaier				return (1);
2337126258Smlaier			}
2338130613Smlaier		} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
2339130613Smlaier			rpool->tblidx = -1;
2340130613Smlaier			if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
2341130613Smlaier			    &rpool->tblidx, &rpool->counter,
2342130613Smlaier			    &raddr, &rmask, af)) {
2343130613Smlaier				/* table contains no address of type 'af' */
2344130613Smlaier				if (rpool->cur != acur)
2345130613Smlaier					goto try_next;
2346130613Smlaier				return (1);
2347130613Smlaier			}
2348126258Smlaier		} else {
2349126258Smlaier			raddr = &rpool->cur->addr.v.a.addr;
2350126258Smlaier			rmask = &rpool->cur->addr.v.a.mask;
2351126258Smlaier			PF_ACPY(&rpool->counter, raddr, af);
2352126258Smlaier		}
2353126258Smlaier
2354126258Smlaier	get_addr:
2355126258Smlaier		PF_ACPY(naddr, &rpool->counter, af);
2356139045Sdhartmei		if (init_addr != NULL && PF_AZERO(init_addr, af))
2357139045Sdhartmei			PF_ACPY(init_addr, naddr, af);
2358126258Smlaier		PF_AINC(&rpool->counter, af);
2359126258Smlaier		break;
2360126258Smlaier	}
2361130613Smlaier	if (*sn != NULL)
2362130613Smlaier		PF_ACPY(&(*sn)->raddr, naddr, af);
2363126258Smlaier
2364126258Smlaier	if (pf_status.debug >= PF_DEBUG_MISC &&
2365126258Smlaier	    (rpool->opts & PF_POOL_TYPEMASK) != PF_POOL_NONE) {
2366130613Smlaier		printf("pf_map_addr: selected address ");
2367126258Smlaier		pf_print_host(naddr, 0, af);
2368126258Smlaier		printf("\n");
2369126258Smlaier	}
2370126258Smlaier
2371126258Smlaier	return (0);
2372126258Smlaier}
2373126258Smlaier
2374126258Smlaierint
2375130613Smlaierpf_get_sport(sa_family_t af, u_int8_t proto, struct pf_rule *r,
2376126258Smlaier    struct pf_addr *saddr, struct pf_addr *daddr, u_int16_t dport,
2377130613Smlaier    struct pf_addr *naddr, u_int16_t *nport, u_int16_t low, u_int16_t high,
2378130613Smlaier    struct pf_src_node **sn)
2379126258Smlaier{
2380130613Smlaier	struct pf_state		key;
2381126258Smlaier	struct pf_addr		init_addr;
2382126258Smlaier	u_int16_t		cut;
2383126258Smlaier
2384126258Smlaier	bzero(&init_addr, sizeof(init_addr));
2385130613Smlaier	if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2386126258Smlaier		return (1);
2387126258Smlaier
2388149884Smlaier	if (proto == IPPROTO_ICMP) {
2389149884Smlaier		low = 1;
2390149884Smlaier		high = 65535;
2391149884Smlaier	}
2392149884Smlaier
2393126258Smlaier	do {
2394126258Smlaier		key.af = af;
2395126258Smlaier		key.proto = proto;
2396130613Smlaier		PF_ACPY(&key.ext.addr, daddr, key.af);
2397130613Smlaier		PF_ACPY(&key.gwy.addr, naddr, key.af);
2398130613Smlaier		key.ext.port = dport;
2399126258Smlaier
2400126258Smlaier		/*
2401126258Smlaier		 * port search; start random, step;
2402126258Smlaier		 * similar 2 portloop in in_pcbbind
2403126258Smlaier		 */
2404149884Smlaier		if (!(proto == IPPROTO_TCP || proto == IPPROTO_UDP ||
2405149884Smlaier		    proto == IPPROTO_ICMP)) {
2406139045Sdhartmei			key.gwy.port = dport;
2407130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2408126258Smlaier				return (0);
2409126258Smlaier		} else if (low == 0 && high == 0) {
2410130613Smlaier			key.gwy.port = *nport;
2411130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL)
2412126258Smlaier				return (0);
2413126258Smlaier		} else if (low == high) {
2414130613Smlaier			key.gwy.port = htons(low);
2415130613Smlaier			if (pf_find_state_all(&key, PF_EXT_GWY, NULL) == NULL) {
2416126258Smlaier				*nport = htons(low);
2417126258Smlaier				return (0);
2418126258Smlaier			}
2419126258Smlaier		} else {
2420126258Smlaier			u_int16_t tmp;
2421126258Smlaier
2422126258Smlaier			if (low > high) {
2423126258Smlaier				tmp = low;
2424126258Smlaier				low = high;
2425126258Smlaier				high = tmp;
2426126258Smlaier			}
2427126258Smlaier			/* low < high */
2428145836Smlaier			cut = htonl(arc4random()) % (1 + high - low) + low;
2429126258Smlaier			/* low <= cut <= high */
2430126258Smlaier			for (tmp = cut; tmp <= high; ++(tmp)) {
2431130613Smlaier				key.gwy.port = htons(tmp);
2432130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2433126258Smlaier				    NULL) {
2434126258Smlaier					*nport = htons(tmp);
2435126258Smlaier					return (0);
2436126258Smlaier				}
2437126258Smlaier			}
2438126258Smlaier			for (tmp = cut - 1; tmp >= low; --(tmp)) {
2439130613Smlaier				key.gwy.port = htons(tmp);
2440130613Smlaier				if (pf_find_state_all(&key, PF_EXT_GWY, NULL) ==
2441126258Smlaier				    NULL) {
2442126258Smlaier					*nport = htons(tmp);
2443126258Smlaier					return (0);
2444126258Smlaier				}
2445126258Smlaier			}
2446126258Smlaier		}
2447126258Smlaier
2448130613Smlaier		switch (r->rpool.opts & PF_POOL_TYPEMASK) {
2449126258Smlaier		case PF_POOL_RANDOM:
2450126258Smlaier		case PF_POOL_ROUNDROBIN:
2451130613Smlaier			if (pf_map_addr(af, r, saddr, naddr, &init_addr, sn))
2452126258Smlaier				return (1);
2453126258Smlaier			break;
2454126258Smlaier		case PF_POOL_NONE:
2455126258Smlaier		case PF_POOL_SRCHASH:
2456126258Smlaier		case PF_POOL_BITMASK:
2457126258Smlaier		default:
2458126258Smlaier			return (1);
2459126258Smlaier		}
2460126258Smlaier	} while (! PF_AEQ(&init_addr, naddr, af) );
2461126258Smlaier
2462126258Smlaier	return (1);					/* none available */
2463126258Smlaier}
2464126258Smlaier
2465126258Smlaierstruct pf_rule *
2466126258Smlaierpf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
2467130613Smlaier    int direction, struct pfi_kif *kif, struct pf_addr *saddr, u_int16_t sport,
2468126258Smlaier    struct pf_addr *daddr, u_int16_t dport, int rs_num)
2469126258Smlaier{
2470145836Smlaier	struct pf_rule		*r, *rm = NULL;
2471126258Smlaier	struct pf_ruleset	*ruleset = NULL;
2472145836Smlaier	struct pf_tag		*pftag = NULL;
2473145836Smlaier	int			 tag = -1;
2474145836Smlaier	int			 asd = 0;
2475126258Smlaier
2476126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[rs_num].active.ptr);
2477126258Smlaier	while (r && rm == NULL) {
2478126258Smlaier		struct pf_rule_addr	*src = NULL, *dst = NULL;
2479126258Smlaier		struct pf_addr_wrap	*xdst = NULL;
2480126258Smlaier
2481126258Smlaier		if (r->action == PF_BINAT && direction == PF_IN) {
2482126258Smlaier			src = &r->dst;
2483126258Smlaier			if (r->rpool.cur != NULL)
2484126258Smlaier				xdst = &r->rpool.cur->addr;
2485126258Smlaier		} else {
2486126258Smlaier			src = &r->src;
2487126258Smlaier			dst = &r->dst;
2488126258Smlaier		}
2489126258Smlaier
2490126258Smlaier		r->evaluations++;
2491130613Smlaier		if (r->kif != NULL &&
2492130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
2493126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
2494126258Smlaier		else if (r->direction && r->direction != direction)
2495126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
2496126258Smlaier		else if (r->af && r->af != pd->af)
2497126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
2498126258Smlaier		else if (r->proto && r->proto != pd->proto)
2499126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
2500145836Smlaier		else if (PF_MISMATCHAW(&src->addr, saddr, pd->af, src->neg))
2501126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
2502126258Smlaier			    PF_SKIP_DST_ADDR].ptr;
2503126258Smlaier		else if (src->port_op && !pf_match_port(src->port_op,
2504126258Smlaier		    src->port[0], src->port[1], sport))
2505126258Smlaier			r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
2506126258Smlaier			    PF_SKIP_DST_PORT].ptr;
2507126258Smlaier		else if (dst != NULL &&
2508145836Smlaier		    PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg))
2509126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
2510126258Smlaier		else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af, 0))
2511126258Smlaier			r = TAILQ_NEXT(r, entries);
2512126258Smlaier		else if (dst != NULL && dst->port_op &&
2513126258Smlaier		    !pf_match_port(dst->port_op, dst->port[0],
2514126258Smlaier		    dst->port[1], dport))
2515126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
2516145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
2517145836Smlaier			r = TAILQ_NEXT(r, entries);
2518126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && (pd->proto !=
2519126258Smlaier		    IPPROTO_TCP || !pf_osfp_match(pf_osfp_fingerprint(pd, m,
2520126258Smlaier		    off, pd->hdr.tcp), r->os_fingerprint)))
2521126258Smlaier			r = TAILQ_NEXT(r, entries);
2522145836Smlaier		else {
2523145836Smlaier			if (r->tag)
2524145836Smlaier				tag = r->tag;
2525145836Smlaier			if (r->anchor == NULL) {
2526126258Smlaier				rm = r;
2527145836Smlaier			} else
2528145836Smlaier				pf_step_into_anchor(&asd, &ruleset, rs_num, &r, NULL);
2529145836Smlaier		}
2530145836Smlaier		if (r == NULL)
2531145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset, rs_num, &r, NULL);
2532126258Smlaier	}
2533145836Smlaier	if (pf_tag_packet(m, pftag, tag))
2534145836Smlaier		return (NULL);
2535126258Smlaier	if (rm != NULL && (rm->action == PF_NONAT ||
2536126258Smlaier	    rm->action == PF_NORDR || rm->action == PF_NOBINAT))
2537126258Smlaier		return (NULL);
2538126258Smlaier	return (rm);
2539126258Smlaier}
2540126258Smlaier
2541126258Smlaierstruct pf_rule *
2542126258Smlaierpf_get_translation(struct pf_pdesc *pd, struct mbuf *m, int off, int direction,
2543130613Smlaier    struct pfi_kif *kif, struct pf_src_node **sn,
2544126258Smlaier    struct pf_addr *saddr, u_int16_t sport,
2545126258Smlaier    struct pf_addr *daddr, u_int16_t dport,
2546126258Smlaier    struct pf_addr *naddr, u_int16_t *nport)
2547126258Smlaier{
2548126258Smlaier	struct pf_rule	*r = NULL;
2549126258Smlaier
2550126258Smlaier	if (direction == PF_OUT) {
2551130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2552126258Smlaier		    sport, daddr, dport, PF_RULESET_BINAT);
2553126258Smlaier		if (r == NULL)
2554130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2555126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_NAT);
2556126258Smlaier	} else {
2557130613Smlaier		r = pf_match_translation(pd, m, off, direction, kif, saddr,
2558126258Smlaier		    sport, daddr, dport, PF_RULESET_RDR);
2559126258Smlaier		if (r == NULL)
2560130613Smlaier			r = pf_match_translation(pd, m, off, direction, kif,
2561126258Smlaier			    saddr, sport, daddr, dport, PF_RULESET_BINAT);
2562126258Smlaier	}
2563126258Smlaier
2564126258Smlaier	if (r != NULL) {
2565126258Smlaier		switch (r->action) {
2566126258Smlaier		case PF_NONAT:
2567126258Smlaier		case PF_NOBINAT:
2568126258Smlaier		case PF_NORDR:
2569126258Smlaier			return (NULL);
2570126258Smlaier		case PF_NAT:
2571130613Smlaier			if (pf_get_sport(pd->af, pd->proto, r, saddr,
2572126258Smlaier			    daddr, dport, naddr, nport, r->rpool.proxy_port[0],
2573130613Smlaier			    r->rpool.proxy_port[1], sn)) {
2574126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
2575126258Smlaier				    ("pf: NAT proxy port allocation "
2576126258Smlaier				    "(%u-%u) failed\n",
2577126258Smlaier				    r->rpool.proxy_port[0],
2578126258Smlaier				    r->rpool.proxy_port[1]));
2579126258Smlaier				return (NULL);
2580126258Smlaier			}
2581126258Smlaier			break;
2582126258Smlaier		case PF_BINAT:
2583126258Smlaier			switch (direction) {
2584126258Smlaier			case PF_OUT:
2585130613Smlaier				if (r->rpool.cur->addr.type == PF_ADDR_DYNIFTL){
2586145836Smlaier					switch (pd->af) {
2587145836Smlaier#ifdef INET
2588145836Smlaier					case AF_INET:
2589130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2590130613Smlaier						    pfid_acnt4 < 1)
2591130613Smlaier							return (NULL);
2592130613Smlaier						PF_POOLMASK(naddr,
2593130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2594130613Smlaier						    pfid_addr4,
2595130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2596130613Smlaier						    pfid_mask4,
2597130613Smlaier						    saddr, AF_INET);
2598145836Smlaier						break;
2599145836Smlaier#endif /* INET */
2600145836Smlaier#ifdef INET6
2601145836Smlaier					case AF_INET6:
2602130613Smlaier						if (r->rpool.cur->addr.p.dyn->
2603130613Smlaier						    pfid_acnt6 < 1)
2604130613Smlaier							return (NULL);
2605130613Smlaier						PF_POOLMASK(naddr,
2606130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2607130613Smlaier						    pfid_addr6,
2608130613Smlaier						    &r->rpool.cur->addr.p.dyn->
2609130613Smlaier						    pfid_mask6,
2610130613Smlaier						    saddr, AF_INET6);
2611145836Smlaier						break;
2612145836Smlaier#endif /* INET6 */
2613130613Smlaier					}
2614130613Smlaier				} else
2615126258Smlaier					PF_POOLMASK(naddr,
2616126258Smlaier					    &r->rpool.cur->addr.v.a.addr,
2617126258Smlaier					    &r->rpool.cur->addr.v.a.mask,
2618126258Smlaier					    saddr, pd->af);
2619126258Smlaier				break;
2620126258Smlaier			case PF_IN:
2621138041Sdhartmei				if (r->src.addr.type == PF_ADDR_DYNIFTL) {
2622145836Smlaier					switch (pd->af) {
2623145836Smlaier#ifdef INET
2624145836Smlaier					case AF_INET:
2625130613Smlaier						if (r->src.addr.p.dyn->
2626130613Smlaier						    pfid_acnt4 < 1)
2627130613Smlaier							return (NULL);
2628130613Smlaier						PF_POOLMASK(naddr,
2629130613Smlaier						    &r->src.addr.p.dyn->
2630130613Smlaier						    pfid_addr4,
2631130613Smlaier						    &r->src.addr.p.dyn->
2632130613Smlaier						    pfid_mask4,
2633130613Smlaier						    daddr, AF_INET);
2634145836Smlaier						break;
2635145836Smlaier#endif /* INET */
2636145836Smlaier#ifdef INET6
2637145836Smlaier					case AF_INET6:
2638130613Smlaier						if (r->src.addr.p.dyn->
2639130613Smlaier						    pfid_acnt6 < 1)
2640130613Smlaier							return (NULL);
2641130613Smlaier						PF_POOLMASK(naddr,
2642130613Smlaier						    &r->src.addr.p.dyn->
2643130613Smlaier						    pfid_addr6,
2644130613Smlaier						    &r->src.addr.p.dyn->
2645130613Smlaier						    pfid_mask6,
2646130613Smlaier						    daddr, AF_INET6);
2647145836Smlaier						break;
2648145836Smlaier#endif /* INET6 */
2649130613Smlaier					}
2650130613Smlaier				} else
2651126258Smlaier					PF_POOLMASK(naddr,
2652126258Smlaier					    &r->src.addr.v.a.addr,
2653126261Smlaier					    &r->src.addr.v.a.mask, daddr,
2654126258Smlaier					    pd->af);
2655126258Smlaier				break;
2656126258Smlaier			}
2657126258Smlaier			break;
2658126258Smlaier		case PF_RDR: {
2659140518Sdhartmei			if (pf_map_addr(pd->af, r, saddr, naddr, NULL, sn))
2660126258Smlaier				return (NULL);
2661149884Smlaier			if ((r->rpool.opts & PF_POOL_TYPEMASK) ==
2662149884Smlaier			    PF_POOL_BITMASK)
2663149884Smlaier				PF_POOLMASK(naddr, naddr,
2664149884Smlaier				    &r->rpool.cur->addr.v.a.mask, daddr,
2665149884Smlaier				    pd->af);
2666126258Smlaier
2667126258Smlaier			if (r->rpool.proxy_port[1]) {
2668126258Smlaier				u_int32_t	tmp_nport;
2669126258Smlaier
2670126258Smlaier				tmp_nport = ((ntohs(dport) -
2671126258Smlaier				    ntohs(r->dst.port[0])) %
2672126258Smlaier				    (r->rpool.proxy_port[1] -
2673126258Smlaier				    r->rpool.proxy_port[0] + 1)) +
2674126258Smlaier				    r->rpool.proxy_port[0];
2675126258Smlaier
2676126258Smlaier				/* wrap around if necessary */
2677126258Smlaier				if (tmp_nport > 65535)
2678126258Smlaier					tmp_nport -= 65535;
2679126258Smlaier				*nport = htons((u_int16_t)tmp_nport);
2680126258Smlaier			} else if (r->rpool.proxy_port[0])
2681126258Smlaier				*nport = htons(r->rpool.proxy_port[0]);
2682126258Smlaier			break;
2683126258Smlaier		}
2684126258Smlaier		default:
2685126258Smlaier			return (NULL);
2686126258Smlaier		}
2687126258Smlaier	}
2688126258Smlaier
2689126258Smlaier	return (r);
2690126258Smlaier}
2691126258Smlaier
2692126258Smlaierint
2693135920Smlaier#ifdef __FreeBSD__
2694135920Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd,
2695135920Smlaier    struct inpcb *inp_arg)
2696135920Smlaier#else
2697130613Smlaierpf_socket_lookup(uid_t *uid, gid_t *gid, int direction, struct pf_pdesc *pd)
2698135920Smlaier#endif
2699126258Smlaier{
2700126258Smlaier	struct pf_addr		*saddr, *daddr;
2701126258Smlaier	u_int16_t		 sport, dport;
2702127145Smlaier#ifdef __FreeBSD__
2703126261Smlaier	struct inpcbinfo	*pi;
2704126261Smlaier#else
2705126258Smlaier	struct inpcbtable	*tb;
2706126261Smlaier#endif
2707126258Smlaier	struct inpcb		*inp;
2708126258Smlaier
2709126258Smlaier	*uid = UID_MAX;
2710126258Smlaier	*gid = GID_MAX;
2711135920Smlaier#ifdef __FreeBSD__
2712135920Smlaier	if (inp_arg != NULL) {
2713135920Smlaier		INP_LOCK_ASSERT(inp_arg);
2714135920Smlaier		if (inp_arg->inp_socket) {
2715135920Smlaier			*uid = inp_arg->inp_socket->so_cred->cr_uid;
2716135920Smlaier			*gid = inp_arg->inp_socket->so_cred->cr_groups[0];
2717135920Smlaier			return (1);
2718135920Smlaier		} else
2719135920Smlaier			return (0);
2720135920Smlaier	}
2721135920Smlaier#endif
2722130613Smlaier	switch (pd->proto) {
2723126258Smlaier	case IPPROTO_TCP:
2724126258Smlaier		sport = pd->hdr.tcp->th_sport;
2725126258Smlaier		dport = pd->hdr.tcp->th_dport;
2726127145Smlaier#ifdef __FreeBSD__
2727126261Smlaier		pi = &tcbinfo;
2728126261Smlaier#else
2729126258Smlaier		tb = &tcbtable;
2730126261Smlaier#endif
2731126258Smlaier		break;
2732126258Smlaier	case IPPROTO_UDP:
2733126258Smlaier		sport = pd->hdr.udp->uh_sport;
2734126258Smlaier		dport = pd->hdr.udp->uh_dport;
2735127145Smlaier#ifdef __FreeBSD__
2736126261Smlaier		pi = &udbinfo;
2737126261Smlaier#else
2738126258Smlaier		tb = &udbtable;
2739126261Smlaier#endif
2740126258Smlaier		break;
2741126258Smlaier	default:
2742126258Smlaier		return (0);
2743126258Smlaier	}
2744126258Smlaier	if (direction == PF_IN) {
2745126258Smlaier		saddr = pd->src;
2746126258Smlaier		daddr = pd->dst;
2747126258Smlaier	} else {
2748126258Smlaier		u_int16_t	p;
2749126258Smlaier
2750126258Smlaier		p = sport;
2751126258Smlaier		sport = dport;
2752126258Smlaier		dport = p;
2753126258Smlaier		saddr = pd->dst;
2754126258Smlaier		daddr = pd->src;
2755126258Smlaier	}
2756130613Smlaier	switch (pd->af) {
2757145836Smlaier#ifdef INET
2758126258Smlaier	case AF_INET:
2759127145Smlaier#ifdef __FreeBSD__
2760126261Smlaier		INP_INFO_RLOCK(pi);	/* XXX LOR */
2761126261Smlaier		inp = in_pcblookup_hash(pi, saddr->v4, sport, daddr->v4,
2762126261Smlaier			dport, 0, NULL);
2763126261Smlaier		if (inp == NULL) {
2764126261Smlaier			inp = in_pcblookup_hash(pi, saddr->v4, sport,
2765126261Smlaier			   daddr->v4, dport, INPLOOKUP_WILDCARD, NULL);
2766126261Smlaier			if(inp == NULL) {
2767126261Smlaier				INP_INFO_RUNLOCK(pi);
2768126261Smlaier				return (0);
2769126261Smlaier			}
2770126261Smlaier		}
2771126261Smlaier#else
2772126258Smlaier		inp = in_pcbhashlookup(tb, saddr->v4, sport, daddr->v4, dport);
2773126258Smlaier		if (inp == NULL) {
2774130613Smlaier			inp = in_pcblookup_listen(tb, daddr->v4, dport, 0);
2775126258Smlaier			if (inp == NULL)
2776126258Smlaier				return (0);
2777126258Smlaier		}
2778126261Smlaier#endif
2779126258Smlaier		break;
2780145836Smlaier#endif /* INET */
2781126258Smlaier#ifdef INET6
2782126258Smlaier	case AF_INET6:
2783127145Smlaier#ifdef __FreeBSD__
2784126261Smlaier		INP_INFO_RLOCK(pi);
2785126261Smlaier		inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2786126261Smlaier			&daddr->v6, dport, 0, NULL);
2787126261Smlaier		if (inp == NULL) {
2788126261Smlaier			inp = in6_pcblookup_hash(pi, &saddr->v6, sport,
2789126261Smlaier			&daddr->v6, dport, INPLOOKUP_WILDCARD, NULL);
2790126261Smlaier			if (inp == NULL) {
2791126261Smlaier				INP_INFO_RUNLOCK(pi);
2792126261Smlaier				return (0);
2793126261Smlaier			}
2794126261Smlaier		}
2795126261Smlaier#else
2796126258Smlaier		inp = in6_pcbhashlookup(tb, &saddr->v6, sport, &daddr->v6,
2797126258Smlaier		    dport);
2798126258Smlaier		if (inp == NULL) {
2799130613Smlaier			inp = in6_pcblookup_listen(tb, &daddr->v6, dport, 0);
2800126258Smlaier			if (inp == NULL)
2801126258Smlaier				return (0);
2802126258Smlaier		}
2803126261Smlaier#endif
2804126258Smlaier		break;
2805126258Smlaier#endif /* INET6 */
2806126258Smlaier
2807126258Smlaier	default:
2808126258Smlaier		return (0);
2809126258Smlaier	}
2810127145Smlaier#ifdef __FreeBSD__
2811126261Smlaier	INP_LOCK(inp);
2812136925Smlaier	if ((inp->inp_socket == NULL) || (inp->inp_socket->so_cred == NULL)) {
2813136925Smlaier		INP_UNLOCK(inp);
2814136925Smlaier		INP_INFO_RUNLOCK(pi);
2815136925Smlaier		return (0);
2816136925Smlaier	}
2817126261Smlaier	*uid = inp->inp_socket->so_cred->cr_uid;
2818126261Smlaier	*gid = inp->inp_socket->so_cred->cr_groups[0];
2819126261Smlaier	INP_UNLOCK(inp);
2820126261Smlaier	INP_INFO_RUNLOCK(pi);
2821126261Smlaier#else
2822126258Smlaier	*uid = inp->inp_socket->so_euid;
2823126258Smlaier	*gid = inp->inp_socket->so_egid;
2824126261Smlaier#endif
2825126258Smlaier	return (1);
2826126258Smlaier}
2827126258Smlaier
2828126258Smlaieru_int8_t
2829126258Smlaierpf_get_wscale(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2830126258Smlaier{
2831126258Smlaier	int		 hlen;
2832126258Smlaier	u_int8_t	 hdr[60];
2833126258Smlaier	u_int8_t	*opt, optlen;
2834126258Smlaier	u_int8_t	 wscale = 0;
2835126258Smlaier
2836126258Smlaier	hlen = th_off << 2;		/* hlen <= sizeof(hdr) */
2837126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2838126258Smlaier		return (0);
2839126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2840126258Smlaier		return (0);
2841126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2842126258Smlaier	hlen -= sizeof(struct tcphdr);
2843126258Smlaier	while (hlen >= 3) {
2844126258Smlaier		switch (*opt) {
2845126258Smlaier		case TCPOPT_EOL:
2846126258Smlaier		case TCPOPT_NOP:
2847126258Smlaier			++opt;
2848126258Smlaier			--hlen;
2849126258Smlaier			break;
2850126258Smlaier		case TCPOPT_WINDOW:
2851126258Smlaier			wscale = opt[2];
2852126258Smlaier			if (wscale > TCP_MAX_WINSHIFT)
2853126258Smlaier				wscale = TCP_MAX_WINSHIFT;
2854126258Smlaier			wscale |= PF_WSCALE_FLAG;
2855130613Smlaier			/* FALLTHROUGH */
2856126258Smlaier		default:
2857126258Smlaier			optlen = opt[1];
2858126258Smlaier			if (optlen < 2)
2859126258Smlaier				optlen = 2;
2860126258Smlaier			hlen -= optlen;
2861126258Smlaier			opt += optlen;
2862130613Smlaier			break;
2863126258Smlaier		}
2864126258Smlaier	}
2865126258Smlaier	return (wscale);
2866126258Smlaier}
2867126258Smlaier
2868126258Smlaieru_int16_t
2869126258Smlaierpf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
2870126258Smlaier{
2871126258Smlaier	int		 hlen;
2872126258Smlaier	u_int8_t	 hdr[60];
2873126258Smlaier	u_int8_t	*opt, optlen;
2874126258Smlaier	u_int16_t	 mss = tcp_mssdflt;
2875126258Smlaier
2876126258Smlaier	hlen = th_off << 2;	/* hlen <= sizeof(hdr) */
2877126258Smlaier	if (hlen <= sizeof(struct tcphdr))
2878126258Smlaier		return (0);
2879126258Smlaier	if (!pf_pull_hdr(m, off, hdr, hlen, NULL, NULL, af))
2880126258Smlaier		return (0);
2881126258Smlaier	opt = hdr + sizeof(struct tcphdr);
2882126258Smlaier	hlen -= sizeof(struct tcphdr);
2883126258Smlaier	while (hlen >= TCPOLEN_MAXSEG) {
2884126258Smlaier		switch (*opt) {
2885126258Smlaier		case TCPOPT_EOL:
2886126258Smlaier		case TCPOPT_NOP:
2887126258Smlaier			++opt;
2888126258Smlaier			--hlen;
2889126258Smlaier			break;
2890126258Smlaier		case TCPOPT_MAXSEG:
2891126258Smlaier			bcopy((caddr_t)(opt + 2), (caddr_t)&mss, 2);
2892145030Sglebius			NTOHS(mss);
2893130613Smlaier			/* FALLTHROUGH */
2894126258Smlaier		default:
2895126258Smlaier			optlen = opt[1];
2896126258Smlaier			if (optlen < 2)
2897126258Smlaier				optlen = 2;
2898126258Smlaier			hlen -= optlen;
2899126258Smlaier			opt += optlen;
2900130613Smlaier			break;
2901126258Smlaier		}
2902126258Smlaier	}
2903126258Smlaier	return (mss);
2904126258Smlaier}
2905126258Smlaier
2906126258Smlaieru_int16_t
2907126258Smlaierpf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
2908126258Smlaier{
2909126258Smlaier#ifdef INET
2910126258Smlaier	struct sockaddr_in	*dst;
2911126258Smlaier	struct route		 ro;
2912126258Smlaier#endif /* INET */
2913126258Smlaier#ifdef INET6
2914126258Smlaier	struct sockaddr_in6	*dst6;
2915126258Smlaier	struct route_in6	 ro6;
2916126258Smlaier#endif /* INET6 */
2917126258Smlaier	struct rtentry		*rt = NULL;
2918127629Smlaier	int			 hlen = 0;	/* make the compiler happy */
2919126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
2920126258Smlaier
2921126258Smlaier	switch (af) {
2922126258Smlaier#ifdef INET
2923126258Smlaier	case AF_INET:
2924126258Smlaier		hlen = sizeof(struct ip);
2925126258Smlaier		bzero(&ro, sizeof(ro));
2926126258Smlaier		dst = (struct sockaddr_in *)&ro.ro_dst;
2927126258Smlaier		dst->sin_family = AF_INET;
2928126258Smlaier		dst->sin_len = sizeof(*dst);
2929126258Smlaier		dst->sin_addr = addr->v4;
2930127145Smlaier#ifdef __FreeBSD__
2931126261Smlaier#ifdef RTF_PRCLONING
2932126261Smlaier		rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
2933126261Smlaier#else /* !RTF_PRCLONING */
2934126261Smlaier		rtalloc_ign(&ro, RTF_CLONING);
2935126261Smlaier#endif
2936126261Smlaier#else /* ! __FreeBSD__ */
2937126258Smlaier		rtalloc_noclone(&ro, NO_CLONING);
2938126261Smlaier#endif
2939126258Smlaier		rt = ro.ro_rt;
2940126258Smlaier		break;
2941126258Smlaier#endif /* INET */
2942126258Smlaier#ifdef INET6
2943126258Smlaier	case AF_INET6:
2944126258Smlaier		hlen = sizeof(struct ip6_hdr);
2945126258Smlaier		bzero(&ro6, sizeof(ro6));
2946126258Smlaier		dst6 = (struct sockaddr_in6 *)&ro6.ro_dst;
2947126258Smlaier		dst6->sin6_family = AF_INET6;
2948126258Smlaier		dst6->sin6_len = sizeof(*dst6);
2949126258Smlaier		dst6->sin6_addr = addr->v6;
2950127145Smlaier#ifdef __FreeBSD__
2951126261Smlaier#ifdef RTF_PRCLONING
2952126261Smlaier		rtalloc_ign((struct route *)&ro6,
2953126261Smlaier		    (RTF_CLONING | RTF_PRCLONING));
2954126261Smlaier#else /* !RTF_PRCLONING */
2955126261Smlaier		rtalloc_ign((struct route *)&ro6, RTF_CLONING);
2956126261Smlaier#endif
2957126261Smlaier#else /* ! __FreeBSD__ */
2958126258Smlaier		rtalloc_noclone((struct route *)&ro6, NO_CLONING);
2959126261Smlaier#endif
2960126258Smlaier		rt = ro6.ro_rt;
2961126258Smlaier		break;
2962126258Smlaier#endif /* INET6 */
2963126258Smlaier	}
2964126258Smlaier
2965126258Smlaier	if (rt && rt->rt_ifp) {
2966126258Smlaier		mss = rt->rt_ifp->if_mtu - hlen - sizeof(struct tcphdr);
2967126258Smlaier		mss = max(tcp_mssdflt, mss);
2968126258Smlaier		RTFREE(rt);
2969126258Smlaier	}
2970126258Smlaier	mss = min(mss, offer);
2971126258Smlaier	mss = max(mss, 64);		/* sanity - at least max opt space */
2972126258Smlaier	return (mss);
2973126258Smlaier}
2974126258Smlaier
2975126258Smlaiervoid
2976126258Smlaierpf_set_rt_ifp(struct pf_state *s, struct pf_addr *saddr)
2977126258Smlaier{
2978126258Smlaier	struct pf_rule *r = s->rule.ptr;
2979126258Smlaier
2980130613Smlaier	s->rt_kif = NULL;
2981126258Smlaier	if (!r->rt || r->rt == PF_FASTROUTE)
2982126258Smlaier		return;
2983126258Smlaier	switch (s->af) {
2984126258Smlaier#ifdef INET
2985126258Smlaier	case AF_INET:
2986130613Smlaier		pf_map_addr(AF_INET, r, saddr, &s->rt_addr, NULL,
2987130613Smlaier		    &s->nat_src_node);
2988130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2989126258Smlaier		break;
2990126258Smlaier#endif /* INET */
2991126258Smlaier#ifdef INET6
2992126258Smlaier	case AF_INET6:
2993130613Smlaier		pf_map_addr(AF_INET6, r, saddr, &s->rt_addr, NULL,
2994130613Smlaier		    &s->nat_src_node);
2995130613Smlaier		s->rt_kif = r->rpool.cur->kif;
2996126258Smlaier		break;
2997126258Smlaier#endif /* INET6 */
2998126258Smlaier	}
2999126258Smlaier}
3000126258Smlaier
3001126258Smlaierint
3002126258Smlaierpf_test_tcp(struct pf_rule **rm, struct pf_state **sm, int direction,
3003130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3004135920Smlaier#ifdef __FreeBSD__
3005135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3006145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3007135920Smlaier#else
3008145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3009145836Smlaier    struct ifqueue *ifq)
3010135920Smlaier#endif
3011126258Smlaier{
3012130613Smlaier	struct pf_rule		*nr = NULL;
3013126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3014126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
3015126258Smlaier	u_int16_t		 bport, nport = 0;
3016126258Smlaier	sa_family_t		 af = pd->af;
3017126258Smlaier	int			 lookup = -1;
3018126258Smlaier	uid_t			 uid;
3019126258Smlaier	gid_t			 gid;
3020126258Smlaier	struct pf_rule		*r, *a = NULL;
3021126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3022130613Smlaier	struct pf_src_node	*nsn = NULL;
3023126258Smlaier	u_short			 reason;
3024126258Smlaier	int			 rewrite = 0;
3025126258Smlaier	struct pf_tag		*pftag = NULL;
3026126258Smlaier	int			 tag = -1;
3027126258Smlaier	u_int16_t		 mss = tcp_mssdflt;
3028145836Smlaier	int			 asd = 0;
3029126258Smlaier
3030145836Smlaier	if (pf_check_congestion(ifq)) {
3031145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3032145836Smlaier		return (PF_DROP);
3033145836Smlaier	}
3034145836Smlaier
3035126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3036126258Smlaier
3037126258Smlaier	if (direction == PF_OUT) {
3038126258Smlaier		bport = nport = th->th_sport;
3039126258Smlaier		/* check outgoing packet for BINAT/NAT */
3040130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3041126258Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3042130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3043130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3044126258Smlaier			pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3045130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3046126258Smlaier			rewrite++;
3047130613Smlaier			if (nr->natpass)
3048126258Smlaier				r = NULL;
3049130613Smlaier			pd->nat_rule = nr;
3050126258Smlaier		}
3051126258Smlaier	} else {
3052126258Smlaier		bport = nport = th->th_dport;
3053126258Smlaier		/* check incoming packet for BINAT/RDR */
3054130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3055130613Smlaier		    saddr, th->th_sport, daddr, th->th_dport,
3056130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3057130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3058126258Smlaier			pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3059130613Smlaier			    &th->th_sum, &pd->naddr, nport, 0, af);
3060126258Smlaier			rewrite++;
3061130613Smlaier			if (nr->natpass)
3062126258Smlaier				r = NULL;
3063130613Smlaier			pd->nat_rule = nr;
3064126258Smlaier		}
3065126258Smlaier	}
3066126258Smlaier
3067126258Smlaier	while (r != NULL) {
3068126258Smlaier		r->evaluations++;
3069130613Smlaier		if (r->kif != NULL &&
3070130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3071126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3072126258Smlaier		else if (r->direction && r->direction != direction)
3073126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3074126258Smlaier		else if (r->af && r->af != af)
3075126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3076126258Smlaier		else if (r->proto && r->proto != IPPROTO_TCP)
3077126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3078145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3079126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3080126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3081126258Smlaier		    r->src.port[0], r->src.port[1], th->th_sport))
3082126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3083145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3084126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3085126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3086126258Smlaier		    r->dst.port[0], r->dst.port[1], th->th_dport))
3087126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3088126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3089126258Smlaier			r = TAILQ_NEXT(r, entries);
3090126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3091126258Smlaier			r = TAILQ_NEXT(r, entries);
3092126258Smlaier		else if ((r->flagset & th->th_flags) != r->flags)
3093126258Smlaier			r = TAILQ_NEXT(r, entries);
3094126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
3095135920Smlaier#ifdef __FreeBSD__
3096135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3097135920Smlaier#else
3098130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3099135920Smlaier#endif
3100126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3101126258Smlaier		    uid))
3102126258Smlaier			r = TAILQ_NEXT(r, entries);
3103126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
3104135920Smlaier#ifdef __FreeBSD__
3105135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3106135920Smlaier#else
3107130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3108135920Smlaier#endif
3109126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3110126258Smlaier		    gid))
3111126258Smlaier			r = TAILQ_NEXT(r, entries);
3112145836Smlaier		else if (r->prob && r->prob <= arc4random())
3113126258Smlaier			r = TAILQ_NEXT(r, entries);
3114145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3115126258Smlaier			r = TAILQ_NEXT(r, entries);
3116126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY && !pf_osfp_match(
3117126258Smlaier		    pf_osfp_fingerprint(pd, m, off, th), r->os_fingerprint))
3118126258Smlaier			r = TAILQ_NEXT(r, entries);
3119126258Smlaier		else {
3120126258Smlaier			if (r->tag)
3121126258Smlaier				tag = r->tag;
3122126258Smlaier			if (r->anchor == NULL) {
3123126258Smlaier				*rm = r;
3124126258Smlaier				*am = a;
3125126258Smlaier				*rsm = ruleset;
3126126258Smlaier				if ((*rm)->quick)
3127126258Smlaier					break;
3128126258Smlaier				r = TAILQ_NEXT(r, entries);
3129126258Smlaier			} else
3130145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3131145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3132126258Smlaier		}
3133145836Smlaier		if (r == NULL)
3134145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3135145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3136126258Smlaier	}
3137126258Smlaier	r = *rm;
3138126258Smlaier	a = *am;
3139126258Smlaier	ruleset = *rsm;
3140126258Smlaier
3141126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3142126258Smlaier
3143126258Smlaier	if (r->log) {
3144126258Smlaier		if (rewrite)
3145126261Smlaier			m_copyback(m, off, sizeof(*th), (caddr_t)th);
3146130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3147126258Smlaier	}
3148126258Smlaier
3149126258Smlaier	if ((r->action == PF_DROP) &&
3150126258Smlaier	    ((r->rule_flag & PFRULE_RETURNRST) ||
3151126258Smlaier	    (r->rule_flag & PFRULE_RETURNICMP) ||
3152126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3153126258Smlaier		/* undo NAT changes, if they have taken place */
3154130613Smlaier		if (nr != NULL) {
3155130613Smlaier			if (direction == PF_OUT) {
3156130613Smlaier				pf_change_ap(saddr, &th->th_sport, pd->ip_sum,
3157130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3158130613Smlaier				rewrite++;
3159130613Smlaier			} else {
3160130613Smlaier				pf_change_ap(daddr, &th->th_dport, pd->ip_sum,
3161130613Smlaier				    &th->th_sum, &pd->baddr, bport, 0, af);
3162130613Smlaier				rewrite++;
3163130613Smlaier			}
3164126258Smlaier		}
3165126258Smlaier		if (((r->rule_flag & PFRULE_RETURNRST) ||
3166126258Smlaier		    (r->rule_flag & PFRULE_RETURN)) &&
3167126258Smlaier		    !(th->th_flags & TH_RST)) {
3168126258Smlaier			u_int32_t ack = ntohl(th->th_seq) + pd->p_len;
3169126258Smlaier
3170126258Smlaier			if (th->th_flags & TH_SYN)
3171126258Smlaier				ack++;
3172126258Smlaier			if (th->th_flags & TH_FIN)
3173126258Smlaier				ack++;
3174162238Scsjp#ifdef __FreeBSD__
3175162238Scsjp			pf_send_tcp(m, r, af, pd->dst,
3176162238Scsjp#else
3177126258Smlaier			pf_send_tcp(r, af, pd->dst,
3178162238Scsjp#endif
3179126258Smlaier			    pd->src, th->th_dport, th->th_sport,
3180126258Smlaier			    ntohl(th->th_ack), ack, TH_RST|TH_ACK, 0, 0,
3181145836Smlaier			    r->return_ttl, 1, pd->eh, kif->pfik_ifp);
3182126258Smlaier		} else if ((af == AF_INET) && r->return_icmp)
3183126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3184126258Smlaier			    r->return_icmp & 255, af, r);
3185126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3186126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3187126258Smlaier			    r->return_icmp6 & 255, af, r);
3188126258Smlaier	}
3189126258Smlaier
3190126258Smlaier	if (r->action == PF_DROP)
3191126258Smlaier		return (PF_DROP);
3192126258Smlaier
3193126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3194126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3195126258Smlaier		return (PF_DROP);
3196126258Smlaier	}
3197126258Smlaier
3198130613Smlaier	if (r->keep_state || nr != NULL ||
3199126258Smlaier	    (pd->flags & PFDESC_TCP_NORM)) {
3200126258Smlaier		/* create new state */
3201126258Smlaier		u_int16_t	 len;
3202126258Smlaier		struct pf_state	*s = NULL;
3203130613Smlaier		struct pf_src_node *sn = NULL;
3204126258Smlaier
3205126258Smlaier		len = pd->tot_len - off - (th->th_off << 2);
3206130613Smlaier
3207130613Smlaier		/* check maximums */
3208145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3209145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3210145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3211130613Smlaier			goto cleanup;
3212145836Smlaier		}
3213130613Smlaier		/* src node for flter rule */
3214130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3215130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3216145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3217145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3218130613Smlaier			goto cleanup;
3219145836Smlaier		}
3220130613Smlaier		/* src node for translation rule */
3221130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3222130613Smlaier		    ((direction == PF_OUT &&
3223130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3224145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3225145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3226130613Smlaier			goto cleanup;
3227145836Smlaier		}
3228130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3229126258Smlaier		if (s == NULL) {
3230145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3231130613Smlaiercleanup:
3232130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3233130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3234130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3235130613Smlaier				pf_status.src_nodes--;
3236130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3237130613Smlaier			}
3238130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3239130613Smlaier			    nsn->expire == 0) {
3240130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3241130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3242130613Smlaier				pf_status.src_nodes--;
3243130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3244130613Smlaier			}
3245126258Smlaier			return (PF_DROP);
3246126258Smlaier		}
3247126258Smlaier		bzero(s, sizeof(*s));
3248126258Smlaier		s->rule.ptr = r;
3249130613Smlaier		s->nat_rule.ptr = nr;
3250126258Smlaier		s->anchor.ptr = a;
3251145836Smlaier		STATE_INC_COUNTERS(s);
3252126258Smlaier		s->allow_opts = r->allow_opts;
3253126258Smlaier		s->log = r->log & 2;
3254126258Smlaier		s->proto = IPPROTO_TCP;
3255126258Smlaier		s->direction = direction;
3256126258Smlaier		s->af = af;
3257126258Smlaier		if (direction == PF_OUT) {
3258126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3259126258Smlaier			s->gwy.port = th->th_sport;		/* sport */
3260126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3261126258Smlaier			s->ext.port = th->th_dport;
3262130613Smlaier			if (nr != NULL) {
3263130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3264126258Smlaier				s->lan.port = bport;
3265126258Smlaier			} else {
3266126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3267126258Smlaier				s->lan.port = s->gwy.port;
3268126258Smlaier			}
3269126258Smlaier		} else {
3270126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3271126258Smlaier			s->lan.port = th->th_dport;
3272126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3273126258Smlaier			s->ext.port = th->th_sport;
3274130613Smlaier			if (nr != NULL) {
3275130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3276126258Smlaier				s->gwy.port = bport;
3277126258Smlaier			} else {
3278126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3279126258Smlaier				s->gwy.port = s->lan.port;
3280126258Smlaier			}
3281126258Smlaier		}
3282126258Smlaier
3283126258Smlaier		s->src.seqlo = ntohl(th->th_seq);
3284126258Smlaier		s->src.seqhi = s->src.seqlo + len + 1;
3285126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3286126258Smlaier		    r->keep_state == PF_STATE_MODULATE) {
3287126258Smlaier			/* Generate sequence number modulator */
3288145836Smlaier			while ((s->src.seqdiff = htonl(arc4random())) == 0)
3289126258Smlaier				;
3290126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum,
3291126258Smlaier			    htonl(s->src.seqlo + s->src.seqdiff), 0);
3292126258Smlaier			rewrite = 1;
3293126258Smlaier		} else
3294126258Smlaier			s->src.seqdiff = 0;
3295126258Smlaier		if (th->th_flags & TH_SYN) {
3296126258Smlaier			s->src.seqhi++;
3297126258Smlaier			s->src.wscale = pf_get_wscale(m, off, th->th_off, af);
3298126258Smlaier		}
3299126258Smlaier		s->src.max_win = MAX(ntohs(th->th_win), 1);
3300126258Smlaier		if (s->src.wscale & PF_WSCALE_MASK) {
3301126258Smlaier			/* Remove scale factor from initial window */
3302126258Smlaier			int win = s->src.max_win;
3303126258Smlaier			win += 1 << (s->src.wscale & PF_WSCALE_MASK);
3304126258Smlaier			s->src.max_win = (win - 1) >>
3305126258Smlaier			    (s->src.wscale & PF_WSCALE_MASK);
3306126258Smlaier		}
3307126258Smlaier		if (th->th_flags & TH_FIN)
3308126258Smlaier			s->src.seqhi++;
3309126258Smlaier		s->dst.seqhi = 1;
3310126258Smlaier		s->dst.max_win = 1;
3311126258Smlaier		s->src.state = TCPS_SYN_SENT;
3312126258Smlaier		s->dst.state = TCPS_CLOSED;
3313126261Smlaier		s->creation = time_second;
3314126261Smlaier		s->expire = time_second;
3315126258Smlaier		s->timeout = PFTM_TCP_FIRST_PACKET;
3316126258Smlaier		pf_set_rt_ifp(s, saddr);
3317130613Smlaier		if (sn != NULL) {
3318130613Smlaier			s->src_node = sn;
3319130613Smlaier			s->src_node->states++;
3320130613Smlaier		}
3321130613Smlaier		if (nsn != NULL) {
3322130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3323130613Smlaier			s->nat_src_node = nsn;
3324130613Smlaier			s->nat_src_node->states++;
3325130613Smlaier		}
3326126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m,
3327126258Smlaier		    off, pd, th, &s->src, &s->dst)) {
3328126258Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3329130613Smlaier			pf_src_tree_remove_state(s);
3330145836Smlaier			STATE_DEC_COUNTERS(s);
3331126258Smlaier			pool_put(&pf_state_pl, s);
3332126258Smlaier			return (PF_DROP);
3333126258Smlaier		}
3334126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM) && s->src.scrub &&
3335145836Smlaier		    pf_normalize_tcp_stateful(m, off, pd, &reason, th, s,
3336145836Smlaier		    &s->src, &s->dst, &rewrite)) {
3337145836Smlaier			/* This really shouldn't happen!!! */
3338145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
3339145836Smlaier			    ("pf_normalize_tcp_stateful failed on first pkt"));
3340126258Smlaier			pf_normalize_tcp_cleanup(s);
3341130613Smlaier			pf_src_tree_remove_state(s);
3342145836Smlaier			STATE_DEC_COUNTERS(s);
3343126258Smlaier			pool_put(&pf_state_pl, s);
3344126258Smlaier			return (PF_DROP);
3345126258Smlaier		}
3346130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3347126258Smlaier			pf_normalize_tcp_cleanup(s);
3348145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3349130613Smlaier			pf_src_tree_remove_state(s);
3350145836Smlaier			STATE_DEC_COUNTERS(s);
3351126258Smlaier			pool_put(&pf_state_pl, s);
3352126258Smlaier			return (PF_DROP);
3353126258Smlaier		} else
3354126258Smlaier			*sm = s;
3355145836Smlaier		if (tag > 0) {
3356145836Smlaier			pf_tag_ref(tag);
3357145836Smlaier			s->tag = tag;
3358145836Smlaier		}
3359126258Smlaier		if ((th->th_flags & (TH_SYN|TH_ACK)) == TH_SYN &&
3360126258Smlaier		    r->keep_state == PF_STATE_SYNPROXY) {
3361126258Smlaier			s->src.state = PF_TCPS_PROXY_SRC;
3362130613Smlaier			if (nr != NULL) {
3363130613Smlaier				if (direction == PF_OUT) {
3364130613Smlaier					pf_change_ap(saddr, &th->th_sport,
3365130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3366130613Smlaier					    bport, 0, af);
3367130613Smlaier				} else {
3368130613Smlaier					pf_change_ap(daddr, &th->th_dport,
3369130613Smlaier					    pd->ip_sum, &th->th_sum, &pd->baddr,
3370130613Smlaier					    bport, 0, af);
3371130613Smlaier				}
3372130613Smlaier			}
3373145836Smlaier			s->src.seqhi = htonl(arc4random());
3374126258Smlaier			/* Find mss option */
3375126258Smlaier			mss = pf_get_mss(m, off, th->th_off, af);
3376126258Smlaier			mss = pf_calc_mss(saddr, af, mss);
3377126258Smlaier			mss = pf_calc_mss(daddr, af, mss);
3378126258Smlaier			s->src.mss = mss;
3379162238Scsjp#ifdef __FreeBSD__
3380162238Scsjp			pf_send_tcp(NULL, r, af, daddr, saddr, th->th_dport,
3381162238Scsjp#else
3382126258Smlaier			pf_send_tcp(r, af, daddr, saddr, th->th_dport,
3383162238Scsjp#endif
3384130613Smlaier			    th->th_sport, s->src.seqhi, ntohl(th->th_seq) + 1,
3385145836Smlaier			    TH_SYN|TH_ACK, 0, s->src.mss, 0, 1, NULL, NULL);
3386145836Smlaier			REASON_SET(&reason, PFRES_SYNPROXY);
3387126258Smlaier			return (PF_SYNPROXY_DROP);
3388126258Smlaier		}
3389126258Smlaier	}
3390126258Smlaier
3391126258Smlaier	/* copy back packet headers if we performed NAT operations */
3392126258Smlaier	if (rewrite)
3393126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
3394126258Smlaier
3395126258Smlaier	return (PF_PASS);
3396126258Smlaier}
3397126258Smlaier
3398126258Smlaierint
3399126258Smlaierpf_test_udp(struct pf_rule **rm, struct pf_state **sm, int direction,
3400130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3401135920Smlaier#ifdef __FreeBSD__
3402135920Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3403145836Smlaier    struct ifqueue *ifq, struct inpcb *inp)
3404135920Smlaier#else
3405145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3406145836Smlaier    struct ifqueue *ifq)
3407135920Smlaier#endif
3408126258Smlaier{
3409130613Smlaier	struct pf_rule		*nr = NULL;
3410126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3411126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
3412126258Smlaier	u_int16_t		 bport, nport = 0;
3413126258Smlaier	sa_family_t		 af = pd->af;
3414126258Smlaier	int			 lookup = -1;
3415126258Smlaier	uid_t			 uid;
3416126258Smlaier	gid_t			 gid;
3417126258Smlaier	struct pf_rule		*r, *a = NULL;
3418126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3419130613Smlaier	struct pf_src_node	*nsn = NULL;
3420126258Smlaier	u_short			 reason;
3421126258Smlaier	int			 rewrite = 0;
3422126258Smlaier	struct pf_tag		*pftag = NULL;
3423126258Smlaier	int			 tag = -1;
3424145836Smlaier	int			 asd = 0;
3425126258Smlaier
3426145836Smlaier	if (pf_check_congestion(ifq)) {
3427145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3428145836Smlaier		return (PF_DROP);
3429145836Smlaier	}
3430145836Smlaier
3431126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3432126258Smlaier
3433126258Smlaier	if (direction == PF_OUT) {
3434126258Smlaier		bport = nport = uh->uh_sport;
3435126258Smlaier		/* check outgoing packet for BINAT/NAT */
3436130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3437126258Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport,
3438130613Smlaier		    &pd->naddr, &nport)) != NULL) {
3439130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3440126258Smlaier			pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3441130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3442126258Smlaier			rewrite++;
3443130613Smlaier			if (nr->natpass)
3444126258Smlaier				r = NULL;
3445130613Smlaier			pd->nat_rule = nr;
3446126258Smlaier		}
3447126258Smlaier	} else {
3448126258Smlaier		bport = nport = uh->uh_dport;
3449126258Smlaier		/* check incoming packet for BINAT/RDR */
3450130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3451130613Smlaier		    saddr, uh->uh_sport, daddr, uh->uh_dport, &pd->naddr,
3452130613Smlaier		    &nport)) != NULL) {
3453130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3454126258Smlaier			pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3455130613Smlaier			    &uh->uh_sum, &pd->naddr, nport, 1, af);
3456126258Smlaier			rewrite++;
3457130613Smlaier			if (nr->natpass)
3458126258Smlaier				r = NULL;
3459130613Smlaier			pd->nat_rule = nr;
3460126258Smlaier		}
3461126258Smlaier	}
3462126258Smlaier
3463126258Smlaier	while (r != NULL) {
3464126258Smlaier		r->evaluations++;
3465130613Smlaier		if (r->kif != NULL &&
3466130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3467126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3468126258Smlaier		else if (r->direction && r->direction != direction)
3469126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3470126258Smlaier		else if (r->af && r->af != af)
3471126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3472126258Smlaier		else if (r->proto && r->proto != IPPROTO_UDP)
3473126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3474145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3475126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3476126258Smlaier		else if (r->src.port_op && !pf_match_port(r->src.port_op,
3477126258Smlaier		    r->src.port[0], r->src.port[1], uh->uh_sport))
3478126258Smlaier			r = r->skip[PF_SKIP_SRC_PORT].ptr;
3479145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3480126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3481126258Smlaier		else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
3482126258Smlaier		    r->dst.port[0], r->dst.port[1], uh->uh_dport))
3483126258Smlaier			r = r->skip[PF_SKIP_DST_PORT].ptr;
3484126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3485126258Smlaier			r = TAILQ_NEXT(r, entries);
3486126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3487126258Smlaier			r = TAILQ_NEXT(r, entries);
3488126258Smlaier		else if (r->uid.op && (lookup != -1 || (lookup =
3489135920Smlaier#ifdef __FreeBSD__
3490135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3491135920Smlaier#else
3492130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3493135920Smlaier#endif
3494126258Smlaier		    !pf_match_uid(r->uid.op, r->uid.uid[0], r->uid.uid[1],
3495126258Smlaier		    uid))
3496126258Smlaier			r = TAILQ_NEXT(r, entries);
3497126258Smlaier		else if (r->gid.op && (lookup != -1 || (lookup =
3498135920Smlaier#ifdef __FreeBSD__
3499135920Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd, inp), 1)) &&
3500135920Smlaier#else
3501130613Smlaier		    pf_socket_lookup(&uid, &gid, direction, pd), 1)) &&
3502135920Smlaier#endif
3503126258Smlaier		    !pf_match_gid(r->gid.op, r->gid.gid[0], r->gid.gid[1],
3504126258Smlaier		    gid))
3505126258Smlaier			r = TAILQ_NEXT(r, entries);
3506145836Smlaier		else if (r->prob && r->prob <= arc4random())
3507126258Smlaier			r = TAILQ_NEXT(r, entries);
3508145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3509126258Smlaier			r = TAILQ_NEXT(r, entries);
3510126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3511126258Smlaier			r = TAILQ_NEXT(r, entries);
3512126258Smlaier		else {
3513126258Smlaier			if (r->tag)
3514126258Smlaier				tag = r->tag;
3515126258Smlaier			if (r->anchor == NULL) {
3516126258Smlaier				*rm = r;
3517126258Smlaier				*am = a;
3518126258Smlaier				*rsm = ruleset;
3519126258Smlaier				if ((*rm)->quick)
3520126258Smlaier					break;
3521126258Smlaier				r = TAILQ_NEXT(r, entries);
3522126258Smlaier			} else
3523145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3524145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3525126258Smlaier		}
3526145836Smlaier		if (r == NULL)
3527145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3528145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3529126258Smlaier	}
3530126258Smlaier	r = *rm;
3531126258Smlaier	a = *am;
3532126258Smlaier	ruleset = *rsm;
3533126258Smlaier
3534126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3535126258Smlaier
3536126258Smlaier	if (r->log) {
3537126258Smlaier		if (rewrite)
3538126261Smlaier			m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3539130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3540126258Smlaier	}
3541126258Smlaier
3542126258Smlaier	if ((r->action == PF_DROP) &&
3543126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
3544126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
3545126258Smlaier		/* undo NAT changes, if they have taken place */
3546130613Smlaier		if (nr != NULL) {
3547130613Smlaier			if (direction == PF_OUT) {
3548130613Smlaier				pf_change_ap(saddr, &uh->uh_sport, pd->ip_sum,
3549130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3550130613Smlaier				rewrite++;
3551130613Smlaier			} else {
3552130613Smlaier				pf_change_ap(daddr, &uh->uh_dport, pd->ip_sum,
3553130613Smlaier				    &uh->uh_sum, &pd->baddr, bport, 1, af);
3554130613Smlaier				rewrite++;
3555130613Smlaier			}
3556126258Smlaier		}
3557126258Smlaier		if ((af == AF_INET) && r->return_icmp)
3558126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
3559126258Smlaier			    r->return_icmp & 255, af, r);
3560126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
3561126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
3562126258Smlaier			    r->return_icmp6 & 255, af, r);
3563126258Smlaier	}
3564126258Smlaier
3565126258Smlaier	if (r->action == PF_DROP)
3566126258Smlaier		return (PF_DROP);
3567126258Smlaier
3568126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3569126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3570126258Smlaier		return (PF_DROP);
3571126258Smlaier	}
3572126258Smlaier
3573130613Smlaier	if (r->keep_state || nr != NULL) {
3574126258Smlaier		/* create new state */
3575126258Smlaier		struct pf_state	*s = NULL;
3576130613Smlaier		struct pf_src_node *sn = NULL;
3577126258Smlaier
3578130613Smlaier		/* check maximums */
3579145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3580145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3581145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3582130613Smlaier			goto cleanup;
3583145836Smlaier		}
3584130613Smlaier		/* src node for flter rule */
3585130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3586130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3587145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3588145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3589130613Smlaier			goto cleanup;
3590145836Smlaier		}
3591130613Smlaier		/* src node for translation rule */
3592130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3593130613Smlaier		    ((direction == PF_OUT &&
3594130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3595145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3596145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3597130613Smlaier			goto cleanup;
3598145836Smlaier		}
3599130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3600126258Smlaier		if (s == NULL) {
3601145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3602130613Smlaiercleanup:
3603130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3604130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3605130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3606130613Smlaier				pf_status.src_nodes--;
3607130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3608130613Smlaier			}
3609130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3610130613Smlaier			    nsn->expire == 0) {
3611130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3612130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3613130613Smlaier				pf_status.src_nodes--;
3614130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3615130613Smlaier			}
3616126258Smlaier			return (PF_DROP);
3617126258Smlaier		}
3618126258Smlaier		bzero(s, sizeof(*s));
3619126258Smlaier		s->rule.ptr = r;
3620130613Smlaier		s->nat_rule.ptr = nr;
3621126258Smlaier		s->anchor.ptr = a;
3622145836Smlaier		STATE_INC_COUNTERS(s);
3623126258Smlaier		s->allow_opts = r->allow_opts;
3624126258Smlaier		s->log = r->log & 2;
3625126258Smlaier		s->proto = IPPROTO_UDP;
3626126258Smlaier		s->direction = direction;
3627126258Smlaier		s->af = af;
3628126258Smlaier		if (direction == PF_OUT) {
3629126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3630126258Smlaier			s->gwy.port = uh->uh_sport;
3631126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3632126258Smlaier			s->ext.port = uh->uh_dport;
3633130613Smlaier			if (nr != NULL) {
3634130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3635126258Smlaier				s->lan.port = bport;
3636126258Smlaier			} else {
3637126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3638126258Smlaier				s->lan.port = s->gwy.port;
3639126258Smlaier			}
3640126258Smlaier		} else {
3641126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3642126258Smlaier			s->lan.port = uh->uh_dport;
3643126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3644126258Smlaier			s->ext.port = uh->uh_sport;
3645130613Smlaier			if (nr != NULL) {
3646130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3647126258Smlaier				s->gwy.port = bport;
3648126258Smlaier			} else {
3649126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3650126258Smlaier				s->gwy.port = s->lan.port;
3651126258Smlaier			}
3652126258Smlaier		}
3653126258Smlaier		s->src.state = PFUDPS_SINGLE;
3654126258Smlaier		s->dst.state = PFUDPS_NO_TRAFFIC;
3655126261Smlaier		s->creation = time_second;
3656126261Smlaier		s->expire = time_second;
3657126258Smlaier		s->timeout = PFTM_UDP_FIRST_PACKET;
3658126258Smlaier		pf_set_rt_ifp(s, saddr);
3659130613Smlaier		if (sn != NULL) {
3660130613Smlaier			s->src_node = sn;
3661130613Smlaier			s->src_node->states++;
3662130613Smlaier		}
3663130613Smlaier		if (nsn != NULL) {
3664130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3665130613Smlaier			s->nat_src_node = nsn;
3666130613Smlaier			s->nat_src_node->states++;
3667130613Smlaier		}
3668130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3669145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3670130613Smlaier			pf_src_tree_remove_state(s);
3671145836Smlaier			STATE_DEC_COUNTERS(s);
3672126258Smlaier			pool_put(&pf_state_pl, s);
3673126258Smlaier			return (PF_DROP);
3674126258Smlaier		} else
3675126258Smlaier			*sm = s;
3676145836Smlaier		if (tag > 0) {
3677145836Smlaier			pf_tag_ref(tag);
3678145836Smlaier			s->tag = tag;
3679145836Smlaier		}
3680126258Smlaier	}
3681126258Smlaier
3682126258Smlaier	/* copy back packet headers if we performed NAT operations */
3683126258Smlaier	if (rewrite)
3684126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
3685126258Smlaier
3686126258Smlaier	return (PF_PASS);
3687126258Smlaier}
3688126258Smlaier
3689126258Smlaierint
3690126258Smlaierpf_test_icmp(struct pf_rule **rm, struct pf_state **sm, int direction,
3691130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h,
3692145836Smlaier    struct pf_pdesc *pd, struct pf_rule **am, struct pf_ruleset **rsm,
3693145836Smlaier    struct ifqueue *ifq)
3694126258Smlaier{
3695130613Smlaier	struct pf_rule		*nr = NULL;
3696126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
3697126258Smlaier	struct pf_rule		*r, *a = NULL;
3698126258Smlaier	struct pf_ruleset	*ruleset = NULL;
3699130613Smlaier	struct pf_src_node	*nsn = NULL;
3700126258Smlaier	u_short			 reason;
3701149893Smlaier	u_int16_t		 icmpid = 0, bport, nport = 0;
3702126258Smlaier	sa_family_t		 af = pd->af;
3703127629Smlaier	u_int8_t		 icmptype = 0;	/* make the compiler happy */
3704127629Smlaier	u_int8_t		 icmpcode = 0;	/* make the compiler happy */
3705126258Smlaier	int			 state_icmp = 0;
3706126258Smlaier	struct pf_tag		*pftag = NULL;
3707126258Smlaier	int			 tag = -1;
3708126258Smlaier#ifdef INET6
3709126258Smlaier	int			 rewrite = 0;
3710126258Smlaier#endif /* INET6 */
3711145836Smlaier	int			 asd = 0;
3712126258Smlaier
3713145836Smlaier	if (pf_check_congestion(ifq)) {
3714145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
3715145836Smlaier		return (PF_DROP);
3716145836Smlaier	}
3717145836Smlaier
3718126258Smlaier	switch (pd->proto) {
3719126258Smlaier#ifdef INET
3720126258Smlaier	case IPPROTO_ICMP:
3721126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
3722126258Smlaier		icmpcode = pd->hdr.icmp->icmp_code;
3723126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
3724126258Smlaier
3725126258Smlaier		if (icmptype == ICMP_UNREACH ||
3726126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
3727126258Smlaier		    icmptype == ICMP_REDIRECT ||
3728126258Smlaier		    icmptype == ICMP_TIMXCEED ||
3729126258Smlaier		    icmptype == ICMP_PARAMPROB)
3730126258Smlaier			state_icmp++;
3731126258Smlaier		break;
3732126258Smlaier#endif /* INET */
3733126258Smlaier#ifdef INET6
3734126258Smlaier	case IPPROTO_ICMPV6:
3735126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
3736126258Smlaier		icmpcode = pd->hdr.icmp6->icmp6_code;
3737126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
3738126258Smlaier
3739126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
3740126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
3741126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
3742126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
3743126258Smlaier			state_icmp++;
3744126258Smlaier		break;
3745126258Smlaier#endif /* INET6 */
3746126258Smlaier	}
3747126258Smlaier
3748126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
3749126258Smlaier
3750126258Smlaier	if (direction == PF_OUT) {
3751149884Smlaier		bport = nport = icmpid;
3752126258Smlaier		/* check outgoing packet for BINAT/NAT */
3753130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
3754149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
3755149884Smlaier		    NULL) {
3756130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
3757126258Smlaier			switch (af) {
3758126258Smlaier#ifdef INET
3759126258Smlaier			case AF_INET:
3760126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
3761130613Smlaier				    pd->naddr.v4.s_addr, 0);
3762149884Smlaier				pd->hdr.icmp->icmp_cksum = pf_cksum_fixup(
3763149884Smlaier				    pd->hdr.icmp->icmp_cksum, icmpid, nport, 0);
3764149884Smlaier				pd->hdr.icmp->icmp_id = nport;
3765149893Smlaier				m_copyback(m, off, ICMP_MINLEN,
3766149893Smlaier				    (caddr_t)pd->hdr.icmp);
3767126258Smlaier				break;
3768126258Smlaier#endif /* INET */
3769126258Smlaier#ifdef INET6
3770126258Smlaier			case AF_INET6:
3771126258Smlaier				pf_change_a6(saddr, &pd->hdr.icmp6->icmp6_cksum,
3772130613Smlaier				    &pd->naddr, 0);
3773126258Smlaier				rewrite++;
3774126258Smlaier				break;
3775126258Smlaier#endif /* INET6 */
3776126258Smlaier			}
3777130613Smlaier			if (nr->natpass)
3778126258Smlaier				r = NULL;
3779130613Smlaier			pd->nat_rule = nr;
3780126258Smlaier		}
3781126258Smlaier	} else {
3782149884Smlaier		bport = nport = icmpid;
3783126258Smlaier		/* check incoming packet for BINAT/RDR */
3784130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
3785149884Smlaier		    saddr, icmpid, daddr, icmpid, &pd->naddr, &nport)) !=
3786149884Smlaier		    NULL) {
3787130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
3788126258Smlaier			switch (af) {
3789126258Smlaier#ifdef INET
3790126258Smlaier			case AF_INET:
3791126258Smlaier				pf_change_a(&daddr->v4.s_addr,
3792130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
3793126258Smlaier				break;
3794126258Smlaier#endif /* INET */
3795126258Smlaier#ifdef INET6
3796126258Smlaier			case AF_INET6:
3797126258Smlaier				pf_change_a6(daddr, &pd->hdr.icmp6->icmp6_cksum,
3798130613Smlaier				    &pd->naddr, 0);
3799126258Smlaier				rewrite++;
3800126258Smlaier				break;
3801126258Smlaier#endif /* INET6 */
3802126258Smlaier			}
3803130613Smlaier			if (nr->natpass)
3804126258Smlaier				r = NULL;
3805130613Smlaier			pd->nat_rule = nr;
3806126258Smlaier		}
3807126258Smlaier	}
3808126258Smlaier
3809126258Smlaier	while (r != NULL) {
3810126258Smlaier		r->evaluations++;
3811130613Smlaier		if (r->kif != NULL &&
3812130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
3813126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
3814126258Smlaier		else if (r->direction && r->direction != direction)
3815126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
3816126258Smlaier		else if (r->af && r->af != af)
3817126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
3818126258Smlaier		else if (r->proto && r->proto != pd->proto)
3819126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
3820145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, saddr, af, r->src.neg))
3821126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
3822145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, daddr, af, r->dst.neg))
3823126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
3824126258Smlaier		else if (r->type && r->type != icmptype + 1)
3825126258Smlaier			r = TAILQ_NEXT(r, entries);
3826126258Smlaier		else if (r->code && r->code != icmpcode + 1)
3827126258Smlaier			r = TAILQ_NEXT(r, entries);
3828126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
3829126258Smlaier			r = TAILQ_NEXT(r, entries);
3830126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
3831126258Smlaier			r = TAILQ_NEXT(r, entries);
3832145836Smlaier		else if (r->prob && r->prob <= arc4random())
3833126258Smlaier			r = TAILQ_NEXT(r, entries);
3834145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
3835126258Smlaier			r = TAILQ_NEXT(r, entries);
3836126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
3837126258Smlaier			r = TAILQ_NEXT(r, entries);
3838126258Smlaier		else {
3839126258Smlaier			if (r->tag)
3840126258Smlaier				tag = r->tag;
3841126258Smlaier			if (r->anchor == NULL) {
3842126258Smlaier				*rm = r;
3843126258Smlaier				*am = a;
3844126258Smlaier				*rsm = ruleset;
3845126258Smlaier				if ((*rm)->quick)
3846126258Smlaier					break;
3847126258Smlaier				r = TAILQ_NEXT(r, entries);
3848126258Smlaier			} else
3849145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
3850145836Smlaier				    PF_RULESET_FILTER, &r, &a);
3851126258Smlaier		}
3852145836Smlaier		if (r == NULL)
3853145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
3854145836Smlaier			    PF_RULESET_FILTER, &r, &a);
3855126258Smlaier	}
3856126258Smlaier	r = *rm;
3857126258Smlaier	a = *am;
3858126258Smlaier	ruleset = *rsm;
3859126258Smlaier
3860126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
3861126258Smlaier
3862126258Smlaier	if (r->log) {
3863126258Smlaier#ifdef INET6
3864126258Smlaier		if (rewrite)
3865126258Smlaier			m_copyback(m, off, sizeof(struct icmp6_hdr),
3866126261Smlaier			    (caddr_t)pd->hdr.icmp6);
3867126258Smlaier#endif /* INET6 */
3868130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
3869126258Smlaier	}
3870126258Smlaier
3871126258Smlaier	if (r->action != PF_PASS)
3872126258Smlaier		return (PF_DROP);
3873126258Smlaier
3874126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
3875126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
3876126258Smlaier		return (PF_DROP);
3877126258Smlaier	}
3878126258Smlaier
3879130613Smlaier	if (!state_icmp && (r->keep_state || nr != NULL)) {
3880126258Smlaier		/* create new state */
3881126258Smlaier		struct pf_state	*s = NULL;
3882130613Smlaier		struct pf_src_node *sn = NULL;
3883126258Smlaier
3884130613Smlaier		/* check maximums */
3885145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
3886145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
3887145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
3888130613Smlaier			goto cleanup;
3889145836Smlaier		}
3890130613Smlaier		/* src node for flter rule */
3891130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
3892130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
3893145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
3894145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3895130613Smlaier			goto cleanup;
3896145836Smlaier		}
3897130613Smlaier		/* src node for translation rule */
3898130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
3899130613Smlaier		    ((direction == PF_OUT &&
3900130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
3901145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
3902145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
3903130613Smlaier			goto cleanup;
3904145836Smlaier		}
3905130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
3906126258Smlaier		if (s == NULL) {
3907145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
3908130613Smlaiercleanup:
3909130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
3910130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
3911130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3912130613Smlaier				pf_status.src_nodes--;
3913130613Smlaier				pool_put(&pf_src_tree_pl, sn);
3914130613Smlaier			}
3915130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
3916130613Smlaier			    nsn->expire == 0) {
3917130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
3918130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
3919130613Smlaier				pf_status.src_nodes--;
3920130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
3921130613Smlaier			}
3922126258Smlaier			return (PF_DROP);
3923126258Smlaier		}
3924126258Smlaier		bzero(s, sizeof(*s));
3925126258Smlaier		s->rule.ptr = r;
3926130613Smlaier		s->nat_rule.ptr = nr;
3927126258Smlaier		s->anchor.ptr = a;
3928145836Smlaier		STATE_INC_COUNTERS(s);
3929126258Smlaier		s->allow_opts = r->allow_opts;
3930126258Smlaier		s->log = r->log & 2;
3931126258Smlaier		s->proto = pd->proto;
3932126258Smlaier		s->direction = direction;
3933126258Smlaier		s->af = af;
3934126258Smlaier		if (direction == PF_OUT) {
3935126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
3936149884Smlaier			s->gwy.port = nport;
3937126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
3938149884Smlaier			s->ext.port = 0;
3939149884Smlaier			if (nr != NULL) {
3940130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
3941149884Smlaier				s->lan.port = bport;
3942149884Smlaier			} else {
3943126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
3944149884Smlaier				s->lan.port = s->gwy.port;
3945149884Smlaier			}
3946126258Smlaier		} else {
3947126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
3948149884Smlaier			s->lan.port = nport;
3949126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
3950149884Smlaier			s->ext.port = 0;
3951149884Smlaier			if (nr != NULL) {
3952130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
3953149884Smlaier				s->gwy.port = bport;
3954149884Smlaier			} else {
3955126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
3956149884Smlaier				s->gwy.port = s->lan.port;
3957149884Smlaier			}
3958126258Smlaier		}
3959126261Smlaier		s->creation = time_second;
3960126261Smlaier		s->expire = time_second;
3961126258Smlaier		s->timeout = PFTM_ICMP_FIRST_PACKET;
3962126258Smlaier		pf_set_rt_ifp(s, saddr);
3963130613Smlaier		if (sn != NULL) {
3964130613Smlaier			s->src_node = sn;
3965130613Smlaier			s->src_node->states++;
3966130613Smlaier		}
3967130613Smlaier		if (nsn != NULL) {
3968130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
3969130613Smlaier			s->nat_src_node = nsn;
3970130613Smlaier			s->nat_src_node->states++;
3971130613Smlaier		}
3972130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
3973145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
3974130613Smlaier			pf_src_tree_remove_state(s);
3975145836Smlaier			STATE_DEC_COUNTERS(s);
3976126258Smlaier			pool_put(&pf_state_pl, s);
3977126258Smlaier			return (PF_DROP);
3978126258Smlaier		} else
3979126258Smlaier			*sm = s;
3980145836Smlaier		if (tag > 0) {
3981145836Smlaier			pf_tag_ref(tag);
3982145836Smlaier			s->tag = tag;
3983145836Smlaier		}
3984126258Smlaier	}
3985126258Smlaier
3986126258Smlaier#ifdef INET6
3987126258Smlaier	/* copy back packet headers if we performed IPv6 NAT operations */
3988126258Smlaier	if (rewrite)
3989126258Smlaier		m_copyback(m, off, sizeof(struct icmp6_hdr),
3990126261Smlaier		    (caddr_t)pd->hdr.icmp6);
3991126258Smlaier#endif /* INET6 */
3992126258Smlaier
3993126258Smlaier	return (PF_PASS);
3994126258Smlaier}
3995126258Smlaier
3996126258Smlaierint
3997126258Smlaierpf_test_other(struct pf_rule **rm, struct pf_state **sm, int direction,
3998130613Smlaier    struct pfi_kif *kif, struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
3999145836Smlaier    struct pf_rule **am, struct pf_ruleset **rsm, struct ifqueue *ifq)
4000126258Smlaier{
4001130613Smlaier	struct pf_rule		*nr = NULL;
4002126258Smlaier	struct pf_rule		*r, *a = NULL;
4003126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4004130613Smlaier	struct pf_src_node	*nsn = NULL;
4005126258Smlaier	struct pf_addr		*saddr = pd->src, *daddr = pd->dst;
4006126258Smlaier	sa_family_t		 af = pd->af;
4007126258Smlaier	u_short			 reason;
4008126258Smlaier	struct pf_tag		*pftag = NULL;
4009126258Smlaier	int			 tag = -1;
4010145836Smlaier	int			 asd = 0;
4011126258Smlaier
4012145836Smlaier	if (pf_check_congestion(ifq)) {
4013145836Smlaier		REASON_SET(&reason, PFRES_CONGEST);
4014145836Smlaier		return (PF_DROP);
4015145836Smlaier	}
4016145836Smlaier
4017126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4018126258Smlaier
4019126258Smlaier	if (direction == PF_OUT) {
4020126258Smlaier		/* check outgoing packet for BINAT/NAT */
4021130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_OUT, kif, &nsn,
4022130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4023130613Smlaier			PF_ACPY(&pd->baddr, saddr, af);
4024126258Smlaier			switch (af) {
4025126258Smlaier#ifdef INET
4026126258Smlaier			case AF_INET:
4027126258Smlaier				pf_change_a(&saddr->v4.s_addr, pd->ip_sum,
4028130613Smlaier				    pd->naddr.v4.s_addr, 0);
4029126258Smlaier				break;
4030126258Smlaier#endif /* INET */
4031126258Smlaier#ifdef INET6
4032126258Smlaier			case AF_INET6:
4033130613Smlaier				PF_ACPY(saddr, &pd->naddr, af);
4034126258Smlaier				break;
4035126258Smlaier#endif /* INET6 */
4036126258Smlaier			}
4037130613Smlaier			if (nr->natpass)
4038126258Smlaier				r = NULL;
4039130613Smlaier			pd->nat_rule = nr;
4040126258Smlaier		}
4041126258Smlaier	} else {
4042126258Smlaier		/* check incoming packet for BINAT/RDR */
4043130613Smlaier		if ((nr = pf_get_translation(pd, m, off, PF_IN, kif, &nsn,
4044130613Smlaier		    saddr, 0, daddr, 0, &pd->naddr, NULL)) != NULL) {
4045130613Smlaier			PF_ACPY(&pd->baddr, daddr, af);
4046126258Smlaier			switch (af) {
4047126258Smlaier#ifdef INET
4048126258Smlaier			case AF_INET:
4049126258Smlaier				pf_change_a(&daddr->v4.s_addr,
4050130613Smlaier				    pd->ip_sum, pd->naddr.v4.s_addr, 0);
4051126258Smlaier				break;
4052126258Smlaier#endif /* INET */
4053126258Smlaier#ifdef INET6
4054126258Smlaier			case AF_INET6:
4055130613Smlaier				PF_ACPY(daddr, &pd->naddr, af);
4056126258Smlaier				break;
4057126258Smlaier#endif /* INET6 */
4058126258Smlaier			}
4059130613Smlaier			if (nr->natpass)
4060126258Smlaier				r = NULL;
4061130613Smlaier			pd->nat_rule = nr;
4062126258Smlaier		}
4063126258Smlaier	}
4064126258Smlaier
4065126258Smlaier	while (r != NULL) {
4066126258Smlaier		r->evaluations++;
4067130613Smlaier		if (r->kif != NULL &&
4068130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
4069126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4070126258Smlaier		else if (r->direction && r->direction != direction)
4071126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4072126258Smlaier		else if (r->af && r->af != af)
4073126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4074126258Smlaier		else if (r->proto && r->proto != pd->proto)
4075126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4076145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
4077126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4078145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
4079126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4080126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
4081126258Smlaier			r = TAILQ_NEXT(r, entries);
4082126258Smlaier		else if (r->rule_flag & PFRULE_FRAGMENT)
4083126258Smlaier			r = TAILQ_NEXT(r, entries);
4084145836Smlaier		else if (r->prob && r->prob <= arc4random())
4085126258Smlaier			r = TAILQ_NEXT(r, entries);
4086145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
4087126258Smlaier			r = TAILQ_NEXT(r, entries);
4088126258Smlaier		else if (r->os_fingerprint != PF_OSFP_ANY)
4089126258Smlaier			r = TAILQ_NEXT(r, entries);
4090126258Smlaier		else {
4091126258Smlaier			if (r->tag)
4092126258Smlaier				tag = r->tag;
4093126258Smlaier			if (r->anchor == NULL) {
4094126258Smlaier				*rm = r;
4095126258Smlaier				*am = a;
4096126258Smlaier				*rsm = ruleset;
4097126258Smlaier				if ((*rm)->quick)
4098126258Smlaier					break;
4099126258Smlaier				r = TAILQ_NEXT(r, entries);
4100126258Smlaier			} else
4101145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4102145836Smlaier				    PF_RULESET_FILTER, &r, &a);
4103126258Smlaier		}
4104145836Smlaier		if (r == NULL)
4105145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
4106145836Smlaier			    PF_RULESET_FILTER, &r, &a);
4107126258Smlaier	}
4108126258Smlaier	r = *rm;
4109126258Smlaier	a = *am;
4110126258Smlaier	ruleset = *rsm;
4111126258Smlaier
4112126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4113130613Smlaier
4114126258Smlaier	if (r->log)
4115130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
4116126258Smlaier
4117126258Smlaier	if ((r->action == PF_DROP) &&
4118126258Smlaier	    ((r->rule_flag & PFRULE_RETURNICMP) ||
4119126258Smlaier	    (r->rule_flag & PFRULE_RETURN))) {
4120126258Smlaier		struct pf_addr *a = NULL;
4121126258Smlaier
4122130613Smlaier		if (nr != NULL) {
4123130613Smlaier			if (direction == PF_OUT)
4124130613Smlaier				a = saddr;
4125130613Smlaier			else
4126130613Smlaier				a = daddr;
4127130613Smlaier		}
4128126258Smlaier		if (a != NULL) {
4129126258Smlaier			switch (af) {
4130126258Smlaier#ifdef INET
4131126258Smlaier			case AF_INET:
4132126258Smlaier				pf_change_a(&a->v4.s_addr, pd->ip_sum,
4133130613Smlaier				    pd->baddr.v4.s_addr, 0);
4134126258Smlaier				break;
4135126258Smlaier#endif /* INET */
4136126258Smlaier#ifdef INET6
4137126258Smlaier			case AF_INET6:
4138130613Smlaier				PF_ACPY(a, &pd->baddr, af);
4139126258Smlaier				break;
4140126258Smlaier#endif /* INET6 */
4141126258Smlaier			}
4142126258Smlaier		}
4143126258Smlaier		if ((af == AF_INET) && r->return_icmp)
4144126258Smlaier			pf_send_icmp(m, r->return_icmp >> 8,
4145126258Smlaier			    r->return_icmp & 255, af, r);
4146126258Smlaier		else if ((af == AF_INET6) && r->return_icmp6)
4147126258Smlaier			pf_send_icmp(m, r->return_icmp6 >> 8,
4148126258Smlaier			    r->return_icmp6 & 255, af, r);
4149126258Smlaier	}
4150126258Smlaier
4151126258Smlaier	if (r->action != PF_PASS)
4152126258Smlaier		return (PF_DROP);
4153126258Smlaier
4154126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
4155126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4156126258Smlaier		return (PF_DROP);
4157126258Smlaier	}
4158126258Smlaier
4159130613Smlaier	if (r->keep_state || nr != NULL) {
4160126258Smlaier		/* create new state */
4161126258Smlaier		struct pf_state	*s = NULL;
4162130613Smlaier		struct pf_src_node *sn = NULL;
4163126258Smlaier
4164130613Smlaier		/* check maximums */
4165145836Smlaier		if (r->max_states && (r->states >= r->max_states)) {
4166145836Smlaier			pf_status.lcounters[LCNT_STATES]++;
4167145836Smlaier			REASON_SET(&reason, PFRES_MAXSTATES);
4168130613Smlaier			goto cleanup;
4169145836Smlaier		}
4170130613Smlaier		/* src node for flter rule */
4171130613Smlaier		if ((r->rule_flag & PFRULE_SRCTRACK ||
4172130613Smlaier		    r->rpool.opts & PF_POOL_STICKYADDR) &&
4173145836Smlaier		    pf_insert_src_node(&sn, r, saddr, af) != 0) {
4174145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4175130613Smlaier			goto cleanup;
4176145836Smlaier		}
4177130613Smlaier		/* src node for translation rule */
4178130613Smlaier		if (nr != NULL && (nr->rpool.opts & PF_POOL_STICKYADDR) &&
4179130613Smlaier		    ((direction == PF_OUT &&
4180130613Smlaier		    pf_insert_src_node(&nsn, nr, &pd->baddr, af) != 0) ||
4181145836Smlaier		    (pf_insert_src_node(&nsn, nr, saddr, af) != 0))) {
4182145836Smlaier			REASON_SET(&reason, PFRES_SRCLIMIT);
4183130613Smlaier			goto cleanup;
4184145836Smlaier		}
4185130613Smlaier		s = pool_get(&pf_state_pl, PR_NOWAIT);
4186126258Smlaier		if (s == NULL) {
4187145836Smlaier			REASON_SET(&reason, PFRES_MEMORY);
4188130613Smlaiercleanup:
4189130613Smlaier			if (sn != NULL && sn->states == 0 && sn->expire == 0) {
4190130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, sn);
4191130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4192130613Smlaier				pf_status.src_nodes--;
4193130613Smlaier				pool_put(&pf_src_tree_pl, sn);
4194130613Smlaier			}
4195130613Smlaier			if (nsn != sn && nsn != NULL && nsn->states == 0 &&
4196130613Smlaier			    nsn->expire == 0) {
4197130613Smlaier				RB_REMOVE(pf_src_tree, &tree_src_tracking, nsn);
4198130613Smlaier				pf_status.scounters[SCNT_SRC_NODE_REMOVALS]++;
4199130613Smlaier				pf_status.src_nodes--;
4200130613Smlaier				pool_put(&pf_src_tree_pl, nsn);
4201130613Smlaier			}
4202126258Smlaier			return (PF_DROP);
4203126258Smlaier		}
4204126258Smlaier		bzero(s, sizeof(*s));
4205126258Smlaier		s->rule.ptr = r;
4206130613Smlaier		s->nat_rule.ptr = nr;
4207126258Smlaier		s->anchor.ptr = a;
4208145836Smlaier		STATE_INC_COUNTERS(s);
4209126258Smlaier		s->allow_opts = r->allow_opts;
4210126258Smlaier		s->log = r->log & 2;
4211126258Smlaier		s->proto = pd->proto;
4212126258Smlaier		s->direction = direction;
4213126258Smlaier		s->af = af;
4214126258Smlaier		if (direction == PF_OUT) {
4215126258Smlaier			PF_ACPY(&s->gwy.addr, saddr, af);
4216126258Smlaier			PF_ACPY(&s->ext.addr, daddr, af);
4217130613Smlaier			if (nr != NULL)
4218130613Smlaier				PF_ACPY(&s->lan.addr, &pd->baddr, af);
4219126258Smlaier			else
4220126258Smlaier				PF_ACPY(&s->lan.addr, &s->gwy.addr, af);
4221126258Smlaier		} else {
4222126258Smlaier			PF_ACPY(&s->lan.addr, daddr, af);
4223126258Smlaier			PF_ACPY(&s->ext.addr, saddr, af);
4224130613Smlaier			if (nr != NULL)
4225130613Smlaier				PF_ACPY(&s->gwy.addr, &pd->baddr, af);
4226126258Smlaier			else
4227126258Smlaier				PF_ACPY(&s->gwy.addr, &s->lan.addr, af);
4228126258Smlaier		}
4229126258Smlaier		s->src.state = PFOTHERS_SINGLE;
4230126258Smlaier		s->dst.state = PFOTHERS_NO_TRAFFIC;
4231126261Smlaier		s->creation = time_second;
4232126261Smlaier		s->expire = time_second;
4233126258Smlaier		s->timeout = PFTM_OTHER_FIRST_PACKET;
4234126258Smlaier		pf_set_rt_ifp(s, saddr);
4235130613Smlaier		if (sn != NULL) {
4236130613Smlaier			s->src_node = sn;
4237130613Smlaier			s->src_node->states++;
4238130613Smlaier		}
4239130613Smlaier		if (nsn != NULL) {
4240130613Smlaier			PF_ACPY(&nsn->raddr, &pd->naddr, af);
4241130613Smlaier			s->nat_src_node = nsn;
4242130613Smlaier			s->nat_src_node->states++;
4243130613Smlaier		}
4244130613Smlaier		if (pf_insert_state(BOUND_IFACE(r, kif), s)) {
4245145836Smlaier			REASON_SET(&reason, PFRES_STATEINS);
4246130613Smlaier			pf_src_tree_remove_state(s);
4247145836Smlaier			STATE_DEC_COUNTERS(s);
4248126258Smlaier			pool_put(&pf_state_pl, s);
4249126258Smlaier			return (PF_DROP);
4250126258Smlaier		} else
4251126258Smlaier			*sm = s;
4252145836Smlaier		if (tag > 0) {
4253145836Smlaier			pf_tag_ref(tag);
4254145836Smlaier			s->tag = tag;
4255145836Smlaier		}
4256126258Smlaier	}
4257126258Smlaier
4258126258Smlaier	return (PF_PASS);
4259126258Smlaier}
4260126258Smlaier
4261126258Smlaierint
4262130613Smlaierpf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
4263126258Smlaier    struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am,
4264126258Smlaier    struct pf_ruleset **rsm)
4265126258Smlaier{
4266126258Smlaier	struct pf_rule		*r, *a = NULL;
4267126258Smlaier	struct pf_ruleset	*ruleset = NULL;
4268126258Smlaier	sa_family_t		 af = pd->af;
4269126258Smlaier	u_short			 reason;
4270126258Smlaier	struct pf_tag		*pftag = NULL;
4271126258Smlaier	int			 tag = -1;
4272145836Smlaier	int			 asd = 0;
4273126258Smlaier
4274126258Smlaier	r = TAILQ_FIRST(pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);
4275126258Smlaier	while (r != NULL) {
4276126258Smlaier		r->evaluations++;
4277130613Smlaier		if (r->kif != NULL &&
4278130613Smlaier		    (r->kif != kif && r->kif != kif->pfik_parent) == !r->ifnot)
4279126258Smlaier			r = r->skip[PF_SKIP_IFP].ptr;
4280126258Smlaier		else if (r->direction && r->direction != direction)
4281126258Smlaier			r = r->skip[PF_SKIP_DIR].ptr;
4282126258Smlaier		else if (r->af && r->af != af)
4283126258Smlaier			r = r->skip[PF_SKIP_AF].ptr;
4284126258Smlaier		else if (r->proto && r->proto != pd->proto)
4285126258Smlaier			r = r->skip[PF_SKIP_PROTO].ptr;
4286145836Smlaier		else if (PF_MISMATCHAW(&r->src.addr, pd->src, af, r->src.neg))
4287126258Smlaier			r = r->skip[PF_SKIP_SRC_ADDR].ptr;
4288145836Smlaier		else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af, r->dst.neg))
4289126258Smlaier			r = r->skip[PF_SKIP_DST_ADDR].ptr;
4290126258Smlaier		else if (r->tos && !(r->tos & pd->tos))
4291126258Smlaier			r = TAILQ_NEXT(r, entries);
4292126258Smlaier		else if (r->src.port_op || r->dst.port_op ||
4293126258Smlaier		    r->flagset || r->type || r->code ||
4294126258Smlaier		    r->os_fingerprint != PF_OSFP_ANY)
4295126258Smlaier			r = TAILQ_NEXT(r, entries);
4296145836Smlaier		else if (r->prob && r->prob <= arc4random())
4297126258Smlaier			r = TAILQ_NEXT(r, entries);
4298145836Smlaier		else if (r->match_tag && !pf_match_tag(m, r, &pftag, &tag))
4299126258Smlaier			r = TAILQ_NEXT(r, entries);
4300126258Smlaier		else {
4301126258Smlaier			if (r->anchor == NULL) {
4302126258Smlaier				*rm = r;
4303126258Smlaier				*am = a;
4304126258Smlaier				*rsm = ruleset;
4305126258Smlaier				if ((*rm)->quick)
4306126258Smlaier					break;
4307126258Smlaier				r = TAILQ_NEXT(r, entries);
4308126258Smlaier			} else
4309145836Smlaier				pf_step_into_anchor(&asd, &ruleset,
4310145836Smlaier				    PF_RULESET_FILTER, &r, &a);
4311126258Smlaier		}
4312145836Smlaier		if (r == NULL)
4313145836Smlaier			pf_step_out_of_anchor(&asd, &ruleset,
4314145836Smlaier			    PF_RULESET_FILTER, &r, &a);
4315126258Smlaier	}
4316126258Smlaier	r = *rm;
4317126258Smlaier	a = *am;
4318126258Smlaier	ruleset = *rsm;
4319126258Smlaier
4320126258Smlaier	REASON_SET(&reason, PFRES_MATCH);
4321130613Smlaier
4322126258Smlaier	if (r->log)
4323130613Smlaier		PFLOG_PACKET(kif, h, m, af, direction, reason, r, a, ruleset);
4324126258Smlaier
4325126258Smlaier	if (r->action != PF_PASS)
4326126258Smlaier		return (PF_DROP);
4327126258Smlaier
4328126258Smlaier	if (pf_tag_packet(m, pftag, tag)) {
4329126258Smlaier		REASON_SET(&reason, PFRES_MEMORY);
4330126258Smlaier		return (PF_DROP);
4331126258Smlaier	}
4332126258Smlaier
4333126258Smlaier	return (PF_PASS);
4334126258Smlaier}
4335126258Smlaier
4336126258Smlaierint
4337130613Smlaierpf_test_state_tcp(struct pf_state **state, int direction, struct pfi_kif *kif,
4338130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd,
4339126258Smlaier    u_short *reason)
4340126258Smlaier{
4341130613Smlaier	struct pf_state		 key;
4342126258Smlaier	struct tcphdr		*th = pd->hdr.tcp;
4343126258Smlaier	u_int16_t		 win = ntohs(th->th_win);
4344145836Smlaier	u_int32_t		 ack, end, seq, orig_seq;
4345126258Smlaier	u_int8_t		 sws, dws;
4346130613Smlaier	int			 ackskew;
4347126258Smlaier	int			 copyback = 0;
4348126258Smlaier	struct pf_state_peer	*src, *dst;
4349126258Smlaier
4350126258Smlaier	key.af = pd->af;
4351126258Smlaier	key.proto = IPPROTO_TCP;
4352130613Smlaier	if (direction == PF_IN)	{
4353130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4354130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4355130613Smlaier		key.ext.port = th->th_sport;
4356130613Smlaier		key.gwy.port = th->th_dport;
4357130613Smlaier	} else {
4358130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4359130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4360130613Smlaier		key.lan.port = th->th_sport;
4361130613Smlaier		key.ext.port = th->th_dport;
4362130613Smlaier	}
4363126258Smlaier
4364126258Smlaier	STATE_LOOKUP();
4365126258Smlaier
4366126258Smlaier	if (direction == (*state)->direction) {
4367126258Smlaier		src = &(*state)->src;
4368126258Smlaier		dst = &(*state)->dst;
4369126258Smlaier	} else {
4370126258Smlaier		src = &(*state)->dst;
4371126258Smlaier		dst = &(*state)->src;
4372126258Smlaier	}
4373126258Smlaier
4374126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_SRC) {
4375145836Smlaier		if (direction != (*state)->direction) {
4376145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4377126258Smlaier			return (PF_SYNPROXY_DROP);
4378145836Smlaier		}
4379126258Smlaier		if (th->th_flags & TH_SYN) {
4380145836Smlaier			if (ntohl(th->th_seq) != (*state)->src.seqlo) {
4381145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4382126258Smlaier				return (PF_DROP);
4383145836Smlaier			}
4384162238Scsjp#ifdef __FreeBSD__
4385162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4386162238Scsjp#else
4387126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4388162238Scsjp#endif
4389126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4390126258Smlaier			    (*state)->src.seqhi, ntohl(th->th_seq) + 1,
4391145836Smlaier			    TH_SYN|TH_ACK, 0, (*state)->src.mss, 0, 1,
4392145836Smlaier			    NULL, NULL);
4393145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4394126258Smlaier			return (PF_SYNPROXY_DROP);
4395126258Smlaier		} else if (!(th->th_flags & TH_ACK) ||
4396126258Smlaier		    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4397145836Smlaier		    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4398145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4399126258Smlaier			return (PF_DROP);
4400145836Smlaier		} else if ((*state)->src_node != NULL &&
4401145836Smlaier		    pf_src_connlimit(state)) {
4402145836Smlaier			REASON_SET(reason, PFRES_SRCLIMIT);
4403145836Smlaier			return (PF_DROP);
4404145836Smlaier		} else
4405126258Smlaier			(*state)->src.state = PF_TCPS_PROXY_DST;
4406126258Smlaier	}
4407126258Smlaier	if ((*state)->src.state == PF_TCPS_PROXY_DST) {
4408126258Smlaier		struct pf_state_host *src, *dst;
4409126258Smlaier
4410126258Smlaier		if (direction == PF_OUT) {
4411126258Smlaier			src = &(*state)->gwy;
4412126258Smlaier			dst = &(*state)->ext;
4413126258Smlaier		} else {
4414126258Smlaier			src = &(*state)->ext;
4415126258Smlaier			dst = &(*state)->lan;
4416126258Smlaier		}
4417126258Smlaier		if (direction == (*state)->direction) {
4418126258Smlaier			if (((th->th_flags & (TH_SYN|TH_ACK)) != TH_ACK) ||
4419126258Smlaier			    (ntohl(th->th_ack) != (*state)->src.seqhi + 1) ||
4420145836Smlaier			    (ntohl(th->th_seq) != (*state)->src.seqlo + 1)) {
4421145836Smlaier				REASON_SET(reason, PFRES_SYNPROXY);
4422126258Smlaier				return (PF_DROP);
4423145836Smlaier			}
4424126258Smlaier			(*state)->src.max_win = MAX(ntohs(th->th_win), 1);
4425126258Smlaier			if ((*state)->dst.seqhi == 1)
4426145836Smlaier				(*state)->dst.seqhi = htonl(arc4random());
4427162238Scsjp#ifdef __FreeBSD__
4428162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4429162238Scsjp			    &src->addr,
4430162238Scsjp#else
4431126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4432162238Scsjp#endif
4433126258Smlaier			    &dst->addr, src->port, dst->port,
4434130613Smlaier			    (*state)->dst.seqhi, 0, TH_SYN, 0,
4435145836Smlaier			    (*state)->src.mss, 0, 0, NULL, NULL);
4436145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4437126258Smlaier			return (PF_SYNPROXY_DROP);
4438126258Smlaier		} else if (((th->th_flags & (TH_SYN|TH_ACK)) !=
4439126258Smlaier		    (TH_SYN|TH_ACK)) ||
4440145836Smlaier		    (ntohl(th->th_ack) != (*state)->dst.seqhi + 1)) {
4441145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4442126258Smlaier			return (PF_DROP);
4443145836Smlaier		} else {
4444126258Smlaier			(*state)->dst.max_win = MAX(ntohs(th->th_win), 1);
4445126258Smlaier			(*state)->dst.seqlo = ntohl(th->th_seq);
4446162238Scsjp#ifdef __FreeBSD__
4447162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af, pd->dst,
4448162238Scsjp#else
4449126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, pd->dst,
4450162238Scsjp#endif
4451126258Smlaier			    pd->src, th->th_dport, th->th_sport,
4452126258Smlaier			    ntohl(th->th_ack), ntohl(th->th_seq) + 1,
4453145836Smlaier			    TH_ACK, (*state)->src.max_win, 0, 0, 0,
4454145836Smlaier			    NULL, NULL);
4455162238Scsjp#ifdef __FreeBSD__
4456162238Scsjp			pf_send_tcp(NULL, (*state)->rule.ptr, pd->af,
4457162238Scsjp			    &src->addr,
4458162238Scsjp#else
4459126258Smlaier			pf_send_tcp((*state)->rule.ptr, pd->af, &src->addr,
4460162238Scsjp#endif
4461126258Smlaier			    &dst->addr, src->port, dst->port,
4462126258Smlaier			    (*state)->src.seqhi + 1, (*state)->src.seqlo + 1,
4463145836Smlaier			    TH_ACK, (*state)->dst.max_win, 0, 0, 1,
4464145836Smlaier			    NULL, NULL);
4465126258Smlaier			(*state)->src.seqdiff = (*state)->dst.seqhi -
4466126258Smlaier			    (*state)->src.seqlo;
4467126258Smlaier			(*state)->dst.seqdiff = (*state)->src.seqhi -
4468126258Smlaier			    (*state)->dst.seqlo;
4469126258Smlaier			(*state)->src.seqhi = (*state)->src.seqlo +
4470145875Smlaier			    (*state)->dst.max_win;
4471145875Smlaier			(*state)->dst.seqhi = (*state)->dst.seqlo +
4472145836Smlaier			    (*state)->src.max_win;
4473126258Smlaier			(*state)->src.wscale = (*state)->dst.wscale = 0;
4474126258Smlaier			(*state)->src.state = (*state)->dst.state =
4475126258Smlaier			    TCPS_ESTABLISHED;
4476145836Smlaier			REASON_SET(reason, PFRES_SYNPROXY);
4477126258Smlaier			return (PF_SYNPROXY_DROP);
4478126258Smlaier		}
4479126258Smlaier	}
4480126258Smlaier
4481126258Smlaier	if (src->wscale && dst->wscale && !(th->th_flags & TH_SYN)) {
4482126258Smlaier		sws = src->wscale & PF_WSCALE_MASK;
4483126258Smlaier		dws = dst->wscale & PF_WSCALE_MASK;
4484126258Smlaier	} else
4485126258Smlaier		sws = dws = 0;
4486126258Smlaier
4487126258Smlaier	/*
4488126258Smlaier	 * Sequence tracking algorithm from Guido van Rooij's paper:
4489126258Smlaier	 *   http://www.madison-gurkha.com/publications/tcp_filtering/
4490126258Smlaier	 *	tcp_filtering.ps
4491126258Smlaier	 */
4492126258Smlaier
4493145836Smlaier	orig_seq = seq = ntohl(th->th_seq);
4494126258Smlaier	if (src->seqlo == 0) {
4495126258Smlaier		/* First packet from this end. Set its state */
4496126258Smlaier
4497126258Smlaier		if ((pd->flags & PFDESC_TCP_NORM || dst->scrub) &&
4498126258Smlaier		    src->scrub == NULL) {
4499126258Smlaier			if (pf_normalize_tcp_init(m, off, pd, th, src, dst)) {
4500126258Smlaier				REASON_SET(reason, PFRES_MEMORY);
4501126258Smlaier				return (PF_DROP);
4502126258Smlaier			}
4503126258Smlaier		}
4504126258Smlaier
4505126258Smlaier		/* Deferred generation of sequence number modulator */
4506126258Smlaier		if (dst->seqdiff && !src->seqdiff) {
4507145836Smlaier			while ((src->seqdiff = htonl(arc4random())) == 0)
4508126258Smlaier				;
4509126258Smlaier			ack = ntohl(th->th_ack) - dst->seqdiff;
4510126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4511126258Smlaier			    src->seqdiff), 0);
4512126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4513126258Smlaier			copyback = 1;
4514126258Smlaier		} else {
4515126258Smlaier			ack = ntohl(th->th_ack);
4516126258Smlaier		}
4517126258Smlaier
4518126258Smlaier		end = seq + pd->p_len;
4519126258Smlaier		if (th->th_flags & TH_SYN) {
4520126258Smlaier			end++;
4521126258Smlaier			if (dst->wscale & PF_WSCALE_FLAG) {
4522126258Smlaier				src->wscale = pf_get_wscale(m, off, th->th_off,
4523126258Smlaier				    pd->af);
4524126258Smlaier				if (src->wscale & PF_WSCALE_FLAG) {
4525126258Smlaier					/* Remove scale factor from initial
4526126258Smlaier					 * window */
4527126258Smlaier					sws = src->wscale & PF_WSCALE_MASK;
4528126258Smlaier					win = ((u_int32_t)win + (1 << sws) - 1)
4529126258Smlaier					    >> sws;
4530126258Smlaier					dws = dst->wscale & PF_WSCALE_MASK;
4531126258Smlaier				} else {
4532126258Smlaier					/* fixup other window */
4533126258Smlaier					dst->max_win <<= dst->wscale &
4534126258Smlaier					    PF_WSCALE_MASK;
4535126258Smlaier					/* in case of a retrans SYN|ACK */
4536126258Smlaier					dst->wscale = 0;
4537126258Smlaier				}
4538126258Smlaier			}
4539126258Smlaier		}
4540126258Smlaier		if (th->th_flags & TH_FIN)
4541126258Smlaier			end++;
4542126258Smlaier
4543126258Smlaier		src->seqlo = seq;
4544126258Smlaier		if (src->state < TCPS_SYN_SENT)
4545126258Smlaier			src->state = TCPS_SYN_SENT;
4546126258Smlaier
4547126258Smlaier		/*
4548126258Smlaier		 * May need to slide the window (seqhi may have been set by
4549126258Smlaier		 * the crappy stack check or if we picked up the connection
4550126258Smlaier		 * after establishment)
4551126258Smlaier		 */
4552126258Smlaier		if (src->seqhi == 1 ||
4553126258Smlaier		    SEQ_GEQ(end + MAX(1, dst->max_win << dws), src->seqhi))
4554126258Smlaier			src->seqhi = end + MAX(1, dst->max_win << dws);
4555126258Smlaier		if (win > src->max_win)
4556126258Smlaier			src->max_win = win;
4557126258Smlaier
4558126258Smlaier	} else {
4559126258Smlaier		ack = ntohl(th->th_ack) - dst->seqdiff;
4560126258Smlaier		if (src->seqdiff) {
4561126258Smlaier			/* Modulate sequence numbers */
4562126258Smlaier			pf_change_a(&th->th_seq, &th->th_sum, htonl(seq +
4563126258Smlaier			    src->seqdiff), 0);
4564126258Smlaier			pf_change_a(&th->th_ack, &th->th_sum, htonl(ack), 0);
4565126258Smlaier			copyback = 1;
4566126258Smlaier		}
4567126258Smlaier		end = seq + pd->p_len;
4568126258Smlaier		if (th->th_flags & TH_SYN)
4569126258Smlaier			end++;
4570126258Smlaier		if (th->th_flags & TH_FIN)
4571126258Smlaier			end++;
4572126258Smlaier	}
4573126258Smlaier
4574126258Smlaier	if ((th->th_flags & TH_ACK) == 0) {
4575126258Smlaier		/* Let it pass through the ack skew check */
4576126258Smlaier		ack = dst->seqlo;
4577126258Smlaier	} else if ((ack == 0 &&
4578126258Smlaier	    (th->th_flags & (TH_ACK|TH_RST)) == (TH_ACK|TH_RST)) ||
4579126258Smlaier	    /* broken tcp stacks do not set ack */
4580126258Smlaier	    (dst->state < TCPS_SYN_SENT)) {
4581126258Smlaier		/*
4582126258Smlaier		 * Many stacks (ours included) will set the ACK number in an
4583126258Smlaier		 * FIN|ACK if the SYN times out -- no sequence to ACK.
4584126258Smlaier		 */
4585126258Smlaier		ack = dst->seqlo;
4586126258Smlaier	}
4587126258Smlaier
4588126258Smlaier	if (seq == end) {
4589126258Smlaier		/* Ease sequencing restrictions on no data packets */
4590126258Smlaier		seq = src->seqlo;
4591126258Smlaier		end = seq;
4592126258Smlaier	}
4593126258Smlaier
4594126258Smlaier	ackskew = dst->seqlo - ack;
4595126258Smlaier
4596126258Smlaier#define MAXACKWINDOW (0xffff + 1500)	/* 1500 is an arbitrary fudge factor */
4597126258Smlaier	if (SEQ_GEQ(src->seqhi, end) &&
4598126258Smlaier	    /* Last octet inside other's window space */
4599126258Smlaier	    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) &&
4600126258Smlaier	    /* Retrans: not more than one window back */
4601126258Smlaier	    (ackskew >= -MAXACKWINDOW) &&
4602126258Smlaier	    /* Acking not more than one reassembled fragment backwards */
4603145836Smlaier	    (ackskew <= (MAXACKWINDOW << sws)) &&
4604126258Smlaier	    /* Acking not more than one window forward */
4605145836Smlaier	    ((th->th_flags & TH_RST) == 0 || orig_seq == src->seqlo ||
4606145836Smlaier	    (pd->flags & PFDESC_IP_REAS) == 0)) {
4607145836Smlaier	    /* Require an exact sequence match on resets when possible */
4608126258Smlaier
4609145836Smlaier		if (dst->scrub || src->scrub) {
4610145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4611145836Smlaier			    *state, src, dst, &copyback))
4612145836Smlaier				return (PF_DROP);
4613145836Smlaier		}
4614145836Smlaier
4615126258Smlaier		/* update max window */
4616126258Smlaier		if (src->max_win < win)
4617126258Smlaier			src->max_win = win;
4618126258Smlaier		/* synchronize sequencing */
4619126258Smlaier		if (SEQ_GT(end, src->seqlo))
4620126258Smlaier			src->seqlo = end;
4621126258Smlaier		/* slide the window of what the other end can send */
4622126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4623126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4624126258Smlaier
4625126258Smlaier
4626126258Smlaier		/* update states */
4627126258Smlaier		if (th->th_flags & TH_SYN)
4628126258Smlaier			if (src->state < TCPS_SYN_SENT)
4629126258Smlaier				src->state = TCPS_SYN_SENT;
4630126258Smlaier		if (th->th_flags & TH_FIN)
4631126258Smlaier			if (src->state < TCPS_CLOSING)
4632126258Smlaier				src->state = TCPS_CLOSING;
4633126258Smlaier		if (th->th_flags & TH_ACK) {
4634145836Smlaier			if (dst->state == TCPS_SYN_SENT) {
4635126258Smlaier				dst->state = TCPS_ESTABLISHED;
4636145836Smlaier				if (src->state == TCPS_ESTABLISHED &&
4637145836Smlaier				    (*state)->src_node != NULL &&
4638145836Smlaier				    pf_src_connlimit(state)) {
4639145836Smlaier					REASON_SET(reason, PFRES_SRCLIMIT);
4640145836Smlaier					return (PF_DROP);
4641145836Smlaier				}
4642145836Smlaier			} else if (dst->state == TCPS_CLOSING)
4643126258Smlaier				dst->state = TCPS_FIN_WAIT_2;
4644126258Smlaier		}
4645126258Smlaier		if (th->th_flags & TH_RST)
4646126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4647126258Smlaier
4648126258Smlaier		/* update expire time */
4649126261Smlaier		(*state)->expire = time_second;
4650126258Smlaier		if (src->state >= TCPS_FIN_WAIT_2 &&
4651126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4652126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSED;
4653126258Smlaier		else if (src->state >= TCPS_FIN_WAIT_2 ||
4654126258Smlaier		    dst->state >= TCPS_FIN_WAIT_2)
4655126258Smlaier			(*state)->timeout = PFTM_TCP_FIN_WAIT;
4656126258Smlaier		else if (src->state < TCPS_ESTABLISHED ||
4657126258Smlaier		    dst->state < TCPS_ESTABLISHED)
4658126258Smlaier			(*state)->timeout = PFTM_TCP_OPENING;
4659126258Smlaier		else if (src->state >= TCPS_CLOSING ||
4660126258Smlaier		    dst->state >= TCPS_CLOSING)
4661126258Smlaier			(*state)->timeout = PFTM_TCP_CLOSING;
4662126258Smlaier		else
4663126258Smlaier			(*state)->timeout = PFTM_TCP_ESTABLISHED;
4664126258Smlaier
4665126258Smlaier		/* Fall through to PASS packet */
4666126258Smlaier
4667126258Smlaier	} else if ((dst->state < TCPS_SYN_SENT ||
4668126258Smlaier		dst->state >= TCPS_FIN_WAIT_2 ||
4669126258Smlaier		src->state >= TCPS_FIN_WAIT_2) &&
4670126258Smlaier	    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) &&
4671126258Smlaier	    /* Within a window forward of the originating packet */
4672126258Smlaier	    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW)) {
4673126258Smlaier	    /* Within a window backward of the originating packet */
4674126258Smlaier
4675126258Smlaier		/*
4676126258Smlaier		 * This currently handles three situations:
4677126258Smlaier		 *  1) Stupid stacks will shotgun SYNs before their peer
4678126258Smlaier		 *     replies.
4679126258Smlaier		 *  2) When PF catches an already established stream (the
4680126258Smlaier		 *     firewall rebooted, the state table was flushed, routes
4681126258Smlaier		 *     changed...)
4682126258Smlaier		 *  3) Packets get funky immediately after the connection
4683126258Smlaier		 *     closes (this should catch Solaris spurious ACK|FINs
4684126258Smlaier		 *     that web servers like to spew after a close)
4685126258Smlaier		 *
4686126258Smlaier		 * This must be a little more careful than the above code
4687126258Smlaier		 * since packet floods will also be caught here. We don't
4688126258Smlaier		 * update the TTL here to mitigate the damage of a packet
4689126258Smlaier		 * flood and so the same code can handle awkward establishment
4690126258Smlaier		 * and a loosened connection close.
4691126258Smlaier		 * In the establishment case, a correct peer response will
4692126258Smlaier		 * validate the connection, go through the normal state code
4693126258Smlaier		 * and keep updating the state TTL.
4694126258Smlaier		 */
4695126258Smlaier
4696126258Smlaier		if (pf_status.debug >= PF_DEBUG_MISC) {
4697126258Smlaier			printf("pf: loose state match: ");
4698126258Smlaier			pf_print_state(*state);
4699126258Smlaier			pf_print_flags(th->th_flags);
4700126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d\n",
4701126258Smlaier			    seq, ack, pd->p_len, ackskew,
4702126258Smlaier			    (*state)->packets[0], (*state)->packets[1]);
4703126258Smlaier		}
4704126258Smlaier
4705145836Smlaier		if (dst->scrub || src->scrub) {
4706145836Smlaier			if (pf_normalize_tcp_stateful(m, off, pd, reason, th,
4707145836Smlaier			    *state, src, dst, &copyback))
4708145836Smlaier				return (PF_DROP);
4709145836Smlaier		}
4710145836Smlaier
4711126258Smlaier		/* update max window */
4712126258Smlaier		if (src->max_win < win)
4713126258Smlaier			src->max_win = win;
4714126258Smlaier		/* synchronize sequencing */
4715126258Smlaier		if (SEQ_GT(end, src->seqlo))
4716126258Smlaier			src->seqlo = end;
4717126258Smlaier		/* slide the window of what the other end can send */
4718126258Smlaier		if (SEQ_GEQ(ack + (win << sws), dst->seqhi))
4719126258Smlaier			dst->seqhi = ack + MAX((win << sws), 1);
4720126258Smlaier
4721126258Smlaier		/*
4722126258Smlaier		 * Cannot set dst->seqhi here since this could be a shotgunned
4723126258Smlaier		 * SYN and not an already established connection.
4724126258Smlaier		 */
4725126258Smlaier
4726126258Smlaier		if (th->th_flags & TH_FIN)
4727126258Smlaier			if (src->state < TCPS_CLOSING)
4728126258Smlaier				src->state = TCPS_CLOSING;
4729126258Smlaier		if (th->th_flags & TH_RST)
4730126258Smlaier			src->state = dst->state = TCPS_TIME_WAIT;
4731126258Smlaier
4732126258Smlaier		/* Fall through to PASS packet */
4733126258Smlaier
4734126258Smlaier	} else {
4735126258Smlaier		if ((*state)->dst.state == TCPS_SYN_SENT &&
4736126258Smlaier		    (*state)->src.state == TCPS_SYN_SENT) {
4737126258Smlaier			/* Send RST for state mismatches during handshake */
4738145836Smlaier			if (!(th->th_flags & TH_RST))
4739162238Scsjp#ifdef __FreeBSD__
4740162238Scsjp				pf_send_tcp(m, (*state)->rule.ptr, pd->af,
4741162238Scsjp#else
4742126258Smlaier				pf_send_tcp((*state)->rule.ptr, pd->af,
4743162238Scsjp#endif
4744126258Smlaier				    pd->dst, pd->src, th->th_dport,
4745145836Smlaier				    th->th_sport, ntohl(th->th_ack), 0,
4746145836Smlaier				    TH_RST, 0, 0,
4747145836Smlaier				    (*state)->rule.ptr->return_ttl, 1,
4748145836Smlaier				    pd->eh, kif->pfik_ifp);
4749126258Smlaier			src->seqlo = 0;
4750126258Smlaier			src->seqhi = 1;
4751126258Smlaier			src->max_win = 1;
4752126258Smlaier		} else if (pf_status.debug >= PF_DEBUG_MISC) {
4753126258Smlaier			printf("pf: BAD state: ");
4754126258Smlaier			pf_print_state(*state);
4755126258Smlaier			pf_print_flags(th->th_flags);
4756126258Smlaier			printf(" seq=%u ack=%u len=%u ackskew=%d pkts=%d:%d "
4757126258Smlaier			    "dir=%s,%s\n", seq, ack, pd->p_len, ackskew,
4758126258Smlaier			    (*state)->packets[0], (*state)->packets[1],
4759126258Smlaier			    direction == PF_IN ? "in" : "out",
4760126258Smlaier			    direction == (*state)->direction ? "fwd" : "rev");
4761126258Smlaier			printf("pf: State failure on: %c %c %c %c | %c %c\n",
4762126258Smlaier			    SEQ_GEQ(src->seqhi, end) ? ' ' : '1',
4763126258Smlaier			    SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws)) ?
4764126258Smlaier			    ' ': '2',
4765126258Smlaier			    (ackskew >= -MAXACKWINDOW) ? ' ' : '3',
4766126258Smlaier			    (ackskew <= (MAXACKWINDOW << sws)) ? ' ' : '4',
4767126258Smlaier			    SEQ_GEQ(src->seqhi + MAXACKWINDOW, end) ?' ' :'5',
4768126258Smlaier			    SEQ_GEQ(seq, src->seqlo - MAXACKWINDOW) ?' ' :'6');
4769126258Smlaier		}
4770145836Smlaier		REASON_SET(reason, PFRES_BADSTATE);
4771126258Smlaier		return (PF_DROP);
4772126258Smlaier	}
4773126258Smlaier
4774126258Smlaier	/* Any packets which have gotten here are to be passed */
4775126258Smlaier
4776126258Smlaier	/* translate source/destination address, if necessary */
4777126258Smlaier	if (STATE_TRANSLATE(*state)) {
4778126258Smlaier		if (direction == PF_OUT)
4779126258Smlaier			pf_change_ap(pd->src, &th->th_sport, pd->ip_sum,
4780126258Smlaier			    &th->th_sum, &(*state)->gwy.addr,
4781126258Smlaier			    (*state)->gwy.port, 0, pd->af);
4782126258Smlaier		else
4783126258Smlaier			pf_change_ap(pd->dst, &th->th_dport, pd->ip_sum,
4784126258Smlaier			    &th->th_sum, &(*state)->lan.addr,
4785126258Smlaier			    (*state)->lan.port, 0, pd->af);
4786126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4787126258Smlaier	} else if (copyback) {
4788126258Smlaier		/* Copyback sequence modulation or stateful scrub changes */
4789126261Smlaier		m_copyback(m, off, sizeof(*th), (caddr_t)th);
4790126258Smlaier	}
4791126258Smlaier
4792126258Smlaier	return (PF_PASS);
4793126258Smlaier}
4794126258Smlaier
4795126258Smlaierint
4796130613Smlaierpf_test_state_udp(struct pf_state **state, int direction, struct pfi_kif *kif,
4797130613Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd)
4798126258Smlaier{
4799126258Smlaier	struct pf_state_peer	*src, *dst;
4800130613Smlaier	struct pf_state		 key;
4801126258Smlaier	struct udphdr		*uh = pd->hdr.udp;
4802126258Smlaier
4803126258Smlaier	key.af = pd->af;
4804126258Smlaier	key.proto = IPPROTO_UDP;
4805130613Smlaier	if (direction == PF_IN)	{
4806130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
4807130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4808130613Smlaier		key.ext.port = uh->uh_sport;
4809130613Smlaier		key.gwy.port = uh->uh_dport;
4810130613Smlaier	} else {
4811130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
4812130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
4813130613Smlaier		key.lan.port = uh->uh_sport;
4814130613Smlaier		key.ext.port = uh->uh_dport;
4815130613Smlaier	}
4816126258Smlaier
4817126258Smlaier	STATE_LOOKUP();
4818126258Smlaier
4819126258Smlaier	if (direction == (*state)->direction) {
4820126258Smlaier		src = &(*state)->src;
4821126258Smlaier		dst = &(*state)->dst;
4822126258Smlaier	} else {
4823126258Smlaier		src = &(*state)->dst;
4824126258Smlaier		dst = &(*state)->src;
4825126258Smlaier	}
4826126258Smlaier
4827126258Smlaier	/* update states */
4828126258Smlaier	if (src->state < PFUDPS_SINGLE)
4829126258Smlaier		src->state = PFUDPS_SINGLE;
4830126258Smlaier	if (dst->state == PFUDPS_SINGLE)
4831126258Smlaier		dst->state = PFUDPS_MULTIPLE;
4832126258Smlaier
4833126258Smlaier	/* update expire time */
4834126261Smlaier	(*state)->expire = time_second;
4835126258Smlaier	if (src->state == PFUDPS_MULTIPLE && dst->state == PFUDPS_MULTIPLE)
4836126258Smlaier		(*state)->timeout = PFTM_UDP_MULTIPLE;
4837126258Smlaier	else
4838126258Smlaier		(*state)->timeout = PFTM_UDP_SINGLE;
4839126258Smlaier
4840126258Smlaier	/* translate source/destination address, if necessary */
4841126258Smlaier	if (STATE_TRANSLATE(*state)) {
4842126258Smlaier		if (direction == PF_OUT)
4843126258Smlaier			pf_change_ap(pd->src, &uh->uh_sport, pd->ip_sum,
4844126258Smlaier			    &uh->uh_sum, &(*state)->gwy.addr,
4845126258Smlaier			    (*state)->gwy.port, 1, pd->af);
4846126258Smlaier		else
4847126258Smlaier			pf_change_ap(pd->dst, &uh->uh_dport, pd->ip_sum,
4848126258Smlaier			    &uh->uh_sum, &(*state)->lan.addr,
4849126258Smlaier			    (*state)->lan.port, 1, pd->af);
4850126261Smlaier		m_copyback(m, off, sizeof(*uh), (caddr_t)uh);
4851126258Smlaier	}
4852126258Smlaier
4853126258Smlaier	return (PF_PASS);
4854126258Smlaier}
4855126258Smlaier
4856126258Smlaierint
4857130613Smlaierpf_test_state_icmp(struct pf_state **state, int direction, struct pfi_kif *kif,
4858145836Smlaier    struct mbuf *m, int off, void *h, struct pf_pdesc *pd, u_short *reason)
4859126258Smlaier{
4860126258Smlaier	struct pf_addr	*saddr = pd->src, *daddr = pd->dst;
4861127629Smlaier	u_int16_t	 icmpid = 0;		/* make the compiler happy */
4862127629Smlaier	u_int16_t	*icmpsum = NULL;	/* make the compiler happy */
4863127629Smlaier	u_int8_t	 icmptype = 0;		/* make the compiler happy */
4864130613Smlaier	int		 state_icmp = 0;
4865126258Smlaier
4866126258Smlaier	switch (pd->proto) {
4867126258Smlaier#ifdef INET
4868126258Smlaier	case IPPROTO_ICMP:
4869126258Smlaier		icmptype = pd->hdr.icmp->icmp_type;
4870126258Smlaier		icmpid = pd->hdr.icmp->icmp_id;
4871126258Smlaier		icmpsum = &pd->hdr.icmp->icmp_cksum;
4872126258Smlaier
4873126258Smlaier		if (icmptype == ICMP_UNREACH ||
4874126258Smlaier		    icmptype == ICMP_SOURCEQUENCH ||
4875126258Smlaier		    icmptype == ICMP_REDIRECT ||
4876126258Smlaier		    icmptype == ICMP_TIMXCEED ||
4877126258Smlaier		    icmptype == ICMP_PARAMPROB)
4878126258Smlaier			state_icmp++;
4879126258Smlaier		break;
4880126258Smlaier#endif /* INET */
4881126258Smlaier#ifdef INET6
4882126258Smlaier	case IPPROTO_ICMPV6:
4883126258Smlaier		icmptype = pd->hdr.icmp6->icmp6_type;
4884126258Smlaier		icmpid = pd->hdr.icmp6->icmp6_id;
4885126258Smlaier		icmpsum = &pd->hdr.icmp6->icmp6_cksum;
4886126258Smlaier
4887126258Smlaier		if (icmptype == ICMP6_DST_UNREACH ||
4888126258Smlaier		    icmptype == ICMP6_PACKET_TOO_BIG ||
4889126258Smlaier		    icmptype == ICMP6_TIME_EXCEEDED ||
4890126258Smlaier		    icmptype == ICMP6_PARAM_PROB)
4891126258Smlaier			state_icmp++;
4892126258Smlaier		break;
4893126258Smlaier#endif /* INET6 */
4894126258Smlaier	}
4895126258Smlaier
4896126258Smlaier	if (!state_icmp) {
4897126258Smlaier
4898126258Smlaier		/*
4899126258Smlaier		 * ICMP query/reply message not related to a TCP/UDP packet.
4900126258Smlaier		 * Search for an ICMP state.
4901126258Smlaier		 */
4902130613Smlaier		struct pf_state		key;
4903126258Smlaier
4904126258Smlaier		key.af = pd->af;
4905126258Smlaier		key.proto = pd->proto;
4906130613Smlaier		if (direction == PF_IN)	{
4907130613Smlaier			PF_ACPY(&key.ext.addr, pd->src, key.af);
4908130613Smlaier			PF_ACPY(&key.gwy.addr, pd->dst, key.af);
4909149884Smlaier			key.ext.port = 0;
4910130613Smlaier			key.gwy.port = icmpid;
4911130613Smlaier		} else {
4912130613Smlaier			PF_ACPY(&key.lan.addr, pd->src, key.af);
4913130613Smlaier			PF_ACPY(&key.ext.addr, pd->dst, key.af);
4914130613Smlaier			key.lan.port = icmpid;
4915149884Smlaier			key.ext.port = 0;
4916130613Smlaier		}
4917126258Smlaier
4918126258Smlaier		STATE_LOOKUP();
4919126258Smlaier
4920126261Smlaier		(*state)->expire = time_second;
4921126258Smlaier		(*state)->timeout = PFTM_ICMP_ERROR_REPLY;
4922126258Smlaier
4923126258Smlaier		/* translate source/destination address, if necessary */
4924149884Smlaier		if (STATE_TRANSLATE(*state)) {
4925126258Smlaier			if (direction == PF_OUT) {
4926126258Smlaier				switch (pd->af) {
4927126258Smlaier#ifdef INET
4928126258Smlaier				case AF_INET:
4929126258Smlaier					pf_change_a(&saddr->v4.s_addr,
4930126258Smlaier					    pd->ip_sum,
4931126258Smlaier					    (*state)->gwy.addr.v4.s_addr, 0);
4932149884Smlaier					pd->hdr.icmp->icmp_cksum =
4933149884Smlaier					    pf_cksum_fixup(
4934149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
4935149884Smlaier					    (*state)->gwy.port, 0);
4936149884Smlaier					pd->hdr.icmp->icmp_id =
4937149884Smlaier					    (*state)->gwy.port;
4938149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
4939149893Smlaier					    (caddr_t)pd->hdr.icmp);
4940126258Smlaier					break;
4941126258Smlaier#endif /* INET */
4942126258Smlaier#ifdef INET6
4943126258Smlaier				case AF_INET6:
4944126258Smlaier					pf_change_a6(saddr,
4945126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4946126258Smlaier					    &(*state)->gwy.addr, 0);
4947126258Smlaier					m_copyback(m, off,
4948126258Smlaier					    sizeof(struct icmp6_hdr),
4949126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4950126258Smlaier					break;
4951126258Smlaier#endif /* INET6 */
4952126258Smlaier				}
4953126258Smlaier			} else {
4954126258Smlaier				switch (pd->af) {
4955126258Smlaier#ifdef INET
4956126258Smlaier				case AF_INET:
4957126258Smlaier					pf_change_a(&daddr->v4.s_addr,
4958126258Smlaier					    pd->ip_sum,
4959126258Smlaier					    (*state)->lan.addr.v4.s_addr, 0);
4960149884Smlaier					pd->hdr.icmp->icmp_cksum =
4961149884Smlaier					    pf_cksum_fixup(
4962149884Smlaier					    pd->hdr.icmp->icmp_cksum, icmpid,
4963149884Smlaier					    (*state)->lan.port, 0);
4964149884Smlaier					pd->hdr.icmp->icmp_id =
4965149884Smlaier					    (*state)->lan.port;
4966149884Smlaier					m_copyback(m, off, ICMP_MINLEN,
4967149893Smlaier					    (caddr_t)pd->hdr.icmp);
4968126258Smlaier					break;
4969126258Smlaier#endif /* INET */
4970126258Smlaier#ifdef INET6
4971126258Smlaier				case AF_INET6:
4972126258Smlaier					pf_change_a6(daddr,
4973126258Smlaier					    &pd->hdr.icmp6->icmp6_cksum,
4974126258Smlaier					    &(*state)->lan.addr, 0);
4975126258Smlaier					m_copyback(m, off,
4976126258Smlaier					    sizeof(struct icmp6_hdr),
4977126261Smlaier					    (caddr_t)pd->hdr.icmp6);
4978126258Smlaier					break;
4979126258Smlaier#endif /* INET6 */
4980126258Smlaier				}
4981126258Smlaier			}
4982126258Smlaier		}
4983126258Smlaier
4984126258Smlaier		return (PF_PASS);
4985126258Smlaier
4986126258Smlaier	} else {
4987126258Smlaier		/*
4988126258Smlaier		 * ICMP error message in response to a TCP/UDP packet.
4989126258Smlaier		 * Extract the inner TCP/UDP header and search for that state.
4990126258Smlaier		 */
4991126258Smlaier
4992126258Smlaier		struct pf_pdesc	pd2;
4993126258Smlaier#ifdef INET
4994126258Smlaier		struct ip	h2;
4995126258Smlaier#endif /* INET */
4996126258Smlaier#ifdef INET6
4997126258Smlaier		struct ip6_hdr	h2_6;
4998126258Smlaier		int		terminal = 0;
4999126258Smlaier#endif /* INET6 */
5000127629Smlaier		int		ipoff2 = 0;	/* make the compiler happy */
5001127629Smlaier		int		off2 = 0;	/* make the compiler happy */
5002126258Smlaier
5003126258Smlaier		pd2.af = pd->af;
5004126258Smlaier		switch (pd->af) {
5005126258Smlaier#ifdef INET
5006126258Smlaier		case AF_INET:
5007126258Smlaier			/* offset of h2 in mbuf chain */
5008126258Smlaier			ipoff2 = off + ICMP_MINLEN;
5009126258Smlaier
5010126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2, sizeof(h2),
5011145836Smlaier			    NULL, reason, pd2.af)) {
5012126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5013126258Smlaier				    ("pf: ICMP error message too short "
5014126258Smlaier				    "(ip)\n"));
5015126258Smlaier				return (PF_DROP);
5016126258Smlaier			}
5017126258Smlaier			/*
5018126258Smlaier			 * ICMP error messages don't refer to non-first
5019126258Smlaier			 * fragments
5020126258Smlaier			 */
5021145836Smlaier			if (h2.ip_off & htons(IP_OFFMASK)) {
5022145836Smlaier				REASON_SET(reason, PFRES_FRAG);
5023126258Smlaier				return (PF_DROP);
5024145836Smlaier			}
5025126258Smlaier
5026126258Smlaier			/* offset of protocol header that follows h2 */
5027126258Smlaier			off2 = ipoff2 + (h2.ip_hl << 2);
5028126258Smlaier
5029126258Smlaier			pd2.proto = h2.ip_p;
5030126258Smlaier			pd2.src = (struct pf_addr *)&h2.ip_src;
5031126258Smlaier			pd2.dst = (struct pf_addr *)&h2.ip_dst;
5032126258Smlaier			pd2.ip_sum = &h2.ip_sum;
5033126258Smlaier			break;
5034126258Smlaier#endif /* INET */
5035126258Smlaier#ifdef INET6
5036126258Smlaier		case AF_INET6:
5037126258Smlaier			ipoff2 = off + sizeof(struct icmp6_hdr);
5038126258Smlaier
5039126258Smlaier			if (!pf_pull_hdr(m, ipoff2, &h2_6, sizeof(h2_6),
5040145836Smlaier			    NULL, reason, pd2.af)) {
5041126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5042126258Smlaier				    ("pf: ICMP error message too short "
5043126258Smlaier				    "(ip6)\n"));
5044126258Smlaier				return (PF_DROP);
5045126258Smlaier			}
5046126258Smlaier			pd2.proto = h2_6.ip6_nxt;
5047126258Smlaier			pd2.src = (struct pf_addr *)&h2_6.ip6_src;
5048126258Smlaier			pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
5049126258Smlaier			pd2.ip_sum = NULL;
5050126258Smlaier			off2 = ipoff2 + sizeof(h2_6);
5051126258Smlaier			do {
5052126258Smlaier				switch (pd2.proto) {
5053126258Smlaier				case IPPROTO_FRAGMENT:
5054126258Smlaier					/*
5055126258Smlaier					 * ICMPv6 error messages for
5056126258Smlaier					 * non-first fragments
5057126258Smlaier					 */
5058145836Smlaier					REASON_SET(reason, PFRES_FRAG);
5059126258Smlaier					return (PF_DROP);
5060126258Smlaier				case IPPROTO_AH:
5061126258Smlaier				case IPPROTO_HOPOPTS:
5062126258Smlaier				case IPPROTO_ROUTING:
5063126258Smlaier				case IPPROTO_DSTOPTS: {
5064126258Smlaier					/* get next header and header length */
5065126258Smlaier					struct ip6_ext opt6;
5066126258Smlaier
5067126258Smlaier					if (!pf_pull_hdr(m, off2, &opt6,
5068145836Smlaier					    sizeof(opt6), NULL, reason,
5069145836Smlaier					    pd2.af)) {
5070126258Smlaier						DPFPRINTF(PF_DEBUG_MISC,
5071126258Smlaier						    ("pf: ICMPv6 short opt\n"));
5072126258Smlaier						return (PF_DROP);
5073126258Smlaier					}
5074126258Smlaier					if (pd2.proto == IPPROTO_AH)
5075126258Smlaier						off2 += (opt6.ip6e_len + 2) * 4;
5076126258Smlaier					else
5077126258Smlaier						off2 += (opt6.ip6e_len + 1) * 8;
5078126258Smlaier					pd2.proto = opt6.ip6e_nxt;
5079126258Smlaier					/* goto the next header */
5080126258Smlaier					break;
5081126258Smlaier				}
5082126258Smlaier				default:
5083126258Smlaier					terminal++;
5084126258Smlaier					break;
5085126258Smlaier				}
5086126258Smlaier			} while (!terminal);
5087126258Smlaier			break;
5088126258Smlaier#endif /* INET6 */
5089126258Smlaier		}
5090126258Smlaier
5091126258Smlaier		switch (pd2.proto) {
5092126258Smlaier		case IPPROTO_TCP: {
5093126258Smlaier			struct tcphdr		 th;
5094126258Smlaier			u_int32_t		 seq;
5095130613Smlaier			struct pf_state		 key;
5096126258Smlaier			struct pf_state_peer	*src, *dst;
5097126258Smlaier			u_int8_t		 dws;
5098128129Smlaier			int			 copyback = 0;
5099126258Smlaier
5100126258Smlaier			/*
5101126258Smlaier			 * Only the first 8 bytes of the TCP header can be
5102126258Smlaier			 * expected. Don't access any TCP header fields after
5103126258Smlaier			 * th_seq, an ackskew test is not possible.
5104126258Smlaier			 */
5105145836Smlaier			if (!pf_pull_hdr(m, off2, &th, 8, NULL, reason,
5106145836Smlaier			    pd2.af)) {
5107126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5108126258Smlaier				    ("pf: ICMP error message too short "
5109126258Smlaier				    "(tcp)\n"));
5110126258Smlaier				return (PF_DROP);
5111126258Smlaier			}
5112126258Smlaier
5113126258Smlaier			key.af = pd2.af;
5114126258Smlaier			key.proto = IPPROTO_TCP;
5115130613Smlaier			if (direction == PF_IN)	{
5116130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5117130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5118130613Smlaier				key.ext.port = th.th_dport;
5119130613Smlaier				key.gwy.port = th.th_sport;
5120130613Smlaier			} else {
5121130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5122130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5123130613Smlaier				key.lan.port = th.th_dport;
5124130613Smlaier				key.ext.port = th.th_sport;
5125130613Smlaier			}
5126126258Smlaier
5127126258Smlaier			STATE_LOOKUP();
5128126258Smlaier
5129126258Smlaier			if (direction == (*state)->direction) {
5130126258Smlaier				src = &(*state)->dst;
5131126258Smlaier				dst = &(*state)->src;
5132126258Smlaier			} else {
5133126258Smlaier				src = &(*state)->src;
5134126258Smlaier				dst = &(*state)->dst;
5135126258Smlaier			}
5136126258Smlaier
5137130613Smlaier			if (src->wscale && dst->wscale &&
5138130613Smlaier			    !(th.th_flags & TH_SYN))
5139126258Smlaier				dws = dst->wscale & PF_WSCALE_MASK;
5140126258Smlaier			else
5141126258Smlaier				dws = 0;
5142126258Smlaier
5143126258Smlaier			/* Demodulate sequence number */
5144126258Smlaier			seq = ntohl(th.th_seq) - src->seqdiff;
5145128129Smlaier			if (src->seqdiff) {
5146128129Smlaier				pf_change_a(&th.th_seq, icmpsum,
5147126258Smlaier				    htonl(seq), 0);
5148128129Smlaier				copyback = 1;
5149128129Smlaier			}
5150126258Smlaier
5151126258Smlaier			if (!SEQ_GEQ(src->seqhi, seq) ||
5152126258Smlaier			    !SEQ_GEQ(seq, src->seqlo - (dst->max_win << dws))) {
5153126258Smlaier				if (pf_status.debug >= PF_DEBUG_MISC) {
5154126258Smlaier					printf("pf: BAD ICMP %d:%d ",
5155126258Smlaier					    icmptype, pd->hdr.icmp->icmp_code);
5156126258Smlaier					pf_print_host(pd->src, 0, pd->af);
5157126258Smlaier					printf(" -> ");
5158126258Smlaier					pf_print_host(pd->dst, 0, pd->af);
5159126258Smlaier					printf(" state: ");
5160126258Smlaier					pf_print_state(*state);
5161126258Smlaier					printf(" seq=%u\n", seq);
5162126258Smlaier				}
5163145836Smlaier				REASON_SET(reason, PFRES_BADSTATE);
5164126258Smlaier				return (PF_DROP);
5165126258Smlaier			}
5166126258Smlaier
5167126258Smlaier			if (STATE_TRANSLATE(*state)) {
5168126258Smlaier				if (direction == PF_IN) {
5169126258Smlaier					pf_change_icmp(pd2.src, &th.th_sport,
5170128129Smlaier					    daddr, &(*state)->lan.addr,
5171126258Smlaier					    (*state)->lan.port, NULL,
5172126258Smlaier					    pd2.ip_sum, icmpsum,
5173126258Smlaier					    pd->ip_sum, 0, pd2.af);
5174126258Smlaier				} else {
5175126258Smlaier					pf_change_icmp(pd2.dst, &th.th_dport,
5176126258Smlaier					    saddr, &(*state)->gwy.addr,
5177126258Smlaier					    (*state)->gwy.port, NULL,
5178126258Smlaier					    pd2.ip_sum, icmpsum,
5179126258Smlaier					    pd->ip_sum, 0, pd2.af);
5180126258Smlaier				}
5181128129Smlaier				copyback = 1;
5182128129Smlaier			}
5183128129Smlaier
5184128129Smlaier			if (copyback) {
5185126258Smlaier				switch (pd2.af) {
5186126258Smlaier#ifdef INET
5187126258Smlaier				case AF_INET:
5188126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5189126261Smlaier					    (caddr_t)pd->hdr.icmp);
5190126258Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5191126261Smlaier					    (caddr_t)&h2);
5192126258Smlaier					break;
5193126258Smlaier#endif /* INET */
5194126258Smlaier#ifdef INET6
5195126258Smlaier				case AF_INET6:
5196126258Smlaier					m_copyback(m, off,
5197126258Smlaier					    sizeof(struct icmp6_hdr),
5198126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5199126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5200126261Smlaier					    (caddr_t)&h2_6);
5201126258Smlaier					break;
5202126258Smlaier#endif /* INET6 */
5203126258Smlaier				}
5204126261Smlaier				m_copyback(m, off2, 8, (caddr_t)&th);
5205126258Smlaier			}
5206126258Smlaier
5207126258Smlaier			return (PF_PASS);
5208126258Smlaier			break;
5209126258Smlaier		}
5210126258Smlaier		case IPPROTO_UDP: {
5211126258Smlaier			struct udphdr		uh;
5212130613Smlaier			struct pf_state		key;
5213126258Smlaier
5214126258Smlaier			if (!pf_pull_hdr(m, off2, &uh, sizeof(uh),
5215145836Smlaier			    NULL, reason, pd2.af)) {
5216126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5217126258Smlaier				    ("pf: ICMP error message too short "
5218126258Smlaier				    "(udp)\n"));
5219126258Smlaier				return (PF_DROP);
5220126258Smlaier			}
5221126258Smlaier
5222126258Smlaier			key.af = pd2.af;
5223126258Smlaier			key.proto = IPPROTO_UDP;
5224130613Smlaier			if (direction == PF_IN)	{
5225130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5226130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5227130613Smlaier				key.ext.port = uh.uh_dport;
5228130613Smlaier				key.gwy.port = uh.uh_sport;
5229130613Smlaier			} else {
5230130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5231130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5232130613Smlaier				key.lan.port = uh.uh_dport;
5233130613Smlaier				key.ext.port = uh.uh_sport;
5234130613Smlaier			}
5235126258Smlaier
5236126258Smlaier			STATE_LOOKUP();
5237126258Smlaier
5238126258Smlaier			if (STATE_TRANSLATE(*state)) {
5239126258Smlaier				if (direction == PF_IN) {
5240126258Smlaier					pf_change_icmp(pd2.src, &uh.uh_sport,
5241126258Smlaier					    daddr, &(*state)->lan.addr,
5242126258Smlaier					    (*state)->lan.port, &uh.uh_sum,
5243126258Smlaier					    pd2.ip_sum, icmpsum,
5244126258Smlaier					    pd->ip_sum, 1, pd2.af);
5245126258Smlaier				} else {
5246126258Smlaier					pf_change_icmp(pd2.dst, &uh.uh_dport,
5247126258Smlaier					    saddr, &(*state)->gwy.addr,
5248126258Smlaier					    (*state)->gwy.port, &uh.uh_sum,
5249126258Smlaier					    pd2.ip_sum, icmpsum,
5250126258Smlaier					    pd->ip_sum, 1, pd2.af);
5251126258Smlaier				}
5252126258Smlaier				switch (pd2.af) {
5253126258Smlaier#ifdef INET
5254126258Smlaier				case AF_INET:
5255126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5256126261Smlaier					    (caddr_t)pd->hdr.icmp);
5257126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5258126261Smlaier					    (caddr_t)&h2);
5259126258Smlaier					break;
5260126258Smlaier#endif /* INET */
5261126258Smlaier#ifdef INET6
5262126258Smlaier				case AF_INET6:
5263126258Smlaier					m_copyback(m, off,
5264126258Smlaier					    sizeof(struct icmp6_hdr),
5265126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5266126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5267126261Smlaier					    (caddr_t)&h2_6);
5268126258Smlaier					break;
5269126258Smlaier#endif /* INET6 */
5270126258Smlaier				}
5271126261Smlaier				m_copyback(m, off2, sizeof(uh),
5272126261Smlaier				    (caddr_t)&uh);
5273126258Smlaier			}
5274126258Smlaier
5275126258Smlaier			return (PF_PASS);
5276126258Smlaier			break;
5277126258Smlaier		}
5278126258Smlaier#ifdef INET
5279126258Smlaier		case IPPROTO_ICMP: {
5280126258Smlaier			struct icmp		iih;
5281130613Smlaier			struct pf_state		key;
5282126258Smlaier
5283126258Smlaier			if (!pf_pull_hdr(m, off2, &iih, ICMP_MINLEN,
5284145836Smlaier			    NULL, reason, pd2.af)) {
5285126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5286126258Smlaier				    ("pf: ICMP error message too short i"
5287126258Smlaier				    "(icmp)\n"));
5288126258Smlaier				return (PF_DROP);
5289126258Smlaier			}
5290126258Smlaier
5291126258Smlaier			key.af = pd2.af;
5292126258Smlaier			key.proto = IPPROTO_ICMP;
5293130613Smlaier			if (direction == PF_IN)	{
5294130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5295130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5296149884Smlaier				key.ext.port = 0;
5297130613Smlaier				key.gwy.port = iih.icmp_id;
5298130613Smlaier			} else {
5299130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5300130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5301130613Smlaier				key.lan.port = iih.icmp_id;
5302149884Smlaier				key.ext.port = 0;
5303130613Smlaier			}
5304126258Smlaier
5305126258Smlaier			STATE_LOOKUP();
5306126258Smlaier
5307126258Smlaier			if (STATE_TRANSLATE(*state)) {
5308126258Smlaier				if (direction == PF_IN) {
5309126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp_id,
5310126258Smlaier					    daddr, &(*state)->lan.addr,
5311126258Smlaier					    (*state)->lan.port, NULL,
5312126258Smlaier					    pd2.ip_sum, icmpsum,
5313126258Smlaier					    pd->ip_sum, 0, AF_INET);
5314126258Smlaier				} else {
5315126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp_id,
5316126258Smlaier					    saddr, &(*state)->gwy.addr,
5317126258Smlaier					    (*state)->gwy.port, NULL,
5318126258Smlaier					    pd2.ip_sum, icmpsum,
5319126258Smlaier					    pd->ip_sum, 0, AF_INET);
5320126258Smlaier				}
5321126261Smlaier				m_copyback(m, off, ICMP_MINLEN,
5322126261Smlaier				    (caddr_t)pd->hdr.icmp);
5323126261Smlaier				m_copyback(m, ipoff2, sizeof(h2),
5324126261Smlaier				    (caddr_t)&h2);
5325126261Smlaier				m_copyback(m, off2, ICMP_MINLEN,
5326126261Smlaier				    (caddr_t)&iih);
5327126258Smlaier			}
5328126258Smlaier
5329126258Smlaier			return (PF_PASS);
5330126258Smlaier			break;
5331126258Smlaier		}
5332126258Smlaier#endif /* INET */
5333126258Smlaier#ifdef INET6
5334126258Smlaier		case IPPROTO_ICMPV6: {
5335126258Smlaier			struct icmp6_hdr	iih;
5336130613Smlaier			struct pf_state		key;
5337126258Smlaier
5338126258Smlaier			if (!pf_pull_hdr(m, off2, &iih,
5339145836Smlaier			    sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
5340126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
5341126258Smlaier				    ("pf: ICMP error message too short "
5342126258Smlaier				    "(icmp6)\n"));
5343126258Smlaier				return (PF_DROP);
5344126258Smlaier			}
5345126258Smlaier
5346126258Smlaier			key.af = pd2.af;
5347126258Smlaier			key.proto = IPPROTO_ICMPV6;
5348130613Smlaier			if (direction == PF_IN)	{
5349130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5350130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5351149884Smlaier				key.ext.port = 0;
5352130613Smlaier				key.gwy.port = iih.icmp6_id;
5353130613Smlaier			} else {
5354130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5355130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5356130613Smlaier				key.lan.port = iih.icmp6_id;
5357149884Smlaier				key.ext.port = 0;
5358130613Smlaier			}
5359126258Smlaier
5360126258Smlaier			STATE_LOOKUP();
5361126258Smlaier
5362126258Smlaier			if (STATE_TRANSLATE(*state)) {
5363126258Smlaier				if (direction == PF_IN) {
5364126258Smlaier					pf_change_icmp(pd2.src, &iih.icmp6_id,
5365126258Smlaier					    daddr, &(*state)->lan.addr,
5366126258Smlaier					    (*state)->lan.port, NULL,
5367126258Smlaier					    pd2.ip_sum, icmpsum,
5368126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5369126258Smlaier				} else {
5370126258Smlaier					pf_change_icmp(pd2.dst, &iih.icmp6_id,
5371126258Smlaier					    saddr, &(*state)->gwy.addr,
5372126258Smlaier					    (*state)->gwy.port, NULL,
5373126258Smlaier					    pd2.ip_sum, icmpsum,
5374126258Smlaier					    pd->ip_sum, 0, AF_INET6);
5375126258Smlaier				}
5376126258Smlaier				m_copyback(m, off, sizeof(struct icmp6_hdr),
5377126261Smlaier				    (caddr_t)pd->hdr.icmp6);
5378126261Smlaier				m_copyback(m, ipoff2, sizeof(h2_6),
5379126261Smlaier				    (caddr_t)&h2_6);
5380126258Smlaier				m_copyback(m, off2, sizeof(struct icmp6_hdr),
5381126261Smlaier				    (caddr_t)&iih);
5382126258Smlaier			}
5383126258Smlaier
5384126258Smlaier			return (PF_PASS);
5385126258Smlaier			break;
5386126258Smlaier		}
5387126258Smlaier#endif /* INET6 */
5388126258Smlaier		default: {
5389130613Smlaier			struct pf_state		key;
5390126258Smlaier
5391126258Smlaier			key.af = pd2.af;
5392126258Smlaier			key.proto = pd2.proto;
5393130613Smlaier			if (direction == PF_IN)	{
5394130613Smlaier				PF_ACPY(&key.ext.addr, pd2.dst, key.af);
5395130613Smlaier				PF_ACPY(&key.gwy.addr, pd2.src, key.af);
5396130613Smlaier				key.ext.port = 0;
5397130613Smlaier				key.gwy.port = 0;
5398130613Smlaier			} else {
5399130613Smlaier				PF_ACPY(&key.lan.addr, pd2.dst, key.af);
5400130613Smlaier				PF_ACPY(&key.ext.addr, pd2.src, key.af);
5401130613Smlaier				key.lan.port = 0;
5402130613Smlaier				key.ext.port = 0;
5403130613Smlaier			}
5404126258Smlaier
5405126258Smlaier			STATE_LOOKUP();
5406126258Smlaier
5407126258Smlaier			if (STATE_TRANSLATE(*state)) {
5408126258Smlaier				if (direction == PF_IN) {
5409126258Smlaier					pf_change_icmp(pd2.src, NULL,
5410126258Smlaier					    daddr, &(*state)->lan.addr,
5411126258Smlaier					    0, NULL,
5412126258Smlaier					    pd2.ip_sum, icmpsum,
5413126258Smlaier					    pd->ip_sum, 0, pd2.af);
5414126258Smlaier				} else {
5415126258Smlaier					pf_change_icmp(pd2.dst, NULL,
5416126258Smlaier					    saddr, &(*state)->gwy.addr,
5417126258Smlaier					    0, NULL,
5418126258Smlaier					    pd2.ip_sum, icmpsum,
5419126258Smlaier					    pd->ip_sum, 0, pd2.af);
5420126258Smlaier				}
5421126258Smlaier				switch (pd2.af) {
5422126258Smlaier#ifdef INET
5423126258Smlaier				case AF_INET:
5424126258Smlaier					m_copyback(m, off, ICMP_MINLEN,
5425126261Smlaier					    (caddr_t)pd->hdr.icmp);
5426126261Smlaier					m_copyback(m, ipoff2, sizeof(h2),
5427126261Smlaier					    (caddr_t)&h2);
5428126258Smlaier					break;
5429126258Smlaier#endif /* INET */
5430126258Smlaier#ifdef INET6
5431126258Smlaier				case AF_INET6:
5432126258Smlaier					m_copyback(m, off,
5433126258Smlaier					    sizeof(struct icmp6_hdr),
5434126261Smlaier					    (caddr_t)pd->hdr.icmp6);
5435126258Smlaier					m_copyback(m, ipoff2, sizeof(h2_6),
5436126261Smlaier					    (caddr_t)&h2_6);
5437126258Smlaier					break;
5438126258Smlaier#endif /* INET6 */
5439126258Smlaier				}
5440126258Smlaier			}
5441126258Smlaier
5442126258Smlaier			return (PF_PASS);
5443126258Smlaier			break;
5444126258Smlaier		}
5445126258Smlaier		}
5446126258Smlaier	}
5447126258Smlaier}
5448126258Smlaier
5449126258Smlaierint
5450130613Smlaierpf_test_state_other(struct pf_state **state, int direction, struct pfi_kif *kif,
5451126258Smlaier    struct pf_pdesc *pd)
5452126258Smlaier{
5453126258Smlaier	struct pf_state_peer	*src, *dst;
5454130613Smlaier	struct pf_state		 key;
5455126258Smlaier
5456126258Smlaier	key.af = pd->af;
5457126258Smlaier	key.proto = pd->proto;
5458130613Smlaier	if (direction == PF_IN)	{
5459130613Smlaier		PF_ACPY(&key.ext.addr, pd->src, key.af);
5460130613Smlaier		PF_ACPY(&key.gwy.addr, pd->dst, key.af);
5461130613Smlaier		key.ext.port = 0;
5462130613Smlaier		key.gwy.port = 0;
5463130613Smlaier	} else {
5464130613Smlaier		PF_ACPY(&key.lan.addr, pd->src, key.af);
5465130613Smlaier		PF_ACPY(&key.ext.addr, pd->dst, key.af);
5466130613Smlaier		key.lan.port = 0;
5467130613Smlaier		key.ext.port = 0;
5468130613Smlaier	}
5469126258Smlaier
5470126258Smlaier	STATE_LOOKUP();
5471126258Smlaier
5472126258Smlaier	if (direction == (*state)->direction) {
5473126258Smlaier		src = &(*state)->src;
5474126258Smlaier		dst = &(*state)->dst;
5475126258Smlaier	} else {
5476126258Smlaier		src = &(*state)->dst;
5477126258Smlaier		dst = &(*state)->src;
5478126258Smlaier	}
5479126258Smlaier
5480126258Smlaier	/* update states */
5481126258Smlaier	if (src->state < PFOTHERS_SINGLE)
5482126258Smlaier		src->state = PFOTHERS_SINGLE;
5483126258Smlaier	if (dst->state == PFOTHERS_SINGLE)
5484126258Smlaier		dst->state = PFOTHERS_MULTIPLE;
5485126258Smlaier
5486126258Smlaier	/* update expire time */
5487126261Smlaier	(*state)->expire = time_second;
5488126258Smlaier	if (src->state == PFOTHERS_MULTIPLE && dst->state == PFOTHERS_MULTIPLE)
5489126258Smlaier		(*state)->timeout = PFTM_OTHER_MULTIPLE;
5490126258Smlaier	else
5491126258Smlaier		(*state)->timeout = PFTM_OTHER_SINGLE;
5492126258Smlaier
5493126258Smlaier	/* translate source/destination address, if necessary */
5494126258Smlaier	if (STATE_TRANSLATE(*state)) {
5495126258Smlaier		if (direction == PF_OUT)
5496126258Smlaier			switch (pd->af) {
5497126258Smlaier#ifdef INET
5498126258Smlaier			case AF_INET:
5499126258Smlaier				pf_change_a(&pd->src->v4.s_addr,
5500126258Smlaier				    pd->ip_sum, (*state)->gwy.addr.v4.s_addr,
5501126258Smlaier				    0);
5502126258Smlaier				break;
5503126258Smlaier#endif /* INET */
5504126258Smlaier#ifdef INET6
5505126258Smlaier			case AF_INET6:
5506126258Smlaier				PF_ACPY(pd->src, &(*state)->gwy.addr, pd->af);
5507126258Smlaier				break;
5508126258Smlaier#endif /* INET6 */
5509126258Smlaier			}
5510126258Smlaier		else
5511126258Smlaier			switch (pd->af) {
5512126258Smlaier#ifdef INET
5513126258Smlaier			case AF_INET:
5514126258Smlaier				pf_change_a(&pd->dst->v4.s_addr,
5515126258Smlaier				    pd->ip_sum, (*state)->lan.addr.v4.s_addr,
5516126258Smlaier				    0);
5517126258Smlaier				break;
5518126258Smlaier#endif /* INET */
5519126258Smlaier#ifdef INET6
5520126258Smlaier			case AF_INET6:
5521126258Smlaier				PF_ACPY(pd->dst, &(*state)->lan.addr, pd->af);
5522126258Smlaier				break;
5523126258Smlaier#endif /* INET6 */
5524126258Smlaier			}
5525126258Smlaier	}
5526126258Smlaier
5527126258Smlaier	return (PF_PASS);
5528126258Smlaier}
5529126258Smlaier
5530126258Smlaier/*
5531126258Smlaier * ipoff and off are measured from the start of the mbuf chain.
5532126258Smlaier * h must be at "ipoff" on the mbuf chain.
5533126258Smlaier */
5534126258Smlaiervoid *
5535126258Smlaierpf_pull_hdr(struct mbuf *m, int off, void *p, int len,
5536126258Smlaier    u_short *actionp, u_short *reasonp, sa_family_t af)
5537126258Smlaier{
5538126258Smlaier	switch (af) {
5539126258Smlaier#ifdef INET
5540126258Smlaier	case AF_INET: {
5541126258Smlaier		struct ip	*h = mtod(m, struct ip *);
5542126258Smlaier		u_int16_t	 fragoff = (ntohs(h->ip_off) & IP_OFFMASK) << 3;
5543126258Smlaier
5544126258Smlaier		if (fragoff) {
5545126258Smlaier			if (fragoff >= len)
5546126258Smlaier				ACTION_SET(actionp, PF_PASS);
5547126258Smlaier			else {
5548126258Smlaier				ACTION_SET(actionp, PF_DROP);
5549126258Smlaier				REASON_SET(reasonp, PFRES_FRAG);
5550126258Smlaier			}
5551126258Smlaier			return (NULL);
5552126258Smlaier		}
5553130613Smlaier		if (m->m_pkthdr.len < off + len ||
5554130613Smlaier		    ntohs(h->ip_len) < off + len) {
5555126258Smlaier			ACTION_SET(actionp, PF_DROP);
5556126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5557126258Smlaier			return (NULL);
5558126258Smlaier		}
5559126258Smlaier		break;
5560126258Smlaier	}
5561126258Smlaier#endif /* INET */
5562126258Smlaier#ifdef INET6
5563126258Smlaier	case AF_INET6: {
5564126258Smlaier		struct ip6_hdr	*h = mtod(m, struct ip6_hdr *);
5565126258Smlaier
5566126258Smlaier		if (m->m_pkthdr.len < off + len ||
5567126258Smlaier		    (ntohs(h->ip6_plen) + sizeof(struct ip6_hdr)) <
5568126258Smlaier		    (unsigned)(off + len)) {
5569126258Smlaier			ACTION_SET(actionp, PF_DROP);
5570126258Smlaier			REASON_SET(reasonp, PFRES_SHORT);
5571126258Smlaier			return (NULL);
5572126258Smlaier		}
5573126258Smlaier		break;
5574126258Smlaier	}
5575126258Smlaier#endif /* INET6 */
5576126258Smlaier	}
5577126258Smlaier	m_copydata(m, off, len, p);
5578126258Smlaier	return (p);
5579126258Smlaier}
5580126258Smlaier
5581126258Smlaierint
5582126258Smlaierpf_routable(struct pf_addr *addr, sa_family_t af)
5583126258Smlaier{
5584126258Smlaier	struct sockaddr_in	*dst;
5585145836Smlaier#ifdef INET6
5586145836Smlaier	struct sockaddr_in6	*dst6;
5587145836Smlaier	struct route_in6	 ro;
5588145836Smlaier#else
5589126258Smlaier	struct route		 ro;
5590145836Smlaier#endif
5591126258Smlaier
5592126258Smlaier	bzero(&ro, sizeof(ro));
5593145836Smlaier	switch (af) {
5594145836Smlaier	case AF_INET:
5595145836Smlaier		dst = satosin(&ro.ro_dst);
5596145836Smlaier		dst->sin_family = AF_INET;
5597145836Smlaier		dst->sin_len = sizeof(*dst);
5598145836Smlaier		dst->sin_addr = addr->v4;
5599145836Smlaier		break;
5600145836Smlaier#ifdef INET6
5601145836Smlaier	case AF_INET6:
5602145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5603145836Smlaier		dst6->sin6_family = AF_INET6;
5604145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5605145836Smlaier		dst6->sin6_addr = addr->v6;
5606145836Smlaier		break;
5607145836Smlaier#endif /* INET6 */
5608145836Smlaier	default:
5609145836Smlaier		return (0);
5610145836Smlaier	}
5611145836Smlaier
5612127145Smlaier#ifdef __FreeBSD__
5613126261Smlaier#ifdef RTF_PRCLONING
5614145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING | RTF_PRCLONING));
5615126261Smlaier#else /* !RTF_PRCLONING */
5616145836Smlaier	rtalloc_ign((struct route *)&ro, RTF_CLONING);
5617126261Smlaier#endif
5618126261Smlaier#else /* ! __FreeBSD__ */
5619145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5620126261Smlaier#endif
5621126258Smlaier
5622126258Smlaier	if (ro.ro_rt != NULL) {
5623126258Smlaier		RTFREE(ro.ro_rt);
5624145836Smlaier		return (1);
5625126258Smlaier	}
5626126258Smlaier
5627145836Smlaier	return (0);
5628145836Smlaier}
5629145836Smlaier
5630145836Smlaierint
5631145836Smlaierpf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
5632145836Smlaier{
5633145836Smlaier	struct sockaddr_in	*dst;
5634145836Smlaier#ifdef INET6
5635145836Smlaier	struct sockaddr_in6	*dst6;
5636145836Smlaier	struct route_in6	 ro;
5637145836Smlaier#else
5638145836Smlaier	struct route		 ro;
5639145836Smlaier#endif
5640145836Smlaier	int			 ret = 0;
5641145836Smlaier
5642145836Smlaier	bzero(&ro, sizeof(ro));
5643145836Smlaier	switch (af) {
5644145836Smlaier	case AF_INET:
5645145836Smlaier		dst = satosin(&ro.ro_dst);
5646145836Smlaier		dst->sin_family = AF_INET;
5647145836Smlaier		dst->sin_len = sizeof(*dst);
5648145836Smlaier		dst->sin_addr = addr->v4;
5649145836Smlaier		break;
5650145836Smlaier#ifdef INET6
5651145836Smlaier	case AF_INET6:
5652145836Smlaier		dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
5653145836Smlaier		dst6->sin6_family = AF_INET6;
5654145836Smlaier		dst6->sin6_len = sizeof(*dst6);
5655145836Smlaier		dst6->sin6_addr = addr->v6;
5656145836Smlaier		break;
5657145836Smlaier#endif /* INET6 */
5658145836Smlaier	default:
5659145836Smlaier		return (0);
5660145836Smlaier	}
5661145836Smlaier
5662145836Smlaier#ifdef __FreeBSD__
5663145836Smlaier# ifdef RTF_PRCLONING
5664145836Smlaier	rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
5665145836Smlaier# else /* !RTF_PRCLONING */
5666145836Smlaier	rtalloc_ign((struct route *)&ro, RTF_CLONING);
5667145836Smlaier# endif
5668145836Smlaier#else /* ! __FreeBSD__ */
5669145836Smlaier	rtalloc_noclone((struct route *)&ro, NO_CLONING);
5670145836Smlaier#endif
5671145836Smlaier
5672145836Smlaier	if (ro.ro_rt != NULL) {
5673145836Smlaier#ifdef __FreeBSD__
5674145836Smlaier		/* XXX_IMPORT: later */
5675145836Smlaier#else
5676145836Smlaier		if (ro.ro_rt->rt_labelid == aw->v.rtlabel)
5677145836Smlaier			ret = 1;
5678145836Smlaier#endif
5679145836Smlaier		RTFREE(ro.ro_rt);
5680145836Smlaier	}
5681145836Smlaier
5682126258Smlaier	return (ret);
5683126258Smlaier}
5684126258Smlaier
5685126258Smlaier#ifdef INET
5686126261Smlaier
5687126258Smlaiervoid
5688126258Smlaierpf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5689126258Smlaier    struct pf_state *s)
5690126258Smlaier{
5691126258Smlaier	struct mbuf		*m0, *m1;
5692132303Smlaier	struct m_tag		*mtag;
5693126258Smlaier	struct route		 iproute;
5694127629Smlaier	struct route		*ro = NULL;	/* XXX: was uninitialized */
5695126258Smlaier	struct sockaddr_in	*dst;
5696126258Smlaier	struct ip		*ip;
5697126258Smlaier	struct ifnet		*ifp = NULL;
5698126258Smlaier	struct pf_addr		 naddr;
5699130613Smlaier	struct pf_src_node	*sn = NULL;
5700126258Smlaier	int			 error = 0;
5701127145Smlaier#ifdef __FreeBSD__
5702126261Smlaier	int sw_csum;
5703126261Smlaier#endif
5704126258Smlaier
5705126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5706126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5707126258Smlaier		panic("pf_route: invalid parameters");
5708126258Smlaier
5709132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
5710132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
5711132303Smlaier		    NULL) {
5712132303Smlaier			m0 = *m;
5713132303Smlaier			*m = NULL;
5714132303Smlaier			goto bad;
5715132303Smlaier		}
5716132303Smlaier		*(char *)(mtag + 1) = 1;
5717132303Smlaier		m_tag_prepend(*m, mtag);
5718132303Smlaier	} else {
5719132303Smlaier		if (*(char *)(mtag + 1) > 3) {
5720132303Smlaier			m0 = *m;
5721132303Smlaier			*m = NULL;
5722132303Smlaier			goto bad;
5723132303Smlaier		}
5724132303Smlaier		(*(char *)(mtag + 1))++;
5725132303Smlaier	}
5726132303Smlaier
5727126258Smlaier	if (r->rt == PF_DUPTO) {
5728127145Smlaier#ifdef __FreeBSD__
5729132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
5730126261Smlaier#else
5731132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
5732126261Smlaier#endif
5733126258Smlaier			return;
5734126258Smlaier	} else {
5735126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
5736126258Smlaier			return;
5737126258Smlaier		m0 = *m;
5738126258Smlaier	}
5739126258Smlaier
5740145836Smlaier	if (m0->m_len < sizeof(struct ip)) {
5741145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
5742145836Smlaier		    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
5743145836Smlaier		goto bad;
5744145836Smlaier	}
5745145836Smlaier
5746126258Smlaier	ip = mtod(m0, struct ip *);
5747126258Smlaier
5748126258Smlaier	ro = &iproute;
5749126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
5750126258Smlaier	dst = satosin(&ro->ro_dst);
5751126258Smlaier	dst->sin_family = AF_INET;
5752126258Smlaier	dst->sin_len = sizeof(*dst);
5753126258Smlaier	dst->sin_addr = ip->ip_dst;
5754126258Smlaier
5755126258Smlaier	if (r->rt == PF_FASTROUTE) {
5756126258Smlaier		rtalloc(ro);
5757126258Smlaier		if (ro->ro_rt == 0) {
5758126258Smlaier			ipstat.ips_noroute++;
5759126258Smlaier			goto bad;
5760126258Smlaier		}
5761126258Smlaier
5762126258Smlaier		ifp = ro->ro_rt->rt_ifp;
5763126258Smlaier		ro->ro_rt->rt_use++;
5764126258Smlaier
5765126258Smlaier		if (ro->ro_rt->rt_flags & RTF_GATEWAY)
5766126258Smlaier			dst = satosin(ro->ro_rt->rt_gateway);
5767126258Smlaier	} else {
5768145836Smlaier		if (TAILQ_EMPTY(&r->rpool.list)) {
5769145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
5770145836Smlaier			    ("pf_route: TAILQ_EMPTY(&r->rpool.list)\n"));
5771145836Smlaier			goto bad;
5772145836Smlaier		}
5773126258Smlaier		if (s == NULL) {
5774130613Smlaier			pf_map_addr(AF_INET, r, (struct pf_addr *)&ip->ip_src,
5775130613Smlaier			    &naddr, NULL, &sn);
5776126258Smlaier			if (!PF_AZERO(&naddr, AF_INET))
5777126258Smlaier				dst->sin_addr.s_addr = naddr.v4.s_addr;
5778130613Smlaier			ifp = r->rpool.cur->kif ?
5779130613Smlaier			    r->rpool.cur->kif->pfik_ifp : NULL;
5780126258Smlaier		} else {
5781126258Smlaier			if (!PF_AZERO(&s->rt_addr, AF_INET))
5782126258Smlaier				dst->sin_addr.s_addr =
5783126258Smlaier				    s->rt_addr.v4.s_addr;
5784130613Smlaier			ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
5785126258Smlaier		}
5786126258Smlaier	}
5787126258Smlaier	if (ifp == NULL)
5788126258Smlaier		goto bad;
5789126258Smlaier
5790130639Smlaier	if (oifp != ifp) {
5791127145Smlaier#ifdef __FreeBSD__
5792126261Smlaier		PF_UNLOCK();
5793145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
5794126261Smlaier			PF_LOCK();
5795126261Smlaier			goto bad;
5796126261Smlaier		} else if (m0 == NULL) {
5797126261Smlaier			PF_LOCK();
5798126261Smlaier			goto done;
5799126261Smlaier		}
5800126261Smlaier		PF_LOCK();
5801126261Smlaier#else
5802145836Smlaier		if (pf_test(PF_OUT, ifp, &m0, NULL) != PF_PASS)
5803126258Smlaier			goto bad;
5804126258Smlaier		else if (m0 == NULL)
5805126258Smlaier			goto done;
5806126261Smlaier#endif
5807145836Smlaier		if (m0->m_len < sizeof(struct ip)) {
5808145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
5809145836Smlaier			    ("pf_route: m0->m_len < sizeof(struct ip)\n"));
5810145836Smlaier			goto bad;
5811145836Smlaier		}
5812126258Smlaier		ip = mtod(m0, struct ip *);
5813126258Smlaier	}
5814126258Smlaier
5815127145Smlaier#ifdef __FreeBSD__
5816126261Smlaier	/* Copied from FreeBSD 5.1-CURRENT ip_output. */
5817126261Smlaier	m0->m_pkthdr.csum_flags |= CSUM_IP;
5818126261Smlaier	sw_csum = m0->m_pkthdr.csum_flags & ~ifp->if_hwassist;
5819126261Smlaier	if (sw_csum & CSUM_DELAY_DATA) {
5820126261Smlaier		/*
5821126261Smlaier		 * XXX: in_delayed_cksum assumes HBO for ip->ip_len (at least)
5822126261Smlaier		 */
5823126261Smlaier		NTOHS(ip->ip_len);
5824126261Smlaier		NTOHS(ip->ip_off);	 /* XXX: needed? */
5825126261Smlaier		in_delayed_cksum(m0);
5826126261Smlaier		HTONS(ip->ip_len);
5827126261Smlaier		HTONS(ip->ip_off);
5828126261Smlaier		sw_csum &= ~CSUM_DELAY_DATA;
5829126261Smlaier	}
5830126261Smlaier	m0->m_pkthdr.csum_flags &= ifp->if_hwassist;
5831126261Smlaier
5832126261Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu ||
5833126261Smlaier	    (ifp->if_hwassist & CSUM_FRAGMENT &&
5834126261Smlaier		((ip->ip_off & htons(IP_DF)) == 0))) {
5835126261Smlaier		/*
5836126261Smlaier		 * ip->ip_len = htons(ip->ip_len);
5837126261Smlaier		 * ip->ip_off = htons(ip->ip_off);
5838126261Smlaier		 */
5839126261Smlaier		ip->ip_sum = 0;
5840126261Smlaier		if (sw_csum & CSUM_DELAY_IP) {
5841126261Smlaier			/* From KAME */
5842126261Smlaier			if (ip->ip_v == IPVERSION &&
5843126261Smlaier			    (ip->ip_hl << 2) == sizeof(*ip)) {
5844126261Smlaier				ip->ip_sum = in_cksum_hdr(ip);
5845126261Smlaier			} else {
5846126261Smlaier				ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5847126261Smlaier			}
5848126261Smlaier		}
5849126261Smlaier		PF_UNLOCK();
5850126261Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), ro->ro_rt);
5851126261Smlaier		PF_LOCK();
5852126261Smlaier		goto done;
5853126261Smlaier	}
5854126261Smlaier
5855126261Smlaier#else
5856126258Smlaier	/* Copied from ip_output. */
5857130613Smlaier#ifdef IPSEC
5858130613Smlaier	/*
5859130613Smlaier	 * If deferred crypto processing is needed, check that the
5860130613Smlaier	 * interface supports it.
5861130613Smlaier	 */
5862130613Smlaier	if ((mtag = m_tag_find(m0, PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED, NULL))
5863130613Smlaier	    != NULL && (ifp->if_capabilities & IFCAP_IPSEC) == 0) {
5864130613Smlaier		/* Notify IPsec to do its own crypto. */
5865130613Smlaier		ipsp_skipcrypto_unmark((struct tdb_ident *)(mtag + 1));
5866130613Smlaier		goto bad;
5867130613Smlaier	}
5868130613Smlaier#endif /* IPSEC */
5869130613Smlaier
5870130613Smlaier	/* Catch routing changes wrt. hardware checksumming for TCP or UDP. */
5871130613Smlaier	if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT) {
5872130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
5873130613Smlaier		    ifp->if_bridge != NULL) {
5874130613Smlaier			in_delayed_cksum(m0);
5875130613Smlaier			m0->m_pkthdr.csum &= ~M_TCPV4_CSUM_OUT; /* Clear */
5876130613Smlaier		}
5877130613Smlaier	} else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT) {
5878130613Smlaier		if (!(ifp->if_capabilities & IFCAP_CSUM_UDPv4) ||
5879130613Smlaier		    ifp->if_bridge != NULL) {
5880130613Smlaier			in_delayed_cksum(m0);
5881130613Smlaier			m0->m_pkthdr.csum &= ~M_UDPV4_CSUM_OUT; /* Clear */
5882130613Smlaier		}
5883130613Smlaier	}
5884130613Smlaier
5885126258Smlaier	if (ntohs(ip->ip_len) <= ifp->if_mtu) {
5886126258Smlaier		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
5887126258Smlaier		    ifp->if_bridge == NULL) {
5888126258Smlaier			m0->m_pkthdr.csum |= M_IPV4_CSUM_OUT;
5889126258Smlaier			ipstat.ips_outhwcsum++;
5890126258Smlaier		} else {
5891126258Smlaier			ip->ip_sum = 0;
5892126258Smlaier			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
5893126258Smlaier		}
5894126258Smlaier		/* Update relevant hardware checksum stats for TCP/UDP */
5895126258Smlaier		if (m0->m_pkthdr.csum & M_TCPV4_CSUM_OUT)
5896126258Smlaier			tcpstat.tcps_outhwcsum++;
5897126258Smlaier		else if (m0->m_pkthdr.csum & M_UDPV4_CSUM_OUT)
5898126258Smlaier			udpstat.udps_outhwcsum++;
5899126258Smlaier		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
5900126258Smlaier		goto done;
5901126258Smlaier	}
5902126261Smlaier#endif
5903126258Smlaier	/*
5904126258Smlaier	 * Too large for interface; fragment if possible.
5905126258Smlaier	 * Must be able to put at least 8 bytes per fragment.
5906126258Smlaier	 */
5907126258Smlaier	if (ip->ip_off & htons(IP_DF)) {
5908126258Smlaier		ipstat.ips_cantfrag++;
5909126258Smlaier		if (r->rt != PF_DUPTO) {
5910127145Smlaier#ifdef __FreeBSD__
5911126261Smlaier			/* icmp_error() expects host byte ordering */
5912126261Smlaier			NTOHS(ip->ip_len);
5913126261Smlaier			NTOHS(ip->ip_off);
5914126261Smlaier			PF_UNLOCK();
5915126258Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
5916145886Smlaier			    ifp->if_mtu);
5917145874Smlaier			PF_LOCK();
5918145874Smlaier#else
5919145874Smlaier			icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
5920145873Smlaier			    ifp);
5921126261Smlaier#endif
5922126258Smlaier			goto done;
5923126258Smlaier		} else
5924126258Smlaier			goto bad;
5925126258Smlaier	}
5926126258Smlaier
5927126258Smlaier	m1 = m0;
5928127145Smlaier#ifdef __FreeBSD__
5929126261Smlaier	/*
5930126261Smlaier	 * XXX: is cheaper + less error prone than own function
5931126261Smlaier	 */
5932126261Smlaier	NTOHS(ip->ip_len);
5933126261Smlaier	NTOHS(ip->ip_off);
5934126261Smlaier	error = ip_fragment(ip, &m0, ifp->if_mtu, ifp->if_hwassist, sw_csum);
5935126261Smlaier#else
5936126258Smlaier	error = ip_fragment(m0, ifp, ifp->if_mtu);
5937126261Smlaier#endif
5938127531Smlaier	if (error) {
5939127531Smlaier#ifndef __FreeBSD__	/* ip_fragment does not do m_freem() on FreeBSD */
5940127531Smlaier		m0 = NULL;
5941126261Smlaier#endif
5942126258Smlaier		goto bad;
5943127531Smlaier	}
5944126258Smlaier
5945126258Smlaier	for (m0 = m1; m0; m0 = m1) {
5946126258Smlaier		m1 = m0->m_nextpkt;
5947126258Smlaier		m0->m_nextpkt = 0;
5948127145Smlaier#ifdef __FreeBSD__
5949126261Smlaier		if (error == 0) {
5950126261Smlaier			PF_UNLOCK();
5951126261Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5952126261Smlaier			    NULL);
5953126261Smlaier			PF_LOCK();
5954126261Smlaier		} else
5955126261Smlaier#else
5956126258Smlaier		if (error == 0)
5957126258Smlaier			error = (*ifp->if_output)(ifp, m0, sintosa(dst),
5958126258Smlaier			    NULL);
5959126258Smlaier		else
5960126261Smlaier#endif
5961126258Smlaier			m_freem(m0);
5962126258Smlaier	}
5963126258Smlaier
5964126258Smlaier	if (error == 0)
5965126258Smlaier		ipstat.ips_fragmented++;
5966126258Smlaier
5967126258Smlaierdone:
5968126258Smlaier	if (r->rt != PF_DUPTO)
5969126258Smlaier		*m = NULL;
5970126258Smlaier	if (ro == &iproute && ro->ro_rt)
5971126258Smlaier		RTFREE(ro->ro_rt);
5972126258Smlaier	return;
5973126258Smlaier
5974126258Smlaierbad:
5975126258Smlaier	m_freem(m0);
5976126258Smlaier	goto done;
5977126258Smlaier}
5978126258Smlaier#endif /* INET */
5979126258Smlaier
5980126258Smlaier#ifdef INET6
5981126258Smlaiervoid
5982126258Smlaierpf_route6(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
5983126258Smlaier    struct pf_state *s)
5984126258Smlaier{
5985126258Smlaier	struct mbuf		*m0;
5986126258Smlaier	struct m_tag		*mtag;
5987126258Smlaier	struct route_in6	 ip6route;
5988126258Smlaier	struct route_in6	*ro;
5989126258Smlaier	struct sockaddr_in6	*dst;
5990126258Smlaier	struct ip6_hdr		*ip6;
5991126258Smlaier	struct ifnet		*ifp = NULL;
5992126258Smlaier	struct pf_addr		 naddr;
5993130613Smlaier	struct pf_src_node	*sn = NULL;
5994126258Smlaier	int			 error = 0;
5995126258Smlaier
5996126258Smlaier	if (m == NULL || *m == NULL || r == NULL ||
5997126258Smlaier	    (dir != PF_IN && dir != PF_OUT) || oifp == NULL)
5998126258Smlaier		panic("pf_route6: invalid parameters");
5999126258Smlaier
6000132303Smlaier	if ((mtag = m_tag_find(*m, PACKET_TAG_PF_ROUTED, NULL)) == NULL) {
6001132303Smlaier		if ((mtag = m_tag_get(PACKET_TAG_PF_ROUTED, 1, M_NOWAIT)) ==
6002132303Smlaier		    NULL) {
6003132303Smlaier			m0 = *m;
6004132303Smlaier			*m = NULL;
6005132303Smlaier			goto bad;
6006132303Smlaier		}
6007132303Smlaier		*(char *)(mtag + 1) = 1;
6008132303Smlaier		m_tag_prepend(*m, mtag);
6009132303Smlaier	} else {
6010132303Smlaier		if (*(char *)(mtag + 1) > 3) {
6011132303Smlaier			m0 = *m;
6012132303Smlaier			*m = NULL;
6013132303Smlaier			goto bad;
6014132303Smlaier		}
6015132303Smlaier		(*(char *)(mtag + 1))++;
6016132303Smlaier	}
6017132303Smlaier
6018126258Smlaier	if (r->rt == PF_DUPTO) {
6019127145Smlaier#ifdef __FreeBSD__
6020132303Smlaier		if ((m0 = m_dup(*m, M_DONTWAIT)) == NULL)
6021126261Smlaier#else
6022132303Smlaier		if ((m0 = m_copym2(*m, 0, M_COPYALL, M_NOWAIT)) == NULL)
6023126261Smlaier#endif
6024126258Smlaier			return;
6025126258Smlaier	} else {
6026126258Smlaier		if ((r->rt == PF_REPLYTO) == (r->direction == dir))
6027126258Smlaier			return;
6028126258Smlaier		m0 = *m;
6029126258Smlaier	}
6030126258Smlaier
6031145836Smlaier	if (m0->m_len < sizeof(struct ip6_hdr)) {
6032145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6033145836Smlaier		    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6034145836Smlaier		goto bad;
6035145836Smlaier	}
6036126258Smlaier	ip6 = mtod(m0, struct ip6_hdr *);
6037126258Smlaier
6038126258Smlaier	ro = &ip6route;
6039126258Smlaier	bzero((caddr_t)ro, sizeof(*ro));
6040126258Smlaier	dst = (struct sockaddr_in6 *)&ro->ro_dst;
6041126258Smlaier	dst->sin6_family = AF_INET6;
6042126258Smlaier	dst->sin6_len = sizeof(*dst);
6043126258Smlaier	dst->sin6_addr = ip6->ip6_dst;
6044126258Smlaier
6045126258Smlaier	/* Cheat. */
6046126258Smlaier	if (r->rt == PF_FASTROUTE) {
6047127145Smlaier#ifdef __FreeBSD__
6048132280Smlaier		m0->m_flags |= M_SKIP_FIREWALL;
6049126261Smlaier		PF_UNLOCK();
6050126261Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL, NULL);
6051126261Smlaier		PF_LOCK();
6052126261Smlaier#else
6053132280Smlaier		mtag = m_tag_get(PACKET_TAG_PF_GENERATED, 0, M_NOWAIT);
6054132280Smlaier		if (mtag == NULL)
6055132280Smlaier			goto bad;
6056132280Smlaier		m_tag_prepend(m0, mtag);
6057126258Smlaier		ip6_output(m0, NULL, NULL, 0, NULL, NULL);
6058126261Smlaier#endif
6059126258Smlaier		return;
6060126258Smlaier	}
6061126258Smlaier
6062145836Smlaier	if (TAILQ_EMPTY(&r->rpool.list)) {
6063145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6064145836Smlaier		    ("pf_route6: TAILQ_EMPTY(&r->rpool.list)\n"));
6065145836Smlaier		goto bad;
6066145836Smlaier	}
6067126258Smlaier	if (s == NULL) {
6068130613Smlaier		pf_map_addr(AF_INET6, r, (struct pf_addr *)&ip6->ip6_src,
6069130613Smlaier		    &naddr, NULL, &sn);
6070126258Smlaier		if (!PF_AZERO(&naddr, AF_INET6))
6071126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6072126258Smlaier			    &naddr, AF_INET6);
6073130613Smlaier		ifp = r->rpool.cur->kif ? r->rpool.cur->kif->pfik_ifp : NULL;
6074126258Smlaier	} else {
6075126258Smlaier		if (!PF_AZERO(&s->rt_addr, AF_INET6))
6076126258Smlaier			PF_ACPY((struct pf_addr *)&dst->sin6_addr,
6077126258Smlaier			    &s->rt_addr, AF_INET6);
6078130613Smlaier		ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
6079126258Smlaier	}
6080126258Smlaier	if (ifp == NULL)
6081126258Smlaier		goto bad;
6082126258Smlaier
6083126258Smlaier	if (oifp != ifp) {
6084127145Smlaier#ifdef __FreeBSD__
6085132303Smlaier		PF_UNLOCK();
6086145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL, NULL) != PF_PASS) {
6087126261Smlaier			PF_LOCK();
6088132303Smlaier			goto bad;
6089132303Smlaier		} else if (m0 == NULL) {
6090132303Smlaier			PF_LOCK();
6091132303Smlaier			goto done;
6092132303Smlaier		}
6093132303Smlaier		PF_LOCK();
6094126261Smlaier#else
6095145836Smlaier		if (pf_test6(PF_OUT, ifp, &m0, NULL) != PF_PASS)
6096132303Smlaier			goto bad;
6097132303Smlaier		else if (m0 == NULL)
6098132303Smlaier			goto done;
6099126261Smlaier#endif
6100145836Smlaier		if (m0->m_len < sizeof(struct ip6_hdr)) {
6101145836Smlaier			DPFPRINTF(PF_DEBUG_URGENT,
6102145836Smlaier			    ("pf_route6: m0->m_len < sizeof(struct ip6_hdr)\n"));
6103145836Smlaier			goto bad;
6104145836Smlaier		}
6105132303Smlaier		ip6 = mtod(m0, struct ip6_hdr *);
6106126258Smlaier	}
6107126258Smlaier
6108126258Smlaier	/*
6109126258Smlaier	 * If the packet is too large for the outgoing interface,
6110126258Smlaier	 * send back an icmp6 error.
6111126258Smlaier	 */
6112126258Smlaier	if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr))
6113126258Smlaier		dst->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
6114126258Smlaier	if ((u_long)m0->m_pkthdr.len <= ifp->if_mtu) {
6115127145Smlaier#ifdef __FreeBSD__
6116126261Smlaier		PF_UNLOCK();
6117126261Smlaier#endif
6118126258Smlaier		error = nd6_output(ifp, ifp, m0, dst, NULL);
6119127145Smlaier#ifdef __FreeBSD__
6120126261Smlaier		PF_LOCK();
6121126261Smlaier#endif
6122126258Smlaier	} else {
6123126258Smlaier		in6_ifstat_inc(ifp, ifs6_in_toobig);
6124127145Smlaier#ifdef __FreeBSD__
6125126261Smlaier		if (r->rt != PF_DUPTO) {
6126126261Smlaier			PF_UNLOCK();
6127126261Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6128126261Smlaier			PF_LOCK();
6129126261Smlaier		 } else
6130126261Smlaier#else
6131126258Smlaier		if (r->rt != PF_DUPTO)
6132126258Smlaier			icmp6_error(m0, ICMP6_PACKET_TOO_BIG, 0, ifp->if_mtu);
6133126258Smlaier		else
6134126261Smlaier#endif
6135126258Smlaier			goto bad;
6136126258Smlaier	}
6137126258Smlaier
6138126258Smlaierdone:
6139126258Smlaier	if (r->rt != PF_DUPTO)
6140126258Smlaier		*m = NULL;
6141126258Smlaier	return;
6142126258Smlaier
6143126258Smlaierbad:
6144126258Smlaier	m_freem(m0);
6145126258Smlaier	goto done;
6146126258Smlaier}
6147126258Smlaier#endif /* INET6 */
6148126258Smlaier
6149126258Smlaier
6150127145Smlaier#ifdef __FreeBSD__
6151126258Smlaier/*
6152132566Smlaier * FreeBSD supports cksum offloads for the following drivers.
6153137413Sru *  em(4), fxp(4), ixgb(4), lge(4), ndis(4), nge(4), re(4),
6154132566Smlaier *   ti(4), txp(4), xl(4)
6155132566Smlaier *
6156132566Smlaier * CSUM_DATA_VALID | CSUM_PSEUDO_HDR :
6157132566Smlaier *  network driver performed cksum including pseudo header, need to verify
6158132566Smlaier *   csum_data
6159132566Smlaier * CSUM_DATA_VALID :
6160132566Smlaier *  network driver performed cksum, needs to additional pseudo header
6161132566Smlaier *  cksum computation with partial csum_data(i.e. lack of H/W support for
6162132566Smlaier *  pseudo header, for instance hme(4), sk(4) and possibly gem(4))
6163132566Smlaier *
6164132566Smlaier * After validating the cksum of packet, set both flag CSUM_DATA_VALID and
6165132566Smlaier * CSUM_PSEUDO_HDR in order to avoid recomputation of the cksum in upper
6166132566Smlaier * TCP/UDP layer.
6167132566Smlaier * Also, set csum_data to 0xffff to force cksum validation.
6168126261Smlaier */
6169126261Smlaierint
6170126261Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p, sa_family_t af)
6171126261Smlaier{
6172126261Smlaier	u_int16_t sum = 0;
6173126261Smlaier	int hw_assist = 0;
6174126261Smlaier	struct ip *ip;
6175126261Smlaier
6176126261Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6177126261Smlaier		return (1);
6178126261Smlaier	if (m->m_pkthdr.len < off + len)
6179126261Smlaier		return (1);
6180126261Smlaier
6181126261Smlaier	switch (p) {
6182126261Smlaier	case IPPROTO_TCP:
6183126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6184126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6185126261Smlaier				sum = m->m_pkthdr.csum_data;
6186126261Smlaier			} else {
6187126261Smlaier				ip = mtod(m, struct ip *);
6188126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6189135078Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6190135078Smlaier					m->m_pkthdr.csum_data + IPPROTO_TCP));
6191126261Smlaier			}
6192126261Smlaier			sum ^= 0xffff;
6193126261Smlaier			++hw_assist;
6194126261Smlaier		}
6195126261Smlaier		break;
6196126261Smlaier	case IPPROTO_UDP:
6197126261Smlaier		if (m->m_pkthdr.csum_flags & CSUM_DATA_VALID) {
6198126261Smlaier			if (m->m_pkthdr.csum_flags & CSUM_PSEUDO_HDR) {
6199126261Smlaier				sum = m->m_pkthdr.csum_data;
6200126261Smlaier			} else {
6201126261Smlaier				ip = mtod(m, struct ip *);
6202126261Smlaier				sum = in_pseudo(ip->ip_src.s_addr,
6203126261Smlaier					ip->ip_dst.s_addr, htonl((u_short)len +
6204126261Smlaier					m->m_pkthdr.csum_data + IPPROTO_UDP));
6205126261Smlaier			}
6206126261Smlaier			sum ^= 0xffff;
6207126261Smlaier			++hw_assist;
6208126261Smlaier                }
6209126261Smlaier		break;
6210126261Smlaier	case IPPROTO_ICMP:
6211126261Smlaier#ifdef INET6
6212126261Smlaier	case IPPROTO_ICMPV6:
6213126261Smlaier#endif /* INET6 */
6214126261Smlaier		break;
6215126261Smlaier	default:
6216126261Smlaier		return (1);
6217126261Smlaier	}
6218126261Smlaier
6219126261Smlaier	if (!hw_assist) {
6220126261Smlaier		switch (af) {
6221126261Smlaier		case AF_INET:
6222126261Smlaier			if (p == IPPROTO_ICMP) {
6223126261Smlaier				if (m->m_len < off)
6224126261Smlaier					return (1);
6225126261Smlaier				m->m_data += off;
6226126261Smlaier				m->m_len -= off;
6227126261Smlaier				sum = in_cksum(m, len);
6228126261Smlaier				m->m_data -= off;
6229126261Smlaier				m->m_len += off;
6230126261Smlaier			} else {
6231126261Smlaier				if (m->m_len < sizeof(struct ip))
6232126261Smlaier					return (1);
6233126261Smlaier				sum = in4_cksum(m, p, off, len);
6234126261Smlaier			}
6235126261Smlaier			break;
6236126261Smlaier#ifdef INET6
6237126261Smlaier		case AF_INET6:
6238126261Smlaier			if (m->m_len < sizeof(struct ip6_hdr))
6239126261Smlaier				return (1);
6240126261Smlaier			sum = in6_cksum(m, p, off, len);
6241126261Smlaier			break;
6242126261Smlaier#endif /* INET6 */
6243126261Smlaier		default:
6244126261Smlaier			return (1);
6245126261Smlaier		}
6246126261Smlaier	}
6247126261Smlaier	if (sum) {
6248126261Smlaier		switch (p) {
6249126261Smlaier		case IPPROTO_TCP:
6250126261Smlaier			tcpstat.tcps_rcvbadsum++;
6251126261Smlaier			break;
6252126261Smlaier		case IPPROTO_UDP:
6253126261Smlaier			udpstat.udps_badsum++;
6254126261Smlaier			break;
6255126261Smlaier		case IPPROTO_ICMP:
6256126261Smlaier			icmpstat.icps_checksum++;
6257126261Smlaier			break;
6258126261Smlaier#ifdef INET6
6259126261Smlaier		case IPPROTO_ICMPV6:
6260126261Smlaier			icmp6stat.icp6s_checksum++;
6261126261Smlaier			break;
6262126261Smlaier#endif /* INET6 */
6263126261Smlaier		}
6264126261Smlaier		return (1);
6265132566Smlaier	} else {
6266132566Smlaier		if (p == IPPROTO_TCP || p == IPPROTO_UDP) {
6267132566Smlaier			m->m_pkthdr.csum_flags |=
6268132566Smlaier			    (CSUM_DATA_VALID | CSUM_PSEUDO_HDR);
6269132566Smlaier			m->m_pkthdr.csum_data = 0xffff;
6270132566Smlaier		}
6271126261Smlaier	}
6272126261Smlaier	return (0);
6273126261Smlaier}
6274126261Smlaier#else
6275126261Smlaier/*
6276126258Smlaier * check protocol (tcp/udp/icmp/icmp6) checksum and set mbuf flag
6277126258Smlaier *   off is the offset where the protocol header starts
6278126258Smlaier *   len is the total length of protocol header plus payload
6279126258Smlaier * returns 0 when the checksum is valid, otherwise returns 1.
6280126258Smlaier */
6281126258Smlaierint
6282130613Smlaierpf_check_proto_cksum(struct mbuf *m, int off, int len, u_int8_t p,
6283130613Smlaier    sa_family_t af)
6284126258Smlaier{
6285126258Smlaier	u_int16_t flag_ok, flag_bad;
6286126258Smlaier	u_int16_t sum;
6287126258Smlaier
6288126258Smlaier	switch (p) {
6289126258Smlaier	case IPPROTO_TCP:
6290126258Smlaier		flag_ok = M_TCP_CSUM_IN_OK;
6291126258Smlaier		flag_bad = M_TCP_CSUM_IN_BAD;
6292126258Smlaier		break;
6293126258Smlaier	case IPPROTO_UDP:
6294126258Smlaier		flag_ok = M_UDP_CSUM_IN_OK;
6295126258Smlaier		flag_bad = M_UDP_CSUM_IN_BAD;
6296126258Smlaier		break;
6297126258Smlaier	case IPPROTO_ICMP:
6298126258Smlaier#ifdef INET6
6299126258Smlaier	case IPPROTO_ICMPV6:
6300126258Smlaier#endif /* INET6 */
6301126258Smlaier		flag_ok = flag_bad = 0;
6302126258Smlaier		break;
6303126258Smlaier	default:
6304126258Smlaier		return (1);
6305126258Smlaier	}
6306126258Smlaier	if (m->m_pkthdr.csum & flag_ok)
6307126258Smlaier		return (0);
6308126258Smlaier	if (m->m_pkthdr.csum & flag_bad)
6309126258Smlaier		return (1);
6310126258Smlaier	if (off < sizeof(struct ip) || len < sizeof(struct udphdr))
6311126258Smlaier		return (1);
6312126258Smlaier	if (m->m_pkthdr.len < off + len)
6313126258Smlaier		return (1);
6314145836Smlaier	switch (af) {
6315145836Smlaier#ifdef INET
6316126258Smlaier	case AF_INET:
6317126258Smlaier		if (p == IPPROTO_ICMP) {
6318126258Smlaier			if (m->m_len < off)
6319126258Smlaier				return (1);
6320126258Smlaier			m->m_data += off;
6321126258Smlaier			m->m_len -= off;
6322126258Smlaier			sum = in_cksum(m, len);
6323126258Smlaier			m->m_data -= off;
6324126258Smlaier			m->m_len += off;
6325126258Smlaier		} else {
6326126258Smlaier			if (m->m_len < sizeof(struct ip))
6327126258Smlaier				return (1);
6328126258Smlaier			sum = in4_cksum(m, p, off, len);
6329126258Smlaier		}
6330126258Smlaier		break;
6331145836Smlaier#endif /* INET */
6332126258Smlaier#ifdef INET6
6333126258Smlaier	case AF_INET6:
6334126258Smlaier		if (m->m_len < sizeof(struct ip6_hdr))
6335126258Smlaier			return (1);
6336126258Smlaier		sum = in6_cksum(m, p, off, len);
6337126258Smlaier		break;
6338126258Smlaier#endif /* INET6 */
6339126258Smlaier	default:
6340126258Smlaier		return (1);
6341126258Smlaier	}
6342126258Smlaier	if (sum) {
6343126258Smlaier		m->m_pkthdr.csum |= flag_bad;
6344126258Smlaier		switch (p) {
6345126258Smlaier		case IPPROTO_TCP:
6346126258Smlaier			tcpstat.tcps_rcvbadsum++;
6347126258Smlaier			break;
6348126258Smlaier		case IPPROTO_UDP:
6349126258Smlaier			udpstat.udps_badsum++;
6350126258Smlaier			break;
6351126258Smlaier		case IPPROTO_ICMP:
6352126258Smlaier			icmpstat.icps_checksum++;
6353126258Smlaier			break;
6354126258Smlaier#ifdef INET6
6355126258Smlaier		case IPPROTO_ICMPV6:
6356126258Smlaier			icmp6stat.icp6s_checksum++;
6357126258Smlaier			break;
6358126258Smlaier#endif /* INET6 */
6359126258Smlaier		}
6360126258Smlaier		return (1);
6361126258Smlaier	}
6362126258Smlaier	m->m_pkthdr.csum |= flag_ok;
6363126258Smlaier	return (0);
6364126258Smlaier}
6365126261Smlaier#endif
6366126258Smlaier
6367130613Smlaierstatic int
6368130613Smlaierpf_add_mbuf_tag(struct mbuf *m, u_int tag)
6369130613Smlaier{
6370130613Smlaier	struct m_tag *mtag;
6371130613Smlaier
6372130613Smlaier	if (m_tag_find(m, tag, NULL) != NULL)
6373130613Smlaier		return (0);
6374130613Smlaier	mtag = m_tag_get(tag, 0, M_NOWAIT);
6375130613Smlaier	if (mtag == NULL)
6376130613Smlaier		return (1);
6377130613Smlaier	m_tag_prepend(m, mtag);
6378130613Smlaier	return (0);
6379130613Smlaier}
6380130613Smlaier
6381126258Smlaier#ifdef INET
6382126258Smlaierint
6383135920Smlaier#ifdef __FreeBSD__
6384145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6385145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6386135920Smlaier#else
6387145836Smlaierpf_test(int dir, struct ifnet *ifp, struct mbuf **m0,
6388145836Smlaier    struct ether_header *eh)
6389135920Smlaier#endif
6390126258Smlaier{
6391130613Smlaier	struct pfi_kif		*kif;
6392130613Smlaier	u_short			 action, reason = 0, log = 0;
6393130613Smlaier	struct mbuf		*m = *m0;
6394130613Smlaier	struct ip		*h = NULL;	/* make the compiler happy */
6395130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6396130613Smlaier	struct pf_state		*s = NULL;
6397130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6398130613Smlaier	struct pf_pdesc		 pd;
6399130613Smlaier	int			 off, dirndx, pqid = 0;
6400126258Smlaier
6401127145Smlaier#ifdef __FreeBSD__
6402126261Smlaier	PF_LOCK();
6403126261Smlaier#endif
6404126258Smlaier	if (!pf_status.running ||
6405127145Smlaier#ifdef __FreeBSD__
6406132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
6407126261Smlaier		PF_UNLOCK();
6408132280Smlaier#else
6409132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
6410126261Smlaier#endif
6411126261Smlaier	    	return (PF_PASS);
6412126261Smlaier	}
6413126258Smlaier
6414145836Smlaier#ifdef __FreeBSD__
6415145836Smlaier	/* XXX_IMPORT: later */
6416145836Smlaier#else
6417145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6418145836Smlaier		ifp = ifp->if_carpdev;
6419145836Smlaier#endif
6420145836Smlaier
6421130613Smlaier	kif = pfi_index2kif[ifp->if_index];
6422130613Smlaier	if (kif == NULL) {
6423130613Smlaier#ifdef __FreeBSD__
6424130613Smlaier		PF_UNLOCK();
6425130613Smlaier#endif
6426145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6427145836Smlaier		    ("pf_test: kif == NULL, if_xname %s\n", ifp->if_xname));
6428130613Smlaier		return (PF_DROP);
6429130613Smlaier	}
6430145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6431145836Smlaier#ifdef __FreeBSD__
6432145836Smlaier		PF_UNLOCK();
6433145836Smlaier#endif
6434145836Smlaier		return (PF_PASS);
6435145836Smlaier	}
6436130613Smlaier
6437130613Smlaier#ifdef __FreeBSD__
6438126261Smlaier	M_ASSERTPKTHDR(m);
6439126261Smlaier#else
6440126258Smlaier#ifdef DIAGNOSTIC
6441126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6442126258Smlaier		panic("non-M_PKTHDR is passed to pf_test");
6443145836Smlaier#endif /* DIAGNOSTIC */
6444145836Smlaier#endif /* __FreeBSD__ */
6445126258Smlaier
6446130613Smlaier	memset(&pd, 0, sizeof(pd));
6447126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6448126258Smlaier		action = PF_DROP;
6449126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6450126258Smlaier		log = 1;
6451126258Smlaier		goto done;
6452126258Smlaier	}
6453126258Smlaier
6454126258Smlaier	/* We do IP header normalization and packet reassembly here */
6455145836Smlaier	if (pf_normalize_ip(m0, dir, kif, &reason, &pd) != PF_PASS) {
6456126258Smlaier		action = PF_DROP;
6457126258Smlaier		goto done;
6458126258Smlaier	}
6459126258Smlaier	m = *m0;
6460126258Smlaier	h = mtod(m, struct ip *);
6461126258Smlaier
6462126258Smlaier	off = h->ip_hl << 2;
6463126258Smlaier	if (off < (int)sizeof(*h)) {
6464126258Smlaier		action = PF_DROP;
6465126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6466126258Smlaier		log = 1;
6467126258Smlaier		goto done;
6468126258Smlaier	}
6469126258Smlaier
6470126258Smlaier	pd.src = (struct pf_addr *)&h->ip_src;
6471126258Smlaier	pd.dst = (struct pf_addr *)&h->ip_dst;
6472130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET);
6473126258Smlaier	pd.ip_sum = &h->ip_sum;
6474126258Smlaier	pd.proto = h->ip_p;
6475126258Smlaier	pd.af = AF_INET;
6476126258Smlaier	pd.tos = h->ip_tos;
6477126258Smlaier	pd.tot_len = ntohs(h->ip_len);
6478145836Smlaier	pd.eh = eh;
6479126258Smlaier
6480126258Smlaier	/* handle fragments that didn't get reassembled by normalization */
6481126258Smlaier	if (h->ip_off & htons(IP_MF | IP_OFFMASK)) {
6482130613Smlaier		action = pf_test_fragment(&r, dir, kif, m, h,
6483126258Smlaier		    &pd, &a, &ruleset);
6484126258Smlaier		goto done;
6485126258Smlaier	}
6486126258Smlaier
6487126258Smlaier	switch (h->ip_p) {
6488126258Smlaier
6489126258Smlaier	case IPPROTO_TCP: {
6490126258Smlaier		struct tcphdr	th;
6491126258Smlaier
6492126258Smlaier		pd.hdr.tcp = &th;
6493126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6494126258Smlaier		    &action, &reason, AF_INET)) {
6495126258Smlaier			log = action != PF_PASS;
6496126258Smlaier			goto done;
6497126258Smlaier		}
6498126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6499126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_TCP, AF_INET)) {
6500126258Smlaier			action = PF_DROP;
6501126258Smlaier			goto done;
6502126258Smlaier		}
6503126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6504126258Smlaier		if ((th.th_flags & TH_ACK) && pd.p_len == 0)
6505126258Smlaier			pqid = 1;
6506130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6507126258Smlaier		if (action == PF_DROP)
6508130613Smlaier			goto done;
6509130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6510126258Smlaier		    &reason);
6511126258Smlaier		if (action == PF_PASS) {
6512130613Smlaier#if NPFSYNC
6513130613Smlaier			pfsync_update_state(s);
6514145836Smlaier#endif /* NPFSYNC */
6515126258Smlaier			r = s->rule.ptr;
6516130613Smlaier			a = s->anchor.ptr;
6517126258Smlaier			log = s->log;
6518126258Smlaier		} else if (s == NULL)
6519135920Smlaier#ifdef __FreeBSD__
6520130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6521145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6522135920Smlaier#else
6523135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6524145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6525135920Smlaier#endif
6526126258Smlaier		break;
6527126258Smlaier	}
6528126258Smlaier
6529126258Smlaier	case IPPROTO_UDP: {
6530126258Smlaier		struct udphdr	uh;
6531126258Smlaier
6532126258Smlaier		pd.hdr.udp = &uh;
6533126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6534126258Smlaier		    &action, &reason, AF_INET)) {
6535126258Smlaier			log = action != PF_PASS;
6536126258Smlaier			goto done;
6537126258Smlaier		}
6538126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6539126258Smlaier		    off, ntohs(h->ip_len) - off, IPPROTO_UDP, AF_INET)) {
6540126258Smlaier			action = PF_DROP;
6541126258Smlaier			goto done;
6542126258Smlaier		}
6543130613Smlaier		if (uh.uh_dport == 0 ||
6544130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6545130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6546130613Smlaier			action = PF_DROP;
6547130613Smlaier			goto done;
6548130613Smlaier		}
6549130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6550126258Smlaier		if (action == PF_PASS) {
6551130613Smlaier#if NPFSYNC
6552130613Smlaier			pfsync_update_state(s);
6553145836Smlaier#endif /* NPFSYNC */
6554126258Smlaier			r = s->rule.ptr;
6555126258Smlaier			a = s->anchor.ptr;
6556126258Smlaier			log = s->log;
6557126258Smlaier		} else if (s == NULL)
6558135920Smlaier#ifdef __FreeBSD__
6559130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6560145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6561135920Smlaier#else
6562135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6563145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6564135920Smlaier#endif
6565126258Smlaier		break;
6566126258Smlaier	}
6567126258Smlaier
6568126258Smlaier	case IPPROTO_ICMP: {
6569126258Smlaier		struct icmp	ih;
6570126258Smlaier
6571126258Smlaier		pd.hdr.icmp = &ih;
6572126258Smlaier		if (!pf_pull_hdr(m, off, &ih, ICMP_MINLEN,
6573126258Smlaier		    &action, &reason, AF_INET)) {
6574126258Smlaier			log = action != PF_PASS;
6575126258Smlaier			goto done;
6576126258Smlaier		}
6577126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6578126258Smlaier		    ntohs(h->ip_len) - off, IPPROTO_ICMP, AF_INET)) {
6579126258Smlaier			action = PF_DROP;
6580126258Smlaier			goto done;
6581126258Smlaier		}
6582145836Smlaier		action = pf_test_state_icmp(&s, dir, kif, m, off, h, &pd,
6583145836Smlaier		    &reason);
6584126258Smlaier		if (action == PF_PASS) {
6585130613Smlaier#if NPFSYNC
6586130613Smlaier			pfsync_update_state(s);
6587145836Smlaier#endif /* NPFSYNC */
6588126258Smlaier			r = s->rule.ptr;
6589126258Smlaier			a = s->anchor.ptr;
6590126258Smlaier			log = s->log;
6591126258Smlaier		} else if (s == NULL)
6592145836Smlaier#ifdef __FreeBSD__
6593130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6594145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6595145836Smlaier#else
6596145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6597145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ipintrq);
6598145836Smlaier#endif
6599126258Smlaier		break;
6600126258Smlaier	}
6601126258Smlaier
6602126258Smlaier	default:
6603130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
6604126258Smlaier		if (action == PF_PASS) {
6605130613Smlaier#if NPFSYNC
6606130613Smlaier			pfsync_update_state(s);
6607145836Smlaier#endif /* NPFSYNC */
6608126258Smlaier			r = s->rule.ptr;
6609126258Smlaier			a = s->anchor.ptr;
6610126258Smlaier			log = s->log;
6611126258Smlaier		} else if (s == NULL)
6612145836Smlaier#ifdef __FreeBSD__
6613130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6614145836Smlaier			    &pd, &a, &ruleset, NULL);
6615145836Smlaier#else
6616145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
6617145836Smlaier			    &pd, &a, &ruleset, &ipintrq);
6618145836Smlaier#endif
6619126258Smlaier		break;
6620126258Smlaier	}
6621126258Smlaier
6622126258Smlaierdone:
6623126258Smlaier	if (action == PF_PASS && h->ip_hl > 5 &&
6624126258Smlaier	    !((s && s->allow_opts) || r->allow_opts)) {
6625126258Smlaier		action = PF_DROP;
6626145836Smlaier		REASON_SET(&reason, PFRES_IPOPTIONS);
6627126258Smlaier		log = 1;
6628126258Smlaier		DPFPRINTF(PF_DEBUG_MISC,
6629126258Smlaier		    ("pf: dropping packet with ip options\n"));
6630126258Smlaier	}
6631126258Smlaier
6632145836Smlaier	if (s && s->tag)
6633145836Smlaier		pf_tag_packet(m, pf_get_tag(m), s->tag);
6634145836Smlaier
6635126258Smlaier#ifdef ALTQ
6636126258Smlaier	if (action == PF_PASS && r->qid) {
6637126258Smlaier		struct m_tag	*mtag;
6638126258Smlaier		struct altq_tag	*atag;
6639126258Smlaier
6640126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
6641126258Smlaier		if (mtag != NULL) {
6642126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
6643126258Smlaier			if (pqid || pd.tos == IPTOS_LOWDELAY)
6644126258Smlaier				atag->qid = r->pqid;
6645126258Smlaier			else
6646126258Smlaier				atag->qid = r->qid;
6647126258Smlaier			/* add hints for ecn */
6648126258Smlaier			atag->af = AF_INET;
6649126258Smlaier			atag->hdr = h;
6650126258Smlaier			m_tag_prepend(m, mtag);
6651126258Smlaier		}
6652126258Smlaier	}
6653145836Smlaier#endif /* ALTQ */
6654126258Smlaier
6655130613Smlaier	/*
6656130613Smlaier	 * connections redirected to loopback should not match sockets
6657130613Smlaier	 * bound specifically to loopback due to security implications,
6658130613Smlaier	 * see tcp_input() and in_pcblookup_listen().
6659130613Smlaier	 */
6660130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
6661130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
6662130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
6663130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
6664130613Smlaier	    (ntohl(pd.dst->v4.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET &&
6665130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
6666130613Smlaier		action = PF_DROP;
6667130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
6668130613Smlaier	}
6669130613Smlaier
6670126258Smlaier	if (log)
6671130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET, dir, reason, r, a, ruleset);
6672126258Smlaier
6673130613Smlaier	kif->pfik_bytes[0][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
6674130613Smlaier	kif->pfik_packets[0][dir == PF_OUT][action != PF_PASS]++;
6675130613Smlaier
6676130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
6677130613Smlaier		r->packets++;
6678130613Smlaier		r->bytes += pd.tot_len;
6679130613Smlaier		if (a != NULL) {
6680130613Smlaier			a->packets++;
6681130613Smlaier			a->bytes += pd.tot_len;
6682130613Smlaier		}
6683130613Smlaier		if (s != NULL) {
6684130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
6685130613Smlaier			s->packets[dirndx]++;
6686130613Smlaier			s->bytes[dirndx] += pd.tot_len;
6687130613Smlaier			if (s->nat_rule.ptr != NULL) {
6688130613Smlaier				s->nat_rule.ptr->packets++;
6689130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
6690130613Smlaier			}
6691130613Smlaier			if (s->src_node != NULL) {
6692130613Smlaier				s->src_node->packets++;
6693130613Smlaier				s->src_node->bytes += pd.tot_len;
6694130613Smlaier			}
6695130613Smlaier			if (s->nat_src_node != NULL) {
6696130613Smlaier				s->nat_src_node->packets++;
6697130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
6698130613Smlaier			}
6699130613Smlaier		}
6700130613Smlaier		tr = r;
6701130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
6702130613Smlaier		if (nr != NULL) {
6703130613Smlaier			struct pf_addr *x;
6704130613Smlaier			/*
6705130613Smlaier			 * XXX: we need to make sure that the addresses
6706130613Smlaier			 * passed to pfr_update_stats() are the same than
6707130613Smlaier			 * the addresses used during matching (pfr_match)
6708130613Smlaier			 */
6709130613Smlaier			if (r == &pf_default_rule) {
6710130613Smlaier				tr = nr;
6711130613Smlaier				x = (s == NULL || s->direction == dir) ?
6712130613Smlaier				    &pd.baddr : &pd.naddr;
6713130613Smlaier			} else
6714130613Smlaier				x = (s == NULL || s->direction == dir) ?
6715130613Smlaier				    &pd.naddr : &pd.baddr;
6716130613Smlaier			if (x == &pd.baddr || s == NULL) {
6717130613Smlaier				/* we need to change the address */
6718130613Smlaier				if (dir == PF_OUT)
6719130613Smlaier					pd.src = x;
6720130613Smlaier				else
6721130613Smlaier					pd.dst = x;
6722130613Smlaier			}
6723130613Smlaier		}
6724130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
6725130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
6726130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
6727130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6728145836Smlaier			    tr->src.neg);
6729130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
6730130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
6731130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
6732130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
6733145836Smlaier			    tr->dst.neg);
6734130613Smlaier	}
6735130613Smlaier
6736130613Smlaier
6737126258Smlaier	if (action == PF_SYNPROXY_DROP) {
6738126258Smlaier		m_freem(*m0);
6739126258Smlaier		*m0 = NULL;
6740126258Smlaier		action = PF_PASS;
6741126258Smlaier	} else if (r->rt)
6742126258Smlaier		/* pf_route can free the mbuf causing *m0 to become NULL */
6743126258Smlaier		pf_route(m0, r, dir, ifp, s);
6744126258Smlaier
6745127145Smlaier#ifdef __FreeBSD__
6746126261Smlaier	PF_UNLOCK();
6747126261Smlaier#endif
6748126261Smlaier
6749126258Smlaier	return (action);
6750126258Smlaier}
6751126258Smlaier#endif /* INET */
6752126258Smlaier
6753126258Smlaier#ifdef INET6
6754126258Smlaierint
6755135920Smlaier#ifdef __FreeBSD__
6756145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
6757145836Smlaier    struct ether_header *eh, struct inpcb *inp)
6758135920Smlaier#else
6759145836Smlaierpf_test6(int dir, struct ifnet *ifp, struct mbuf **m0,
6760145836Smlaier    struct ether_header *eh)
6761135920Smlaier#endif
6762126258Smlaier{
6763130613Smlaier	struct pfi_kif		*kif;
6764130613Smlaier	u_short			 action, reason = 0, log = 0;
6765130613Smlaier	struct mbuf		*m = *m0;
6766130613Smlaier	struct ip6_hdr		*h = NULL;	/* make the compiler happy */
6767130613Smlaier	struct pf_rule		*a = NULL, *r = &pf_default_rule, *tr, *nr;
6768130613Smlaier	struct pf_state		*s = NULL;
6769130613Smlaier	struct pf_ruleset	*ruleset = NULL;
6770130613Smlaier	struct pf_pdesc		 pd;
6771130613Smlaier	int			 off, terminal = 0, dirndx;
6772126258Smlaier
6773127145Smlaier#ifdef __FreeBSD__
6774126261Smlaier	PF_LOCK();
6775126261Smlaier#endif
6776126261Smlaier
6777126258Smlaier	if (!pf_status.running ||
6778127145Smlaier#ifdef __FreeBSD__
6779132280Smlaier	    (m->m_flags & M_SKIP_FIREWALL)) {
6780126261Smlaier		PF_UNLOCK();
6781132280Smlaier#else
6782132280Smlaier	    (m_tag_find(m, PACKET_TAG_PF_GENERATED, NULL) != NULL)) {
6783126261Smlaier#endif
6784126258Smlaier		return (PF_PASS);
6785126261Smlaier	}
6786126258Smlaier
6787145836Smlaier#ifdef __FreeBSD__
6788145836Smlaier	/* XXX_IMPORT: later */
6789145836Smlaier#else
6790145836Smlaier	if (ifp->if_type == IFT_CARP && ifp->if_carpdev)
6791145836Smlaier		ifp = ifp->if_carpdev;
6792145836Smlaier#endif
6793145836Smlaier
6794130613Smlaier	kif = pfi_index2kif[ifp->if_index];
6795130613Smlaier	if (kif == NULL) {
6796130613Smlaier#ifdef __FreeBSD__
6797130613Smlaier		PF_UNLOCK();
6798130613Smlaier#endif
6799145836Smlaier		DPFPRINTF(PF_DEBUG_URGENT,
6800145836Smlaier		    ("pf_test6: kif == NULL, if_xname %s\n", ifp->if_xname));
6801130613Smlaier		return (PF_DROP);
6802130613Smlaier	}
6803145836Smlaier	if (kif->pfik_flags & PFI_IFLAG_SKIP) {
6804145836Smlaier#ifdef __FreeBSD__
6805145836Smlaier		PF_UNLOCK();
6806145836Smlaier#endif
6807145836Smlaier		return (PF_PASS);
6808145836Smlaier	}
6809130613Smlaier
6810130613Smlaier#ifdef __FreeBSD__
6811126261Smlaier	M_ASSERTPKTHDR(m);
6812126261Smlaier#else
6813126258Smlaier#ifdef DIAGNOSTIC
6814126258Smlaier	if ((m->m_flags & M_PKTHDR) == 0)
6815145836Smlaier		panic("non-M_PKTHDR is passed to pf_test6");
6816145836Smlaier#endif /* DIAGNOSTIC */
6817126258Smlaier#endif
6818126258Smlaier
6819130613Smlaier	memset(&pd, 0, sizeof(pd));
6820126258Smlaier	if (m->m_pkthdr.len < (int)sizeof(*h)) {
6821126258Smlaier		action = PF_DROP;
6822126258Smlaier		REASON_SET(&reason, PFRES_SHORT);
6823126258Smlaier		log = 1;
6824126258Smlaier		goto done;
6825126258Smlaier	}
6826126258Smlaier
6827126258Smlaier	/* We do IP header normalization and packet reassembly here */
6828145836Smlaier	if (pf_normalize_ip6(m0, dir, kif, &reason, &pd) != PF_PASS) {
6829126258Smlaier		action = PF_DROP;
6830126258Smlaier		goto done;
6831126258Smlaier	}
6832126258Smlaier	m = *m0;
6833126258Smlaier	h = mtod(m, struct ip6_hdr *);
6834126258Smlaier
6835126258Smlaier	pd.src = (struct pf_addr *)&h->ip6_src;
6836126258Smlaier	pd.dst = (struct pf_addr *)&h->ip6_dst;
6837130613Smlaier	PF_ACPY(&pd.baddr, dir == PF_OUT ? pd.src : pd.dst, AF_INET6);
6838126258Smlaier	pd.ip_sum = NULL;
6839126258Smlaier	pd.af = AF_INET6;
6840126258Smlaier	pd.tos = 0;
6841126258Smlaier	pd.tot_len = ntohs(h->ip6_plen) + sizeof(struct ip6_hdr);
6842145836Smlaier	pd.eh = eh;
6843126258Smlaier
6844126258Smlaier	off = ((caddr_t)h - m->m_data) + sizeof(struct ip6_hdr);
6845126258Smlaier	pd.proto = h->ip6_nxt;
6846126258Smlaier	do {
6847126258Smlaier		switch (pd.proto) {
6848126258Smlaier		case IPPROTO_FRAGMENT:
6849130613Smlaier			action = pf_test_fragment(&r, dir, kif, m, h,
6850126258Smlaier			    &pd, &a, &ruleset);
6851126258Smlaier			if (action == PF_DROP)
6852126258Smlaier				REASON_SET(&reason, PFRES_FRAG);
6853126258Smlaier			goto done;
6854126258Smlaier		case IPPROTO_AH:
6855126258Smlaier		case IPPROTO_HOPOPTS:
6856126258Smlaier		case IPPROTO_ROUTING:
6857126258Smlaier		case IPPROTO_DSTOPTS: {
6858126258Smlaier			/* get next header and header length */
6859126258Smlaier			struct ip6_ext	opt6;
6860126258Smlaier
6861126258Smlaier			if (!pf_pull_hdr(m, off, &opt6, sizeof(opt6),
6862145836Smlaier			    NULL, &reason, pd.af)) {
6863126258Smlaier				DPFPRINTF(PF_DEBUG_MISC,
6864126258Smlaier				    ("pf: IPv6 short opt\n"));
6865126258Smlaier				action = PF_DROP;
6866126258Smlaier				log = 1;
6867126258Smlaier				goto done;
6868126258Smlaier			}
6869126258Smlaier			if (pd.proto == IPPROTO_AH)
6870126258Smlaier				off += (opt6.ip6e_len + 2) * 4;
6871126258Smlaier			else
6872126258Smlaier				off += (opt6.ip6e_len + 1) * 8;
6873126258Smlaier			pd.proto = opt6.ip6e_nxt;
6874126258Smlaier			/* goto the next header */
6875126258Smlaier			break;
6876126258Smlaier		}
6877126258Smlaier		default:
6878126258Smlaier			terminal++;
6879126258Smlaier			break;
6880126258Smlaier		}
6881126258Smlaier	} while (!terminal);
6882126258Smlaier
6883126258Smlaier	switch (pd.proto) {
6884126258Smlaier
6885126258Smlaier	case IPPROTO_TCP: {
6886126258Smlaier		struct tcphdr	th;
6887126258Smlaier
6888126258Smlaier		pd.hdr.tcp = &th;
6889126258Smlaier		if (!pf_pull_hdr(m, off, &th, sizeof(th),
6890126258Smlaier		    &action, &reason, AF_INET6)) {
6891126258Smlaier			log = action != PF_PASS;
6892126258Smlaier			goto done;
6893126258Smlaier		}
6894126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6895138387Sdhartmei		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6896138387Sdhartmei		    IPPROTO_TCP, AF_INET6)) {
6897126258Smlaier			action = PF_DROP;
6898145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6899126258Smlaier			goto done;
6900126258Smlaier		}
6901126258Smlaier		pd.p_len = pd.tot_len - off - (th.th_off << 2);
6902130613Smlaier		action = pf_normalize_tcp(dir, kif, m, 0, off, h, &pd);
6903126258Smlaier		if (action == PF_DROP)
6904130613Smlaier			goto done;
6905130613Smlaier		action = pf_test_state_tcp(&s, dir, kif, m, off, h, &pd,
6906126258Smlaier		    &reason);
6907126258Smlaier		if (action == PF_PASS) {
6908130613Smlaier#if NPFSYNC
6909130613Smlaier			pfsync_update_state(s);
6910145836Smlaier#endif /* NPFSYNC */
6911126258Smlaier			r = s->rule.ptr;
6912130613Smlaier			a = s->anchor.ptr;
6913126258Smlaier			log = s->log;
6914126258Smlaier		} else if (s == NULL)
6915135920Smlaier#ifdef __FreeBSD__
6916130613Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6917145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6918135920Smlaier#else
6919135920Smlaier			action = pf_test_tcp(&r, &s, dir, kif,
6920145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6921135920Smlaier#endif
6922126258Smlaier		break;
6923126258Smlaier	}
6924126258Smlaier
6925126258Smlaier	case IPPROTO_UDP: {
6926126258Smlaier		struct udphdr	uh;
6927126258Smlaier
6928126258Smlaier		pd.hdr.udp = &uh;
6929126258Smlaier		if (!pf_pull_hdr(m, off, &uh, sizeof(uh),
6930126258Smlaier		    &action, &reason, AF_INET6)) {
6931126258Smlaier			log = action != PF_PASS;
6932126258Smlaier			goto done;
6933126258Smlaier		}
6934126258Smlaier		if (dir == PF_IN && uh.uh_sum && pf_check_proto_cksum(m,
6935138387Sdhartmei		    off, ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6936138387Sdhartmei		    IPPROTO_UDP, AF_INET6)) {
6937126258Smlaier			action = PF_DROP;
6938145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6939126258Smlaier			goto done;
6940126258Smlaier		}
6941130613Smlaier		if (uh.uh_dport == 0 ||
6942130613Smlaier		    ntohs(uh.uh_ulen) > m->m_pkthdr.len - off ||
6943130613Smlaier		    ntohs(uh.uh_ulen) < sizeof(struct udphdr)) {
6944130613Smlaier			action = PF_DROP;
6945130613Smlaier			goto done;
6946130613Smlaier		}
6947130613Smlaier		action = pf_test_state_udp(&s, dir, kif, m, off, h, &pd);
6948126258Smlaier		if (action == PF_PASS) {
6949130613Smlaier#if NPFSYNC
6950130613Smlaier			pfsync_update_state(s);
6951145836Smlaier#endif /* NPFSYNC */
6952126258Smlaier			r = s->rule.ptr;
6953130613Smlaier			a = s->anchor.ptr;
6954126258Smlaier			log = s->log;
6955126258Smlaier		} else if (s == NULL)
6956135920Smlaier#ifdef __FreeBSD__
6957130613Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6958145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL, inp);
6959135920Smlaier#else
6960135920Smlaier			action = pf_test_udp(&r, &s, dir, kif,
6961145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6962135920Smlaier#endif
6963126258Smlaier		break;
6964126258Smlaier	}
6965126258Smlaier
6966126258Smlaier	case IPPROTO_ICMPV6: {
6967126258Smlaier		struct icmp6_hdr	ih;
6968126258Smlaier
6969126258Smlaier		pd.hdr.icmp6 = &ih;
6970126258Smlaier		if (!pf_pull_hdr(m, off, &ih, sizeof(ih),
6971126258Smlaier		    &action, &reason, AF_INET6)) {
6972126258Smlaier			log = action != PF_PASS;
6973126258Smlaier			goto done;
6974126258Smlaier		}
6975126258Smlaier		if (dir == PF_IN && pf_check_proto_cksum(m, off,
6976145836Smlaier		    ntohs(h->ip6_plen) - (off - sizeof(struct ip6_hdr)),
6977138387Sdhartmei		    IPPROTO_ICMPV6, AF_INET6)) {
6978126258Smlaier			action = PF_DROP;
6979145836Smlaier			REASON_SET(&reason, PFRES_PROTCKSUM);
6980126258Smlaier			goto done;
6981126258Smlaier		}
6982130613Smlaier		action = pf_test_state_icmp(&s, dir, kif,
6983145836Smlaier		    m, off, h, &pd, &reason);
6984126258Smlaier		if (action == PF_PASS) {
6985130613Smlaier#if NPFSYNC
6986130613Smlaier			pfsync_update_state(s);
6987145836Smlaier#endif /* NPFSYNC */
6988126258Smlaier			r = s->rule.ptr;
6989130613Smlaier			a = s->anchor.ptr;
6990126258Smlaier			log = s->log;
6991126258Smlaier		} else if (s == NULL)
6992145836Smlaier#ifdef __FreeBSD__
6993130613Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6994145836Smlaier			    m, off, h, &pd, &a, &ruleset, NULL);
6995145836Smlaier#else
6996145836Smlaier			action = pf_test_icmp(&r, &s, dir, kif,
6997145836Smlaier			    m, off, h, &pd, &a, &ruleset, &ip6intrq);
6998145836Smlaier#endif
6999126258Smlaier		break;
7000126258Smlaier	}
7001126258Smlaier
7002126258Smlaier	default:
7003130613Smlaier		action = pf_test_state_other(&s, dir, kif, &pd);
7004130613Smlaier		if (action == PF_PASS) {
7005145836Smlaier#if NPFSYNC
7006145836Smlaier			pfsync_update_state(s);
7007145836Smlaier#endif /* NPFSYNC */
7008130613Smlaier			r = s->rule.ptr;
7009130613Smlaier			a = s->anchor.ptr;
7010130613Smlaier			log = s->log;
7011130613Smlaier		} else if (s == NULL)
7012145836Smlaier#ifdef __FreeBSD__
7013130613Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7014145836Smlaier			    &pd, &a, &ruleset, NULL);
7015145836Smlaier#else
7016145836Smlaier			action = pf_test_other(&r, &s, dir, kif, m, off, h,
7017145836Smlaier			    &pd, &a, &ruleset, &ip6intrq);
7018145836Smlaier#endif
7019126258Smlaier		break;
7020126258Smlaier	}
7021126258Smlaier
7022126258Smlaierdone:
7023126258Smlaier	/* XXX handle IPv6 options, if not allowed. not implemented. */
7024126258Smlaier
7025145836Smlaier	if (s && s->tag)
7026145836Smlaier		pf_tag_packet(m, pf_get_tag(m), s->tag);
7027145836Smlaier
7028126258Smlaier#ifdef ALTQ
7029126258Smlaier	if (action == PF_PASS && r->qid) {
7030126258Smlaier		struct m_tag	*mtag;
7031126258Smlaier		struct altq_tag	*atag;
7032126258Smlaier
7033126258Smlaier		mtag = m_tag_get(PACKET_TAG_PF_QID, sizeof(*atag), M_NOWAIT);
7034126258Smlaier		if (mtag != NULL) {
7035126258Smlaier			atag = (struct altq_tag *)(mtag + 1);
7036126258Smlaier			if (pd.tos == IPTOS_LOWDELAY)
7037126258Smlaier				atag->qid = r->pqid;
7038126258Smlaier			else
7039126258Smlaier				atag->qid = r->qid;
7040126258Smlaier			/* add hints for ecn */
7041126258Smlaier			atag->af = AF_INET6;
7042126258Smlaier			atag->hdr = h;
7043126258Smlaier			m_tag_prepend(m, mtag);
7044126258Smlaier		}
7045126258Smlaier	}
7046145836Smlaier#endif /* ALTQ */
7047126258Smlaier
7048130613Smlaier	if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP ||
7049130613Smlaier	    pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL &&
7050130613Smlaier	    (s->nat_rule.ptr->action == PF_RDR ||
7051130613Smlaier	    s->nat_rule.ptr->action == PF_BINAT) &&
7052130613Smlaier	    IN6_IS_ADDR_LOOPBACK(&pd.dst->v6) &&
7053130613Smlaier	    pf_add_mbuf_tag(m, PACKET_TAG_PF_TRANSLATE_LOCALHOST)) {
7054130613Smlaier		action = PF_DROP;
7055130613Smlaier		REASON_SET(&reason, PFRES_MEMORY);
7056130613Smlaier	}
7057130613Smlaier
7058126258Smlaier	if (log)
7059130613Smlaier		PFLOG_PACKET(kif, h, m, AF_INET6, dir, reason, r, a, ruleset);
7060126258Smlaier
7061130613Smlaier	kif->pfik_bytes[1][dir == PF_OUT][action != PF_PASS] += pd.tot_len;
7062130613Smlaier	kif->pfik_packets[1][dir == PF_OUT][action != PF_PASS]++;
7063130613Smlaier
7064130613Smlaier	if (action == PF_PASS || r->action == PF_DROP) {
7065130613Smlaier		r->packets++;
7066130613Smlaier		r->bytes += pd.tot_len;
7067130613Smlaier		if (a != NULL) {
7068130613Smlaier			a->packets++;
7069130613Smlaier			a->bytes += pd.tot_len;
7070130613Smlaier		}
7071130613Smlaier		if (s != NULL) {
7072130613Smlaier			dirndx = (dir == s->direction) ? 0 : 1;
7073130613Smlaier			s->packets[dirndx]++;
7074130613Smlaier			s->bytes[dirndx] += pd.tot_len;
7075130613Smlaier			if (s->nat_rule.ptr != NULL) {
7076130613Smlaier				s->nat_rule.ptr->packets++;
7077130613Smlaier				s->nat_rule.ptr->bytes += pd.tot_len;
7078130613Smlaier			}
7079130613Smlaier			if (s->src_node != NULL) {
7080130613Smlaier				s->src_node->packets++;
7081130613Smlaier				s->src_node->bytes += pd.tot_len;
7082130613Smlaier			}
7083130613Smlaier			if (s->nat_src_node != NULL) {
7084130613Smlaier				s->nat_src_node->packets++;
7085130613Smlaier				s->nat_src_node->bytes += pd.tot_len;
7086130613Smlaier			}
7087130613Smlaier		}
7088130613Smlaier		tr = r;
7089130613Smlaier		nr = (s != NULL) ? s->nat_rule.ptr : pd.nat_rule;
7090130613Smlaier		if (nr != NULL) {
7091130613Smlaier			struct pf_addr *x;
7092130613Smlaier			/*
7093130613Smlaier			 * XXX: we need to make sure that the addresses
7094130613Smlaier			 * passed to pfr_update_stats() are the same than
7095130613Smlaier			 * the addresses used during matching (pfr_match)
7096130613Smlaier			 */
7097130613Smlaier			if (r == &pf_default_rule) {
7098130613Smlaier				tr = nr;
7099130613Smlaier				x = (s == NULL || s->direction == dir) ?
7100130613Smlaier				    &pd.baddr : &pd.naddr;
7101130613Smlaier			} else {
7102130613Smlaier				x = (s == NULL || s->direction == dir) ?
7103130613Smlaier				    &pd.naddr : &pd.baddr;
7104130613Smlaier			}
7105130613Smlaier			if (x == &pd.baddr || s == NULL) {
7106130613Smlaier				if (dir == PF_OUT)
7107130613Smlaier					pd.src = x;
7108130613Smlaier				else
7109130613Smlaier					pd.dst = x;
7110130613Smlaier			}
7111130613Smlaier		}
7112130613Smlaier		if (tr->src.addr.type == PF_ADDR_TABLE)
7113130613Smlaier			pfr_update_stats(tr->src.addr.p.tbl, (s == NULL ||
7114130613Smlaier			    s->direction == dir) ? pd.src : pd.dst, pd.af,
7115130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7116145836Smlaier			    tr->src.neg);
7117130613Smlaier		if (tr->dst.addr.type == PF_ADDR_TABLE)
7118130613Smlaier			pfr_update_stats(tr->dst.addr.p.tbl, (s == NULL ||
7119130613Smlaier			    s->direction == dir) ? pd.dst : pd.src, pd.af,
7120130613Smlaier			    pd.tot_len, dir == PF_OUT, r->action == PF_PASS,
7121145836Smlaier			    tr->dst.neg);
7122130613Smlaier	}
7123130613Smlaier
7124130613Smlaier
7125126258Smlaier	if (action == PF_SYNPROXY_DROP) {
7126126258Smlaier		m_freem(*m0);
7127126258Smlaier		*m0 = NULL;
7128126258Smlaier		action = PF_PASS;
7129126258Smlaier	} else if (r->rt)
7130126258Smlaier		/* pf_route6 can free the mbuf causing *m0 to become NULL */
7131126258Smlaier		pf_route6(m0, r, dir, ifp, s);
7132126258Smlaier
7133127145Smlaier#ifdef __FreeBSD__
7134126261Smlaier	PF_UNLOCK();
7135126261Smlaier#endif
7136126258Smlaier	return (action);
7137126258Smlaier}
7138126258Smlaier#endif /* INET6 */
7139145836Smlaier
7140145836Smlaierint
7141145836Smlaierpf_check_congestion(struct ifqueue *ifq)
7142145836Smlaier{
7143145836Smlaier#ifdef __FreeBSD__
7144145836Smlaier	/* XXX_IMPORT: later */
7145145836Smlaier	return (0);
7146145836Smlaier#else
7147145836Smlaier	if (ifq->ifq_congestion)
7148145836Smlaier		return (1);
7149145836Smlaier	else
7150145836Smlaier		return (0);
7151145836Smlaier#endif
7152145836Smlaier}
7153